Bulk Order Import
This guide describes a mutation allowing users to create multiple orders in Saleor. Purpose of this mutation could be importing orders from other systems. The main assumption is to allow the user to specify as many fields as possible and skip most of the logic and calculations that are done when creating orders from draft or checkout. Among other things, the mutation allows specifying things like: order creation date, order number, order lines with net and gross line prices, payment transactions and fulfillments.
orderBulkCreate
Mutation example:
mutation OrderBulkCreate(
$orders: [OrderBulkCreateInput!]!
$errorPolicy: ErrorPolicyEnum
$stockUpdatePolicy: StockUpdatePolicyEnum
) {
orderBulkCreate(
orders: $orders
errorPolicy: $errorPolicy
stockUpdatePolicy: $stockUpdatePolicy
) {
count
results {
order {
id
user {
id
email
}
metadata {
key
value
}
privateMetadata {
key
value
}
lines {
id
variant {
id
}
productName
variantName
translatedVariantName
translatedProductName
productVariantId
isShippingRequired
quantity
quantityFulfilled
unitPrice {
gross {
amount
}
net {
amount
}
}
unitDiscount {
amount
}
totalPrice {
gross {
amount
}
net {
amount
}
}
undiscountedUnitPrice {
gross {
amount
}
net {
amount
}
}
metadata {
key
value
}
privateMetadata {
key
value
}
taxClass {
id
}
taxClassName
taxRate
taxClassMetadata {
key
value
}
taxClassPrivateMetadata {
key
value
}
}
billingAddress {
postalCode
}
shippingAddress {
postalCode
}
shippingMethodName
shippingTaxClass {
name
}
shippingTaxClassName
shippingTaxClassMetadata {
key
value
}
shippingTaxClassPrivateMetadata {
key
value
}
shippingPrice {
gross {
amount
}
net {
amount
}
}
total {
gross {
amount
}
net {
amount
}
}
undiscountedTotal {
gross {
amount
}
net {
amount
}
}
events {
message
user {
id
}
app {
id
}
}
weight {
value
}
externalReference
trackingClientId
displayGrossPrices
channel {
slug
}
status
created
languageCode
collectionPointName
redirectUrl
origin
fulfillments {
lines {
quantity
orderLine {
id
}
}
trackingNumber
fulfillmentOrder
status
}
transactions {
id
reference
type
status
authorizedAmount {
amount
currency
}
canceledAmount {
currency
amount
}
chargedAmount {
currency
amount
}
refundedAmount {
currency
amount
}
events {
amount {
amount
}
type
}
}
invoices {
number
url
}
discounts {
valueType
value
reason
}
}
errors {
path
message
code
}
}
}
}
Input example:
{
"stockUpdatePolicy": "SKIP",
"errorPolicy": "REJECT_EVERYTHING",
"orders": [
{
"channel": "default-channel",
"createdAt": "2022-07-13T17:30:15+05:30",
"status": "DRAFT",
"user": {
"email":"alec.thornton@example.com"
},
"billingAddress": {
"firstName": "John Saleor",
"lastName": "Doe Mirumee",
"companyName": "Mirumee Software",
"streetAddress1": "Tęczowa 7",
"streetAddress2": "",
"postalCode": "53-601",
"country": "PL",
"city": "Wrocław",
"countryArea": "",
"phone": "+48321321888"
},
"currency": "PLN",
"languageCode": "PL",
"deliveryMethod": {
"shippingMethodId": "U2hpcHBpbmdNZXRob2Q6MQ==",
"shippingTaxClassId": "VGF4Q2xhc3M6MQ==",
"shippingPrice": {
"gross": 120,
"net": 100
},
"shippingTaxRate": 0.2,
"shippingTaxClassMetadata": [
{
"key": "md key",
"value": "md value"
}
],
"shippingTaxClassPrivateMetadata": [
{
"key": "pmd key",
"value": "pmd value"
}
]
},
"lines": [
{
"variantId": "UHJvZHVjdFZhcmlhbnQ6NDAz",
"createdAt": "2022-07-20T17:30:15+05:30",
"productName": "Product Name",
"variantName": "Variant Name",
"translatedProductName": "Nazwa Produktu",
"translatedVariantName": "Nazwa Wariantu",
"isShippingRequired": true,
"isGiftCard": false,
"quantity": 5,
"totalPrice": {
"gross": 120,
"net": 100
},
"undiscountedTotalPrice": {
"gross": 120,
"net": 100
},
"warehouse": "V2FyZWhvdXNlOmZiMWNkYzNmLWVhYmYtNDQxNC1iZTFhLTFkNWEwZTA5YzA2OA==",
"taxRate": 0.2,
"taxClassId": "VGF4Q2xhc3M6MQ==",
"taxClassName": "Line Tax Class Name",
"taxClassMetadata": [
{
"key": "md key",
"value": "md value"
}
],
"taxClassPrivateMetadata": [
{
"key": "pmd key",
"value": "pmd value"
}
]
}
],
"fulfillments": [
{
"trackingCode": "abc-123",
"lines": [
{
"variantId": "UHJvZHVjdFZhcmlhbnQ6NDAz",
"quantity": 5,
"warehouse": "V2FyZWhvdXNlOmZiMWNkYzNmLWVhYmYtNDQxNC1iZTFhLTFkNWEwZTA5YzA2OA==",
"orderLineIndex": 0
}
]
}
],
"transactions": [
{
"status": "Authorized for 10$",
"reference": "PSP reference - 123",
"availableActions": [
"REFUND",
"CANCEL"
],
"amountAuthorized": {
"amount": 120,
"currency": "PLN"
},
"amountCharged": {
"amount": 120,
"currency": "PLN"
},
"metadata": [
{
"key": "md key",
"value": "md value"
}
],
"privateMetadata": [
{
"key": "pmd key",
"value": "pmd value"
}
]
}
],
"invoices": [
{
"number": "01/12/2020/TEST",
"url": "http://www.example.com",
"createdAt": "2022-07-13T17:30:15+05:30",
"metadata": [
{
"key": "md key",
"value": "md value"
}
],
"privateMetadata": [
{
"key": "pmd key",
"value": "pmd value"
}
]
}
],
"discounts": [
{
"valueType": "FIXED",
"value": 10,
"reason": "Black Friday"
}
],
"giftCards": ["Gift_card_1"],
"voucherCode": "FREESHIPPING",
"weight": "10.15",
"trackingClientId": "tracking-id-123",
"metadata": [
{
"key": "md key",
"value": "md value"
}
],
"privateMetadata": [
{
"key": "pmd key",
"value": "pmd value"
}
]
}
]
}
Expected response:
{
"data": {
"orderBulkCreate": {
"count": 1,
"results": [
{
"order": {
"id": "T3JkZXI6NDQxYzhlYzItNDA0ZC00NmEwLWEwMDMtNmY2MjgzMTRmNTNi",
"user": {
"id": "VXNlcjoxODEyMzc4ODk1",
"email": "alec.thornton@example.com"
},
"metadata": [
{
"key": "md key",
"value": "md value"
}
],
"privateMetadata": [
{
"key": "pmd key",
"value": "pmd value"
}
],
"lines": [
{
"id": "T3JkZXJMaW5lOmQyYzdhODk1LTgxZTctNGIxOC04MjZjLThkMWUyMDVlMDI1YQ==",
"variant": {
"id": "UHJvZHVjdFZhcmlhbnQ6NDAz"
},
"productName": "Product Name",
"variantName": "Variant Name",
"translatedVariantName": "Nazwa Wariantu",
"translatedProductName": "Nazwa Produktu",
"productVariantId": "UHJvZHVjdFZhcmlhbnQ6NDAz",
"isShippingRequired": true,
"quantity": 5,
"quantityFulfilled": 5,
"unitPrice": {
"gross": {
"amount": 24.0
},
"net": {
"amount": 20.0
}
},
"unitDiscount": {
"amount": 0.0
},
"totalPrice": {
"gross": {
"amount": 120.0
},
"net": {
"amount": 100.0
}
},
"undiscountedUnitPrice": {
"gross": {
"amount": 24.0
},
"net": {
"amount": 20.0
}
},
"metadata": [],
"privateMetadata": [],
"taxClass": {
"id": "VGF4Q2xhc3M6MQ=="
},
"taxClassName": "Line Tax Class Name",
"taxRate": 0.2,
"taxClassMetadata": [
{
"key": "md key",
"value": "md value"
}
],
"taxClassPrivateMetadata": [
{
"key": "pmd key",
"value": "pmd value"
}
]
}
],
"billingAddress": {
"postalCode": "53-601"
},
"shippingAddress": null,
"shippingMethodName": "DHL",
"shippingTaxClass": null,
"shippingTaxClassName": "No Taxes",
"shippingTaxClassMetadata": [
{
"key": "md key",
"value": "md value"
}
],
"shippingTaxClassPrivateMetadata": [
{
"key": "pmd key",
"value": "pmd value"
}
],
"shippingPrice": {
"gross": {
"amount": 120.0
},
"net": {
"amount": 100.0
}
},
"total": {
"gross": {
"amount": 120.0
},
"net": {
"amount": 100.0
}
},
"undiscountedTotal": {
"gross": {
"amount": 120.0
},
"net": {
"amount": 100.0
}
},
"events": [],
"weight": {
"value": 10.15
},
"externalReference": null,
"trackingClientId": "tracking-id-123",
"displayGrossPrices": true,
"channel": {
"slug": "default-channel"
},
"status": "DRAFT",
"created": "2022-07-13T17:30:15+05:30",
"languageCode": "pl",
"collectionPointName": null,
"redirectUrl": null,
"origin": "BULK_CREATE",
"fulfillments": [
{
"lines": [
{
"quantity": 5,
"orderLine": {
"id": "T3JkZXJMaW5lOmQyYzdhODk1LTgxZTctNGIxOC04MjZjLThkMWUyMDVlMDI1YQ=="
}
}
],
"trackingNumber": "abc-123",
"fulfillmentOrder": 1,
"status": "FULFILLED"
}
],
"transactions": [
{
"id": "VHJhbnNhY3Rpb25JdGVtOjI3MTYwYWRlLTA4ZWYtNDhiNC05OWE1LTFkNWExOWYzZDhkNA==",
"reference": "PSP reference - 123",
"type": "",
"status": "Authorized for 10$",
"authorizedAmount": {
"amount": 120.0,
"currency": "PLN"
},
"canceledAmount": {
"currency": "PLN",
"amount": 0.0
},
"chargedAmount": {
"currency": "PLN",
"amount": 120.0
},
"refundedAmount": {
"currency": "PLN",
"amount": 0.0
},
"events": [
{
"amount": {
"amount": 120.0
},
"type": "CHARGE_SUCCESS"
},
{
"amount": {
"amount": 120.0
},
"type": "AUTHORIZATION_SUCCESS"
}
]
}
],
"invoices": [
{
"number": "01/12/2020/TEST",
"url": "http://www.example.com"
}
],
"discounts": [
{
"valueType": "FIXED",
"value": 10.0,
"reason": "Black Friday"
}
]
},
"errors": []
}
]
}
},
"extensions": {
"cost": {
"requestedQueryCost": 22,
"maximumAvailable": 50000
}
}
}
Permission
Since this operation is broader in scope than regular order management, it is not automatically assigned to staff users or apps with MANAGE_ORDERS
permission. The mutation requires a new permission: MANAGE_ORDERS_IMPORT
.
Input details
User (OrderBulkCreateUserInput
)
To identify a user, the mutation accepts one of the following identifiers: id
, email
or external_reference
. If the user associated with an order doesn’t exist in Saleor database, user's email can be provided as a reference in the order instance.
If you want to skip adding user, you need to use IGNORE_FAILED
policy.
Delivery method (OrderBulkCreateDeliveryMethodInput
)
Since orders can be either shipped or collected directly from a warehouse, either warehouseId
or shippingMethodId
must be provided. Orders with all lines set isShippingRequired
flag to false
don't require physical delivery. In this case, OrderBulkCreateDeliveryMethodInput
can be omitted.
The input also accepts arbitrary names of delivery methods (warehouseName
and shippingMethodName
fields) and tax class (taxClassName
).
If shippingPrice
is not provided, Saleor will fetch the current shipping method price from database.
Order line (OrderBulkCreateOrderLineInput
)
totalPrice
and undiscountedTotalPrice
are the primary sources of truth about the order pricing. Based on the fields, Saleor calculates unit price, undiscounted unit price, unit discount amount, order total and subtotal.
To find product variant, the mutation accepts one of the following identifiers: id
, sku
or external_reference
.
The input also accepts arbitrary names of variant (variantName
), product (productName
) and tax class (taxClassName
).
isShippingRequired
- determines if line items need to be physically shipped. If all lines of an order do not require shipping, OrderBulkCreateInput.deliveryMethod
can be skipped.
warehouse
- ID of the warehouse, where the order line should be allocated. It is required to check stock availability.
Fulfillments (OrderBulkCreateFulfillmentLineInput
)
Product variant is searched by one of the following identifiers: id
, sku
or external_reference
.
To match fulfillment line with respective order line, OrderBulkCreateFulfillmentLineInput
requires orderLineIndex
. It is a 0-based index of OrderBulkCreateInput.lines
list.
Notes (OrderBulkCreateNoteInput
)
The input allows to provide a custom list of events that would be saved as OrderEvent
instances in the order history. For each event, the user can provide a message, timestamp, and either a user or an app that is associated with the event.
Gift cards and vouchers
The input accepts a list of gift card codes and a single voucher code that should be associated with the order, but it doesn’t trigger any price recalculation. Prices are based only on line totals. Please note, that the voucher is not validated during import, therefore code usage will not be counted.
CreatedAt fields
Some systems might have incorrect time that is in the future compared to Saleor. Therefore mutation accepts future time values within 5 minutes from current time. createdAt
is required field in following inputs:
OrderBulkCreateInput
OrderBulkCreateOrderLineInput
OrderBulkCreateInvoiceInput
Stock update policy
The policy determines how stocks should be updated, while processing an order.
UPDATE
(default) - only do an update, if there is enough stock. Otherwise produce an error.SKIP
- stocks are not checked and not updated.FORCE
- force update, if there is not enough stock.
Error policy
orderBulkCreate
mutation as well as other new bulk mutations accepts errorPolicy
argument, which determines how to handle errors. But please note, that some of errors ignore this policy and disqualify whole order:
- order number is not unique
- invalid billing address
- channel can’t be resolved
- delivery method can’t be resolved (if shipping is required)
- at least one of the order lines can’t be created
- at least one of the fulfillments can’t be created
- not enough or non-existing stocks (taking into account
stockUpdatePolicy
)
Webhooks
If successful, the mutation will emit ORDER_BULK_CREATE
event with a list of all created orders.