Interacting with products
The "Catalog" schema is one of the fundamentals in shop management. It will also allow you to retrieve products from the catalog and to edit them, manage your stock ...
Introduction
The product catalog is built from different schemas and their relationships. The schemas that make it up are listed below:
To illustrate the schema of the product catalog, it is important to analyze the following graph where the relationships between the listed schemas are represented.
Some explanations:
- Each
VariantPrice
has a uniquePrice
, for example "Tarif Boutique" or "Tarif Ecommerce. - Each
Product
has aCategory
(represented as folder in the application) and a uniqueTax
(20%
,10%
,5.5%
...). - Each
Product
has a list ofVariant
, where each variant represents the same product with different characteristics (alcohol volume, quantity, year ...) - Each
Variant
has astock
property which lets you know the stock at a given time. The entityStockActivity
gives a history of stock increments and decrementations on theVariant
.
Ahead of this documentation, each schema is explained separately.
Fetch a product data
note
We highly recommend to check the Playground Guide and test it yourself!
After analyzing the flowchart, we can see that the product query is very complete, it reaches many levels of relationships and details through the diagrams.
Thus, to include all the fundamental fields while keeping it simple, it is possible to use the following query:
REQUEST /graphql
query {
product(id: "e59b278f-c86c-4024-acc9-7e8e89802c0d") {
id
name
kind
producer
category {
name
}
tax {
name
}
variants {
edges {
node {
name
stock {
rawQuantity
formattedQuantity
}
variantPrices {
edges {
node {
valueIncludingTax
valueExcludingTax
toQuantity
fromQuantity
price {
name
taxIncluded
}
}
}
}
stockActivities {
edges {
node {
kind
quantity
}
}
}
}
}
}
}
}
RESPONSE /graphql
{
"data": {
"product": {
"id": "e59b278f-c86c-4024-acc9-7e8e89802c0d",
"name": "Samorens",
"kind": "WINE",
"producer": "Ferraton",
"category": {
"name": "Blanc"
},
"tax": {
"name": "TVA 20%"
},
"variants": {
"edges": [
{
"node": {
"name": "2018, 0.75L",
"stock": {
"rawQuantity": 5,
"formattedQuantity": "5"
},
"variantPrices": {
"edges": [
{
"node": {
"valueIncludingTax": 16,
"valueExcludingTax": 13.33,
"toQuantity": null,
"fromQuantity": null,
"price": {
"name": "Tarif Pro",
"taxIncluded": false
}
}
},
{
"node": {
"valueIncludingTax": 13.5,
"valueExcludingTax": 11.25,
"toQuantity": -1,
"fromQuantity": 6,
"price": {
"name": "Tarif Cave",
"taxIncluded": true
}
}
},
{
"node": {
"valueIncludingTax": 14,
"valueExcludingTax": 11.6,
"toQuantity": 5,
"fromQuantity": 1,
"price": {
"name": "Tarif Cave",
"taxIncluded": true
}
}
}
]
},
"stockActivities": {
"edges": [
{
"node": {
"kind": "SALE",
"quantity": 1
}
},
{
"node": {
"kind": "RESET",
"quantity": 6
}
}
]
}
}
}
]
}
}
}
}
Yes, it's a giant query.
Thanks to this query, we can perceive the power and simplicity of GraphQL: it is possible to retrieve very complex data easily.
We now have all the fundamental elements of a product sheet gathered in the same query! For the rest of this guide, we will come back to some details and particularities of the responses of this query.
General use
Product variants
Each product has one or more variants. A variant can correspond to a specific capacity/vintage... For example, the same wine can be sold in "BIB" or "0,75L" format. This will result in the presence of two Variant
entities on the same Product
entity.
note
From Wino, the merchant organises his catalog with products and variants. Two vintages of the same wine will be grouped by the merchant in Wino as one product with two variants.
However, if you are using the Wino API to create an online store or to link to online wine auction platforms or other platforms, we strongly advise you to use the variants
query to retrieve the "products" and not the products
query. Indeed, it is necessary to consider a vintage of a wine as a unique reference and not a variation. Think a variant within the Wino API as a unique product and not a declination.
REQUEST /graphql
query {
products {
edges {
node {
name
variants {
edges {
node {
name
stock {
rawQuantity
}
}
}
}
}
}
}
}
RESPONSE /graphql
{
"data": {
"products": {
"edges": [
{
"node": {
"name": "Samorens",
"variants": {
"edges": [
{
"node": {
"name": "2018, 0.75L",
"stock": {
"rawQuantity": 12
}
}
}
{
"node": {
"name": "2018, BIB 10L",
"stock": {
"rawQuantity": 4
}
}
}
]
}
}
}
]
}
}
}
Note that each variant of a product has its own stock and selling prices.
Kind of product
A merchant can sell several kinds of products in his store, each with its own business specificities. Today there are four kinds of product in Wino:
SPIRITUROUS
: composes the group of distillates and beverages with high alcohol content. E.g. vodkas, whiskys, etc.WINE
: composes the group of wines. It is possible to see in the schemaProduct
that the product has several other properties that further characterize this group of products. For example,productWineType
,productWhiteWineType
,color
, etc.BEER
: composes the group of beers. It is possible to see in the schema Product that the product has several other properties that further characterize this group of products. For example,beerType
,color
, etc.SIMPLE
: composes the group of simple drinks and other products related to the target market. E.g. juices, cheeses, etc.
Within the Variant
and Product
schemas, we therefore bring together different specific types to allow retailers to better segment and categorize their product references.
The following query will give one example of each kind and their specifications (to be run in the playground !).
REQUEST /graphql
query {
products {
edges {
node {
id
name
kind
producer
country
# Specific fields for wines and beers
color
# Specific fields for wines
region
designation
wineType
# Specific fields for beers
beerType
}
}
}
}
Formatted data
All fields that start with formatted
are automatically generated by the API from schema information. The idea related to these fields is to perform the necessary formatting, reducing the work for the front-end. In this sense, the information processing is even more located in the back-end and these variables are not allocated in the database, only generated from your call in queries. These fields should not be inserted in mutations and can be searched within queries.
For example, the formattedName
field of the Variant
schema is the composition of the name
of the product associated and the name
of the variant.
Here is an example query to check the formatted fields related to the product:
REQUEST /graphql
query {
products {
edges {
node {
id
category {
# A formatted field on `Category`
formattedName
}
variants {
edges {
node {
id
# Some formatted fields on `Variant`
formattedName
formattedDescription
}
}
}
}
}
}
}
Bulk variants
Products can be sold individually or in bulk within the checkout application. Some, it's possible that the same product is sold in many different ways. For example, A cheese can be packaged individually with a fixed capacity or sold by the cut with a varying capacity.
In this sense, the creation of a product variation is fundamental so that the same product can be managed and distributed in its different forms.
In the following example, a "cheese" product can be defined in three different ways:
REQUEST /graphql
query {
products {
edges {
node {
variants {
edges {
node {
## Formatted properties
formattedName
formattedDescription
# Bulk properties
bulk
capacityUnit
capacityPrecision
capacityValue
}
}
}
}
}
}
}
RESPONSE /graphql
- Non-bulk (without capacity)
- Non-bulk (with capacity)
- Bulk
{
"data": {
"products": {
"edges": [
{
"node": {
"variants": {
"edges": [
{
"node": {
"id": "ad5cbe9d-d740-4d8b-a09d-1c6fbc25eb23",
"formattedName": "Brie de Meaux - Γ l'unitΓ©",
"formattedDescription": "Meaux, France",
"bulk": false,
"capacityUnit": null,
"capacityPrecision": null,
"capacityValue": null
}
}
]
}
}
}
]
}
}
}
{
"data": {
"products": {
"edges": [
{
"node": {
"variants": {
"edges": [
{
"node": {
"id": "ad5cbe9d-d740-4d8b-a09d-1c6fbc25eb23",
"formattedName": "Brie de Meaux - 0,15kg",
"formattedDescription": "Meaux, France",
"bulk": false,
"capacityUnit": "kg",
"capacityPrecision": null,
"capacityValue": 0.15
}
}
]
}
}
}
]
}
}
}
{
"data": {
"products": {
"edges": [
{
"node": {
"variants": {
"edges": [
{
"node": {
"id": "ad5cbe9d-d740-4d8b-a09d-1c6fbc25eb23",
"formattedName": "Brie de Meaux - Au vrac",
"formattedDescription": "Meaux, France",
"bulk": true,
"capacityUnit": "kg",
"capacityPrecision": 3,
"capacityValue": null
}
}
]
}
}
}
]
}
}
}
After analysis of the code, there are several possible cases:
- When a product is sold in bulk, the
capacityUnit
andcacpacityPrecision
properties must be defined. - When a product is sold individually, the
capacityUnit
,capacityPrecision
andcapacityValue
properties may or may not be defined. It depends on whether the merchant wished to enter these details. It's all or nothing.
It can also be noted that the formattedName
field is closely related to these capability properties.
Stock management
After defining the properties of each product, customizing its features, etc., it's necessary to manage its distribution. For this, the first step is stock management. Stock management is the process related to the calculation, analysis and valuation of the stock of each variant.
The stock management is performed for each variant around the stock
object schema:
fragement variant on Variant {
stock {
# Quantity
rawQuantity
formattedQuantity
# State
stockState
# Valuation
rawValuation
formattedValuation
}
}
Use the following query to check the stock of the product:
REQUEST /graphql
query {
products {
edges {
node {
variants {
edges {
node {
stock {
# Quantity
rawQuantity
formattedQuantity
# State
state
# Valuation
rawValuation
formattedValuation
}
}
}
}
}
}
}
}
To go through this example, the stock management is divided into three parts: quantity, state and valuation.
Quantity
The stock quantity of each variant is present in the rawQuantity
attribute (in its raw form) and the formattedQuantity
attribute (in its formatted form).
The following examples can be observed:
- Non Bulk
- Bulk
{
"stock": {
"rawQuantity": 10,
"formattedQuantity": "10"
}
}
{
"stock": {
"rawQuantity": 20099,
"formattedQuantity": "20,099L"
}
}
In the case of a bulk product, the capacityUnit
and capacityPrecision
properties will be used to format the stock quantity.
State
The stock state has three possible values: OK
, ALERT
or DANGER
. The assignment of these depends on the quantities. Taking a general rule you can assign the meanings:
OK
: the quantity in stock does not yet present a risk of stock shortage (customized for each type of variant).ALERT
: the stock quantity is on the threshold between a safe quantity and the possible stock shortage in case of an unplanned sale.DANGER
: out of stock.
Valuation
The idea of stock valuation is based on the weighted average cost.
This cost relates the total cost of purchase and the quantity on a given date. Therefore, the stock valuation is recalculated after each stock activity so that it is possible to always have the current stock value.
Multiple selling prices
A product can be sold at different prices. For example, a bottle of wine may be sold individually at a certain price in the store. The same bottle can also be sold at another price for a professional (a restaurant for example) who buys in larger quantities (the selling price will then be lower per unit sold).
Thus, depending on the sales context, it is easy to choose the selling price to be applied to the product. The merchant can add as many selling prices (VariantPrice
) as there are price lists (Price
).
note
The taxIncluded
property of the associated Price
defines which property of VariantPrice
should be used (valueIncludingTaxes
or valueExcludingTaxes
). If variantPrice.price.taxInlucded
is true, it should be used the variantPrice.valueIncludingTax
value else it should be used the variantPrice.valueExcludingTax
value.
Degressive selling prices
In addition to being able to apply several selling prices on the same variant, a merchant can define degressive selling prices with quantity increments.
REQUEST /graphql
query {
products {
edges {
node {
variants {
edges {
node {
variantPrices {
edges {
node {
valueIncludingTax
valueExcludingTax
toQuantity
fromQuantity
price {
name
taxIncluded
}
}
}
}
}
}
}
}
}
}
}
RESPONSE /graphql
{
"data": {
"products": {
"variants": {
"edges": [
{
"node": {
"variantPrices": {
"edges": [
{
"node": {
"valueIncludingTax": 14,
"valueExcludingTax": 11.6,
"toQuantity": 5,
"fromQuantity": 1,
"price": {
"name": "Tarif Cave",
"taxIncluded": true
}
}
}
{
"node": {
"valueIncludingTax": 13.5,
"valueExcludingTax": 11.25,
"toQuantity": -1,
"fromQuantity": 6,
"price": {
"name": "Tarif Cave",
"taxIncluded": true
}
}
},
]
}
}
}
]
}
}
}
}
- When the quantity is between 1 and 5, the first price will be applied:
14.00β¬
. - When the quantity is between 6 and more, the second price will be applied:
13.50β¬
.
In this sense, it is possible to adjust these variables to perform the sales management of this variant.
Finally it is possible to perceive the power related to all the use cases present in this schema. Each one of them has its fundamental importance in the whole.