AirwallexPayController.java 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810
  1. package com.szwl.controller;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  5. import com.baomidou.mybatisplus.core.toolkit.Wrappers;
  6. import com.fasterxml.jackson.core.JsonProcessingException;
  7. import com.fasterxml.jackson.databind.JsonNode;
  8. import com.fasterxml.jackson.databind.ObjectMapper;
  9. import com.fasterxml.jackson.databind.node.ArrayNode;
  10. import com.fasterxml.jackson.databind.node.JsonNodeFactory;
  11. import com.fasterxml.jackson.databind.node.ObjectNode;
  12. import com.szwl.common.AccessTokenCommon;
  13. import com.szwl.constant.AirwallexConstant;
  14. import com.szwl.feign.bean.SzwlFeign;
  15. import com.szwl.model.bean.PaymentIntentRequestBody;
  16. import com.szwl.model.bean.RefundRequestBody;
  17. import com.szwl.model.bo.R;
  18. import com.szwl.model.bo.ResponseModel;
  19. import com.szwl.model.dto.*;
  20. import com.szwl.model.entity.*;
  21. import com.szwl.model.utils.AccessTokenThreadUtil;
  22. import com.szwl.service.*;
  23. import io.swagger.annotations.Api;
  24. import io.swagger.annotations.ApiOperation;
  25. import lombok.extern.slf4j.Slf4j;
  26. import org.apache.commons.lang.StringUtils;
  27. import org.springframework.beans.factory.annotation.Value;
  28. import org.springframework.scheduling.annotation.Scheduled;
  29. import org.springframework.web.bind.annotation.*;
  30. import java.math.BigDecimal;
  31. import java.math.RoundingMode;
  32. import java.sql.Timestamp;
  33. import java.text.ParseException;
  34. import java.text.SimpleDateFormat;
  35. import java.time.OffsetDateTime;
  36. import java.time.format.DateTimeFormatter;
  37. import java.util.*;
  38. //@CrossOrigin
  39. @Api(value = "/api/airwallexPay", tags = {"空中云汇"})
  40. @RestController
  41. @RequestMapping("/api/airwallexPay")
  42. @Slf4j
  43. public class AirwallexPayController {
  44. // @Value("${test.value:bbb}")
  45. // private String testValue;
  46. TAdminService tAdminService;
  47. AirwallexService airwallexService;
  48. TCoinOrderService tCoinOrderService;
  49. TOrderDetailsService tOrderDetailsService;
  50. TAirwallexPaymentService tAirwallexPaymentService;
  51. SzwlFeign szwlFeign;
  52. TAirwallexMchService airwallexMchService;
  53. TAirwallexWalletService airwallexWalletService;
  54. public AirwallexPayController(TAdminService tAdminService, AirwallexService airwallexService, TCoinOrderService tCoinOrderService, TOrderDetailsService tOrderDetailsService, TAirwallexPaymentService tAirwallexPaymentService, SzwlFeign szwlFeign, TAirwallexMchService airwallexMchService, TAirwallexWalletService airwallexWalletService) {
  55. this.tAdminService = tAdminService;
  56. this.airwallexService = airwallexService;
  57. this.tCoinOrderService = tCoinOrderService;
  58. this.tOrderDetailsService = tOrderDetailsService;
  59. this.tAirwallexPaymentService = tAirwallexPaymentService;
  60. this.szwlFeign = szwlFeign;
  61. this.airwallexMchService = airwallexMchService;
  62. this.airwallexWalletService = airwallexWalletService;
  63. }
  64. @ApiOperation(value = "创建收款人")
  65. @PostMapping("/caBeneficiary")
  66. public JsonNode caBeneficiary(@RequestBody CaBeneficiaryRequestDTO requestDTO) {
  67. BeneficiaryDTO beneficiary = requestDTO.getBeneficiary();
  68. List<String> paymentMethods = requestDTO.getPaymentMethods();
  69. String nickname = requestDTO.getNickname();
  70. String resp = airwallexService.caBeneficiary(beneficiary, nickname, paymentMethods);
  71. try {
  72. JsonNode jsonNode = new ObjectMapper().readTree(resp);
  73. return jsonNode;
  74. } catch (JsonProcessingException e) {
  75. e.printStackTrace();
  76. }
  77. // JSONObject jsonObject = JSON.parseObject(resp);
  78. // String beneficiaryId = jsonObject.getString("beneficiary_id");
  79. return null;
  80. }
  81. @ApiOperation(value = "获取authCode")
  82. @PostMapping("/getAuthCode")
  83. public JsonNode getAuthCode(@RequestBody GetAuthCodeDTO getAuthCodeDTO) {
  84. String codeChallenge = getAuthCodeDTO.getCodeChallenge();
  85. String[] scope = getAuthCodeDTO.getScope();
  86. String resp = airwallexService.getAuthCode(codeChallenge, scope);
  87. try {
  88. JsonNode jsonNode = new ObjectMapper().readTree(resp);
  89. return jsonNode;
  90. } catch (JsonProcessingException e) {
  91. e.printStackTrace();
  92. }
  93. return null;
  94. }
  95. // @GetMapping("/getAccessToken")
  96. // public ResponseModel<?> getAccessToken() {
  97. // String accessToken = airwallexService.getAccessToken();
  98. // //获取到的accessToken可以放入内存或者存到数据库中,不用每次都获取
  99. // return R.ok(accessToken);
  100. // }
  101. @ApiOperation(value = "获取token")
  102. @GetMapping("/getAccessToken")
  103. @Scheduled(cron = "0 0/20 * * * ?")
  104. public void getAccessToken() {
  105. AccessTokenCommon.ACCESS_TOKEN = AccessTokenThreadUtil.getAccessToken();
  106. }
  107. /**
  108. * 创建付款意向 - 消费者发起
  109. *
  110. * @param paymentIntentRequestBody
  111. * @return
  112. */
  113. @ApiOperation(value = "Create a PaymentIntent")
  114. @PostMapping("/createAPaymentIntent")
  115. public R createAPaymentIntent(@RequestBody PaymentIntentRequestBody paymentIntentRequestBody) {
  116. log.info("发起支付请求");
  117. // 先获取token
  118. // String accessToken = airwallexService.getAccessToken();
  119. // new AccessTokenThreadUtil().run();
  120. // String accessToken = AccessTokenCommon.ACCESS_TOKEN;
  121. //
  122. // if(accessToken == null || "".equals(accessToken)) {
  123. // accessToken = new AccessTokenThreadUtil().getAccessToken();
  124. // return R.fail(L0006);
  125. // }
  126. // 如果是海外客户,使用的是 Airwallex ,就要判断他有没有设置分销
  127. // 在 Airwallex 支付之前,要先判断
  128. String createDate = paymentIntentRequestBody.getCreateDate();
  129. BigDecimal amount = paymentIntentRequestBody.getAmount();
  130. String currency = paymentIntentRequestBody.getCurrency();
  131. String merchantOrderId = paymentIntentRequestBody.getMerchantOrderId();
  132. // String requestId = paymentIntentRequestBody.getRequestId();
  133. String requestId = UUID.randomUUID().toString().trim().replaceAll("-", "");
  134. Long productId = paymentIntentRequestBody.getProductId();
  135. String productName = paymentIntentRequestBody.getProductName();
  136. String clientId = paymentIntentRequestBody.getClientId();
  137. Long equipmentId = paymentIntentRequestBody.getEquipmentId();
  138. Integer productNumber = paymentIntentRequestBody.getProductNumber();
  139. // 生成订单编号
  140. String sn = tCoinOrderService.initSn(equipmentId);
  141. // 七云还是申泽
  142. TEquipment equipment = R.getDataIfSuccess(szwlFeign.findEquipmentByClientId(clientId));
  143. if (equipment == null || equipmentId == null) {
  144. return R.fail("找不到设备");
  145. }
  146. // System.out.println("设备信息:>>> " + equipment);
  147. String machineType = equipment.getMachineType(); // 设备类型
  148. Long adminId = equipment.getAdminId();
  149. if (adminId == null) {
  150. return R.fail("找不到设备商家");
  151. }
  152. String adminIdStr = String.valueOf(adminId);
  153. // 根据 adminId 获取admin信息中的公司类型
  154. TAdmin adminById = R.getDataIfSuccess(szwlFeign.getAdmin(adminIdStr));
  155. // TAdmin byId = tAdminService.getById(adminId);
  156. String companyType = adminById.getCompanyType(); // 公司类型
  157. // Airwallex 分账参数
  158. ArrayNode altInfos = JsonNodeFactory.instance.arrayNode();
  159. // Airwallex 分账明细
  160. ObjectNode airDistributionDetails = JsonNodeFactory.instance.objectNode();
  161. // 查找商品
  162. ResponseModel<TProduct> product = szwlFeign.getProduct(String.valueOf(equipmentId), productName);
  163. // 获取关联设备的分销
  164. TProportion proportion = R.getDataIfSuccess(szwlFeign.getProportion(String.valueOf(equipmentId)));
  165. airDistributionDetails = getDistributionDetails(proportion, amount);
  166. // 创建订单
  167. TCoinOrder tCoinOrder = new TCoinOrder();
  168. tCoinOrder.setAdminId(adminById.getId());
  169. if (StringUtils.isNotEmpty(createDate)) {
  170. SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  171. Date parse = null;
  172. try {
  173. parse = simpleDateFormat.parse(createDate);
  174. } catch (ParseException e) {
  175. throw new RuntimeException(e);
  176. }
  177. tCoinOrder.setCreateDate(parse);
  178. tCoinOrder.setModifyDate(parse);
  179. } else {
  180. tCoinOrder.setCreateDate(new Date());
  181. tCoinOrder.setModifyDate(new Date());
  182. }
  183. tCoinOrder.setPayDate(new Date());
  184. tCoinOrder.setSn(sn);
  185. tCoinOrder.setAmount(amount);
  186. tCoinOrder.setCurrency(currency);
  187. tCoinOrder.setMerchantOrderId(merchantOrderId);
  188. tCoinOrder.setRequestId(requestId);
  189. tCoinOrder.setProductId(productId);
  190. tCoinOrder.setProductName(productName);
  191. tCoinOrder.setProductNumber(productNumber);
  192. tCoinOrder.setClientId(clientId);
  193. tCoinOrder.setEquipmentId(equipmentId);
  194. // 设置订单支付状态,0未支付,1已支付,3已退款。
  195. tCoinOrder.setStatus(0);
  196. tCoinOrder.setIsAir("1");
  197. tCoinOrder.setAltInfo(altInfos.toString());
  198. tCoinOrder.setMachineType(machineType);
  199. tCoinOrder.setCompanyType(companyType);
  200. tCoinOrder.setType(adminById.getType());
  201. switch (adminById.getType()) {
  202. case 0:
  203. tCoinOrder.setAdminProportion(proportion.getAdminProportion());
  204. tCoinOrder.setAgencyProportion(proportion.getAgencyProportion());
  205. tCoinOrder.setAgencyId(proportion.getAgencyId());
  206. break;
  207. case 1:
  208. tCoinOrder.setAdminProportion(proportion.getAdminProportion());
  209. tCoinOrder.setAgencyProportion(proportion.getAgencyProportion());
  210. tCoinOrder.setAgencyId(proportion.getAgencyId());
  211. tCoinOrder.setMerchantProportion(proportion.getMerchantProportion());
  212. tCoinOrder.setMerchantId(proportion.getMerchantId());
  213. break;
  214. case 2:
  215. tCoinOrder.setAdminProportion(proportion.getAdminProportion());
  216. tCoinOrder.setAgencyProportion(proportion.getAgencyProportion());
  217. tCoinOrder.setAgencyId(proportion.getAgencyId());
  218. tCoinOrder.setMerchantProportion(proportion.getMerchantProportion());
  219. tCoinOrder.setMerchantId(proportion.getMerchantId());
  220. tCoinOrder.setPersonageProportion(proportion.getPersonageProportion());
  221. tCoinOrder.setPersonageId(proportion.getPersonageId());
  222. break;
  223. default:
  224. // 如果类型不匹配任何 case,则执行默认逻辑
  225. break;
  226. }
  227. tCoinOrder.setAltInfo(airDistributionDetails.toString());
  228. // 订单明细表
  229. TOrderDetails tOrderDetails = new TOrderDetails();
  230. tOrderDetails.setId(merchantOrderId);
  231. tOrderDetails.setAdminId(adminById.getId());
  232. tOrderDetails.setEquipmentId(equipmentId);
  233. if (StringUtils.isNotEmpty(createDate)) {
  234. SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  235. Date parse = null;
  236. try {
  237. parse = simpleDateFormat.parse(createDate);
  238. } catch (ParseException e) {
  239. throw new RuntimeException(e);
  240. }
  241. tOrderDetails.setCreateDate(parse);
  242. } else {
  243. tOrderDetails.setCreateDate(new Date());
  244. }
  245. tOrderDetails.setOrderSn(sn);
  246. tOrderDetails.setPrice(amount);
  247. tOrderDetails.setProductName(productName);
  248. tOrderDetails.setProductNo(product.getData().getNo());
  249. tOrderDetails.setProductNumber(productNumber);
  250. tOrderDetails.setAmount(amount);
  251. tOrderDetails.setRefundStatus("0");
  252. tOrderDetails.setCompanyType(companyType);
  253. tOrderDetails.setMachineType(machineType);
  254. String clientSix = clientId.substring(clientId.length() - 6);
  255. String productNameMerge = "";
  256. if (productNumber > 1) {
  257. if (machineType == null || "0".equals(machineType)) {
  258. productNameMerge = "棉花糖-" + equipment.getName() + "-" + clientSix;
  259. } else {
  260. productNameMerge = "爆米花-" + equipment.getName() + "-" + clientSix;
  261. }
  262. } else {
  263. productNameMerge = productName + "-" + equipment.getName() + "-" + clientSix;
  264. }
  265. ObjectMapper mapper = new ObjectMapper();
  266. ObjectNode order = mapper.createObjectNode();
  267. ArrayNode products = mapper.createArrayNode();
  268. ObjectNode airProduct = mapper.createObjectNode();
  269. // Name of the product. Maximum of 255 characters.
  270. // airProduct.put("name", productNameMerge);
  271. // Product description. Maximum of 500 characters.
  272. airProduct.put("desc", productNameMerge);
  273. airProduct.put("quantity", productNumber);
  274. products.add(airProduct);
  275. order.set("products", products);
  276. // 返回payment intent id和client secret
  277. Map<String, Object> responseMap = airwallexService.caPaymentIntent(amount, currency, requestId, merchantOrderId, order);
  278. String paymentIntentId = (String) responseMap.get("id");
  279. String clientSecret = (String) responseMap.get("client_secret");
  280. // 把 paymentIntentId 保存到表中
  281. tCoinOrder.setPaymentIntentId(paymentIntentId);
  282. // boolean save = tOrderAbroadService.save(tOrderAbroad);
  283. // System.out.println("将订单存入数据库:" + save);
  284. // 拼接二维码链接给前端
  285. // String env = AirwallexConstant.ENV;
  286. // String mode = AirwallexConstant.MODE;
  287. // String locale = "it";
  288. String qrUrl = AirwallexConstant.QR_URL;
  289. String QR = qrUrl + "?intent_id=" + paymentIntentId + "&client_secret=" + clientSecret + "&currency=" + currency;
  290. // 将订单存入数据库
  291. tCoinOrderService.save(tCoinOrder);
  292. tOrderDetailsService.save(tOrderDetails);
  293. return R.ok().setData(QR);
  294. }
  295. @ApiOperation(value = "获取支付订单的信息,订单状态")
  296. @GetMapping("/retrieveAPaymentIntent")
  297. public JSON retrieveAPaymentIntent(@RequestParam String id) {
  298. log.info("查询支付订单信息");
  299. // 这里的intId指的是paymentIntendId,也是id
  300. String intentResp = airwallexService.retrieveAPaymentIntent(id);
  301. JSONObject jsonObject = JSON.parseObject(intentResp);
  302. // 取消订单的原因
  303. // String cancellationReason = jsonObject.getString("cancellation_reason");
  304. // 支付信息
  305. String amount = jsonObject.getString("amount");
  306. String currency = jsonObject.getString("currency");
  307. String createdAt = jsonObject.getString("created_at");
  308. String updatedAt = jsonObject.getString("updated_at");
  309. String status = jsonObject.getString("status");
  310. // String customer = jsonObject.getString("customer");
  311. // JSONObject customerObj = JSON.parseObject(customer);
  312. // String address = customerObj.getString("address");
  313. // TODO: 要改???
  314. String type = jsonObject.getJSONObject("latest_payment_attempt").getJSONObject("payment_method").getString("type");
  315. // JSONObject jsonObject4 = Optional.ofNullable(jsonObject)
  316. // .flatMap(jsonObject3 -> Optional.ofNullable(jsonObject3.getJSONObject("customer")))
  317. // .flatMap(jsonObject3 -> Optional.ofNullable(jsonObject3.getJSONObject("address")))
  318. // .flatMap(jsonObject3 -> Optional.ofNullable(jsonObject3.getJSONObject("state")))
  319. // .orElse(null);
  320. // String state = JSON.toJSONString(jsonObject4);
  321. // JSONObject jsonObject3 = Optional.ofNullable(jsonObject)
  322. // .map(jsonObject1 -> jsonObject1.getJSONObject("latest_payment_attempt"))
  323. // .map(jsonObject1 -> jsonObject1.getJSONObject("payment_method"))
  324. // .map(jsonObject1 -> jsonObject1.getJSONObject("type"))
  325. // .orElse(null);
  326. // String state = JSON.toJSONString(jsonObject3);
  327. // JSONObject stateJson = Optional.ofNullable(jsonObject)
  328. // .flatMap(jsonObject1 -> Optional.ofNullable(jsonObject1.getJSONObject("customer")))
  329. // .flatMap(jsonObject1 -> Optional.ofNullable(jsonObject1.getJSONObject("address")))
  330. // .flatMap(jsonObject1 -> Optional.ofNullable(jsonObject1.getJSONObject("state")))
  331. // .orElse(null);
  332. // String state = JSON.toJSONString(stateJson);
  333. // JSONObject cityJson = Optional.ofNullable(jsonObject)
  334. // .flatMap(jsonObject1 -> Optional.ofNullable(jsonObject1.getJSONObject("latest_payment_attempt")))
  335. // .flatMap(jsonObject1 -> Optional.ofNullable(jsonObject1.getJSONObject("payment_method")))
  336. // .flatMap(jsonObject1 -> Optional.ofNullable(jsonObject1.getJSONObject("id")))
  337. // .orElse(null);
  338. // String city = JSON.toJSONString(cityJson);
  339. Map<String, Object> intentDetails = new HashMap<>();
  340. intentDetails.put("amount", amount);
  341. intentDetails.put("currency", currency);
  342. // intentDetails.put("state",state);
  343. intentDetails.put("type", type);
  344. intentDetails.put("createdAt", createdAt);
  345. intentDetails.put("status", status);
  346. return new JSONObject(intentDetails);
  347. }
  348. @ApiOperation(value = "发起退款")
  349. @PostMapping("/createARefund")
  350. public ResponseModel<String> createARefund(@RequestBody RefundRequestBody refundRequestBody) {
  351. log.info("发起退款");
  352. String requestId = UUID.randomUUID().toString().trim().replaceAll("-", "");
  353. // String requestId = refundRequestBody.getRequestId();
  354. String paymentIntentId = refundRequestBody.getPaymentIntentId();
  355. Date refundDate = refundRequestBody.getRefundDate();
  356. // String reason = refundRequestBody.getReason();
  357. // QueryWrapper<TOrderAbroad> tOrderAbroadQueryWrapper = new QueryWrapper<>();
  358. // tOrderAbroadQueryWrapper.eq("request_id", requestId);
  359. // TOrderAbroad orderAbroad = tOrderAbroadService.getOne(tOrderAbroadQueryWrapper);
  360. LambdaQueryWrapper<TCoinOrder> lambdaQueryWrapper = Wrappers.lambdaQuery();
  361. lambdaQueryWrapper.eq(TCoinOrder::getPaymentIntentId, paymentIntentId);
  362. TCoinOrder coinOrder = tCoinOrderService.getOne(lambdaQueryWrapper);
  363. if (coinOrder == null) {
  364. return R.fail("订单为空/error");
  365. }
  366. // 支付状态:退款中
  367. coinOrder.setStatus(2);
  368. // 修改订单表
  369. // SimpleDateFormat sdf = new SimpleDateFormat();
  370. // sdf.applyPattern("yyyy-MM-dd HH:mm:ss");
  371. // orderAbroad.setRefundDate(sdf.format(date));
  372. // LocalDateTime localDateTime = LocalDateTime.now();
  373. // DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
  374. // String format = localDateTime.format(dtf);
  375. // 退款发起时间
  376. coinOrder.setRefundDate(refundDate);
  377. tCoinOrderService.updateById(coinOrder);
  378. // TODO: 退款要扣除用户钱包中的金额,如果金额为0或者不足,改为负数?或者提示余额不足,联系商家手动退款
  379. // 发起退款
  380. // String refund = airwallexService.createARefund(requestId, paymentIntentId, reason);
  381. String refund = airwallexService.createARefund(requestId, paymentIntentId);
  382. System.out.println(refund);
  383. JSONObject jsonObject = JSON.parseObject(refund);
  384. String status = jsonObject.getString("status");
  385. // orderAbroad.set;
  386. // tOrderAbroadService.updateById(orderAbroad);
  387. // switch (status) {
  388. // case "RECEIVED" :
  389. // System.out.println("退款被接收");
  390. // break;
  391. // case "ACCEPTED" :
  392. // System.out.println("退款被接受");
  393. // break;
  394. // case "SUCCEEDED" :
  395. // System.out.println("退款成功");
  396. // break;
  397. // case "FAILED" :
  398. // System.out.println("退款失败");
  399. // break;
  400. // }
  401. // if (!status.equals("FAILED")) {
  402. if (status.equals("RECEIVED") || status.equals("ACCEPTED") || status.equals("SUCCEEDED")) {
  403. String refundId = jsonObject.getString("id");
  404. coinOrder.setRefundId(refundId);
  405. tCoinOrderService.updateById(coinOrder);
  406. return R.ok("退款处理中,请稍候查询");
  407. }
  408. return R.fail("退款失败");
  409. // if (Objects.equals(status, "SUCCEEDED")) {
  410. // String refundId = jsonObject.getString("id");
  411. // orderAbroad.setRefundId(refundId);
  412. //// orderAbroad.setPayStatus(3);
  413. // tOrderAbroadService.updateById(orderAbroad);
  414. // return R.ok("退款申请中,请稍候查询");
  415. // } else {
  416. // return R.ok("退款失败");
  417. // }
  418. }
  419. @ApiOperation(value = "查询某笔退款详情")
  420. @GetMapping("/retrieveARefund/{id}")
  421. public Map<String, Object> retrieveARefund(@PathVariable("id") String refundId) {
  422. log.info("根据rfd_查询某笔退款详情");
  423. // String requestId = UUID.randomUUID().toString().trim().replaceAll("-", "");
  424. String refundResp = airwallexService.retrieveARefund(refundId);
  425. JSONObject jsonObject = JSON.parseObject(refundResp);
  426. String amount = jsonObject.getString("amount");
  427. String status = jsonObject.getString("status");
  428. String currency = jsonObject.getString("currency");
  429. String paymentIntentId = jsonObject.getString("payment_intent_id");
  430. String createdAt = jsonObject.getString("created_at");
  431. Map<String, Object> hashMap = new HashMap<>();
  432. hashMap.put("amount", amount);
  433. hashMap.put("status", status);
  434. hashMap.put("currency", currency);
  435. hashMap.put("payment_intent_id", paymentIntentId);
  436. hashMap.put("created_at", createdAt);
  437. // if (status.equals("SUCCEEDED")) {
  438. //
  439. // LambdaQueryWrapper<TOrderAbroad> lambdaQueryWrapper = Wrappers.lambdaQuery();
  440. // lambdaQueryWrapper.eq(TOrderAbroad::getRefundId, refundId);
  441. // TOrderAbroad orderAbroad = tOrderAbroadService.getOne(lambdaQueryWrapper);
  442. //
  443. //// if (orderAbroad == null ) {
  444. //// return "订单为空/error";
  445. //// }
  446. // if (Objects.isNull(orderAbroad)) {
  447. // return "订单为空/error";
  448. // }
  449. // // 设置支付状态为 3已退款
  450. // orderAbroad.setPayStatus(3);
  451. // tOrderAbroadService.updateById(orderAbroad);
  452. // }
  453. return hashMap;
  454. }
  455. @ApiOperation(value = "新建一笔付款,用于提现")
  456. @PostMapping("/caPayment")
  457. public R caPayment(@RequestBody CaPaymentRequestDTO caPaymentRequestDTO) {
  458. Long adminId = caPaymentRequestDTO.getAdminId();
  459. String resp = airwallexService.caPayment(caPaymentRequestDTO);
  460. ObjectMapper objectMapper = new ObjectMapper();
  461. JsonNode jsonNode = null;
  462. try {
  463. jsonNode = objectMapper.readTree(resp);
  464. } catch (JsonProcessingException e) {
  465. e.printStackTrace();
  466. }
  467. // 断言确保 jsonNode 不为 null
  468. assert jsonNode != null;
  469. String paymentId = jsonNode.get("payment_id").asText();
  470. String paymentCurrency = jsonNode.get("payment_currency").asText();
  471. String paymentAmountStr = jsonNode.get("payment_amount").asText();
  472. String beneficiaryId = jsonNode.get("beneficiary_id").asText();
  473. String createdAtStr = jsonNode.get("created_at").asText();
  474. // 保存支付提现明细
  475. TAirwallexPayment tAirwallexPayment = new TAirwallexPayment();
  476. tAirwallexPayment.setPaymentId(paymentId);
  477. tAirwallexPayment.setPaymentCurrency(paymentCurrency);
  478. BigDecimal paymentAmount = new BigDecimal(paymentAmountStr);
  479. tAirwallexPayment.setPaymentAmount(paymentAmount);
  480. tAirwallexPayment.setBeneficiaryId(beneficiaryId);
  481. DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ");
  482. OffsetDateTime createdAt = OffsetDateTime.parse(createdAtStr, formatter);
  483. Timestamp from = Timestamp.from(createdAt.toInstant());
  484. tAirwallexPayment.setCreateTime(from);
  485. tAirwallexPayment.setAdminId(adminId);
  486. tAirwallexPaymentService.save(tAirwallexPayment);
  487. // TODO: 默认每次将余额全部提现,考虑货币
  488. // tAirwallexWalletService.list()
  489. // LambdaQueryWrapper<TAirwallexWallet> wrapper = Wrappers.lambdaQuery();
  490. // wrapper.eq(TAirwallexWallet::getAdminId, adminId);
  491. //// List<TAirwallexWallet> list = tAirwallexWalletService.list(wrapper);
  492. // TAirwallexWallet one = tAirwallexWalletService.getOne(wrapper);
  493. // String accountCurrency = one.getAccountCurrency();
  494. // BigDecimal accountAmount = one.getAccountAmount();
  495. // 先判断货币是否一样
  496. // if (accountCurrency.equals(paymentCurrency)) {
  497. // accountAmount = accountAmount.subtract(paymentAmount);
  498. // } else {
  499. // //
  500. // }
  501. // 返回 payment_id
  502. return R.ok(paymentId);
  503. }
  504. @ApiOperation(value = "查询支付结果")
  505. @GetMapping("/getPaymentById/{payment_id}")
  506. public R getPaymentById(@PathVariable("payment_id") String paymentId) {
  507. String resp = airwallexService.getPaymentById(paymentId);
  508. return R.ok(resp);
  509. }
  510. @ApiOperation(value = "查询当前账户余额")
  511. @GetMapping("/getCurrentBalances")
  512. public R getCurrentBalances() {
  513. String resp = airwallexService.getCurrentBalances();
  514. return R.ok(resp);
  515. }
  516. /**
  517. * 获取 Airwallex 分销明细
  518. *
  519. * @param proportion
  520. * @param price
  521. * @return
  522. */
  523. public ObjectNode getDistributionDetails(TProportion proportion, BigDecimal price) {
  524. // 获取分账有几方:0:分账方2个,1:分账方3个,2:分账方4个,3:分账方超4个
  525. Integer type = proportion.getType();
  526. // 空中云汇 分账明细参数
  527. // ArrayNode altInfos = new ObjectMapper().createArrayNode();
  528. ArrayNode altInfos = JsonNodeFactory.instance.arrayNode();
  529. ObjectNode distributionDetails = JsonNodeFactory.instance.objectNode();
  530. BigDecimal airProportion = null, // 空中云汇平台分销百分比,假设是0
  531. selfProportion = null, // 商家自己的分销百分比
  532. agencyProportion = null, // 一级分销商分销百分比
  533. merchantProportion = null; // 二级分销商分销百分比
  534. BigDecimal airAmount = null, // 空中云汇的钱,假设是0
  535. selfAmount = null, // 商家自己所得的钱
  536. agencyAmount = null, // 一级分销商所得的钱
  537. merchantAmount = null; // 二级分销商所得的钱
  538. TAirwallexWallet selfAirWallet = null, // 商家收款信息
  539. agencyAirWallet = null, // 一级分销商收款信息
  540. merchantAirWallet = null; // 二级分销商收款信息
  541. ObjectNode airJson = null, // 空中云汇
  542. selfJson = null, // 商家
  543. agencyJson = null, // 一级
  544. merchantJson = null; // 二级
  545. // 取消平台扣手续费,将price四舍五入保留2位小数
  546. BigDecimal cutPrice = price.setScale(2, RoundingMode.HALF_UP);
  547. BigDecimal refuseAmount = new BigDecimal(0.00);
  548. switch (type) {
  549. case 0: // 分账方有2个:申泽admin + 商家proportion
  550. // 目前都暂定空中云汇平台分销为 0
  551. // airProportion = proportion.getAdminProportion();
  552. // 申泽的分销 eg.1% 不显示
  553. // adminProportion = proportion.getAdminProportion();
  554. // 商家自己的分销
  555. selfProportion = proportion.getProportion();
  556. // 平台分销获得利润
  557. // airAmount = cutPrice.multiply(airProportion.divide(new BigDecimal(100))).setScale(2, RoundingMode.HALF_UP);
  558. // 商家分销获得利润,五舍六入
  559. selfAmount = cutPrice.multiply(selfProportion.divide(new BigDecimal(100))).setScale(2, RoundingMode.HALF_DOWN);
  560. // Airwallex 平台收款信息表
  561. // Long adminId = proportion.getAdminId();
  562. // LambdaQueryWrapper<TAirwallexMch> wrapper = Wrappers.lambdaQuery();
  563. // wrapper.eq(TAirwallexMch::getAdminId, proportion.getAdminId());
  564. // selfAirMch = airwallexMchService.getOne(wrapper);
  565. // Airwallex 钱包信息
  566. LambdaQueryWrapper<TAirwallexWallet> query = Wrappers.lambdaQuery();
  567. query.eq(TAirwallexWallet::getAdminId, proportion.getAdminId());
  568. selfAirWallet = airwallexWalletService.getOne(query);
  569. // 平台分销
  570. // airJson = JsonNodeFactory.instance.objectNode();
  571. // // 分账方受益人编号
  572. // airJson.put("altMchId", selfAirMch.getBeneficiaryId());
  573. // // 受益人所分金额,单位美元$
  574. // airJson.put("altAirAmount", airAmount.toString());
  575. // altInfos.add(airJson);
  576. // 商家分销
  577. selfJson = JsonNodeFactory.instance.objectNode();
  578. selfJson.put("airBeneId", selfAirWallet.getAdminId()); // 受益人Bene编号,使用adminId
  579. selfJson.put("airAmount", selfAmount.toString());
  580. altInfos.add(selfJson);
  581. break;
  582. case 1: // 分账方有3个:申泽admin + 商家proportion + 商家一级agency
  583. // 商家自己的分销
  584. selfProportion = proportion.getProportion();
  585. // 一级代理的分销
  586. agencyProportion = proportion.getAgencyProportion();
  587. // 商家分销获得利润
  588. selfAmount = cutPrice.multiply(selfProportion.divide(new BigDecimal(100))).setScale(2, RoundingMode.HALF_DOWN);
  589. // Airwallex 平台收款信息表
  590. agencyAirWallet = airwallexWalletService.getAirWallet(proportion.getAgencyId());
  591. selfAirWallet = airwallexWalletService.getAirWallet(proportion.getAdminId());
  592. if (!(agencyProportion.compareTo(refuseAmount) == 0 || agencyProportion == null)) {
  593. // 一级代理获得利润
  594. agencyAmount = cutPrice.multiply(agencyProportion.divide(new BigDecimal(100))).setScale(2, RoundingMode.HALF_DOWN);
  595. agencyJson = JsonNodeFactory.instance.objectNode();
  596. agencyJson.put("airBeneId", agencyAirWallet.getAdminId());
  597. agencyJson.put("airAmount", agencyAmount.toString());
  598. altInfos.add(agencyJson);
  599. }
  600. // 商家自己获得利润
  601. selfJson = JsonNodeFactory.instance.objectNode();
  602. selfJson.put("airBeneId", selfAirWallet.getAdminId());
  603. selfJson.put("airAmount", selfAmount.toString());
  604. altInfos.add(selfJson);
  605. break;
  606. case 2: // 分账方有4个:申泽admin + 商家self + 商家一级agency + 商家二级merchant
  607. // 商家自己的分销
  608. selfProportion = proportion.getProportion();
  609. // 一级代理的分销
  610. agencyProportion = proportion.getAgencyProportion();
  611. // 二级代理的分销
  612. merchantProportion = proportion.getMerchantProportion();
  613. // 商家分销获得利润,五舍六入
  614. selfAmount = cutPrice.multiply(selfProportion.divide(new BigDecimal(100))).setScale(2, RoundingMode.HALF_DOWN);
  615. // Airwallex 平台收款信息表
  616. Long adminId = proportion.getAdminId();
  617. if (adminId != null) {
  618. selfAirWallet = airwallexWalletService.getAirWallet(adminId);
  619. System.out.println("selfAirWallet打印出来》》》" + selfAirWallet);
  620. }
  621. Long agencyId = proportion.getAgencyId();
  622. if (agencyId != null) {
  623. agencyAirWallet = airwallexWalletService.getAirWallet(agencyId);
  624. System.out.println("agencyAirWallet打印出来》》》" + agencyAirWallet);
  625. }
  626. Long merchantId = proportion.getMerchantId();
  627. if (merchantId != null ) {
  628. merchantAirWallet = airwallexWalletService.getAirWallet(merchantId);
  629. System.out.println("merchantAirWallet打印出来》》》" + merchantAirWallet);
  630. }
  631. if (!(agencyProportion.compareTo(refuseAmount) == 0 || agencyProportion == null)) {
  632. // 一级代理获得利润
  633. agencyAmount = cutPrice.multiply(agencyProportion.divide(new BigDecimal(100))).setScale(2, RoundingMode.HALF_DOWN);
  634. agencyJson = JsonNodeFactory.instance.objectNode();
  635. agencyJson.put("airBeneId", agencyAirWallet.getAdminId());
  636. agencyJson.put("airAmount", agencyAmount.toString());
  637. altInfos.add(agencyJson);
  638. }
  639. if (!(merchantProportion.compareTo(refuseAmount) == 0 || merchantProportion == null)) {
  640. // 二级经销商获得利润
  641. merchantAmount = cutPrice.multiply(merchantProportion.divide(new BigDecimal(100))).setScale(2, RoundingMode.HALF_DOWN);
  642. merchantJson = JsonNodeFactory.instance.objectNode();
  643. merchantJson.put("airBeneId", merchantAirWallet.getAdminId());
  644. merchantJson.put("airAmount", merchantAmount.toString());
  645. altInfos.add(merchantJson);
  646. }
  647. // 商家自己获得利润
  648. selfJson = JsonNodeFactory.instance.objectNode();
  649. selfJson.put("airBeneId", selfAirWallet.getAdminId());
  650. selfJson.put("airAmount", selfAmount.toString());
  651. altInfos.add(selfJson);
  652. break;
  653. case 3: // 分账方超过4个:申泽admin + 商家self + 商家一级agency + 商家二级merchant + 商家三级personage
  654. // personageProportion = proportion.getPersonageProportion();
  655. break;
  656. }
  657. // 计算airAmount的总和
  658. BigDecimal sumAmount = BigDecimal.ZERO;
  659. Iterator<JsonNode> iterator = altInfos.iterator();
  660. while (iterator.hasNext()) {
  661. JsonNode jsonNode = iterator.next();
  662. String airAmounts = jsonNode.get("airAmount").asText();
  663. if (airAmounts.equals("0.00")) {
  664. iterator.remove();
  665. }
  666. if (jsonNode.has("airAmount")) {
  667. BigDecimal airAmountSum = new BigDecimal(jsonNode.get("airAmount").asText());
  668. sumAmount = sumAmount.add(airAmountSum);
  669. }
  670. }
  671. // 如果sumAmount大于原本price
  672. if (sumAmount.compareTo(price) > 0) {
  673. BigDecimal subtract = sumAmount.subtract(price);
  674. Iterator<JsonNode> iterator1 = altInfos.iterator();
  675. while (iterator1.hasNext()) {
  676. JsonNode jsonNode = iterator1.next();
  677. String airBeneId = jsonNode.get("airBeneId").asText();
  678. // String airBeneId1 = jsonNode.get("airBeneId").toString();
  679. if (airBeneId.equals(AirwallexConstant.clientid)) {
  680. BigDecimal airAmount1 = new BigDecimal(jsonNode.get("airAmount").asText());
  681. BigDecimal fixAirAmount = airAmount1.subtract(subtract).max(BigDecimal.ZERO);
  682. // ObjectMapper objectMapper = new ObjectMapper();
  683. // ObjectNode objectNode = objectMapper.convertValue(jsonNode, ObjectNode.class);
  684. // objectNode.put("airAmount", fixAirAmount.toString());
  685. ((ObjectNode) jsonNode).put("airAmount", fixAirAmount.toString());
  686. break;
  687. }
  688. }
  689. }
  690. distributionDetails.put("alt_infos", altInfos);
  691. return distributionDetails;
  692. }
  693. // 查询实时汇率
  694. // Retrieve an indicative MarketFX quote
  695. @ApiOperation(value = "查询实时汇率")
  696. @GetMapping("/getMarketFX")
  697. public Map<String, Object> getMarketFX(@RequestParam Map<String, String> params) {
  698. String buyCurrency = params.get("buy_currency");
  699. String sellCurrency = params.get("sell_currency");
  700. BigDecimal buyAmount = new BigDecimal(params.get("buy_amount"));
  701. Map<String, Object> marketFX = airwallexService.getMarketFX(buyCurrency, sellCurrency, buyAmount);
  702. return marketFX;
  703. }
  704. }