Merge remote-tracking branch 'origin/master'

This commit is contained in:
zjf committed 2025-07-04 19:54:37 +08:00
commit bb765bf459
15 files changed
+435 -39

No files matched your search

@@ -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<HardOrderMapper, HardOrder
public Long appCreateOrderScancode(HardAppCreateOrderDto dto) {
MchManageVo mch = remoteMchService.getById(dto.getMerchantId()).getData();
if (ObjectUtil.isEmpty(mch)) throw new RuntimeException("商户不存在");
// 判断商户合作状态
if (ObjectUtil.equals(mch.getTypes(), MerchantTypeEnum.SUPERMARKET.getType()) && ObjectUtil.equals(mch.getSupType(), WalletMchSupType.MCH.getCode())) {
if (ObjectUtil.equals(mch.getCooperationStatus(), YesNoEnum.NO.getCode())) {
throw new RuntimeException("改商家未合作");
}
}
// 查询用户
UserInfo userDetail = userService.getInnerByUserId(dto.getUserId()).getData();
if (ObjectUtil.isEmpty(userDetail)) throw new RuntimeException("用户不存在不存在");
@@ -92,28 +92,10 @@ public class SysDeptController {
*/
@GetMapping(value = "/tree")
public R getTree(String deptName, Long parentId) {
Long deptId = null;
try {
PjcloudUser user = SecurityUtils.getUser();
deptId = user.getDeptId();
} catch (Exception e) {
log.error("获取当前用户ID异常", e);
}
if (ObjectUtil.isEmpty(parentId)) {
parentId = deptId;
}
return R.ok(sysDeptService.selectTree(deptName, parentId, DataScope.of()));
PjcloudUser user = SecurityUtils.getUser();
return R.ok(sysDeptService.selectTree(deptName, parentId, user));
}
/**
* 返回树形菜单集合
*/
@GetMapping(value = "/tree-select")
public R getTreeSelect(String deptName, Long parentId) {
return R.ok(sysDeptService.selectTree(deptName, parentId, null));
}
/**
* 查询所有,无权限过滤
* simpleTree
@@ -27,6 +27,7 @@ import com.bsd.pjcloud.admin.api.vo.DeptExcelVO;
import com.bsd.pjcloud.admin.api.vo.OrgTreeVO;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.common.data.datascope.DataScope;
import com.bsd.pjcloud.common.security.service.PjcloudUser;
import jakarta.validation.Valid;
import org.springframework.validation.BindingResult;
@@ -49,7 +50,7 @@ public interface SysDeptService extends IService<SysDept> {
* @param deptName 部门名称
* @return 树
*/
List<Tree<Long>> selectTree(String deptName, Long parentId, DataScope dataScope);
List<Tree<Long>> selectTree(String deptName, Long parentId, PjcloudUser user);
List<Tree<Long>> selectSimpleTree(String deptName, Long parentId);
@@ -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<SysDeptMapper, SysDept> impl
* @return 树 部门名称
*/
@Override
public List<Tree<Long>> selectTree(String deptName, Long parentId, DataScope dataScope) {
List<SysDept> deptAllList = new ArrayList<>();
public List<Tree<Long>> selectTree(String deptName, Long parentId, PjcloudUser user) {
// 查询全部部门
LambdaQueryWrapper<SysDept> queryWrapper = Wrappers.<SysDept>lambdaQuery().like(StrUtil.isNotBlank(deptName), SysDept::getName, deptName);
deptAllList = deptMapper.selectListByScope(queryWrapper, dataScope);
List<SysDept> deptAllList = deptMapper.selectList(queryWrapper);
// 查询数据权限内部门
List<Long> deptOwnIdList = deptMapper
.selectListByScope(
@@ -159,6 +160,7 @@ public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> impl
// 有权限不返回标识
Map<String, Object> 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<SysDeptMapper, SysDept> 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<Long>> tree = TreeUtil.build(collect, parentId == null ? 0 : parentId);
if (ObjectUtil.isNotEmpty(tree)) {
if (ObjectUtil.isNotEmpty(user) && ObjectUtil.isNotEmpty(user.getDeptId())) {
for (Tree<Long> rootNode : tree) {
markDeptAndRelatedVisible(rootNode, user.getDeptId());
}
}
}
return TreeUtil.build(collect, parentId == null ? 0 : parentId);
return tree;
}
/**
* 如果都是在targetDeptId这树上的visible都为true
*/
private void markDeptAndRelatedVisible(Tree<Long> node, Long targetDeptId) {
boolean shouldMarkVisible = isTargetOrAncestor(node, targetDeptId) || hasChildMatching(node, targetDeptId);
if (shouldMarkVisible) {
node.put("visible", true);
}
if (node.getChildren() != null) {
for (Tree<Long> child : node.getChildren()) {
markDeptAndRelatedVisible(child, targetDeptId);
}
}
}
/**
* 判断当前节点是否是目标节点,或者其父节点链上包含目标节点
*/
private boolean isTargetOrAncestor(Tree<Long> node, Long targetDeptId) {
if (node.getId().equals(targetDeptId)) {
return true;
}
Tree<Long> parent = node.getParent();
while (parent != null) {
if (parent.getId().equals(targetDeptId)) {
return true;
}
parent = parent.getParent();
}
return false;
}
/**
* 检查该节点及其子节点中是否存在目标节点
*/
private boolean hasChildMatching(Tree<Long> node, Long targetDeptId) {
if (node.getChildren() == null) {
return false;
}
return node.getChildren().stream().anyMatch(child -> child.getId().equals(targetDeptId) || hasChildMatching(child, targetDeptId));
}
@Override
@@ -28,4 +28,13 @@ public class WalletRechargeBindInvoiceDto extends WalletRechargeInvoiceVo {
*/
private LocalDateTime[] createTimeList;
/**
* 申请时间
*/
private LocalDateTime[] applyTimeList;
/**
* 审核时间
*/
private LocalDateTime[] processTimeList;
}
@@ -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;
}
@@ -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<WalletRechargeInvoiceEnti
@Schema(description = "状态")
private String status;
/**
* 发票审核状态
*/
// @Schema(description = "发票审核状态")
// private String invoiceStatus;
/**
* 发票图片地址(不盖章)
*/
@Schema(description = "发票图片地址(不盖章)")
private String picUrl;
/**
* 发票图片地址(盖章)
*/
@Schema(description = "发票图片地址(盖章)")
private String stampPicUrl;
/**
* 流程id
*/
@Schema(description = "流程id")
private String processId;
/**
* 流程状态
*/
@Schema(description = "流程状态")
private String processStatus;
/**
* 申请时间
*/
@Schema(description = "申请时间")
private LocalDateTime applyTime;
/**
* 审核时间
*/
@Schema(description = "审核时间")
private LocalDateTime processTime;
/**
* 创建人
*/
@@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.common.data.datascope.DataScope;
import com.bsd.pjcloud.common.excel.annotation.RequestExcel;
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.flow.task.dto.ProcessNodeRecordAssignUserParamDto;
@@ -150,11 +151,13 @@ public class WalletRechargeApplyController {
}
@PostMapping("/read-excel")
@Idempotent(expireTime = 3, info = "正在上传中,请勿重复操作")
public R readExcel(@RequestExcel List<WalletRechargeExcelDto> 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<WalletRechargeExcelDto> excelVOList, BindingResult bindingResult) {
return walletRechargeApplyService.readTopupExcel(excelVOList, bindingResult);
}
@@ -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<WalletRechargeInvoiceVo> getInvoice(@RequestParam Long id) {
@@ -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<WalletRechargeInv
* 批量删除发票
*/
void delByIds(ArrayList<Long> list);
/**
* 发票申请回调
*/
void applyCallback(ProcessNodeRecordAssignUserParamDto dto, Long tenantId);
/**
* 发票申请
*/
void apply(@Valid WalletRechargeInvoiceApplyDto body);
/**
* 生成盖章图片
*/
String stamp(WalletRechargeInvoiceEntity invoice);
}
@@ -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<WalletRechargeInvoiceMapper, WalletRechargeInvoiceEntity> 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<WalletRecharge
if (ObjectUtil.isEmpty(detail)) throw new RuntimeException("查询不到发票");
baseMapper.update(new LambdaUpdateWrapper<WalletRechargeInvoiceEntity>()
.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<WalletRecharge
UserInfo userInfo = remoteUserService.getByUserId(detail.getApplyUserId()).getData();
throw new RuntimeException("用户<" + userInfo.getSysUser().getName() + ">创建的发票已经" + 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<WalletRecharge
return String.format("%07d", count);
}
/**
* 发票申请回调
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void applyCallback(ProcessNodeRecordAssignUserParamDto dto, Long tenantId) {
if (!flowUtil.checkCallback(dto)) {
return;
}
if (ObjectUtil.isNotEmpty(tenantId) && ObjectUtil.notEqual(tenantId, 1L)) {
TenantContextHolder.setTenantId(tenantId);
}
String processId = dto.getProcessInstanceId();
WalletRechargeInvoiceEntity detail = baseMapper.selectOne(new LambdaQueryWrapper<WalletRechargeInvoiceEntity>().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;
}
}
/**
* 绑定发票
*/
@@ -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;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 315 KiB

@@ -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 @@
<if test="dto.status != null">
and a.status = #{dto.status}
</if>
<if test="dto.processStatus != null and dto.processStatus != '' and dto.processStatus != 99 ">
and a.process_status = #{dto.processStatus}
</if>
<if test="dto.processStatus != null and dto.processStatus != '' and dto.processStatus == 99 ">
and a.process_id is null
</if>
<if test="dto.deptOrUser != null and dto.deptOrUser != '' ">
and a.dept_or_user like concat('%', #{dto.deptOrUser}, '%')
</if>
<if test="dto.userIds != null and dto.userIds.size() != 0">
and a.apply_user_id in
<foreach collection="dto.userIds" item="v" open="(" close=")" separator=",">
@@ -39,6 +53,12 @@
<if test="dto.createTimeList != null and dto.createTimeList.length == 2">
and a.create_time between #{dto.createTimeList[0]} and #{dto.createTimeList[1]}
</if>
<if test="dto.applyTimeList != null and dto.applyTimeList.length == 2">
and a.apply_time between #{dto.applyTimeList[0]} and #{dto.applyTimeList[1]}
</if>
<if test="dto.processTimeList != null and dto.processTimeList.length == 2">
and a.process_time between #{dto.processTimeList[0]} and #{dto.processTimeList[1]}
</if>
</sql>
<select id="selectAllCount" resultType="java.lang.Long">
@@ -0,0 +1,31 @@
package com.bsd.pjcloud;
import cn.hutool.core.util.ObjectUtil;
import com.bsd.pjcloud.wallet.WalletApp;
import com.bsd.pjcloud.wallet.api.entity.recharge.WalletRechargeInvoiceEntity;
import com.bsd.pjcloud.wallet.service.WalletRechargeInvoiceService;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;
/**
* @author liusiyang_dxm
* @since 2025/7/4
*/
@SpringBootTest(classes = WalletApp.class)
public class InvoiceTest {
@Resource
private WalletRechargeInvoiceService invoiceService;
@Test
@Transactional
public void test() {
WalletRechargeInvoiceEntity detail = invoiceService.getById(1937849346822692865L);
if (ObjectUtil.isNotEmpty(detail)) {
invoiceService.stamp(detail);
}
}
}