You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

509 lines
23 KiB

3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
  1. package com.example.demo.serviceImpl.cash;
  2. import com.example.demo.Util.JWTUtil;
  3. import com.example.demo.config.RabbitMQConfig;
  4. import com.example.demo.domain.entity.*;
  5. import com.example.demo.domain.vo.cash.CashCollection;
  6. import com.example.demo.domain.vo.cash.CashCollectionMessage;
  7. import com.example.demo.domain.vo.coin.GoldUser;
  8. import com.example.demo.domain.vo.coin.Messages;
  9. import com.example.demo.domain.vo.coin.Result;
  10. import com.example.demo.mapper.cash.CashCollectionMapper;
  11. import com.example.demo.mapper.coin.MarketMapper;
  12. import com.example.demo.mapper.coin.UserMapper;
  13. import com.example.demo.service.cash.CashCollectionService;
  14. import com.github.pagehelper.PageHelper;
  15. import com.github.pagehelper.PageInfo;
  16. import jakarta.servlet.http.HttpServletRequest;
  17. import lombok.extern.slf4j.Slf4j;
  18. import org.springframework.amqp.rabbit.core.RabbitTemplate;
  19. import org.springframework.beans.factory.annotation.Autowired;
  20. import org.springframework.stereotype.Service;
  21. import org.springframework.transaction.annotation.Transactional;
  22. import org.springframework.util.CollectionUtils;
  23. import org.springframework.web.context.request.RequestContextHolder;
  24. import org.springframework.web.context.request.ServletRequestAttributes;
  25. import java.math.BigDecimal;
  26. import java.time.LocalDateTime;
  27. import java.time.ZoneOffset;
  28. import java.util.Arrays;
  29. import java.util.List;
  30. import java.util.Objects;
  31. import java.util.UUID;
  32. import java.util.stream.Collectors;
  33. /**
  34. * @program: gold-java
  35. * @ClassName cashCollectionServiceImpl
  36. * @description: 处理收款相关业务逻辑
  37. * @author: Ethan
  38. * @create: 202509-26 11:23
  39. * @Version 1.0
  40. **/
  41. @Service
  42. @Slf4j
  43. public class CashCollectionServiceImpl implements CashCollectionService {
  44. @Autowired
  45. private CashCollectionMapper cashCollectionMapper;
  46. @Autowired
  47. private UserMapper userMapper;
  48. @Autowired
  49. private MarketMapper marketMapper;
  50. @Autowired
  51. private RabbitTemplate rabbitTemplate;
  52. //新增收款订单
  53. @Override
  54. public String add(CashCollection cashCollection) {
  55. if (cashCollection.getJwcode() == null) {
  56. throw new IllegalArgumentException("精网号不能为空");
  57. }
  58. if (cashCollection.getJwcode() < 10000000 || cashCollection.getJwcode() > 99999999) {
  59. throw new IllegalArgumentException("精网号必须为8位");
  60. }
  61. if (cashCollection.getName() == null || cashCollection.getName().isEmpty()){
  62. throw new IllegalArgumentException("客户姓名不能为空");
  63. }
  64. if (cashCollection.getActivity() == null || cashCollection.getActivity().isEmpty()) {
  65. throw new IllegalArgumentException("活动不能为空");
  66. }
  67. if (cashCollection.getGoodsName() == null|| cashCollection.getGoodsName().isEmpty()) {
  68. throw new IllegalArgumentException("产品名称不能为空");
  69. }
  70. if (cashCollection.getGoodsName().equals("金币充值")) {
  71. if (cashCollection.getPermanentGold() == 0 && cashCollection.getFreeGold() == 0) {
  72. throw new IllegalArgumentException("金币数量不能为空");
  73. }
  74. }
  75. if (!cashCollection.getGoodsName().equals("金币充值")) {
  76. if (cashCollection.getGoodNum() == 0) {
  77. throw new IllegalArgumentException("产品数量不能为空");
  78. }
  79. if (cashCollection.getNumUnit() == null|| cashCollection.getNumUnit().isEmpty()) {
  80. throw new IllegalArgumentException("数量单位不能为空");
  81. }
  82. }
  83. if (cashCollection.getPaymentCurrencyOrig() == null || cashCollection.getPaymentCurrencyOrig().isEmpty()) {
  84. throw new IllegalArgumentException("支付币种不能为空");
  85. }
  86. if (cashCollection.getPaymentAmountOrig() == null || cashCollection.getPaymentAmountOrig().compareTo(BigDecimal.ZERO) == 0) {
  87. throw new IllegalArgumentException("支付金额不能为空");
  88. }
  89. if (cashCollection.getPayType() == null|| cashCollection.getPayType().isEmpty()) {
  90. throw new IllegalArgumentException("支付方式不能为空");
  91. }
  92. if (cashCollection.getReceivedMarket() == null||cashCollection.getReceivedMarket().isEmpty()) {
  93. throw new IllegalArgumentException("到账地区不能为空");
  94. }
  95. if (cashCollection.getPayTime() == null) {
  96. throw new IllegalArgumentException("付款时间不能为空");
  97. }
  98. //生成订单号后半部分
  99. String orderNumber = UUID.randomUUID().toString().replaceAll("-", "");
  100. CashRecord cashRecord = new CashRecord();
  101. //构建订单信息
  102. cashRecord.setOrderCode("XJ_" + orderNumber); //订单号
  103. cashRecord.setJwcode(cashCollection.getJwcode()); //精网号
  104. cashRecord.setName(cashCollection.getName()); //客户姓名
  105. cashRecord.setActivity(cashCollection.getActivity()); // 活动
  106. cashRecord.setGoodsName(cashCollection.getGoodsName()); //商品名称
  107. cashRecord.setGoodNum(cashCollection.getGoodNum()); //商品数量
  108. cashRecord.setNumUnit(cashCollection.getNumUnit()); //数量单位
  109. cashRecord.setPermanentGold(cashCollection.getPermanentGold()); //永久金币
  110. cashRecord.setFreeGold(cashCollection.getFreeGold()); //免费金币
  111. cashRecord.setPaymentCurrencyOrig(cashCollection.getPaymentCurrencyOrig()); //付款币种
  112. cashRecord.setPaymentAmountOrig(cashCollection.getPaymentAmountOrig()); //付款金额
  113. cashRecord.setReceivedMarket(cashCollection.getReceivedMarket()); //到账地区
  114. cashRecord.setPayType(cashCollection.getPayType()); //支付方式
  115. cashRecord.setPayTime(cashCollection.getPayTime()); //付款时间
  116. cashRecord.setVoucher(cashCollection.getVoucher()); //转账凭证
  117. cashRecord.setRemark(cashCollection.getRemark()); //备注
  118. cashRecord.setStatus(0); //订单状态:付款线下财务待审核
  119. cashRecord.setSubmitterId(cashCollection.getSubmitterId()); //提交人ID
  120. cashRecord.setSubmitterMarket(cashCollection.getSubmitterMarket());
  121. cashRecord.setOrderType(1); //订单类型:1-收款
  122. cashRecord.setMarket(cashCollection.getMarket());
  123. //地区,根据jwcode插入
  124. //cashRecord.setMarket(cashCollectionMapper.getMarketByJwcode(cashRecord.getJwcode()));
  125. //插入新收款订单
  126. cashCollectionMapper.add(cashRecord);
  127. // 发送收款创建消息
  128. Messages message = new Messages();
  129. message.setJwcode(cashRecord.getJwcode());
  130. message.setName(cashRecord.getName());
  131. message.setStatus(cashRecord.getStatus());
  132. message.setDesc(cashRecord.getJwcode()+"用户的现金收款申请待审核,请前往审核");
  133. message.setTitle("现金收款--新增收款");
  134. message.setType(1);
  135. message.setTypeId(cashRecord.getId());
  136. message.setMarket(Integer.valueOf(cashRecord.getMarket()));
  137. rabbitTemplate.convertAndSend(RabbitMQConfig.CASH_COLLECTION_EXCHANGE, "cash.collection.save", message);
  138. return "添加成功";
  139. }
  140. @Override
  141. public String addFreeCoin(CashCollection cashCollection) {
  142. if (cashCollection.getJwcode() == null) {
  143. throw new IllegalArgumentException("精网号不能为空");
  144. }
  145. if (cashCollection.getJwcode() < 10000000 || cashCollection.getJwcode() > 99999999) {
  146. throw new IllegalArgumentException("精网号必须为8位");
  147. }
  148. if (cashCollection.getName() == null || cashCollection.getName().isEmpty()){
  149. throw new IllegalArgumentException("客户姓名不能为空");
  150. }
  151. if (cashCollection.getActivity() == null || cashCollection.getActivity().isEmpty()) {
  152. throw new IllegalArgumentException("活动不能为空");
  153. }
  154. if (cashCollection.getFreeGold() == 0) {
  155. throw new IllegalArgumentException("免费金币数量不能为空");
  156. }
  157. //生成订单号后半部分
  158. String orderNumber = UUID.randomUUID().toString().replaceAll("-", "");
  159. CashRecord cashRecord = new CashRecord();
  160. //构建订单信息
  161. cashRecord.setOrderCode("XJ_" + orderNumber); //订单号
  162. cashRecord.setJwcode(cashCollection.getJwcode()); //精网号
  163. cashRecord.setName(cashCollection.getName()); //客户姓名
  164. cashRecord.setActivity(cashCollection.getActivity()); // 活动
  165. cashRecord.setGoodsName("免费金币赠送"); //商品名称
  166. cashRecord.setFreeGold(cashCollection.getFreeGold()); //免费金币
  167. cashRecord.setRemark(cashCollection.getRemark()); //备注
  168. cashRecord.setStatus(0); //订单状态:付款线下财务待审核
  169. cashRecord.setSubmitterId(cashCollection.getSubmitterId()); //提交人ID
  170. cashRecord.setSubmitterMarket(cashCollection.getSubmitterMarket());
  171. cashRecord.setOrderType(1); //订单类型:1-收款
  172. cashRecord.setMarket(cashCollection.getMarket());
  173. //地区,根据jwcode插入
  174. //cashRecord.setMarket(cashCollectionMapper.getMarketByJwcode(cashRecord.getJwcode()));
  175. //插入新收款订单
  176. cashCollectionMapper.add(cashRecord);
  177. // 发送收款创建消息
  178. Messages message = new Messages();
  179. message.setJwcode(cashRecord.getJwcode());
  180. message.setName(cashRecord.getName());
  181. message.setStatus(cashRecord.getStatus());
  182. message.setDesc(cashRecord.getJwcode()+"用户的现金收款申请待审核,请前往审核");
  183. message.setTitle("现金收款--赠送免费金币");
  184. message.setType(1);
  185. message.setTypeId(cashRecord.getId());
  186. message.setMarket(Integer.valueOf(cashRecord.getMarket()));
  187. rabbitTemplate.convertAndSend(RabbitMQConfig.CASH_COLLECTION_EXCHANGE, "cash.collection.save", message);
  188. return "添加成功";
  189. }
  190. //撤回未审核的订单
  191. @Override
  192. public String cancel(String orderCode) {
  193. CashRecord cashRecord = cashCollectionMapper.selectByOrderCode(orderCode);
  194. if (cashRecord == null) {
  195. throw new IllegalArgumentException("订单不存在");
  196. }
  197. if (cashRecord.getStatus() != 0) {
  198. throw new IllegalArgumentException("订单状态不符合条件");
  199. }
  200. //修改订单状态
  201. int rows = cashCollectionMapper.updateStatus(orderCode, 5);
  202. return rows > 0 ? "撤回成功" : "撤回失败";
  203. }
  204. //编辑并重新提交收款订单
  205. @Override
  206. public String reSubmit(CashRecord cashRecord) {
  207. if (cashRecord.getJwcode() == null) {
  208. throw new IllegalArgumentException("精网号不能为空");
  209. }
  210. if (cashRecord.getJwcode() < 10000000 || cashRecord.getJwcode() > 99999999) {
  211. throw new IllegalArgumentException("精网号必须为8位");
  212. }
  213. if (cashRecord.getName() == null) {
  214. throw new IllegalArgumentException("客户姓名不能为空");
  215. }
  216. if (cashRecord.getActivity() == null) {
  217. throw new IllegalArgumentException("活动不能为空");
  218. }
  219. if (cashRecord.getGoodsName() == null) {
  220. throw new IllegalArgumentException("商品名不能为空");
  221. }
  222. if (cashRecord.getGoodsName().equals("金币充值")) {
  223. if (cashRecord.getPermanentGold() == 0 && cashRecord.getFreeGold() == 0) {
  224. throw new IllegalArgumentException("金币数量不能为空");
  225. }
  226. }
  227. if (!cashRecord.getGoodsName().equals("金币充值")) {
  228. if (cashRecord.getGoodNum() == 0) {
  229. throw new IllegalArgumentException("产品数量不能为空");
  230. }
  231. if (cashRecord.getNumUnit() == null) {
  232. throw new IllegalArgumentException("数量单位不能为空");
  233. }
  234. }
  235. if (cashRecord.getPaymentCurrency() == null) {
  236. throw new IllegalArgumentException("支付币种不能为空");
  237. }
  238. if (cashRecord.getPaymentAmount() == null || cashRecord.getPaymentAmount().compareTo(BigDecimal.ZERO) == 0) {
  239. throw new IllegalArgumentException("支付金额不能为空");
  240. }
  241. if (cashRecord.getPayType() == null) {
  242. throw new IllegalArgumentException("支付方式不能为空");
  243. }
  244. if (cashRecord.getReceivedMarket() == null) {
  245. throw new IllegalArgumentException("到账地区不能为空");
  246. }
  247. if (cashRecord.getPayTime() == null) {
  248. throw new IllegalArgumentException("付款时间不能为空");
  249. }
  250. CashRecord status = cashCollectionMapper.selectByOrderCode(cashRecord.getOrderCode());
  251. if (!status.getStatus().equals(5)) {
  252. throw new IllegalArgumentException("只允许编辑已撤回订单");
  253. }
  254. //地区,根据jwcode插入(弃用,插入前调用接口获取地区和姓名,之后前端传入)
  255. //cashRecord.setMarket(cashCollectionMapper.getMarketByJwcode(cashRecord.getJwcode()));
  256. int rows = cashCollectionMapper.updateByOrderCode(cashRecord);
  257. if (rows > 0) {
  258. // 发送重新提交消息
  259. CashCollectionMessage message = new CashCollectionMessage();
  260. message.setId(cashRecord.getId());
  261. message.setOrderCode(cashRecord.getOrderCode());
  262. message.setStatus(0); // 重新提交后状态变为待审核
  263. message.setStatusDescription("线下财务待审核");
  264. message.setMessage("收款订单已重新提交");
  265. message.setSubmitterId(cashRecord.getSubmitterId());
  266. message.setTimestamp(LocalDateTime.now());
  267. rabbitTemplate.convertAndSend(
  268. RabbitMQConfig.CASH_COLLECTION_EXCHANGE,
  269. "collection.created",
  270. message
  271. );
  272. }
  273. return rows > 0 ? "重新提交成功" : "重新提交失败";
  274. }
  275. //多条件查询收款订单列表
  276. @Override
  277. public PageInfo<CashCollection> selectCollection(Integer pageNum, Integer pageSize, CashCollection cashCollection) {
  278. /* //将操作人的地区列表改为id
  279. List<String> markets = marketMapper.getMarketIds(cashCollection.getMarkets());
  280. if (markets.contains("9") || markets.contains("9999")) {
  281. markets = null;
  282. }*/
  283. // cashCollection.setReceivedMarket(marketMapper.getMarketId(cashCollection.getReceivedMarket()));
  284. if (cashCollection.getCashRoleId() == 2) {
  285. //角色是总部时,若不特地传状态,传1346,sql处理为(1,3,4,6)筛选,
  286. if (cashCollection.getStatus() == null) {
  287. cashCollection.setStatus(1346);
  288. }
  289. cashCollection.setSubmitterId(null);
  290. cashCollection.setReceivedMarket(null);
  291. cashCollection.setSubmitterMarket(null);
  292. }
  293. if (cashCollection.getCashRoleId() == 1) {
  294. //角色是地方财务,提交人置空不设筛选条件,仅按收款地区、提交人地区筛选()
  295. if (cashCollection.getStatus() == null) {
  296. cashCollection.setStatus(123460);
  297. }
  298. //状态为待审核和已驳回时按照提交人地区筛选
  299. if (cashCollection.getStatus() == 0 || cashCollection.getStatus() == 2) {
  300. cashCollection.setReceivedMarket(null);
  301. }
  302. //状态为已通过和Link通过时,满足收款地区或提交人地区即可
  303. /* if (cashCollection.getStatus() == 13) {
  304. cashCollection.setSubmitterId(null);
  305. }*/
  306. //状态为13 或46,已通过或已完成和已退款,满足收款地区或提交人地区即可,
  307. cashCollection.setSubmitterId(null);
  308. }
  309. if (cashCollection.getCashRoleId() == 0) {
  310. //角色是地方财务,提交人置空不设筛选条件---仅当角色是0 地方客服时,按提交人筛选
  311. if (cashCollection.getStatus() == null) {
  312. cashCollection.setStatus(1234560);
  313. }
  314. cashCollection.setSubmitterId(cashCollection.getSubmitterId());
  315. cashCollection.setReceivedMarket(null);
  316. }
  317. // cashCollection.setMarkets(markets);
  318. PageHelper.startPage(pageNum, pageSize); //必须要直接跟mapper
  319. List<CashCollection> cashCollections = cashCollectionMapper.selectCollection1(pageNum, pageSize, cashCollection);
  320. return new PageInfo<>(cashCollections);
  321. }
  322. //补全手续费等内容
  323. @Override
  324. public String complete(CashRecord cashRecord) {
  325. if (!Objects.equals(cashRecord.getPaymentCurrency(), cashRecord.getReceivedCurrency())){
  326. throw new IllegalArgumentException("支付币种(转换后)和到账币种不一致");
  327. }
  328. int rows = cashCollectionMapper.complete(cashRecord);
  329. return rows > 0 ? "编辑成功" : "编辑失败";
  330. }
  331. //根据精网号查询姓名和地区
  332. @Override
  333. public User getNameAndMarket(Integer jwcode) {
  334. try {
  335. HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
  336. String token = request.getHeader("token");
  337. Admin admin = (Admin) JWTUtil.getUserDetailsList(String.valueOf(token), Admin.class);
  338. if (admin != null) {
  339. List<String> list = Arrays.asList(admin.getMarkets().split(","));
  340. List<String> markets = marketMapper.getMarketIds(list);
  341. if (markets.contains("9") || markets.contains("9999")) {
  342. markets = null;
  343. }
  344. GoldUser gUser = userMapper.selectUserCard(jwcode.toString(), markets);
  345. if (gUser != null) {
  346. User user = new User();
  347. user.setMarket(cashCollectionMapper.getMarketByJwcode(jwcode));
  348. user.setName(cashCollectionMapper.getNameByJwcode(jwcode));
  349. user.setMarketName(cashCollectionMapper.getMarketNameByJwcode(jwcode));
  350. return user;
  351. }
  352. }
  353. } catch (Exception e) {
  354. e.printStackTrace();
  355. }
  356. // 如果没有返回有效用户信息,则抛出异常
  357. throw new RuntimeException("无法获取用户信息");
  358. }
  359. //获取收款活动列表
  360. @Override
  361. public List<RechargeActivity> getActivityList() {
  362. LocalDateTime now = LocalDateTime.now();
  363. return cashCollectionMapper.getActivityList(now);
  364. }
  365. //同步g_order订单到cash_record表
  366. @Override
  367. public Object syncToCashRecord() {
  368. int total = 0;
  369. while (true) {
  370. List<GOrder> gOrders = cashCollectionMapper.getUnSync(50);
  371. if (CollectionUtils.isEmpty(gOrders)) {
  372. break;
  373. }
  374. try {
  375. // 每批独立事务
  376. processBatch(gOrders);
  377. total += gOrders.size();
  378. log.info("✅ 同步完成一批,数量: {}, 累计: {}", gOrders.size(), total);
  379. } catch (Exception e) {
  380. List<Integer> failedIds = gOrders.stream().map(GOrder::getId).collect(Collectors.toList());
  381. log.error("失败订单ID: {}", failedIds);
  382. // 可存入 error_log 表,供人工处理
  383. // 这里选择继续下一批(容忍部分失败)
  384. }
  385. if (gOrders.size() < 50) {
  386. break; // 最后一批
  387. }
  388. }
  389. return "同步完毕,成功处理 " + total + " 条";
  390. }
  391. @Override
  392. @Transactional(rollbackFor = Exception.class)
  393. public void processBatch(List<GOrder> gOrders) {
  394. for (GOrder gOrder : gOrders) {
  395. CashRecord cashRecord = new CashRecord();
  396. //构建基础信息
  397. cashRecord.setOrderType(1);
  398. cashRecord.setJwcode(gOrder.getJwcode());
  399. String name=cashCollectionMapper.getNameByJwcode(gOrder.getJwcode());
  400. if (name!=null){
  401. cashRecord.setName(name);
  402. }else cashRecord.setName("未知");
  403. cashRecord.setMarket(cashCollectionMapper.getMarketByJwcode(gOrder.getJwcode()));
  404. if (gOrder.getType().equals("gold")){ //充金豆
  405. cashRecord.setActivity("99");
  406. cashRecord.setGoodsName("Link充值金豆");
  407. cashRecord.setRemark("Link充值金豆");
  408. cashRecord.setNumUnit("个");
  409. cashRecord.setPermanentGold(0);
  410. cashRecord.setGoodNum(gOrder.getCount());
  411. }
  412. if (gOrder.getType().equals("gold_coin")){//充金币
  413. cashRecord.setActivity("98");
  414. cashRecord.setGoodsName("Link充值金币");
  415. cashRecord.setRemark("Link充值金币");
  416. cashRecord.setPermanentGold(gOrder.getCount()*100);
  417. cashRecord.setGoodNum(0);
  418. }
  419. cashRecord.setOrderCode(gOrder.getOrderNo());
  420. if (gOrder != null) {
  421. switch (gOrder.getPayStyle()) {
  422. case 3:
  423. cashRecord.setPayType("IOS内购");
  424. cashRecord.setBankCode(gOrder.getIosTransactionId());
  425. cashRecord.setReceivedMarket("4");
  426. cashRecord.setPayload("IOS");
  427. break;
  428. case 5:
  429. cashRecord.setPayType("Stripe");
  430. cashRecord.setReceivedMarket("13");
  431. cashRecord.setPayload("Stripe");
  432. break;
  433. case 6:
  434. cashRecord.setPayType("PaymentAsia");
  435. cashRecord.setReceivedMarket("13");
  436. cashRecord.setPayload("PaymentAsia");
  437. break;
  438. case 7:
  439. cashRecord.setPayType("Ipay88");
  440. cashRecord.setReceivedMarket("5");
  441. cashRecord.setPayload("Ipay88");
  442. break;
  443. case 9:
  444. cashRecord.setPayType("FirstData");
  445. cashRecord.setReceivedMarket("4");
  446. cashRecord.setBankCode(gOrder.getFirstdataIpgTransactionId());
  447. cashRecord.setPayload("FirstData");
  448. break;
  449. default:
  450. break;
  451. }
  452. }
  453. cashRecord.setFreeGold(0);
  454. cashRecord.setPaymentCurrency("");
  455. cashRecord.setPaymentAmount(BigDecimal.valueOf(0));
  456. //转换时间戳,加上时区偏移
  457. cashRecord.setPayTime(LocalDateTime.ofEpochSecond(gOrder.getSuccessTime(), 0, ZoneOffset.of("+08:00")));
  458. cashRecord.setAuditTime(LocalDateTime.ofEpochSecond(gOrder.getSuccessTime(), 0, ZoneOffset.of("+08:00")));
  459. cashRecord.setStatus(3);
  460. cashRecord.setSubmitterId(99999);
  461. //存入现金库
  462. cashCollectionMapper.add(cashRecord);
  463. cashCollectionMapper.markSynced(gOrder.getId());
  464. }
  465. }
  466. @Override
  467. public CashCollection selectById(CashCollection cashCollection) {
  468. return cashCollectionMapper.selectById(cashCollection.getId());
  469. }
  470. //根据goldcoin订单号查询收款订单
  471. @Override
  472. public CashCollection selectByGoldCoinOrderCode(String orderNo) {
  473. return cashCollectionMapper.selectByGoldCoinOrderCode(orderNo);
  474. }
  475. }