Australia Post zones and rate data for importing to Shopify.
This project contains PowerShell scripts that can be used to upload shipping rates to Shopify via the API.
You will need to have PowerShell Core (crossplatform) installed to run the scripts.
In the Shopfiy admin, go to Apps > Manage private apps.
You will need to enable private apps, and then create a new app (call it something like "AusPost Rates" or "Data Manager", or whatever name makes sense to you). It will need Read and write permission to Shipping, as well as other functions you want to use, e.g. to use scripts to add products to shipping, you need Read access to Products.
Record the API parameters in variables, which will be used in other scripts. For graph queries you will need the 'Password' value (you don't need the API key for Shared Secret).
$password = '<Password>'
$shopName = '<shop name>'
First set up the base URL and headers, using the variables above.
$uri = "https://$shopName.myshopify.com/admin/api/2021-01/graphql.json"
$headers = @{
'Content-Type' = 'application/graphql';
'X-Shopify-Access-Token' = $password
}
A simple query can be used to check the existing shipping profiles.
$body = '{
deliveryProfiles(first:10) {
edges {
node {
id
name
default
}
}
}
}'
Invoke-RestMethod -Method Post -Uri $uri -Headers $headers -Body $body | ConvertTo-Json -Depth 5
You can also interactively test out queries in the Shopify API developer documentation site: https://shopify.dev/docs/admin-api/graphql/reference/shipping-and-fulfillment/deliveryprofile#samples
You will need to get the delivery profile ID's and location group ID's to use in other queries.
$body = '{
deliveryProfiles(first:10) {
edges {
node {
id
name
default
profileLocationGroups {
locationGroup {
id
}
}
}
}
}
}'
$deliveryProfiles = Invoke-RestMethod -Method Post -Uri $uri -Headers $headers -Body $body
$defaultProfileId = ($deliveryProfiles.data.deliveryProfiles.edges | Where-Object { $_.node.default }).node.id
$defaultProfileId
Parametised queries use application/json
instead of raw application/graphql
, with the query passed as a string
parameter.
You can view the content of a profile, for the zone definitions with the countries in that zone and the list of delivery methods and prices (for different methods or conditions).
Use this to examine your current profiles, or to check the contents after you have created a new profile for Australia Post.
$jsonHeaders = @{
'Content-Type' = 'application/json';
'X-Shopify-Access-Token' = $password
}
$getDeliveryProfileQuery = 'query($id: ID!)
{
deliveryProfile (id: $id) {
profileLocationGroups {
locationGroupZones (first: 20) {
edges {
node {
zone {
id
name
countries {
id
name
code {
countryCode
restOfWorld
}
provinces {
id
code
name
}
}
}
methodDefinitions (first:8) {
edges {
node {
id
name
active
methodConditions {
conditionCriteria {
... on Weight {
unit
value
}
}
field
operator
}
rateProvider {
... on DeliveryRateDefinition {
id
price {
currencyCode
amount
}
}
}
}
}
}
}
}
}
}
}
}'
$getDeliveryProfileData = @{
query = $getDeliveryProfileQuery;
variables = @{
id = $defaultProfileId;
}
}
$defaultProfileDetails = Invoke-RestMethod -Method Post -Uri $uri -Headers $jsonHeaders -Body (ConvertTo-Json -Depth 3 $getDeliveryProfileData)
$defaultProfileDetails | ConvertTo-Json -Depth 15
This outputs a summary of the zone name, and countries and provinces allocated to that zone.
$zoneData = $defaultProfileDetails.data.deliveryProfile.profileLocationGroups[0].locationGroupZones.edges | ForEach-Object {
$zone = $_.node.zone
$zone.countries | ForEach-Object {
$country = $_
if ($country.code.restOfWorld) {
[PSCustomObject]@{ zone = $zone.name; country = $null; countryName = $null; province = $null; provinceName = $null }
} else {
if (-not $country.provinces) {
[PSCustomObject]@{ zone = $zone.name; country = $country.code.countryCode; countryName = $country.name; province = $null; provinceName = $null }
} else {;
$country.provinces | ForEach-Object {
$province = $_
[PSCustomObject]@{ zone = $zone.name; country = $country.code.countryCode; countryName = $country.name; province = $province.code; provinceName = $province.name }
}
}
}
}
}
$zoneData | Format-Table
This can then be saved to a comma separated value (CSV) file, e.g. for manipulation in a spreadsheet program.
$zoneData | Export-Csv 'data/zone-country-province.csv'
Create a new profile named 'Australia Post' to load the data into.
Use the data files to create zones and assign countries to them, then load the shipping rates for the zones.
The Shopify API reference for delivery profile updates is: https://shopify.dev/docs/admin-api/graphql/reference/shipping-and-fulfillment/deliveryprofileupdate
Get the profile you want to update based on the name:
$deliveryProfile = $deliveryProfiles.data.deliveryProfiles.edges | Where-Object { $_.node.name -eq 'General Profile' }
$deliveryProfile.node.profileLocationGroups | Measure-Object
$locationGroupId = $deliveryProfile.node.profileLocationGroups[0].locationGroup.id
A zone-country CSV data file can be used to create zone information for input.
$zoneCountryData = Import-Csv 'data/auspost-zone-country-province.csv'
$zonesToCreate = [System.Collections.ArrayList]@()
$zoneInput = $null
$zoneCountryData | ForEach-Object {
$line = $_
if ($line.zone -ne $zoneInput.name) {
$zoneInput = @{ name = $line.zone; countries = [System.Collections.ArrayList]@() }
$countryInput = $null
$i = $zonesToCreate.Add($zoneInput)
}
if (-not $line.country) {
$i = $zoneInput.countries.Add(@{ restOfWorld = $true })
} else {
if ($line.country -ne $countryInput.code) {
if ($line.province) {
$countryInput = @{ code = $line.country; provinces = [System.Collections.ArrayList]@() }
} else {
$countryInput = @{ code = $line.country; includeAllProvinces = $true }
}
$i = $zoneInput.countries.Add($countryInput)
}
if ($line.province) {
$i = $countryInput.provinces.Add(@{ code = $line.province })
}
}
}
$zonesToCreate | ConvertTo-Json -Depth 5
Within a profile, each location group that you ship from has different rates. In the example below there is only one location group to update.
Use the profile selected above, and add the zones to create to the profile location group ID.
$profileLocationGroupInput = @{ id = $locationGroupId; zonesToCreate = $zonesToCreate }
Send this as an update.
$updateProfileQuery = 'mutation($id: ID!, $profile: DeliveryProfileInput!) {
deliveryProfileUpdate (id: $id, profile: $profile)
{
profile {
id
name
profileLocationGroups {
locationGroupZones (first: 15) {
edges {
node {
zone {
id
name
}
methodDefinitions (first:20) {
edges {
node {
id
name
rateProvider {
... on DeliveryRateDefinition {
id
price {
currencyCode
amount
}
}
}
}
}
}
}
}
}
}
}
userErrors {
field
message
}
}
}'
$addZones = @{
query = $updateProfileQuery;
variables = @{
id = $deliveryProfile.node.id;
profile = @{
locationGroupsToUpdate = @( $profileLocationGroupInput )
}
}
}
$addZonesResult = Invoke-RestMethod -Method Post -Uri $uri -Headers $jsonHeaders -Body (ConvertTo-Json -Depth 10 $addZones)
$addZonesResult
To update the zones we have created with the rates, first we need to get the created zone IDs.
$getDeliveryProfileZonesQuery = 'query($id: ID!)
{
deliveryProfile (id: $id) {
profileLocationGroups {
locationGroupZones (first: 15) {
edges {
node {
zone {
id
name
}
}
}
}
}
}
}'
$getDeliveryProfileZonesData = @{
query = $getDeliveryProfileZonesQuery;
variables = @{
id = $deliveryProfile.node.id;
}
}
$profileZones = Invoke-RestMethod -Method Post -Uri $uri -Headers $jsonHeaders -Body (ConvertTo-Json -Depth 3 $getDeliveryProfileZonesData)
$zoneIdsAndNames = $profileZones.data.deliveryProfile.profileLocationGroups[0].locationGroupZones.edges.node.zone
$zoneIdsAndNames | Measure-Object
Read the data file and use it to build the zone updates adding the method definitions.
$zoneRateData = Import-Csv 'data/auspost-rates-to-5kg.csv'
$zonesToUpdate = [System.Collections.ArrayList]@()
$currentZone = $null
$zoneRateData | ForEach-Object {
$line = $_
if ($line.zone -ne $currentZone) {
$currentZone = $line.zone
$zone = $zoneIdsAndNames | Where-Object { $_.name -eq $currentZone}
if (-not $zone) { throw "Zone $($_.name) not found" }
$zoneInput = @{ id = $zone.id; methodDefinitionsToCreate = [System.Collections.ArrayList]@() }
$i = $zonesToUpdate.Add($zoneInput)
}
$weightConditionsInput = [System.Collections.ArrayList]@()
if ([decimal]$line.lessThanKg) {
$i = $weightConditionsInput.Add(@{ criteria = @{ unit = 'GRAMS'; value = [decimal]$line.lessThanKg * 1000; }; operator = 'LESS_THAN_OR_EQUAL_TO' })
}
if ([decimal]$line.greaterThanKg) {
$i = $weightConditionsInput.Add(@{ criteria = @{ unit = 'GRAMS'; value = [decimal]$line.greaterThanKg * 1000; }; operator = 'GREATER_THAN_OR_EQUAL_TO' })
}
$methodInput = @{
active = $true;
name = $line.method;
rateDefinition = @{ price = @{ amount = [decimal]$line.rateAud; currencyCode = 'AUD' } };
weightConditionsToCreate = $weightConditionsInput;
}
$i = $zoneInput.methodDefinitionsToCreate.Add($methodInput)
}
$zonesToUpdate | ConvertTo-Json -Depth 6
$updateProfileQuery = 'mutation($id: ID!, $profile: DeliveryProfileInput!) {
deliveryProfileUpdate (id: $id, profile: $profile)
{
profile {
id
name
profileLocationGroups {
locationGroupZones (first: 15) {
edges {
node {
zone {
id
name
}
methodDefinitions (first:40) {
edges {
node {
id
name
}
}
}
}
}
}
}
}
userErrors {
field
message
}
}
}'
$profileLocationGroupUpdateInput = @{ id = $locationGroupId; zonesToUpdate = $zonesToUpdate }
If you are replacing rates continue back in the replacing instructions (see below); otherwise continue to add the new rates.
$addRates = @{
query = $updateProfileQuery;
variables = @{
id = $deliveryProfile.node.id;
profile = @{
locationGroupsToUpdate = @( $profileLocationGroupUpdateInput )
}
}
}
$addRatesResult = Invoke-RestMethod -Method Post -Uri $uri -Headers $jsonHeaders -Body (ConvertTo-Json -Depth 11 $addRates)
$addRatesResult
To replace existing rates, you remove all the old method definitions for that profile, and create new ones.
Get the existing profile ID, based on the name (change the name to update different profiles)
$deliveryProfile = $deliveryProfiles.data.deliveryProfiles.edges | Where-Object { $_.node.name -eq 'General Profile' }
First get the existing rates. This uses the query from 'Get existing shipping profile information', with the Australia Post delivery profile.
$getDeliveryProfileData = @{
query = $getDeliveryProfileQuery;
variables = @{
id = $deliveryProfile.node.id;
}
}
$profileDetails = Invoke-RestMethod -Method Post -Uri $uri -Headers $jsonHeaders -Body (ConvertTo-Json -Depth 3 $getDeliveryProfileData)
The list of existing delivery method definitions can be easily shown:
$methodsToDelete = $profileDetails.data.deliveryProfile.profileLocationGroups.locationGroupZones.edges.node.methodDefinitions.edges.node.id
$methodsToDelete
Then follow the instructions in 'Read shipping rate data' and 'Uploading rates' up to the point where
$profileLocationGroupUpdateInput
is created.
Then use both $profileLocationGroupUpdateInput
and $methodsToDelete
to update the rates.
$updateRates = @{
query = $updateProfileQuery;
variables = @{
id = $deliveryProfile.node.id;
profile = @{
methodDefinitionsToDelete = $methodsToDelete
locationGroupsToUpdate = @( $profileLocationGroupUpdateInput )
}
}
}
$updateRatesResult = Invoke-RestMethod -Method Post -Uri $uri -Headers $jsonHeaders -Body (ConvertTo-Json -Depth 15 $updateRates)
$updateRatesResult
If the data doesn't update in one go cleanly, e.g. you get multiple rate definitions, try deleting separately. Run this, then query the rates again (above, at the start of 'Replacing existing rates') and see if there are any more to delete.
You may need to delete and check multiple times, as it may only do a few (e.g. 40) rows at a time. Check the IDs change each time you query a batch to be deleted:
$updateRates = @{
query = $updateProfileQuery;
variables = @{
id = $deliveryProfile.node.id;
profile = @{
methodDefinitionsToDelete = $methodsToDelete
}
}
}
$updateRatesResult = Invoke-RestMethod -Method Post -Uri $uri -Headers $jsonHeaders -Body (ConvertTo-Json -Depth 15 $updateRates)
$updateRatesResult
New rates:
$updateRates = @{
query = $updateProfileQuery;
variables = @{
id = $deliveryProfile.node.id;
profile = @{
locationGroupsToUpdate = @( $profileLocationGroupUpdateInput )
}
}
}
$updateRatesResult = Invoke-RestMethod -Method Post -Uri $uri -Headers $jsonHeaders -Body (ConvertTo-Json -Depth 15 $updateRates)
$updateRatesResult
Get details of the existing profile you want to replace:
$getDeliveryProfileData = @{
query = $getDeliveryProfileQuery;
variables = @{
id = $deliveryProfile.node.id;
}
}
$profileDetails = Invoke-RestMethod -Method Post -Uri $uri -Headers $jsonHeaders -Body (ConvertTo-Json -Depth 3 $getDeliveryProfileData)
Get all existing location group zones:
$zonesToDelete = $profileDetails.data.deliveryProfile.profileLocationGroups.locationGroupZones.edges.node.zone.id
$zonesToDelete
Then delete them:
$deleteZones = @{
query = $updateProfileQuery;
variables = @{
id = $deliveryProfile.node.id
profile = @{
zonesToDelete = $zonesToDelete
}
}
}
$deleteZonesResult = Invoke-RestMethod -Method Post -Uri $uri -Headers $jsonHeaders -Body (ConvertTo-Json -Depth 11 $deleteZones)
$deleteZonesResult
Get a list of all products you want to assign, e.g. from one vendor.
$getProductsQuery = 'query($first: Int, $filter: String)
{
products(first: $first, query: $filter) {
edges {
node {
id
handle
vendor
status
variants (first: 2) {
edges {
node {
id
title
}
}
}
}
}
pageInfo {
hasNextPage
}
}
}
'
$getProductsData = @{
query = $getProductsQuery;
variables = @{
first = 150;
filter = 'vendor:"Wholesale (AU)"'
}
}
$wholesaleProducts = Invoke-RestMethod -Method Post -Uri $uri -Headers $jsonHeaders -Body (ConvertTo-Json -Depth 3 $getProductsData)
$wholesaleProducts.data.products.edges.node | Measure-Object
You can further filter the objects based on properties.
Then use an update query to add them to a delivery profile.
$activeProducts = $wholesaleProducts.data.products.edges.node | ? { $_.status -eq 'ACTIVE' }
$activeProducts | Measure-Object
$activeDeliveryProfileId = ($deliveryProfiles.data.deliveryProfiles.edges | Where-Object { $_.node.name -eq 'Australia Post' }).node.id
$updateProfileQuery = 'mutation($id: ID!, $profile: DeliveryProfileInput!) {
deliveryProfileUpdate (id: $id, profile: $profile)
{
profile {
id
name
profileItems (first: 150) {
edges {
node {
product {
id
handle
vendor
}
variants (first: 2) {
edges {
node {
id
title
}
}
}
}
}
}
}
userErrors {
field
message
}
}
}'
$addActiveProducts = @{
query = $updateProfileQuery;
variables = @{
id = $activeDeliveryProfileId;
profile = @{
variantsToAssociate = $activeProducts.variants.edges.node.id
}
}
}
$addResult1 = Invoke-RestMethod -Method Post -Uri $uri -Headers $jsonHeaders -Body (ConvertTo-Json -Depth 4 $addActiveProducts)
$addResult1
You can reuse the same query with different variables:
$otherProducts = $wholesaleProducts.data.products.edges.node | ? { $_.status -ne 'ACTIVE' }
$otherProducts | Measure-Object
$otherDeliveryProfileId = ($deliveryProfiles.data.deliveryProfiles.edges | Where-Object { $_.node.name -eq 'Australia Post 2' }).node.id
$addOtherProducts = @{
query = $updateProfileQuery;
variables = @{
id = $otherDeliveryProfileId;
profile = @{
variantsToAssociate = $otherProducts.variants.edges.node.id
}
}
}
$addResult2 = Invoke-RestMethod -Method Post -Uri $uri -Headers $jsonHeaders -Body (ConvertTo-Json -Depth 4 $addOtherProducts)
$addResult2.data.deliveryProfileUpdate.profile
To update the rates in a second profile.
Follow the process up to Get existing shipping profile information, where you have retrieved $deliveryProfiles
. To see all the profile names you can query $deliveryProfiles.data.deliveryProfiles.edges
.
Note: Use the name of the rate you want to change, e.g. 'Wholesale Shipping':
$deliveryProfile2 = $deliveryProfiles.data.deliveryProfiles.edges | Where-Object { $_.node.name -eq 'Wholesale Shipping' }
$deliveryProfile2.node.profileLocationGroups | Measure-Object
$locationGroupId2 = $deliveryProfile2.node.profileLocationGroups[0].locationGroup.id
Get the existing profile details:
$getDeliveryProfileData2 = @{
query = $getDeliveryProfileQuery;
variables = @{
id = $deliveryProfile2.node.id;
}
}
$profileDetails2 = Invoke-RestMethod -Method Post -Uri $uri -Headers $jsonHeaders -Body (ConvertTo-Json -Depth 3 $getDeliveryProfileData2)
Then convert that to the rates to be deleted:
$methodsToDelete2 = $profileDetails2.data.deliveryProfile.profileLocationGroups.locationGroupZones.edges.node.methodDefinitions.edges.node.id
$methodsToDelete2
Then follow the instructions in 'Read shipping rate data' and 'Uploading rates' up to the point where
$profileLocationGroupUpdateInput
is created.
Get the created zone IDs.
$getDeliveryProfileZonesQuery = 'query($id: ID!)
{
deliveryProfile (id: $id) {
profileLocationGroups {
locationGroupZones (first: 15) {
edges {
node {
zone {
id
name
}
}
}
}
}
}
}'
$getDeliveryProfileZonesData2 = @{
query = $getDeliveryProfileZonesQuery;
variables = @{
id = $deliveryProfile2.node.id;
}
}
$profileZones2 = Invoke-RestMethod -Method Post -Uri $uri -Headers $jsonHeaders -Body (ConvertTo-Json -Depth 3 $getDeliveryProfileZonesData2)
$zoneIdsAndNames2 = $profileZones2.data.deliveryProfile.profileLocationGroups[0].locationGroupZones.edges.node.zone
$zoneIdsAndNames2 | Measure-Object
Read the data file and use it to build the zone updates adding the method definitions.
Note: Use the file name of the rates being changed, e.g. 'data/auspost-rates-discounted-insured-express-to-4kg.csv'
$zoneRateData2 = Import-Csv 'data/auspost-rates-discounted-insured-express-to-5kg.csv'
$zonesToUpdate2 = [System.Collections.ArrayList]@()
$currentZone = $null
$zoneRateData2 | ForEach-Object {
$line = $_
if ($line.zone -ne $currentZone) {
$currentZone = $line.zone
$zone = $zoneIdsAndNames2 | Where-Object { $_.name -eq $currentZone}
if (-not $zone) { throw "Zone $($_.name) not found" }
$zoneInput = @{ id = $zone.id; methodDefinitionsToCreate = [System.Collections.ArrayList]@() }
$i = $zonesToUpdate2.Add($zoneInput)
}
$weightConditionsInput = [System.Collections.ArrayList]@()
if ([decimal]$line.lessThanKg) {
$i = $weightConditionsInput.Add(@{ criteria = @{ unit = 'GRAMS'; value = [decimal]$line.lessThanKg * 1000; }; operator = 'LESS_THAN_OR_EQUAL_TO' })
}
if ([decimal]$line.greaterThanKg) {
$i = $weightConditionsInput.Add(@{ criteria = @{ unit = 'GRAMS'; value = [decimal]$line.greaterThanKg * 1000; }; operator = 'GREATER_THAN_OR_EQUAL_TO' })
}
$methodInput = @{
active = $true;
name = $line.method;
rateDefinition = @{ price = @{ amount = [decimal]$line.rateAud; currencyCode = 'AUD' } };
weightConditionsToCreate = $weightConditionsInput;
}
$i = $zoneInput.methodDefinitionsToCreate.Add($methodInput)
}
$zonesToUpdate2 | ConvertTo-Json -Depth 6
We can then build the quety to update the zones:
$updateProfileQuery = 'mutation($id: ID!, $profile: DeliveryProfileInput!) {
deliveryProfileUpdate (id: $id, profile: $profile)
{
profile {
id
name
profileLocationGroups {
locationGroupZones (first: 15) {
edges {
node {
zone {
id
name
}
methodDefinitions (first:20) {
edges {
node {
id
name
}
}
}
}
}
}
}
}
userErrors {
field
message
}
}
}'
$profileLocationGroupUpdateInput2 = @{ id = $locationGroupId2; zonesToUpdate = $zonesToUpdate2 }
Then use both $profileLocationGroupUpdateInput2
and $methodsToDelete2
to update the rates.
Build the delete query:
$updateRates = @{
query = $updateProfileQuery;
variables = @{
id = $deliveryProfile2.node.id;
profile = @{
methodDefinitionsToDelete = $methodsToDelete2
}
}
}
$updateRatesResult = Invoke-RestMethod -Method Post -Uri $uri -Headers $jsonHeaders -Body (ConvertTo-Json -Depth 11 $updateRates)
$updateRatesResult
And then the update:
$updateRates2 = @{
query = $updateProfileQuery;
variables = @{
id = $deliveryProfile2.node.id;
profile = @{
locationGroupsToUpdate = @( $profileLocationGroupUpdateInput2 )
}
}
}
$updateRatesResult = Invoke-RestMethod -Method Post -Uri $uri -Headers $jsonHeaders -Body (ConvertTo-Json -Depth 11 $updateRates2)
$updateRatesResult
Check the rates have updated in the UI.
-
Get the new rates from the Australia Post website, https://auspost.com.au/
-
Open
data/auspost-rates-data.ods
(OpenOffice, or should also be able to open in MS Office) -
Check that there are no changes affective
Zones and countries
andDomestic zones
, i.e. the zones are the same (just the rates change). If the zones or zone structure has changed, then updates may be a lot more involved than just a rate update. -
Update the
Rate data
sheet, fill in the new base values (in blue); check other values calculate correctly. -
Check Rate definitions 1 and Rate definitions contain the list of rates you want, or create your own.
e.g. Rate definitions 1 has retail rates for both standard and express options, up to 1 kg, for domestic + all zones. Rate definitions 2 is desgined for wholesale products, with only express rates, with insurance, and larger weights (up to 5kg), but with a discount applied.
-
Export the output tables
Zone rates 1
andZone rates 2
to CSV. -
Commit to track in source control
-
Open a PowerShell terminal
-
Check credentials working as per
Configure a Private App to get access to the API
andAccessing the GraphQL API
$password = '<Password>'
$shopName = '<shop name>'
$uri = "https://$shopName.myshopify.com/admin/api/2021-01/graphql.json"
$headers = @{
'Content-Type' = 'application/graphql';
'X-Shopify-Access-Token' = $password
}
$body = '{
deliveryProfiles(first:10) {
edges {
node {
id
name
default
}
}
}
}'
Invoke-RestMethod -Method Post -Uri $uri -Headers $headers -Body $body | ConvertTo-Json -Depth 5
- Get profile information, following
Get existing shipping profile information
$body = '{
deliveryProfiles(first:10) {
edges {
node {
id
name
default
profileLocationGroups {
locationGroup {
id
}
}
}
}
}
}'
$deliveryProfiles = Invoke-RestMethod -Method Post -Uri $uri -Headers $headers -Body $body
$defaultProfileId = ($deliveryProfiles.data.deliveryProfiles.edges | Where-Object { $_.node.default }).node.id
$defaultProfileId
- Then follow the details in
Replacing existing rates
, starting with selecting the profile (change the name for a different profile):
$profileName = 'General Profile'
$zoneRateDataFile = 'data/auspost-rates-to-1-5kg.csv'
$deliveryProfile = $deliveryProfiles.data.deliveryProfiles.edges | Where-Object { $_.node.name -eq $profileName }
$deliveryProfile.node.profileLocationGroups | Measure-Object
$locationGroupId = $deliveryProfile.node.profileLocationGroups[0].locationGroup.id
$profileLocationGroupInput = @{ id = $locationGroupId; zonesToCreate = $zonesToCreate }
Then getting the profile and checking the list of existing method definitions to delete:
$getDeliveryProfileData = @{
query = $getDeliveryProfileQuery;
variables = @{
id = $deliveryProfile.node.id;
}
}
$profileDetails = Invoke-RestMethod -Method Post -Uri $uri -Headers $jsonHeaders -Body (ConvertTo-Json -Depth 3 $getDeliveryProfileData)
$methodsToDelete = $profileDetails.data.deliveryProfile.profileLocationGroups.locationGroupZones.edges.node.methodDefinitions.edges.node.id
$methodsToDelete
- With the data prepared above, load the CSV data following
Read shipping rate data
First, get the zone IDs
$getDeliveryProfileZonesQuery = 'query($id: ID!)
{
deliveryProfile (id: $id) {
profileLocationGroups {
locationGroupZones (first: 15) {
edges {
node {
zone {
id
name
}
}
}
}
}
}
}'
$getDeliveryProfileZonesData = @{
query = $getDeliveryProfileZonesQuery;
variables = @{
id = $deliveryProfile.node.id;
}
}
$profileZones = Invoke-RestMethod -Method Post -Uri $uri -Headers $jsonHeaders -Body (ConvertTo-Json -Depth 3 $getDeliveryProfileZonesData)
$zoneIdsAndNames = $profileZones.data.deliveryProfile.profileLocationGroups[0].locationGroupZones.edges.node.zone
$zoneIdsAndNames | Measure-Object
Then read the data file and build the new rates (change the data file to match the profile)
$zoneRateData = Import-Csv $zoneRateDataFile
$zonesToUpdate = [System.Collections.ArrayList]@()
$currentZone = $null
$zoneRateData | ForEach-Object {
$line = $_
if ($line.zone -ne $currentZone) {
$currentZone = $line.zone
$zone = $zoneIdsAndNames | Where-Object { $_.name -eq $currentZone}
if (-not $zone) { throw "Zone $($_.name) not found" }
$zoneInput = @{ id = $zone.id; methodDefinitionsToCreate = [System.Collections.ArrayList]@() }
$i = $zonesToUpdate.Add($zoneInput)
}
$weightConditionsInput = [System.Collections.ArrayList]@()
$i = $weightConditionsInput.Add(@{ criteria = @{ unit = 'KILOGRAMS'; value = [decimal]$line.lessThanKg; }; operator = 'LESS_THAN_OR_EQUAL_TO' })
if ([decimal]$line.greaterThanKg) {
$i = $weightConditionsInput.Add(@{ criteria = @{ unit = 'KILOGRAMS'; value = [decimal]$line.greaterThanKg; }; operator = 'GREATER_THAN_OR_EQUAL_TO' })
}
$methodInput = @{
active = $true;
name = $line.method;
rateDefinition = @{ price = @{ amount = [decimal]$line.rateAud; currencyCode = 'AUD' } };
weightConditionsToCreate = $weightConditionsInput;
}
$i = $zoneInput.methodDefinitionsToCreate.Add($methodInput)
}
$zonesToUpdate | ConvertTo-Json -Depth 6
- And then 'Uploading rates' up to the point where
$profileLocationGroupUpdateInput
is created.
$updateProfileQuery = 'mutation($id: ID!, $profile: DeliveryProfileInput!) {
deliveryProfileUpdate (id: $id, profile: $profile)
{
profile {
id
name
profileLocationGroups {
locationGroupZones (first: 15) {
edges {
node {
zone {
id
name
}
methodDefinitions (first:20) {
edges {
node {
id
name
}
}
}
}
}
}
}
}
userErrors {
field
message
}
}
}'
$profileLocationGroupUpdateInput = @{ id = $locationGroupId; zonesToUpdate = $zonesToUpdate }
- Then use both
$profileLocationGroupUpdateInput
and$methodsToDelete
to update the rates.
$updateRates = @{
query = $updateProfileQuery;
variables = @{
id = $deliveryProfile.node.id;
profile = @{
methodDefinitionsToDelete = $methodsToDelete
locationGroupsToUpdate = @( $profileLocationGroupUpdateInput )
}
}
}
$updateRatesResult = Invoke-RestMethod -Method Post -Uri $uri -Headers $jsonHeaders -Body (ConvertTo-Json -Depth 11 $updateRates)
$updateRatesResult | ConvertTo-Json -Depth 9
- After loading, check the rates in Shopify Admin > Settings > Shipping and delivery > Manage (for the profile), then scroll down and look at the rates.
- Follow the steps above in
Replace rates for a profile for shoping
, but for a different profile and data file, e.g.:
$profileName = 'Wholesale Shipping'
$zoneRateDataFile = 'data/auspost-rates-discounted-insured-express-to-4kg.csv'
$deliveryProfile = $deliveryProfiles.data.deliveryProfiles.edges | Where-Object { $_.node.name -eq $profileName }
$deliveryProfile.node.profileLocationGroups | Measure-Object
$locationGroupId = $deliveryProfile.node.profileLocationGroups[0].locationGroup.id
$profileLocationGroupInput = @{ id = $locationGroupId; zonesToCreate = $zonesToCreate }