SplitAccountService.java 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618
  1. package com.caimei.modules.order.service;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.caimei.modules.order.dao.NewOrderDao;
  5. import com.caimei.modules.order.dao.NewShopOrderDao;
  6. import com.caimei.modules.order.entity.*;
  7. import com.caimei.modules.order.utils.Disguiser;
  8. import com.caimei.modules.user.dao.CmReportingClubMapper;
  9. import com.caimei.modules.user.entity.CmReportingClub;
  10. import com.caimei.redis.RedisService;
  11. import com.caimei.utils.MathUtil;
  12. import com.thinkgem.jeesite.common.service.BaseService;
  13. import okhttp3.*;
  14. import org.apache.commons.lang3.StringUtils;
  15. import org.springframework.stereotype.Service;
  16. import org.springframework.transaction.annotation.Transactional;
  17. import javax.annotation.Resource;
  18. import java.io.IOException;
  19. import java.lang.reflect.Field;
  20. import java.math.BigDecimal;
  21. import java.text.SimpleDateFormat;
  22. import java.util.*;
  23. import java.util.concurrent.TimeUnit;
  24. import java.util.concurrent.atomic.AtomicReference;
  25. import java.util.stream.Collectors;
  26. @Service
  27. @Transactional(readOnly = true)
  28. public class SplitAccountService extends BaseService {
  29. public static OkHttpClient client = new OkHttpClient.Builder()
  30. .connectTimeout(3, TimeUnit.SECONDS)
  31. .readTimeout(20, TimeUnit.SECONDS)
  32. .build();
  33. @Resource
  34. private NewOrderDao newOrderDao;
  35. @Resource
  36. private RedisService redisService;
  37. @Resource
  38. private NewShopOrderDao newShopOrderDao;
  39. @Resource
  40. private CmReportingClubMapper cmReportingClubMapper;
  41. /**
  42. * !!!!注意:分帐时合利宝收费规则为谁分收谁0.1%手续费,这里是供应商承担的,如果要采美,服务商承担各自的费用,要提前计算好!!!
  43. *
  44. * 当前版本分帐逻辑变更,前台传入分帐帐号及金额,直接分帐
  45. * splits : "E123456,10;E123456,20;E123456,30"
  46. *
  47. * @param shopOrderId
  48. */
  49. @Transactional(readOnly = false, rollbackFor = Exception.class)
  50. public void SplitByHand(String shopOrderId, String splits) {
  51. logger.info("【手动分账开始】>>>>>>>>>>手动分账");
  52. /** todo
  53. * 校验splits参数总金额是否正确
  54. */
  55. String[] split = splits.split(";");
  56. if (split.length <= 0) {
  57. logger.info("分帐帐号及金额输入不正确!");
  58. return;
  59. }
  60. ArrayList<AccountPayOrder.AccountPayOrderExt.SplitBillRule> splitBillRules = new ArrayList<>();
  61. // 保存分帐参数,固定三方:成本,采美,服务商
  62. List<SplitAccountPo> splitBillDetail = new ArrayList<>();
  63. ShopOrderVo shopOrder = newOrderDao.getShopOrderListByOrderId(Integer.valueOf(shopOrderId));
  64. Double costPrice = 0d;
  65. for (int i = 0; i < split.length; i++) {
  66. AccountPayOrder.AccountPayOrderExt.SplitBillRule splitBillRule = new AccountPayOrder.AccountPayOrderExt.SplitBillRule();
  67. String[] rules = split[i].split(",");
  68. /**
  69. * splits : "E123456,10;E123456,20;E123456,30"
  70. */
  71. if (i > 0) {
  72. BigDecimal cost = BigDecimal.valueOf(Double.parseDouble(rules[1]));
  73. splitBillRule.setSplitBillAmount(cost);
  74. splitBillRule.setSplitBillMerchantNo(rules[0]);
  75. splitBillRules.add(splitBillRule);
  76. }
  77. /**
  78. * cm_split_account 分帐详情参数
  79. */
  80. Integer productType = 0 == i ? 1 : 1 == i ? 3 : 5;
  81. Integer type = 0 == i ? 4 : 5;
  82. SplitAccountPo splitAccount = new SplitAccountPo();
  83. splitAccount.setOrderId(shopOrder.getOrderId());
  84. splitAccount.setShopOrderId(shopOrder.getShopOrderId());
  85. /** 前台获取金额
  86. * (暂定前台输入金额未计算手续费,采美和第三方分帐出去金额总量的0.1%为手续费,从成本扣除)
  87. */
  88. splitAccount.setSplitAccount(Double.parseDouble(rules[1]));
  89. splitAccount.setProductType(productType);
  90. splitAccount.setType(type);
  91. // 前台获取
  92. splitAccount.setSubUserNo(rules[0]);
  93. splitBillDetail.add(splitAccount);
  94. if (0 == i) {
  95. costPrice = Double.parseDouble(rules[1]);
  96. }
  97. }
  98. if (null != splitBillRules && splitBillRules.size() > 0) {
  99. //第三方分账接口
  100. try {
  101. AccountPayOrder accountPayOrder = new AccountPayOrder();
  102. accountPayOrder.setP1_bizType("AccountPaySub");
  103. accountPayOrder.setP2_signType("MD5");
  104. String format1 = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss.SSS").format(new Date());
  105. accountPayOrder.setP3_timestamp(format1);
  106. String substring = format1.substring(20);
  107. // fz+当前微秒时间+原唯一订单号
  108. accountPayOrder.setP4_orderId("FZ" + substring + shopOrderId);
  109. //付款账户子订单绑定商户号(付款商户商编)
  110. accountPayOrder.setP5_customerNumber(shopOrder.getSplitCode());
  111. AccountPayOrder.AccountPayOrderExt accountPayOrderExt = new AccountPayOrder.AccountPayOrderExt();
  112. //收款账户商编 填写splitBillRules时候不填写MerchantNo,Amount并且即使填写这两个参数不生效!!
  113. //accountPayOrderExt.setInMerchantNo(splitMoneyVo.getName());
  114. //accountPayOrderExt.setAmount(splitMoneyVo.getSplitMoney());
  115. accountPayOrderExt.setOrderType(AccountPayOrderType.TRANSFER);
  116. accountPayOrderExt.setServerCallbackUrl(Constant.prodSplit);
  117. accountPayOrderExt.setGoodsName("分账");
  118. if (null != splitBillRules && splitBillRules.size() > 0) {
  119. accountPayOrderExt.setSplitBillRules(splitBillRules);
  120. }
  121. String ext = JSON.toJSONString(accountPayOrderExt);
  122. logger.info("分账规则串json串:" + ext);
  123. accountPayOrder.setP6_ext(ext);
  124. // 生成签名
  125. StringBuilder builder = new StringBuilder();
  126. builder.append(Constant.SPLIT)
  127. .append(accountPayOrder.getP1_bizType()).append(Constant.SPLIT)
  128. .append(accountPayOrder.getP2_signType()).append(Constant.SPLIT)
  129. .append(accountPayOrder.getP3_timestamp()).append(Constant.SPLIT)
  130. .append(accountPayOrder.getP4_orderId()).append(Constant.SPLIT)
  131. .append(accountPayOrder.getP5_customerNumber()).append(Constant.SPLIT)
  132. .append(accountPayOrder.getP6_ext()).append(Constant.SPLIT)
  133. .append(Constant.XUNI);
  134. String sign = Disguiser.disguiseMD5(builder.toString().trim());
  135. Map<String, String> bean = convertBean(accountPayOrder);
  136. logger.info("--------------------> 发送分账参数: " + bean);
  137. Map<String, String> map = postForm(bean, Constant.FZ, sign, Map.class);
  138. logger.info("----------------分账返回数据: " + map.toString());
  139. if (map != null) {
  140. String code = map.get("rt5_retCode");
  141. if (!"0000".equals(code)) {
  142. String msg = map.get("rt6_retMsg");
  143. logger.info("【手动分账】>>>>>>>>>>手动分账失败>>>>>>>msg:" + msg);
  144. } else {
  145. // 返回值0000分帐成功
  146. for (SplitAccountPo splitAccount : splitBillDetail) {
  147. splitAccount.setPayStatus(1);
  148. // 保存分账详情
  149. newOrderDao.insertSplitAccount(splitAccount);
  150. }
  151. /**
  152. * 付款单
  153. */
  154. // 修改子订单付款状态及付款金额
  155. newOrderDao.updateShopOrderByPayStatus(Integer.valueOf(shopOrderId), costPrice, shopOrder.getPayStatus());
  156. SimpleDateFormat format2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  157. String currentTime2 = format2.format(new Date());
  158. // 保存付款单表
  159. PayShopPo payShop = new PayShopPo();
  160. payShop.setShopId(shopOrder.getShopId());
  161. payShop.setName("线上支付分账");
  162. payShop.setTotalAmount(costPrice);
  163. payShop.setWipePayment(0d);
  164. payShop.setPayType(6);
  165. payShop.setStatus(1);
  166. payShop.setDelFlag(0);
  167. payShop.setApplyTime(currentTime2);
  168. payShop.setReviewTime(currentTime2);
  169. payShop.setPayTime(currentTime2);
  170. newOrderDao.insertPayShop(payShop);
  171. // 保存 付供应商记录
  172. PayShopRecordPo shopRecord = new PayShopRecordPo();
  173. shopRecord.setShopId(shopOrder.getShopId());
  174. shopRecord.setShopOrderId(shopOrder.getShopOrderId());
  175. shopRecord.setShopOrderNo(shopOrder.getShopOrderNo());
  176. shopRecord.setPayAmount(costPrice);
  177. shopRecord.setWipePayment(0d);
  178. shopRecord.setPayType(6);
  179. shopRecord.setPayTime(currentTime2);
  180. shopRecord.setPayShopId(payShop.getId());
  181. shopRecord.setStatus(1);
  182. shopRecord.setDelFlag(0);
  183. newOrderDao.insertPayShopRecord(shopRecord);
  184. // 子订单是否全部付款
  185. List<String> payStatus = newShopOrderDao.findPayStatusByOrderID(shopOrder.getOrderId());
  186. boolean isPay = true;
  187. for (String shops : payStatus) {
  188. if (!"3".equals(shops)) {
  189. isPay = false;
  190. break;
  191. }
  192. }
  193. // 修改主订单付款状态
  194. if (isPay) {
  195. newOrderDao.updateOrderByPayStatus(shopOrder.getOrderId(), 3);
  196. } else {
  197. newOrderDao.updateOrderByPayStatus(shopOrder.getOrderId(), 2);
  198. }
  199. redisService.remove("XSFZMDS");
  200. logger.info("【手动分账】>>>>>>>>>>此订单分账结束");
  201. }
  202. }
  203. } catch (Exception e) {
  204. logger.error("【手动分账】>>>>>>>>>>错误信息", e);
  205. }
  206. }
  207. }
  208. @Transactional(readOnly = false, rollbackFor = Exception.class)
  209. public void SplitAccount(String[] shopOrderIds) {
  210. logger.info("【手动分账开始】>>>>>>>>>>手动分账");
  211. Calendar calendar = Calendar.getInstance();
  212. calendar.setTime(new Date());
  213. SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  214. String currentTime = format.format(calendar.getTime());
  215. List<String> ids = new ArrayList<>();
  216. ids = Arrays.stream(shopOrderIds).collect(Collectors.toList());
  217. ids.forEach(i -> {
  218. // 查询未分账已支付收款
  219. List<OrderReceiptRelationPo> orderRelations = newOrderDao.getUndividedPaidReceipt(currentTime, i);
  220. List<SplitAccountPo> splitBillDetail = new ArrayList<>();
  221. AtomicReference<Double> costPrice = new AtomicReference<Double>(0d);
  222. AtomicReference<Double> cmCostPrice = new AtomicReference<Double>(0d);
  223. AtomicReference<Double> organizeCostPrice = new AtomicReference<Double>(0d);
  224. AtomicReference<Double> total = new AtomicReference<Double>(0d);
  225. // 收款对应的订单信息
  226. ShopOrderVo shopOrder = newOrderDao.getShopOrderListByOrderId(Integer.valueOf(i));
  227. for (OrderReceiptRelationPo orderRelation : orderRelations) {
  228. logger.info("【分账】>>>>>>>>>>子订单id:" + orderRelation.getShopOrderId() + "进入分账");
  229. setSplitAccountDetail(costPrice, organizeCostPrice, cmCostPrice, total, shopOrder, orderRelation);
  230. }
  231. /** todo
  232. * 当前版本优惠券和促销活动为商家承担
  233. */
  234. if (shopOrder.getCouponAmount() > 0 || shopOrder.getPromotionFullReduction() > 0) {
  235. costPrice.set(MathUtil.sub(costPrice, MathUtil.add(shopOrder.getCouponAmount(), shopOrder.getPromotionFullReduction())).doubleValue());
  236. }
  237. if (MathUtil.compare(total, MathUtil.add(MathUtil.add(costPrice, cmCostPrice), organizeCostPrice)) < 0) {
  238. logger.info("收款总金额不足分帐------------->total: " + total.get()
  239. + "costPrice: " + costPrice.get() + "----------"
  240. + "cmCostPrice: " + cmCostPrice.get() + "-------------"
  241. + "organizeCostPrice: " + organizeCostPrice.get() + "---------------");
  242. return;
  243. }
  244. /**
  245. * 线上订单,付第三方如果不为0,需要从供应商成本中支付
  246. */
  247. double payOther = newOrderDao.findPayOther(Integer.valueOf(i));
  248. if (MathUtil.compare(payOther, 0) > 0) {
  249. SplitAccountPo splitAccount = new SplitAccountPo();
  250. splitAccount.setOrderId(shopOrder.getOrderId());
  251. splitAccount.setShopOrderId(shopOrder.getShopOrderId());
  252. splitAccount.setSplitAccount(payOther);
  253. splitAccount.setProductType(6);
  254. splitAccount.setType(6);
  255. splitAccount.setSubUserNo(Constant.CUSTOMERNUM3);
  256. logger.info("付第三方分账参数------------->" + splitAccount);
  257. splitBillDetail.add(splitAccount);
  258. // 当前版本付第三方从供应商成本支出
  259. costPrice.updateAndGet(v -> MathUtil.sub(v, payOther).doubleValue());
  260. }
  261. if (costPrice.get() > 0) {
  262. SplitAccountPo splitAccount = new SplitAccountPo();
  263. splitAccount.setShopOrderId(shopOrder.getShopOrderId());
  264. splitAccount.setOrderId(shopOrder.getOrderId());
  265. splitAccount.setSplitAccount(costPrice.get());
  266. splitAccount.setProductType(1);
  267. // 该商品设置了商户号
  268. splitAccount.setType(4);
  269. splitAccount.setSubUserNo(shopOrder.getSplitCode());
  270. logger.info("成本分账参数------------->" + splitAccount.toString());
  271. splitBillDetail.add(splitAccount);
  272. }
  273. /** 成本分完,金额未尽,有组织佣金的情况,优先组织佣金
  274. * 当前版本,采美供应商上架丽格商城,会存在三成本均>0的情况
  275. * 若无组织佣金,所有剩余金额归于采美佣金
  276. */
  277. if (organizeCostPrice.get() > 0) {
  278. SplitAccountPo splitAccount = new SplitAccountPo();
  279. Integer identity = newOrderDao.findUserIdentityByOrder(shopOrder.getOrderId());
  280. splitAccount.setShopOrderId(shopOrder.getShopOrderId());
  281. splitAccount.setOrderId(shopOrder.getOrderId());
  282. splitAccount.setSplitAccount(organizeCostPrice.get());
  283. splitAccount.setProductType(identity == 8 ? 7 : 5);
  284. // 该商品设置了商户号
  285. splitAccount.setType(4);
  286. String code = null;
  287. //分销人员分账修改报备记录
  288. if (identity == 8) {
  289. CmReportingClub cmReportingClubById = cmReportingClubMapper.getByCmReportingClub(new CmReportingClub().orderId(shopOrder.getOrderId()).orderStatus(1));
  290. if (null != cmReportingClubById) {
  291. //分销团队分账号
  292. code = cmReportingClubById.splitCode();
  293. cmReportingClubMapper.updateCmReportingClub(new CmReportingClub()
  294. .id(cmReportingClubById.id())
  295. .splitSettleStatus(2)
  296. );
  297. } else {
  298. logger.info("分销订单分账异常,订单Id:" + shopOrder.getOrderId() + ">>>>!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
  299. return;
  300. }
  301. } else {
  302. code = newOrderDao.findSplitCodeByOrganize(shopOrder.getOrganizeId());
  303. }
  304. String splitName = identity == 8 ? "分销团队" : "组织";
  305. if (StringUtils.isBlank(code)) {
  306. logger.info(splitName + "的分帐号未空,无法分帐" + splitName + "佣金!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
  307. return;
  308. }
  309. splitAccount.setSubUserNo(code);
  310. logger.info(splitName + "佣金分账参数------------->" + splitAccount.toString());
  311. splitBillDetail.add(splitAccount);
  312. }
  313. /** 当前版本还要考虑分组织/集团佣金
  314. * 如果还有钱则为佣金,分到网络
  315. */
  316. if (cmCostPrice.get() > 0) {
  317. // 此处不考虑手续费,外部计算总额
  318. SplitAccountPo splitAccount = new SplitAccountPo();
  319. splitAccount.setOrderId(shopOrder.getOrderId());
  320. splitAccount.setShopOrderId(shopOrder.getShopOrderId());
  321. splitAccount.setSplitAccount(cmCostPrice.get());
  322. splitAccount.setProductType(3);
  323. splitAccount.setType(5);
  324. splitAccount.setSubUserNo(Constant.CUSTOMERNUM2);
  325. logger.info("佣金分账参数------------->" + splitAccount);
  326. splitBillDetail.add(splitAccount);
  327. }
  328. HashMap<String, BigDecimal> sbm = new HashMap<>();
  329. for (SplitAccountPo splitAccountPo : splitBillDetail) {
  330. String subUserNo = splitAccountPo.getSubUserNo();
  331. // 计算当前商户号总分账金额
  332. if (sbm.containsKey(subUserNo)) {
  333. BigDecimal v = MathUtil.add(sbm.get(subUserNo), splitAccountPo.getSplitAccount());
  334. sbm.put(subUserNo, v);
  335. } else {
  336. sbm.put(subUserNo, BigDecimal.valueOf(splitAccountPo.getSplitAccount()));
  337. }
  338. // splitcode相同的收款的时候已经是成本已分帐
  339. if (subUserNo.equals(shopOrder.getSplitCode())) {
  340. // 供应商自己收款,此部分金额留在自己商户号,作为成本分账
  341. splitAccountPo.setPayStatus(1);
  342. // 保存分账详情
  343. newOrderDao.insertSplitAccount(splitAccountPo);
  344. }
  345. }
  346. ArrayList<AccountPayOrder.AccountPayOrderExt.SplitBillRule> splitBillRules = new ArrayList<>();
  347. sbm.forEach((key, value) -> {
  348. /**
  349. * 不是自己的splitcode分走,是自己的不动
  350. * 把成本之外的金额加入splitRule分账参数,延续上面逻辑,供应商自己的成本由自己的商户号收款,
  351. * 自己成本部分不需要加入分账参数,仅需在else中做业务表参数处理
  352. */
  353. if (!key.equals(shopOrder.getSplitCode())) {
  354. // 佣金
  355. AccountPayOrder.AccountPayOrderExt.SplitBillRule splitBillRule = new AccountPayOrder.AccountPayOrderExt.SplitBillRule();
  356. // 分账计算的时候未处理手续费,总额处理手续费 x + x * 0.1% = value
  357. BigDecimal div = MathUtil.div(value, 1.001, 2);
  358. if (MathUtil.sub(value, div).doubleValue() < 0.01) {
  359. // 如果手续费小于最低手续费,取0.01
  360. div = MathUtil.round(MathUtil.sub(value, 0.01), 2);
  361. }
  362. splitBillRule.setSplitBillAmount(div);
  363. splitBillRule.setSplitBillMerchantNo(key);
  364. splitBillRules.add(splitBillRule);
  365. } else {
  366. // 修改子订单付款状态及付款金额
  367. newOrderDao.updateShopOrderByPayStatus(Integer.valueOf(i), value.doubleValue(), shopOrder.getPayStatus());
  368. SimpleDateFormat format2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  369. String currentTime2 = format2.format(new Date());
  370. // 保存付款单表
  371. PayShopPo payShop = new PayShopPo();
  372. payShop.setShopId(shopOrder.getShopId());
  373. payShop.setName("线上支付分账");
  374. payShop.setTotalAmount(value.doubleValue());
  375. payShop.setWipePayment(0d);
  376. payShop.setPayType(6);
  377. payShop.setStatus(1);
  378. payShop.setDelFlag(0);
  379. payShop.setApplyTime(currentTime2);
  380. payShop.setReviewTime(currentTime2);
  381. payShop.setPayTime(currentTime2);
  382. newOrderDao.insertPayShop(payShop);
  383. // 保存 付供应商记录
  384. PayShopRecordPo shopRecord = new PayShopRecordPo();
  385. shopRecord.setShopId(shopOrder.getShopId());
  386. shopRecord.setShopOrderId(shopOrder.getShopOrderId());
  387. shopRecord.setShopOrderNo(shopOrder.getShopOrderNo());
  388. shopRecord.setPayAmount(value.doubleValue());
  389. shopRecord.setWipePayment(0d);
  390. shopRecord.setPayType(6);
  391. shopRecord.setPayTime(currentTime2);
  392. shopRecord.setPayShopId(payShop.getId());
  393. shopRecord.setStatus(1);
  394. shopRecord.setDelFlag(0);
  395. newOrderDao.insertPayShopRecord(shopRecord);
  396. // 子订单是否全部付款
  397. List<String> payStatus = newShopOrderDao.findPayStatusByOrderID(shopOrder.getOrderId());
  398. boolean isPay = true;
  399. for (String shops : payStatus) {
  400. if (!"3".equals(shops)) {
  401. isPay = false;
  402. break;
  403. }
  404. }
  405. // 修改主订单付款状态
  406. if (isPay) {
  407. newOrderDao.updateOrderByPayStatus(shopOrder.getOrderId(), 3);
  408. } else {
  409. newOrderDao.updateOrderByPayStatus(shopOrder.getOrderId(), 2);
  410. }
  411. }
  412. });
  413. /**
  414. * 在上述else代码逻辑中已完成成本的业务表参数处理,在分账详情中排除成本,剩余佣金部分在分账结束收到
  415. * 成功返回码时处理(成本不参与分账)
  416. */
  417. splitBillDetail.removeIf(s -> s.getSubUserNo().equals(shopOrder.getSplitCode()));
  418. if (null != splitBillRules && splitBillRules.size() > 0) {
  419. //第三方分账接口
  420. try {
  421. AccountPayOrder accountPayOrder = new AccountPayOrder();
  422. accountPayOrder.setP1_bizType("AccountPaySub");
  423. accountPayOrder.setP2_signType("MD5");
  424. String format1 = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss.SSS").format(new Date());
  425. accountPayOrder.setP3_timestamp(format1);
  426. String substring = format1.substring(20);
  427. // fz+当前微秒时间+原唯一订单号
  428. accountPayOrder.setP4_orderId("FZ" + substring + shopOrder.getShopOrderId());
  429. //付款账户子订单绑定商户号
  430. accountPayOrder.setP5_customerNumber(shopOrder.getSplitCode());
  431. AccountPayOrder.AccountPayOrderExt accountPayOrderExt = new AccountPayOrder.AccountPayOrderExt();
  432. //收款账户商编 填写splitBillRules时候不填写MerchantNo,Amount并且即使填写这两个参数不生效!!
  433. //accountPayOrderExt.setInMerchantNo(splitMoneyVo.getName());
  434. //accountPayOrderExt.setAmount(splitMoneyVo.getSplitMoney());
  435. accountPayOrderExt.setOrderType(AccountPayOrderType.TRANSFER);
  436. accountPayOrderExt.setServerCallbackUrl(Constant.prodSplit);
  437. accountPayOrderExt.setGoodsName("分账");
  438. if (null != splitBillRules && splitBillRules.size() > 0) {
  439. accountPayOrderExt.setSplitBillRules(splitBillRules);
  440. }
  441. String ext = JSON.toJSONString(accountPayOrderExt);
  442. logger.info("分账规则串json串:" + ext);
  443. accountPayOrder.setP6_ext(ext);
  444. // 生成签名
  445. StringBuilder builder = new StringBuilder();
  446. builder.append(Constant.SPLIT)
  447. .append(accountPayOrder.getP1_bizType()).append(Constant.SPLIT)
  448. .append(accountPayOrder.getP2_signType()).append(Constant.SPLIT)
  449. .append(accountPayOrder.getP3_timestamp()).append(Constant.SPLIT)
  450. .append(accountPayOrder.getP4_orderId()).append(Constant.SPLIT)
  451. .append(accountPayOrder.getP5_customerNumber()).append(Constant.SPLIT)
  452. .append(accountPayOrder.getP6_ext()).append(Constant.SPLIT)
  453. .append(Constant.XUNI);
  454. String sign = Disguiser.disguiseMD5(builder.toString().trim());
  455. Map<String, String> bean = convertBean(accountPayOrder);
  456. logger.info("--------------------> 发送分账参数: " + bean);
  457. Map<String, String> map = postForm(bean, Constant.FZ, sign, Map.class);
  458. logger.info("----------------分账返回数据: " + map.toString());
  459. if (map != null) {
  460. String code = map.get("rt5_retCode");
  461. if (!"0000".equals(code)) {
  462. String msg = map.get("rt6_retMsg");
  463. logger.info("【手动分账】>>>>>>>>>>手动分账失败>>>>>>>msg:" + msg);
  464. } else {
  465. for (SplitAccountPo splitAccount : splitBillDetail) {
  466. splitAccount.setPayStatus(1);
  467. // 保存分账详情
  468. newOrderDao.insertSplitAccount(splitAccount);
  469. }
  470. redisService.remove("XSFZMDS");
  471. logger.info("【手动分账】>>>>>>>>>>此订单分账结束");
  472. }
  473. }
  474. } catch (Exception e) {
  475. logger.error("【手动分账】>>>>>>>>>>错误信息", e);
  476. }
  477. }
  478. });
  479. }
  480. public void setSplitAccountDetail(AtomicReference<Double> costPrice, AtomicReference<Double> organizePrice,
  481. AtomicReference<Double> cmCostPrice, AtomicReference<Double> total,
  482. ShopOrderVo shopOrder, OrderReceiptRelationPo orderRelation) {
  483. // 待分账总金额
  484. double splitAmount = orderRelation.getAssociateAmount();
  485. total.updateAndGet(v -> MathUtil.add(v, splitAmount).doubleValue());
  486. // 总手续费
  487. double procedureFee;
  488. if (12 == orderRelation.getPayType()) {
  489. procedureFee = 10.00;
  490. } else if (17 == orderRelation.getPayType()) {
  491. //b2c 0.2%
  492. procedureFee = MathUtil.mul(splitAmount, 0.002, 2).doubleValue();
  493. //b2c最低手续费0.1
  494. if (procedureFee < 0.1) {
  495. procedureFee = 0.1;
  496. }
  497. } else if (13 == orderRelation.getPayType() || 15 == orderRelation.getPayType()) {
  498. //微信0.65%
  499. procedureFee = MathUtil.mul(splitAmount, 0.0065, 2).doubleValue();
  500. } else if (29 == orderRelation.getPayType()) {
  501. procedureFee = MathUtil.mul(splitAmount, 0.003, 2).doubleValue();
  502. if (procedureFee < 0.1) {
  503. procedureFee = 0.1;
  504. }
  505. } else if (30 == orderRelation.getPayType()) {
  506. procedureFee = MathUtil.mul(splitAmount, 0.006, 2).doubleValue();
  507. if (procedureFee < 0.1) {
  508. procedureFee = 0.1;
  509. }
  510. } else {
  511. //手续费 其他0.25%
  512. procedureFee = MathUtil.mul(splitAmount, 0.0025, 2).doubleValue();
  513. }
  514. if (MathUtil.compare(procedureFee, 0.01) <= 0) {
  515. procedureFee = 0.01;
  516. }
  517. // 商品数据
  518. List<OrderProductVo> orderProductList = newOrderDao.getOrderProductByShopOrderId(shopOrder.getShopOrderId());
  519. for (OrderProductVo orderProduct : orderProductList) {
  520. /** 价格 * 数量
  521. * 前版本为全比例成本,当前版本重新加回固定成本,新增字段cmCostPrice(平台服务费,分帐分采美),organizeCostPrice(组织/集团成本。分帐分组织)
  522. * 在此规则下,分帐方式取cop固定成本值。因存在成本修改,不能取cm_sku实时更新成本!
  523. */
  524. costPrice.updateAndGet(v -> MathUtil.add(v, MathUtil.mul(orderProduct.getCostPrice(), orderProduct.getNum(), 2)).doubleValue());
  525. organizePrice.updateAndGet(v -> MathUtil.add(v, MathUtil.mul(orderProduct.getOrganizeCostPrice(), orderProduct.getNum(), 2)).doubleValue());
  526. cmCostPrice.updateAndGet(v -> MathUtil.add(v, MathUtil.mul(orderProduct.getCmCostPrice(), orderProduct.getNum(), 2)).doubleValue());
  527. }
  528. //手续费承担方 线上支付手续费:默认1采美承担,2供应商承担
  529. Integer supportFlag = newOrderDao.findSupport(shopOrder.getShopOrderId());
  530. if (2 == supportFlag) {
  531. //供应商自己承担手续费
  532. costPrice.set(costPrice.get() - procedureFee);
  533. } else {
  534. cmCostPrice.set(cmCostPrice.get() - procedureFee);
  535. }
  536. }
  537. public <T> T postForm(Map<String, String> params, String url, String sign, Class<T> clazz) {
  538. FormBody.Builder builder = new FormBody.Builder();
  539. for (Map.Entry<String, String> entry : params.entrySet()) {
  540. builder.add(entry.getKey(), entry.getValue());
  541. }
  542. builder.add("sign", sign);
  543. Request request = new Request.Builder() // okHttp post
  544. .url(url)
  545. .post(builder.build())
  546. .build();
  547. Response response = null;
  548. try {
  549. response = client.newCall(request).execute();
  550. } catch (IOException e) {
  551. throw new IllegalStateException("请求出错", e);
  552. }
  553. if (!response.isSuccessful()) {
  554. try {
  555. logger.info(response.body().string());
  556. } catch (IOException e) {
  557. e.printStackTrace();
  558. }
  559. throw new RuntimeException("请求失败了: http response code: " + response.code());
  560. }
  561. ResponseBody body = response.body();
  562. String content = null;
  563. try {
  564. content = body.string();
  565. } catch (IOException e) {
  566. throw new IllegalStateException("IO异常", e);
  567. }
  568. JSONObject res = JSON.parseObject(content);
  569. if (!res.getBooleanValue("rt4_success")) {
  570. logger.error("error: " + res.getString("rt6_retMsg"));
  571. }
  572. /** rt4_success 为 true,需验签 **/
  573. return res.toJavaObject(clazz);
  574. }
  575. public Map<String, String> convertBean(Object bean) {
  576. Class clazz = bean.getClass();
  577. Field[] fields = clazz.getDeclaredFields();
  578. for (Field f : fields) {
  579. f.setAccessible(true);
  580. }
  581. try {
  582. Map<String, String> retMap = new LinkedHashMap<>();
  583. for (Field f : fields) {
  584. String key = f.toString().substring(f.toString().lastIndexOf(".") + 1);
  585. Object value = f.get(bean);
  586. if (value == null) {
  587. value = "";
  588. }
  589. retMap.put(key, (String) value);
  590. }
  591. return retMap;
  592. } catch (Exception e) {
  593. logger.info("分账", e);
  594. throw new IllegalStateException("分账异常", e);
  595. }
  596. }
  597. }