PayCenterService.java 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. package com.sckw.freight.service;
  2. import com.alibaba.fastjson2.JSONArray;
  3. import com.alibaba.fastjson2.JSONObject;
  4. import com.alibaba.fastjson2.TypeReference;
  5. import com.sckw.freight.exception.BusinessException;
  6. import com.sckw.freight.model.dto.*;
  7. import com.sckw.freight.model.enums.ChannelEnum;
  8. import com.sckw.freight.model.enums.PayCenterEnum;
  9. import com.sckw.freight.util.OkHttpUtils;
  10. import com.sckw.freight.util.R;
  11. import jakarta.validation.constraints.NotBlank;
  12. import jakarta.validation.constraints.NotNull;
  13. import lombok.extern.slf4j.Slf4j;
  14. import org.apache.commons.lang3.StringUtils;
  15. import org.springframework.beans.factory.annotation.Value;
  16. import org.springframework.stereotype.Service;
  17. import org.springframework.util.CollectionUtils;
  18. import java.util.HashMap;
  19. import java.util.List;
  20. import java.util.Map;
  21. import java.util.Objects;
  22. /**
  23. * 转发中台接口
  24. *
  25. * @author xucaiqin
  26. * @date 2023-07-21 17:45:51
  27. */
  28. @Service
  29. @Slf4j
  30. public class PayCenterService {
  31. @Value("${payCenter.address}")
  32. private String payCenterAddr;
  33. private <T> R<List<T>> parseArray(String in, Class<T> t) {
  34. R<String> res = JSONObject.parseObject(in, new TypeReference<R<String>>() {
  35. });
  36. String data = res.getData();
  37. List<T> ts = JSONArray.parseArray(data, t);
  38. R<List<T>> ok = R.ok(ts);
  39. ok.setStatus(res.getStatus());
  40. ok.setMsg(res.getMsg());
  41. ok.setCode(res.getCode());
  42. return ok;
  43. }
  44. private String getHttp(PayCenterEnum payCenterEnum, Map<String, Object> para) {
  45. log.info("{}入参->{}", payCenterEnum.getDesc(), JSONObject.toJSONString(para));
  46. OkHttpUtils okHttpUtils = OkHttpUtils.builder().url(payCenterAddr + payCenterEnum.getAddr());
  47. if (!CollectionUtils.isEmpty(para)) {
  48. for (Map.Entry<String, Object> p : para.entrySet()) {
  49. //跳过非空参数
  50. Object v = p.getValue();
  51. String k = p.getKey();
  52. if (Objects.isNull(v)) {
  53. continue;
  54. }
  55. if (v instanceof ChannelEnum channelEnum) {
  56. okHttpUtils.addPara(k, channelEnum.getChannel());
  57. } else if (v instanceof Integer i) {
  58. okHttpUtils.addPara(k, String.valueOf(i));
  59. } else if (v instanceof Long i) {
  60. okHttpUtils.addPara(k, String.valueOf(i));
  61. } else if (v instanceof String i) {
  62. okHttpUtils.addPara(k, i);
  63. } else if ((v.getClass().isArray()) && v instanceof String[] l) {
  64. for (int i = 0; i < l.length; i++) {
  65. okHttpUtils.addPara(k + "[" + i + "]", l[i]);
  66. }
  67. } else {
  68. okHttpUtils.addPara(k, v.toString());
  69. }
  70. }
  71. }
  72. String sync;
  73. try {
  74. sync = okHttpUtils.get().sync();
  75. } catch (Exception e) {
  76. log.error("中台服务异常", e.getCause());
  77. throw new RuntimeException("支付服务异常!");
  78. }
  79. log.info("{}返回值->{}", payCenterEnum.getDesc(), sync);
  80. return changeRes(sync);
  81. }
  82. private String postHttp(PayCenterEnum payCenterEnum, Map<String, Object> para) {
  83. log.info("{}入参->{}", payCenterEnum.getDesc(), JSONObject.toJSONString(para));
  84. OkHttpUtils okHttpUtils = OkHttpUtils.builder().url(payCenterAddr + payCenterEnum.getAddr());
  85. if (!CollectionUtils.isEmpty(para)) {
  86. for (Map.Entry<String, Object> p : para.entrySet()) {
  87. //跳过非空参数
  88. Object v = p.getValue();
  89. String k = p.getKey();
  90. if (Objects.isNull(v)) {
  91. continue;
  92. }
  93. if (v instanceof ChannelEnum channelEnum) {
  94. okHttpUtils.addBodyPara(k, channelEnum.getChannel());
  95. } else if (v instanceof Integer i) {
  96. okHttpUtils.addBodyPara(k, String.valueOf(i));
  97. } else if (v instanceof Long i) {
  98. okHttpUtils.addBodyPara(k, String.valueOf(i));
  99. } else if (v instanceof String i) {
  100. okHttpUtils.addBodyPara(k, i);
  101. } else if ((v.getClass().isArray()) && v instanceof String[] l) {
  102. for (int i = 0; i < l.length; i++) {
  103. okHttpUtils.addPara(k + "[" + i + "]", l[i]);
  104. }
  105. } else {
  106. okHttpUtils.addBodyPara(k, JSONObject.toJSONString(v));
  107. }
  108. }
  109. }
  110. String sync;
  111. try {
  112. sync = okHttpUtils.post(true).sync();
  113. } catch (Exception e) {
  114. log.error("中台服务异常", e.getCause());
  115. throw new RuntimeException("支付服务异常!");
  116. }
  117. log.info("{}返回值->{}", payCenterEnum.getDesc(), sync);
  118. return changeRes(sync);
  119. }
  120. private String jsonHttp(PayCenterEnum payCenterEnum, Object object) {
  121. String para = object instanceof JSONObject jsonObject ? jsonObject.toJSONString() : JSONObject.toJSONString(object);
  122. log.info("{}入参->{}", payCenterEnum.getDesc(), para);
  123. OkHttpUtils okHttpUtils = OkHttpUtils.builder().url(payCenterAddr + payCenterEnum.getAddr());
  124. okHttpUtils.addBodyJsonStr(para);
  125. String sync;
  126. try {
  127. sync = okHttpUtils.post(true).sync();
  128. } catch (Exception e) {
  129. log.error("中台服务异常", e.getCause());
  130. throw new RuntimeException("支付服务异常!");
  131. }
  132. log.info("{}返回值->{}", payCenterEnum.getDesc(), sync);
  133. return changeRes(sync);
  134. }
  135. private String changeRes(String sync) {
  136. if (StringUtils.isBlank(sync)) {
  137. return sync;
  138. }
  139. JSONObject jsonObject = JSONObject.parseObject(sync);
  140. //我的泛型是对象 返回值有可能 是对象或数组 {} []
  141. //data:[]->转换成 data:null 进入if
  142. Object data = jsonObject.get("data");
  143. if (Objects.nonNull(data) && data instanceof JSONArray d && d.isEmpty()) {
  144. jsonObject.put("data", null);
  145. sync = jsonObject.toJSONString();
  146. }
  147. return sync;
  148. }
  149. /**
  150. * 会员注册信息
  151. *
  152. * @param uid
  153. * @return
  154. */
  155. public R<JSONObject> user(String uid, ChannelEnum channelEnum) {
  156. String sync = getHttp(PayCenterEnum.USER, new HashMap<>() {{
  157. put("uid", uid);
  158. put("channel", channelEnum);
  159. put("channels", "xinwang");
  160. }});
  161. return JSONObject.parseObject(sync, new TypeReference<R<JSONObject>>(){});
  162. }
  163. /**
  164. * 订单状态
  165. *
  166. * @param type
  167. * @return
  168. */
  169. public R<Map<String, String>> withdrawStatus(String type) {
  170. if (StringUtils.isBlank(type)) {
  171. type = "order";
  172. }
  173. String finalType = type;
  174. String sync = getHttp(PayCenterEnum.WITHDRAW_STATUS, new HashMap<>() {{
  175. put("type", finalType);
  176. put("channels", "xinwang");
  177. }});
  178. return JSONObject.parseObject(sync, new TypeReference<>() {
  179. });
  180. }
  181. /**
  182. * 取消提现
  183. *
  184. * @param uid
  185. * @param orderNo
  186. * @return
  187. */
  188. public R<Object> withdrawCancel(String uid, String orderNo) {
  189. if (StringUtils.isBlank(uid)) {
  190. throw new BusinessException("用户不能为空");
  191. }
  192. if (StringUtils.isBlank(orderNo)) {
  193. throw new BusinessException("提现订单不能为空");
  194. }
  195. String sync = postHttp(PayCenterEnum.WITHDRAW_CANCEL, new HashMap<>() {{
  196. put("uid", uid);
  197. put("order_no", orderNo);
  198. }});
  199. return JSONObject.parseObject(sync, new TypeReference<R<Object>>(){});
  200. }
  201. /**
  202. * 申请提现
  203. *
  204. * @param uid
  205. * @param channel
  206. * @param money
  207. * @param remarks
  208. * @return
  209. */
  210. public R<Order> withdrawTake(String uid, @NotBlank(message = "渠道不能为空") ChannelEnum channel, Long money, String remarks) {
  211. if (StringUtils.isBlank(uid)) {
  212. throw new BusinessException("提现用户不能为空");
  213. }
  214. if (Objects.isNull(channel)) {
  215. throw new BusinessException("提现渠道不能为空");
  216. }
  217. if (Objects.isNull(money)) {
  218. throw new BusinessException("提现金额不能为空");
  219. }
  220. String sync = postHttp(PayCenterEnum.WITHDRAW_TAKE, new HashMap<>() {{
  221. put("uid", uid);
  222. put("channel", channel);
  223. put("money", money);
  224. put("remarks", remarks);
  225. }});
  226. return JSONObject.parseObject(sync, new TypeReference<R<Order>>(){});
  227. }
  228. /**
  229. * 操作记录-分类
  230. *
  231. * @return
  232. */
  233. public R<Map<String, String>> operateCategory() {
  234. String sync = getHttp(PayCenterEnum.OPERATE_CATEGORY, new HashMap<>());
  235. return JSONObject.parseObject(sync, new TypeReference<>() {
  236. });
  237. }
  238. /**
  239. * 发起预付
  240. *
  241. * @param uid 乙方uid
  242. * @param channel 渠道
  243. * @param filter 甲方uid
  244. * @param money 金额,分
  245. * @return
  246. */
  247. public R<Order> advancePayApply(String uid, ChannelEnum channel, String filter, Long money) {
  248. String sync = postHttp(PayCenterEnum.ADVANCE_PAY_APPLY, new HashMap<>() {{
  249. put("uid", uid);
  250. put("channel", channel);
  251. put("money", money);
  252. put("filter", filter);
  253. }});
  254. return JSONObject.parseObject(sync, new TypeReference<R<Order>>(){});
  255. }
  256. /**
  257. * 清分结果查询
  258. *
  259. * @param uid
  260. * @param channel
  261. * @param businessNo
  262. * @return
  263. */
  264. public R<List<SplitDto>> agentPayQuery(String uid, ChannelEnum channel, String businessNo) {
  265. String sync = getHttp(PayCenterEnum.AGENT_PAY_QUERY, new HashMap<>() {{
  266. put("uid", uid);
  267. put("channel", channel);
  268. put("business_no", businessNo);
  269. put("channels", "xinwang");
  270. }});
  271. return parseArray(sync, SplitDto.class);
  272. }
  273. /**
  274. * 创建/更新账户
  275. *
  276. * @param memberCreate
  277. * @return
  278. */
  279. public R<MemberRes> memberIndex(MemberCreate memberCreate) {
  280. String sync = jsonHttp(PayCenterEnum.MEMBER_INDEX, memberCreate);
  281. //return JSONObject.parseObject(sync, new R<MemberRes>().getClass());
  282. return JSONObject.parseObject(sync, new TypeReference<R<MemberRes>>(){});
  283. }
  284. /**
  285. * 在线充值
  286. *
  287. * @param buyUid 付款方/乙方/买货方 账户
  288. * @param sellUid 收款方/甲方/供货方 账户
  289. * @param channel 渠道方
  290. * @param money 金额,单位分
  291. * @return
  292. */
  293. public R<PayIndex> payIndex(String buyUid, String sellUid, ChannelEnum channel, Long money) {
  294. String sync = postHttp(PayCenterEnum.PAY_INDEX, new HashMap<>() {{
  295. put("buy_uid", buyUid);
  296. put("sell_uid", sellUid);
  297. put("channel", channel);
  298. put("money", money);
  299. }});
  300. // Object object = JSONObject.parseObject(sync);
  301. // R<PayIndex> object1 = JSONObject.parseObject(sync,new R<PayIndex>().getClass());
  302. // return JSONObject.parseObject(sync, new TypeReference<>() {
  303. // });
  304. TypeReference<R<PayIndex>> typeRef = new TypeReference<R<PayIndex>>() {};
  305. return JSONObject.parseObject(sync, typeRef);
  306. //return JSONObject.parseObject(sync,new R<PayIndex>().getClass());
  307. //return (R<PayIndex>) ((JSONObject) JSONObject.parseObject(sync)).values();
  308. }
  309. /**
  310. * 冻结资金
  311. * 中台逻辑:
  312. * 先判断预付金额是否足够,足够就冻结预付金额。
  313. * 不够则进行追加预付操作,在进行冻结
  314. *
  315. * @param uid 付款方uid
  316. * @param channel 支付通道
  317. * @param money 冻结金额,单位分
  318. * @param filter 收款方uid
  319. * @param businessNo 流水号
  320. * @return
  321. */
  322. public R<Freeze> walletFreeze(String uid, ChannelEnum channel, String filter, Long money, String businessNo) {
  323. String sync = postHttp(PayCenterEnum.WALLET_FREEZE, new HashMap<>() {{
  324. put("uid", uid);
  325. put("filter", filter);
  326. put("channel", channel);
  327. put("money", money);
  328. put("business_no", businessNo);
  329. }});
  330. TypeReference<R<Freeze>> typeRef = new TypeReference<R<Freeze>>() {};
  331. return JSONObject.parseObject(sync, typeRef);
  332. }
  333. /**
  334. * 解冻金额
  335. *
  336. * @param businessNo
  337. * @return
  338. */
  339. public R<BusinessNo> walletUnFreeze(String businessNo) {
  340. String sync = postHttp(PayCenterEnum.WALLET_UNFREEZE, new HashMap<>() {{
  341. put("business_no", businessNo);
  342. }});
  343. return JSONObject.parseObject(sync, new TypeReference<>() {
  344. });
  345. }
  346. /**
  347. * 清分
  348. * 中台逻辑:
  349. * 先从预付金额中进行扣除,然后金额不够的情况下在调用三方接口进行清分,然后进行记账
  350. * 因为预付业务实际就是真实的清分业务,所以先判断预付金额是否足够
  351. *
  352. * @param buyUid
  353. * @param sellUid
  354. * @param channel
  355. * @param money
  356. * @param batchPayList
  357. * @param businessNo
  358. * @return
  359. */
  360. public R<BusinessNo> payAgentPay(String buyUid, String sellUid, ChannelEnum channel, Long money, List<PatchPay> batchPayList, String businessNo) {
  361. JSONObject jsonObject = new JSONObject();
  362. jsonObject.put("buy_uid", buyUid);
  363. jsonObject.put("sell_uid", sellUid);
  364. jsonObject.put("channel", channel.getChannel());
  365. jsonObject.put("money", money);
  366. jsonObject.put("batch_pay_list", batchPayList);
  367. jsonObject.put("business_no", businessNo);
  368. String sync = jsonHttp(PayCenterEnum.PAY_AGENT_PAY, jsonObject);
  369. return JSONObject.parseObject(sync, new TypeReference<>() {
  370. });
  371. }
  372. /**
  373. * 清分
  374. *
  375. * @param buyUid 付款方uid
  376. * @param sellUid 收款方
  377. * @param channel 渠道
  378. * @param money 总清分金额
  379. * @param batchPayList 收款方集合
  380. * @param businessNo 流水号
  381. * @param payType 支付类型 0-默认 1-仅预付支付 2-仅余额支付
  382. * @return
  383. */
  384. public R<BusinessNo> payAgentPayV2(String buyUid, String sellUid, ChannelEnum channel, Long money, List<PatchPay> batchPayList, String businessNo, String payType) {
  385. JSONObject jsonObject = new JSONObject();
  386. jsonObject.put("buy_uid", buyUid);
  387. jsonObject.put("sell_uid", sellUid);
  388. jsonObject.put("channel", Objects.nonNull(channel) ? channel.getChannel() : "");
  389. jsonObject.put("money", money);
  390. jsonObject.put("batch_pay_list", batchPayList);
  391. jsonObject.put("business_no", businessNo);
  392. jsonObject.put("pay_type", payType);
  393. String sync = jsonHttp(PayCenterEnum.PAY_AGENT_PAY_V2, jsonObject);
  394. // return JSONObject.parseObject(sync, new TypeReference<>() {
  395. // });
  396. TypeReference<R<BusinessNo>> typeRef = new TypeReference<R<BusinessNo>>() {};
  397. return JSONObject.parseObject(sync, typeRef);
  398. }
  399. /**
  400. * 创建钱包
  401. *
  402. * @param uid
  403. * @param channel
  404. * @param filter
  405. * @param nickname
  406. * @return
  407. */
  408. public R<Object> walletIndex(@NotBlank(message = "uid不能为空") String uid, @NotNull(message = "支付渠道不能为空") ChannelEnum channel, @NotBlank(message = "filter不能为空") String filter, String nickname) {
  409. String sync = postHttp(PayCenterEnum.WALLET_INDEX, new HashMap<>() {{
  410. put("uid", uid);
  411. put("channel", channel);
  412. put("filter", filter);
  413. put("nickname", nickname);
  414. }});
  415. return JSONObject.parseObject(sync, new TypeReference<>() {
  416. });
  417. }
  418. /**
  419. * @description: 根据单号,获取充值记录详情
  420. * @author: xj
  421. * @date: 2025/1/14 星期二 16:28
  422. * @param:
  423. * @return: null
  424. **/
  425. public R<PayOrderDetail> getPayDetailByOrderNo(String orderNo) {
  426. String sync = getHttp(PayCenterEnum.PAY_DETAIL_BY_ORDER_NO, new HashMap<>() {{
  427. put("order_no", orderNo);
  428. }});
  429. return JSONObject.parseObject(sync, new TypeReference<>() {
  430. });
  431. }
  432. }