Specification of Integration

Specification of Integration

The attached excel file contains a list of tables with columns description for each function block data load. It also highlights required and optional tables/fields that are only used when certain features are enabled.

All tables are separated into blocks, just like in the user interface.

Overview

  1. The MySales system works with a wide range of databases (Oracle, Microsoft SQL Server, MySQL, PostgreeSQL, Oracle Teradata and etc.).

  2. We recommend that you choose the database that matches the database of your ERP or similar system where you already have data on sales, stock balances and which is used to register purchase orders and goods receipts.

  3. You can use the following options to create a database:

    1. Database instance on separate server

    2. Separate database instance on the same server as the ERP database instance.

    3. Separate database on ERP server database instance (recommended).

    4. Separate database schema on same database on ERP server database instance.

  4. The main workload usually occurs at night, when sales and stock balance data are exchanged between MySales and ERP system and forecasts and orders calculated.

If you are tackle with difficulties when preparing data for loading or with performance issues, you can always contact us, but you must know the data structure of your ERP system.

We may change the data structure, lengths and types of some fields for data storage optimization and compatibility purposes.

Not all tables are required for integration. The list of tables is determined by the capabilities of the ERP system used and the customer's processes.

Data types

The following data types are used in the MySales system:

Data type

MSSQL

ORACLE

MySQL

PostgeeSQL

Data type

MSSQL

ORACLE

MySQL

PostgeeSQL

Integer 4 Bytes

-2,147,483,648 to 2,147,483,647

int

number(10)

int

integer

Integer 2 Bytes

-32,768 to 32,767

smallint

number(5)

smallint

smallint

1 Byte

0 to 255

tinyint

number(3)
number(1)

smallint

smallint

identity insert

IDENTITY

SEQUENCE

AUTO_INCREMENT

serial (integer)
smallserial (smallint)

ascii string with fixed length

char(*)

char(*)

char(*) character set latin1

char(*)

UNICODE string with fixed length

nchar

nchar(*)

char(*) character set utf8mb4

char(*)

ascii string with variable length

varchar(*)

varchar2(*)

varchar(*) character set latin1

varchar(*)

UNICODE string with variable length

nvarchar(*)

nvarchar2(*)

varchar(*) character set utf8mb4

varchar(*)

Date

date

date

date

date

Date and time (DB server time)

datetime

timestamp

datetime

timestamp without timezone

Decimal number with p length and s precision

numeric(p,s)

number(p,s)

numeric(p,s)

numeric(p,s)

ETL process example

Extract, Transform, Load (ETL)

Here is an example of the integration process between the ERP system and the MySales system:

 

Master data

Below is an example of data exchange for STORES table, which contains a list of stores and warehouses and using an Microsoft SQL Server as database.

The STORES table uses the STORE_ID primary key with type smallint (int) as the store/warehouse identifier.

If the ERP system uses a similar table to store the list of stores and warehouses, and they have the same master key type, you don't need to use STORES.CLIENT_CODE field.

If the ERP system uses a different Primary Key or uses separate tables for Stores and Warehouses you need to use STORES.CLIENT_CODE field:

  1. Set the IDENTITY properties for the STORE.STORE_ID field (auto-increment, sequence in other databases) so that an ID is automatically created for inserted records.

  2. Change the field type STORES.CLIENT_CODE to the type used in the same ERP system table and use this field for subsequent updates and inserting data in other tables such as assortment matrix, sales or stock balances.

  3. If the different tables is used for Stores and Warehouses in ERP with a different key fields, use one of two options:

    • Combine value ‘S'+ERP_STORE_ID and 'W’ + ERP_WHS_ID for STORES.CLIENT_CODE field.

    • Add second field STORES.CLIENT_CODE_W for warehouse correspondence.

Here is an example for MSSQL database, but you can use same technics for other databases:
Similar ERP table is used, with primary key type int that not exceed smallint value.

merge into msls.STORES as T with (tablock) from DbLink.ERPDB.dbo.MASTER_STORES as S with (nolock) on T.STORE_ID = S.ID when matched and ( ((T.STORE_CODE <> S.STORE_NUMBER) or (T.STORE_CODE is NULL and S.STORE_NUMBER is NOT NULL) or (T.STORE_CODE is NOT NULL and S.STORE_NUMBER is NULL)) or ((T.STORE_NAME <> S.NAME) or (T.STORE_NAME is NULL and S.NAME is NOT NULL) or (T.STORE_NAME is NOT NULL and S.NAME is NULL)) -- or ( other_fields_comparison ) then update set T.STORE_CODE = S.STORE_NUMBER, T.STORE_NAME = S.NAME -- other_fields when not matched by target then insert (STORE_ID, STORE_CODE, STORE_NAME) values (S.ID, S.NUMBER, S.NAME);

Similar ERP table is used, with primary key type GUID (binary(16)). STORES.STORE_ID is IDENTITY field.

merge into msls.STORES as T with (tablock) from DbLink.ERPDB.dbo.MASTER_STORES as S with (nolock) on T.CLIENT_CODE= S.ID when matched and ( ((T.STORE_CODE <> S.STORE_NUMBER) or (T.STORE_CODE is NULL and S.STORE_NUMBER is NOT NULL) or (T.STORE_CODE is NOT NULL and S.STORE_NUMBER is NULL)) or ((T.STORE_NAME <> S.NAME) or (T.STORE_NAME is NULL and S.NAME is NOT NULL) or (T.STORE_NAME is NOT NULL and S.NAME is NULL)) -- or ( other_fields_comparison ) then update set T.STORE_CODE = S.STORE_NUMBER, T.STORE_NAME = S.NAME -- other_fields when not matched by target then insert (STORE_CODE, STORE_NAME, CLIENT_CODE) values (S.NUMBER, S.NAME, S.ID);

Two different ERP table are used for Stores and Warehouses. STORES.STORE_ID is IDENTITY field.

merge into msls.STORES as T with (tablock) from ( select concat('S', ID) as CLIENT_CODE, STORE_NUMBER as CODE, NAME from DbLink.ERPDB.dbo.MASTER_STORES with (nolock) union all select concat('W', ID) as ID, concat('W', ID) as CODE, NAME from DbLink.ERPDB.dbo.MASTER_WAREHOUSES with (nolock) ) as S with (nolock) on T.CLIENT_CODE= S.CLIENT_CODE when matched and ( ((T.STORE_CODE <> S.CODE) or (T.STORE_CODE is NULL and S.CODE is NOT NULL) or (T.STORE_CODE is NOT NULL and S.CODE is NULL)) or ((T.STORE_NAME <> S.NAME) or (T.STORE_NAME is NULL and S.NAME is NOT NULL) or (T.STORE_NAME is NOT NULL and S.NAME is NULL)) -- or ( other_fields_comparison ) then update set T.STORE_CODE = S.STORE_NUMBER, T.STORE_NAME = S.NAME -- other_fields when not matched by target then insert (STORE_CODE, STORE_NAME, CLIENT_CODE) values (S.CODE, S.NAME, S.CLIENT_CODE);

General data

Below is an example of data exchange for SKU_RANGE_CURRENT table, which contains current assortment matrix data using delete + insert statement:

truncate table msls.SKU_RANGE_CURRENT; insert into msls.SKU_RANGE_CURRENT with (tablock) (STORE_ID, SKU_ID) select S.STORE_ID, P.SKU_ID from DbLink.ERPDB.dbo.ASSORTMENT_MATRIX as AX with (nolock) inner join msls.STORES as S with (nolock) on S.CLIENT_CODE = AX.STORE_IDENT inner join msls.PRODUCTS as P with (nolock) on P.CLIENT_CODE = AX.PRODUCT_ID;

Sales and stock data

Usually, ERP systems use different tables to store stock balances and sales, goods receipts, but we need to combine all this data to save them in a single final table SALES.

 

DAILY_SALES (SALES_DATE, STORE_IDENT, PRODUCT_ID, SALES_QUANTITY, RETURN_QUANTITY, TOTAL_AMOUNT, DISCOUNT)
INVENTORY_BALANCE (BALANCE_DATE, STORE_IDENT, PRODUCT_ID, QUANTITY)
INVENTORY_GOODS_RECEIPTS (RECEIPT_NUMBER, RECEIPT_DATE, REF_ID, STORE_IDENT, PRODUCT_ID, QUANTITY, AMOUNT)

declare @end_date as date = DATEADD(DAY, -1, cast(getdate() as date)); declare @start_date as date = DATEADD(DAY, -3, @end_date); delete from msls.SALES_SKU_DATE where sdate > @start_date; insert into msls.SALES_SKU_DAY with (tablock) (SDATE, STORE_ID, SKU_ID, SALES_VOLUME, SALES_VALUE, DISCOUNT_VALUE, STOCK_VOLUME, TRX_VOLUME) select SDATE, STORE_ID, SKU_ID, sum(SALES_VOLUME) as SALES_VOLUME, sum(SALES_VALUE) as SALES_VALUE, sum(DISCOUNT) as DISCOUNT, sum(STOCK_VOLUME) as STOCK_VOLUME, sum(TRX_VOLUME) as TRX_VOLUME FROM ( select SALES_DATE as SDATE, S.STORE_ID, P.SKU_ID, iif(SALES_QUANTITY - RETURN_QUANTITY > 0, SALES_QUANTITY - RETURN_QUANTITY, 0) as SALES_VOLUME, iif(TOTAL_AMOUNT > 0, TOTAL_AMOUNT, 0) as SALES_VALUE, DISCOUNT as DISCOUNT_VALUE, cast(0 as number(10,3)) as STOCK_VOLUME, cast(0 as number(10,3)) as TRX_VOLUME from DbLink.ERPDB.dbo.DAILY_SALES as D with (nolock) inner join msls.STORES as S with (nolock) on S.CLIENT_CODE = D.STORE_IDENT inner join msls.PRODUCTS as P with (nolock) on P.CLIENT_CODE = D.PRODUCT_ID where SALES_DATE between @start_date and @end_date union all select BALANCE_DATE as SDATE, S.STORE_ID, P.SKU_ID, cast(0 as number(10,3)) as SALES_VOLUME, cast(0 as number(10,2)) as SALES_VALUE, cast(0 as number(8,2)) as DISCOUNT_VALUE, QUANTITY as STOCK_VOLUME, cast(0 as number(10,3)) as TRX_VOLUME from DbLink.ERPDB.dbo.INVENTORY_BALANCE as I with (nolock) inner join msls.STORES as S with (nolock) on S.CLIENT_CODE = I.STORE_IDENT inner join msls.PRODUCTS as P with (nolock) on P.CLIENT_CODE = I.PRODUCT_ID where BALANCE_DATE between @start_date and @end_date union all select RECEIPT_DATE as SDATE, S.STORE_ID, P.SKU_ID, cast(0 as number(10,3)) as SALES_VOLUME, cast(0 as number(10,2)) as SALES_VALUE, cast(0 as number(8,2)) as DISCOUNT_VALUE, cast(0 as number(10,3)) as STOCK_VOLUME, sum(QUANTITY) as TRX_VOLUME from DbLink.ERPDB.dbo.INVENTORY_GOODS_RECEIPTS as R with (nolock) inner join msls.STORES as S with (nolock) on S.CLIENT_CODE = R.STORE_IDENT inner join msls.PRODUCTS as P with (nolock) on P.CLIENT_CODE = R.PRODUCT_ID where RECEIPT_DATE between @start_date and @end_date group by RECEIPT_DATE, S.STORE_ID, P.SKU_ID ) as vt group by SDATE, STORE_ID, SKU_ID;

Forecast Tables

Master data

PRICELINES - Price lines (price lists)

Data update period: daily merge without deletion

This table is only filled if the prices in the ERP system assigned to a several of stores, and not by each store separately.

Column name

Data type

Allow NULL

Required field

Column Description

Column name

Data type

Allow NULL

Required field

Column Description

PRICELINE_ID

smallint

NOT NULL

Y

Price number

NAME

nvarchar(256)

NULL

 

Name

UPDATED

datetime

NULL

 

Update date

CLIENT_CODE

*

*

*

The priceline ID in the client ERP system, if it is not compatible with the smallint type.

Used to transfer data between systems.

REGIONS - Regions

Data update period: daily merge without deletion

Column name

Data type

Allow NULL

Required field

Column Description

Column name

Data type

Allow NULL

Required field

Column Description

REGION_ID

smallint

NOT NULL

Y

Region number

REGION_NAME

nvarchar(256)

NULL

Y

Region name

CLIENT_CODE

*

*

*

The region ID in the client ERP system, if it is not compatible with the smallint type.

Used to transfer data between systems.

STORES - Stores (and warehouses)

Data update period: daily merge without deletion

Column name

Data type

Allow NULL

Required field

Column Description

Column name

Data type

Allow NULL

Required field

Column Description

STORE_ID

smallint

NOT NULL

Y

Store number. It is desirable that the number that the user sees is filled in here

STORE_NAME

nvarchar(256)

NOT NULL

Y

Store name

REGION_ID

smallint

NOT NULL

Y

Region number from the REGIONS table

PRICELINE_ID

smallint

NULL

 

Price serial number from the PRICELINES table

OPEN_DATE

date

NULL

 

Store opening date

CLOSE_DATE

date

NULL

 

Store closing date

STORE_CODE

nvarchar(32)

NULL

 

Store code from the accounting system. Filled in only if the STORE_ID field is generated and does not match the number that the user sees.

ADDRESS

nvarchar(256)

NULL

 

Store Address

UPDATED

datetime

NULL

 

Update date

WHS

tinyint

NULL

 

Warehouse sign. Filled in as 1 for warehouses. Stores must be NULL. The value 0 is not allowed.

FORMAT_ID

tinyint

NULL

 

Store Format Id

FORMAT_CODE

char(1)

NULL

 

Store Format Code (e.g. Mini, Super, Hyper, Warehouse)

CLIENT_CODE

*

*

*

The store ID / warehouse ID in the client ERP system, if it is not compatible with the smallint type.

If different table in ERP system used, use a prefix, such as S for stores (S45) and W for warehouses (W2).

Used to transfer data between systems.

GROUPS - Product groups

Data update period: daily merge without deletion

Column name

Data type

Allow NULL

Required field

Column Description

Column name

Data type

Allow NULL

Required field

Column Description

GROUP_ID

smallint

NOT NULL

Y

Group number

GROUP_NAME

nvarchar(256)

NULL

Y

The name of the group of goods. Unique.

GROUP_CODE

nvarchar(32)

NULL

 

Group code from accounting system

PARENT_GROUP_ID

smallint

NULL

 

Paternal group number (for building hierarchies)

UPLIFT_WO_DISC

number(12, 2)

NULL

 

Filled in on the MySales side

UPLIFT_WITH_DISC

number(12, 2)

NULL

 

Filled in on the MySales side

AVG_BENEFIT

number(8, 2)

NULL

 

Filled in on the MySales side

AVG_ITEM_WIDTH

number(10, 2)

NULL

 

Filled in on the MySales side

UPDATED

datetime

NULL

 

Update date

CLIENT_CODE

*

*

*

The group ID in the client ERP system, if it is not compatible with the smallint type.

Used to transfer data between systems.

PRODUCTS - Products (SKU - Stock Keeping Units)

Data update period: daily merge without deletion

Column name

Data type

Allow NULL

Required field

Column Description

Column name

Data type

Allow NULL

Required field

Column Description

SKU_ID

int

NOT NULL

Y

Product identifier

GROUP_ID

smallint

NOT NULL

Y

Group number from the GROUPS table. SKUs are tied to the lowest level of the product hierarchy.

ARTICLE_NAME

nvarchar(256)

NOT NULL

Y

Name of product. Unique

ITEM_CODE

nvarchar(20)

NULL

 

Item code from the accounting system. Filled in only if the SKU_ID field is generated and does not match the number that the user sees

SUPPLIER_ID

smallint

NULL

 

Supplier identifier from SUPPLIERS table.
()

LAST_PURCHASE_PRICE

number(10, 2)

NULL

 

Purchase price WITHOUT value added tax

LAST_SALES_WEEK

number(10, 2)

NULL

 

Filled in on the MySales side

UPLIFT_WO_DISC

number(10, 2)

NULL

 

Filled in on the MySales side

UPLIFT_WITH_DISC

number(10, 2)

NULL

 

Filled in on the MySales side

AVG_BENEFIT

number(10, 2)

NULL

 

Filled in on the MySales side

SHELF_DAYS

smallint

NULL

Required for Replenishment

Total expiration period, in days.

(Expiration date minus production date)

PACKAGE_CONTENT

number(10, 3)

NULL

Only for Reorder Point

Multiplicity of orders for DC

MIN_ORDER_QTY

number(10, 3)

NULL

Only for Reorder Point

Minimum order quantity

PRODUCTS_UOM

nvarchar(10)

NULL

 

unit of measurement

UPDATED

datetime

NULL

 

insert or update date

VAT_PERCENT

number(5, 2)

NULL

Only for Price Optimisation

% vat on value added purchases. If %=0 then put 0

WEIGHT

number(10, 3)

NULL

Only for Replenishment

Product weight, kg

VOLUME

number(10, 3)

NULL

 

Product volume, l

HEIGHT

number(6, 2)

NULL

 

Product height, см

WIDTH

number(6, 2)

NULL

 

Product width, cm

DEPTH

number(6, 2)

NULL

 

Product length, cm

CLIENT_CODE

*

*

*

The product ID in the client ERP system, if it is not compatible with the int type.
Used to transfer data between systems.

General data

PRICES - Retail prices

Data update period: daily

Prices are also filled in for future periods if they are known.

Column name

Data type

Allow NULL

Required field

Column Description

Column name

Data type

Allow NULL

Required field

Column Description

SKU_ID

int

NOT NULL

Y

Product identifier from PRODUCTS.SKU_ID

STORE_ID/ PRICELINE_ID

smallint

NOT NULL

Y

Store identifier from STORES.STORE_ID /
Price identifier from PRICELINES.PRICELINE_ID

START_DATE

date

NOT NULL

Y

Price start date

END_DATE

date

NULL

 

Price end date. If the price is active, it should be NULL, or the year 2050. When a new price appears, the date of the last day when it was active must be put on the old price

PRICE

number(10, 2)

NOT NULL

Y

Price with Value Added Tax

PRICE_TYPE

varchar(20)

NULL

 

Price type (Promotion / Sale, etc.). Recommended to fill.

If the client's system does not maintain prices by date, it is possible to fill in the simplified PRICES_CURRENT table, on the basis of which the PRICES table will be automatically generated.

PRICES_CURRENT - Current retail prices

Data update period: daily truncate + insert, daily merge

This table is only populated if the customer prefers it as a simpler alternative to the PRICES table. Once the PRICES_CURRENT table is populated, a query is run that automatically generates the PRICES table.

Column name

Data type

Allow NULL

Required field

Column Description

Column name

Data type

Allow NULL

Required field

Column Description

SKU_ID

int

NOT_NULL

Y

Product identifier from PRODUCTS.SKU_ID

STORE_ID/ PRICELINE_ID

int

NOT_NULL

1

Store identifier from STORES.STORE_ID /
Price identifier from PRICELINES.PRICELINE_ID

PRICE

number(10, 2)

NULL

1

Price with Value Added Tax