# Nearby Store Integration and Configuration

If a brand has multiple sales locations and product stock or price information varies by location, the brand must register all stores in Omnitron and add segments in Omnitron accordingly. To enable selection of a store based on the customer’s location and to display products available in that store to the customer, a service can be implemented on the extension side. Since such services require access to store data in the extension, a hook must be added in Omnitron for store data synchronization.

## <mark style="color:red;">**Extension Implementation Steps**</mark>

### <mark style="color:red;">**1. Store Data Synchronization**</mark>

Stores added or updated in Omnitron must be reflected in the extension. Therefore, the extension must have a model, view, and serializer for store data. The model should include all store data needed by the extension.

Key fields relevant for segment and nearby store assignment are:

* `erp_code`
* `latitude`
* `longitude`
* `is_active`
* `country`

If different settings exist for stores (e.g., some stores sell products from other stores), a `config` field (as `JsonField`) can be added to the model. This config data can be used in nearest store operations when necessary.

#### <mark style="color:red;">**a. Delivery Areas per Delivery Method**</mark>

If the brand uses multiple delivery methods (e.g., schedule, quick) and delivery areas differ per method, the model should include separate polygon data lists for each delivery method (e.g., `schedule_boundary`, `quick_boundary`).

To indicate if a delivery method is active for a store, add boolean fields (e.g., `is_scheduled_active`, `is_quick_active`). Since these fields do not exist in Omnitron by default, they can be initialized as empty lists or `False`.

* If the brand defines an area by latitude and longitude polygons, the [Shapely](https://shapely.readthedocs.io/en/stable/) library can be used. Shapely can create `Point` objects for customer locations and `Polygon` shapes for store boundaries. Polygon data can be created or edited at <https://geojson.io>.\
  \&#xNAN;*Example:*

  <div align="left"><figure><img src="https://2911598027-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlQinVPnOffBiOp126ldR%2Fuploads%2Fgit-blob-5ea2c9c7acc400b45d23a8508c3801f54de77941%2F4.png?alt=media" alt="" width="563"><figcaption></figcaption></figure></div>

#### <mark style="color:red;">**b.**</mark> <mark style="color:red;">**Radius-Based Delivery Areas**</mark>

If delivery areas are defined by a radius around store coordinates per delivery method, the model should include radius fields (e.g., `scheduled_radius`, `quick_radius`). These can have default values since they do not exist in Omnitron.

Alternatively, if radius values differ by delivery type rather than by store, these can be stored in environment variables instead of the model.

* If no polygon data is defined but delivery should cover addresses within a radius from store coordinates, Redis GeoSearch can be used. Newly added or updated stores should be saved both to the model and to Redis Geo with the store name as the member identifier.

### <mark style="color:red;">**2. Delivery Types and Coverage Areas**</mark>

Since delivery types accepted by stores and their coverage areas or radius information is not managed in Omnitron, these fields must be added manually. Thus, the store view in the extension must be accessible and editable.

### <mark style="color:red;">**3. Service for Finding Store by Customer Location**</mark>

A service must be added in the extension to find the appropriate store for a customer’s order based on their location.

#### <mark style="color:red;">**a. Polygon-Based Store Selection**</mark>

If the store’s delivery coverage areas are defined by polygons, Shapely can be used to create a `Point` from the customer’s location. Active stores in the extension store table are checked to see if the customer point is inside the polygon corresponding to the delivery method (`schedule_boundary`, `quick_boundary`, etc.). If the point is inside the polygon and the delivery type is active, the store, delivery type, and store code are included in the response.

{% hint style="warning" %}
The same store may not serve all delivery types in the same location, so including delivery type in the response is important.
{% endhint %}

If no nearby store is found, default stores with currency and polygon coordinates can be included in the environment variables.

#### <mark style="color:red;">**b. Radius-Based Store Selection**</mark>

If coverage areas are defined by radius, Redis GeoSearch can be used with store data previously added to Redis. The service queries Redis with the customer’s latitude, longitude, and the radius to find suitable stores.

* If multiple stores are found within the radius and the closest store should be selected, the `WITHDIST` parameter should be set to `True` in the Redis query. This returns the distance between each store and the customer, allowing selection of the nearest store.
* If the brand operates in multiple countries, stores located in a different country than the customer’s should be excluded. Store filtering must be done by country or currency to ensure a store in the customer's country is selected.\
  Store filtering steps:
  * Filter active extension stores by country or currency.
  * If store data lacks currency, country-to-currency mapping defined in environment variables can be used to infer country.
* If multiple delivery methods exist, filtering and queries should be run separately for each delivery type. Stores must be returned with associated delivery types in the response.

## <mark style="color:red;">**Omnitron Implementation Steps**</mark>

### <mark style="color:red;">**1. Store Hooks**</mark>

To ensure store additions and updates in Omnitron are reflected in the extension, hooks must be added. `POST` requests must be sent to the endpoint: `{{omnitron_base_url}}api/v1/whisperer/hooks/`with `event_type` set to `retail_store.created` and `retail_store.updated`.

* For `retail_store.created`, the `target_url` should point to the extension’s store creation service URL.
* Include authentication info for the extension in the hook configuration.

### <mark style="color:red;">**2. Creating Stores in Omnitron**</mark>

Navigate to: `Sales Channels > Store Management > Stores`

Use the `+New Store` button to add a store with fields:

* Store Name,
* ERP Code,
* Country,
* City,
* Township,
* Address,
* Phone,
* Latitude,
* Longitude,
* Status,
* Delivery from Store,
* Channel.

{% hint style="success" %}
For detailed information, refer to the [How to Manage Stores in Omnitron?](https://app.gitbook.com/s/IbwGN7KwvYi0iLbjtnXz/omnitron/sales-channels/store-management/how-to-manage-stores-in-omnitron) document.
{% endhint %}

### <mark style="color:red;">**3. Creating Price Lists in Omnitron**</mark>

Navigate to: `Products and Catalogs > Price Lists`

Use `+ New Price List` and enter:

* Price List Name,
* ERP Connection status (select `ERP Connection Available` if prices are not loaded via Excel),
* ERP Code, and
* Currency (if applicable).

{% hint style="success" %}
For detailed information, refer to the [How to Create and Update Price Lists in Omnitron?](https://app.gitbook.com/s/IbwGN7KwvYi0iLbjtnXz/omnitron/products-and-catalogs/how-to-create-and-update-price-lists-in-omnitron) document.
{% endhint %}

### <mark style="color:red;">**4. Creating Stock Lists in Omnitron**</mark>

Navigate to: `Products and Catalogs > Stock Lists`

Use `New Stock List` and enter:

* Stock List Name,
* ERP Connection status, and
* ERP Code (if applicable).

{% hint style="success" %}
For detailed information, refer to the [How to Create and Update Stock Lists in Omnitron?](https://app.gitbook.com/s/IbwGN7KwvYi0iLbjtnXz/omnitron/products-and-catalogs/how-to-create-and-update-stock-lists-in-omnitron) document.
{% endhint %}

### <mark style="color:red;">**5. Assigning Price and Stock Lists to Catalogs**</mark>

Navigate to: `Products and Catalogs > Catalogs`

Select the catalog to assign price and stock lists.

* Add price lists via `Add Price List` if they are primary or exclusive for that catalog.
* Add additional price lists under `Extra Price Lists` if they apply only to certain stores.
* Add stock lists similarly.

{% hint style="success" %}
For detailed information, refer to the [How to Manage Catalogs in Omnitron?](https://app.gitbook.com/s/IbwGN7KwvYi0iLbjtnXz/omnitron/products-and-catalogs/how-to-manage-catalogs-in-omnitron) document.
{% endhint %}

### <mark style="color:red;">**6. Adding Segments for Store Product Visibility**</mark>

Navigate to: `Sales Channels > Customer Groups > Customer Groups Settings`

Create a new segment via `New Customer Groups Settings`.

Define rules in the config field using currency and store info to filter products by store.

### <mark style="color:red;">**7. If the Brand Uses OMS**</mark>

Stores added in Omnitron are automatically reflected in OMS Locations. However, to activate a newly added store, you must go to `Akinon OMS > Locations`, find the store, and set its status to "Active."

Check the scenarios defined in `Akinon OMS > Scenarios` for the newly added store.

### <mark style="color:red;">**8. If the Brand Uses Whippy**</mark>

When a brand uses Whippy for stock management, you must configure the new store in Whippy by adding the required stock-related records. If Whippy is being used for the first time, a Stock Provider must also be created.

#### <mark style="color:red;">**a. Add a Stock Provider (if using Whippy for the first time):**</mark>

Go to the **Stock Providers** page in the Whippy interface and click **Add New Provider** to create a new provider.

#### <mark style="color:red;">**b. Add a Stock Location:**</mark>

Navigate to the **Stock Locations** page and click **Add New Location**. Make sure to link the location to the previously created Stock Provider.

#### <mark style="color:red;">**c. Define Stock List Rules:**</mark>

To control which stores can see stock from the new store (and vice versa), go to the **Stock List Rules** page and click **Add New Rule**.

If the new store will also feed stock to existing stores, make sure to update existing rules accordingly.

In the **ss\_locations** field of the rule, list all store locations that should supply stock to the newly added store.

#### <mark style="color:red;">**d. Create a Stock List:**</mark>

Go to the **Stock Lists** page and click **Add New Stock List**.

When creating the list, the **Remote ID** must match the stock list ID from Omnitron.

You must also select the **Stock List Rule** that was created for the new store.

{% hint style="success" %}
For detailed information, refer to the [Whippy Ware](https://app.gitbook.com/s/IbwGN7KwvYi0iLbjtnXz/whippy-ware/whippy-ware) tutorial.
{% endhint %}

### <mark style="color:red;">**9. If the Brand Uses Integrator**</mark>

If the brand uses an Integrator, a price and stock flow must be added in the Integrator to allow data transmission for the newly added store's stock and price lists.

If a single flow is used for all stock and price lists, the existing flow should be reviewed and updated if necessary to include the new stock and price list information.

#### <mark style="color:red;">**a. Creating a Price Flow:**</mark>

1. \- In the Integrator interface, select the relevant project and navigate to **Integration Flows**.\
   \- Click **Create a New Flow** and select [**Price**](https://app.gitbook.com/s/IbwGN7KwvYi0iLbjtnXz/integrator/flows/price-flow) as the Flow Type.\
   \- Choose the login that corresponds to the system where price data is fetched. If no login exists yet, you must first create a [**Login Flow**](https://app.gitbook.com/s/IbwGN7KwvYi0iLbjtnXz/integrator/flows/login-flow).\
   \- Then, set the schedule interval for how frequently the flow should run.
2. \- Once the flow is created, click the **edit (pencil)** icon next to the flow name in the Integration Flows list to configure it.\
   \- In the **Configuration** tab, enter the **Omnitron Price List ID**.\
   \- Under **Omnitron API Settings**, enter the **Omnitron URL** and **Timezone**. Click **Save** to proceed.
3. \- In the **Read Data from ERP** step, provide the necessary parameters for retrieving price data.\
   \- For example, in the Lulu setup, price data is fetched from an extension, so you must enter the **ERP Code** of the store under **ERP Param Settings > Extra Params**.\
   \- In the **Price API URL** field, enter the ERP's price API endpoint.\
   \- Optionally, fill in **Pagination Settings**.\
   \- Specify the response path for the price data in the **Response Settings > Path for data in response as array path**. Click **Save** to continue.
4. If any validation or transformation is needed for the price data other than renaming keys, add a script.
5. In the **Mapping** step, match the fields from the ERP to the expected Omnitron fields.\
   In the mapping, the **price\_list** field must be mapped to the newly created price list ID in Omnitron. Click **Save** to finish.
6. After completing all steps, activate the flow from the **Status** field on the **Integration Flows** page so that it can begin fetching data.

#### <mark style="color:red;">**b. Creating a Stock Flow:**</mark>

1. \- In the integrator interface, select the relevant project and navigate to **Integration Flows**.\
   \- Click **Create a New Flow** and select [**Stock**](https://app.gitbook.com/s/IbwGN7KwvYi0iLbjtnXz/integrator/flows/stock-flow) as the Flow Type.\
   \- Choose the login corresponding to the source system of stock data.\
   \- For example, if stock is fetched from Whippy, use the **Omnitron Login**. If no login exists, create a [**Login Flow**](https://app.gitbook.com/s/IbwGN7KwvYi0iLbjtnXz/integrator/flows/login-flow) first.\
   \- Set the schedule for how often the flow should run.
2. \- Once the flow is created, click the **edit (pencil)** icon to configure it.\
   \- In the **Configuration** tab, enter the **Omnitron Stock List ID**.\
   \- Fill in the **Omnitron URL** and **Timezone** under **Omnitron API Settings**, and click **Save** to proceed.
3. \- In the **Read Data from ERP** step, configure how the stock data will be retrieved.\
   \- In the case of Lulu, stock data is pulled from Whippy, so the **Endpoint URL** should be:\
   `whippy_url/active-stocks/{stock_list_omnitron_id}/`\
   \- Fill in **Pagination Settings** if necessary.\
   \- Define the data path in the **Response Settings > Path for data in response as array path**. Click **Save** to continue.
4. If any custom logic or data transformation is needed beyond key names, add a script at this step.
5. In the **Mapping** step, map the ERP fields to the expected Omnitron fields.\
   For the **stock\_list** field, assign the newly created stock list ID from Omnitron. Click **Save** to complete the mapping.
6. Activate the flow via the **Status** column on the **Integration Flows** page to enable data fetching.

### <mark style="color:red;">**10. Final Configuration in Extension**</mark>

Once all data has been pushed to Omnitron, validate the **store data** in the **extension**.

If the store data is correct but certain required data is missing in Omnitron (e.g., polygons for delivery zones, active delivery types, delivery radius, configuration settings, etc.), these should be patched via a **PATCH request** to the **extension store data**.
