前言:因公司境外业务需要,我们通过shopfiy平台搭建了自己的境外官网商城,现在需要对在境外产生的订单在发货后上送物流信息。最早之前开发了一版,API版本是2021-07,,但由于shopfiy将于2023-4月废弃之前版本,所以不得不更换新版本API。
注意:此博客介绍的是自有应用,只能给自己的应用使用。并非公有应用
一、进入shopify管理页面,点击应用
二、选择应用和销售渠道设置
三、点击开发应用
四、点击创建应用,输入应用名称并创建应用
五、配置api权限
- read_merchant_managed_fulfillment_orders
- write_third_party_fulfillment_orders
- write_assigned_fulfillment_orders
- write_orders
- write_fulfillments
六、选择api凭证,记录app-key、app-secret、并安装应用获取Access-Token
切记:Access-Token只展示一次,一定要保存起来
七、代码开发
添加物流信息
AddTrack202302Test
package com.ratta.shopify;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.apache.commons.lang3.StringUtils;
import com.ratta.dto.AddTrackDTO;
import com.ratta.shopify.mode.Addtrack202301Request;
import com.ratta.shopify.mode.Addtrack202301RequestInfo;
import com.ratta.shopify.mode.LineItemsByFulfillmentOrder;
import com.ratta.shopify.mode.TrackingInfo;
import com.ratta.util.HttpUtil;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
@Slf4j
public class AddTrack202302Test {
public static final String ADD_TRACKING_URL_2023_01 = "https://%s.myshopify.com/admin/api/2023-01/fulfillments.json";
//你的开发商店名(下面会介绍如何查看)
public static final String SHOP = "xxxx";
public static final String API_VERSION = "2023-01";
//Yuan
public static final String RATTASUPERNOTE_ACCESS_TOKEN = "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";
public void addtrackRequest(AddTrackDTO addTrackDTO){
Addtrack202301Request addtrack202301Request = new Addtrack202301Request();
addtrack202301Request.setApi_version(API_VERSION);
List<LineItemsByFulfillmentOrder> lineItemsByFulfillmentOrderList = new ArrayList<LineItemsByFulfillmentOrder>();
LineItemsByFulfillmentOrder lineItemsByFulfillmentOrder = new LineItemsByFulfillmentOrder();
lineItemsByFulfillmentOrder.setFulfillment_order_id(new GetFulfillmentOrder202301Test().getFulfillmentOrderId(addTrackDTO.getTradeNo()));
lineItemsByFulfillmentOrderList.add(lineItemsByFulfillmentOrder);
addtrack202301Request.setLine_items_by_fulfillment_order(lineItemsByFulfillmentOrderList);
TrackingInfo tracking_info = new TrackingInfo();
tracking_info.setCompany(addTrackDTO.getCarrier());
tracking_info.setNumber(addTrackDTO.getTrackingNumber());
tracking_info.setUrl(addTrackDTO.getTrackingWeb());
addtrack202301Request.setTracking_info(tracking_info);
addtrack202301Request.setNotify_customer(false);
Addtrack202301RequestInfo addtrack202301RequestInfo = new Addtrack202301RequestInfo();
addtrack202301RequestInfo.setFulfillment(addtrack202301Request);
org.json.JSONObject object = new org.json.JSONObject(addtrack202301RequestInfo);
String str = object.toString();
Properties headers = new Properties();
headers.put("Content-Type","application/json");
headers.put("X-Shopify-Access-Token", RATTASUPERNOTE_ACCESS_TOKEN);
log.info("addtrackRequest = {}", str);
String url = String.format(ADD_TRACKING_URL_2023_01, SHOP);
log.info("addtrackUrl = {}", url);
String post = HttpUtil.httpsRequest(url, "post", object, headers);
log.info("postResponse = {}",post);
JSONObject json = JSONObject.fromObject(post);
log.info("addtrackResponse = {}",json.toString(4));
if(StringUtils.isEmpty(post) || json.get("errors") != null) {
log.error("调用shopify添加物流信息异常:{}",json.get("errors"));
}else{
log.info("调用shopify添加物流信息成功");
}
}
public static void main(String[] args) {
AddTrackDTO addTrackDTO = new AddTrackDTO();
addTrackDTO.setCarrier("DHL eCommerce Asia");
addTrackDTO.setTrackingNumber("100001");
addTrackDTO.setTradeNo("4041618718926");
new AddTrack202302Test().addtrackRequest(addTrackDTO);
}
}
查询订单信息
GetFulfillmentOrder202301Test
package com.ratta.shopify;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import com.ratta.util.HttpUtil;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
@Slf4j
public class GetFulfillmentOrder202301Test {
public static final String api_version = "2023-01";
//你的开发商店名(下面会介绍如何查看)
public static final String SHOP = "xxxx";
public static final String get_orders_2023_01 = "https://%s.myshopify.com/admin/api/2023-01/orders/%s/fulfillment_orders.json";
//Yuan
public static final String RATTASUPERNOTE_ACCESS_TOKEN = "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";
public Long getFulfillmentOrderId(String tradeNo){
Properties headers = new Properties();
headers.put("X-Shopify-Access-Token", RATTASUPERNOTE_ACCESS_TOKEN);
Map<String, Object> params1 = new HashMap<String, Object>();
params1.put("order_id", tradeNo);
params1.put("api_version", api_version);
org.json.JSONObject js = new org.json.JSONObject(params1);
log.info("getFulfillmentOrderIdRequest = {}", js.toString());
String url = String.format(get_orders_2023_01, SHOP, tradeNo);
log.info("getFulfillmentOrderIdRequestURL = {}", url);
String post = HttpUtil.httpsRequest(url, "get", js, headers);
log.info("getFulfillmentOrderIdResponse = {}",post);
JSONObject json = JSONObject.fromObject(post);
JSONArray jSONArray = json.getJSONArray("fulfillment_orders");
log.info("getFulfillmentOrderIdResponse = {}",jSONArray.toString(4));
Long fulfillmentOrderId = 0L;
for (int i = 0; i < jSONArray.size(); i++) {
JSONObject jsonObject = jSONArray.getJSONObject(i);
String orderId = jsonObject.getString("order_id");
if(tradeNo.equals(orderId)) {
JSONArray array = jsonObject.getJSONArray("line_items");
for (int j = 0; j < array.size(); j++) {
JSONObject jsonObject1 = array.getJSONObject(j);
fulfillmentOrderId = jsonObject1.getLong("fulfillment_order_id");
}
}
}
log.info("fulfillmentOrderId = {}",fulfillmentOrderId);
return fulfillmentOrderId;
}
public static void main(String[] args) {
//shopfiy 上的订单编号(下面会介绍如何查看)
String tradeNo = "4041618718926";
new GetFulfillmentOrder202301Test().getFulfillmentOrderId(tradeNo);
}
}
AddTrackDTO
package com.ratta.dto;
import java.io.Serializable;
import javax.validation.constraints.NotBlank;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.ToString;
@Data
@ToString
public class AddTrackDTO implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "支付订单号 ")
private String tradeNo;
@ApiModelProperty(value = "物流单号 ")
private String trackingNumber;
@ApiModelProperty(value = "物流公司(DHL) ")
private String carrier;
}
Addtrack202301Request
package com.ratta.shopify.mode;
import java.io.Serializable;
import java.util.List;
import lombok.Data;
@Data
public class Addtrack202301Request implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* api版本(必)
*/
private String api_version;
/**
* 发货订单行项目(必)
*/
private List<LineItemsByFulfillmentOrder> line_items_by_fulfillment_order;
/**
* 消息(此消息仅在以下情况下可用 配送订单已分配给已选择管理配送的第三方配送服务 订单)
*/
private String message;
/**
* 是否应通知客户
*/
private Boolean notify_customer;
/**
* 发货地点的地址
*/
private OriginAddress origin_address;
/**
* 发货的跟踪信息
*/
private TrackingInfo tracking_info;
}
LineItemsByFulfillmentOrder
package com.ratta.shopify.mode;
import java.io.Serializable;
import java.util.List;
import lombok.Data;
@Data
public class LineItemsByFulfillmentOrder implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* 配送订单的 ID(必填)
*/
private Long fulfillment_order_id;
/**
* 配送订单行项目以及每个订单项的数量(必填)
*/
private List<FulfillmentOrderLineItems> fulfillment_order_line_items;
}
FulfillmentOrderLineItems
package com.ratta.shopify.mode;
import java.io.Serializable;
import lombok.Data;
@Data
public class FulfillmentOrderLineItems implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* 发货订单订单项的 ID(必填)
*/
private Integer id;
/**
* (最小值:1) 配送订单订单项的数量(必填)
*/
private Integer quantity;
}
OriginAddress
package com.ratta.shopify.mode;
import java.io.Serializable;
import lombok.Data;
@Data
public class OriginAddress implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* 发货地点的街道地址
*/
private String address1;
/**
* 地址的第二行。通常是公寓、套房或单元的编号
*/
private String address2;
/**
* 发货地点所在的城市
*/
private String city;
/**
* 两个字母的国家/地区代码 (ISO 3166-1 α-2格式)的发货地点。(必填)
*/
private String country_code;
/**
* 发货地点的省份
*/
private String province_code;
/**
* 发货地点的邮政编码
*/
private String zip;
}
TrackingInfo
package com.ratta.shopify.mode;
import java.io.Serializable;
import lombok.Data;
@Data
public class TrackingInfo implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* 物流公司的名称
*/
private String company;
/**
* 物流单号
*/
private String number;
/**
* 用于追踪物流信息的 URL
*/
private String url;
}
Addtrack202301RequestInfo
package com.ratta.shopify.mode;
import java.io.Serializable;
import lombok.Data;
@Data
public class Addtrack202301RequestInfo implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private Addtrack202301Request fulfillment;
}
HttpUtil
package com.ratta.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Iterator;
import java.util.Properties;
import org.json.JSONObject;
import java.util.Map.Entry;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class HttpUtil {
private static final String ENCODING = "UTF-8";
@SuppressWarnings("resource")
public static String httpsRequest(String httpUrl, String method, JSONObject param, Properties requestHeaderProperty) {
HttpURLConnection connection = null;
InputStream is = null;
OutputStream os = null;
BufferedReader br = null;
String result = null;
try {
URL url = new URL(httpUrl);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod(method.toUpperCase());
connection.setConnectTimeout(15000);
connection.setReadTimeout(60000);
// 设置请求头。
if (requestHeaderProperty != null) {
Iterator<Entry<Object, Object>> entrys = requestHeaderProperty.entrySet().iterator();
while (entrys.hasNext()) {
Entry<Object, Object> entry = entrys.next();
String key = entry.getKey().toString();
String value = entry.getValue().toString();
connection.setRequestProperty(key, value);
}
}
if ("POST".equals(method.toUpperCase()) || "PUT".equals(method.toUpperCase())) {
// 默认值为:false,当向远程服务器传送数据/写数据时,需要设置为true
connection.setDoOutput(true);
// 默认值为:true,当前向远程服务读取数据时,设置为true,该参数可有可无
connection.setDoInput(true);
// 通过连接对象获取一个输出流
os = connection.getOutputStream();
// 通过输出流对象将参数写出去/传输出去,它是通过字节数组写出的
os.write(param.toString().getBytes());
// 通过连接对象获取一个输入流,向远程读取
}
if ("GET".equals(method.toUpperCase())) {
// 发送请求
connection.connect();
}
log.info("responseCode = {}", connection.getResponseCode());
try {
is = connection.getInputStream();
// 对输入流对象进行包装:charset根据工作项目组的要求来设置
br = new BufferedReader(new InputStreamReader(is, ENCODING));
} catch (Exception e) {
is = connection.getErrorStream();
// 对输入流对象进行包装:charset根据工作项目组的要求来设置
br = new BufferedReader(new InputStreamReader(is, ENCODING));
}
StringBuffer sbf = new StringBuffer();
String temp = null;
// 循环遍历一行一行读取数据
while ((temp = br.readLine()) != null) {
sbf.append(temp);
sbf.append("\r\n");
}
result = sbf.toString();
log.info("result = {}", result);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭资源
if (null != br) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != os) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != is) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// 断开与远程地址url的连接
connection.disconnect();
}
return result;
}
public static void main(String[] args) {
}
}
八、获取shopfiy上的订单编号以及你的商店名
九、测试为该订单上送物流信息
物流信息添加成功