mirror of
https://codeup.aliyun.com/67c68d4e484ca2f0a13ac3c1/ydc/jsowell-charger-web.git
synced 2026-07-18 21:18:01 +08:00
接入司机开票申请待办流程
This commit is contained in:
@@ -46,9 +46,9 @@ PRD 同时要求“幂等键唯一”和“任务完成后允许同一业务重
|
||||
| B03 | 当前用户查询、已读、完成、取消接口及测试 | P0 | done | 全量依赖编译、9 个专项测试通过 | `f84ec43ce` |
|
||||
| B04 | 前端 API、待办中心页面和路由跳转 | P0 | done | ESLint 和生产构建通过 | 前端 `ff6b890` |
|
||||
| B05 | 首页待办卡片、数量展示和轮询刷新 | P0 | done | ESLint 和生产构建通过 | 前端 `0627061` |
|
||||
| B06 | 菜单权限 SQL、联调和首期回归 | P0 | done | 菜单 SQL、构建和专项回归通过;待测试库执行 SQL | 本批提交 |
|
||||
| B07 | 平台采购开票待办接入 | P1 | todo | - | - |
|
||||
| B08 | 司机开票申请待办接入 | P1 | todo | - | - |
|
||||
| B06 | 菜单权限 SQL、联调和首期回归 | P0 | done | 菜单 SQL、构建和专项回归通过;待测试库执行 SQL | `974e68cf5` |
|
||||
| B07 | 平台采购开票待办接入 | P1 | blocked | 仓库内未找到平台采购开票模型、审核状态或接口入口 | - |
|
||||
| B08 | 司机开票申请待办接入 | P1 | done | 全依赖编译、12 个专项测试通过 | 本批提交 |
|
||||
| B09 | 管理端创建、分配、取消和隐藏能力 | P1 | todo | - | - |
|
||||
| B10 | 归档清理、过期任务和操作审计增强 | P2 | todo | - | - |
|
||||
| B11 | 路由白名单、性能压测和安全专项验证 | P2 | todo | - | - |
|
||||
@@ -121,7 +121,7 @@ PRD 同时要求“幂等键唯一”和“任务完成后允许同一业务重
|
||||
|
||||
- 优先级:P0
|
||||
- 批次:B06
|
||||
- 状态:in_progress
|
||||
- 状态:done
|
||||
- 当前进展:
|
||||
- 菜单、查询、已读、完成和取消权限 SQL 已完成。
|
||||
- 列表、查询和已读权限默认授予正常角色;完成和取消权限保留为按业务角色授权。
|
||||
@@ -138,7 +138,8 @@ PRD 同时要求“幂等键唯一”和“任务完成后允许同一业务重
|
||||
|
||||
- 优先级:P1
|
||||
- 批次:B07
|
||||
- 状态:todo
|
||||
- 状态:blocked
|
||||
- 阻塞原因:当前仓库检索不到平台采购开票对应的数据库模型、审核拒绝/补充材料状态和业务接口,无法安全判断创建与完成时机。
|
||||
- 目标:在平台采购开票审核拒绝或要求补充材料时创建待办,重新提交或平台关闭时完成。
|
||||
- 验收标准:同一开票事件对同一接收人只产生一条有效待办,跳转参数和完成条件正确。
|
||||
|
||||
@@ -146,7 +147,7 @@ PRD 同时要求“幂等键唯一”和“任务完成后允许同一业务重
|
||||
|
||||
- 优先级:P1
|
||||
- 批次:B08
|
||||
- 状态:todo
|
||||
- 状态:in_progress
|
||||
- 目标:收到司机开票申请时创建待办,审核通过、驳回或关闭时完成。
|
||||
- 验收标准:创建和完成与开票业务事务一致,异常回滚时不产生脏任务状态。
|
||||
|
||||
@@ -184,4 +185,6 @@ PRD 同时要求“幂等键唯一”和“任务完成后允许同一业务重
|
||||
- 2026-07-16,B03:完成当前用户数量、首页列表、分页列表、详情、已读、全部已读、完成和取消接口;`mvn -pl jsowell-admin -am -DskipTests compile` 通过,9 个 Service/Controller 专项测试通过;commit `f84ec43ce`。
|
||||
- 2026-07-16,B04:完成前端 API、待办中心筛选分页、批量已读和安全路由跳转;新增文件专项 ESLint 通过,`NODE_OPTIONS=--openssl-legacy-provider npm run build:prd` 构建通过;前端 commit `ff6b890`。
|
||||
- 2026-07-16,B05:完成首页右侧待办卡片、`99+` 数量、最近 3 条、空状态、错误重试和 60 秒轮询;专项 ESLint 与生产构建通过;前端 commit `0627061`。
|
||||
- 2026-07-16,B06:完成幂等菜单/权限 SQL;列表、查询和已读权限默认授予正常角色,完成和取消权限需按业务角色显式授权;后端 9 个专项测试再次通过,前端构建沿用 B05 验证结果;commit hash 在下一批记录中回填。
|
||||
- 2026-07-16,B06:完成幂等菜单/权限 SQL;列表、查询和已读权限默认授予正常角色,完成和取消权限需按业务角色显式授权;后端 9 个专项测试再次通过,前端构建沿用 B05 验证结果;commit `974e68cf5`。
|
||||
- 2026-07-16,B07 分析:当前仓库未发现平台采购开票业务落点,需补充对应模块/表/接口信息后继续。
|
||||
- 2026-07-16,B08:司机开票记录创建后,按运营商部门树为正常后台用户幂等创建待办;开票状态更新为已开票时自动完成,删除/关闭记录时自动取消;业务与待办状态处于同一事务;全依赖编译和 12 个专项测试通过;commit hash 在下一批记录中回填。
|
||||
|
||||
@@ -90,7 +90,7 @@ public class OrderInvoiceRecordController extends BaseController {
|
||||
@Log(title = "申请开票", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@RequestBody OrderInvoiceRecord orderInvoiceRecord) {
|
||||
return toAjax(orderInvoiceRecordService.updateOrderInvoiceRecord(orderInvoiceRecord));
|
||||
return toAjax(orderInvoiceRecordService.updateOrderInvoiceRecord(orderInvoiceRecord, getUserId(), getUsername()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,6 +100,6 @@ public class OrderInvoiceRecordController extends BaseController {
|
||||
@Log(title = "申请开票", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public AjaxResult remove(@PathVariable Integer[] ids) {
|
||||
return toAjax(orderInvoiceRecordService.deleteOrderInvoiceRecordByIds(ids));
|
||||
return toAjax(orderInvoiceRecordService.deleteOrderInvoiceRecordByIds(ids, getUsername()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
package com.jsowell.pile.service;
|
||||
|
||||
import com.jsowell.pile.domain.OrderInvoiceRecord;
|
||||
import com.jsowell.pile.domain.PileMerchantInfo;
|
||||
import com.jsowell.pile.mapper.OrderInvoiceRecordMapper;
|
||||
import com.jsowell.pile.service.impl.OrderInvoiceRecordServiceImpl;
|
||||
import com.jsowell.system.constant.TodoTaskConstants;
|
||||
import com.jsowell.system.domain.SysTodoTask;
|
||||
import com.jsowell.system.domain.dto.TodoTaskCreateCommand;
|
||||
import com.jsowell.system.service.TodoTaskAssigneeService;
|
||||
import com.jsowell.system.service.TodoTaskService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class OrderInvoiceRecordTodoTest {
|
||||
@Test
|
||||
void insert_shouldCreateTodoForEachMerchantUser() {
|
||||
OrderInvoiceRecordMapper mapper = mock(OrderInvoiceRecordMapper.class);
|
||||
PileMerchantInfoService merchantService = mock(PileMerchantInfoService.class);
|
||||
TodoTaskAssigneeService assigneeService = mock(TodoTaskAssigneeService.class);
|
||||
TodoTaskService todoTaskService = mock(TodoTaskService.class);
|
||||
OrderInvoiceRecordServiceImpl service = newService(mapper, merchantService, assigneeService, todoTaskService);
|
||||
|
||||
OrderInvoiceRecord invoiceRecord = new OrderInvoiceRecord();
|
||||
invoiceRecord.setMerchantId("100");
|
||||
doAnswer(invocation -> {
|
||||
OrderInvoiceRecord record = invocation.getArgument(0);
|
||||
record.setId(55);
|
||||
return 1;
|
||||
}).when(mapper).insertOrderInvoiceRecord(invoiceRecord);
|
||||
|
||||
PileMerchantInfo merchantInfo = new PileMerchantInfo();
|
||||
merchantInfo.setDeptId("200");
|
||||
when(merchantService.selectPileMerchantInfoById(100L)).thenReturn(merchantInfo);
|
||||
when(assigneeService.findActiveUserIdsByDeptTree(200L)).thenReturn(Arrays.asList(8L, 9L));
|
||||
when(todoTaskService.createTask(any(TodoTaskCreateCommand.class))).thenReturn(new SysTodoTask());
|
||||
|
||||
service.insertOrderInvoiceRecord(invoiceRecord);
|
||||
|
||||
ArgumentCaptor<TodoTaskCreateCommand> captor = ArgumentCaptor.forClass(TodoTaskCreateCommand.class);
|
||||
verify(todoTaskService, times(2)).createTask(captor.capture());
|
||||
List<TodoTaskCreateCommand> commands = captor.getAllValues();
|
||||
assertEquals(Arrays.asList(8L, 9L), Arrays.asList(
|
||||
commands.get(0).getAssigneeUserId(), commands.get(1).getAssigneeUserId()));
|
||||
assertEquals("ORDER_INVOICE_RECORD", commands.get(0).getBusinessType());
|
||||
assertEquals("55", commands.get(0).getBusinessId());
|
||||
assertEquals("invoiceDetail", commands.get(0).getRouteName());
|
||||
assertEquals(TodoTaskConstants.PRIORITY_IMPORTANT, commands.get(0).getPriority());
|
||||
assertEquals("INVOICE_REVIEW:ORDER_INVOICE_RECORD:55:8", commands.get(0).getIdempotentKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateCompleted_shouldCompleteBusinessTodos() {
|
||||
OrderInvoiceRecordMapper mapper = mock(OrderInvoiceRecordMapper.class);
|
||||
TodoTaskService todoTaskService = mock(TodoTaskService.class);
|
||||
OrderInvoiceRecordServiceImpl service = newService(mapper, mock(PileMerchantInfoService.class),
|
||||
mock(TodoTaskAssigneeService.class), todoTaskService);
|
||||
OrderInvoiceRecord invoiceRecord = new OrderInvoiceRecord();
|
||||
invoiceRecord.setId(55);
|
||||
invoiceRecord.setStatus("1");
|
||||
when(mapper.updateOrderInvoiceRecord(invoiceRecord)).thenReturn(1);
|
||||
|
||||
service.updateOrderInvoiceRecord(invoiceRecord, 1L, "admin");
|
||||
|
||||
verify(todoTaskService).completeByBusiness("ORDER_INVOICE_RECORD", "55", null, 1L, "admin");
|
||||
}
|
||||
|
||||
@Test
|
||||
void delete_shouldCancelBusinessTodos() {
|
||||
OrderInvoiceRecordMapper mapper = mock(OrderInvoiceRecordMapper.class);
|
||||
TodoTaskService todoTaskService = mock(TodoTaskService.class);
|
||||
OrderInvoiceRecordServiceImpl service = newService(mapper, mock(PileMerchantInfoService.class),
|
||||
mock(TodoTaskAssigneeService.class), todoTaskService);
|
||||
Integer[] ids = { 55, 56 };
|
||||
when(mapper.deleteOrderInvoiceRecordByIds(ids)).thenReturn(2);
|
||||
|
||||
service.deleteOrderInvoiceRecordByIds(ids, "admin");
|
||||
|
||||
verify(todoTaskService).cancelByBusiness("ORDER_INVOICE_RECORD", "55", null,
|
||||
"admin", "开票申请已关闭");
|
||||
verify(todoTaskService).cancelByBusiness("ORDER_INVOICE_RECORD", "56", null,
|
||||
"admin", "开票申请已关闭");
|
||||
}
|
||||
|
||||
private static OrderInvoiceRecordServiceImpl newService(OrderInvoiceRecordMapper mapper,
|
||||
PileMerchantInfoService merchantService, TodoTaskAssigneeService assigneeService,
|
||||
TodoTaskService todoTaskService) {
|
||||
OrderInvoiceRecordServiceImpl service = new OrderInvoiceRecordServiceImpl();
|
||||
setField(service, "orderInvoiceRecordMapper", mapper);
|
||||
setField(service, "pileMerchantInfoService", merchantService);
|
||||
setField(service, "todoTaskAssigneeService", assigneeService);
|
||||
setField(service, "todoTaskService", todoTaskService);
|
||||
return service;
|
||||
}
|
||||
|
||||
private static void setField(Object target, String fieldName, Object value) {
|
||||
try {
|
||||
Field field = target.getClass().getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
field.set(target, value);
|
||||
} catch (Exception exception) {
|
||||
throw new RuntimeException(exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,7 +61,7 @@ public interface OrderInvoiceRecordService {
|
||||
* @param orderInvoiceRecord 申请开票
|
||||
* @return 结果
|
||||
*/
|
||||
public int updateOrderInvoiceRecord(OrderInvoiceRecord orderInvoiceRecord);
|
||||
public int updateOrderInvoiceRecord(OrderInvoiceRecord orderInvoiceRecord, Long operatorId, String operatorName);
|
||||
|
||||
/**
|
||||
* 批量删除申请开票
|
||||
@@ -69,7 +69,7 @@ public interface OrderInvoiceRecordService {
|
||||
* @param ids 需要删除的申请开票主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteOrderInvoiceRecordByIds(Integer[] ids);
|
||||
public int deleteOrderInvoiceRecordByIds(Integer[] ids, String operatorName);
|
||||
|
||||
/**
|
||||
* 删除申请开票信息
|
||||
@@ -77,5 +77,5 @@ public interface OrderInvoiceRecordService {
|
||||
* @param id 申请开票主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteOrderInvoiceRecordById(Integer id);
|
||||
public int deleteOrderInvoiceRecordById(Integer id, String operatorName);
|
||||
}
|
||||
|
||||
@@ -2,21 +2,31 @@ package com.jsowell.pile.service.impl;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.jsowell.common.core.domain.vo.AuthorizedDeptVO;
|
||||
import com.jsowell.common.util.StringUtils;
|
||||
import com.jsowell.pile.domain.OrderInvoiceRecord;
|
||||
import com.jsowell.pile.domain.PileMerchantInfo;
|
||||
import com.jsowell.pile.dto.GetInvoiceInfoDTO;
|
||||
import com.jsowell.pile.dto.QueryInvoiceRecordDTO;
|
||||
import com.jsowell.pile.mapper.OrderInvoiceRecordMapper;
|
||||
import com.jsowell.pile.service.MemberInvoiceTitleService;
|
||||
import com.jsowell.pile.service.OrderInvoiceRecordService;
|
||||
import com.jsowell.pile.service.OrderBasicInfoService;
|
||||
import com.jsowell.pile.service.PileMerchantInfoService;
|
||||
import com.jsowell.pile.util.UserUtils;
|
||||
import com.jsowell.pile.vo.base.OrderAmountDetailVO;
|
||||
import com.jsowell.pile.vo.uniapp.customer.InvoiceTitleVO;
|
||||
import com.jsowell.pile.vo.web.InvoiceRecordVO;
|
||||
import com.jsowell.pile.vo.web.OrderInvoiceRecordVO;
|
||||
import com.jsowell.system.constant.TodoTaskConstants;
|
||||
import com.jsowell.system.domain.dto.TodoTaskCreateCommand;
|
||||
import com.jsowell.system.service.TodoTaskAssigneeService;
|
||||
import com.jsowell.system.service.TodoTaskService;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
@@ -30,6 +40,11 @@ import java.util.List;
|
||||
*/
|
||||
@Service
|
||||
public class OrderInvoiceRecordServiceImpl implements OrderInvoiceRecordService {
|
||||
private static final Logger log = LoggerFactory.getLogger(OrderInvoiceRecordServiceImpl.class);
|
||||
private static final String TODO_TASK_TYPE = "INVOICE_REVIEW";
|
||||
private static final String TODO_BUSINESS_TYPE = "ORDER_INVOICE_RECORD";
|
||||
private static final String TODO_ROUTE_NAME = "invoiceDetail";
|
||||
|
||||
@Autowired
|
||||
private OrderInvoiceRecordMapper orderInvoiceRecordMapper;
|
||||
|
||||
@@ -39,6 +54,15 @@ public class OrderInvoiceRecordServiceImpl implements OrderInvoiceRecordService
|
||||
@Autowired
|
||||
private OrderBasicInfoService orderBasicInfoService;
|
||||
|
||||
@Autowired
|
||||
private PileMerchantInfoService pileMerchantInfoService;
|
||||
|
||||
@Autowired
|
||||
private TodoTaskAssigneeService todoTaskAssigneeService;
|
||||
|
||||
@Autowired
|
||||
private TodoTaskService todoTaskService;
|
||||
|
||||
/**
|
||||
* 查询申请开票
|
||||
*
|
||||
@@ -132,8 +156,13 @@ public class OrderInvoiceRecordServiceImpl implements OrderInvoiceRecordService
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int insertOrderInvoiceRecord(OrderInvoiceRecord orderInvoiceRecord) {
|
||||
return orderInvoiceRecordMapper.insertOrderInvoiceRecord(orderInvoiceRecord);
|
||||
int rows = orderInvoiceRecordMapper.insertOrderInvoiceRecord(orderInvoiceRecord);
|
||||
if (rows > 0) {
|
||||
createInvoiceReviewTodos(orderInvoiceRecord);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,8 +172,14 @@ public class OrderInvoiceRecordServiceImpl implements OrderInvoiceRecordService
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int updateOrderInvoiceRecord(OrderInvoiceRecord orderInvoiceRecord) {
|
||||
return orderInvoiceRecordMapper.updateOrderInvoiceRecord(orderInvoiceRecord);
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int updateOrderInvoiceRecord(OrderInvoiceRecord orderInvoiceRecord, Long operatorId, String operatorName) {
|
||||
int rows = orderInvoiceRecordMapper.updateOrderInvoiceRecord(orderInvoiceRecord);
|
||||
if (rows > 0 && "1".equals(orderInvoiceRecord.getStatus())) {
|
||||
todoTaskService.completeByBusiness(TODO_BUSINESS_TYPE, String.valueOf(orderInvoiceRecord.getId()),
|
||||
null, operatorId, operatorName);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,8 +189,18 @@ public class OrderInvoiceRecordServiceImpl implements OrderInvoiceRecordService
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int deleteOrderInvoiceRecordByIds(Integer[] ids) {
|
||||
return orderInvoiceRecordMapper.deleteOrderInvoiceRecordByIds(ids);
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int deleteOrderInvoiceRecordByIds(Integer[] ids, String operatorName) {
|
||||
int rows = orderInvoiceRecordMapper.deleteOrderInvoiceRecordByIds(ids);
|
||||
if (rows > 0 && ids != null) {
|
||||
for (Integer id : ids) {
|
||||
if (id != null) {
|
||||
todoTaskService.cancelByBusiness(TODO_BUSINESS_TYPE, String.valueOf(id), null,
|
||||
operatorName, "开票申请已关闭");
|
||||
}
|
||||
}
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -165,7 +210,71 @@ public class OrderInvoiceRecordServiceImpl implements OrderInvoiceRecordService
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int deleteOrderInvoiceRecordById(Integer id) {
|
||||
return orderInvoiceRecordMapper.deleteOrderInvoiceRecordById(id);
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int deleteOrderInvoiceRecordById(Integer id, String operatorName) {
|
||||
int rows = orderInvoiceRecordMapper.deleteOrderInvoiceRecordById(id);
|
||||
if (rows > 0) {
|
||||
todoTaskService.cancelByBusiness(TODO_BUSINESS_TYPE, String.valueOf(id), null,
|
||||
operatorName, "开票申请已关闭");
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
private void createInvoiceReviewTodos(OrderInvoiceRecord invoiceRecord) {
|
||||
if (invoiceRecord.getId() == null || StringUtils.isBlank(invoiceRecord.getMerchantId())) {
|
||||
log.warn("开票申请缺少主键或运营商,无法创建待办,invoiceId={}, merchantId={}",
|
||||
invoiceRecord.getId(), invoiceRecord.getMerchantId());
|
||||
return;
|
||||
}
|
||||
|
||||
PileMerchantInfo merchantInfo;
|
||||
try {
|
||||
merchantInfo = pileMerchantInfoService.selectPileMerchantInfoById(Long.parseLong(invoiceRecord.getMerchantId()));
|
||||
} catch (NumberFormatException exception) {
|
||||
log.warn("开票申请运营商 ID 非法,无法创建待办,invoiceId={}, merchantId={}",
|
||||
invoiceRecord.getId(), invoiceRecord.getMerchantId());
|
||||
return;
|
||||
}
|
||||
|
||||
if (merchantInfo == null || StringUtils.isBlank(merchantInfo.getDeptId())) {
|
||||
log.warn("开票申请运营商未配置部门,无法创建待办,invoiceId={}, merchantId={}",
|
||||
invoiceRecord.getId(), invoiceRecord.getMerchantId());
|
||||
return;
|
||||
}
|
||||
|
||||
Long merchantDeptId;
|
||||
try {
|
||||
merchantDeptId = Long.parseLong(merchantInfo.getDeptId());
|
||||
} catch (NumberFormatException exception) {
|
||||
log.warn("开票申请运营商部门 ID 非法,无法创建待办,invoiceId={}, deptId={}",
|
||||
invoiceRecord.getId(), merchantInfo.getDeptId());
|
||||
return;
|
||||
}
|
||||
|
||||
List<Long> assigneeUserIds = todoTaskAssigneeService.findActiveUserIdsByDeptTree(merchantDeptId);
|
||||
if (CollectionUtils.isEmpty(assigneeUserIds)) {
|
||||
log.warn("开票申请运营商部门下没有正常用户,无法创建待办,invoiceId={}, deptId={}",
|
||||
invoiceRecord.getId(), merchantInfo.getDeptId());
|
||||
return;
|
||||
}
|
||||
|
||||
for (Long assigneeUserId : assigneeUserIds) {
|
||||
String idempotentKey = TODO_TASK_TYPE + ":" + TODO_BUSINESS_TYPE + ":"
|
||||
+ invoiceRecord.getId() + ":" + assigneeUserId;
|
||||
todoTaskService.createTask(TodoTaskCreateCommand.builder()
|
||||
.taskType(TODO_TASK_TYPE)
|
||||
.title("司机开票申请")
|
||||
.summary("有新的司机开票申请需要处理,申请单号:" + invoiceRecord.getId())
|
||||
.businessType(TODO_BUSINESS_TYPE)
|
||||
.businessId(String.valueOf(invoiceRecord.getId()))
|
||||
.routeName(TODO_ROUTE_NAME)
|
||||
.routeParams("{\"params\":{\"id\":\"" + invoiceRecord.getId() + "\"}}")
|
||||
.assigneeUserId(assigneeUserId)
|
||||
.assigneeMerchantId(invoiceRecord.getMerchantId())
|
||||
.priority(TodoTaskConstants.PRIORITY_IMPORTANT)
|
||||
.idempotentKey(idempotentKey)
|
||||
.createBy("invoice-system")
|
||||
.build());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,4 +56,10 @@ public interface SysTodoTaskMapper {
|
||||
int cancelTodo(@Param("todoId") Long todoId,
|
||||
@Param("reason") String reason,
|
||||
@Param("updateBy") String updateBy);
|
||||
|
||||
int cancelTodoByBusiness(@Param("businessType") String businessType,
|
||||
@Param("businessId") String businessId,
|
||||
@Param("assigneeUserId") Long assigneeUserId,
|
||||
@Param("reason") String reason,
|
||||
@Param("updateBy") String updateBy);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,14 @@ public interface SysUserMapper {
|
||||
*/
|
||||
List<SysUser> selectUserList(SysUser sysUser);
|
||||
|
||||
/**
|
||||
* 查询部门及下级部门的正常用户 ID。
|
||||
*
|
||||
* @param deptId 部门 ID
|
||||
* @return 用户 ID 集合
|
||||
*/
|
||||
List<Long> selectActiveUserIdsByDeptTree(@Param("deptId") Long deptId);
|
||||
|
||||
/**
|
||||
* 根据条件分页查询已配用户角色列表
|
||||
*
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.jsowell.system.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 待办接收人解析服务。
|
||||
*
|
||||
* @author jsowell
|
||||
*/
|
||||
public interface TodoTaskAssigneeService {
|
||||
List<Long> findActiveUserIdsByDeptTree(Long deptId);
|
||||
}
|
||||
@@ -36,4 +36,7 @@ public interface TodoTaskService {
|
||||
boolean cancelForAssignee(Long todoId, Long assigneeUserId, String operatorName, String reason);
|
||||
|
||||
boolean cancel(Long todoId, Long operatorId, String operatorName, String reason);
|
||||
|
||||
int cancelByBusiness(String businessType, String businessId, Long assigneeUserId,
|
||||
String operatorName, String reason);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.jsowell.system.service.impl;
|
||||
|
||||
import com.jsowell.common.exception.ServiceException;
|
||||
import com.jsowell.system.mapper.SysUserMapper;
|
||||
import com.jsowell.system.service.TodoTaskAssigneeService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 待办接收人解析服务实现。
|
||||
*
|
||||
* @author jsowell
|
||||
*/
|
||||
@Service
|
||||
public class TodoTaskAssigneeServiceImpl implements TodoTaskAssigneeService {
|
||||
@Autowired
|
||||
private SysUserMapper userMapper;
|
||||
|
||||
@Override
|
||||
public List<Long> findActiveUserIdsByDeptTree(Long deptId) {
|
||||
if (deptId == null || deptId <= 0) {
|
||||
throw new ServiceException("待办接收部门不能为空");
|
||||
}
|
||||
return userMapper.selectActiveUserIdsByDeptTree(deptId);
|
||||
}
|
||||
}
|
||||
@@ -191,6 +191,20 @@ public class TodoTaskServiceImpl implements TodoTaskService {
|
||||
throw new ServiceException("当前待办状态不允许取消");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int cancelByBusiness(String businessType, String businessId, Long assigneeUserId,
|
||||
String operatorName, String reason) {
|
||||
String safeBusinessType = normalizeRequired(businessType, "业务类型", 64);
|
||||
String safeBusinessId = normalizeRequired(businessId, "业务主键", 64);
|
||||
if (assigneeUserId != null) {
|
||||
validateUserId(assigneeUserId);
|
||||
}
|
||||
String safeReason = normalizeRequired(reason, "取消原因", 500);
|
||||
return todoTaskMapper.cancelTodoByBusiness(safeBusinessType, safeBusinessId, assigneeUserId,
|
||||
safeReason, normalizeOperator(operatorName, null));
|
||||
}
|
||||
|
||||
private SysTodoTask buildTask(TodoTaskCreateCommand command) {
|
||||
if (command.getAssigneeUserId() == null || command.getAssigneeUserId() <= 0) {
|
||||
throw new ServiceException("待办接收用户不能为空");
|
||||
|
||||
@@ -212,4 +212,20 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
and del_flag = '0'
|
||||
</update>
|
||||
|
||||
<update id="cancelTodoByBusiness">
|
||||
update sys_todo_task
|
||||
set task_status = 'CANCELLED',
|
||||
cancel_reason = #{reason},
|
||||
active_idempotent_key = null,
|
||||
update_by = #{updateBy},
|
||||
update_time = sysdate()
|
||||
where business_type = #{businessType}
|
||||
and business_id = #{businessId}
|
||||
<if test="assigneeUserId != null">
|
||||
and assignee_user_id = #{assigneeUserId}
|
||||
</if>
|
||||
and task_status in ('PENDING', 'PROCESSING')
|
||||
and del_flag = '0'
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -91,6 +91,23 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
${params.dataScope}
|
||||
</select>
|
||||
|
||||
<select id="selectActiveUserIdsByDeptTree" resultType="Long">
|
||||
select distinct u.user_id
|
||||
from sys_user u
|
||||
where u.status = '0'
|
||||
and u.del_flag = '0'
|
||||
and (
|
||||
u.dept_id = #{deptId}
|
||||
or u.dept_id in (
|
||||
select d.dept_id
|
||||
from sys_dept d
|
||||
where find_in_set(#{deptId}, d.ancestors)
|
||||
and d.status = '0'
|
||||
)
|
||||
)
|
||||
order by u.user_id
|
||||
</select>
|
||||
|
||||
<select id="selectAllocatedList" parameterType="com.jsowell.common.core.domain.entity.SysUser" resultMap="SysUserResult">
|
||||
select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phone, u.status, u.create_time
|
||||
from sys_user u
|
||||
|
||||
Reference in New Issue
Block a user