# Listing

A listing is an item or a commodity that is sold in a facility. It holds information on the product such as price, barcodes or attributes. A listing does not represent the actual stock, i.e., the (available) quantity of a product in a facility. All information specific to individual pieces of a product is kept in [stocks](https://docs.fulfillmenttools.com/documentation/by-pillar/global-inventory-hub/stock).

{% hint style="warning" %}
Please note the difference between listings and [articles](https://docs.fulfillmenttools.com/documentation/by-pillar/global-inventory-hub/articles).
{% endhint %}

## Listings and stocks

While a listing holds master data for a product within a facility such as title, barcode, or price, a stock refers to one or more items in a facility with the same attributes. Stocks can exist without listings and the other way around. However, we advise to always create listings for stocks so that the various stocks are assigned to the corresponding product and product information can be displayed in the clients. See the [Stocks article](https://docs.fulfillmenttools.com/documentation/by-pillar/global-inventory-hub/stock) for more information.

## Listing properties and configurations

### Status

Listings can be active or inactive.

{% hint style="warning" %}
Deactivated listings are not considered for incoming orders.
{% endhint %}

### Listing attributes

Attributes store listing specific information, including:

* Descriptions
* Picking sequence
* Shop and sales price
* Insurance related data for shipping
* Dimensions
* ... and more

{% hint style="info" %}
For more information, see the [article attributes article](https://docs.fulfillmenttools.com/documentation/by-pillar/global-inventory-hub/articles/article-attributes).
{% endhint %}

### Scanning rule

Configuration to show the client how the items should be scanned during picking. For more information, see the [scanning configuration article](https://docs.fulfillmenttools.com/documentation/by-pillar/global-inventory-hub/broken-reference).

### Out of stock behavior <a href="#out-of-stock-behaviour" id="out-of-stock-behaviour"></a>

Defines the behavior when a customer places an order for a product that is out of stock or unavailable for immediate shipment.&#x20;

A listing can be designated as backorderable, preorderable, restockable, or both preorderable and restockable.&#x20;

Additionally, out-of-stock behavior can be configured for specific facility groups or for orders with certain tags. Finally, users can set exceptions to these out-of-stock behaviors.

{% hint style="info" %}
Functional details can be found under [Pre- and Backorders](https://docs.fulfillmenttools.com/documentation/by-pillar/advanced-order-routing/pre-and-backorders).

Configuration details can be found in the [Out of stock behavior and configuration article](https://docs.fulfillmenttools.com/documentation/by-pillar/global-inventory-hub/stock/out-of-stock-behavior-and-configuration).
{% endhint %}

### Availability timeframe <a href="#availability-timeframe" id="availability-timeframe"></a>

If a listing is already flagged with `outOfStockBehaviour` = "BACKORDER" and has an `availabilityTimeFrame` configured, then orders containing that listing are accepted but only assigned a specific facility when the date defined in the `availabilityTimeFrame` is reached.

### Out of stock configuration

{% hint style="warning" %}
This functionality is only available if your tenant is configured for operating in complex networks. If you're interested, contact our Support team via [service request](https://ocfulfillment.atlassian.net/servicedesk/customer/portal/1/group/11/create/39).
{% endhint %}

Defines behavior if customer places an order for an article that is currently out of stock or unavailable for immediate shipment. A listing can be either backorderable, preorderable, restockable, or preorderable and restockable. This can be defined in the `outOfStockBehaviour` of the listing. For preorderable, restockable, or preorderable and restockable, an additional configuration must be made in the listing `outOfStockConfig`. If the out-of-stock behavior should only apply to specific facility groups or to orders with certain tags, an `outOfStockBehaviourByContexts` must be defined.

* preorderable
  * The order can be picked as soon as the `availabilityTimeFrame.start` is reached.
  * If there is no stock available for the order line item(s), this configuration is not considered.
* restockable
  * The order is treated as there would be "infinite" stock for the respective line items (after "x days").
  * The `restockableInDays` is used for calculations in routing (target time, etc.). If `restockableInDays` = 0, routing assumes that a sufficient amount of stock is present in the facility.

{% hint style="info" %}
If there are different out of stock behaviors for different facility groups or orders, a `context` can be added to the [out of stock configuration](https://docs.fulfillmenttools.com/documentation/by-pillar/global-inventory-hub/stock/out-of-stock-behavior-and-configuration).
{% endhint %}

### Tags

Tags consist of a Tag-Reference plus allowed values for each Tag. They can be used to map very individual processes and to customize entities according to particular needs. For more information, see the [Tags](https://docs.fulfillmenttools.com/documentation/getting-started/tags) and [Stickers](https://docs.fulfillmenttools.com/documentation/getting-started/stickers) articles.

### Measurement units

Measurement units specify the unit in which the product is counted or measured. They can be set using the `measurementUnitKey` field. The default counting unit is pieces. However, other units, such as gram, liters, or custom units, can be defined. For more information on creating new units and their localizations, refer to the [Measurement units article.](https://docs.fulfillmenttools.com/documentation/by-pillar/global-inventory-hub/measurement-units).

If one product should be tracked in different units (for example, as bulk by weight and also by prepackaged quantity), two listings with different tenantArticleIds need to be created, for example, "xyz-123-bulk" and "xyz-123-packaged". Since each product is kept in just one measurement unit, operations like adding or moving stock do not need to validate or convert units between stocks.

### Stock properties

Stock properties allow tracking specific values on a set of items, a [Stock](https://docs.fulfillmenttools.com/documentation/by-pillar/global-inventory-hub/stock). A typical example of properties is the expiry date or batch number. The listing defines which properties should be tracked for stocks associated with this specific listing. Moreover, it is configurable in the listing whether it is mandatory to track stock properties, e.g., during goods receipt, and if the value is expected to be a text or date.

Often, it is helpful to limit and enforce which properties are tracked for which type of product. You can configure this using the `stockProperties` field on `Listings`. This field does not contain key-value pairs of property values but rather `StockPropertyDefinitions`. Each defines the following:

For more information, see the [Stock properties article](https://docs.fulfillmenttools.com/documentation/by-pillar/global-inventory-hub/stock/stock-properties).

|                | Description                                                                                                                                           |
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `inputType`    | `DATE` or `TEXT`. The input type controls how values of this property should be treated by clients (i.e. show a date picker instead of a text field). |
| `required`     | `boolean`. Creating a stock without providing a value for a `required` property will be forbidden and fail.                                           |
| `defaultValue` | String or `{{NOW}}` which will be interpolated to current timestamp.                                                                                  |

{% hint style="warning" %}
Constraints, validations as well as default values are **ONLY** applied on creation of stocks.

This means that existing stocks may still not have properties, even if required, or have properties which are - by a newer ruleset - not allowed.
{% endhint %}

If no constraints should be enforced, the `stockProperties` field can be set to null/undefined. In that case it is ensured that no properties are set.

### Stock available until

The `availableUntil` field defines until when a stock is included in the stock availability, which is, for example, used to communicate available stock to shop systems. For customer orders, the availability check ensures that stock has not exceeded its `availableUntil` value until it is delivered to the customer.&#x20;

In the listing it can be specified until when the corresponding stock should be available. The `availableUntil` value is set upon stock creation if configured in the listing. When updating a listing with `stockAvailableUntil`, the value will be only added to newly created stock.

For more information, see the [Stock availability article](https://docs.fulfillmenttools.com/documentation/by-pillar/global-inventory-hub/stock/stock-availability).

* `calculation base:` Specifies the base date for the calculation of `availableUntil`. Set the field to EXPIRY if the stock should become unavailable before it expires. EXPIRY must be configured in the [stockProperties](#stock-properties) before it can be used here. Set the field to CREATION if the stock should become unavailable sometime after it was created.
* `modifier:` The time span is applied to the calculation base to calculate when stock should become unavailable. Use negative values to move the date backward. Example: "-P30D" places the "availableUntil" value 30 days before the calculated date.

{% hint style="warning" %}

* `StockAvailableUntil` defaults to the expiry date. So, if there is no `stockAvailableUntil` configured on the listing, the `stockAvailableUntil` of a stock will be its expiry date.
* An undefined `stockAvailableUntil` on stocks (for example, no `stockAvailableUntil` and no expiry is configured) means the stock will be available indefinitely.
  {% endhint %}

### Legal

Under `legal`, users can specify a `hsCode`. "HS" stands for "Harmonized system" and is a description and coding system authorities use to classify a product. In our platform, it is used, for example, when requesting a carrier label for sending a package.

### Categories

A listing can belong to one to many categories. The `categoryRef` on the listing allows different listings to be assigned to the same category.

{% hint style="info" %}
More information can be found under [article categories](https://docs.fulfillmenttools.com/documentation/by-pillar/global-inventory-hub/categories).
{% endhint %}

{% hint style="info" %}
For detailed API specifications, see the [REST API documentation for Listings](https://fulfillmenttools.github.io/fulfillmenttools-api-reference-ui/#get-/api/facilities/-facilityId-/listings).
{% endhint %}

## Creating a listing

{% hint style="warning" %}
Before creating a listing, a [facility](https://docs.fulfillmenttools.com/documentation/getting-started/facilities) must be created. Listings are always related to a specific facility.
{% endhint %}

To create a listing, send a `PUT` request to the following endpoint with a JSON body:

```http
PUT https://{YOUR-TENANT-NAME}.api.fulfillmenttools.com/api/facilities/{facilityId}/listings
```

```json
{
  "listings": [
    {
      "imageUrl": "https://upload.wikimedia.org/wikipedia/en/3/35/Wonka_Bar%2C_packaging.jpg",
      "price": 2.99,
      "tenantArticleId": "4892",
      "titleLocalized": {
        "de_DE": "Wonkas Schokoriegel",
        "en_US": "Wonkas Chocolate Bar"
      }
    }
  ]
}
```

A successful request returns an `HTTP 200 OK` response.

## Retrieving listings

To retrieve all listings for a specific facility, send a paginated `GET` request to the following endpoint using the `facilityId`:

```http
GET https://{YOUR-TENANT-NAME}.api.fulfillmenttools.com/api/facilities/{facilityId}/listings
```

A successful request returns an `HTTP 200 OK` response containing all listings for that facility.

```json
{
    "total": 1,
    "listings": [
        {
            "id": "5d174533-29b9-464b-9325-94bfacefe335_4892",
            "version": 1,
            "status": "ACTIVE",
            "tenantArticleId": "4892",
            "created": "2023-08-22T12:19:14.129Z"
        }
    ]
}
```

Alternatively, to retrieve a specific listing by its `tenantArticleId`, use the following `GET` endpoint:

```http
GET https://{YOUR-TENANT-NAME}.api.fulfillmenttools.com/api/facilities/{facilityId}/listings/{tenantArticleId}
```

The endpoint returns an `HTTP 200 OK` response with a detailed view of the specified listing:

```json
{
  "attributes": null,
  "imageUrl": "https://upload.wikimedia.org/wikipedia/en/3/35/Wonka_Bar%2C_packaging.jpg",
  "price": 2.99,
  "tenantArticleId": "4892",
  "titleLocalized": {
    "de_DE": "Wonkas Schokoriegel",
    "en_US": "Wonkas Chocolate Bar"
  },
  "scannableCodes": [],
  "created": "2023-08-22T12:19:14.129Z",
  "lastModified": "2023-08-22T12:19:14.129Z",
  "version": 1,
  "facilityId": "5d174533-29b9-464b-9325-94bfacefe335",
  "id": "5d174533-29b9-464b-9325-94bfacefe335_4892",
  "status": "ACTIVE"
}
```

## Bulk upserting listings

To upsert listings for multiple facilities while minimizing API calls, use the bulk upsert endpoint.

There are two options for using the endpoint:

* [`ListingForBulkUpsertBySelector`](#updating-with-listingforbulkupsertbyselector): Allows sending listing information once and updating it for multiple facilities.
* [`ListingForBulkUpsertByFacility`](#updating-with-listingforbulkupsertbyfacility): Allows sending different listing information for the same `tenantArticleId` for multiple facilities.

{% hint style="info" %}
The listing `version` must be sent for an update; otherwise, a new listing is created. If a listing with the same `tenantArticleId` already exists, the entire update batch fails.
{% endhint %}

### Searching for the listing version

Before updating existing listings, their current `version` must be retrieved. This can be done by searching for the listings. The bulk API can then be used to update multiple listings across various facilities simultaneously.

The following example demonstrates searching for all listings with `tenantArticleId` 4711 to retrieve their current versions.

```http
POST https://{YOUR-TENANT-NAME}.api.fulfillmenttools.com/api/listings/search
```

```json
{
  "query": {
    "tenantArticleId": {
      "eq": "4711"
    }
  }
}
```

{% hint style="info" %}
It might be necessary to iterate over multiple pages to get all listings with the corresponding `tenantArticleId`. More information can be found under [Pagination.](https://docs.fulfillmenttools.com/documentation/getting-started/general-concepts#pagination)
{% endhint %}

The search returns the complete listings.

### Updating with `ListingForBulkUpsertBySelector`

To update multiple listings, send a `PUT` request to the following endpoint with the JSON body:

```http
PUT https://{YOUR-TENANT-NAME}.api.fulfillmenttools.com/api/listings
```

```json
{
  "listings": [
    {
      "tenantArticleId": "4711",
      "selector": [
        {
          "facility": {
            "facilityRef": "facility1"
          },
          "version": 42
        },
        {
          "facility": {
            "facilityRef": "facility2"
          },
          "version": 43
        }
      ],
      "targetingStrategy": "MULTI_SELECTOR",
       ... // the full updated listing
    }
  ]
}
```

Each object in the `selector` array specifies a listing in a particular facility by its `tenantArticleId` and current `version`. A single batch can update up to 25 listings. This can be achieved by providing 25 selectors for one listing, or through multiple listings with their respective selectors. The endpoint returns the updated listings and a summary of the operations.

{% hint style="warning" %}
This is an all-or-nothing behavior. If one listing insert fails, all others will fail as well.
{% endhint %}

```json
{
  "listings": [
    {
      ...
    },
    ...
  ],
  "summary": {
    "created": 0,
    "updated": 2
  }
}
```

### Updating with `ListingForBulkUpsertByFacility`

To update multiple listings, send a `PUT` request to the following endpoint with the JSON body:

```http
PUT https://{YOUR-TENANT-NAME}.api.fulfillmenttools.com/api/listings
```

```json
{
  "listings": [
    {
      "tenantArticleId": "4711",
      "facility": {
        "facilityRef": "facility1"
      },
      "targetingStrategy": "SINGLE_FACILITY",
      "version": 42,
      ... // the full updated listing
    },
    {
      "tenantArticleId": "4711",
      "facility": {
        "facilityRef": "facility2"
      },
      "targetingStrategy": "SINGLE_FACILITY",
      "version": 43,
      ... // the full updated listing
    },
    ...
  ]
}
```

The endpoint returns the updated listings and a summary of the operations.

{% hint style="warning" %}
This is an all-or-nothing behavior. If one listing insert fails, all others will fail as well.
{% endhint %}

```json
{
  "listings": [
    {
      ...
    },
    ...
  ],
  "summary": {
    "created": 0,
    "updated": 2
  }
}
```
