Tesco Product Update
Version | Date | Created / Updated | Notes |
---|---|---|---|
v1.0 | Hristiyan Georgiev | Initial version | |
v1.1 | 12/05/2025 | Hristiyan Georgiev | Mapping changes |
v1.2 | 21/05/2025 | Hristiyan Georgiev | Additional mapping changes |
When we are talking about product updates on Tesco we need to distinguish them by two flows : Advert(product) updates and Variant updates :
- Advert updates: These encompass general product information such as description, title, product features, and dimensions. The tricky part is that an advert update can include variants, making it essentially a full update.
- Variant updates: These pertain to specific product variations, allowing updates to price and quantity. These updates are used for stock and price changes, which are explained in separate pages.
As advised above, in this page we will only look for the advert updates which can be considered full updates on our end.
Protect flags handle :
The good thing in GraphQL is that we do not need to block any communication but rather we can exclude fields that we don’t want to update.
Protect the whole item
- This field blocks all content updates for the relevant product to the marketplace except for Stock & Price update. GraphQL allows us to only update the stock & price in a single “full” update call, but it will be misleading for the end user and if we have this flag, we want to skip the update and leave theList/Update the whole item
on Pending.Protect Price
- This means we include everything except theprice
andsalePrice
fields in our variables payload.Protect Stock
- This means we include everything exceptcountOnHand
field in our variables payload.
All triggers, validations except the protect flags mentioned above, are as per the listing abstraction for product update - Product Listing general requirements. <v1.2> We also want to add an additional trigger on top of the abstraction, and this is Listing
> Product Status
= Product Created <v1.2>
<v1.2>GraphQL Query</v1.2> :
mutation AdvertUpdate($input: AdvertUpsertMutationInput!) {
advertUpsert(input: $input) {
advert {
id
statusText
displayable
catalogRulesErrors{
errorMessage
fieldName
objectId
}
legacyId
variants(displayableOnly: false)
{
nodes {
sku
id
displayable
}
}
}
errors {
field
messages
}
}
}
Query Variables :
{
"input": {
"advertId": "QWR2ZXJ0LTEwMDA5NTcwNg==",
"attributes": {
"brandId": "QnJhbmQtNA==",
"taxonId": "VGF4b24tMjgw",
"title": "Noviq TESTIKO NO QTY Puuuut6",
"description": "Test test test. Shetst Shets!",
"productFeatures": ["Super Best, Very Good", "Amazin' Feature2", "the best feature3"],
"shippingParcelAttributes": {
"weight": 100,
"massUnit": "g",
"length": 5,
"width": 6,
"depth": 15,
"distanceUnit": "cm"
},
"saleType": "BUY_ONLINE",
"attemptAutoPublish": true,
"images": [
{
"sourceUrl": "https://images.puma.net/images/398352/03/fnd/GBR/"
},
{
"sourceUrl": "https://images.puma.net/images/398672/02/sv01/fnd/GBR/"
},
{
"sourceUrl": "https://images.puma.net/images/398672/02/sv02/fnd/GBR/"
}
],
"advertOptionValues": [
{
"optionValueId": "T3B0aW9uVmFsdWUtNzM0"
},
{
"optionValueId": "T3B0aW9uVmFsdWUtNzI4"
},
{
"optionValueId": "T3B0aW9uVmFsdWUtNzI5"
},
{
"optionTypeId": "T3B0aW9uVHlwZS0yNTA=",
"textValue": "asdasda"
}
],
"variants": [
{
"id": "VmFyaWFudC0xMDU2NDI=",
"description": "Its amazing!",
"sku": "1234561",
"barcode": "6723827005389",
"price": "99",
"salePrice": "98",
"countOnHand": 110,
"images": [
{
"sourceUrl": "https://images.puma.net/images/935520/01/fnd/GBR/"
},
{
"sourceUrl": "https://images.puma.net/images/935520/01/bv/fnd/GBR/"
},
{
"sourceUrl": "https://images.puma.net/images/935520/01/mod02/fnd/GBR/"
}
],
"variantOptionValues": [
{
"optionValueId": "T3B0aW9uVmFsdWUtNzMy"
},
{
"optionValueId": "T3B0aW9uVmFsdWUtNzIz"
},
{
"optionValueId": "T3B0aW9uVmFsdWUtNzI0"
},
{
"optionTypeId": "T3B0aW9uVHlwZS0yNTI=",
"textValue": "Very not cool Color"
}
]
},
{
"id": "VmFyaWFudC0xMDU2MzU=",
"description": "Its amazing!",
"sku": "6543211",
"price": "99",
"salePrice": "55",
"countOnHand": 10,
"images": [
{
"sourceUrl": "https://images.puma.net/images/398352/03/fnd/GBR/"
}
],
"variantOptionValues": [
{
"optionValueId": "T3B0aW9uVmFsdWUtNzMx"
},
{
"optionValueId": "T3B0aW9uVmFsdWUtNzIz"
},
{
"optionValueId": "T3B0aW9uVmFsdWUtNzI0"
},
{
"optionTypeId": "T3B0aW9uVHlwZS0yNTI=", "textValue": "Very not cool Color"
}
]
}
]
}
}
}
Variables mapping :
Tesco Field | Integration Requried | Hemi Mapping | Hemi Notes | |||
---|---|---|---|---|---|---|
input |
||||||
advertId |
Yes | Product Account > Channel Item ID |
||||
attributes |
||||||
brandId |
Yes | Product > Brand |
OR
Product Account
> Item Specifics
| Product
is with priority. We need to send the Id of the brand as per the taxonomy. |
| | taxonId
| | | Yes | Product Account
> Primary Category ID
| We need to send the Id of the category |
| | title
| | | Yes | Product Account
> Title
| Since we keep this info on Product Account
level, we might have a case where we have a variation and we have different titles across the variations. In the case we have more than one product selectefd for update, we want to pick the Proudct Account
with the lowest ID and use its title. |
| | description
| | | Yes | Product Account
> Description
| |
| | productFeatures
| | | No | Product Account Tesco
> Product Features
| New field! This should be a field with the possibility to “add more features”. Similar to the Item/Variation specifics fields. The only difference is that here we will have only one box for input instead of two. Then each row needs to be separated by comma in the payload. |
| | shippingParcelAttributes
| | | | | |
| | | weight
| | Conditional | Product
> Weight
| We need to send this together with massUnit
. If we are not sending weight, we need to exclude massUnit
from the payload |
| | | massUnit
| | Conditional | | Hardcoded as “g” . We only need to send it when sending weight
|
| | | length
| | Conditional | Product
> Length
| We need to send either all 3 of length
, width
and depth
or none of them. |
| | | width
| | Conditional | Product
> Width
| We need to send either all 3 of length
, width
and depth
or none of them. |
| | | depth
| | Conditional | Product
> Height
| We need to send either all 3 of length
, width
and depth
or none of them.. |
| | | distanceUnit
| | Conditional | | Hardcoded as ‘cm’ . We want to exclude this if we are not sending any measurements. |
| | saleType
| | | No | Product Account
Tesco
> Sale Type
| New field!
Should be an enumeration dropdown with the following options :
- Buy Online sent as
BUY_ONLINE
- Buy Online & Click and Collect sent as
BUY_ONLINE_OR_CLICK_AND_COLLECT
- Click and Collect sent as
CLICK_AND_COLLECT
Our default option should be empty and if we have empty option, we sendBUY_ONLINE
as default when creating products. | | |attemptAutoPublish
| | | No |Product Account Tesco
>Auto Publish
| New field. Should be a radio button with options “Yes” and “No”. When Yes is selected we sendtrue
When No is selected we sendfalse
Default option should be “Yes” | | |images
| | | | | | | | |sourceUrl
| | Yes | (2) Main Image(s), (1) Listing Image AND (3) More Images | As per the images abstraction - Images Handling Additional Explanation | | |advertOptionValues
| | | | | | | | |optionValueId
| | Yes |Product Account
>Item Specifics
| We need to send the ID corresponding to the item specific name | | | |optionTypeId
| | No |Product Account
>Item Specifics
| We need to send the ID corresponding to the item specific name. We only need to send this if we have FREE_TEXT field type in the taxonomy | | | |textValue
| | Conditional |Product Account
>Item Specifics Value
| This becomes required if we are sendingoptionTypeId
| | |variants
| | | | | | | | |id
| | Yes |Product Account
Tesco
>Variant ID
| | | | |description
| | No |Product Account
>Description
| | | | |sku
| | No |Product
>SKU
| | | | |barcode
| | No |Product Account
>Marketplace EAN
ORProduct
>EAN
ORProduct
>Barcode
ORProduct
>MPN
ORProduct
>UPC
|Product Account
is with priority. The priority in the other fields is : EAN, Barcode, MPN, UPC | | | |price
| | No |Product Account
>RRP
| This must be excluded if we haveProtect Price
= Yes | | | |salePrice
| | No |Product Account
>Price
| This must be excluded if we haveProtect Price
= Yes | | | |countOnHand
| | No |Product Account
>Quantity
| This must be excluded if we haveProtect Quantity
= Yes | | | |images
| | | | | | | | |sourceUrl
| No | (2) Main Image | We want to have a logic and only send the Main image for the specific variant Images Handling Additional Explanation | | | |variantOptionValues
| | | | | | | | |optionValueId
| Yes |Product Account
>Variation Specifics
| | | | | |optionTypeId
| No |Product Account
>Variation Specifics
| | | | | |textValue
| Conditional |Product Account
>Variation Specifics Value
| This becomes required if we are sendingoptionTypeId
|
<v1.2>Example response :
{
"data": {
"advertUpsert": {
"advert": {
"id": "QWR2ZXJ0LTEwMDEwMjIwMg==",
"statusText": "Invalid",
"displayable": false,
"catalogRulesErrors": [
{
"errorMessage": "Product description must be greater than 10 characters",
"fieldName": "description",
"objectId": "26533820"
}
],
"legacyId": 100102202,
"variants": {
"nodes": [
{
"sku": "321123",
"id": "VmFyaWFudC0xMzA3NTQ=",
"displayable": true
},
{
"sku": "1234561",
"id": "VmFyaWFudC0xMzA3NTM=",
"displayable": true
}
]
}
},
"errors": null
}
}
}
<v1.1>Response Mapping :
Integration Field | McPro Field | Notes | |||||
---|---|---|---|---|---|---|---|
data |
|||||||
advertUpsert |
|||||||
advert |
|||||||
id |
We want to use this id to map with Product Account > Channel Item ID and find which product we need to store the error into. |
||||||
<v1.2> statusText |
N/A | ||||||
displayable |
Based on this we want to update the Listings > Product Status : |
If we have displayable
= true, we set the status to Product Published
If we have displayable
= false, we leave the status as it is </v1.2> |
| | | | catalogRulesErrors
| | | | |
| | | | | errorMessage
| | Product Account
> Update item error
| |
| | | | | fieldName
| | | |
| | | | | objectId
| | | |
| | | | legacyId
| | | | |
| | | | variants
| | | | |
| | | | | nodes
| | | |
| | | | | | sku
| | We map this to find out which SKU we need to apply the below logic to. |
| | | | | | id
| | |
| | | | | | displayable
| | This is a boolean flag. We need to create a logic :
If we receive this as false
or if we have 0 quantity for the product, we set Product Account
> Listing Status
= Inactive
In any other case, we set Product Account
> Listing Status
= Active |
| | | errors
| | | | | |
We want to act and update as per the listing abstraction Product Listing general requirements depending on if the update was successful or any errors will need to be stored. </v1.1>