1、移除无用post岗位代码;2、发票管理单元测试完善,优惠活动单测覆盖率异常修复;

This commit is contained in:
gaoqr
2025-12-16 16:27:25 +08:00
parent bdeb0366f9
commit 010678724d
19 changed files with 1310 additions and 274 deletions
@@ -21,4 +21,6 @@ public @interface WithMockLoginUser {
long deptId() default 0L;
boolean isSuperAdmin() default false;
long organId() default 0L;
}
@@ -2,6 +2,7 @@ package com.cf.imes.framework.security.test;
import cn.hutool.core.util.RandomUtil;
import com.cf.imes.framework.security.core.LoginUser;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
@@ -23,10 +24,13 @@ public class WithMockLoginUserSecurityContextFactory implements WithSecurityCont
LoginUser loginUser = new LoginUser();
long annotationUserId = annotation.userId();
long annotationOrganId = annotation.organId();
String username = annotation.username();
loginUser.setId(annotationUserId == 0L ? RandomUtil.randomLong() : annotationUserId);
loginUser.setNickname(RandomUtil.randomString(10));
loginUser.setNickname(StringUtils.isNotEmpty(username) ? username : RandomUtil.randomString(10));
loginUser.setDeptId(RandomUtil.randomLong());
loginUser.setOrganId(RandomUtil.randomLong());
loginUser.setOrganId(annotationOrganId == 0L ? RandomUtil.randomLong() : annotationOrganId);
loginUser.setIsSupAdmin(annotation.isSuperAdmin());
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
@@ -28,6 +28,8 @@ import java.util.stream.Stream;
* @author 晨丰科技
*/
public class RandomUtils {
private RandomUtils() {
}
private static final int RANDOM_STRING_LENGTH = 10;
@@ -51,7 +53,7 @@ public class RandomUtils {
}
// 如果是 type、status 结尾的字段,返回 tinyint 范围
if (CharSequenceUtil.endWithAnyIgnoreCase(attributeMetadata.getAttributeName(),
"type", "status", "category", "scope", "result", "sort", "unit")) {
"type", "status", "category", "scope", "result", "sort", "unit", "currency")) {
return RandomUtil.randomInt(0, TINYINT_MAX + 1);
}
return RandomUtil.randomInt();
@@ -142,8 +144,7 @@ public class RandomUtils {
@SafeVarargs
public static <T> List<T> randomPojoList(Class<T> clazz, Consumer<T>... consumers) {
int size = RandomUtil.randomInt(1, RANDOM_COLLECTION_LENGTH);
return Stream.iterate(0, i -> i).limit(size).map(o -> randomPojo(clazz, consumers))
.collect(Collectors.toList());
return Stream.iterate(0, i -> i).limit(size).map(o -> randomPojo(clazz, consumers)).toList();
}
}
@@ -61,7 +61,7 @@ public class UserProfileController {
DeptDO dept = user.getDeptId() != null ? deptService.getDept(user.getDeptId()) : null;
// 获得社交用户信息
List<SocialUserDO> socialUsers = socialService.getSocialUserList(user.getId(), UserTypeEnum.ADMIN.getValue());
return success(UserConvert.INSTANCE.convert(user, userRoles, dept, null, socialUsers));
return success(UserConvert.INSTANCE.convert(user, userRoles, dept, socialUsers));
}
@PutMapping("/update")
@@ -10,7 +10,6 @@ import com.cf.imes.module.system.controller.admin.user.vo.user.UserExportRespVO;
import com.cf.imes.module.system.controller.admin.user.vo.user.UserRespVO;
import com.cf.imes.module.system.controller.admin.user.vo.user.UserSimpleRespVO;
import com.cf.imes.module.system.dal.dataobject.dept.DeptDO;
import com.cf.imes.module.system.dal.dataobject.dept.PostDO;
import com.cf.imes.module.system.dal.dataobject.permission.RoleDO;
import com.cf.imes.module.system.dal.dataobject.social.SocialUserDO;
import com.cf.imes.module.system.dal.dataobject.user.AdminUserDO;
@@ -59,11 +58,10 @@ public interface UserConvert {
}
default UserProfileRespVO convert(AdminUserDO user, List<RoleDO> userRoles,
DeptDO dept, List<PostDO> posts, List<SocialUserDO> socialUsers) {
DeptDO dept, List<SocialUserDO> socialUsers) {
UserProfileRespVO userVO = BeanUtils.toBean(user, UserProfileRespVO.class);
userVO.setRoles(BeanUtils.toBean(userRoles, RoleSimpleRespVO.class));
userVO.setDept(BeanUtils.toBean(dept, DeptSimpleRespVO.class));
// userVO.setPosts(BeanUtils.toBean(posts, PostSimpleRespVO.class));
userVO.setSocialUsers(BeanUtils.toBean(socialUsers, UserProfileRespVO.SocialUser.class));
return userVO;
}
@@ -1,51 +0,0 @@
package com.cf.imes.module.system.dal.dataobject.dept;
import com.cf.imes.framework.common.enums.CommonStatusEnum;
import com.cf.imes.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.cf.imes.framework.organ.core.db.OrganBaseDO;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 岗位表
*
* @author ruoyi
*/
@TableName("system_post")
@KeySequence("system_post_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
public class PostDO extends OrganBaseDO {
/**
* 岗位序号
*/
@TableId
private Long id;
/**
* 岗位名称
*/
private String name;
/**
* 岗位编码
*/
private String code;
/**
* 岗位排序
*/
private Integer sort;
/**
* 状态
*
* 枚举 {@link CommonStatusEnum}
*/
private Integer status;
/**
* 备注
*/
private String remark;
}
@@ -1,40 +0,0 @@
package com.cf.imes.module.system.dal.dataobject.dept;
import com.cf.imes.framework.mybatis.core.dataobject.BaseDO;
import com.cf.imes.module.system.dal.dataobject.user.AdminUserDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 用户和岗位关联
*
* @author ruoyi
*/
@TableName("system_user_post")
@KeySequence("system_user_post_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
public class UserPostDO extends BaseDO {
/**
* 自增主键
*/
@TableId
private Long id;
/**
* 用户 ID
*
* 关联 {@link AdminUserDO#getId()}
*/
private Long userId;
/**
* 角色 ID
*
* 关联 {@link PostDO#getId()}
*/
private Long postId;
}
@@ -1,82 +0,0 @@
package com.cf.imes.module.system.dal.mysql.dept;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.mybatis.core.mapper.BaseMapperX;
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cf.imes.framework.organ.core.context.OrganContextHolder;
import com.cf.imes.framework.security.core.LoginUser;
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
import com.cf.imes.module.system.controller.admin.dept.vo.post.PostPageReqVO;
import com.cf.imes.module.system.dal.dataobject.dept.PostDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
@Mapper
public interface PostMapper extends BaseMapperX<PostDO> {
default List<PostDO> selectList(Collection<Long> ids, Collection<Integer> statuses, Long organId) {
return selectList(new LambdaQueryWrapperX<PostDO>()
.eqIfPresent(PostDO::getOrganId, organId)
.inIfPresent(PostDO::getId, ids)
.inIfPresent(PostDO::getStatus, statuses));
}
default PageResult<PostDO> selectPage(PostPageReqVO reqVO) {
LambdaQueryWrapperX<PostDO> lambdaQueryWrapperX = new LambdaQueryWrapperX<>();
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
assert loginUser != null;
Boolean isSupAdmin = loginUser.getIsSupAdmin();
if(isSupAdmin && !Objects.isNull(reqVO.getOrganId())) {
lambdaQueryWrapperX.eqIfPresent(PostDO::getOrganId, reqVO.getOrganId());
}else{
lambdaQueryWrapperX.eqIfPresent(PostDO::getOrganId, loginUser.getOrganId());
}
lambdaQueryWrapperX.likeIfPresent(PostDO::getCode, reqVO.getCode())
.likeIfPresent(PostDO::getName, reqVO.getName())
.eqIfPresent(PostDO::getStatus, reqVO.getStatus());
if (reqVO.getOrder() == null) {
lambdaQueryWrapperX.orderByDesc(PostDO::getSort);
} else {
if (reqVO.getOrder().equals("ascend")) {
switch (reqVO.getField()) {
case "name" -> lambdaQueryWrapperX.orderByAsc(PostDO::getName);
case "code" -> lambdaQueryWrapperX.orderByAsc(PostDO::getCode);
case "sort" -> lambdaQueryWrapperX.orderByAsc(PostDO::getSort);
case "status" -> lambdaQueryWrapperX.orderByAsc(PostDO::getStatus);
case "create_time" -> lambdaQueryWrapperX.orderByAsc(PostDO::getCreateTime);
default -> {
// default不排序
}
}
} else if (reqVO.getOrder().equals("descend")) {
switch (reqVO.getField()) {
case "name" -> lambdaQueryWrapperX.orderByDesc(PostDO::getName);
case "code" -> lambdaQueryWrapperX.orderByDesc(PostDO::getCode);
case "sort" -> lambdaQueryWrapperX.orderByDesc(PostDO::getSort);
case "status" -> lambdaQueryWrapperX.orderByDesc(PostDO::getStatus);
case "create_time" -> lambdaQueryWrapperX.orderByDesc(PostDO::getCreateTime);
default -> {
// default不排序
}
}
}
}
return selectPage(reqVO, lambdaQueryWrapperX);
}
default PostDO selectByName(String name) {
return selectOne(PostDO::getName, name, PostDO::getOrganId, OrganContextHolder.getOrganId());
}
default PostDO selectByCode(String code) {
return selectOne(PostDO::getCode, code, PostDO::getOrganId, OrganContextHolder.getOrganId());
}
}
@@ -1,32 +0,0 @@
package com.cf.imes.module.system.dal.mysql.dept;
import com.cf.imes.framework.mybatis.core.mapper.BaseMapperX;
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cf.imes.module.system.dal.dataobject.dept.UserPostDO;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.apache.ibatis.annotations.Mapper;
import java.util.Collection;
import java.util.List;
@Mapper
public interface UserPostMapper extends BaseMapperX<UserPostDO> {
default List<UserPostDO> selectListByUserId(Long userId) {
return selectList(UserPostDO::getUserId, userId);
}
default void deleteByUserIdAndPostId(Long userId, Collection<Long> postIds) {
delete(new LambdaQueryWrapperX<UserPostDO>()
.eq(UserPostDO::getUserId, userId)
.in(UserPostDO::getPostId, postIds));
}
default List<UserPostDO> selectListByPostIds(Collection<Long> postIds) {
return selectList(UserPostDO::getPostId, postIds);
}
default void deleteByUserId(Long userId) {
delete(Wrappers.lambdaUpdate(UserPostDO.class).eq(UserPostDO::getUserId, userId));
}
}
@@ -2,7 +2,6 @@ package com.cf.imes.module.system.service.funds.incomeandexpense;
import com.cf.imes.module.system.dal.dataobject.incomeandexpense.IncomeExpenseDetailsDO;
import com.cf.imes.module.system.dal.mysql.incomeandexpense.IncomeExpenseDetailsMapper;
import com.cf.imes.module.system.service.organ.OrganService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
@@ -17,9 +16,6 @@ public class IncomeExpenseServiceImpl implements IncomeExpenseService {
@Resource
private IncomeExpenseDetailsMapper incomeExpenseDetailsMapper;
@Resource
private OrganService organService;
@Override
public Long createDetail(IncomeExpenseDetailsDO incomeExpenseDetailsDO) {
incomeExpenseDetailsMapper.insert(incomeExpenseDetailsDO);
@@ -7,7 +7,6 @@ import cn.hutool.core.util.ObjectUtil;
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.core.toolkit.ObjectUtils;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.exception.enums.GlobalErrorCodeConstants;
import com.cf.imes.framework.common.pojo.PageResult;
@@ -220,11 +219,12 @@ public class InvoiceServiceImpl implements InvoiceService {
@Override
@Transactional(rollbackFor = Exception.class)
public void applyInvoice(InvoiceRecordsReqVO reqVO) {
Long organId = SecurityFrameworkUtils.getUserOrganId();
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
if (loginUser == null) {
throw new ServiceException(GlobalErrorCodeConstants.UNAUTHORIZED);
}
Long organId = loginUser.getOrganId();
List<Long> purchaseRecordId = reqVO.getPurchaseRecordId();
// 查询发票抬头
InvoiceTitleInfoDO invoiceTitleInfoDO = invoiceTitleInfoMapper.selectOne(new LambdaQueryWrapper<InvoiceTitleInfoDO>()
@@ -240,7 +240,7 @@ public class InvoiceServiceImpl implements InvoiceService {
// 查询可开票金额:余额支付+扫码支付
BigDecimal invoicableAmount = purchaseRecordMapper.getInvoicableAmount(organId, purchaseRecordId);
// 可开票金额不能为0
AssertUtils.isTrue(ObjectUtils.isNull(invoicableAmount) || invoicableAmount.compareTo(BigDecimal.ZERO) == 0, INVOICE_AMOUNT_ZERO_ERROR);
AssertUtils.isTrue(invoicableAmount.compareTo(BigDecimal.ZERO) == 0, INVOICE_AMOUNT_ZERO_ERROR);
// 更新购买记录表的发票状态
int update = purchaseRecordMapper.update(new LambdaUpdateWrapper<PurchaseRecordDO>()
@@ -300,17 +300,15 @@ public class InvoiceServiceImpl implements InvoiceService {
.in(PurchaseRecordDO::getId, purchaseIdList));
List<InvoicePurchaseRecord> invoicePurchaseRecords = new ArrayList<>();
if (CollUtil.isNotEmpty(purchaseRecordDOS)) {
for (PurchaseRecordDO purchaseRecordDO : purchaseRecordDOS) {
InvoicePurchaseRecord invoicePurchaseRecord = new InvoicePurchaseRecord();
invoicePurchaseRecord.setPurchaseRecordId(purchaseRecordDO.getId());
invoicePurchaseRecord.setProductName(purchaseRecordDO.getProductName());
invoicePurchaseRecord.setTradeType(TradeTypeEnum.PRODUCT.getCode());
invoicePurchaseRecord.setInvoicableAmount(purchaseRecordDO.getTotalAmount());
invoicePurchaseRecord.setTotalAmount(purchaseRecordDO.getTotalAmount());
invoicePurchaseRecord.setCreateTime(purchaseRecordDO.getCreateTime());
invoicePurchaseRecords.add(invoicePurchaseRecord);
}
for (PurchaseRecordDO purchaseRecordDO : purchaseRecordDOS) {
InvoicePurchaseRecord invoicePurchaseRecord = new InvoicePurchaseRecord();
invoicePurchaseRecord.setPurchaseRecordId(purchaseRecordDO.getId());
invoicePurchaseRecord.setProductName(purchaseRecordDO.getProductName());
invoicePurchaseRecord.setTradeType(TradeTypeEnum.PRODUCT.getCode());
invoicePurchaseRecord.setInvoicableAmount(purchaseRecordDO.getTotalAmount());
invoicePurchaseRecord.setTotalAmount(purchaseRecordDO.getTotalAmount());
invoicePurchaseRecord.setCreateTime(purchaseRecordDO.getCreateTime());
invoicePurchaseRecords.add(invoicePurchaseRecord);
}
// 解压发票抬头
@@ -0,0 +1,222 @@
package com.cf.imes.module.system.controller.admin.funds.invoice;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.test.core.ut.BaseWebUnitTest;
import com.cf.imes.module.system.controller.admin.funds.invoice.vo.*;
import com.cf.imes.module.system.enums.pay.InvoiceIssueTypeEnum;
import com.cf.imes.module.system.enums.pay.InvoiceTypeEnum;
import com.cf.imes.module.system.service.funds.invoice.InvoiceService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.servlet.MockMvc;
import java.math.BigDecimal;
import java.util.List;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* @author 发票管理 Controller 测试类
*/
@WebMvcTest(controllers = InvoiceController.class, excludeAutoConfiguration = SecurityAutoConfiguration.class)
class InvoiceControllerTest extends BaseWebUnitTest {
@Autowired
private MockMvc mockMvc;
@MockitoBean
private InvoiceService invoiceService;
@Autowired
private ObjectMapper objectMapper;
@Test
void testGetOrgInvoiceTitle() throws Exception {
InvoiceTitleInfo respVO = new InvoiceTitleInfo();
respVO.setId(1L);
respVO.setInvoiceTitle("测试公司");
when(invoiceService.getInvoiceTitle()).thenReturn(respVO);
mockMvc.perform(get("/system/invoice/title"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.id").value(1L))
.andExpect(jsonPath("$.data.invoiceTitle").value("测试公司"));
verify(invoiceService).getInvoiceTitle();
}
@Test
void testInsetInvoiceTitle() throws Exception {
InvoiceTitleSaveReqVO reqVO = new InvoiceTitleSaveReqVO();
reqVO.setInvoiceTitle("测试公司");
reqVO.setIssueType(InvoiceIssueTypeEnum.ENTERPRISE.getValue());
reqVO.setInvoiceType(InvoiceTypeEnum.VAT_GENERAL.getValue());
reqVO.setEmail("test@test.com");
doNothing().when(invoiceService).insetInvoiceTitle(any());
mockMvc.perform(post("/system/invoice/title")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(reqVO)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data").value(true));
verify(invoiceService).insetInvoiceTitle(any());
}
@Test
void testGetInvoiceAmount() throws Exception {
InvoiceAmountRespVO respVO = new InvoiceAmountRespVO();
respVO.setInvocable(new BigDecimal("100.00"));
respVO.setPendingInvoice(new BigDecimal("50.00"));
respVO.setInTheInvoice(new BigDecimal("30.00"));
respVO.setInvoiced(new BigDecimal("200.00"));
when(invoiceService.getInvoiceAmount()).thenReturn(respVO);
mockMvc.perform(get("/system/invoice/org/amount"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.invocable").value(100.00))
.andExpect(jsonPath("$.data.pendingInvoice").value(50.00))
.andExpect(jsonPath("$.data.inTheInvoice").value(30.00))
.andExpect(jsonPath("$.data.invoiced").value(200.00));
verify(invoiceService).getInvoiceAmount();
}
@Test
void testGetManageEndPointInvoiceAmount() throws Exception {
InvoiceAmountRespVO respVO = new InvoiceAmountRespVO();
respVO.setPendingInvoice(new BigDecimal("150.00"));
respVO.setInvoiced(new BigDecimal("300.00"));
when(invoiceService.getManageInvoiceAmount()).thenReturn(respVO);
mockMvc.perform(get("/system/invoice/manage/amount"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.pendingInvoice").value(150.00))
.andExpect(jsonPath("$.data.invoiced").value(300.00));
verify(invoiceService).getManageInvoiceAmount();
}
@Test
void testGetAvailablePage() throws Exception {
InvoiceAmountAndAvailablePageReqVO reqVO = new InvoiceAmountAndAvailablePageReqVO();
PageResult<InvoiceAvailablePageRespVO> mockPage = new PageResult<>();
mockPage.setTotal(1L);
InvoiceAvailablePageRespVO pageRespVO = new InvoiceAvailablePageRespVO();
pageRespVO.setId(1L);
pageRespVO.setAvailableAmount(new BigDecimal("100.00"));
mockPage.setList(List.of(pageRespVO));
when(invoiceService.getAvailablePage(any())).thenReturn(mockPage);
mockMvc.perform(get("/system/invoice/available")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(reqVO)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.list[0].id").value(1L))
.andExpect(jsonPath("$.data.list[0].availableAmount").value(100.00));
verify(invoiceService, times(1)).getAvailablePage(any());
}
@Test
void testApplyInvoiceRecords() throws Exception {
InvoiceRecordsReqVO reqVO = new InvoiceRecordsReqVO();
reqVO.setPurchaseRecordId(List.of(1L, 2L));
doNothing().when(invoiceService).applyInvoice(any());
mockMvc.perform(post("/system/invoice")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(reqVO)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data").value(true));
verify(invoiceService).applyInvoice(any());
}
@Test
void testGetInvoiceRecords() throws Exception {
InvoiceDetailsPageReqVO reqVO = new InvoiceDetailsPageReqVO();
PageResult<InvoiceRecordsRespVO> mockPage = new PageResult<>();
mockPage.setTotal(1L);
InvoiceRecordsRespVO pageRespVO = new InvoiceRecordsRespVO();
pageRespVO.setId(1L);
pageRespVO.setInvoiceAmount(new BigDecimal("150.00"));
mockPage.setList(List.of(pageRespVO));
when(invoiceService.getInvoiceRecords(any())).thenReturn(mockPage);
mockMvc.perform(get("/system/invoice/records")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(reqVO)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.list[0].id").value(1L))
.andExpect(jsonPath("$.data.list[0].invoiceAmount").value(150.00));
verify(invoiceService, times(1)).getInvoiceRecords(any());
}
@Test
void testGetInvoiceRecordDetail() throws Exception {
Long recordId = 1L;
InvoiceDetailsRespVO respVO = new InvoiceDetailsRespVO();
respVO.setInvoiceNo("FP20231010101010");
respVO.setRemark("测试备注");
when(invoiceService.getInvoiceRecordDetail(recordId)).thenReturn(respVO);
mockMvc.perform(get("/system/invoice/record/{recordId}", recordId))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.invoiceNo").value("FP20231010101010"))
.andExpect(jsonPath("$.data.remark").value("测试备注"));
verify(invoiceService).getInvoiceRecordDetail(recordId);
}
@Test
void testConfirmInvoice() throws Exception {
InvoiceConfirmReqVO reqVO = new InvoiceConfirmReqVO();
reqVO.setId(1L);
reqVO.setAgree(true);
reqVO.setInvoiceNo("FP20231010101010");
reqVO.setRemark("同意开票");
doNothing().when(invoiceService).confirmInvoice(any(), any());
MockMultipartFile file = new MockMultipartFile(
"file",
"invoice.pdf",
"application/pdf",
"test data".getBytes()
);
// 使用param方式传递reqVO参数
mockMvc.perform(multipart("/system/invoice/confirm")
.file(file)
.param("id", "1")
.param("agree", "true")
.param("invoiceNo", "FP20231010101010")
.param("remark", "同意开票"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data").value(true));
verify(invoiceService).confirmInvoice(any(), any());
}
}
@@ -17,9 +17,9 @@ import static org.mockito.Mockito.verify;
*/
class SystemPermissionRefreshRedisListenerTest {
@Test
void onMessage_shouldClearDictDataI18nCache() {
SecurityFrameworkService securityFrameworkService = mock(SecurityFrameworkService.class);
void onMessage_shouldInvalidateAllPermissionsCache() {
// given
SecurityFrameworkService securityFrameworkService = mock(SecurityFrameworkService.class);
SystemPermissionRefreshRedisListener listener =
new SystemPermissionRefreshRedisListener(securityFrameworkService);
@@ -0,0 +1,64 @@
package com.cf.imes.module.system.service.funds.incomeandexpense;
import com.cf.imes.framework.test.core.ut.BaseDbAndRedisUnitTest;
import com.cf.imes.module.system.dal.dataobject.incomeandexpense.IncomeExpenseDetailsDO;
import com.cf.imes.module.system.dal.mysql.incomeandexpense.IncomeExpenseDetailsMapper;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
import java.math.BigDecimal;
import static org.junit.jupiter.api.Assertions.*;
/**
* {@link IncomeExpenseServiceImpl} 的单元测试类
*
* @author Gqr
*/
@Import(IncomeExpenseServiceImpl.class)
class IncomeExpenseServiceImplTest extends BaseDbAndRedisUnitTest {
@Resource
private IncomeExpenseServiceImpl incomeExpenseService;
@Resource
private IncomeExpenseDetailsMapper incomeExpenseDetailsMapper;
@Test
void testCreateDetail() {
// 准备数据
IncomeExpenseDetailsDO incomeExpenseDetailsDO = new IncomeExpenseDetailsDO();
incomeExpenseDetailsDO.setBusinessNo("BUS20251215001");
incomeExpenseDetailsDO.setOrderNo("ORD20251215001");
incomeExpenseDetailsDO.setOrganId(1L);
incomeExpenseDetailsDO.setPurchaseId(100L);
incomeExpenseDetailsDO.setTradeType(1);
incomeExpenseDetailsDO.setIncomeExpenseType(2);
incomeExpenseDetailsDO.setAmount(new BigDecimal("100.00"));
incomeExpenseDetailsDO.setCurrency(1);
incomeExpenseDetailsDO.setCurrencyUnit("CNY");
incomeExpenseDetailsDO.setRemark("测试收支明细");
// 调用方法
Long id = incomeExpenseService.createDetail(incomeExpenseDetailsDO);
// 验证结果
assertNotNull(id);
assertTrue(id > 0);
// 验证数据库中是否已插入数据
IncomeExpenseDetailsDO dbRecord = incomeExpenseDetailsMapper.selectById(id);
assertNotNull(dbRecord);
assertEquals("BUS20251215001", dbRecord.getBusinessNo());
assertEquals("ORD20251215001", dbRecord.getOrderNo());
assertEquals(1L, dbRecord.getOrganId());
assertEquals(100L, dbRecord.getPurchaseId());
assertEquals(1, dbRecord.getTradeType());
assertEquals(2, dbRecord.getIncomeExpenseType());
assertEquals(new BigDecimal("100.00"), dbRecord.getAmount());
assertEquals(1, dbRecord.getCurrency());
assertEquals("CNY", dbRecord.getCurrencyUnit());
assertEquals("测试收支明细", dbRecord.getRemark());
}
}
@@ -0,0 +1,906 @@
package com.cf.imes.module.system.service.funds.invoice;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.exception.enums.GlobalErrorCodeConstants;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
import com.cf.imes.framework.security.test.WithMockLoginUser;
import com.cf.imes.framework.test.core.ut.BaseDbAndRedisUnitTest;
import com.cf.imes.module.infra.api.file.FileApi;
import com.cf.imes.module.system.controller.admin.funds.invoice.vo.*;
import com.cf.imes.module.system.dal.dataobject.funds.invoice.InvoiceRecordsDO;
import com.cf.imes.module.system.dal.dataobject.funds.invoice.InvoiceTitleInfoDO;
import com.cf.imes.module.system.dal.dataobject.funds.purchase.PurchaseRecordDO;
import com.cf.imes.module.system.dal.dataobject.organ.OrganizationDO;
import com.cf.imes.module.system.dal.mysql.funds.invoice.InvoiceRecordsMapper;
import com.cf.imes.module.system.dal.mysql.funds.invoice.InvoiceTitleInfoMapper;
import com.cf.imes.module.system.dal.mysql.funds.purchase.PurchaseRecordMapper;
import com.cf.imes.module.system.enums.pay.InvoiceIssueTypeEnum;
import com.cf.imes.module.system.enums.pay.InvoiceStatusEnum;
import com.cf.imes.module.system.enums.pay.PayChannelCodeEnum;
import com.cf.imes.module.system.enums.pay.TradeTypeEnum;
import com.cf.imes.module.system.service.organ.OrganService;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import static com.cf.imes.framework.common.util.json.JsonUtils.zipString;
import static com.cf.imes.framework.test.core.util.AssertUtils.assertServiceException;
import static com.cf.imes.framework.test.core.util.RandomUtils.randomPojo;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
/**
* 发票服务测试类
*
* @author Gqr
* @since 2025/12/15 15:31
*/
@Import(InvoiceServiceImpl.class)
class InvoiceServiceImplTest extends BaseDbAndRedisUnitTest {
@Resource
private InvoiceServiceImpl invoiceService;
@Resource
private InvoiceTitleInfoMapper invoiceTitleInfoMapper;
@Resource
private PurchaseRecordMapper purchaseRecordMapper;
@Resource
private InvoiceRecordsMapper invoiceRecordsMapper;
@MockitoBean
private OrganService organService;
@MockitoBean
private FileApi fileApi;
@Test
@WithMockLoginUser
void testGetInvoiceTitle() {
// 准备参数
Long organId = SecurityFrameworkUtils.getUserOrganId();
// 使用真实数据查询发票抬头信息
InvoiceTitleInfoDO invoiceTitleInfoDO = randomPojo(InvoiceTitleInfoDO.class, o -> {
o.setId(1L);
o.setOrganId(organId);
o.setInvoiceTitle("测试公司");
});
invoiceTitleInfoMapper.insert(invoiceTitleInfoDO);
// 调用
InvoiceTitleInfo result = invoiceService.getInvoiceTitle();
// 断言
assertNotNull(result);
assertEquals(1L, result.getId());
assertEquals("测试公司", result.getInvoiceTitle());
assertEquals(organId, result.getOrganId());
}
@Test
@WithMockLoginUser
void insetInvoiceTitle_create_success() {
Long organId = SecurityFrameworkUtils.getUserOrganId();
InvoiceTitleSaveReqVO reqVO = new InvoiceTitleSaveReqVO();
reqVO.setInvoiceTitle("测试公司");
reqVO.setIssueType(InvoiceIssueTypeEnum.ENTERPRISE.getValue());
reqVO.setInvoiceType(0);
reqVO.setTaxNumber("91330101MA2HXXXXXX");
reqVO.setEmail("test@company.com");
invoiceService.insetInvoiceTitle(reqVO);
// ====== 校验数据库 ======
InvoiceTitleInfoDO dbRecord = invoiceTitleInfoMapper.selectOne(
new LambdaQueryWrapper<InvoiceTitleInfoDO>()
.eq(InvoiceTitleInfoDO::getOrganId, organId)
);
assertNotNull(dbRecord);
assertEquals("测试公司", dbRecord.getInvoiceTitle());
assertEquals("91330101MA2HXXXXXX", dbRecord.getTaxNumber());
}
@Test
@WithMockLoginUser
void insetInvoiceTitle_enterpriseWithoutTaxNumber_throwException() {
InvoiceTitleSaveReqVO reqVO = new InvoiceTitleSaveReqVO();
reqVO.setInvoiceTitle("测试公司");
reqVO.setIssueType(InvoiceIssueTypeEnum.ENTERPRISE.getValue());
reqVO.setInvoiceType(0);
reqVO.setTaxNumber(null);
ServiceException ex = assertThrows(
ServiceException.class,
() -> invoiceService.insetInvoiceTitle(reqVO)
);
assertEquals(
INVOICE_TITLE_ENTERPRISE_TAXNUMBER_EMPTY_ERROR.getCode(),
ex.getCode()
);
}
@Test
@WithMockLoginUser
void insetInvoiceTitle_sameOrgan_throwOrgExists() {
Long organId = SecurityFrameworkUtils.getUserOrganId();
invoiceTitleInfoMapper.insert(InvoiceTitleInfoDO.builder()
.organId(organId)
.issueType(InvoiceIssueTypeEnum.PERSONAL.getValue())
.invoiceTitle("已存在")
.build());
InvoiceTitleSaveReqVO reqVO = new InvoiceTitleSaveReqVO();
reqVO.setInvoiceTitle("新抬头");
reqVO.setIssueType(InvoiceIssueTypeEnum.PERSONAL.getValue());
ServiceException ex = assertThrows(
ServiceException.class,
() -> invoiceService.insetInvoiceTitle(reqVO)
);
assertEquals(
INVOICE_TITLE_ORG_EXISTS_ERROR.getCode(),
ex.getCode()
);
}
@Test
@WithMockLoginUser
void insetInvoiceTitle_update_notExists_throwException() {
InvoiceTitleSaveReqVO reqVO = new InvoiceTitleSaveReqVO();
reqVO.setId(999L); // 数据库不存在
reqVO.setInvoiceTitle("测试抬头");
reqVO.setIssueType(InvoiceIssueTypeEnum.PERSONAL.getValue());
ServiceException ex = assertThrows(
ServiceException.class,
() -> invoiceService.insetInvoiceTitle(reqVO)
);
assertEquals(
INVOICE_TITLE_NOT_EXISTS_ERROR.getCode(),
ex.getCode()
);
}
@Test
@WithMockLoginUser
void insetInvoiceTitle_update_orgNotMatch_throwException() {
InvoiceTitleInfoDO exist = InvoiceTitleInfoDO.builder()
.organId(2L)
.issueType(InvoiceIssueTypeEnum.PERSONAL.getValue())
.invoiceTitle("原抬头")
.build();
invoiceTitleInfoMapper.insert(exist);
InvoiceTitleSaveReqVO reqVO = new InvoiceTitleSaveReqVO();
reqVO.setId(exist.getId());
reqVO.setInvoiceTitle("非法更新");
reqVO.setIssueType(exist.getIssueType());
ServiceException ex = assertThrows(
ServiceException.class,
() -> invoiceService.insetInvoiceTitle(reqVO)
);
assertEquals(
INVOICE_TITLE_NOT_EXISTS_ERROR.getCode(),
ex.getCode()
);
}
@Test
@WithMockLoginUser
void insetInvoiceTitle_insert_success() {
Long organId = SecurityFrameworkUtils.getUserOrganId();
InvoiceTitleSaveReqVO reqVO = new InvoiceTitleSaveReqVO();
reqVO.setInvoiceTitle("新增抬头");
reqVO.setIssueType(InvoiceIssueTypeEnum.PERSONAL.getValue());
reqVO.setInvoiceType(0);
reqVO.setEmail("test@test.com");
invoiceService.insetInvoiceTitle(reqVO);
// 验证数据库
List<InvoiceTitleInfoDO> list = invoiceTitleInfoMapper.selectList(null);
assertEquals(1, list.size());
InvoiceTitleInfoDO saved = list.get(0);
assertEquals(organId, saved.getOrganId());
assertEquals("新增抬头", saved.getInvoiceTitle());
}
@Test
@WithMockLoginUser
void insetInvoiceTitle_enterprise_taxNumberExists_throwException() {
// 先插入一条企业发票抬头
InvoiceTitleInfoDO exist = InvoiceTitleInfoDO.builder()
.organId(2L) // 不同组织也没关系
.invoiceTitle("已存在抬头")
.issueType(InvoiceIssueTypeEnum.ENTERPRISE.getValue())
.taxNumber("91330100XXXXXX")
.build();
invoiceTitleInfoMapper.insert(exist);
// 再新增一条相同税号
InvoiceTitleSaveReqVO reqVO = new InvoiceTitleSaveReqVO();
reqVO.setInvoiceTitle("新抬头");
reqVO.setIssueType(InvoiceIssueTypeEnum.ENTERPRISE.getValue());
reqVO.setTaxNumber("91330100XXXXXX");
ServiceException ex = assertThrows(
ServiceException.class,
() -> invoiceService.insetInvoiceTitle(reqVO)
);
assertEquals(
INVOICE_TITLE_TAXPAYERID_EXISTS_ERROR.getCode(),
ex.getCode()
);
}
@Test
@WithMockLoginUser
void insetInvoiceTitle_update_success() {
Long organId = SecurityFrameworkUtils.getUserOrganId();
// given:数据库已有数据(organId 一定要一致)
InvoiceTitleInfoDO exist = InvoiceTitleInfoDO.builder()
.organId(organId)
.invoiceTitle("旧抬头")
.issueType(InvoiceIssueTypeEnum.PERSONAL.getValue())
.build();
invoiceTitleInfoMapper.insert(exist);
// when:更新
InvoiceTitleSaveReqVO reqVO = new InvoiceTitleSaveReqVO();
reqVO.setId(exist.getId());
reqVO.setInvoiceTitle("新抬头");
reqVO.setIssueType(InvoiceIssueTypeEnum.PERSONAL.getValue());
invoiceService.insetInvoiceTitle(reqVO);
// then:断言更新成功
InvoiceTitleInfoDO updated = invoiceTitleInfoMapper.selectById(exist.getId());
assertEquals("新抬头", updated.getInvoiceTitle());
}
@Test
@WithMockLoginUser
void getAvailablePage_whenEmptyList_returnEmptyPageResult() {
// given
InvoiceAmountAndAvailablePageReqVO reqVO = new InvoiceAmountAndAvailablePageReqVO();
// when
PageResult<InvoiceAvailablePageRespVO> result =
invoiceService.getAvailablePage(reqVO);
// then
assertNotNull(result);
assertEquals(0, result.getTotal());
assertTrue(CollUtil.isEmpty(result.getList()));
}
@Test
@WithMockLoginUser(organId = 1L)
void getAvailablePage_whenHasData_returnConvertedPage() {
// given
InvoiceAmountAndAvailablePageReqVO reqVO =
new InvoiceAmountAndAvailablePageReqVO();
PurchaseRecordDO invoiceRecordsDO = randomPojo(PurchaseRecordDO.class, o -> {
o.setId(1L);
o.setCreateTime(LocalDateTime.now());
o.setExternalSpent(new BigDecimal("100.00"));
o.setProductName("测试产品");
o.setTotalAmount(new BigDecimal("200.00"));
o.setPaymentMethod(PayChannelCodeEnum.ALIPAY_PC.getCode());
o.setIsInvocing(InvoiceStatusEnum.INVOICABLE.getCode());
o.setInitial(false);
o.setOrganId(1L);
});
purchaseRecordMapper.insert(invoiceRecordsDO);
// when
PageResult<InvoiceAvailablePageRespVO> result =
invoiceService.getAvailablePage(reqVO);
// then
assertNotNull(result);
assertEquals(1L, result.getTotal());
assertEquals(1, result.getList().size());
InvoiceAvailablePageRespVO vo = result.getList().get(0);
assertEquals(1L, vo.getId());
assertEquals(TradeTypeEnum.PRODUCT.getCode(), vo.getTradeType());
assertEquals(invoiceRecordsDO.getExternalSpent(), vo.getAvailableAmount());
assertEquals("测试产品", vo.getProductName());
assertEquals(invoiceRecordsDO.getTotalAmount(), vo.getTotalAmount());
}
@Test
void applyInvoice_whenNoLogin_throwUnauthorized() {
InvoiceRecordsReqVO reqVO = new InvoiceRecordsReqVO();
assertServiceException(() -> invoiceService.applyInvoice(reqVO), GlobalErrorCodeConstants.UNAUTHORIZED);
}
@Test
@WithMockLoginUser(organId = 1L)
void applyInvoice_whenUninvoicableExist_throwException() {
InvoiceRecordsReqVO reqVO = new InvoiceRecordsReqVO();
assertServiceException(() -> invoiceService.applyInvoice(reqVO), INVOICE_TITLE_NOT_EXISTS_ERROR);
}
@Test
@WithMockLoginUser(organId = 1L)
void applyInvoice_uninvoiceableExist() {
// 先插入一条企业发票抬头
InvoiceTitleInfoDO exist = InvoiceTitleInfoDO.builder()
.organId(1L) // 不同组织也没关系
.invoiceTitle("已存在抬头")
.issueType(InvoiceIssueTypeEnum.ENTERPRISE.getValue())
.taxNumber("91330100XXXXXX")
.build();
invoiceTitleInfoMapper.insert(exist);
InvoiceRecordsReqVO reqVO = new InvoiceRecordsReqVO();
PurchaseRecordDO invoiceRecordsDO = randomPojo(PurchaseRecordDO.class, o -> {
o.setId(1L);
o.setCreateTime(LocalDateTime.now());
o.setExternalSpent(new BigDecimal("100.00"));
o.setProductName("测试产品");
o.setTotalAmount(new BigDecimal("200.00"));
o.setPaymentMethod(PayChannelCodeEnum.ALIPAY_PC.getCode());
o.setIsInvocing(InvoiceStatusEnum.INVOICINGSUCCESSFUL.getCode());
o.setInitial(false);
o.setOrganId(1L);
});
purchaseRecordMapper.insert(invoiceRecordsDO);
// 有不可开票状态的记录
reqVO.setPurchaseRecordId(List.of(invoiceRecordsDO.getId()));
assertServiceException(() -> invoiceService.applyInvoice(reqVO), INVOICE_APPLY_UNINVOICEABLE_EXIST);
// 可开金额为0
invoiceRecordsDO.setId(null);
invoiceRecordsDO.setExternalSpent(BigDecimal.ZERO);
invoiceRecordsDO.setIsInvocing(InvoiceStatusEnum.INVOICABLE.getCode());
purchaseRecordMapper.insert(invoiceRecordsDO);
reqVO.setPurchaseRecordId(List.of(invoiceRecordsDO.getId()));
assertServiceException(() -> invoiceService.applyInvoice(reqVO), INVOICE_AMOUNT_ZERO_ERROR);
// 更新开票状态和开票id数量不匹配
invoiceRecordsDO.setId(null);
invoiceRecordsDO.setIsInvocing(InvoiceStatusEnum.INVOICABLE.getCode());
invoiceRecordsDO.setExternalSpent(new BigDecimal("100"));
purchaseRecordMapper.insert(invoiceRecordsDO);
reqVO.setPurchaseRecordId(List.of(invoiceRecordsDO.getId(), 999L));
assertServiceException(
() -> invoiceService.applyInvoice(reqVO),
ORG_INVOICE_PURCHASE_RECORD_UPDATE_NUM_NOT_MATCH_ERROR
);
}
@Test
@WithMockLoginUser(organId = 1L)
void applyInvoice_success() {
// 先插入一条企业发票抬头
InvoiceTitleInfoDO exist = InvoiceTitleInfoDO.builder()
.organId(1L) // 不同组织也没关系
.invoiceTitle("已存在抬头")
.issueType(InvoiceIssueTypeEnum.ENTERPRISE.getValue())
.taxNumber("91330100XXXXXX")
.build();
invoiceTitleInfoMapper.insert(exist);
InvoiceRecordsReqVO reqVO = new InvoiceRecordsReqVO();
PurchaseRecordDO invoiceRecordsDO = randomPojo(PurchaseRecordDO.class, o -> {
o.setCreateTime(LocalDateTime.now());
o.setExternalSpent(new BigDecimal("100.00"));
o.setProductName("测试产品");
o.setTotalAmount(new BigDecimal("200.00"));
o.setPaymentMethod(PayChannelCodeEnum.ALIPAY_PC.getCode());
o.setIsInvocing(InvoiceStatusEnum.INVOICABLE.getCode());
o.setInitial(false);
o.setOrganId(1L);
});
purchaseRecordMapper.insert(invoiceRecordsDO);
Long recordId = invoiceRecordsDO.getId();
reqVO.setPurchaseRecordId(List.of(recordId));
// 组织
OrganizationDO org = new OrganizationDO();
org.setName("测试组织");
org.setId(1L);
when(organService.validOrgan(1L)).thenReturn(org);
assertDoesNotThrow(() -> {
invoiceService.applyInvoice(reqVO);
});
List<InvoiceRecordsDO> invoiceRecordsDOS = invoiceRecordsMapper.selectList();
assertEquals(1, invoiceRecordsDOS.size());
InvoiceRecordsDO query = invoiceRecordsDOS.get(0);
assertNotNull(invoiceRecordsDO);
assertEquals(invoiceRecordsDO.getOrganId(), invoiceRecordsDO.getOrganId());
assertEquals(query.getPurchaseIds(), List.of(invoiceRecordsDO.getId()).toString());
assertEquals("测试组织", query.getOrganName());
}
@Test
@WithMockLoginUser
void getInvoiceRecords_whenEmptyList_returnEmptyPageResult() {
// given
InvoiceDetailsPageReqVO pageReqVO = new InvoiceDetailsPageReqVO();
// when
PageResult<InvoiceRecordsRespVO> result = invoiceService.getInvoiceRecords(pageReqVO);
// then
assertNotNull(result);
assertEquals(0, result.getTotal());
assertTrue(CollUtil.isEmpty(result.getList()));
}
@Test
@WithMockLoginUser
void getInvoiceRecords_whenHasData_returnConvertedPage() {
// given
InvoiceDetailsPageReqVO pageReqVO = new InvoiceDetailsPageReqVO();
InvoiceRecordsDO invoiceRecordsDO = randomPojo(InvoiceRecordsDO.class, o->{
o.setId(1L);
o.setInvoiceAmount(new BigDecimal("100.00"));
o.setStatus(InvoiceStatusEnum.INVOICABLE.getCode());
});
invoiceRecordsMapper.insert(invoiceRecordsDO);
// when
PageResult<InvoiceRecordsRespVO> result = invoiceService.getInvoiceRecords(pageReqVO);
// then
assertNotNull(result);
assertEquals(1L, result.getTotal());
assertEquals(1, result.getList().size());
InvoiceRecordsRespVO vo = result.getList().get(0);
assertEquals(1L, vo.getId());
assertEquals(invoiceRecordsDO.getInvoiceAmount(), vo.getInvoiceAmount());
assertEquals(invoiceRecordsDO.getStatus(), vo.getStatus());
}
@Test
@WithMockLoginUser
void getInvoiceRecordDetail_whenRecordNotExists_thenThrowException() {
assertServiceException(() -> invoiceService.getInvoiceRecordDetail(1L), INVOICE_NO_EXIST);
}
@Test
@WithMockLoginUser
void getInvoiceRecordDetail_whenRecordExists_thenReturnDetail() {
// 准备数据
InvoiceRecordsDO invoiceRecordsDO = randomPojo(InvoiceRecordsDO.class, o -> {
o.setId(1L);
o.setOrganId(1L);
o.setInvoiceAmount(new BigDecimal("100.00"));
o.setPurchaseIds("[1, 2]");
o.setInvoiceTitleInfo(zipString("{\"invoiceTitle\":\"测试公司\"}"));
});
invoiceRecordsMapper.insert(invoiceRecordsDO);
PurchaseRecordDO purchase1 = randomPojo(PurchaseRecordDO.class, o -> {
o.setId(1L);
o.setOrganId(1L);
o.setProductName("产品1");
o.setTotalAmount(new BigDecimal("50.00"));
o.setPaymentMethod(PayChannelCodeEnum.ALIPAY_PC.getCode());
o.setIsInvocing(InvoiceStatusEnum.INVOICABLE.getCode());
o.setInitial(false);
});
purchaseRecordMapper.insert(purchase1);
PurchaseRecordDO purchase2 = randomPojo(PurchaseRecordDO.class, o -> {
o.setId(2L);
o.setOrganId(1L);
o.setProductName("产品2");
o.setTotalAmount(new BigDecimal("50.00"));
o.setPaymentMethod(PayChannelCodeEnum.ALIPAY_PC.getCode());
o.setIsInvocing(InvoiceStatusEnum.INVOICABLE.getCode());
o.setInitial(false);
});
purchaseRecordMapper.insert(purchase2);
// 调用方法
InvoiceDetailsRespVO result = invoiceService.getInvoiceRecordDetail(1L);
// 验证结果
assertNotNull(result);
assertEquals(2, result.getInvoicePurchaseRecords().size());
assertEquals("测试公司", result.getInvoiceTitleInfo().getInvoiceTitle());
}
@Test
void confirmInvoice_whenNoLogin_thenThrowUnauthorized() {
InvoiceConfirmReqVO reqVO = new InvoiceConfirmReqVO();
assertServiceException(() -> invoiceService.confirmInvoice(reqVO, null), GlobalErrorCodeConstants.UNAUTHORIZED);
}
@Test
@WithMockLoginUser
void confirmInvoice_whenRecordNotExists_thenThrowException() {
InvoiceConfirmReqVO reqVO = new InvoiceConfirmReqVO();
reqVO.setId(1L);
assertServiceException(() -> invoiceService.confirmInvoice(reqVO, null), INVOICE_NO_EXIST);
}
@Test
@WithMockLoginUser
void confirmInvoice_whenRecordAlreadySuccess_thenThrowException() {
// 准备数据
InvoiceRecordsDO invoiceRecordsDO = randomPojo(InvoiceRecordsDO.class, o -> {
o.setId(1L);
o.setStatus(InvoiceStatusEnum.INVOICINGSUCCESSFUL.getCode());
});
invoiceRecordsMapper.insert(invoiceRecordsDO);
InvoiceConfirmReqVO reqVO = new InvoiceConfirmReqVO();
reqVO.setId(1L);
assertServiceException(() -> invoiceService.confirmInvoice(reqVO, null), THIS_INVOICE_IS_FAIL);
}
@Test
@WithMockLoginUser
void confirmInvoice_whenRecordAlreadyFailed_thenThrowException() {
// 准备数据
InvoiceRecordsDO invoiceRecordsDO = randomPojo(InvoiceRecordsDO.class, o -> {
o.setId(1L);
o.setStatus(InvoiceStatusEnum.INVOICINGFAILED.getCode());
});
invoiceRecordsMapper.insert(invoiceRecordsDO);
InvoiceConfirmReqVO reqVO = new InvoiceConfirmReqVO();
reqVO.setId(1L);
assertServiceException(() -> invoiceService.confirmInvoice(reqVO, null), THIS_INVOICE_IS_FAIL);
}
@Test
@WithMockLoginUser
void confirmInvoice_whenPurchaseRecordNotExists_thenThrowException() {
// 准备数据
InvoiceRecordsDO invoiceRecordsDO = randomPojo(InvoiceRecordsDO.class, o -> {
o.setId(1L);
o.setStatus(InvoiceStatusEnum.PENDINGINVOICING.getCode());
o.setPurchaseIds("[1]");
o.setInvoiceTitleId(1L);
o.setOrganId(1L);
});
invoiceRecordsMapper.insert(invoiceRecordsDO);
InvoiceConfirmReqVO reqVO = new InvoiceConfirmReqVO();
reqVO.setId(1L);
assertServiceException(() -> invoiceService.confirmInvoice(reqVO, null), PURCHASE_RECORD_NO_EXIST);
}
@Test
@WithMockLoginUser
void confirmInvoice_agreeWithoutFile_thenThrowException() {
// 准备数据
InvoiceRecordsDO invoiceRecordsDO = randomPojo(InvoiceRecordsDO.class, o -> {
o.setId(1L);
o.setStatus(InvoiceStatusEnum.PENDINGINVOICING.getCode());
o.setPurchaseIds("[1]");
o.setInvoiceTitleId(1L);
o.setOrganId(1L);
});
invoiceRecordsMapper.insert(invoiceRecordsDO);
InvoiceTitleInfoDO title = randomPojo(InvoiceTitleInfoDO.class, o -> {
o.setId(1L);
o.setOrganId(1L);
o.setInvoiceTitle("测试公司");
});
invoiceTitleInfoMapper.insert(title);
PurchaseRecordDO purchase = randomPojo(PurchaseRecordDO.class, o -> {
o.setId(1L);
o.setOrganId(1L);
o.setPaymentMethod(PayChannelCodeEnum.ALIPAY_PC.getCode());
o.setIsInvocing(InvoiceStatusEnum.INVOICABLE.getCode());
o.setInitial(false);
});
purchaseRecordMapper.insert(purchase);
InvoiceConfirmReqVO reqVO = new InvoiceConfirmReqVO();
reqVO.setId(1L);
reqVO.setAgree(true);
assertServiceException(() -> invoiceService.confirmInvoice(reqVO, null), ORG_INVOICE_AGREE_FILE_NULL_ERROR);
}
@Test
@WithMockLoginUser
void confirmInvoice_rejectWithoutRemark_thenThrowException() {
// 准备数据
InvoiceRecordsDO invoiceRecordsDO = randomPojo(InvoiceRecordsDO.class, o -> {
o.setId(1L);
o.setStatus(InvoiceStatusEnum.PENDINGINVOICING.getCode());
o.setPurchaseIds("[1]");
o.setInvoiceTitleId(1L);
o.setOrganId(1L);
});
invoiceRecordsMapper.insert(invoiceRecordsDO);
InvoiceTitleInfoDO title = randomPojo(InvoiceTitleInfoDO.class, o -> {
o.setId(1L);
o.setOrganId(1L);
o.setInvoiceTitle("测试公司");
});
invoiceTitleInfoMapper.insert(title);
PurchaseRecordDO purchase = randomPojo(PurchaseRecordDO.class, o -> {
o.setId(1L);
o.setOrganId(1L);
o.setPaymentMethod(PayChannelCodeEnum.ALIPAY_PC.getCode());
o.setIsInvocing(InvoiceStatusEnum.INVOICABLE.getCode());
o.setInitial(false);
});
purchaseRecordMapper.insert(purchase);
InvoiceConfirmReqVO reqVO = new InvoiceConfirmReqVO();
reqVO.setId(1L);
reqVO.setAgree(false);
reqVO.setRemark(null);
assertServiceException(() -> invoiceService.confirmInvoice(reqVO, null), INVOICING_REJECT_REASON);
}
@Test
@WithMockLoginUser(username = "测试用户", userId = 1L)
void confirmInvoice_agreeWithFile_thenSuccess() {
// 准备数据
InvoiceRecordsDO invoiceRecordsDO = randomPojo(InvoiceRecordsDO.class, o -> {
o.setId(1L);
o.setStatus(InvoiceStatusEnum.PENDINGINVOICING.getCode());
o.setPurchaseIds("[1]");
o.setInvoiceTitleId(1L);
o.setOrganId(1L);
o.setInvoiceAmount(new BigDecimal("100.00"));
});
invoiceRecordsMapper.insert(invoiceRecordsDO);
InvoiceTitleInfoDO title = randomPojo(InvoiceTitleInfoDO.class, o -> {
o.setId(1L);
o.setOrganId(1L);
o.setInvoiceTitle("测试公司");
});
invoiceTitleInfoMapper.insert(title);
PurchaseRecordDO purchase = randomPojo(PurchaseRecordDO.class, o -> {
o.setId(1L);
o.setOrganId(1L);
o.setPaymentMethod(PayChannelCodeEnum.ALIPAY_PC.getCode());
o.setIsInvocing(InvoiceStatusEnum.INVOICABLE.getCode());
o.setInitial(false);
});
purchaseRecordMapper.insert(purchase);
// Mock 文件上传
MockMultipartFile file = new MockMultipartFile("file", "测试公司-20231010101010-100.pdf", "application/pdf", "content".getBytes());
when(fileApi.createFileAndReturnId(any(byte[].class), anyString())).thenReturn(1L);
InvoiceConfirmReqVO reqVO = new InvoiceConfirmReqVO();
reqVO.setId(1L);
reqVO.setAgree(true);
reqVO.setInvoiceNo("FP20231010101010");
reqVO.setRemark("同意开票");
// 调用方法
assertDoesNotThrow(() -> invoiceService.confirmInvoice(reqVO, file));
// 验证数据库更新
InvoiceRecordsDO updatedRecord = invoiceRecordsMapper.selectById(1L);
assertEquals(InvoiceStatusEnum.INVOICINGSUCCESSFUL.getCode(), updatedRecord.getStatus());
assertEquals("FP20231010101010", updatedRecord.getInvoiceNo());
assertEquals("同意开票", updatedRecord.getRemark());
assertEquals("测试用户", updatedRecord.getInvoicePerson());
assertEquals(1L, updatedRecord.getInvoicePersonId());
assertNotNull(updatedRecord.getInvoiceTime());
assertEquals(1L, updatedRecord.getInvoiceAttachmentId());
PurchaseRecordDO updatedPurchase = purchaseRecordMapper.selectById(1L);
assertEquals(InvoiceStatusEnum.INVOICINGSUCCESSFUL.getCode(), updatedPurchase.getIsInvocing());
}
@Test
@WithMockLoginUser(userId = 1L, username = "测试用户")
void confirmInvoice_reject_thenSuccess() {
// 准备数据
InvoiceRecordsDO invoiceRecordsDO = randomPojo(InvoiceRecordsDO.class, o -> {
o.setId(1L);
o.setStatus(InvoiceStatusEnum.PENDINGINVOICING.getCode());
o.setPurchaseIds("[1]");
o.setInvoiceTitleId(1L);
o.setOrganId(1L);
});
invoiceRecordsMapper.insert(invoiceRecordsDO);
InvoiceTitleInfoDO title = randomPojo(InvoiceTitleInfoDO.class, o -> {
o.setId(1L);
o.setOrganId(1L);
o.setInvoiceTitle("测试公司");
});
invoiceTitleInfoMapper.insert(title);
PurchaseRecordDO purchase = randomPojo(PurchaseRecordDO.class, o -> {
o.setId(1L);
o.setOrganId(1L);
o.setPaymentMethod(PayChannelCodeEnum.ALIPAY_PC.getCode());
o.setIsInvocing(InvoiceStatusEnum.INVOICABLE.getCode());
o.setInitial(false);
});
purchaseRecordMapper.insert(purchase);
InvoiceConfirmReqVO reqVO = new InvoiceConfirmReqVO();
reqVO.setId(1L);
reqVO.setAgree(false);
reqVO.setRemark("拒绝开票");
// 调用方法
assertDoesNotThrow(() -> invoiceService.confirmInvoice(reqVO, null));
// 验证数据库更新
InvoiceRecordsDO updatedRecord = invoiceRecordsMapper.selectById(1L);
assertEquals(InvoiceStatusEnum.INVOICINGFAILED.getCode(), updatedRecord.getStatus());
assertEquals("拒绝开票", updatedRecord.getRemark());
assertEquals("测试用户", updatedRecord.getInvoicePerson());
assertEquals(1L, updatedRecord.getInvoicePersonId());
assertNotNull(updatedRecord.getInvoiceTime());
PurchaseRecordDO updatedPurchase = purchaseRecordMapper.selectById(1L);
assertEquals(InvoiceStatusEnum.INVOICABLE.getCode(), updatedPurchase.getIsInvocing());
}
@Test
@WithMockLoginUser
void getInvoiceAmount_whenNoData_thenReturnZeroValues() {
// 调用方法
InvoiceAmountRespVO result = invoiceService.getInvoiceAmount();
// 验证结果
assertNotNull(result);
assertEquals(BigDecimal.ZERO, result.getInvocable());
assertEquals(BigDecimal.ZERO, result.getInTheInvoice());
assertEquals(BigDecimal.ZERO, result.getInvoiced());
}
@Test
@WithMockLoginUser
void getInvoiceAmount_whenHasData_thenReturnCorrectValues() {
// 可开票
PurchaseRecordDO purchaseRecordDO = randomPojo(PurchaseRecordDO.class, o->{
o.setExternalSpent(new BigDecimal("100.00"));
o.setPaymentMethod(PayChannelCodeEnum.ALIPAY_PC.getCode());
o.setIsInvocing(InvoiceStatusEnum.INVOICABLE.getCode());
o.setInitial(false);
o.setOrganId(SecurityFrameworkUtils.getUserOrganId());
});
purchaseRecordMapper.insert(purchaseRecordDO);
InvoiceAmountRespVO result = invoiceService.getInvoiceAmount();
assertNotNull(result);
assertEquals(new BigDecimal("100.00"), result.getInvocable());
// 开票中
purchaseRecordDO.setId(null);
purchaseRecordDO.setIsInvocing(InvoiceStatusEnum.PENDINGINVOICING.getCode());
purchaseRecordMapper.insert(purchaseRecordDO);
result = invoiceService.getInvoiceAmount();
assertNotNull(result);
assertEquals(new BigDecimal("100.00"), result.getInTheInvoice());
// 已开票
purchaseRecordDO.setId(null);
purchaseRecordDO.setIsInvocing(InvoiceStatusEnum.INVOICINGSUCCESSFUL.getCode());
purchaseRecordMapper.insert(purchaseRecordDO);
result = invoiceService.getInvoiceAmount();
assertNotNull(result);
assertEquals(new BigDecimal("100.00"), result.getInvoiced());
}
@Test
void getManageInvoiceAmount_whenNoData_thenReturnZeroValues() {
// 调用方法
InvoiceAmountRespVO result = invoiceService.getManageInvoiceAmount();
// 验证结果
assertNotNull(result);
assertEquals(BigDecimal.ZERO, result.getPendingInvoice());
assertEquals(BigDecimal.ZERO, result.getInvoiced());
}
@Test
void getManageInvoiceAmount_whenHasData_thenReturnCorrectValues() {
// 待开票
InvoiceRecordsDO invoiceRecordsDO = randomPojo(InvoiceRecordsDO.class, o -> {
o.setInvoiceAmount(new BigDecimal("150.00"));
o.setStatus(InvoiceStatusEnum.PENDINGINVOICING.getCode());
});
invoiceRecordsMapper.insert(invoiceRecordsDO);
InvoiceAmountRespVO result = invoiceService.getManageInvoiceAmount();
assertNotNull(result);
assertEquals(new BigDecimal("150.00"), result.getPendingInvoice());
// 已开票
invoiceRecordsDO.setId(null);
invoiceRecordsDO.setStatus(InvoiceStatusEnum.INVOICINGSUCCESSFUL.getCode());
invoiceRecordsDO.setInvoiceAmount(new BigDecimal("300.00"));
invoiceRecordsMapper.insert(invoiceRecordsDO);
result = invoiceService.getManageInvoiceAmount();
assertEquals(new BigDecimal("300.00"), result.getInvoiced());
}
@Test
void getFileExtension_whenFileNameIsNull_thenReturnEmpty() {
assertEquals("", InvoiceServiceImpl.getFileExtension(null));
}
@Test
void getFileExtension_whenFileNameIsEmpty_thenReturnEmpty() {
assertEquals("", InvoiceServiceImpl.getFileExtension(""));
}
@Test
void getFileExtension_whenFileNameHasNoExtension_thenReturnEmpty() {
assertEquals("", InvoiceServiceImpl.getFileExtension("filename"));
}
@Test
void getFileExtension_whenFileNameEndsWithDot_thenReturnEmpty() {
assertEquals("", InvoiceServiceImpl.getFileExtension("filename."));
}
@Test
void getFileExtension_whenFileNameHasExtension_thenReturnExtension() {
assertEquals(".pdf", InvoiceServiceImpl.getFileExtension("filename.pdf"));
}
@Test
void getFileExtension_whenFileNameHasMultipleDots_thenReturnLastExtension() {
assertEquals(".pdf", InvoiceServiceImpl.getFileExtension("file.name.pdf"));
}
@Test
void getFileExtension_whenFileNameHasExtensionInUpperCase_thenReturnLowerCaseExtension() {
assertEquals(".pdf", InvoiceServiceImpl.getFileExtension("filename.PDF"));
}
}
@@ -2,6 +2,7 @@ package com.cf.imes.module.system.service.funds.productpromotion;
import cn.hutool.core.bean.BeanUtil;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.common.util.i18n.core.util.I18nUtils;
import com.cf.imes.framework.test.core.ut.BaseDbClearAfterClassAndRedisUnitTest;
import com.cf.imes.module.system.controller.admin.funds.productpromotion.vo.ProductPromotionPageReqVO;
import com.cf.imes.module.system.controller.admin.funds.productpromotion.vo.ProductPromotionSaveReqVO;
@@ -50,6 +51,9 @@ class ProductPromotionServiceImplTest extends BaseDbClearAfterClassAndRedisUnitT
@MockitoBean
private ProductsDetailService productsDetailService;
@MockitoBean
private I18nUtils i18nUtils;
private static ProductPromotionDO createDO;
@Test
@@ -5,7 +5,6 @@ import com.cf.imes.framework.common.enums.CommonStatusEnum;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.common.util.collection.ArrayUtils;
import com.cf.imes.framework.common.util.collection.CollectionUtils;
import com.cf.imes.framework.test.core.ut.BaseDbUnitTest;
import com.cf.imes.module.infra.api.file.FileApi;
import com.cf.imes.module.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO;
@@ -15,11 +14,8 @@ import com.cf.imes.module.system.controller.admin.user.vo.user.UserImportRespVO;
import com.cf.imes.module.system.controller.admin.user.vo.user.UserPageReqVO;
import com.cf.imes.module.system.controller.admin.user.vo.user.UserSaveReqVO;
import com.cf.imes.module.system.dal.dataobject.dept.DeptDO;
import com.cf.imes.module.system.dal.dataobject.dept.PostDO;
import com.cf.imes.module.system.dal.dataobject.dept.UserPostDO;
import com.cf.imes.module.system.dal.dataobject.organ.OrganizationDO;
import com.cf.imes.module.system.dal.dataobject.user.AdminUserDO;
import com.cf.imes.module.system.dal.mysql.dept.UserPostMapper;
import com.cf.imes.module.system.dal.mysql.user.AdminUserMapper;
import com.cf.imes.module.system.enums.common.SexEnum;
import com.cf.imes.module.system.service.dept.DeptService;
@@ -27,11 +23,12 @@ import com.cf.imes.module.system.service.permission.PermissionService;
import com.cf.imes.module.system.service.organ.OrganService;
import org.junit.jupiter.api.Test;
import org.mockito.stubbing.Answer;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.security.crypto.password.PasswordEncoder;
import static com.cf.imes.framework.test.core.util.RandomUtils.*;
import jakarta.annotation.Resource;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import java.io.ByteArrayInputStream;
import java.util.Collection;
import java.util.List;
@@ -62,18 +59,16 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest {
@Resource
private AdminUserMapper userMapper;
@Resource
private UserPostMapper userPostMapper;
@MockBean
@MockitoBean
private DeptService deptService;
@MockBean
@MockitoBean
private PermissionService permissionService;
@MockBean
@MockitoBean
private PasswordEncoder passwordEncoder;
@MockBean
@MockitoBean
private OrganService tenantService;
@MockBean
@MockitoBean
private FileApi fileApi;
@Test
@@ -96,13 +91,6 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest {
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
});
when(deptService.getDept(eq(dept.getId()))).thenReturn(dept);
// mock postService 的方法
List<PostDO> posts = CollectionUtils.convertList(reqVO.getPostIds(), postId ->
randomPojo(PostDO.class, o -> {
o.setId(postId);
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
}));
//when(postService.getPostList(eq(reqVO.getPostIds()), isNull())).thenReturn(posts);
// 调用
Long userId = userService.createUser(reqVO);
@@ -111,10 +99,6 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest {
assertPojoEquals(reqVO, user, "password", "id");
assertEquals("chenfengyuanma", user.getPassword());
assertEquals(CommonStatusEnum.ENABLE.getStatus(), user.getStatus());
// 断言关联岗位
List<UserPostDO> userPosts = userPostMapper.selectListByUserId(user.getId());
assertEquals(1L, userPosts.get(0).getPostId());
assertEquals(2L, userPosts.get(1).getPostId());
}
@Test
@@ -137,8 +121,6 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest {
// mock 数据
AdminUserDO dbUser = randomAdminUserDO(o -> o.setPostIds(asSet(1L, 2L)));
userMapper.insert(dbUser);
userPostMapper.insert(new UserPostDO().setUserId(dbUser.getId()).setPostId(1L));
userPostMapper.insert(new UserPostDO().setUserId(dbUser.getId()).setPostId(2L));
// 准备参数
UserSaveReqVO reqVO = randomPojo(UserSaveReqVO.class, o -> {
o.setId(dbUser.getId());
@@ -152,23 +134,12 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest {
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
});
when(deptService.getDept(eq(dept.getId()))).thenReturn(dept);
// mock postService 的方法
List<PostDO> posts = CollectionUtils.convertList(reqVO.getPostIds(), postId ->
randomPojo(PostDO.class, o -> {
o.setId(postId);
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
}));
//when(postService.getPostList(eq(reqVO.getPostIds()), isNull())).thenReturn(posts);
// 调用
userService.updateUser(reqVO);
// 断言
AdminUserDO user = userMapper.selectById(reqVO.getId());
assertPojoEquals(reqVO, user, "password");
// 断言关联岗位
List<UserPostDO> userPosts = userPostMapper.selectListByUserId(user.getId());
assertEquals(2L, userPosts.get(0).getPostId());
assertEquals(3L, userPosts.get(1).getPostId());
}
@Test
@@ -627,12 +598,10 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest {
// mock user1 数据
AdminUserDO user1 = randomAdminUserDO(o -> o.setPostIds(asSet(10L, 30L)));
userMapper.insert(user1);
userPostMapper.insert(new UserPostDO().setUserId(user1.getId()).setPostId(10L));
userPostMapper.insert(new UserPostDO().setUserId(user1.getId()).setPostId(30L));
// mock user2 数据
AdminUserDO user2 = randomAdminUserDO(o -> o.setPostIds(singleton(100L)));
userMapper.insert(user2);
userPostMapper.insert(new UserPostDO().setUserId(user2.getId()).setPostId(100L));
// 调用
List<AdminUserDO> result = userService.getUserListByPostIds(postIds);
@@ -40,4 +40,7 @@ DELETE FROM "products_details";
DELETE FROM "product_promotion";
DELETE FROM "advertisement";
DELETE FROM "product_delay_record";
DELETE FROM "purchase_record"
DELETE FROM "purchase_record";
DELETE FROM "income_expense_details";
DELETE FROM "invoice_title_info";
DELETE FROM "invoice_records";
@@ -808,3 +808,77 @@ CREATE TABLE IF NOT EXISTS "purchase_record"
"deleted" BIT NOT NULL DEFAULT FALSE COMMENT '是否删除:0否 1是',
PRIMARY KEY ("id")
) COMMENT '购买记录表';
CREATE TABLE IF NOT EXISTS "income_expense_details"
(
"id" BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT 'ID,主键',
"business_no" VARCHAR(64) DEFAULT NULL COMMENT '流水号',
"order_no" VARCHAR(64) DEFAULT NULL COMMENT '订单号',
"gift_money_id" BIGINT DEFAULT NULL COMMENT '充值-赠送金规则ID',
"purchase_id" BIGINT DEFAULT NULL COMMENT '购买-购买记录ID',
"organ_id" BIGINT NOT NULL DEFAULT '0' COMMENT '组织ID',
"trade_type" TINYINT NOT NULL COMMENT '交易类型 0充值 1软件购买',
"income_expense_type" TINYINT NOT NULL COMMENT '收支类型 0收入 1支出',
"cash_amount_change" DECIMAL(10, 2) NOT NULL DEFAULT '0.00' COMMENT '支出/入账现金金额',
"gift_amount_change" DECIMAL(10, 2) NOT NULL DEFAULT '0.00' COMMENT '支出/入账赠送金金额',
"available_amount" DECIMAL(10, 2) NOT NULL DEFAULT '0.00' COMMENT '可用余额(现金+赠送金)',
"amount" DECIMAL(10, 2) DEFAULT NULL COMMENT '现金余额',
"gift_amount" DECIMAL(10, 2) DEFAULT NULL COMMENT '赠送余额',
"currency" TINYINT DEFAULT NULL COMMENT '货币类型(字典)',
"currency_unit" VARCHAR(10) DEFAULT NULL COMMENT '货币单位',
"creator" VARCHAR(64) DEFAULT NULL COMMENT '创建者/操作人',
"create_time" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间/交易时间',
"updater" VARCHAR(64) DEFAULT NULL COMMENT '更新者',
"update_time" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
"remark" VARCHAR(255) DEFAULT NULL COMMENT '备注',
"deleted" BIT NOT NULL DEFAULT FALSE COMMENT '是否删除 0否 1是',
PRIMARY KEY ("id")
) COMMENT '收支明细表';
CREATE TABLE IF NOT EXISTS "invoice_title_info"
(
"id" BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '主键,根据ID号规则生成',
"organ_id" BIGINT NOT NULL COMMENT '组织ID',
"invoice_title" VARCHAR(64) NOT NULL COMMENT '发票抬头',
"issue_type" TINYINT NOT NULL COMMENT '开具类型,0企业 1个人',
"invoice_type" TINYINT NOT NULL DEFAULT '0' COMMENT '发票类型,0增值税普通发票 1增值税专用发票',
"tax_number" VARCHAR(18) DEFAULT NULL COMMENT '统一社会信用代码',
"bank_name" VARCHAR(64) DEFAULT NULL COMMENT '开户银行名称',
"bank_account" VARCHAR(40) DEFAULT NULL COMMENT '开户银行账号',
"registered_address" VARCHAR(64) DEFAULT NULL COMMENT '注册场所地址',
"fixed_phone" VARCHAR(20) DEFAULT NULL COMMENT '注册固定电话',
"email" VARCHAR(255) DEFAULT '' COMMENT '邮箱',
"creator" VARCHAR(64) DEFAULT NULL COMMENT '创建者',
"create_time" TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
"updater" VARCHAR(64) DEFAULT NULL COMMENT '更新者',
"update_time" TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
"deleted" BIT DEFAULT FALSE COMMENT '是否删除,0否1是',
PRIMARY KEY ("id")
) COMMENT '发票抬头信息表';
CREATE TABLE IF NOT EXISTS "invoice_records"
(
"id" BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '发票记录ID',
"organ_id" BIGINT NOT NULL DEFAULT '0' COMMENT '组织ID',
"organ_name" VARCHAR(30) DEFAULT NULL COMMENT '组织/发票抬头名称',
"user_id" BIGINT NOT NULL COMMENT '发票申请人ID',
"invoice_no" VARCHAR(32) DEFAULT NULL COMMENT '发票号',
"purchase_ids" VARCHAR(2048) DEFAULT NULL COMMENT '购买记录id集合',
"invoice_amount" DECIMAL(10, 2) NOT NULL DEFAULT '0.00' COMMENT '发票金额',
"status" TINYINT NOT NULL COMMENT '发票状态 1待开票 2已开票 3开票失败',
"invoice_attachment_path" VARCHAR(255) DEFAULT NULL COMMENT '发票附件保存路径',
"invoice_attachment_id" BIGINT DEFAULT NULL COMMENT '发票附件文件id',
"invoice_attachment_name" VARCHAR(255) DEFAULT NULL COMMENT '发票附件名称',
"invoice_person" VARCHAR(64) DEFAULT NULL COMMENT '开票人',
"invoice_person_id" BIGINT DEFAULT NULL COMMENT '开票人用户ID',
"invoice_time" TIMESTAMP DEFAULT NULL COMMENT '开票时间',
"invoice_title_id" BIGINT DEFAULT NULL COMMENT '抬头ID',
"invoice_title_info" CLOB DEFAULT NULL COMMENT '抬头的信息',
"remark" VARCHAR(1024) DEFAULT NULL COMMENT '备注',
"creator" VARCHAR(64) DEFAULT NULL COMMENT '创建者/申请人',
"create_time" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间/申请时间',
"updater" VARCHAR(64) DEFAULT NULL COMMENT '更新者',
"update_time" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
"deleted" BIT NOT NULL DEFAULT FALSE COMMENT '是否删除 0否1是',
PRIMARY KEY ("id")
) COMMENT '开票记录表';