Skip to content

Technical

Components

ERP Connector consists of the following components:

  • Data structure (existing + new tables and fields) in Lime CRM.
  • Lime Bootstrap apps.
  • Endpoints.
  • Web component.
  • Syncify's on-premise service.
  • Syncify's cloud service.

Table and Field Definitions Lime CRM

These tables and fields must be created before you can use the ERP Connector.

Company

On the company card, some fields included in the Lime CRM Base Solution are used. Please note that database field names are hardcoded in Syncify's migration scripts and Syncify's default integration field mappings. This means that if the fields are not named as ERP Connector expects them to be you have to notify Syncify.

The following fields are expected to exist:

Table database name: company

Database Field Name Field Type
name Text field
registrationno Text field
coworker Relation field
postaladdress1 Text field
postaladdress2 Text field
postalzipcode Text field
postalcity Text field
country Text field
phone Text field
visitingaddress1 Text field
visitingaddress2 Text field
visitingzipcode Text field
visitingcity Text field

The following fields are added by ERP Connector.

Database Field Name Field Type Length Field Label Description
invoiceaddress1 Text field 72 N/A Populated by the integration.
invoiceaddress2 Text field 72 N/A Populated by the integration.
invoicezipcode Text field 10 N/A Populated by the integration.
invoicecity Text field 72 N/A Populated by the integration.
fullinvoiceaddress Text field 256 N/A SQL for update, hidden on forms.
erp_id Text field 16 Key The integration key. Set label key to avoid duplicates.
erp_status Option field N/A N/A Status to keep track of the sync process. Readonly.
erp_errormessage Text field 512 N/A Populated by the integration on error. Readonly.
emailinvoice Link field 100 N/A Populated by the integration.
erp_firstsynced Time field N/A N/A Populated by the integration first time an object is synced. Readonly, Null allowed, no default value.
erp_lastsynced Time field N/A N/A Populated by the integration every time an object is synced. Readonly, Null allowed, no default value.
erp_turnover_yearnow Decimal N/A N/A Populated by the sales trend calculation task.
erp_turnover_lastyear Decimal N/A N/A Populated by the sales trend calculation task.
erp_turnover_lastyeartodate Decimal N/A N/A Populated by the sales trend calculation task.
erp_salestrend Option field N/A N/A Calculated trend based on turnover, populated by the sales trend calculation task. Readonly.
erp_ytdgrowth Decimal N/A N/A Calculated growth in % based on turnover, populated by the sales trend calculation task. Readonly.
erp_connector_graph HTML (tab) N/A N/A HTML tab for showing the graph for paid invoices the last 5 years. Only for the Lime CRM Desktop Client.
invoice Relation (tab) N/A N/A Populated by the integration.
invoicerow Relation (tab) N/A N/A Populated by the integration.
Required Fields

Having a field in Lime CRM mapped to the name property in the ERP systems' API:s is required.

Invoice

Invoices are connected to the company using erp_id when generated in Lime CRM from the ERP system. The following table and fields are added by ERP Connector:

Table database name: invoice

Database Field Name Field Type Length Description
invoice_number Text field 64 Unique invoice number
company Relation (field) 256 Relation to company
customerid Text field 128 Customer ID for matching to company
customer_reference Text field N/A Customer reference from ERP
coworker Relation (field) N/A Company reference (Our reference)
invoice_type Text field 64 Invoice type
invoice_date Time (date) N/A When invoice is booked
invoice_expires Time (date) N/A When invoice expires
invoice_sum Decimal N/A Sum ex VAT (moms)
invoice_vat Decimal N/A VAT (moms)
invoice_total_sum Decimal N/A Sum incl VAT
currency Text field 32 Currency
conversionrate Decimal N/A Conversion rate
invoice_balance Decimal N/A Invoice balance (saldo)
paid Yes/no N/A Yes if it is paid
paid_date Time (date) N/A The date when payment is registered
invoice shredded Yes/no N/A Yes if the payment is shredded (makulerad)
invoicerow Relation (tab) N/A All invoice rows belonging to the invoice

Invoice Row

Invoice rows are connected to an invoice using the invoice_number. The following table and fields are added by ERP Connector:

Table database name: invoicerow

Database Field Name Field Type Length Description
invoice Relation (field) N/A Relation to invoice
company Relation (field) N/A Relation to company
item Text field 128 Item
description Text field 128 Description of Items
units Decimal N/A Number of items
row_margin Decimal N/A Contribution margin
row_value Decimal N/A Sum of row
rowid Text field 32 Used to make a row unique (hidden)
position Integer N/A Position of the invoice row

Lime Bootstrap Apps

These are only used when using the ERP Connector from the Lime CRM Desktop Client.

The first Lime Bootstrap app is for the button to send a new customer to the ERP system, as well as showing the current sync status. It is using the same backend as the web client counterpart. The second LBS app is for the invoice overview graph shown in the HTML tab on the company card.

Web Component

This is only used when using the ERP Connector from the Lime CRM Web Client.

ERP Status

Will show the button to send company information to the ERP system, as well as the current sync status.

Sales Trend

Will visualize the turnover growth this year compared to the same period last fiscal year for each company in the table view.

Syncify Services

Syncify has built two different services. One for cloud based ERP systems and one for on-premise ERP Systems. It is these two services that connect to the ERP systems' API.

If the ERP system is installed on-premise, the Syncify service must be installed and configured on the ERP system server (or a server with access to the ERP server). Syncify is responsible for installations of their service.

If the ERP system is cloud based there is no need for a local Syncify service. The integration is instead registered in Syncify's cloud service through their web portal. This is also done by Syncify.

The Syncify services connects to the ERP systems as described below. Some ERP systems are cloud based and some are installed on-premise.

ERP system Connects through cloud on-premise
BL Administration ? ✔️
e-conomic REST API ✔️
Exact Online ? ✔️
Fortnox REST API ✔️
Maconomy ?
Business Central cloud: REST API and OData, on-premise: Webservice (SOAP) ✔️ ✔️
Microsoft Dynamics NAV Webservice (SOAP) ✔️
Monitor G5 ? ✔️ ✔️
Power Office Go ? ✔️
Tripletex ? ✔️
Uniconta ? ✔️
Visma Administration adk.dll ✔️
Visma Business VBS (Visma Business Services) ✔️
Visma eEkonomi ? ✔️
Visma Global ? ✔️
Visma.Net REST API ✔️
Visma Nova ?

Lime Services

The add-on consumes four different services in the Lime server. The most obvious service is the Web server, but the Event handler, Task handler and Task scheduler are also involved. In many cases several services are used in the same flow, meaning that logs also will be split depending on what service executed the particular part of the flow. The flows with their corresponding services are described below.

User uses WC/LBS app to set limeobject ready for first sync

When the button in the app is pressed to set "Ready for first sync", a request goes to a custom endpoint to set the ERP status. Only the Web server is involved.

Limeobject is updated by user or other integration than Syncify

The add-on is continously looking for updated limeobjects using the Event handler. Each time a limeobject is updated, the event handler checks whether the limetype of that limeobject is configured in any ERP instance(s). If there's a match on the limetype, a check whether any of the properties that are configured as propertiesSynced in these instances determines if that should lead to an ERP status update. If that's the case, an update instance status task is sent to the Task handler that eventually will update the limeobject's ERP status(es) asynchronously. Notes:

  1. All limeobject updates triggered by the erpsync@lime user are ignored by the event handler.
  2. Rules for the ERP status flow are here.
  3. Due to the large amount of update events, the run time configuration is cached to avoid loading it from the database at each event.

Limeobjects are fetched by Syncify

Syncify uses custom endpoints to get data. The endpoints are using Lime query and they're excuted synchronously on the Web server.

Limeobjects are updated by Syncify

Syncify uses custom endpoints to update/insert data. The Web server receives the payload and directly delegates all work to a task that will be executed asynchronously by the Task handler. The endpoint returns a task id so Syncify can poll the status of the task.

Sales trend is calculated

If any sales trend instances are configured, the Task scheduler will pick them up and run a daily calculations task at the time configured in the Environment Config. If the current date is the date that the fiscal year starts, a yearly reset function will be run prior to the daily calculations in the same scheduled task.

Endpoints

Objects

/<string:limetype_name>/

Gets all objects based on limetype. Useful for getting data for migrations. Limit number of results with optional limit arg. Start from a specific id with optional offset arg. Properties can be requested in the payload (lime_query syntax).

Example:

/deal/?limit=2&offset=1004

Payload:

{
    "name": "",
    "value": "",
    "coworker": {
        "name": "",
        "office": {
            "name": ""
        }
    }
}

Response:

{
    "objects": [
         {
            "_id": 1004,
            "_limetype": "deal",
            "name": "Ice cream",
            "value": 50000,
            "coworker": {
                "_id": 1010,
                "_limetype": "coworker",
                "name": "Terry I",
                "office": null
            }
        },
        {
            "_id": 1005,
            "_limetype": "deal",
            "name": "Meat",
            "value": 299,
            "coworker": {
                "_id": 1023,
                "_limetype": "coworker",
                "name": "Carlito Calzone",
                "office": {
                    "_id": 4003,
                    "_limetype": "building",
                    "name": "Havana",
                }
            }
        },
    ],
    "next": 1006
}

next can be used as offset for the next request. If no more objects are available, next is null.

Objects from limetype and erp_id property

GET
/<string:limetype_name>/<string:erp_id_name>/

Gets all objects based on limetype and the name of the property that has the erp_id. This combination must exist as an instance in the configuration. This endpoint should be used to get objects based on status. Filter on status with optional status arg. Limit number of results with optional limit arg. Start from a specific id with optional offset arg. Properties can be requested in the payload (lime_query syntax).

Example:

/company/erp_id/?status=updatesmade&status=new&limit=2&offset=1009

Payload:

{
    "name": "",
    "phone": "",
    "postalcity": "",
    "erp_id": "",
    "coworker": {
        "name": "",
        "office": {
            "name": ""
        }
    }
}

Response:

{
    "objects": [
        {
            "_id": 1009,
            "_limetype": "company",
            "_status": "updatesmade",
            "_first_synced": "2021-01-21T13:20:24.863000+01:00",
            "_last_synced": "2021-04-27T16:44:22.400000+02:00",
            "name": "Basemetrics Oy (demo)",
            "phone": "0417784718",
            "postalcity": "HELSINKI",
            "erp_id": "7779311",
            "coworker": {
                "_id": "1023",
                "_limetype": "coworker",
                "name": "Carlito Calzone",
                "office": {
                    "_id": "4003",
                    "_limetype": "building",
                    "name": "Havana",
                }
            }
        },
        {
            "_id": 1022,
            "_limetype": "company",
            "_status": "new",
            "_first_synced": "2021-01-05T00:00:00+01:00",
            "_last_synced": "2021-04-27T16:44:22.403000+02:00",
            "name": "PH Glas (DEMO)",
            "phone": "+4521324545",
            "postalcity": "\u00c5rhus V",
            "erp_id": null,
            "coworker": {
                "_id": "1010",
                "_limetype": "coworker",
                "name": "Terry I",
                "office": null
            }
        }
    ],
    "instance": "company-visma",
    "system": "vismabusiness",
    "erp_id_property": "erp_id",
    "status_property": "erp_status",
    "next": 1023
}

next can be used as offset for the next request. If no more objects are available, next is null.

PUT
/

Updates multiple objects asynchronously. Returns a task id to be used with the task endpoint. Related objects can be created/updated just as their parents.

Payload:

[
    {
        "_limetype": "company",
        "_id": 1009,
        "erp_status": "synced",
        "name": "Batch updated OY"        
    },
    {
        "_limetype": "company",
        "_search": {
            "property": "erp_id",
            "value": "4422", 
        },
        "erp_status": "synced",
        "name": "Identified by erp_id, will be created if it doesn't exist",
        "person": {
            "_search": {
                "property": "name",
                "value": "Klas Buffel"
            },
            "phone": "88599",
            "firstname": "Claes",
            "lastname": "Buffel"
        }
    },
    {
        "_limetype": "company",
        "_id": 1450,
        "erp_status": "synced",
        "_search": {
            "property": "erp_id",
            "value": "4423", 
        },
        "name": "_id will be priorized over search"
    },
    {
        "_limetype": "company",
        "_id": 1019,
        "erp_status": "synced",
        "buyingstatus": "prospect",
        "wwa": "https://www.wrestler.se/"
    },
    {
        "_limetype": "company",
        "_id": 10101,
        "erp_status": "synced",
        "name": "Unknown company"
    },
    {
        "_limetype": "deal",
        "_id": 1009,
        "name": "A new deal"
    },
    {
        "_limetype": "person",
        "_search": {
            "property": "lastname",
            "value": "Tunberg"
        },
        "lastname": "Thunberg"
    },
    {
        "_limetype": "person",
        "_search": {
            "property": "email",
            "value": "[email protected]",
            "create": false
        },
        "name": "Carlito Calzone"
    }
]

Response:

{
    "id": "5b607d37-c9bd-4722-8ce9-7fb71517930f",
    "status": "PENDING",
    "result": null
}

The _search object allows limeobjects to be searched for using the name of a property and its value. A search should only be used on a property that has a unique value. In case there are several matches, only the first match is returned. If no limeobject is found, it's created by default. This behaviour can be overriden by setting create to false.

{
    "_search": {
        "property": "email",
        "value": "[email protected]",
        "create": false // Default behaviour is true
    }
}
Notes
  • Any limeobject can be updated, whether it's configured in an instance or not.
  • _id will always be prioritized over _search.
  • _id and optionally _searchare always available in the response from the task to be able to relate back to the data that was sent to this endpoint.
  • If any properties updated are configured in an instance as either the erp_id or erp_status property, the name of the instance(s) will also be returned.
  • The _first_synced and _last_synced properties are automatically set for all updated objects where instances were found. See above.

Task

GET
/task/<string:task_id>/

Poll to get the status on a task.

Example:

/task/5b607d37-c9bd-4722-8ce9-7fb71517930f/

Response:

{
    "id": "5b607d37-c9bd-4722-8ce9-7fb71517930f",
    "status": "SUCCESS",
    "result": [
        {
            "_success": true,
            "_error": null,
            "_limetype": "company",
            "_id": 1009,
            "_action": "updated",
            "erp_status": "synced",
            "name": "Batch updated OY" 
        },
        {
            "_success": true,
            "_error": null,
            "_limetype": "company",
            "_id": 2000,
            "_action": "created",
            "_search": {
                "property": "erp_id",
                "value": "4422"
            },
            "_instances": [
                "company-visma"
            ],
            "erp_id": "4422",
            "erp_status": "synced",
            "name": "Identified by erp_id, will be created if it doesn't exist",
            "person": {
                "_success": true,
                "_error": null,
                "_limetype": "person",
                "_id": 1013,
                "_action": "updated",
                "_search": {
                    "property": "name",
                    "value": "Klas Buffel"
                },
                "phone": "88599",
                "firstname": "Claes",
                "lastname": "Buffel"
            }
        },
        {
            "_success": true,
            "_error": null,
            "_limetype": "company",
            "_id": 1450,
            "_action": "updated",
            "_search": {
                "property": "erp_id",
                "value": "4423", 
            },
            "_instances": [
                "company-visma"
            ],
            "name": "_id will be priorized over search"
        },
        {
            "_success": false,
            "_error": "The property \"wwa\" does not exist",
            "_limetype": "company",
            "_id": 1019,
            "_action": null,
            "_instances": [
                "company-visma"
            ]
        },
        {
            "_success": false,
            "_error": "The company \"10101\" does not exist.",
            "_limetype": "company",
            "_id": null,
            "_action": null,
            "_instances": [
                "company-visma"
            ]
        },
        {
            "_success": true,
            "_error": null,
            "_limetype": "deal",
            "_id": 1009,
            "_action": "updated",
            "name": "A new deal"
        },
        {
            "_success": true,
            "_error": null,
            "_limetype": "person",
            "_id": 1999,
            "_action": "updated",
            "_search": {
                "property": "lastname",
                "value": "Tunberg"
            },
            "lastname": "Thunberg"
        },
        {
            "_success": true,
            "_error": null,
            "_limetype": "person",
            "_action": "not_created",
            "_search": {
                "property": "email",
                "value": "[email protected]",
                "create": false
            },
            "name": "Carlito Calzone"
        }
    ]
}

The outer status is that of the task. Values can be PENDING, SUCCESS or FAILED. When PENDING, it's ideal to keep polling. The other statuses are final. result contains the result of the task, and is depending on what the task was for. In this case for a PUT of multiple objects.

Info

If an object update was not successful, a new PUT request should be made updating the object's ERP status and ERP error message.

Status

GET
/status/<string:limetype_name>/<int:id>/

Gets the statuses for the instance(s) on a limeobject. Used by the web component and LBS app.

Example:

/status/company/1009/

Response:

[
    {
        "status": "updatesmade",
        "statusText": "Updates made",
        "firstSynced": "2020-06-30T17:36:31.307000+02:00",
        "lastSynced": "2021-04-14T11:59:08.180000+02:00",
        "system": "vismabusiness",
        "instance": "company-visma",
        "systemDisplayName": "Visma Business",
        "readPermission": true,
        "updatePermission": true
    },
    {
        "status": "empty",
        "statusText": "",
        "firstSynced": "",
        "lastSynced": "",
        "system": "fortnox",
        "instance": "company-fortnox",
        "systemDisplayName": "Fortnox",
        "readPermission": true,
        "updatePermission": false
    }
]
PUT
/<string:instance_name>/<int:id>/

Updates status on a single object. Used by the web component and LBS app.

Payload:

{
    "status": "STRING"
}

Example:

/company-visma/1009/

Payload:

{
    "status": "synced"
}

Response:

{
    "status": "synced",
    "statusText": "Synkad",
    "firstSynced": "2020-06-30T17:36:31.307000+02:00",
    "lastSynced": "2021-04-14T12:39:55.130000+02:00",
    "system": "vismabusiness",
    "instance": "company-visma",
    "systemDisplayName": "Visma Business",
    "readPermission": true,
    "updatePermission": true
}

Translations

GET
/translations/

Gets all translations for the ERP Connector. Language is based on the Accept-Language header. Used by the LBS app.

Events

All events that are either published or handled by the add-on.

erp_connector.config_updated

Custom event that is published by the add-on whenever the run time config is saved. This is used to refresh the run time config cache.

core.limeobject.{instance_limetype}.update.v1

Lime core event. Whenever the run time config is updated, event handlers will be registered for all limetypes in that are configured in ERP instances.

Tasks

create_or_update_objects_task

Creates or updates limeobjects.

update_instance_object_status_task

Updates the ERP status on a limeobject.

Scheduled Tasks

calculate_sales_trend

Calculates the sales trend on a daily basis. If the date is the start of the fiscal year, a yearly reset function (that resets old sales trend data) will be run prior to the daily calculations.