|
@@ -0,0 +1,253 @@
|
|
|
|
|
+package com.fs.kdniaoNew.service.impl;
|
|
|
|
|
+
|
|
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
|
|
+import com.fs.kdniaoNew.config.KdniaoUniversalConfig;
|
|
|
|
|
+import com.fs.kdniaoNew.domain.*;
|
|
|
|
|
+import com.fs.kdniaoNew.rule.IKdniaoCarrierRule;
|
|
|
|
|
+import com.fs.kdniaoNew.rule.impl.DefaultCarrierRule;
|
|
|
|
|
+import com.fs.kdniaoNew.service.IKdniaoUniversalEOrderService;
|
|
|
|
|
+import com.fs.kdniaoNew.util.KdniaoRequestUtil;
|
|
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
|
|
+import org.springframework.util.StringUtils;
|
|
|
|
|
+
|
|
|
|
|
+import java.net.URLEncoder;
|
|
|
|
|
+import java.util.*;
|
|
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 快递鸟统一电子面单服务实现
|
|
|
|
|
+ *
|
|
|
|
|
+ * 核心思想:
|
|
|
|
|
+ * 1. 公共字段统一组装
|
|
|
|
|
+ * 2. 每个快递规则单独类实现
|
|
|
|
|
+ * 3. 每个快递配置单独放在 yml
|
|
|
|
|
+ */
|
|
|
|
|
+@Service
|
|
|
|
|
+public class KdniaoUniversalEOrderServiceImpl implements IKdniaoUniversalEOrderService {
|
|
|
|
|
+
|
|
|
|
|
+ private final KdniaoUniversalConfig kdniaoConfig;
|
|
|
|
|
+ private final List<IKdniaoCarrierRule> carrierRules;
|
|
|
|
|
+
|
|
|
|
|
+ public KdniaoUniversalEOrderServiceImpl(KdniaoUniversalConfig kdniaoConfig,
|
|
|
|
|
+ List<IKdniaoCarrierRule> carrierRules) {
|
|
|
|
|
+ this.kdniaoConfig = kdniaoConfig;
|
|
|
|
|
+ this.carrierRules = carrierRules;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public KdniaoUniversalResponse submit(KdniaoSubmitCommand command) {
|
|
|
|
|
+ //校验公共参数
|
|
|
|
|
+ validateCommon(command);
|
|
|
|
|
+
|
|
|
|
|
+ String shipperCode = command.getShipperCode() == null ? null : command.getShipperCode().trim().toUpperCase();
|
|
|
|
|
+
|
|
|
|
|
+ if (!StringUtils.hasText(shipperCode)) {
|
|
|
|
|
+ throw new IllegalArgumentException("shipperCode不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (kdniaoConfig.getCarriers() == null || kdniaoConfig.getCarriers().isEmpty()) {
|
|
|
|
|
+ throw new IllegalArgumentException("kdniao.carriers配置为空,请检查application.yml");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ KdniaoCarrierConfig config = kdniaoConfig.getCarriers().get(shipperCode);
|
|
|
|
|
+ if (config == null) {
|
|
|
|
|
+ throw new IllegalArgumentException("未配置快递公司账号信息:" + shipperCode);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (config.getSender() == null) {
|
|
|
|
|
+ throw new IllegalArgumentException("未配置快递公司发件人信息:" + shipperCode);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Map<String, Object> requestData = buildCommonRequestData(command, config, shipperCode);
|
|
|
|
|
+
|
|
|
|
|
+ IKdniaoCarrierRule rule = resolveRule(shipperCode);
|
|
|
|
|
+ rule.apply(command, config, requestData);
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ String requestDataJson = JSON.toJSONString(requestData);
|
|
|
|
|
+ String dataSign = KdniaoRequestUtil.getDataSign(requestDataJson, kdniaoConfig.getApiKey());
|
|
|
|
|
+
|
|
|
|
|
+ StringBuilder form = new StringBuilder();
|
|
|
|
|
+ form.append("RequestData=").append(URLEncoder.encode(requestDataJson, "UTF-8"));
|
|
|
|
|
+ form.append("&EBusinessID=").append(URLEncoder.encode(kdniaoConfig.getEBusinessId(), "UTF-8"));
|
|
|
|
|
+ form.append("&RequestType=").append(URLEncoder.encode("1007", "UTF-8"));
|
|
|
|
|
+ form.append("&DataSign=").append(dataSign);
|
|
|
|
|
+ form.append("&DataType=").append(URLEncoder.encode("2", "UTF-8"));
|
|
|
|
|
+
|
|
|
|
|
+ String resp = KdniaoRequestUtil.doPost(kdniaoConfig.getReqUrl(), form.toString());
|
|
|
|
|
+ return JSON.parseObject(resp, KdniaoUniversalResponse.class);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ throw new RuntimeException("调用快递鸟失败:" + e.getMessage(), e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 构建公共请求体
|
|
|
|
|
+ */
|
|
|
|
|
+ private Map<String, Object> buildCommonRequestData(KdniaoSubmitCommand command,
|
|
|
|
|
+ KdniaoCarrierConfig config,
|
|
|
|
|
+ String shipperCode) {
|
|
|
|
|
+ Map<String, Object> data = new LinkedHashMap<>();
|
|
|
|
|
+
|
|
|
|
|
+ data.put("ShipperCode", shipperCode);
|
|
|
|
|
+ data.put("OrderCode", buildOrderCode(command.getBizOrderNo()));
|
|
|
|
|
+ data.put("PayType", command.getPayType());
|
|
|
|
|
+ data.put("ExpType", command.getExpType());
|
|
|
|
|
+
|
|
|
|
|
+ data.put("Sender", toPersonMap(config.getSender()));
|
|
|
|
|
+ data.put("Receiver", toPersonMap(command.getReceiver()));
|
|
|
|
|
+ data.put("Commodity", toCommodityList(command.getCommodity()));
|
|
|
|
|
+ data.put("Quantity", command.getQuantity() == null ? 1 : command.getQuantity());
|
|
|
|
|
+
|
|
|
|
|
+ putIfNotNull(data, "Weight", command.getWeight());
|
|
|
|
|
+ putIfNotNull(data, "Volume", command.getVolume());
|
|
|
|
|
+ putIfNotNull(data, "Cost", command.getCost());
|
|
|
|
|
+ putIfNotNull(data, "OtherCost", command.getOtherCost());
|
|
|
|
|
+
|
|
|
|
|
+ putIfHasText(data, "Remark", command.getRemark());
|
|
|
|
|
+ putIfHasText(data, "IsReturnPrintTemplate",
|
|
|
|
|
+ StringUtils.hasText(command.getIsReturnPrintTemplate()) ? command.getIsReturnPrintTemplate() : "1");
|
|
|
|
|
+ putIfHasText(data, "TemplateSize",
|
|
|
|
|
+ StringUtils.hasText(command.getTemplateSize()) ? command.getTemplateSize() : "130");
|
|
|
|
|
+ putIfHasText(data, "IsSubscribe",
|
|
|
|
|
+ StringUtils.hasText(command.getIsSubscribe()) ? command.getIsSubscribe() : "0");
|
|
|
|
|
+
|
|
|
|
|
+ putIfNotNull(data, "IsNotice", command.getIsNotice());
|
|
|
|
|
+ putIfHasText(data, "StartDate", command.getStartDate());
|
|
|
|
|
+ putIfHasText(data, "EndDate", command.getEndDate());
|
|
|
|
|
+
|
|
|
|
|
+ if (command.getAddService() != null && !command.getAddService().isEmpty()) {
|
|
|
|
|
+ List<Map<String, Object>> addServices = new ArrayList<>();
|
|
|
|
|
+ for (KdniaoAddServiceNew item : command.getAddService()) {
|
|
|
|
|
+ Map<String, Object> map = new LinkedHashMap<>();
|
|
|
|
|
+ putIfHasText(map, "Name", item.getName());
|
|
|
|
|
+ if (item.getValue() != null) {
|
|
|
|
|
+ map.put("Value", item.getValue());
|
|
|
|
|
+ }
|
|
|
|
|
+ putIfHasText(map, "CustomerID", item.getCustomerId());
|
|
|
|
|
+ addServices.add(map);
|
|
|
|
|
+ }
|
|
|
|
|
+ data.put("AddService", addServices);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return data;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 解析规则
|
|
|
|
|
+ */
|
|
|
|
|
+ private IKdniaoCarrierRule resolveRule(String shipperCode) {
|
|
|
|
|
+ for (IKdniaoCarrierRule rule : carrierRules) {
|
|
|
|
|
+ if (!(rule instanceof DefaultCarrierRule) && rule.supports(shipperCode)) {
|
|
|
|
|
+ return rule;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ for (IKdniaoCarrierRule rule : carrierRules) {
|
|
|
|
|
+ if (rule instanceof DefaultCarrierRule) {
|
|
|
|
|
+ return rule;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ throw new IllegalStateException("未找到默认规则实现");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 公共参数校验
|
|
|
|
|
+ */
|
|
|
|
|
+ private void validateCommon(KdniaoSubmitCommand command) {
|
|
|
|
|
+ if (command == null) {
|
|
|
|
|
+ throw new IllegalArgumentException("请求参数不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!StringUtils.hasText(command.getShipperCode())) {
|
|
|
|
|
+ throw new IllegalArgumentException("shipperCode不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (command.getPayType() == null) {
|
|
|
|
|
+ throw new IllegalArgumentException("payType不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!StringUtils.hasText(command.getExpType())) {
|
|
|
|
|
+ throw new IllegalArgumentException("expType不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (command.getReceiver() == null) {
|
|
|
|
|
+ throw new IllegalArgumentException("receiver不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!StringUtils.hasText(command.getReceiver().getName())) {
|
|
|
|
|
+ throw new IllegalArgumentException("receiver.name不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!StringUtils.hasText(command.getReceiver().getMobile())
|
|
|
|
|
+ && !StringUtils.hasText(command.getReceiver().getTel())) {
|
|
|
|
|
+ throw new IllegalArgumentException("receiver.mobile和receiver.tel至少填写一个");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!StringUtils.hasText(command.getReceiver().getProvinceName())) {
|
|
|
|
|
+ throw new IllegalArgumentException("receiver.provinceName不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!StringUtils.hasText(command.getReceiver().getCityName())) {
|
|
|
|
|
+ throw new IllegalArgumentException("receiver.cityName不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!StringUtils.hasText(command.getReceiver().getExpAreaName())) {
|
|
|
|
|
+ throw new IllegalArgumentException("receiver.expAreaName不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!StringUtils.hasText(command.getReceiver().getAddress())) {
|
|
|
|
|
+ throw new IllegalArgumentException("receiver.address不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (command.getCommodity() == null || command.getCommodity().isEmpty()) {
|
|
|
|
|
+ throw new IllegalArgumentException("commodity不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!StringUtils.hasText(command.getCommodity().get(0).getGoodsName())) {
|
|
|
|
|
+ throw new IllegalArgumentException("commodity.goodsName不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 构建订单号
|
|
|
|
|
+ */
|
|
|
|
|
+ private String buildOrderCode(String bizOrderNo) {
|
|
|
|
|
+ if (StringUtils.hasText(bizOrderNo)) {
|
|
|
|
|
+ return bizOrderNo.trim() + "-" + System.currentTimeMillis();
|
|
|
|
|
+ }
|
|
|
|
|
+ return "KD" + System.currentTimeMillis();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 发件人/收件人转Map
|
|
|
|
|
+ */
|
|
|
|
|
+ private Map<String, Object> toPersonMap(KdniaoPersonNew p) {
|
|
|
|
|
+ Map<String, Object> map = new LinkedHashMap<>();
|
|
|
|
|
+ putIfHasText(map, "Company", p.getCompany());
|
|
|
|
|
+ putIfHasText(map, "Name", p.getName());
|
|
|
|
|
+ putIfHasText(map, "Tel", p.getTel());
|
|
|
|
|
+ putIfHasText(map, "Mobile", p.getMobile());
|
|
|
|
|
+ putIfHasText(map, "ProvinceName", p.getProvinceName());
|
|
|
|
|
+ putIfHasText(map, "CityName", p.getCityName());
|
|
|
|
|
+ putIfHasText(map, "ExpAreaName", p.getExpAreaName());
|
|
|
|
|
+ putIfHasText(map, "Address", p.getAddress());
|
|
|
|
|
+ putIfHasText(map, "PostCode", p.getPostCode());
|
|
|
|
|
+ return map;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 商品列表转Map列表
|
|
|
|
|
+ */
|
|
|
|
|
+ private List<Map<String, Object>> toCommodityList(List<KdniaoCommodityNew> commodityList) {
|
|
|
|
|
+ return commodityList.stream().map(c -> {
|
|
|
|
|
+ Map<String, Object> map = new LinkedHashMap<>();
|
|
|
|
|
+ putIfHasText(map, "GoodsName", c.getGoodsName());
|
|
|
|
|
+ putIfHasText(map, "GoodsCode", c.getGoodsCode());
|
|
|
|
|
+ putIfNotNull(map, "Goodsquantity", c.getGoodsQuantity());
|
|
|
|
|
+ putIfNotNull(map, "GoodsPrice", c.getGoodsPrice());
|
|
|
|
|
+ putIfNotNull(map, "GoodsWeight", c.getGoodsWeight());
|
|
|
|
|
+ putIfHasText(map, "GoodsDesc", c.getGoodsDesc());
|
|
|
|
|
+ putIfNotNull(map, "GoodsVol", c.getGoodsVol());
|
|
|
|
|
+ return map;
|
|
|
|
|
+ }).collect(Collectors.toList());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void putIfHasText(Map<String, Object> map, String key, String value) {
|
|
|
|
|
+ if (StringUtils.hasText(value)) {
|
|
|
|
|
+ map.put(key, value.trim());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void putIfNotNull(Map<String, Object> map, String key, Object value) {
|
|
|
|
|
+ if (value != null) {
|
|
|
|
|
+ map.put(key, value);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|