ContractFlow.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. package com.fjhx.sale.flow;
  2. import cn.hutool.core.bean.BeanUtil;
  3. import cn.hutool.core.util.ObjectUtil;
  4. import com.alibaba.fastjson.JSONObject;
  5. import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
  6. import com.baomidou.mybatisplus.core.toolkit.IdWorker;
  7. import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
  8. import com.fjhx.area.utils.CustomizeAreaUtil;
  9. import com.fjhx.common.entity.InOutBo;
  10. import com.fjhx.common.enums.CodingRuleEnum;
  11. import com.fjhx.common.enums.FlowStatusEnum1;
  12. import com.fjhx.common.enums.InOutType;
  13. import com.fjhx.common.service.coding.CodingRuleService;
  14. import com.fjhx.common.service.file.FtpFileService;
  15. import com.fjhx.common.utils.Assert;
  16. import com.fjhx.file.utils.ObsFileUtil;
  17. import com.fjhx.flow.core.FlowDelegate;
  18. import com.fjhx.flow.enums.FlowStatusEnum;
  19. import com.fjhx.item.entity.product.po.ProductBomDetail;
  20. import com.fjhx.item.entity.product.po.ProductInfo;
  21. import com.fjhx.item.entity.product.po.ProductStockInfo;
  22. import com.fjhx.item.enums.ProductAvailableRecordType;
  23. import com.fjhx.item.service.product.ProductBomDetailService;
  24. import com.fjhx.item.service.product.ProductInfoService;
  25. import com.fjhx.item.service.product.ProductStockInfoService;
  26. import com.fjhx.purchase.entity.subscribe.po.SubscribeDetail;
  27. import com.fjhx.purchase.service.subscribe.SubscribeDetailService;
  28. import com.fjhx.sale.entity.contract.dto.ContractDto;
  29. import com.fjhx.sale.entity.contract.dto.ContractProductDto;
  30. import com.fjhx.sale.entity.contract.po.Contract;
  31. import com.fjhx.sale.entity.contract.po.ContractProduct;
  32. import com.fjhx.sale.entity.contract.po.ContractProductBom;
  33. import com.fjhx.sale.entity.contract.po.ContractProject;
  34. import com.fjhx.sale.service.contract.ContractProductBomService;
  35. import com.fjhx.sale.service.contract.ContractProductService;
  36. import com.fjhx.sale.service.contract.ContractProjectService;
  37. import com.fjhx.sale.service.contract.ContractService;
  38. import com.fjhx.tenant.utils.DeptUstil;
  39. import com.ruoyi.common.annotation.LogicIgnore;
  40. import com.ruoyi.common.core.domain.BasePo;
  41. import com.ruoyi.common.core.domain.entity.SysDept;
  42. import com.ruoyi.common.core.domain.entity.SysUser;
  43. import com.ruoyi.common.exception.ServiceException;
  44. import com.ruoyi.common.utils.SecurityUtils;
  45. import com.ruoyi.common.utils.StringUtils;
  46. import com.ruoyi.system.service.ISysDeptService;
  47. import org.springframework.beans.factory.annotation.Autowired;
  48. import org.springframework.stereotype.Component;
  49. import java.math.BigDecimal;
  50. import java.util.*;
  51. import java.util.stream.Collectors;
  52. /**
  53. * 外销合同流程
  54. *
  55. * @Author:caozj
  56. * @DATE:2023/4/3 17:38
  57. */
  58. @Component
  59. //@DS(SourceConstant.SALE)
  60. public class ContractFlow extends FlowDelegate {
  61. @Autowired
  62. private CodingRuleService codingRuleService;
  63. @Autowired
  64. private ContractService contractService;
  65. @Autowired
  66. private ContractProductService contractProductService;
  67. @Autowired
  68. private ContractProjectService contractProjectService;
  69. @Autowired
  70. private FtpFileService ftpFileService;
  71. @Autowired
  72. private ProductInfoService productInfoService;
  73. @Autowired
  74. private SubscribeDetailService subscribeDetailService;
  75. @Autowired
  76. private ProductBomDetailService productBomDetailService;
  77. @Autowired
  78. private ISysDeptService deptService;
  79. @Autowired
  80. private ProductStockInfoService productStockInfoService;
  81. @Autowired
  82. private ContractProductBomService contractProductBomService;
  83. @Override
  84. public String getFlowKey() {
  85. return "contract_flow";
  86. }
  87. /**
  88. * 发起流程
  89. *
  90. * @param flowId 流程ID
  91. * @param submitData 采购付款数据
  92. * @return 业务id
  93. */
  94. @Override
  95. public Long start(Long flowId, JSONObject submitData) {
  96. ContractDto contract = submitData.toJavaObject(ContractDto.class);
  97. contract.setFlowId(flowId);
  98. if (StringUtils.isEmpty(contract.getCurrency())) {
  99. throw new ServiceException("币种不能为空");
  100. }
  101. contract.setCode(codingRuleService.createCode(CodingRuleEnum.CONTRACT.getKey(), contract.getBuyCorporationId()));
  102. // 保存合同产品
  103. List<ContractProductDto> contractProductList = contract.getContractProductList();
  104. // 赋值待处理数量
  105. if (CollectionUtils.isNotEmpty(contractProductList)) {
  106. contractProductList.forEach(item -> item.setExpendQuantity(item.getQuantity()));
  107. }
  108. //将code赋值给流程引擎
  109. submitData.put("code", contract.getCode());
  110. return start(contract);
  111. }
  112. /**
  113. * 结束流程
  114. *
  115. * @param flowId 流程ID
  116. * @param businessId 业务ID
  117. * @param submitData 数据
  118. */
  119. @Override
  120. public void end(Long flowId, Long businessId, JSONObject submitData) {
  121. // 通过业务ID查询合同数据
  122. Contract contract = contractService.getById(businessId);
  123. if (ObjectUtils.isEmpty(contract)) {
  124. throw new ServiceException("合同不存在");
  125. }
  126. // 修改合同状态为审批通过
  127. contract.setStatus(FlowStatusEnum1.PASS.getKey());
  128. contract.setApprovedDate(new Date());
  129. contractService.updateById(contract);
  130. //生成物料待采购数据
  131. createMaterialWaitPurchase(contract);
  132. }
  133. public Long start(ContractDto contract) {
  134. //赋值归属部门,归属公司信息
  135. Long deptId = contract.getDeptId();
  136. Assert.notEmpty(deptId, "归属部门id不能为空!");
  137. Long companyId = DeptUstil.getCompanyIdByDeptId(deptId);
  138. contract.setCompanyId(companyId);
  139. // 赋值城市省份信息
  140. CustomizeAreaUtil.setAreaId(contract);
  141. SysUser loginUser = SecurityUtils.getLoginUser().getUser();
  142. contract.setUserName(loginUser.getNickName());
  143. contract.setBuyCityId(contract.getCityId());
  144. contract.setBuyCountryId(contract.getCountryId());
  145. contract.setBuyProvinceId(contract.getProvinceId());
  146. contract.setStatus(FlowStatusEnum1.UNDER_REVIEW.getKey());
  147. contractService.saveOrUpdate(contract);
  148. // 保存合同产品
  149. List<ContractProductDto> contractProductListDto = contract.getContractProductList();
  150. contractProductListDto = ObjectUtil.isEmpty(contractProductListDto) ? new ArrayList<>() : contractProductListDto;
  151. for (ContractProductDto cp : contractProductListDto) {
  152. //对新数据创建id
  153. cp.setId(ObjectUtil.isEmpty(cp.getId()) ? IdWorker.getId() : cp.getId());
  154. //赋值合同Id
  155. cp.setContractId(contract.getId());
  156. //保存设计稿图
  157. ObsFileUtil.editFile(cp.getFileList(), cp.getId());
  158. //保存生产源文件
  159. String prodFilePath = cp.getProdFilePath();
  160. if (ObjectUtil.isNotEmpty(prodFilePath) && prodFilePath.startsWith("/temp")) {
  161. String targetFolderPath = String.format("/contractProduct/%s", cp.getId());
  162. com.alibaba.fastjson2.JSONObject prodFile = ftpFileService.moveFolder(prodFilePath, targetFolderPath);
  163. cp.setProdFilePath(prodFile.getString("path"));
  164. }
  165. //赋值产品BOM信息
  166. List<ContractProductBom> contractProductBomList = cp.getContractProductBomList();
  167. for (ContractProductBom contractProductBom : contractProductBomList) {
  168. contractProductBom.setContractProductId(cp.getId());
  169. contractProductBom.setProductId(cp.getProductId());
  170. }
  171. contractProductBomService.editLinked(contractProductBomList, ContractProductBom::getContractProductId, cp.getId());
  172. }
  173. List<ContractProduct> contractProductList1 = BeanUtil.copyToList(contractProductListDto, ContractProduct.class);
  174. contractProductService.editLinked(contractProductList1, ContractProduct::getContractId, contract.getId());
  175. // 保存收费项目
  176. List<ContractProject> contractProjectList = contract.getContractProjectList();
  177. contractProjectList = ObjectUtil.isEmpty(contractProjectList) ? new ArrayList<>() : contractProjectList;
  178. for (ContractProject c : contractProjectList) {
  179. c.setContractId(contract.getId());
  180. }
  181. contractProjectService.editLinked(contractProjectList, ContractProject::getContractId, contract.getId());
  182. return contract.getId();
  183. }
  184. /**
  185. * 重新发起
  186. *
  187. * @param flowId
  188. * @param businessId
  189. * @param flowStatus
  190. * @param submitData
  191. */
  192. @Override
  193. @LogicIgnore
  194. public void relaunch(Long flowId, Long businessId, FlowStatusEnum flowStatus, JSONObject submitData) {
  195. //删除采购合同
  196. ContractDto contractDto = submitData.toJavaObject(ContractDto.class);
  197. if (ObjectUtils.isEmpty(contractDto)) {
  198. throw new ServiceException("合同数据不能为空");
  199. }
  200. start(contractDto);
  201. }
  202. /**
  203. * 驳回
  204. *
  205. * @param flowId
  206. * @param businessId
  207. * @param flowStatus
  208. */
  209. @Override
  210. public void reject(Long flowId, Long businessId, FlowStatusEnum flowStatus) {
  211. contractService.update(q -> q
  212. .eq(Contract::getId, businessId)
  213. .set(Contract::getStatus, 20)//20为驳回
  214. .set(Contract::getUpdateTime, new Date())
  215. .set(BasePo::getUpdateUser, SecurityUtils.getUserId())
  216. );
  217. }
  218. @Override
  219. public void cancellation(Long flowId, Long businessId, FlowStatusEnum flowStatus) {
  220. super.cancellation(flowId, businessId, flowStatus);
  221. contractService.update(q -> q
  222. .eq(Contract::getId, businessId)
  223. .set(Contract::getStatus, FlowStatusEnum1.CANCELLATION.getKey())
  224. .set(BasePo::getUpdateTime, new Date())
  225. .set(BasePo::getUpdateUser, SecurityUtils.getUserId())
  226. );
  227. }
  228. /**
  229. * 创建合同产品 物料待采购信息
  230. */
  231. private void createMaterialWaitPurchase(Contract contract) {
  232. //生成物料待采购数据
  233. List<ContractProduct> contractProductList = contractProductService.list(q -> q.eq(ContractProduct::getContractId, contract.getId()));
  234. List<Long> productIds = contractProductList.stream().map(ContractProduct::getProductId).collect(Collectors.toList());
  235. //获取产品列表
  236. Map<Long, ProductInfo> productInfoMap = productInfoService.mapKEntity(ProductInfo::getId, q -> q.in(ProductInfo::getId, productIds));
  237. //获取物料信息
  238. Map<Long, List<ProductBomDetail>> productBomMap = productBomDetailService.mapKGroup(ProductBomDetail::getProductId, q -> q.in(ProductBomDetail::getProductId, productIds));
  239. //待采购列表
  240. List<SubscribeDetail> subscribeDetailList = new ArrayList<>();
  241. for (ContractProduct contractProduct : contractProductList) {
  242. Long productId = contractProduct.getProductId();
  243. ProductInfo productInfo = productInfoMap.get(productId);
  244. //获取物料列表,以及原材料
  245. List<ProductBomDetail> productBomDetails = productBomMap.get(productId);
  246. if (ObjectUtil.isNotEmpty(productBomDetails)) {
  247. List<Long> materialIds = productBomDetails.stream().map(ProductBomDetail::getMaterialId).collect(Collectors.toList());
  248. Map<Long, ProductInfo> materialMap = productInfoService.mapKEntity(ProductInfo::getId, q -> q.in(ProductInfo::getId, materialIds));
  249. //获取合同归属归属的物料可用库存
  250. Map<Long, BigDecimal> availableQuantityMap = productStockInfoService.mapKV(ProductStockInfo::getId, ProductStockInfo::getAvailableQuantity, q -> q
  251. .in(ProductStockInfo::getProductId, materialIds)
  252. .eq(ProductStockInfo::getCompanyId, contract.getCompanyId())
  253. );
  254. //遍历物料列表
  255. for (ProductBomDetail productBomDetail : productBomDetails) {
  256. Long materialId = productBomDetail.getMaterialId();
  257. ProductInfo materialInfo = materialMap.get(materialId);
  258. BigDecimal multiply = productBomDetail.getQuantity().multiply(contractProduct.getQuantity());
  259. //获取产品安全库存
  260. BigDecimal stockThreshold = materialInfo.getStockThreshold();
  261. //获取可用库存
  262. BigDecimal availableQuantity = availableQuantityMap.getOrDefault(materialId, BigDecimal.ZERO);
  263. //计数需要采购的数量(需采购量 = 安全库存 - (可用库存 - 合同量)若 需采购量<0,则按0算不采购)
  264. BigDecimal subtract = availableQuantity.subtract(multiply);
  265. BigDecimal requiredQuantity = stockThreshold.subtract(subtract);
  266. //计算可用库存
  267. if (requiredQuantity.compareTo(BigDecimal.ZERO) < 0) {
  268. //需要采购的数量<0 可用库存 = 可用库存 - 合同量
  269. InOutBo inOutBo = new InOutBo();
  270. inOutBo.setProductId(materialId);
  271. inOutBo.setQuantity(multiply);
  272. productInfoService.editAvailableQuantity(Arrays.asList(inOutBo), InOutType.OUT, contractProduct.getId(), ProductAvailableRecordType.SALE_PASS, contract.getCompanyId());
  273. } else {
  274. //需要采购的数量>=0 可用库存 = 安全库存
  275. InOutBo inOutBo = new InOutBo();
  276. inOutBo.setProductId(materialId);
  277. inOutBo.setQuantity(stockThreshold);
  278. productInfoService.editAvailableQuantity(Arrays.asList(inOutBo), InOutType.EQ, contractProduct.getId(), ProductAvailableRecordType.SALE_PASS, contract.getCompanyId());
  279. }
  280. //需要采购的数量大于0生成待采购数据
  281. if (requiredQuantity.compareTo(BigDecimal.ZERO) > 0) {
  282. SubscribeDetail subscribeDetail = new SubscribeDetail();
  283. subscribeDetail.setProductId(materialId);
  284. subscribeDetail.setCount(requiredQuantity);
  285. subscribeDetail.setStatus(15);//待采购
  286. subscribeDetail.setContractId(contract.getId());
  287. subscribeDetail.setContractDetailId(contractProduct.getId());
  288. subscribeDetail.setDataType(1);
  289. subscribeDetailList.add(subscribeDetail);
  290. }
  291. }
  292. }
  293. }
  294. //根据归属公司将数据赋值给指定公司
  295. Long companyId = contract.getCompanyId();
  296. SysDept company = deptService.getById(companyId);
  297. if (ObjectUtil.isEmpty(companyId)) {
  298. throw new ServiceException("归属公司不存在");
  299. }
  300. //保存待采购明细
  301. subscribeDetailService.saveBatch(subscribeDetailList);
  302. }
  303. }