diff --git a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/impl/order/HardOrderServiceImpl.java b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/impl/order/HardOrderServiceImpl.java index f1b88c3e8..264151c03 100644 --- a/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/impl/order/HardOrderServiceImpl.java +++ b/pjcloud-hardware/pjcloud-hardware-biz/src/main/java/com/bsd/pjcloud/hard/service/impl/order/HardOrderServiceImpl.java @@ -61,6 +61,7 @@ import com.bsd.pjcloud.wallet.api.constant.WalletBizEnum; import com.bsd.pjcloud.wallet.api.constant.WalletCodeBizEnum; import com.bsd.pjcloud.wallet.api.constant.WalletTypeEnum; import com.bsd.pjcloud.wallet.api.constant.mch.WalletMchRulePriceTypeEnum; +import com.bsd.pjcloud.wallet.api.constant.mch.WalletMchSupType; import com.bsd.pjcloud.wallet.api.dto.WalletBalanceTransactionDto; import com.bsd.pjcloud.wallet.api.entity.WalletCodeUseEntity; import com.bsd.pjcloud.wallet.api.entity.WalletManageEntity; @@ -497,6 +498,12 @@ public class HardOrderServiceImpl extends ServiceImpl { * @param deptName 部门名称 * @return 树 */ - List> selectTree(String deptName, Long parentId, DataScope dataScope); + List> selectTree(String deptName, Long parentId, PjcloudUser user); List> selectSimpleTree(String deptName, Long parentId); diff --git a/pjcloud-upms/pjcloud-upms-biz/src/main/java/com/bsd/pjcloud/admin/service/impl/SysDeptServiceImpl.java b/pjcloud-upms/pjcloud-upms-biz/src/main/java/com/bsd/pjcloud/admin/service/impl/SysDeptServiceImpl.java index b6ec66f74..89eeaa548 100644 --- a/pjcloud-upms/pjcloud-upms-biz/src/main/java/com/bsd/pjcloud/admin/service/impl/SysDeptServiceImpl.java +++ b/pjcloud-upms/pjcloud-upms-biz/src/main/java/com/bsd/pjcloud/admin/service/impl/SysDeptServiceImpl.java @@ -42,6 +42,8 @@ import com.bsd.pjcloud.common.core.constant.enums.YesNoEnum; import com.bsd.pjcloud.common.core.util.R; import com.bsd.pjcloud.common.data.datascope.DataScope; import com.bsd.pjcloud.common.excel.vo.ErrorMessage; +import com.bsd.pjcloud.common.security.service.PjcloudUser; +import com.bsd.pjcloud.common.security.util.SecurityUtils; import com.bsd.pjcloud.wallet.api.feign.RemoteWalletService; import lombok.AllArgsConstructor; import org.springframework.beans.BeanUtils; @@ -132,11 +134,10 @@ public class SysDeptServiceImpl extends ServiceImpl impl * @return 树 部门名称 */ @Override - public List> selectTree(String deptName, Long parentId, DataScope dataScope) { - List deptAllList = new ArrayList<>(); + public List> selectTree(String deptName, Long parentId, PjcloudUser user) { // 查询全部部门 LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery().like(StrUtil.isNotBlank(deptName), SysDept::getName, deptName); - deptAllList = deptMapper.selectListByScope(queryWrapper, dataScope); + List deptAllList = deptMapper.selectList(queryWrapper); // 查询数据权限内部门 List deptOwnIdList = deptMapper .selectListByScope( @@ -159,6 +160,7 @@ public class SysDeptServiceImpl extends ServiceImpl impl // 有权限不返回标识 Map extra = new HashMap<>(8); extra.put("isLock", !deptOwnIdList.contains(dept.getDeptId())); + extra.put("visible", false); extra.put("createTime", dept.getCreateTime()); treeNode.setExtra(extra); return treeNode; @@ -174,13 +176,58 @@ public class SysDeptServiceImpl extends ServiceImpl impl return tree; }).collect(Collectors.toList()); } - if (ObjectUtil.isNotEmpty(parentId)) { - SysDept parentDept = getById(parentId); - if (ObjectUtil.isNotEmpty(parentDept) && ObjectUtil.isNotEmpty(parentDept.getParentId())) { - parentId = parentDept.getParentId(); + List> tree = TreeUtil.build(collect, parentId == null ? 0 : parentId); + if (ObjectUtil.isNotEmpty(tree)) { + if (ObjectUtil.isNotEmpty(user) && ObjectUtil.isNotEmpty(user.getDeptId())) { + for (Tree rootNode : tree) { + markDeptAndRelatedVisible(rootNode, user.getDeptId()); + } } } - return TreeUtil.build(collect, parentId == null ? 0 : parentId); + return tree; + } + + /** + * 如果都是在targetDeptId这树上的visible都为true + */ + private void markDeptAndRelatedVisible(Tree node, Long targetDeptId) { + boolean shouldMarkVisible = isTargetOrAncestor(node, targetDeptId) || hasChildMatching(node, targetDeptId); + if (shouldMarkVisible) { + node.put("visible", true); + } + if (node.getChildren() != null) { + for (Tree child : node.getChildren()) { + markDeptAndRelatedVisible(child, targetDeptId); + } + } + } + + + /** + * 判断当前节点是否是目标节点,或者其父节点链上包含目标节点 + */ + private boolean isTargetOrAncestor(Tree node, Long targetDeptId) { + if (node.getId().equals(targetDeptId)) { + return true; + } + Tree parent = node.getParent(); + while (parent != null) { + if (parent.getId().equals(targetDeptId)) { + return true; + } + parent = parent.getParent(); + } + return false; + } + + /** + * 检查该节点及其子节点中是否存在目标节点 + */ + private boolean hasChildMatching(Tree node, Long targetDeptId) { + if (node.getChildren() == null) { + return false; + } + return node.getChildren().stream().anyMatch(child -> child.getId().equals(targetDeptId) || hasChildMatching(child, targetDeptId)); } @Override diff --git a/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/recharge/WalletRechargeBindInvoiceDto.java b/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/recharge/WalletRechargeBindInvoiceDto.java index f2b35c5b9..c404f150f 100644 --- a/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/recharge/WalletRechargeBindInvoiceDto.java +++ b/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/recharge/WalletRechargeBindInvoiceDto.java @@ -28,4 +28,13 @@ public class WalletRechargeBindInvoiceDto extends WalletRechargeInvoiceVo { */ private LocalDateTime[] createTimeList; + /** + * 申请时间 + */ + private LocalDateTime[] applyTimeList; + + /** + * 审核时间 + */ + private LocalDateTime[] processTimeList; } diff --git a/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/recharge/WalletRechargeInvoiceApplyDto.java b/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/recharge/WalletRechargeInvoiceApplyDto.java new file mode 100644 index 000000000..c6d339d9a --- /dev/null +++ b/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/dto/recharge/WalletRechargeInvoiceApplyDto.java @@ -0,0 +1,15 @@ +package com.bsd.pjcloud.wallet.api.dto.recharge; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Data +public class WalletRechargeInvoiceApplyDto { + + @NotNull(message = "发票id不能为空") + private Long id; + + @NotNull(message = "发票图片不能为空") + private String picUrl; + +} diff --git a/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/entity/recharge/WalletRechargeInvoiceEntity.java b/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/entity/recharge/WalletRechargeInvoiceEntity.java index 4d0fefd53..865933303 100644 --- a/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/entity/recharge/WalletRechargeInvoiceEntity.java +++ b/pjcloud-wallet/pjcloud-wallet-api/src/main/java/com/bsd/pjcloud/wallet/api/entity/recharge/WalletRechargeInvoiceEntity.java @@ -3,8 +3,7 @@ package com.bsd.pjcloud.wallet.api.entity.recharge; import com.baomidou.mybatisplus.annotation.*; import com.baomidou.mybatisplus.extension.activerecord.Model; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; +import lombok.*; import com.bsd.pjcloud.common.core.util.TenantTable; import java.time.LocalDateTime; @@ -12,6 +11,9 @@ import java.time.LocalDateTime; /** * 充值/扣款申请发票记录 */ +@Builder +@AllArgsConstructor +@NoArgsConstructor @Data @TenantTable @TableName("wallet_recharge_invoice") @@ -99,18 +101,42 @@ public class WalletRechargeInvoiceEntity extends Model excelVOList, BindingResult bindingResult, @RequestParam(required = false) String bizType) { return walletRechargeApplyService.readExcel(excelVOList, bindingResult, bizType); } @PostMapping("/read-topup-excel") + @Idempotent(expireTime = 3, info = "正在上传中,请勿重复操作") public R readTopupExcel(@RequestExcel List excelVOList, BindingResult bindingResult) { return walletRechargeApplyService.readTopupExcel(excelVOList, bindingResult); } diff --git a/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/controller/recharge/WalletRechargeInvoiceController.java b/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/controller/recharge/WalletRechargeInvoiceController.java index 04adc6bf4..170280e3a 100644 --- a/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/controller/recharge/WalletRechargeInvoiceController.java +++ b/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/controller/recharge/WalletRechargeInvoiceController.java @@ -4,10 +4,17 @@ import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.bsd.pjcloud.admin.api.entity.SysUser; import com.bsd.pjcloud.common.core.util.R; import com.bsd.pjcloud.common.data.datascope.DataScope; +import com.bsd.pjcloud.common.idempotent.annotation.Idempotent; import com.bsd.pjcloud.common.log.annotation.SysLog; +import com.bsd.pjcloud.common.security.annotation.Inner; +import com.bsd.pjcloud.common.security.service.PjcloudUser; +import com.bsd.pjcloud.common.security.util.SecurityUtils; +import com.bsd.pjcloud.flow.task.dto.ProcessNodeRecordAssignUserParamDto; import com.bsd.pjcloud.wallet.api.dto.recharge.WalletRechargeBindInvoiceDto; +import com.bsd.pjcloud.wallet.api.dto.recharge.WalletRechargeInvoiceApplyDto; import com.bsd.pjcloud.wallet.api.entity.recharge.WalletRechargeInvoiceEntity; import com.bsd.pjcloud.wallet.api.vo.recharge.WalletRechargeInvoiceVo; import com.bsd.pjcloud.wallet.service.WalletRechargeInvoiceService; @@ -36,6 +43,25 @@ public class WalletRechargeInvoiceController { private final WalletRechargeInvoiceService walletRechargeInvoiceService; + /* ************************************* start callback start ************************************* */ + @Inner(value = false) + @PostMapping("/apply-callback") + public void applyCallback(@RequestBody ProcessNodeRecordAssignUserParamDto dto, @RequestParam(required = false) Long tenantId) { + walletRechargeInvoiceService.applyCallback(dto, tenantId); + } + /* ************************************* start callback start ************************************* */ + + + @Operation(summary = "提交申请", description = "提交申请") + @SysLog("提交申请") + @PostMapping("/apply") + @Idempotent(expireTime = 3, info = "正在申请中,请勿重复操作") + public R apply(@Valid @RequestBody WalletRechargeInvoiceApplyDto body) { + walletRechargeInvoiceService.apply(body); + return R.ok(true); + } + + @GetMapping("/get-invoice") @Operation(summary = "批量充值/扣款发票信息") public R getInvoice(@RequestParam Long id) { diff --git a/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/service/WalletRechargeInvoiceService.java b/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/service/WalletRechargeInvoiceService.java index 4073883ad..43b5155ae 100644 --- a/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/service/WalletRechargeInvoiceService.java +++ b/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/service/WalletRechargeInvoiceService.java @@ -4,7 +4,9 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; import com.bsd.pjcloud.common.data.datascope.DataScope; import com.bsd.pjcloud.common.security.service.PjcloudUser; +import com.bsd.pjcloud.flow.task.dto.ProcessNodeRecordAssignUserParamDto; import com.bsd.pjcloud.wallet.api.dto.recharge.WalletRechargeBindInvoiceDto; +import com.bsd.pjcloud.wallet.api.dto.recharge.WalletRechargeInvoiceApplyDto; import com.bsd.pjcloud.wallet.api.entity.recharge.WalletRechargeInvoiceEntity; import com.bsd.pjcloud.wallet.api.vo.recharge.WalletRechargeInvoiceVo; import jakarta.validation.Valid; @@ -57,4 +59,19 @@ public interface WalletRechargeInvoiceService extends IService list); + + /** + * 发票申请回调 + */ + void applyCallback(ProcessNodeRecordAssignUserParamDto dto, Long tenantId); + + /** + * 发票申请 + */ + void apply(@Valid WalletRechargeInvoiceApplyDto body); + + /** + * 生成盖章图片 + */ + String stamp(WalletRechargeInvoiceEntity invoice); } \ No newline at end of file diff --git a/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/service/impl/recharge/WalletRechargeInvoiceServiceImpl.java b/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/service/impl/recharge/WalletRechargeInvoiceServiceImpl.java index 2c8b711ba..9e4e07027 100644 --- a/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/service/impl/recharge/WalletRechargeInvoiceServiceImpl.java +++ b/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/service/impl/recharge/WalletRechargeInvoiceServiceImpl.java @@ -1,20 +1,34 @@ package com.bsd.pjcloud.wallet.service.impl.recharge; import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.json.JSONUtil; +import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.bsd.pjcloud.admin.api.dto.UserInfo; +import com.bsd.pjcloud.admin.api.entity.SysDept; +import com.bsd.pjcloud.admin.api.feign.RemoteDeptService; +import com.bsd.pjcloud.admin.api.feign.RemoteFileService; import com.bsd.pjcloud.admin.api.feign.RemoteUserService; +import com.bsd.pjcloud.common.core.util.R; import com.bsd.pjcloud.common.data.datascope.DataScope; +import com.bsd.pjcloud.common.data.resolver.ParamResolver; +import com.bsd.pjcloud.common.data.tenant.TenantContextHolder; import com.bsd.pjcloud.common.security.service.PjcloudUser; +import com.bsd.pjcloud.flow.task.api.feign.RemoteFlowEngineService; import com.bsd.pjcloud.flow.task.constant.TaskCheckStatusEnum; +import com.bsd.pjcloud.flow.task.dto.ProcessNodeRecordAssignUserParamDto; +import com.bsd.pjcloud.flow.task.dto.TaskParamDto; import com.bsd.pjcloud.wallet.api.constant.WalletBizRechargeEnum; import com.bsd.pjcloud.wallet.api.constant.WalletRechargeInvoiceStatusEnum; import com.bsd.pjcloud.wallet.api.dto.recharge.WalletRechargeBindInvoiceDto; +import com.bsd.pjcloud.wallet.api.dto.recharge.WalletRechargeInvoiceApplyDto; import com.bsd.pjcloud.wallet.api.entity.recharge.WalletRechargeApplyEntity; import com.bsd.pjcloud.wallet.api.entity.recharge.WalletRechargeImportEntity; import com.bsd.pjcloud.wallet.api.entity.recharge.WalletRechargeInvoiceEntity; @@ -27,27 +41,49 @@ import com.bsd.pjcloud.wallet.mapper.recharge.WalletRechargeImportMapper; import com.bsd.pjcloud.wallet.mapper.recharge.WalletRechargeInvoiceMapper; import com.bsd.pjcloud.wallet.service.WalletRechargeInvoiceService; import com.bsd.pjcloud.wallet.utils.ConvertCnPriceUtil; -import lombok.AllArgsConstructor; -import org.springframework.stereotype.Service; +import com.bsd.pjcloud.wallet.utils.flow.FlowUtil; +import com.bsd.pjcloud.wallet.utils.flow.dto.WalletRechargeInvoiceFlowDto; +import org.springframework.mock.web.MockMultipartFile; import org.springframework.transaction.annotation.Transactional; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; import java.math.BigDecimal; import java.math.RoundingMode; +import java.net.URL; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; +import java.util.Map; /** * 充值/扣款申请发票记录 */ +@Slf4j @Service @AllArgsConstructor public class WalletRechargeInvoiceServiceImpl extends ServiceImpl implements WalletRechargeInvoiceService { + static private final String TAG = "充值/扣款发票"; + + private final FlowUtil flowUtil; + private final WalletRechargeImportMapper importMapper; private final WalletRechargeApplyMapper applyMapper; private final RemoteUserService remoteUserService; + private final RemoteDeptService remoteDeptService; + private final RemoteFileService remoteFileService; + private final RemoteFlowEngineService flowEngineService; private final RemoteWalletSettingService remoteWalletSettingService; /** @@ -59,6 +95,11 @@ public class WalletRechargeInvoiceServiceImpl extends ServiceImpl() .set(WalletRechargeInvoiceEntity::getPicUrl, null) + .set(WalletRechargeInvoiceEntity::getApplyTime, null) + .set(WalletRechargeInvoiceEntity::getProcessId, null) + .set(WalletRechargeInvoiceEntity::getProcessStatus, null) + .set(WalletRechargeInvoiceEntity::getProcessTime, null) + .set(WalletRechargeInvoiceEntity::getStampPicUrl, null) .eq(WalletRechargeInvoiceEntity::getId, id) ); } @@ -222,6 +263,12 @@ public class WalletRechargeInvoiceServiceImpl extends ServiceImpl创建的发票已经" + WalletRechargeInvoiceStatusEnum.codeOf(detail.getStatus()).getDesc() + "不能删除"); } + // 如果是审批中就取消审批 + if (ObjectUtil.equals(detail.getProcessStatus(), TaskCheckStatusEnum.PADDING.getCode())) { + TaskParamDto dto = new TaskParamDto(); + dto.setProcessInstanceIdList(List.of(detail.getProcessId())); + flowEngineService.stopProcessInstance(dto).getData(); + } // 删除申请记录 baseMapper.deleteById(v); // 删除申请记录条目 @@ -239,6 +286,147 @@ public class WalletRechargeInvoiceServiceImpl extends ServiceImpl().eq(WalletRechargeInvoiceEntity::getProcessId, processId)); + if (ObjectUtil.isEmpty(detail)) { + return; + } + if (!ObjectUtil.equals(detail.getProcessStatus(), TaskCheckStatusEnum.PADDING.getCode())) { + log.error("|{}|重复的回调,dto:|{}|", TAG, JSON.toJSONString(dto)); + return; + } + try { + Boolean isConsent = flowUtil.isConsent(dto); + String processStatus = isConsent ? TaskCheckStatusEnum.RESULT.getCode() : TaskCheckStatusEnum.REJECT.getCode(); + baseMapper.updateById(WalletRechargeInvoiceEntity.builder().id(detail.getId()).processTime(LocalDateTime.now()).processStatus(processStatus).build()); + + if (isConsent) { + // 盖章 + String stampPicUrl = stamp(detail); + if (ObjectUtil.isNotEmpty(stampPicUrl)) { + // 更新盖章图片 + baseMapper.updateById(WalletRechargeInvoiceEntity.builder().id(detail.getId()).stampPicUrl(stampPicUrl).build()); + } + } + } catch (Exception e) { + e.printStackTrace(); + log.error("|{}|审批回调意外的错误,dto:|{}|error:|{}|", TAG, JSON.toJSONString(dto), e.getMessage()); + throw new RuntimeException(e); + } + } + + /** + * 发票申请 + */ + @Override + public void apply(WalletRechargeInvoiceApplyDto body) { + // 查询详情 + WalletRechargeInvoiceEntity detail = baseMapper.selectById(body.getId()); + if (ObjectUtil.isEmpty(detail)) { + throw new RuntimeException("发票申请不存在"); + } + // 查询用户 + UserInfo user = remoteUserService.getInnerByUserId(detail.getApplyUserId()).getData(); + if (ObjectUtil.isEmpty(user)) { + throw new RuntimeException("申请人不存在"); + } + // 查询部门 + SysDept dept = remoteDeptService.getDeptByDeptId(detail.getApplyDeptId()).getData(); + if (ObjectUtil.isEmpty(dept)) { + throw new RuntimeException("发起人部门不存在"); + } + // 发起审批 + WalletRechargeInvoiceFlowDto flowDto = new WalletRechargeInvoiceFlowDto(); + flowDto.setApplyUsername(user.getSysUser().getUsername()); + flowDto.setApplyUserId(user.getSysUser().getUserId()); + flowDto.setApplyDeptName(dept.getName()); + flowDto.setApplyDeptId(dept.getDeptId()); + flowDto.setApplyCreateTime(LocalDateTimeUtil.format(detail.getCreateTime(), DatePattern.NORM_DATETIME_PATTERN)); + flowDto.setPrice((double) (detail.getTotalPrice() / 100)); + flowDto.setDeptOrUser(detail.getDeptOrUser()); + flowDto.setRemark(detail.getRemark()); + String processId = flowUtil.startFlow("TASK_RECHARGE_APPLY_INVOICE_FLOW", user.getSysUser(), detail.getId(), flowDto); + // 更新 + WalletRechargeInvoiceEntity updateObj = new WalletRechargeInvoiceEntity(); + updateObj.setId(detail.getId()); + updateObj.setProcessId(processId); + updateObj.setApplyTime(LocalDateTime.now()); + updateObj.setProcessStatus(TaskCheckStatusEnum.PADDING.getCode()); + updateObj.setPicUrl(body.getPicUrl()); + baseMapper.updateById(updateObj); + } + + /** + * 生成盖章图片 + */ + @Override + public String stamp(WalletRechargeInvoiceEntity invoice) { + // 查看有没有盖章 + if (ObjectUtil.isEmpty(invoice)) { + log.error("|{}|盖章失败,发票查询为空,invoice:|{}|", TAG, JSONUtil.toJsonStr(invoice)); + return null; + } + // 审核成功才能开发票 + if (ObjectUtil.notEqual(invoice.getProcessStatus(), TaskCheckStatusEnum.RESULT.getCode()) && false) { + log.error("|{}|盖章失败,审核成功才能开发票,invoice:|{}|", TAG, JSONUtil.toJsonStr(invoice)); + return null; + } + String imageBaseUrl = ParamResolver.getStr("IMAGE_BASE_URL"); + if (ObjectUtil.isEmpty(imageBaseUrl)) { + throw new RuntimeException("请配置图片基础路径"); + } + // 开始盖章 + String picUrl = String.format("%s%s", imageBaseUrl, invoice.getPicUrl()); + File receiptStamp = FileUtil.file("image/receiptStamp.png"); + // 发票底图宽高 3969 x 2154 + int baseMapWidth = 3969, baseMapHeight = 2154; + // 盖章图片宽高 + int stampOrgWidth = 600, stampOrgHeight = 600; + int stampWidth = 500, stampHeight = 500; + try { + // 读取底图 + BufferedImage baseImage = ImageIO.read(new URL(picUrl)); + // 读取盖章图片 + BufferedImage stampImage = ImageIO.read(receiptStamp); + stampImage.getScaledInstance(stampWidth, stampHeight, Image.SCALE_SMOOTH); + // 创建新的图像上下文 + Graphics2D g2d = baseImage.createGraphics(); + // 设置抗锯齿 + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + int x = (int) (stampWidth + baseMapWidth * 0.15 + 80); + int y = baseMapHeight - stampHeight - 50; + g2d.drawImage(stampImage, x, y, stampWidth, stampHeight, null); + g2d.dispose(); + String newPicUrl = invoice.getPicUrl().replaceFirst("(\\.\\w+)$", "_stamped$1"); + File tempFile = File.createTempFile(newPicUrl, ".png"); + ImageIO.write(baseImage, "PNG", tempFile); + // 保存到本地用于测试 + // ImageIO.write(baseImage, "PNG", new File("test.png")); + + // 上传图片 + MultipartFile multipartFile = new MockMultipartFile("file", newPicUrl, "image/png", new FileInputStream(tempFile)); + R upload = remoteFileService.innerUpload(multipartFile, null, null, null); + Map data = (Map) upload.getData(); + String url = (String) data.get("url"); + return url; + } catch (IOException e) { + log.error("|{}|盖章失败,IO异常,invoice:|{}|error:|{}|", TAG, JSONUtil.toJsonStr(invoice), e.getMessage()); + return null; + } + } + /** * 绑定发票 */ diff --git a/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/utils/flow/dto/WalletRechargeInvoiceFlowDto.java b/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/utils/flow/dto/WalletRechargeInvoiceFlowDto.java new file mode 100644 index 000000000..bc2abd893 --- /dev/null +++ b/pjcloud-wallet/pjcloud-wallet-biz/src/main/java/com/bsd/pjcloud/wallet/utils/flow/dto/WalletRechargeInvoiceFlowDto.java @@ -0,0 +1,24 @@ +package com.bsd.pjcloud.wallet.utils.flow.dto; + +import com.bsd.pjcloud.flow.task.dto.base.FlowBaseDto; +import lombok.Data; + +@Data +public class WalletRechargeInvoiceFlowDto extends FlowBaseDto { + + /** + * 交款单位或个人 + */ + private String deptOrUser; + + /** + * 金额 + */ + private Double price; + + /** + * 备注 + */ + private String remark; + +} diff --git a/pjcloud-wallet/pjcloud-wallet-biz/src/main/resources/image/receiptStamp.png b/pjcloud-wallet/pjcloud-wallet-biz/src/main/resources/image/receiptStamp.png new file mode 100644 index 000000000..6c15885a0 Binary files /dev/null and b/pjcloud-wallet/pjcloud-wallet-biz/src/main/resources/image/receiptStamp.png differ diff --git a/pjcloud-wallet/pjcloud-wallet-biz/src/main/resources/mapper/recharge/WalletRechargeInvoiceMapper.xml b/pjcloud-wallet/pjcloud-wallet-biz/src/main/resources/mapper/recharge/WalletRechargeInvoiceMapper.xml index 0ca287a8e..6cd870bcd 100644 --- a/pjcloud-wallet/pjcloud-wallet-biz/src/main/resources/mapper/recharge/WalletRechargeInvoiceMapper.xml +++ b/pjcloud-wallet/pjcloud-wallet-biz/src/main/resources/mapper/recharge/WalletRechargeInvoiceMapper.xml @@ -17,6 +17,11 @@ a.remark, a.status, a.pic_url, + a.stamp_pic_url, + a.process_id, + a.process_status, + a.apply_time, + a.process_time, a.create_by, a.create_time, a.update_by, @@ -30,6 +35,15 @@ and a.status = #{dto.status} + + and a.process_status = #{dto.processStatus} + + + and a.process_id is null + + + and a.dept_or_user like concat('%', #{dto.deptOrUser}, '%') + and a.apply_user_id in @@ -39,6 +53,12 @@ and a.create_time between #{dto.createTimeList[0]} and #{dto.createTimeList[1]} + + and a.apply_time between #{dto.applyTimeList[0]} and #{dto.applyTimeList[1]} + + + and a.process_time between #{dto.processTimeList[0]} and #{dto.processTimeList[1]} +