Commit e7a0e032 by HlQ

[add]

1.添加集团管理相关接口
2.添加同步新CRM平台合同的接口以及创建合同的接口
3.添加文件下载的接口(通过流返回文件)
1 parent b9276b67
......@@ -15,6 +15,7 @@ import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.http.server.servlet.JakartaServletUtil;
import org.slf4j.MDC;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
......@@ -41,7 +42,7 @@ public class LogAspect {
// 登录等接口,无需登录可访问,根据 token 获取当前用户会抛未登录的异常,需捕获进行处理
var username = Opt.ofTry(() -> (UserVO) StpUtil.getTokenSession().get("curLoginUser"))
.map(UserVO::getUsername)
.orElse("未知");
.orElse("Unknown");
var attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (ObjUtil.isNull(attributes)) {
......@@ -73,6 +74,10 @@ public class LogAspect {
var startTime = (Long) request.getAttribute("startTime");
var responseTime = System.currentTimeMillis() - startTime;
if (result instanceof ResponseEntity) {
log.info("Response time: {} ms. File download completed.", responseTime);
return;
}
var resStr = objectMapper.writeValueAsString(result);
if (resStr.length() > 1000) {
resStr = resStr.substring(0, 1000);
......
......@@ -2,10 +2,12 @@ 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.springframework.core.MethodParameter;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
......@@ -34,7 +36,7 @@ public class ResBodyAdvice implements ResponseBodyAdvice<Object> {
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
if (body instanceof ResultVO || body instanceof ModelAndView) {
if (ObjUtil.isNull(body) || body instanceof ResultVO || body instanceof ModelAndView || body instanceof Resource) {
return body;
}
......
......@@ -53,7 +53,8 @@ public enum RedisKeyEnum {
/**
* 合同同步时间
*/
CONTRACT_SYNC_TIME("contract:sync:time");
CONTRACT_SYNC_TIME("contract:sync:time"),
CONTRACT_SYNC_NEW_TIME("contract:sync:new:time");
private final String val;
......
package vion.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import vion.dto.BaseDTO;
import vion.model.Account;
import vion.service.IAccountService;
/**
* 集团管理
*/
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
@Slf4j
public class AccountController {
private final IAccountService accountService;
@GetMapping("/accounts")
@GetMapping("/account")
@SaCheckPermission(value = "account:list", orRole = "admin")
public Page<Account> getAccountList(BaseDTO dto) {
return accountService.page(Page.of(dto.getPageNum(), dto.getPageSize()));
public Page<Account> getAccountList(Account dto) {
return accountService.page(Page.of(dto.getPageNum(), dto.getPageSize()),
Wrappers.lambdaQuery(dto).orderByDesc(Account::getModifyTime));
}
@GetMapping("/account")
@GetMapping("/onlyAccount")
@SaCheckPermission(value = "account:listAccount", orRole = "admin")
public Page<Account> getAccountNameList(Account dto) {
return accountService.lambdaQuery(dto)
.select(Account::getId, Account::getName)
.orderByDesc(Account::getModifyTime)
.page(Page.of(dto.getPageNum(),
dto.getPageSize()));
}
@GetMapping("/account/{id}")
@SaCheckPermission(value = "account:query", orRole = "admin")
public Account getAccountById(Integer id) {
public Account getAccountById(@PathVariable Long id) {
return accountService.getById(id);
}
@PostMapping("/accounts")
@PostMapping("/account")
@SaCheckPermission(value = "account:editAndSave", orRole = "admin")
public Account saveOrUpdate(@RequestBody Account data) {
accountService.save(data);
accountService.saveOrUpdate(data);
return data;
}
@DeleteMapping("/account/{id}")
@SaCheckPermission(value = "account:remove", orRole = "admin")
public String remove(@PathVariable(name = "id") Integer id) {
// todo 删除时,得判断集团下是否关联其他东西
accountService.removeById(id);
return "集团删除成功";
}
}
......@@ -11,6 +11,7 @@ import lombok.RequiredArgsConstructor;
import org.apache.poi.ss.usermodel.Workbook;
import org.dromara.hutool.core.date.DateUtil;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.text.CharSequenceUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.json.JSONObject;
......@@ -19,6 +20,7 @@ import vion.cron.ContractRunner;
import vion.dto.ContractDTO;
import vion.dto.RContractStoreDTO;
import vion.dto.RContractTeamDTO;
import vion.model.RContractProduct;
import vion.model.RContractStore;
import vion.model.RContractUser;
import vion.service.IContractService;
......@@ -74,6 +76,7 @@ public class ContractController {
public String updateById(@PathVariable Long id, ContractDTO dto) {
return contractService.updateById(id, null, dto);
}
@PostMapping("/contract/store")
@SaCheckPermission(value = "contract:store:save", orRole = "admin")
public String bindStore(@RequestBody RContractStoreDTO dto) {
......@@ -148,6 +151,35 @@ public class ContractController {
return "成功";
}
@PostMapping("/contractSync1")
@SaCheckPermission(value = "contract:sync1", orRole = "admin")
public String manualSyncContract1() {
contractRunner.contractSync1();
return "成功";
}
@PostMapping("/contract/createCRMContract")
@SaCheckPermission(value = "contract:createCRM", orRole = "admin")
public String createCRMContract(@RequestBody String contractJson) {
return contractService.createContract(CharSequenceUtil.removeAll(contractJson, '\r', '\n', ' '));
}
@GetMapping("/contract/getCRMProduct")
@SaCheckPermission(value = "contract:CRMProduct", orRole = "admin")
public JSONObject getCRMProduct(@RequestParam String name,
@RequestParam String code,
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "20") Integer pageSize) {
return contractService.getCRMProduct(name, code, page, pageSize);
}
@GetMapping("/contract/product")
@SaCheckPermission(value = "contract:product", orRole = "admin")
public List<RContractProduct> getProduct(@RequestParam String contractNo) {
return contractService.getProduct(contractNo);
}
@GetMapping("/contract/export")
@SaCheckPermission(value = "contract:export", orRole = "admin")
public void pointExport(ContractDTO dto, HttpServletResponse response) {
......
package vion.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.net.URLEncodeUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.github.linpeilie.Converter;
import lombok.RequiredArgsConstructor;
......@@ -12,6 +14,10 @@ import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.crypto.SecureUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import vion.dto.FileInfoDTO;
......@@ -20,6 +26,7 @@ import vion.service.IFileService;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Date;
@RestController
......@@ -35,6 +42,7 @@ public class FileController {
private String fileUrl;
@GetMapping("/files")
@SaCheckPermission(value = "file:list", orRole = "admin")
public Page<FileInfo> getFiles(FileInfoDTO data) {
return fileService.lambdaQuery(converter.convert(data, new FileInfo()))
.eq(ObjUtil.isNotNull(data.getStoreId()), FileInfo::getStoreId, data.getStoreId())
......@@ -46,7 +54,29 @@ public class FileController {
.page(Page.of(data.getPageNum(), data.getPageSize()));
}
@GetMapping("/file/download")
@SaCheckPermission(value = "file:download", orRole = "admin")
public ResponseEntity<FileSystemResource> download(Long id) {
var fileInfo = fileService.getById(id);
var file = FileUtil.file(fileInfo.getUrl());
if (!FileUtil.exists(file)) {
return ResponseEntity.notFound().build();
}
FileSystemResource resource = new FileSystemResource(file);
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE);
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + URLEncodeUtil.encode(file.getName(), StandardCharsets.UTF_8).replace("+", "%20"));
return ResponseEntity.ok()
.headers(headers)
.contentLength(file.length())
.body(resource);
}
@DeleteMapping("/file/{id}")
@SaCheckPermission(value = "file:remove", orRole = "admin")
public String remove(@PathVariable(name = "id") Integer id) {
FileInfo file = fileService.getById(id);
FileUtil.del(file.getUrl());
......@@ -55,6 +85,7 @@ public class FileController {
}
@PostMapping("/file/formFileUpload")
@SaCheckPermission(value = "file:form:upload", orRole = "admin")
public String uploadFile(FileInfo fileInfo, @RequestParam(name = "file") MultipartFile infile) throws IOException {
String orgName = infile.getOriginalFilename();
String mainName = FileNameUtil.mainName(orgName);
......@@ -92,6 +123,7 @@ public class FileController {
}
@PostMapping("/file/uploadFile")
@SaCheckPermission(value = "file:upload", orRole = "admin")
public String uploadFile1(FileInfo fileInfo, @RequestParam(name = "files") MultipartFile[] files) throws IOException {
for (MultipartFile infile : files) {
String orgName = infile.getOriginalFilename();
......
......@@ -156,7 +156,6 @@ public class StoreController {
@PostMapping("/store/tag/{id}")
@SaCheckPermission(value = "store:tag", orRole = "admin")
// 权限未加
public String addTag(@PathVariable Long id, @RequestBody List<Long> tagIdList) {
return storeService.addTag(id, tagIdList);
}
......
package vion.cron;
import cn.hutool.core.util.NumberUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.hutool.core.collection.CollUtil;
......@@ -8,16 +9,26 @@ 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.crypto.SecureUtil;
import org.dromara.hutool.http.client.Request;
import org.dromara.hutool.http.meta.Method;
import org.dromara.hutool.json.JSONObject;
import org.dromara.hutool.json.JSONUtil;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import vion.constant.RedisKeyEnum;
import vion.model.Dictionary;
import vion.model.*;
import vion.service.*;
import java.math.BigDecimal;
import java.sql.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
......@@ -37,9 +48,16 @@ public class ContractRunner {
private final IRContractStoreService contractStoreService;
private final IStoreService storeService;
private final IPaymentService paymentService;
private final IRContractProductService contractProductService;
private final RedissonClient redissonClient;
@Value("${xbongbong.token}")
private String token;
@Value("${xbongbong.corpid}")
private String corpid;
@Scheduled(cron = "0 0 * * * *")
@Transactional(rollbackFor = Exception.class)
public void contractSync() {
log.info("【开始】从crm系统同步合同信息");
Map<String, Contract> no2ContactMap = contractService.list().stream().collect(Collectors.toMap(Contract::getContractNo, Function.identity()));
......@@ -53,58 +71,86 @@ public class ContractRunner {
String username = "vion-reader";
String password = "vion-reader";
try (Connection connection = DriverManager.getConnection(url, username, password)) {
String sql = StrUtil.format(
"select t5.hetongpingshen_name as name,t1.hetongluru_name as contract_no,t1.hetongluru_char12 as type,t1.hetongluru_date01 as sign_date,t1.hetongluru_char01 as warranty_period,t1.hetongluru_start_date as maintain_sdate,t1.hetongluru_end_date as maintain_edate,t1.hetongluru_dec01 as total_amount,t5.hetongpingshen_dec02 as sign_ratio,t5.hetongpingshen_dec03 as arrive_ratio,t5.hetongpingshen_dec04 as system_check_ratio,t5.hetongpingshen_dec05 as project_check_ratio,t5.hetongpingshen_dec06 as warranty_ratio,t5.hetongpingshen_dec07 as maintain1_ratio,t5.hetongpingshen_dec09 as maintain2_ratio,t5.hetongpingshen_dec10 as maintain3_ratio,t2.cCusAbbName as customer_name,t4.cUser_Name as sale_name,t1.create_time as entry_time,t5.hetongpingshen_date01 as sign_date1,t5.hetongpingshen_date04 as arrive_date,t5.hetongpingshen_date05 as system_check_date,t5.hetongpingshen_date06 as project_check_date,t5.hetongpingshen_date07 as warranty_date,t5.hetongpingshen_date08 as maintain_date1, t6.hetongpingshen_date09 as maintain_date2,t6.hetongpingshen_date10 as maintain_date3,t1.modify_time as original_mod_time" +
" from tcu_hetongluru t1 left join Customer t2 on t1.account_id = t2.cCusCode left join tc_opportunity t3 on t1.hetongluru_char04 = t3.ufcode left join UA_User_Ex t4 on t1.owner_user_id = t4.cUser_Id left join tcu_hetongpingshen t5 on t1.hetongluru_name = t5.hetongpingshen_char05 left join tcu_hetongpingshen_attr t6 on t5.hetongpingshen_id = t6.hetongpingshen_id where t1.modify_time > '{}' order by t1.modify_time desc", modifyTime);
String contractTemplate = """
select t5.hetongpingshen_name as name,t1.hetongluru_name as contract_no,t1.hetongluru_char12 as type,t1.hetongluru_date01 as sign_date,t1.hetongluru_char01 as warranty_period,t1.hetongluru_start_date as maintain_sdate,t1.hetongluru_end_date as maintain_edate,t1.hetongluru_dec01 as total_amount,t5.hetongpingshen_dec02 as sign_ratio,t5.hetongpingshen_dec03 as arrive_ratio,t5.hetongpingshen_dec04 as system_check_ratio,t5.hetongpingshen_dec05 as project_check_ratio,t5.hetongpingshen_dec06 as warranty_ratio,t5.hetongpingshen_dec07 as maintain1_ratio,t5.hetongpingshen_dec09 as maintain2_ratio,t5.hetongpingshen_dec10 as maintain3_ratio,t2.cCusAbbName as customer_name,t4.cUser_Name as sale_name,t1.create_time as entry_time,t5.hetongpingshen_date01 as sign_date1,t5.hetongpingshen_date04 as arrive_date,t5.hetongpingshen_date05 as system_check_date,t5.hetongpingshen_date06 as project_check_date,t5.hetongpingshen_date07 as warranty_date,t5.hetongpingshen_date08 as maintain_date1, t6.hetongpingshen_date09 as maintain_date2,t6.hetongpingshen_date10 as maintain_date3,t1.modify_time as original_mod_time
from tcu_hetongluru t1 left join Customer t2 on t1.account_id = t2.cCusCode left join tc_opportunity t3 on t1.hetongluru_char04 = t3.ufcode left join UA_User_Ex t4 on t1.owner_user_id = t4.cUser_Id left join tcu_hetongpingshen t5 on t1.hetongluru_name = t5.hetongpingshen_char05 left join tcu_hetongpingshen_attr t6 on t5.hetongpingshen_id = t6.hetongpingshen_id where t1.modify_time > '{}' order by t1.modify_time desc
""";
String contractSql = StrUtil.format(contractTemplate, modifyTime);
try (Statement statement = connection.createStatement()) {
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
String contractNo = resultSet.getString("contract_no");
var rs = statement.executeQuery(contractSql);
while (rs.next()) {
String contractNo = rs.getString("contract_no");
Contract contract = new Contract();
Optional.ofNullable(resultSet.getString("name"))
Optional.ofNullable(rs.getString("name"))
.filter(StrUtil::isNotBlank)
.ifPresentOrElse(contract::setName, () -> contract.setName(contractNo));
contract.setContractNo(contractNo);
contract.setType(contractTypeMap.getOrDefault(resultSet.getString("type"), 0));
contract.setSignDate(resultSet.getDate("sign_date"));
String warrantyPeriod = resultSet.getString("warranty_period");
contract.setType(contractTypeMap.getOrDefault(rs.getString("type"), 0));
contract.setSignDate(rs.getDate("sign_date"));
String warrantyPeriod = rs.getString("warranty_period");
if (StrUtil.isNotBlank(warrantyPeriod) && warrantyPeriod.contains("个月")) {
String substring = warrantyPeriod.substring(0, (warrantyPeriod.length() - 2));
contract.setWarrantyPeriod(Integer.parseInt(substring));
}
contract.setMaintainSdate(resultSet.getDate("maintain_sdate"));
contract.setMaintainEdate(resultSet.getDate("maintain_edate"));
contract.setMaintainSdate(rs.getDate("maintain_sdate"));
contract.setMaintainEdate(rs.getDate("maintain_edate"));
contract.setStatus(1);
contract.setTotalAmount(resultSet.getBigDecimal("total_amount"));
contract.setSignRatio(resultSet.getBigDecimal("sign_ratio"));
contract.setSignDate1(resultSet.getDate("sign_date1"));
contract.setArriveRatio(resultSet.getBigDecimal("arrive_ratio"));
contract.setArriveDate(resultSet.getDate("arrive_date"));
contract.setSystemCheckRatio(resultSet.getBigDecimal("system_check_ratio"));
contract.setSystemCheckDate(resultSet.getDate("system_check_date"));
contract.setProjectCheckRatio(resultSet.getBigDecimal("project_check_ratio"));
contract.setProjectCheckDate(resultSet.getDate("project_check_date"));
contract.setWarrantyRatio(resultSet.getBigDecimal("warranty_ratio"));
contract.setWarrantyDate(resultSet.getDate("warranty_date"));
contract.setMaintainRatio1(resultSet.getBigDecimal("maintain1_ratio"));
contract.setMaintainDate1(resultSet.getDate("maintain_date1"));
contract.setMaintainRatio2(resultSet.getBigDecimal("maintain2_ratio"));
contract.setMaintainDate2(resultSet.getDate("maintain_date2"));
contract.setMaintainRatio3(resultSet.getBigDecimal("maintain3_ratio"));
contract.setMaintainDate3(resultSet.getDate("maintain_date3"));
contract.setTotalAmount(rs.getBigDecimal("total_amount"));
contract.setSignRatio(rs.getBigDecimal("sign_ratio"));
contract.setSignDate1(rs.getDate("sign_date1"));
contract.setArriveRatio(rs.getBigDecimal("arrive_ratio"));
contract.setArriveDate(rs.getDate("arrive_date"));
contract.setSystemCheckRatio(rs.getBigDecimal("system_check_ratio"));
contract.setSystemCheckDate(rs.getDate("system_check_date"));
contract.setProjectCheckRatio(rs.getBigDecimal("project_check_ratio"));
contract.setProjectCheckDate(rs.getDate("project_check_date"));
contract.setWarrantyRatio(rs.getBigDecimal("warranty_ratio"));
contract.setWarrantyDate(rs.getDate("warranty_date"));
contract.setMaintainRatio1(rs.getBigDecimal("maintain1_ratio"));
contract.setMaintainDate1(rs.getDate("maintain_date1"));
contract.setMaintainRatio2(rs.getBigDecimal("maintain2_ratio"));
contract.setMaintainDate2(rs.getDate("maintain_date2"));
contract.setMaintainRatio3(rs.getBigDecimal("maintain3_ratio"));
contract.setMaintainDate3(rs.getDate("maintain_date3"));
contract.setPaidAmount(BigDecimal.ZERO);
contract.setReceivableAmount(BigDecimal.ZERO);
contract.setOutstandingAmount(resultSet.getBigDecimal("total_amount"));
contract.setOutstandingAmount(rs.getBigDecimal("total_amount"));
contract.setSubject("北京文安智能技术股份有限公司");
contract.setCustomerName(resultSet.getString("customer_name"));
contract.setSaleName(resultSet.getString("sale_name"));
contract.setCustomerName(rs.getString("customer_name"));
contract.setSaleName(rs.getString("sale_name"));
contract.setCreateUser(-1L);
contract.setModifyUser(-1L);
contract.setEntryTime(resultSet.getTimestamp("entry_time"));
contract.setOriginalModTime(resultSet.getTimestamp("original_mod_time"));
contract.setEntryTime(rs.getTimestamp("entry_time"));
contract.setOriginalModTime(rs.getTimestamp("original_mod_time"));
insOrUpdContractList.add(contract);
}
if (CollUtil.isNotEmpty(insOrUpdContractList)) {
var noStr = insOrUpdContractList.stream().map(Contract::getContractNo).distinct().collect(Collectors.joining("','", "'", "'"));
String productTemplate = """
SELECT c.cInvName as product_name,c.cInvCode as product_code,c.cInvStd as product_model,a.hetongluru_name as contract_no,b.hetongluru_d_dec01 as num,b.hetongluru_d_dec02 as tax_price,b.hetongluru_d_dec03 as tax_rate,b.hetongluru_d_dec04 as no_tax_price,b.hetongluru_d_dec05 as discount_rate,b.hetongluru_d_dec06 as actual_price,b.hetongluru_d_dec07 as total_price,b.hetongluru_d_dec08 as erase from tcu_hetongluru a left join tcu_hetongluru_d b on a.hetongluru_id=b.m_id LEFT JOIN Inventory c on b.ref_obj_id=c.cInvCode where a.hetongluru_name in ({})
""";
var productSql = StrUtil.format(productTemplate, noStr);
var rs1 = statement.executeQuery(productSql);
var productList = new ArrayList<RContractProduct>();
while (rs1.next()) {
var contractProduct = new RContractProduct();
contractProduct.setContractNo(rs1.getString("contract_no"));
contractProduct.setProductName(rs1.getString("product_name"));
contractProduct.setProductCode(rs1.getString("product_code"));
contractProduct.setProductModel(rs1.getString("product_model"));
contractProduct.setNum(rs1.getInt("num"));
contractProduct.setTaxPrice(rs1.getBigDecimal("tax_price"));
contractProduct.setTaxRate(rs1.getBigDecimal("tax_rate"));
contractProduct.setNoTaxPrice(rs1.getBigDecimal("no_tax_price"));
contractProduct.setDiscountRate(rs1.getBigDecimal("discount_rate"));
contractProduct.setActualPrice(rs1.getBigDecimal("actual_price"));
contractProduct.setErase(rs1.getBigDecimal("erase"));
contractProduct.setTotalPrice(rs1.getBigDecimal("total_price"));
productList.add(contractProduct);
}
contractProductService.saveBatch(productList);
}
}
} catch (SQLException e) {
log.error("合同信息同步失败:", e);
......@@ -245,8 +291,335 @@ public class ContractRunner {
contractService.updateById(updDto);
});
log.info("【结束】从crm系统同步合同信息");
redissonClient.getBucket(RedisKeyEnum.CONTRACT_SYNC_TIME.getVal()).set(DateUtil.formatDateTime(insOrUpdContractList.get(0).getOriginalModTime()));
log.info("【结束】从crm系统同步合同信息");
}
// @Scheduled(cron = "0 0 * * * *")
@Transactional(rollbackFor = Exception.class)
public void contractSync1() {
String modifyTime = Opt.ofNullable((String) redissonClient.getBucket(RedisKeyEnum.CONTRACT_SYNC_NEW_TIME.getVal()).get()).orElse("0");
var json = JSONUtil.ofObj()
.set("sortMap", JSONUtil.ofObj()
.set("field", "updateTime")
.set("order", "desc"))
.set("conditions", JSONUtil.ofArray()
.put(JSONUtil.ofObj()
.set("attr", "updateTime")
.set("fieldType", "10015")
.set("symbol", "greatethan")
.set("value", new String[]{"1713324916"}))
)
.set("corpid", corpid)
.set("formId", 8429903);
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 jobj = JSONUtil.parseObj(res.bodyStr());
if (jobj.getInt("code") != 1) {
log.error("获取合同列表失败,错误原因:{}", jobj);
return;
}
var jsonArray = jobj.getJSONObject("result").getJSONArray("list");
var dataIdList = jsonArray.stream().map(v -> JSONUtil.parseObj(v).getInt("dataId")).toList();
if (CollUtil.isEmpty(dataIdList)) {
log.info("没有需要插入或更新的合同");
return;
}
Map<String, Integer> contractTypeMap = dictionaryService.lambdaQuery().eq(Dictionary::getType, "contract_type").list().stream().collect(Collectors.toMap(Dictionary::getValue, Dictionary::getKey));
List<Contract> insOrUpdContractList = new ArrayList<>();
List<RContractProduct> productList = new ArrayList<>();
var crmProList = getProductList();
if (CollUtil.isEmpty(crmProList)) {
log.error("获取CRM产品信息为空");
return;
}
dataIdList.forEach(dataId -> {
var json1 = JSONUtil.ofObj()
.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))
.body(json1.toString())
.method(Method.POST)
.send();
var jobj1 = JSONUtil.parseObj(res1.bodyStr());
if (jobj1.getInt("code") != 1) {
log.error("获取合同详情失败,错误原因:{}", jobj1);
return;
}
var result = jobj1.getJSONObject("result");
var jsonObj1 = result.getJSONObject("data");
Contract contract = new Contract();
contract.setName(jsonObj1.getStr("text_14"));
contract.setContractNo(jsonObj1.getStr("serialNo"));
contract.setType(contractTypeMap.getOrDefault(jsonObj1.getJSONObject("text_17").getStr("text"), 0));
contract.setSignDate(DateUtil.date(jsonObj1.getLong("date_1") * 1000));
contract.setMaintainSdate(Opt.ofNullable(jsonObj1.getLong("date_4")).map(sec -> DateUtil.date(sec * 1000)).orElse(null));
contract.setMaintainEdate(Opt.ofNullable(jsonObj1.getLong("date_5")).map(sec -> DateUtil.date(sec * 1000)).orElse(null));
contract.setStatus(1);
contract.setTotalAmount(jsonObj1.getBigDecimal("num_1"));
contract.setPaidAmount(BigDecimal.ZERO);
contract.setReceivableAmount(BigDecimal.ZERO);
contract.setOutstandingAmount(jsonObj1.getBigDecimal("num_1"));
var paymentForm = jsonObj1.getJSONArray("subForm_1");
paymentForm.forEach(pf -> {
var pfObj = JSONUtil.parseObj(pf);
var ratio = NumberUtil.div(BigDecimal.valueOf(Double.parseDouble(pfObj.getStr("text_1"))), 100);
var date = DateUtil.date(pfObj.getLong("date_1") * 1000);
var stage = pfObj.getJSONObject("text_2").getStr("text");
if (StrUtil.equals(stage, "预付款")) {
contract.setSignRatio(ratio);
contract.setSignDate1(date);
} else if (StrUtil.equals(stage, "到货款")) {
contract.setArriveRatio(ratio);
contract.setArriveDate(date);
} else if (StrUtil.equals(stage, "系统验收款")) {
contract.setSystemCheckRatio(ratio);
contract.setSystemCheckDate(date);
} else if (StrUtil.equals(stage, "项目终验款")) {
contract.setProjectCheckRatio(ratio);
contract.setProjectCheckDate(date);
} else if (StrUtil.equals(stage, "质保款")) {
contract.setWarrantyRatio(ratio);
contract.setWarrantyDate(date);
} else if (StrUtil.equals(stage, "维保第一笔款")) {
contract.setMaintainRatio1(ratio);
contract.setMaintainDate1(date);
} else if (StrUtil.equals(stage, "维保第二笔款")) {
contract.setMaintainRatio2(ratio);
contract.setMaintainDate2(date);
} else if (StrUtil.equals(stage, "维保第三笔款")) {
contract.setMaintainRatio3(ratio);
contract.setMaintainDate3(date);
} else if (StrUtil.equals(stage, "维保进度款")) {
contract.setMaintainProgressRatio(ratio);
contract.setMaintainProgressDate(date);
} else if (StrUtil.equals(stage, "维保验收款")) {
contract.setMaintainAcceptanceRatio(ratio);
contract.setMaintainAcceptanceDate(date);
}
});
contract.setSubject("北京文安智能技术股份有限公司");
contract.setCustomerName(jsonObj1.getJSONObject("text_2").getStr("name"));
contract.setSaleName(jsonObj1.getJSONObject("text_8").getStr("name"));
contract.setCreateUser(-1L);
contract.setModifyUser(-1L);
contract.setEntryTime(DateUtil.date(result.getLong("addTime") * 1000));
contract.setOriginalModTime(DateUtil.date(result.getLong("updateTime") * 1000));
insOrUpdContractList.add(contract);
var productArr = jsonObj1.getJSONArray("array_4");
productArr.forEach(pro -> {
var product = JSONUtil.parseObj(pro);
var crmProJson = crmProList.stream().filter(p -> p.getInt("dataId").equals(product.getInt("text_1"))).toList().get(0);
var crmPro = crmProJson.getJSONObject("data");
var contractProduct = new RContractProduct();
contractProduct.setContractNo(contract.getContractNo());
contractProduct.setProductName(crmPro.getStr("text_1"));
contractProduct.setProductCode(crmPro.getStr("text_17"));
contractProduct.setProductModel(crmPro.getStr("text_4"));
contractProduct.setNum(product.getInt("num_3"));
contractProduct.setTaxPrice(product.getBigDecimal("num_1"));
contractProduct.setTaxRate(BigDecimal.valueOf(Integer.parseInt(crmPro.getStr("text_12").replace("%", "")) / 100));
// contractProduct.setNoTaxPrice(product.getBigDecimal("num_6"));
contractProduct.setDiscountRate(NumberUtil.div(product.getBigDecimal("num_4"), 100));
contractProduct.setActualPrice(product.getBigDecimal("num_6"));
// contractProduct.setErase(product);
contractProduct.setTotalPrice(product.getBigDecimal("num_5"));
productList.add(contractProduct);
});
contractProductService.saveBatch(productList);
});
Map<String, Contract> no2ContactMap = contractService.list().stream().collect(Collectors.toMap(Contract::getContractNo, Function.identity()));
List<Long> updContractIdList = new ArrayList<>();
insOrUpdContractList.forEach(v -> {
if (no2ContactMap.containsKey(v.getContractNo())) {
Long contractId = no2ContactMap.get(v.getContractNo()).getId();
v.setId(contractId);
// 已有合同不更新状态
v.setStatus(null);
updContractIdList.add(contractId);
}
});
// 合同更新,同步调用一下更新项目的维保状态
Opt.ofEmptyAble(updContractIdList)
.map(contractIdList -> contractStoreService.lambdaQuery().in(RContractStore::getContractId, contractIdList).list())
.map(csList -> csList.stream().map(RContractStore::getStoreId).collect(Collectors.toList()))
.filter(CollUtil::isNotEmpty)
.ifPresent(storeService::calMaintainStatus);
contractService.saveOrUpdateBatch(insOrUpdContractList, 500);
insOrUpdContractList.forEach(v -> {
// 合同状态不为空,代表此条记录为新增,需要同步销售人信息到 r_contract_user 表中
if (ObjUtil.isNotNull(v.getStatus())) {
RContractUser contractUser = new RContractUser();
String userId = Opt.ofNullable(redissonClient.getBucket(RedisKeyEnum.DING_PREFIX.getVal() + RedisKeyEnum.USER_NAME.getVal() + v.getSaleName()).get())
.map(u -> (User) u)
.map(User::getUserid)
.orElse(null);
contractUser.setUserId(userId);
contractUser.setUsername(v.getSaleName());
contractUser.setEnterDate(v.getSignDate());
contractUser.setContractId(v.getId());
contractUser.setContractNo(v.getContractNo());
contractUserService.save(contractUser);
}
});
List<ContractPayment> existContractPaymentList = contractPaymentService.list();
Map<Long, Map<Integer, Long>> contractId2PaymentMap = existContractPaymentList.stream().collect(Collectors.groupingBy(ContractPayment::getContractId, Collectors.toMap(ContractPayment::getPaymentType, ContractPayment::getId)));
// 合同付款比例
List<ContractPayment> contractPaymentList = new ArrayList<>();
for (Contract contract : insOrUpdContractList) {
// 签订
ContractPayment contractSignPayment = new ContractPayment();
contractSignPayment.setId(contractId2PaymentMap.getOrDefault(contract.getId(), new HashMap<>()).get(1));
contractSignPayment.setContractId(contract.getId());
contractSignPayment.setPaymentType(1);
contractSignPayment.setPaymentRatio(Opt.ofNullable(contract.getSignRatio()).orElse(BigDecimal.ZERO));
contractSignPayment.setPaymentDate(contract.getSignDate1());
contractSignPayment.setNodeDate(contract.getSignDate());
contractPaymentList.add(contractSignPayment);
// 到货
ContractPayment contractArrivePayment = new ContractPayment();
contractArrivePayment.setId(contractId2PaymentMap.getOrDefault(contract.getId(), new HashMap<>()).get(2));
contractArrivePayment.setContractId(contract.getId());
contractArrivePayment.setPaymentType(2);
contractArrivePayment.setPaymentRatio(Opt.ofNullable(contract.getArriveRatio()).orElse(BigDecimal.ZERO));
contractArrivePayment.setPaymentDate(contract.getArriveDate());
contractPaymentList.add(contractArrivePayment);
// 系统验收
ContractPayment contractSystemCheckPayment = new ContractPayment();
contractSystemCheckPayment.setId(contractId2PaymentMap.getOrDefault(contract.getId(), new HashMap<>()).get(3));
contractSystemCheckPayment.setContractId(contract.getId());
contractSystemCheckPayment.setPaymentType(3);
contractSystemCheckPayment.setPaymentRatio(Opt.ofNullable(contract.getSystemCheckRatio()).orElse(BigDecimal.ZERO));
contractSystemCheckPayment.setPaymentDate(contract.getSystemCheckDate());
contractPaymentList.add(contractSystemCheckPayment);
// 项目验收
ContractPayment contractProjectCheckPayment = new ContractPayment();
contractProjectCheckPayment.setId(contractId2PaymentMap.getOrDefault(contract.getId(), new HashMap<>()).get(4));
contractProjectCheckPayment.setContractId(contract.getId());
contractProjectCheckPayment.setPaymentType(4);
contractProjectCheckPayment.setPaymentRatio(Opt.ofNullable(contract.getProjectCheckRatio()).orElse(BigDecimal.ZERO));
contractProjectCheckPayment.setPaymentDate(contract.getProjectCheckDate());
contractPaymentList.add(contractProjectCheckPayment);
// 质保
ContractPayment contractWarrantyPayment = new ContractPayment();
contractWarrantyPayment.setId(contractId2PaymentMap.getOrDefault(contract.getId(), new HashMap<>()).get(5));
contractWarrantyPayment.setContractId(contract.getId());
contractWarrantyPayment.setPaymentType(5);
contractWarrantyPayment.setPaymentRatio(Opt.ofNullable(contract.getWarrantyRatio()).orElse(BigDecimal.ZERO));
contractWarrantyPayment.setPaymentDate(contract.getWarrantyDate());
contractPaymentList.add(contractWarrantyPayment);
// 第一笔维保款
ContractPayment contractMaintainPayment1 = new ContractPayment();
contractMaintainPayment1.setId(contractId2PaymentMap.getOrDefault(contract.getId(), new HashMap<>()).get(6));
contractMaintainPayment1.setContractId(contract.getId());
contractMaintainPayment1.setPaymentType(6);
contractMaintainPayment1.setPaymentRatio(Opt.ofNullable(contract.getMaintainRatio1()).orElse(BigDecimal.ZERO));
contractMaintainPayment1.setPaymentDate(contract.getMaintainDate1());
contractPaymentList.add(contractMaintainPayment1);
// 第二笔维保款
ContractPayment contractMaintainPayment2 = new ContractPayment();
contractMaintainPayment2.setId(contractId2PaymentMap.getOrDefault(contract.getId(), new HashMap<>()).get(7));
contractMaintainPayment2.setContractId(contract.getId());
contractMaintainPayment2.setPaymentType(7);
contractMaintainPayment2.setPaymentRatio(Opt.ofNullable(contract.getMaintainRatio2()).orElse(BigDecimal.ZERO));
contractMaintainPayment2.setPaymentDate(contract.getMaintainDate2());
contractPaymentList.add(contractMaintainPayment2);
// 第三笔维保款
ContractPayment contractMaintainPayment3 = new ContractPayment();
contractMaintainPayment3.setId(contractId2PaymentMap.getOrDefault(contract.getId(), new HashMap<>()).get(8));
contractMaintainPayment3.setContractId(contract.getId());
contractMaintainPayment3.setPaymentType(8);
contractMaintainPayment3.setPaymentRatio(Opt.ofNullable(contract.getMaintainRatio3()).orElse(BigDecimal.ZERO));
contractMaintainPayment3.setPaymentDate(contract.getMaintainDate3());
contractPaymentList.add(contractMaintainPayment3);
}
contractPaymentService.saveOrUpdateBatch(contractPaymentList);
List<Payment> paymentList = paymentService.list();
Map<String, BigDecimal> no2PaymentMap = paymentList.stream().collect(Collectors.groupingBy(Payment::getContractNo, Collectors.reducing(BigDecimal.ZERO, Payment::getPaymentAmount, BigDecimal::add)));
insOrUpdContractList.forEach(c -> {
String contractNo = c.getContractNo();
Contract exist = contractService.lambdaQuery().eq(Contract::getContractNo, contractNo).one();
Contract updDto = new Contract();
updDto.setId(exist.getId());
updDto.setPaidAmount(no2PaymentMap.getOrDefault(contractNo, BigDecimal.ZERO));
contractPaymentService.calMoney(exist, updDto);
contractService.updateById(updDto);
});
redissonClient.getBucket(RedisKeyEnum.CONTRACT_SYNC_NEW_TIME.getVal()).set(insOrUpdContractList.get(0).getOriginalModTime().getTime());
log.info("【结束】从crm系统同步合同信息");
}
/**
* 获取CRM产品列表,若循环调用接口出现一次失败,则直接返回空列表
*
* @return java.util.List<org.dromara.hutool.json.JSONObject>
*/
public List<JSONObject> getProductList() {
List<JSONObject> resList = new ArrayList<>();
var json = JSONUtil.ofObj()
.set("corpid", corpid)
.set("page", 1)
.set("pageSize", 100);
var res = Request.of("https://proapi.xbongbong.com/pro/v2/api/product/list")
.header("sign", SecureUtil.sha256(json.toString() + token))
.body(json.toString())
.method(Method.POST)
.send();
var body = res.bodyStr();
var jobj = JSONUtil.parseObj(body);
if (jobj.getInt("code") != 1) {
log.error("获取CRM产品列表失败:{}", jobj);
return List.of();
}
var result = jobj.getJSONObject("result");
var totalPage = result.getInt("totalPage");
result.getJSONArray("list").stream().map(JSONUtil::parseObj).forEach(resList::add);
for (int i = 2; i <= totalPage; i++) {
var json1 = JSONUtil.ofObj()
.set("corpid", corpid)
.set("page", i)
.set("pageSize", 100);
var res1 = Request.of("https://proapi.xbongbong.com/pro/v2/api/product/list")
.header("sign", SecureUtil.sha256(json1 + token))
.body(json1.toString())
.method(Method.POST)
.send();
var body1 = res1.bodyStr();
var jobj1 = JSONUtil.parseObj(body1);
if (jobj1.getInt("code") != 1) {
log.error("获取CRM产品列表失败:{}", jobj1);
return List.of();
}
var result1 = jobj1.getJSONObject("result");
result1.getJSONArray("list").stream().map(JSONUtil::parseObj).forEach(resList::add);
}
return resList;
}
@Scheduled(cron = "0 0 1 * * ?")
......
......@@ -31,7 +31,7 @@ public class ContractDTO extends BaseDTO {
private Integer type;
/**
* 合同进度:1-签订 2-到货 3-系统验收(初验) 4-项目验收(终验) 5-质保 6-第一笔维保款 7-第二笔维保款 8-第三笔维保款
* 合同进度:1-签订 2-到货 3-系统验收(初验) 4-项目验收(终验) 5-质保 6-第一笔维保款 7-第二笔维保款 8-第三笔维保款 9-维保进度款 10-维保验收款
*/
private Integer status;
......
......@@ -58,6 +58,11 @@ public class SparePartDTO extends BaseDTO {
private Integer deviceNum;
/**
* 设备名称
*/
private String deviceName;
/**
* 收货地址
*/
private String shippingAddress;
......
......@@ -70,6 +70,20 @@ public class StoreDTO extends BaseDTO {
private Date planFinishDate;
/** 项目规模 */
private Integer projectSize;
/**
* 巡检次数
*/
private Integer inspectCount;
/**
* 巡检要求
*/
private String inspectRemark;
/**
* 施工数量
*/
private Integer constructionCount;
private Long sourceId;
private Long targetId;
......
......@@ -32,4 +32,6 @@ public class UserDTO extends BaseDTO {
/* 状态 0:正常 1:禁用 */
private Integer status;
private Long roleId;
}
\ No newline at end of file
package vion.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import vion.model.RContractProduct;
/**
* @author HlQ
* @date 2024/3/26
*/
public interface RContractProductMapper extends BaseMapper<RContractProduct> {
}
\ No newline at end of file
......@@ -3,29 +3,41 @@ package vion.model;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import vion.dto.BaseDTO;
import java.util.Date;
@Data
@TableName(value="tbl_account_info")
public class Account {
/** 自增列 */
@TableName(value = "tbl_account_info")
public class Account extends BaseDTO {
/**
* 自增列
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/** 名称 */
/**
* 名称
*/
@TableField(condition = SqlCondition.LIKE)
private String name;
/** 创建时间 */
/**
* 创建时间
*/
@TableField(value = "create_time", fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/** 修改时间 */
/**
* 修改时间
*/
@TableField(value = "modify_time", fill = FieldFill.INSERT_UPDATE)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date modifyTime;
/** 备注 */
/**
* 备注
*/
private String remark;
}
......@@ -260,14 +260,38 @@ public class Contract {
private Date maintainDate2;
/**
* 合同维保付款比例2
* 合同维保付款比例3
*/
@TableField(exist = false)
private BigDecimal maintainRatio3;
/**
* 合同维保付款日期2
* 合同维保付款日期3
*/
@TableField(exist = false)
private Date maintainDate3;
/**
* 维保进度款
*/
@TableField(exist = false)
private BigDecimal maintainProgressRatio;
/**
* 维保进度款付款日期
*/
@TableField(exist = false)
private Date maintainProgressDate;
/**
* 维保验收款
*/
@TableField(exist = false)
private BigDecimal maintainAcceptanceRatio;
/**
* 维保验收款付款日期
*/
@TableField(exist = false)
private Date maintainAcceptanceDate;
}
\ No newline at end of file
package vion.model;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
* @author HlQ
* @date 2024/3/26
*/
@Data
@TableName(value = "r_contract_product")
public class RContractProduct {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 合同编号
*/
@TableField(value = "contract_no")
private String contractNo;
/**
* 产品名称
*/
@TableField(value = "product_name")
private String productName;
/**
* 产品编码
*/
@TableField(value = "product_code")
private String productCode;
/**
* 产品模型
*/
@TableField(value = "product_model")
private String productModel;
/**
* 数量
*/
@TableField(value = "num")
private Integer num;
/**
* 含税单价
*/
@TableField(value = "tax_price")
private BigDecimal taxPrice;
/**
* 税率
*/
@TableField(value = "tax_rate")
private BigDecimal taxRate;
/**
* 无税单价
*/
@TableField(value = "no_tax_price")
private BigDecimal noTaxPrice;
/**
* 折扣率
*/
@TableField(value = "discount_rate")
private BigDecimal discountRate;
/**
* 实际单价
*/
@TableField(value = "actual_price")
private BigDecimal actualPrice;
/**
* 抹零
*/
@TableField(value = "erase")
private BigDecimal erase;
/**
* 价税合计
*/
@TableField(value = "total_price")
private BigDecimal totalPrice;
@TableField(value = "create_time", fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
}
\ No newline at end of file
......@@ -72,6 +72,12 @@ public class SparePart {
private Integer deviceNum;
/**
* 设备名称
*/
@TableField(value = "device_name")
private String deviceName;
/**
* 收货地址
*/
@TableField(value = "shipping_address")
......
......@@ -14,7 +14,7 @@ import java.util.Date;
* 门店信息
*/
@Data
@TableName(value="tbl_store_info")
@TableName(value = "tbl_store_info")
@AutoMappers({
@AutoMapper(target = StoreVO.class),
@AutoMapper(target = StoreDTO.class),
......@@ -22,74 +22,137 @@ import java.util.Date;
public class Store {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/** 门店名称 */
/**
* 门店名称
*/
@TableField(condition = SqlCondition.LIKE)
private String name;
/** 销售人 */
/**
* 销售人
*/
private Integer salesperson;
/** 客户姓名 */
/**
* 客户姓名
*/
private String customerName;
/** 实施类型:0纯供货、1供货+安装、3续保、4维修 */
/**
* 实施类型:0纯供货、1供货+安装、3续保、4维修
*/
private Integer implementType;
/** 项目状态:0待确认、1进行中、2已完成、3挂起 */
/**
* 项目状态:0待确认、1进行中、2已完成、3挂起
*/
private Integer projectState;
/** 创建者 */
/**
* 创建者
*/
private Long createUser;
/** 修改者 */
/**
* 修改者
*/
private Long modifyUser;
/** 创建时间 */
/**
* 创建时间
*/
@TableField(value = "create_time", fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@OrderBy
private Date createTime;
/** 修改时间 */
/**
* 修改时间
*/
@TableField(value = "modify_time", fill = FieldFill.INSERT_UPDATE)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date modifyTime;
/** 备注 */
/**
* 备注
*/
private String remark;
/** 项目阶段 */
/**
* 项目阶段
*/
private Integer projectStage;
/** 集团id */
/**
* 集团id
*/
private Long accountId;
/** 主合同id */
/**
* 主合同id
*/
private Long masterContract;
/** 维保状态 */
/**
* 维保状态
*/
private String maintainStatus;
/** 产品线属性 */
/**
* 产品线属性
*/
private Integer productLine;
/** 是否重点项目 0:不是 1:是 */
/**
* 是否重点项目 0:不是 1:是
*/
private Integer isImportant;
/** 任务详情 */
/**
* 任务详情
*/
private String taskDetail;
/** 实际完成日期 */
/**
* 实际完成日期
*/
private Date finishDate;
/** 完成百分比 */
/**
* 完成百分比
*/
private Double percentage;
/** 当前卡点 */
/**
* 当前卡点
*/
private String stuckPoint;
/** 主要产品 */
/**
* 主要产品
*/
private Integer mainProduct;
/** 点位数量 */
/**
* 点位数量
*/
private Integer pointNum;
/** 计划完成日期 */
/**
* 计划完成日期
*/
private Date planFinishDate;
/** 项目规模 */
/**
* 项目规模
*/
private Integer projectSize;
/**
* 巡检次数
*/
private Integer inspectCount;
/**
* 巡检要求
*/
private String inspectRemark;
/**
* 施工数量
*/
private Integer constructionCount;
}
package vion.service;
import org.dromara.hutool.json.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.base.MPJBaseService;
import org.dromara.hutool.json.JSONObject;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import vion.dto.ContractDTO;
import vion.dto.RContractTeamDTO;
import vion.model.Contract;
import vion.model.RContractProduct;
import vion.model.RContractUser;
import vion.vo.ContractVO;
import java.util.List;
import java.util.Map;
/**
* @author HlQ
* @date 2023/11/29
*/
public interface IContractService extends MPJBaseService<Contract>{
public interface IContractService extends MPJBaseService<Contract> {
Page<ContractVO> list(ContractDTO dto);
......@@ -41,4 +43,10 @@ public interface IContractService extends MPJBaseService<Contract>{
String unbindSale(RContractUser contractUser);
List<RContractProduct> getProduct(String contractNo);
String createContract(String contractJson);
JSONObject getCRMProduct(String name, String code, Integer page, Integer pageSize);
}
\ No newline at end of file
package vion.service;
import vion.model.RContractProduct;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @author HlQ
* @date 2024/3/26
*/
public interface IRContractProductService extends IService<RContractProduct>{
}
......@@ -11,6 +11,7 @@ import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import io.github.linpeilie.Converter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.bean.BeanUtil;
import org.dromara.hutool.core.collection.CollUtil;
......@@ -26,6 +27,8 @@ import org.dromara.hutool.core.map.MapUtil;
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.Request;
import org.dromara.hutool.http.meta.Method;
import org.dromara.hutool.json.JSONObject;
import org.dromara.hutool.json.JSONUtil;
import org.springframework.beans.factory.annotation.Value;
......@@ -53,6 +56,7 @@ import java.util.stream.Collectors;
*/
@Service
@RequiredArgsConstructor
@Slf4j
public class ContractServiceImpl extends MPJBaseServiceImpl<ContractMapper, Contract> implements IContractService {
private final IFileService fileService;
......@@ -61,6 +65,7 @@ public class ContractServiceImpl extends MPJBaseServiceImpl<ContractMapper, Cont
private final IContractLogService contractLogService;
private final IRContractTeamService contractTeamService;
private final IRContractUserService contractUserService;
private final IRContractProductService contractProductService;
// 引入 settlementDiffService 会循环依赖
private final SettlementDiffMapper settlementDiffMapper;
private final DingMod dingMod;
......@@ -68,6 +73,8 @@ public class ContractServiceImpl extends MPJBaseServiceImpl<ContractMapper, Cont
@Value("${fileUrl:}")
private String fileUrl;
@Value("${xbongbong.token}")
private String token;
@Override
public Page<ContractVO> list(ContractDTO dto) {
......@@ -78,13 +85,20 @@ public class ContractServiceImpl extends MPJBaseServiceImpl<ContractMapper, Cont
.ifPresent(page::addOrder);
Page<ContractVO> contractVOList = this.selectJoinListPage(page, ContractVO.class, result.wrapper);
Opt.ofEmptyAble(settlementDiffMapper.selectList(Wrappers.<SettlementDiff>lambdaQuery()
.in(CollUtil.isNotEmpty(contractVOList.getRecords()), SettlementDiff::getContractId, contractVOList.getRecords().stream().map(ContractVO::getId).collect(Collectors.toList()))))
var idList = Opt.ofEmptyAble(contractVOList.getRecords())
.map(r -> r.stream().map(ContractVO::getId).collect(Collectors.toList()))
.orElse(ListUtil.empty());
// 结算差异
Opt.ofEmptyAble(idList)
.map(l -> settlementDiffMapper.selectList(Wrappers.<SettlementDiff>lambdaQuery()
.in(SettlementDiff::getContractId, l)))
.map(list -> list.stream().collect(Collectors.groupingBy(SettlementDiff::getContractId, Collectors.reducing(BigDecimal.ZERO, SettlementDiff::getSettlementDiff, BigDecimal::add))))
.ifPresent(map -> contractVOList.getRecords().forEach(vo -> vo.setDiffAmount(map.getOrDefault(vo.getId(), BigDecimal.ZERO))));
Opt.ofEmptyAble(contractUserService.lambdaQuery()
.in(CollUtil.isNotEmpty(contractVOList.getRecords()), RContractUser::getContractId, contractVOList.getRecords().stream().map(ContractVO::getId).collect(Collectors.toList()))
// 合同绑定销售
Opt.ofEmptyAble(idList)
.map(l -> contractUserService.lambdaQuery()
.in(RContractUser::getContractId, l)
.list())
.map(list -> list.stream().collect(Collectors.groupingBy(RContractUser::getContractId)))
.ifPresent(map -> contractVOList.getRecords().forEach(vo -> map.getOrDefault(vo.getId(), ListUtil.empty()).stream()
......@@ -167,6 +181,11 @@ public class ContractServiceImpl extends MPJBaseServiceImpl<ContractMapper, Cont
contractVO.setOutstandingAmount(null);
contractVO.setInvoiceAmount(null);
}
// 合同关联产品
var contractProducts = contractProductService.lambdaQuery()
.eq(RContractProduct::getContractNo, contractVO.getContractNo())
.list();
contractVO.setContractProducts(contractProducts);
return contractVO;
}
......@@ -242,6 +261,10 @@ public class ContractServiceImpl extends MPJBaseServiceImpl<ContractMapper, Cont
contractLog.setContent("合同:第二笔维保款");
} else if (status == 8) {
contractLog.setContent("合同:第三笔维保款");
} else if (status == 9) {
contractLog.setContent("合同:维保进度款");
} else if (status == 10) {
contractLog.setContent("合同:维保验收款");
}
contractLog.setOperator(userVO.getId());
contractLogService.save(contractLog);
......@@ -414,6 +437,64 @@ public class ContractServiceImpl extends MPJBaseServiceImpl<ContractMapper, Cont
return contractUserService.remove(Wrappers.<RContractUser>lambdaQuery().eq(RContractUser::getContractId, contractUser.getContractId()).eq(RContractUser::getUserId, contractUser.getUserId())) ? "解绑成功" : "解绑失败";
}
@Override
public List<RContractProduct> getProduct(String contractNo) {
return contractProductService.lambdaQuery().eq(RContractProduct::getContractNo, contractNo).list();
}
@Override
public String createContract(String contractJson) {
var sha256 = SecureUtil.sha256(contractJson + token);
var res = Request.of("https://proapi.xbongbong.com/pro/v2/api/contract/list")
.header("sign", sha256)
.body(contractJson)
.method(Method.POST)
.send();
var body = res.bodyStr();
var jobj = JSONUtil.parseObj(body);
if (jobj.getInt("code") != 1) {
log.error("调用CRM接口创建合同失败,错误原因:{}", body);
return "创建合同失败";
}
return "合同创建成功";
}
@Override
public JSONObject getCRMProduct(String name, String code, Integer page, Integer pageSize) {
var conditions = JSONUtil.ofArray().put(JSONUtil.ofObj()
.set("attr", "num_3")
.set("symbol", "noequal")
.set("value", new int[]{0}));
if (StrUtil.isNotBlank(name)) {
conditions.put(JSONUtil.ofObj().set("attr", "text_1").set("symbol", "like").set("value", new String[]{name}));
}
if (StrUtil.isNotBlank(code)) {
conditions.put(JSONUtil.ofObj().set("attr", "serialNo").set("symbol", "like").set("value", new String[]{code}));
}
var json = JSONUtil.ofObj()
.set("corpid", "ding6bb660048f7ae2dcee0f45d8e4f7c288")
.set("page", page)
.set("pageSize", pageSize)
.set("conditions", conditions);
var res = Request.of("https://proapi.xbongbong.com/pro/v2/api/product/list")
.header("sign", SecureUtil.sha256(json.toString() + token))
.body(json.toString())
.method(Method.POST)
.send();
var body = res.bodyStr();
var jobj = JSONUtil.parseObj(body);
if (jobj.getInt("code") != 1) {
log.error("调用CRM接口获取产品列表失败,错误原因:{}", body);
return JSONUtil.ofObj();
}
return JSONUtil.ofObj().set("records", jobj.getJSONObject("result").getJSONArray("list"))
.set("current", page)
.set("size", pageSize)
.set("total", jobj.getJSONObject("result").getInt("totalCount"))
.set("pages", jobj.getJSONObject("result").getInt("totalPage"));
}
private Result getResult(ContractDTO dto) {
// 查询已关联项目的合同id
List<Long> contractIdList = dto.getSwitchFlag() == 1 ?
......
......@@ -48,7 +48,6 @@ public class DeliveryRecordServiceImpl extends MPJBaseServiceImpl<DeliveryRecord
private final IFileService fileService;
private final IContractService contractService;
private final IRContractUserService contractUserService;
private final IContractPaymentService contractPaymentService;
private final IPointInfoService pointInfoService;
private final DingMod dingMod;
private final Converter converter;
......
package vion.service.impl;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import vion.model.RContractProduct;
import vion.mapper.RContractProductMapper;
import vion.service.IRContractProductService;
/**
* @author HlQ
* @date 2024/3/26
*/
@Service
public class RContractProductServiceImpl extends ServiceImpl<RContractProductMapper, RContractProduct> implements IRContractProductService {
}
......@@ -55,6 +55,7 @@ public class StoreServiceImpl extends MPJBaseServiceImpl<StoreMapper, Store> imp
private final ITagService tagService;
private final IRStoreTagService storeTagService;
private final IRStoreUserService storeUserService;
private final IStoreLogService storeLogService;
private final Converter converter;
// 引入 taskService 会循环依赖
private final TaskMapper taskMapper;
......@@ -140,6 +141,12 @@ public class StoreServiceImpl extends MPJBaseServiceImpl<StoreMapper, Store> imp
.map(serviceOrderList -> serviceOrderList.stream().collect(Collectors.groupingBy(ServiceOrder::getTaskId)))
.orElse(MapUtil.empty());
// storeId -> storeLog
var store2LogMap = Opt.ofEmptyAble(storeIdList)
.map(l -> storeLogService.lambdaQuery().in(StoreLog::getStoreId, l).list())
.map(storeLogList -> storeLogList.stream().collect(Collectors.groupingBy(StoreLog::getStoreId)))
.orElse(MapUtil.empty());
// storeId -> tagList
var storeId2TagMap = Opt.ofEmptyAble(storeIdList)
.map(l -> {
......@@ -186,6 +193,7 @@ public class StoreServiceImpl extends MPJBaseServiceImpl<StoreMapper, Store> imp
storeVO.setMainContract(Opt.ofNullable(masterContract).map(c -> converter.convert(c, ContractVO.class)).orElse(null));
storeVO.setTaskCount(store2TaskIdMap.getOrDefault(storeId, ListUtil.empty()).size());
storeVO.setLogCount(store2LogMap.getOrDefault(storeId, ListUtil.empty()).size());
// 补充服务单
if (store2TaskIdMap.containsKey(item.getId())) {
......@@ -385,6 +393,7 @@ public class StoreServiceImpl extends MPJBaseServiceImpl<StoreMapper, Store> imp
var fileMap = storeId2FileMap.getOrDefault(storeId, MapUtil.empty());
Map<String, Number> map = new HashMap<>();
map.put("storeId", storeId);
map.put("1", fileMap.getOrDefault(1, List.of()).size());
map.put("24", fileMap.getOrDefault(24, List.of()).size());
map.put("25", fileMap.getOrDefault(25, List.of()).size());
map.put("26", fileMap.getOrDefault(26, List.of()).size());
......
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;
import io.github.linpeilie.Converter;
import lombok.RequiredArgsConstructor;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.collection.ListUtil;
import org.dromara.hutool.core.lang.Opt;
import org.dromara.hutool.core.tree.MapTree;
......@@ -18,6 +20,7 @@ import vion.model.RUserRole;
import vion.model.Role;
import vion.model.User;
import vion.service.IDeptService;
import vion.service.IRUserRoleService;
import vion.service.IRoleService;
import vion.service.IUserService;
import vion.vo.RoleVO;
......@@ -26,6 +29,7 @@ import vion.vo.UserVO;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@Service
......@@ -34,15 +38,23 @@ public class UserServiceImpl extends MPJBaseServiceImpl<UserMapper, User> implem
private final IDeptService deptService;
private final IRoleService roleService;
private final IRUserRoleService userRoleService;
private final Converter converter;
@Override
public Page<UserVO> getUserList(UserDTO dto) {
var userIdSet = Opt.ofNullable(dto.getRoleId())
.map(roleId -> userRoleService.lambdaQuery().eq(RUserRole::getRoleId, roleId).list())
.filter(CollUtil::isNotEmpty)
.map(l -> l.stream().map(RUserRole::getUserId).collect(Collectors.toSet()))
.orElse(Set.of(-1L));
var wrapper = new MPJLambdaWrapper<>(converter.convert(dto, User.class))
.selectAll(User.class)
.select(Dept::getDeptName)
.leftJoin(Dept.class, Dept::getDeptId, User::getDeptId)
.ne(User::getStatus, 5)
.in(ObjUtil.isNotNull(dto.getRoleId()), User::getId, userIdSet)
.orderByAsc(User::getStatus);
var userVOS = this.selectJoinListPage(Page.of(dto.getPageNum(), dto.getPageSize()), UserVO.class, wrapper);
var roleWrapper = new MPJLambdaWrapper<Role>()
......
......@@ -32,8 +32,8 @@ import vion.vo.RoleVO;
import vion.vo.UserVO;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
......@@ -235,9 +235,12 @@ public class DingMod {
return useridObj;
}
String userid = useridObj.getJSONObject("result").getStr("userid");
User user = userService.lambdaQuery().select(User::getId, User::getUserid, User::getUsername, User::getPhone, User::getStatus).eq(User::getUserid, userid).one();
User user = userService.lambdaQuery()
.select(User::getId, User::getUserid, User::getUsername, User::getPhone, User::getStatus, User::getEmployeeStatus)
.eq(User::getUserid, userid).one();
UserVO userVO = converter.convert(user, UserVO.class);
if (userVO.getStatus() == 1) {
// 禁用用户或离职用户禁止登录系统
if (userVO.getStatus() == 1 || userVO.getEmployeeStatus() == 5) {
return "该用户禁止登录系统,请联系管理员!";
}
Long id = userVO.getId();
......@@ -322,20 +325,15 @@ public class DingMod {
* 构建获取用户信息url
*/
String buildSignUrl() {
try {
String appSecret = "Ul5UTZqIost_kEAdfZXidvLoZhzvraYurm_g7PCHg-IrDMLHT7mdSgRS1iCHrDPt";
String timestamp = String.valueOf(System.currentTimeMillis());
HMac hMac = SecureUtil.hmacSha256(appSecret);
byte[] signBytes = hMac.digest(timestamp);
String sign = Base64.encode(signBytes);
String encode = URLEncoder.encode(sign, "UTF-8");
String encode = URLEncoder.encode(sign, StandardCharsets.UTF_8);
String encodeSign = encode.replace("+", "%20").replace("*", "%2A").replace("~", "%7E").replace("/", "%2F").replace("=", "%3D");
return StrUtil.format("https://oapi.dingtalk.com/sns/getuserinfo_bycode?accessKey=dingkrzwks0jpi2di3uo&timestamp={}&signature={}", timestamp, encodeSign);
} catch (UnsupportedEncodingException e) {
log.error("通过appSecret计算出来的签名值失败", e);
}
return "";
}
public String robotPush(String access_token, String body) {
......
......@@ -6,6 +6,7 @@ import com.github.liaochong.myexcel.core.annotation.ExcelModel;
import lombok.Getter;
import lombok.Setter;
import vion.model.ContractLog;
import vion.model.RContractProduct;
import java.math.BigDecimal;
import java.util.Date;
......@@ -171,4 +172,6 @@ public class ContractVO {
private List<StoreVO> storeVOS;
private List<ContractLog> contractLogs;
private List<RContractProduct> contractProducts;
}
\ No newline at end of file
......@@ -72,6 +72,11 @@ public class SparePartVO {
private Integer deviceNum;
/**
* 设备名称
*/
private String deviceName;
/**
* 收货地址
*/
private String shippingAddress;
......
......@@ -143,4 +143,24 @@ public class StoreVO {
* 项目负责人 or 项目经理
*/
private Long mainUser;
/**
* 巡检次数
*/
private Integer inspectCount;
/**
* 巡检要求
*/
private String inspectRemark;
/**
* 施工数量
*/
private Integer constructionCount;
/**
* 工单日志数量
*/
private Integer logCount;
}
debug=false
server.port=8011
################################## DATABASE ########################################
spring.datasource.url=jdbc:postgresql://pgm-2ze3cjpyjgjw0bl5uo.pg.rds.aliyuncs.com:1921/work-order
spring.datasource.username=vion
......@@ -17,9 +18,11 @@ wx.mp.config-storage.redis.password==RtOTnx2V
wx.mp.config-storage.redis.port=6379
wx.mp.config-storage.redis.database=8
server.port=8011
fileUrl=D:/pic
#fileurl=/nas-data/work-order
appkey=dingkrzwks0jpi2di3uo
appsecret=Ul5UTZqIost_kEAdfZXidvLoZhzvraYurm_g7PCHg-IrDMLHT7mdSgRS1iCHrDPt
xbongbong.corpid=ding6bb660048f7ae2dcee0f45d8e4f7c288
xbongbong.token=c7f9264e9e1687866c37032295552610
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
\ No newline at end of file
debug=false
server.port=8011
################################## DATABASE ########################################
spring.datasource.url=jdbc:postgresql://pgm-2ze3cjpyjgjw0bl5uo.pg.rds.aliyuncs.com:1921/work-order
spring.datasource.username=vion
spring.datasource.password=jkou72j32m4K5d8k
spring.datasource.driver-class-name=org.postgresql.Driver
server.port=8088
\ No newline at end of file
spring.data.redis.host=r-2zejlb88mng3q50aw7pd.redis.rds.aliyuncs.com
spring.data.redis.password=RtOTnx2V
spring.data.redis.port=6379
spring.data.redis.database=8
wx.mp.config-storage.type=Redisson
wx.mp.config-storage.key-prefix=wa
wx.mp.config-storage.redis.host=r-2zejlb88mng3q50aw7pd.redis.rds.aliyuncs.com
wx.mp.config-storage.redis.password==RtOTnx2V
wx.mp.config-storage.redis.port=6379
wx.mp.config-storage.redis.database=8
fileurl=/nas-data/work-order
appkey=dingkrzwks0jpi2di3uo
appsecret=Ul5UTZqIost_kEAdfZXidvLoZhzvraYurm_g7PCHg-IrDMLHT7mdSgRS1iCHrDPt
\ No newline at end of file
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!