Commit df7adda4 by HlQ

[add] 添加同步销帮帮合同文件定时任务和接口

1 parent 6976245f
......@@ -8,7 +8,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.3</version>
<version>3.3.0</version>
</parent>
<artifactId>Vion-DevOps</artifactId>
......@@ -17,7 +17,7 @@
<pg.version>42.7.0</pg.version>
<sqlserver.version>12.2.0.jre8</sqlserver.version>
<lombok.version>1.18.30</lombok.version>
<hutool.version>6.0.0-M11</hutool.version>
<hutool.version>6.0.0-M13</hutool.version>
<redisson.verion>3.27.1</redisson.verion>
<mapstruct-plus.version>1.3.5</mapstruct-plus.version>
<mp.version>3.5.5</mp.version>
......
......@@ -13,7 +13,7 @@ import org.aspectj.lang.annotation.Pointcut;
import org.dromara.hutool.core.lang.Opt;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.http.server.servlet.JakartaServletUtil;
import org.dromara.hutool.http.server.servlet.ServletUtil;
import org.slf4j.MDC;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
......@@ -56,10 +56,10 @@ public class LogAspect {
log.info("Request URL:{}, Method:{}, IP:{}, Operator:{}, Args:{}, Body:{}",
request.getRequestURI(),
request.getMethod(),
JakartaServletUtil.getClientIP(request),
ServletUtil.getClientIP(request),
username,
objectMapper.writeValueAsString(request.getParameterMap()),
StrUtil.replaceChars(JakartaServletUtil.getBody(request), " \r\n", "")
StrUtil.replaceChars(ServletUtil.getBody(request), " \r\n", "")
);
}
......
......@@ -2,10 +2,10 @@ package vion.advice;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.hutool.core.util.ObjUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.dromara.hutool.core.util.ObjUtil;
import org.springframework.core.MethodParameter;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
......
......@@ -73,7 +73,7 @@ public class ContractController {
@PostMapping("/contract/{id}")
@SaCheckPermission(value = "contract:edit", orRole = "admin")
public String updateById(@PathVariable Long id, ContractDTO dto) {
public String updateById(@PathVariable Long id, @RequestBody ContractDTO dto) {
return contractService.updateById(id, null, dto);
}
......@@ -198,4 +198,10 @@ public class ContractController {
throw new RuntimeException(e);
}
}
@GetMapping("/contract/fileSync")
@SaCheckPermission(value = "contract:fileSync", orRole = "admin")
public String fileSync(String[] contractNoList) {
return contractService.syncContractFile(contractNoList);
}
}
......@@ -54,7 +54,7 @@ public class ContractRunner {
@Value("${xbongbong.token}")
private String token;
@Value("${xbongbong.corpid}")
private String corpid;
private String corpId;
// @Scheduled(cron = "0 0 * * * *")
@Transactional(rollbackFor = Exception.class)
......@@ -302,7 +302,7 @@ public class ContractRunner {
public void contractSync1() {
Long modifyTime = Opt.ofNullable((Long) redissonClient.getBucket(RedisKeyEnum.CONTRACT_SYNC_NEW_TIME.getVal()).get()).orElse(0L);
// 只同步2024-05-07号(含)之后的合同
// 只同步申请日期(原CRM中的签订日期)2024-05-07号(含)之后的合同
var json = JSONUtil.ofObj()
.set("sortMap", JSONUtil.ofObj()
.set("field", "updateTime")
......@@ -317,7 +317,7 @@ public class ContractRunner {
.set("symbol", "greatethan")
.set("value", new String[]{String.valueOf(modifyTime / 1000)}))
)
.set("corpid", corpid)
.set("corpid", corpId)
.set("formId", 8429903)
.set("pageSize", 100);
var res = Request.of("https://proapi.xbongbong.com/pro/v2/api/contract/list")
......@@ -347,18 +347,22 @@ public class ContractRunner {
.set("order", "desc"))
.set("conditions", JSONUtil.ofArray()
.put(JSONUtil.ofObj()
.set("attr", "date_3")
.set("symbol", "greaterequal")
.set("value", new String[]{"1715356800"}))
.put(JSONUtil.ofObj()
.set("attr", "updateTime")
.set("fieldType", "10015")
.set("symbol", "greatethan")
.set("value", new String[]{String.valueOf(modifyTime)}))
)
.set("corpid", corpid)
.set("corpid", corpId)
.set("formId", 8429903)
.set("page", i)
.set("pageSize", 100);
var resR = Request.of("https://proapi.xbongbong.com/pro/v2/api/contract/list")
.header("sign", SecureUtil.sha256(jsonR.toString() + token))
.body(json.toString())
.body(jsonR.toString())
.method(Method.POST)
.send();
var jobR = JSONUtil.parseObj(resR.bodyStr());
......@@ -378,7 +382,7 @@ public class ContractRunner {
}
dataIdSet.forEach(dataId -> {
var json1 = JSONUtil.ofObj()
.set("corpid", corpid)
.set("corpid", corpId)
.set("dataId", dataId);
var res1 = Request.of("https://proapi.xbongbong.com/pro/v2/api/contract/detail")
.header("sign", SecureUtil.sha256(json1.toString() + token))
......@@ -633,7 +637,7 @@ public class ContractRunner {
public List<JSONObject> getProductList() {
List<JSONObject> resList = new ArrayList<>();
var json = JSONUtil.ofObj()
.set("corpid", corpid)
.set("corpid", corpId)
.set("page", 1)
.set("pageSize", 100);
......@@ -654,7 +658,7 @@ public class ContractRunner {
for (int i = 2; i <= totalPage; i++) {
var json1 = JSONUtil.ofObj()
.set("corpid", corpid)
.set("corpid", corpId)
.set("page", i)
.set("pageSize", 100);
var res1 = Request.of("https://proapi.xbongbong.com/pro/v2/api/product/list")
......@@ -680,4 +684,9 @@ public class ContractRunner {
storeService.calMaintainStatus(ListUtil.empty());
log.info("【结束】计算门店维保状态");
}
@Scheduled(cron = "0 10 * ? * *")
public void syncContractFile() {
contractService.syncContractFile(null);
}
}
package vion.cron;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.util.ObjUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.hutool.core.date.DateUtil;
import org.dromara.hutool.core.lang.Opt;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.cron.CronUtil;
import org.dromara.hutool.cron.task.Task;
import org.dromara.hutool.json.JSONObject;
......
......@@ -67,6 +67,8 @@ public class Contract {
/**
* 合同总金额
* <p>
* 更新合同时,合同相关金额计算是由合同收款记录计算的,不能通过更新接口自己修改
*/
@TableField(value = "total_amount")
@ReverseAutoMapping(targetClass = ContractDTO.class, ignore = true)
......
......@@ -49,4 +49,5 @@ public interface IContractService extends MPJBaseService<Contract> {
JSONObject getCRMProduct(String name, String code, Integer page, Integer pageSize);
String syncContractFile(String[] contractNoList);
}
\ No newline at end of file
package vion.service.impl;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.PageUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
......@@ -17,6 +15,7 @@ import org.dromara.hutool.core.bean.BeanUtil;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.collection.ListUtil;
import org.dromara.hutool.core.collection.set.SetUtil;
import org.dromara.hutool.core.comparator.CompareUtil;
import org.dromara.hutool.core.date.DateUnit;
import org.dromara.hutool.core.date.DateUtil;
import org.dromara.hutool.core.io.file.FileNameUtil;
......@@ -24,9 +23,11 @@ import org.dromara.hutool.core.io.file.FileUtil;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.lang.Opt;
import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.math.NumberUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.crypto.SecureUtil;
import org.dromara.hutool.http.client.HttpDownloader;
import org.dromara.hutool.http.client.Request;
import org.dromara.hutool.http.meta.Method;
import org.dromara.hutool.json.JSONObject;
......@@ -73,6 +74,8 @@ public class ContractServiceImpl extends MPJBaseServiceImpl<ContractMapper, Cont
@Value("${fileUrl:}")
private String fileUrl;
@Value("${xbongbong.corpid}")
private String corpId;
@Value("${xbongbong.token}")
private String token;
......@@ -322,8 +325,10 @@ public class ContractServiceImpl extends MPJBaseServiceImpl<ContractMapper, Cont
Opt.ofEmptyAble(contracts)
.ifPresent(list -> {
BigDecimal totalAmount = list.stream().map(Contract::getTotalAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal paidAmount = list.stream().map(v -> NumberUtil.max(BigDecimal.ZERO, v.getPaidAmount())).reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal recAmount = list.stream().map(v -> NumberUtil.max(BigDecimal.ZERO, v.getReceivableAmount())).reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal paidAmount =
list.stream().map(v -> CompareUtil.max(BigDecimal.ZERO, v.getPaidAmount())).reduce(BigDecimal.ZERO,
BigDecimal::add);
BigDecimal recAmount = list.stream().map(v -> CompareUtil.max(BigDecimal.ZERO, v.getReceivableAmount())).reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal outAmount = list.stream().map(Contract::getOutstandingAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
List<String> noList = list.stream().map(Contract::getContractNo).collect(Collectors.toList());
......@@ -350,7 +355,6 @@ public class ContractServiceImpl extends MPJBaseServiceImpl<ContractMapper, Cont
return new JSONObject();
}
// todo 优化查询,当下是查询所有
Map<Long, List<ContractPayment>> id2PaymentMap = Opt.ofEmptyAble(contractPaymentService
.lambdaQuery().gt(ContractPayment::getPaymentRatio, 0)
.list())
......@@ -376,13 +380,13 @@ public class ContractServiceImpl extends MPJBaseServiceImpl<ContractMapper, Cont
for (Map.Entry<Integer, BigDecimal> entry : sortMap.entrySet()) {
Integer type = entry.getKey();
BigDecimal curAmount = entry.getValue();
if (NumberUtil.isGreater(paidAmount, BigDecimal.ZERO)) {
if (CompareUtil.gt(paidAmount, BigDecimal.ZERO)) {
paidAmount = NumberUtil.sub(paidAmount, curAmount);
if (NumberUtil.equals(paidAmount, BigDecimal.ZERO)) {
continue;
}
}
if (NumberUtil.isLessOrEqual(paidAmount, BigDecimal.ZERO)) {
if (CompareUtil.le(paidAmount, BigDecimal.ZERO)) {
FinancialAgeVO financialAgeVO = new FinancialAgeVO();
financialAgeVO.setContractNo(c.getContractNo());
financialAgeVO.setContractName(c.getName());
......@@ -402,8 +406,9 @@ public class ContractServiceImpl extends MPJBaseServiceImpl<ContractMapper, Cont
});
Map<String, Object> map = MapUtil.<String, Object>builder()
.put("totalAmount", financialAgeVOList.stream().map(FinancialAgeVO::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add)).build();
// 手动分页
int[] transToStartEnd = PageUtil.transToStartEnd(dto.getPageNum() - 1, dto.getPageSize());
// 手动分页 todo hutool 6.0 暂时没有
int[] transToStartEnd = {(dto.getPageNum() - 1 ) * dto.getPageSize(),
(dto.getPageNum() - 1 ) * dto.getPageSize() + dto.getPageSize()};
Page<FinancialAgeVO> financialAgeVOPage = Page.<FinancialAgeVO>of(dto.getPageNum(), dto.getPageSize(), financialAgeVOList.size())
.setRecords(CollUtil.sub(financialAgeVOList, transToStartEnd[0], transToStartEnd[1]));
map.put("list", financialAgeVOPage);
......@@ -495,6 +500,123 @@ public class ContractServiceImpl extends MPJBaseServiceImpl<ContractMapper, Cont
.set("pages", jobj.getJSONObject("result").getInt("totalPage"));
}
@Override
public String syncContractFile(String[] contractNoList) {
log.info("同步销帮帮合同文件[开始]");
// 只同步申请日期(原CRM中的签订日期)2024-05-07号(含)之后的合同
var conditions = JSONUtil.ofArray()
.put(JSONUtil.ofObj()
.set("attr", "date_3")
.set("symbol", "greaterequal")
.set("value", new String[]{"1715356800"}));
if (ArrayUtil.isNotEmpty(contractNoList)) {
conditions.put(JSONUtil.ofObj()
.set("attr", "serialNo")
.set("symbol", "in")
.set("value", contractNoList));
}
var json = JSONUtil.ofObj()
.set("conditions", conditions)
.set("corpid", corpId)
.set("formId", 8429903)
.set("pageSize", 100);
var res = Request.of("https://proapi.xbongbong.com/pro/v2/api/contract/list")
.header("sign", SecureUtil.sha256(json.toString() + token))
.body(json.toString())
.method(Method.POST)
.send();
var jobO = JSONUtil.parseObj(res.bodyStr());
if (jobO.getInt("code") != 1) {
var errorInfo = StrUtil.format("获取合同列表失败,错误原因:{}", jobO);
log.error(errorInfo);
return errorInfo;
}
Integer cnt = jobO.getJSONObject("result").getInt("totalCount");
Integer page = jobO.getJSONObject("result").getInt("totalPage");
if (NumberUtil.equals(cnt, 0)) {
return "没有需要插入或更新的合同";
}
var jsonArray = jobO.getJSONObject("result").getJSONArray("list");
var fileList = jsonArray.stream().map(v -> {
var fileArr = JSONUtil.parseObj(v).getJSONObject("data").getJSONArray("file_1");
var contractNo = JSONUtil.parseObj(v).getJSONObject("data").getStr("serialNo");
return JSONUtil.ofObj().set("contractNo", contractNo).set("fileArr", fileArr);
}).collect(Collectors.toList());
for (int i = 2; i <= page; i++) {
var jsonR = JSONUtil.ofObj()
.set("conditions", conditions)
.set("corpid", corpId)
.set("formId", 8429903)
.set("page", i)
.set("pageSize", 100);
var resR = Request.of("https://proapi.xbongbong.com/pro/v2/api/contract/list")
.header("sign", SecureUtil.sha256(jsonR.toString() + token))
.body(jsonR.toString())
.method(Method.POST)
.send();
var jobR = JSONUtil.parseObj(resR.bodyStr());
var jsonArrR = jobR.getJSONObject("result").getJSONArray("list");
var fileListR = jsonArrR.stream().map(v -> {
var fileArr = JSONUtil.parseObj(v).getJSONObject("data").getJSONArray("file_1");
var contractNo = JSONUtil.parseObj(v).getJSONObject("data").getStr("serialNo");
return JSONUtil.ofObj().set("contractNo", contractNo).set("fileArr", fileArr);
}).collect(Collectors.toList());
fileList.addAll(fileListR);
}
var contractList = this.lambdaQuery().likeRight(Contract::getContractNo, "SC").list();
var contractNo2IdMap = contractList.stream().collect(Collectors.toMap(Contract::getContractNo, Contract::getId));
var fileInfoList = fileService.lambdaQuery().in(FileInfo::getContractId, contractNo2IdMap.values()).eq(FileInfo::getSourceType, 5).list();
// 合同id -> sha256 的 List
var contractId2Sha256Map = fileInfoList.stream().collect(Collectors.groupingBy(FileInfo::getContractId,
Collectors.mapping(FileInfo::getSha256, Collectors.toList())));
for (JSONObject entries : fileList) {
var contractNo = entries.getStr("contractNo");
var fileArr = entries.getJSONArray("fileArr");
if (ObjUtil.isNull(fileArr) || fileArr.isEmpty()) {
log.info("合同:{},没有文件", contractNo);
continue;
}
var contractId = contractNo2IdMap.get(contractNo);
if (ObjUtil.isNull(contractId)) {
log.info("合同:{},不存在,还未同步", contractNo);
continue;
}
List<FileInfo> saveFileInfoList = new ArrayList<>();
for (Object o : fileArr) {
var fileObj = JSONUtil.parseObj(o);
var filename = fileObj.getStr("filename");
String path = fileUrl + FileUtil.FILE_SEPARATOR + "contract" + FileUtil.FILE_SEPARATOR + contractId + FileUtil.FILE_SEPARATOR + filename;
var bytes = HttpDownloader.downloadBytes(fileObj.getStr("attachIndex"));
var sha256 = SecureUtil.sha256().digestHex(bytes).toUpperCase();
// sha256 对应的文件不存在已有的文件列表,才保存
if (contractId2Sha256Map.getOrDefault(contractId, ListUtil.empty()).contains(sha256)) {
log.info("合同:{},文件已存在", contractNo);
continue;
}
var file = FileUtil.writeBytes(bytes, path);
log.info("合同:{},文件存入路径:{}", contractNo, path);
FileInfo fileInfo = new FileInfo();
fileInfo.setStoreId(-1L);
fileInfo.setSourceId(contractId);
fileInfo.setSourceType(5);
fileInfo.setContractId(contractId);
fileInfo.setName(filename);
fileInfo.setUrl(path);
fileInfo.setType(FileNameUtil.extName(file));
fileInfo.setSha256(sha256);
fileInfo.setUploader("销帮帮同步");
saveFileInfoList.add(fileInfo);
}
fileService.saveBatch(saveFileInfoList);
}
log.info("同步销帮帮合同文件[完成]");
return "销帮帮合同文件同步完成,请核对已同步文件!";
}
private Result getResult(ContractDTO dto) {
// 查询已关联项目的合同id
List<Long> contractIdList = dto.getSwitchFlag() == 1 ?
......
package vion.service.impl;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.DesensitizedUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
......@@ -12,6 +11,7 @@ import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.collection.ListUtil;
import org.dromara.hutool.core.collection.set.SetUtil;
import org.dromara.hutool.core.data.MaskingUtil;
import org.dromara.hutool.core.data.id.IdUtil;
import org.dromara.hutool.core.date.DateUtil;
import org.dromara.hutool.core.io.file.FileNameUtil;
......@@ -325,7 +325,7 @@ public class TaskServiceImpl extends MPJBaseServiceImpl<TaskMapper, Task> implem
.build();
List<WxMpTemplateData> wxMpTemplateDataList = ListUtil.of(
new WxMpTemplateData("character_string21", existTask.getUuid()),
new WxMpTemplateData("thing12", DesensitizedUtil.chineseName(user.getUsername())),
new WxMpTemplateData("thing12", MaskingUtil.chineseName(user.getUsername())),
new WxMpTemplateData("time11", DateUtil.formatDateTime(new Date())),
new WxMpTemplateData("thing20", existTask.getFaultDescription().length() > 20 ? StrUtil.sub(existTask.getFaultDescription(), 0, 17) + "..." : existTask.getFaultDescription()),
new WxMpTemplateData("phrase25", statusMap.get(existTask.getStatus())));
......
package vion.service.impl;
import cn.hutool.core.util.ObjUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
......@@ -12,6 +11,7 @@ import org.dromara.hutool.core.lang.Opt;
import org.dromara.hutool.core.tree.MapTree;
import org.dromara.hutool.core.tree.TreeNode;
import org.dromara.hutool.core.tree.TreeUtil;
import org.dromara.hutool.core.util.ObjUtil;
import org.springframework.stereotype.Service;
import vion.dto.UserDTO;
import vion.mapper.UserMapper;
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!