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` |
|
| B03 | 当前用户查询、已读、完成、取消接口及测试 | P0 | done | 全量依赖编译、9 个专项测试通过 | `f84ec43ce` |
|
||||||
| B04 | 前端 API、待办中心页面和路由跳转 | P0 | done | ESLint 和生产构建通过 | 前端 `ff6b890` |
|
| B04 | 前端 API、待办中心页面和路由跳转 | P0 | done | ESLint 和生产构建通过 | 前端 `ff6b890` |
|
||||||
| B05 | 首页待办卡片、数量展示和轮询刷新 | P0 | done | ESLint 和生产构建通过 | 前端 `0627061` |
|
| B05 | 首页待办卡片、数量展示和轮询刷新 | P0 | done | ESLint 和生产构建通过 | 前端 `0627061` |
|
||||||
| B06 | 菜单权限 SQL、联调和首期回归 | P0 | done | 菜单 SQL、构建和专项回归通过;待测试库执行 SQL | 本批提交 |
|
| B06 | 菜单权限 SQL、联调和首期回归 | P0 | done | 菜单 SQL、构建和专项回归通过;待测试库执行 SQL | `974e68cf5` |
|
||||||
| B07 | 平台采购开票待办接入 | P1 | todo | - | - |
|
| B07 | 平台采购开票待办接入 | P1 | blocked | 仓库内未找到平台采购开票模型、审核状态或接口入口 | - |
|
||||||
| B08 | 司机开票申请待办接入 | P1 | todo | - | - |
|
| B08 | 司机开票申请待办接入 | P1 | done | 全依赖编译、12 个专项测试通过 | 本批提交 |
|
||||||
| B09 | 管理端创建、分配、取消和隐藏能力 | P1 | todo | - | - |
|
| B09 | 管理端创建、分配、取消和隐藏能力 | P1 | todo | - | - |
|
||||||
| B10 | 归档清理、过期任务和操作审计增强 | P2 | todo | - | - |
|
| B10 | 归档清理、过期任务和操作审计增强 | P2 | todo | - | - |
|
||||||
| B11 | 路由白名单、性能压测和安全专项验证 | P2 | todo | - | - |
|
| B11 | 路由白名单、性能压测和安全专项验证 | P2 | todo | - | - |
|
||||||
@@ -121,7 +121,7 @@ PRD 同时要求“幂等键唯一”和“任务完成后允许同一业务重
|
|||||||
|
|
||||||
- 优先级:P0
|
- 优先级:P0
|
||||||
- 批次:B06
|
- 批次:B06
|
||||||
- 状态:in_progress
|
- 状态:done
|
||||||
- 当前进展:
|
- 当前进展:
|
||||||
- 菜单、查询、已读、完成和取消权限 SQL 已完成。
|
- 菜单、查询、已读、完成和取消权限 SQL 已完成。
|
||||||
- 列表、查询和已读权限默认授予正常角色;完成和取消权限保留为按业务角色授权。
|
- 列表、查询和已读权限默认授予正常角色;完成和取消权限保留为按业务角色授权。
|
||||||
@@ -138,7 +138,8 @@ PRD 同时要求“幂等键唯一”和“任务完成后允许同一业务重
|
|||||||
|
|
||||||
- 优先级:P1
|
- 优先级:P1
|
||||||
- 批次:B07
|
- 批次:B07
|
||||||
- 状态:todo
|
- 状态:blocked
|
||||||
|
- 阻塞原因:当前仓库检索不到平台采购开票对应的数据库模型、审核拒绝/补充材料状态和业务接口,无法安全判断创建与完成时机。
|
||||||
- 目标:在平台采购开票审核拒绝或要求补充材料时创建待办,重新提交或平台关闭时完成。
|
- 目标:在平台采购开票审核拒绝或要求补充材料时创建待办,重新提交或平台关闭时完成。
|
||||||
- 验收标准:同一开票事件对同一接收人只产生一条有效待办,跳转参数和完成条件正确。
|
- 验收标准:同一开票事件对同一接收人只产生一条有效待办,跳转参数和完成条件正确。
|
||||||
|
|
||||||
@@ -146,7 +147,7 @@ PRD 同时要求“幂等键唯一”和“任务完成后允许同一业务重
|
|||||||
|
|
||||||
- 优先级:P1
|
- 优先级:P1
|
||||||
- 批次:B08
|
- 批次: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,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,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,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)
|
@Log(title = "申请开票", businessType = BusinessType.UPDATE)
|
||||||
@PutMapping
|
@PutMapping
|
||||||
public AjaxResult edit(@RequestBody OrderInvoiceRecord orderInvoiceRecord) {
|
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)
|
@Log(title = "申请开票", businessType = BusinessType.DELETE)
|
||||||
@DeleteMapping("/{ids}")
|
@DeleteMapping("/{ids}")
|
||||||
public AjaxResult remove(@PathVariable Integer[] 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 申请开票
|
* @param orderInvoiceRecord 申请开票
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
public int updateOrderInvoiceRecord(OrderInvoiceRecord orderInvoiceRecord);
|
public int updateOrderInvoiceRecord(OrderInvoiceRecord orderInvoiceRecord, Long operatorId, String operatorName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量删除申请开票
|
* 批量删除申请开票
|
||||||
@@ -69,7 +69,7 @@ public interface OrderInvoiceRecordService {
|
|||||||
* @param ids 需要删除的申请开票主键集合
|
* @param ids 需要删除的申请开票主键集合
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
public int deleteOrderInvoiceRecordByIds(Integer[] ids);
|
public int deleteOrderInvoiceRecordByIds(Integer[] ids, String operatorName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除申请开票信息
|
* 删除申请开票信息
|
||||||
@@ -77,5 +77,5 @@ public interface OrderInvoiceRecordService {
|
|||||||
* @param id 申请开票主键
|
* @param id 申请开票主键
|
||||||
* @return 结果
|
* @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.google.common.collect.Lists;
|
||||||
import com.jsowell.common.core.domain.vo.AuthorizedDeptVO;
|
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.OrderInvoiceRecord;
|
||||||
|
import com.jsowell.pile.domain.PileMerchantInfo;
|
||||||
import com.jsowell.pile.dto.GetInvoiceInfoDTO;
|
import com.jsowell.pile.dto.GetInvoiceInfoDTO;
|
||||||
import com.jsowell.pile.dto.QueryInvoiceRecordDTO;
|
import com.jsowell.pile.dto.QueryInvoiceRecordDTO;
|
||||||
import com.jsowell.pile.mapper.OrderInvoiceRecordMapper;
|
import com.jsowell.pile.mapper.OrderInvoiceRecordMapper;
|
||||||
import com.jsowell.pile.service.MemberInvoiceTitleService;
|
import com.jsowell.pile.service.MemberInvoiceTitleService;
|
||||||
import com.jsowell.pile.service.OrderInvoiceRecordService;
|
import com.jsowell.pile.service.OrderInvoiceRecordService;
|
||||||
import com.jsowell.pile.service.OrderBasicInfoService;
|
import com.jsowell.pile.service.OrderBasicInfoService;
|
||||||
|
import com.jsowell.pile.service.PileMerchantInfoService;
|
||||||
import com.jsowell.pile.util.UserUtils;
|
import com.jsowell.pile.util.UserUtils;
|
||||||
import com.jsowell.pile.vo.base.OrderAmountDetailVO;
|
import com.jsowell.pile.vo.base.OrderAmountDetailVO;
|
||||||
import com.jsowell.pile.vo.uniapp.customer.InvoiceTitleVO;
|
import com.jsowell.pile.vo.uniapp.customer.InvoiceTitleVO;
|
||||||
import com.jsowell.pile.vo.web.InvoiceRecordVO;
|
import com.jsowell.pile.vo.web.InvoiceRecordVO;
|
||||||
import com.jsowell.pile.vo.web.OrderInvoiceRecordVO;
|
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.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -30,6 +40,11 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class OrderInvoiceRecordServiceImpl implements OrderInvoiceRecordService {
|
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
|
@Autowired
|
||||||
private OrderInvoiceRecordMapper orderInvoiceRecordMapper;
|
private OrderInvoiceRecordMapper orderInvoiceRecordMapper;
|
||||||
|
|
||||||
@@ -39,6 +54,15 @@ public class OrderInvoiceRecordServiceImpl implements OrderInvoiceRecordService
|
|||||||
@Autowired
|
@Autowired
|
||||||
private OrderBasicInfoService orderBasicInfoService;
|
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 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public int insertOrderInvoiceRecord(OrderInvoiceRecord orderInvoiceRecord) {
|
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 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int updateOrderInvoiceRecord(OrderInvoiceRecord orderInvoiceRecord) {
|
@Transactional(rollbackFor = Exception.class)
|
||||||
return orderInvoiceRecordMapper.updateOrderInvoiceRecord(orderInvoiceRecord);
|
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 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int deleteOrderInvoiceRecordByIds(Integer[] ids) {
|
@Transactional(rollbackFor = Exception.class)
|
||||||
return orderInvoiceRecordMapper.deleteOrderInvoiceRecordByIds(ids);
|
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 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int deleteOrderInvoiceRecordById(Integer id) {
|
@Transactional(rollbackFor = Exception.class)
|
||||||
return orderInvoiceRecordMapper.deleteOrderInvoiceRecordById(id);
|
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,
|
int cancelTodo(@Param("todoId") Long todoId,
|
||||||
@Param("reason") String reason,
|
@Param("reason") String reason,
|
||||||
@Param("updateBy") String updateBy);
|
@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);
|
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 cancelForAssignee(Long todoId, Long assigneeUserId, String operatorName, String reason);
|
||||||
|
|
||||||
boolean cancel(Long todoId, Long operatorId, 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("当前待办状态不允许取消");
|
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) {
|
private SysTodoTask buildTask(TodoTaskCreateCommand command) {
|
||||||
if (command.getAssigneeUserId() == null || command.getAssigneeUserId() <= 0) {
|
if (command.getAssigneeUserId() == null || command.getAssigneeUserId() <= 0) {
|
||||||
throw new ServiceException("待办接收用户不能为空");
|
throw new ServiceException("待办接收用户不能为空");
|
||||||
|
|||||||
@@ -212,4 +212,20 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
and del_flag = '0'
|
and del_flag = '0'
|
||||||
</update>
|
</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>
|
</mapper>
|
||||||
|
|||||||
@@ -91,6 +91,23 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
${params.dataScope}
|
${params.dataScope}
|
||||||
</select>
|
</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 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
|
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
|
from sys_user u
|
||||||
|
|||||||
Reference in New Issue
Block a user