✨ 进行中配载可编辑、汇票可选放开限制,并补充业务部门与待确认回单
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+6
@@ -207,6 +207,12 @@ public class Dept extends TenantEntity {
|
||||
@Schema(description = "是否平台公司:0否,1是")
|
||||
private Integer isPlatformCompany;
|
||||
|
||||
/**
|
||||
* 是否业务部门:0否,1是
|
||||
*/
|
||||
@Schema(description = "是否业务部门:0否,1是")
|
||||
private Integer isBusinessDept;
|
||||
|
||||
/**
|
||||
* OA主键,仅同步记录,不对外展示
|
||||
*/
|
||||
|
||||
+4
@@ -199,6 +199,10 @@ public class ContractManage extends TenantEntity {
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||
private String changeContent;
|
||||
|
||||
@TableField(exist = false)
|
||||
@Schema(description = "变更类型")
|
||||
private String changeType;
|
||||
|
||||
@Schema(description = "变更原因")
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||
private String changeReason;
|
||||
|
||||
+11
@@ -260,6 +260,17 @@ public class DeptController extends BladeController {
|
||||
return R.data(deptService.listPlatformCompany());
|
||||
}
|
||||
|
||||
/**
|
||||
* 业务部门下拉(是否业务部门=是)
|
||||
*/
|
||||
@PreAuth(AuthConstant.PERMIT_ALL)
|
||||
@GetMapping("/business-dept-select")
|
||||
@ApiOperationSupport(order = 12)
|
||||
@Operation(summary = "业务部门下拉", description = "返回是否业务部门=是的部门列表")
|
||||
public R<List<Dept>> businessDeptSelect() {
|
||||
return R.data(deptService.listBusinessDept());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取部门的主管信息
|
||||
*/
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
<result column="mnemonic_code" property="mnemonicCode"/>
|
||||
<result column="carrier_customer_id" property="carrierCustomerId"/>
|
||||
<result column="is_platform_company" property="isPlatformCompany"/>
|
||||
<result column="is_business_dept" property="isBusinessDept"/>
|
||||
<result column="sort" property="sort"/>
|
||||
<result column="remark" property="remark"/>
|
||||
<result column="status" property="status"/>
|
||||
@@ -43,6 +44,7 @@
|
||||
<result column="mnemonic_code" property="mnemonicCode"/>
|
||||
<result column="carrier_customer_id" property="carrierCustomerId"/>
|
||||
<result column="is_platform_company" property="isPlatformCompany"/>
|
||||
<result column="is_business_dept" property="isBusinessDept"/>
|
||||
<result column="sort" property="sort"/>
|
||||
<result column="remark" property="remark"/>
|
||||
<result column="status" property="status"/>
|
||||
|
||||
+7
@@ -106,6 +106,13 @@ public interface IDeptService extends IService<Dept> {
|
||||
*/
|
||||
List<Dept> listPlatformCompany();
|
||||
|
||||
/**
|
||||
* 业务部门下拉(是否业务部门=是)
|
||||
*
|
||||
* @return 业务部门列表
|
||||
*/
|
||||
List<Dept> listBusinessDept();
|
||||
|
||||
/**
|
||||
* 根据部门名称精确匹配获取部门ID集合
|
||||
*
|
||||
|
||||
+19
@@ -337,6 +337,18 @@ public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements ID
|
||||
return list(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Dept> listBusinessDept() {
|
||||
LambdaQueryWrapper<Dept> queryWrapper = Wrappers.<Dept>lambdaQuery()
|
||||
.eq(Dept::getIsBusinessDept, 1)
|
||||
.orderByAsc(Dept::getSort)
|
||||
.orderByAsc(Dept::getId);
|
||||
if (!AuthUtil.isAdministrator()) {
|
||||
queryWrapper.eq(Dept::getTenantId, AuthUtil.getTenantId());
|
||||
}
|
||||
return list(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeptIds(String tenantId, String deptNames) {
|
||||
List<Dept> deptList = baseMapper.selectList(Wrappers.<Dept>query().lambda().eq(Dept::getTenantId, tenantId).in(Dept::getDeptName, Func.toStrList(deptNames)));
|
||||
@@ -443,6 +455,7 @@ public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements ID
|
||||
rootDept.setIsDeleted(BladeConstant.DB_NOT_DELETED);
|
||||
rootDept.setIsOa(0);
|
||||
rootDept.setIsPlatformCompany(0);
|
||||
rootDept.setIsBusinessDept(0);
|
||||
rootDept.setSyncTime(new Date());
|
||||
this.save(rootDept);
|
||||
log.info("已创建 OA 同步集团顶级 id={} name={} code={}",
|
||||
@@ -536,6 +549,7 @@ public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements ID
|
||||
newRoot.setIsDeleted(BladeConstant.DB_NOT_DELETED);
|
||||
newRoot.setIsOa(0);
|
||||
newRoot.setIsPlatformCompany(0);
|
||||
newRoot.setIsBusinessDept(0);
|
||||
newRoot.setSyncTime(new Date());
|
||||
this.save(newRoot);
|
||||
log.info("迁移创建新集团顶级 id={}(来自历史 id={})", newRootId, legacyRootId);
|
||||
@@ -598,6 +612,7 @@ public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements ID
|
||||
externalDept.setIsDeleted(BladeConstant.DB_NOT_DELETED);
|
||||
externalDept.setIsOa(0);
|
||||
externalDept.setIsPlatformCompany(0);
|
||||
externalDept.setIsBusinessDept(0);
|
||||
externalDept.setSyncTime(new Date());
|
||||
this.save(externalDept);
|
||||
log.info("已创建外部组织顶级 id={}", externalDept.getId());
|
||||
@@ -678,6 +693,9 @@ public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements ID
|
||||
if (dept.getIsPlatformCompany() == null) {
|
||||
dept.setIsPlatformCompany(0);
|
||||
}
|
||||
if (dept.getIsBusinessDept() == null) {
|
||||
dept.setIsBusinessDept(0);
|
||||
}
|
||||
// 排序未填时默认 1
|
||||
if (dept.getSort() == null) {
|
||||
dept.setSort(1);
|
||||
@@ -804,6 +822,7 @@ public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements ID
|
||||
dept.setIsDeleted(BladeConstant.DB_NOT_DELETED);
|
||||
dept.setIsOa(1);
|
||||
dept.setIsPlatformCompany(0);
|
||||
dept.setIsBusinessDept(0);
|
||||
dept.setSyncTime(new Date());
|
||||
boolean saved = save(dept);
|
||||
if (saved) {
|
||||
|
||||
+24
-1
@@ -924,7 +924,8 @@ public class OASyncServiceImpl implements IOASyncService {
|
||||
.select(Dept::getId, Dept::getDeptCode, Dept::getDeptName, Dept::getFullName,
|
||||
Dept::getOaModified, Dept::getParentId, Dept::getOaId, Dept::getBelongCompanyCode,
|
||||
Dept::getParentCode, Dept::getOaSupSubComId,
|
||||
Dept::getContractCodePrefix, Dept::getContractInitialSerial));
|
||||
Dept::getContractCodePrefix, Dept::getContractInitialSerial,
|
||||
Dept::getIsPlatformCompany, Dept::getIsBusinessDept));
|
||||
Map<String, Dept> byOaId = new HashMap<>();
|
||||
for (Dept dept : deptList) {
|
||||
if (StringUtils.isNotBlank(dept.getOaId())) {
|
||||
@@ -989,6 +990,8 @@ public class OASyncServiceImpl implements IOASyncService {
|
||||
}
|
||||
// OA 不同步合同本地配置:保留已有值,并把 -1 空占位规范为 null,避免 ALWAYS 策略写回 -1/清空
|
||||
preserveLocalContractFields(dept, existing);
|
||||
// OA 不同步「是否平台公司 / 是否业务部门」:更新时强制保留本地已配置值,新增默认否
|
||||
preserveLocalBizFlags(dept, existing);
|
||||
normalizeContractInitialSerial(dept);
|
||||
if (StringUtils.isNotBlank(dept.getDeptCode())) {
|
||||
deptIdByCode.put(dept.getDeptCode(), dept.getId());
|
||||
@@ -1066,6 +1069,26 @@ public class OASyncServiceImpl implements IOASyncService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* OA 同步不携带本地业务标志:更新时保留已配置的「是否平台公司 / 是否业务部门」,新增默认否。
|
||||
*/
|
||||
private void preserveLocalBizFlags(Dept incoming, Dept existing) {
|
||||
if (incoming == null) {
|
||||
return;
|
||||
}
|
||||
if (existing != null) {
|
||||
incoming.setIsPlatformCompany(existing.getIsPlatformCompany() != null ? existing.getIsPlatformCompany() : 0);
|
||||
incoming.setIsBusinessDept(existing.getIsBusinessDept() != null ? existing.getIsBusinessDept() : 0);
|
||||
return;
|
||||
}
|
||||
if (incoming.getIsPlatformCompany() == null) {
|
||||
incoming.setIsPlatformCompany(0);
|
||||
}
|
||||
if (incoming.getIsBusinessDept() == null) {
|
||||
incoming.setIsBusinessDept(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 合同初始流水号 -1 为空占位,同步落库前规范为 null。
|
||||
*/
|
||||
|
||||
+1
-32
@@ -107,7 +107,7 @@ public class BillLedgerServiceImpl extends BaseServiceImpl<BillLedgerMapper, Bil
|
||||
private List<BillLedgerVO> availableList(String keyword, Long deptId, Long selectedId, String payerName,
|
||||
String payeeName) {
|
||||
LocalDate today = LocalDate.now();
|
||||
// 未到期且有余额;收票且部门可用,或出票/收票单位与结算收付款方一致(开票、收票都可)
|
||||
// 可选汇票:未到期且可用余额 > 0(已选中的可回显);不再按部门、开票/收票类型、结算收付款方过滤
|
||||
return list(Wrappers.<BillLedger>lambdaQuery()
|
||||
.and(Func.isNotEmpty(keyword), wrapper -> wrapper.like(BillLedger::getBillNo, keyword)
|
||||
.or().like(BillLedger::getIssuerName, keyword)
|
||||
@@ -119,35 +119,10 @@ public class BillLedgerServiceImpl extends BaseServiceImpl<BillLedgerMapper, Bil
|
||||
.or(selectedId != null, child -> child.eq(BillLedger::getId, selectedId)))
|
||||
.orderByAsc(BillLedger::getMaturityDate)
|
||||
.orderByDesc(BillLedger::getCreateTime)).stream()
|
||||
.filter(item -> selectedId != null && Objects.equals(item.getId(), selectedId)
|
||||
|| selectableBill(item, deptId, payerName, payeeName))
|
||||
.map(item -> BillLedgerWrapper.build().entityVO(item))
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 收票且当前部门在可用范围内,或出票单位、收票单位与结算付款方、收款方一致(顺序不限)。
|
||||
*/
|
||||
private boolean selectableBill(BillLedger ledger, Long deptId, String payerName, String payeeName) {
|
||||
boolean receivedAndDept = "received".equals(ledger.getBillType()) && departmentAvailable(ledger, deptId);
|
||||
return receivedAndDept || partiesMatch(ledger.getIssuerName(), ledger.getReceiverName(), payerName, payeeName);
|
||||
}
|
||||
|
||||
private boolean partiesMatch(String issuerName, String receiverName, String payerName, String payeeName) {
|
||||
String issuer = trimName(issuerName);
|
||||
String receiver = trimName(receiverName);
|
||||
String payer = trimName(payerName);
|
||||
String payee = trimName(payeeName);
|
||||
if (issuer.isEmpty() || receiver.isEmpty() || payer.isEmpty() || payee.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return (issuer.equals(payer) && receiver.equals(payee)) || (issuer.equals(payee) && receiver.equals(payer));
|
||||
}
|
||||
|
||||
private String trimName(String value) {
|
||||
return value == null ? "" : value.trim();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long submit(BillLedgerSaveRequest request) {
|
||||
@@ -292,12 +267,6 @@ public class BillLedgerServiceImpl extends BaseServiceImpl<BillLedgerMapper, Bil
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
}
|
||||
|
||||
private boolean departmentAvailable(BillLedger ledger, Long deptId) {
|
||||
List<?> values = parseArray(ledger.getAvailableDeptIdsJson(), "可用部门");
|
||||
if (values.stream().anyMatch(value -> "all".equals(String.valueOf(value)))) return true;
|
||||
return deptId == null || values.stream().anyMatch(value -> String.valueOf(deptId).equals(String.valueOf(value)));
|
||||
}
|
||||
|
||||
private List<?> parseArray(String value, String name) {
|
||||
if (Func.isEmpty(value)) return List.of();
|
||||
try {
|
||||
|
||||
+4
-20
@@ -32,7 +32,6 @@ import lombok.RequiredArgsConstructor;
|
||||
import org.springblade.core.log.exception.ServiceException;
|
||||
import org.springblade.core.mp.base.BaseServiceImpl;
|
||||
import org.springblade.core.secure.utils.AuthUtil;
|
||||
import org.springblade.core.tool.jackson.JsonUtil;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.system.cache.SysCache;
|
||||
import org.springblade.transport.constant.TransportBusiConstant;
|
||||
@@ -112,7 +111,7 @@ public class BillPaymentServiceImpl extends BaseServiceImpl<BillPaymentMapper, B
|
||||
String deptName = required(SysCache.getDeptName(deptId), "使用部门", 100);
|
||||
BillLedger ledger = lockedBill(request.getBillLedgerId());
|
||||
BigDecimal usedAmount = positive(request.getUsedAmount(), "本次使用");
|
||||
validateLedgerAmount(ledger, usedAmount, deptId);
|
||||
validateLedgerAmount(ledger, usedAmount);
|
||||
if (entity.getId() == null) {
|
||||
entity.setPaymentNo(nextNo());
|
||||
entity.setApprovalStatus(TransportBusiConstant.DRAFT);
|
||||
@@ -165,7 +164,7 @@ public class BillPaymentServiceImpl extends BaseServiceImpl<BillPaymentMapper, B
|
||||
throw new ServiceException("仅审批中的汇票付款允许审核");
|
||||
}
|
||||
BillLedger ledger = lockedBill(entity.getBillLedgerId());
|
||||
validateLedgerAmount(ledger, entity.getUsedAmount(), entity.getDeptId());
|
||||
validateLedgerAmount(ledger, entity.getUsedAmount());
|
||||
BillLedgerUsage exists = usageMapper.selectOne(Wrappers.<BillLedgerUsage>lambdaQuery()
|
||||
.eq(BillLedgerUsage::getBillPaymentId, entity.getId())
|
||||
.eq(BillLedgerUsage::getUsageStatus, TransportBusiConstant.APPROVED)
|
||||
@@ -245,13 +244,13 @@ public class BillPaymentServiceImpl extends BaseServiceImpl<BillPaymentMapper, B
|
||||
|
||||
private void validateStoredAmount(BillPayment entity) {
|
||||
BillLedger ledger = lockedBill(entity.getBillLedgerId());
|
||||
validateLedgerAmount(ledger, entity.getUsedAmount(), entity.getDeptId());
|
||||
validateLedgerAmount(ledger, entity.getUsedAmount());
|
||||
entity.setBillNo(ledger.getBillNo());
|
||||
entity.setFaceAmount(ledger.getFaceAmount());
|
||||
entity.setAvailableBalance(ledger.getAvailableBalance());
|
||||
}
|
||||
|
||||
private void validateLedgerAmount(BillLedger ledger, BigDecimal usedAmount, Long deptId) {
|
||||
private void validateLedgerAmount(BillLedger ledger, BigDecimal usedAmount) {
|
||||
if (usedAmount == null || usedAmount.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
throw new ServiceException("本次使用必须大于0");
|
||||
}
|
||||
@@ -261,21 +260,6 @@ public class BillPaymentServiceImpl extends BaseServiceImpl<BillPaymentMapper, B
|
||||
if (usedAmount.compareTo(money(ledger.getAvailableBalance())) > 0) {
|
||||
throw new ServiceException("本次使用不能超过汇票可用余额");
|
||||
}
|
||||
if (!departmentAvailable(ledger, deptId)) {
|
||||
throw new ServiceException("当前使用部门不在汇票可用部门范围内");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean departmentAvailable(BillLedger ledger, Long deptId) {
|
||||
if (Func.isEmpty(ledger.getAvailableDeptIdsJson())) return false;
|
||||
try {
|
||||
Object parsed = JsonUtil.parse(ledger.getAvailableDeptIdsJson(), List.class);
|
||||
if (!(parsed instanceof List<?> values)) return false;
|
||||
if (values.stream().anyMatch(item -> "all".equals(String.valueOf(item)))) return true;
|
||||
return deptId != null && values.stream().anyMatch(item -> String.valueOf(deptId).equals(String.valueOf(item)));
|
||||
} catch (Exception exception) {
|
||||
throw new ServiceException("汇票可用部门配置不正确");
|
||||
}
|
||||
}
|
||||
|
||||
private BillLedger lockedBill(Long id) {
|
||||
|
||||
+78
-22
@@ -83,6 +83,8 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
|
||||
private static final String ARCHIVE_STATUS_PENDING = "未归档";
|
||||
private static final String ARCHIVE_STATUS_ARCHIVED = "已归档";
|
||||
private static final String FILE_TYPE_SEAL_ARCHIVE = "双章归档文件";
|
||||
private static final String CHANGE_TYPE_INFO = "合同信息变更";
|
||||
private static final String CHANGE_TYPE_SETTLEMENT = "结算规则变更";
|
||||
private static final long TEMPORARY_VALIDITY_DAYS = 30L;
|
||||
private static final BigDecimal TAX_RATE_MIN = BigDecimal.ZERO;
|
||||
private static final BigDecimal TAX_RATE_MAX = BigDecimal.valueOf(100);
|
||||
@@ -285,45 +287,99 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
|
||||
|| !List.of(STATUS_APPROVED, STATUS_CHANGE_APPROVED, STATUS_CHANGE_REJECTED).contains(source.getApprovalStatus())) {
|
||||
throw new ServiceException("当前合同状态不允许发起变更");
|
||||
}
|
||||
TransportBusinessSupport.validateRequired(request.getSettlementCurrency(), "请选择结算币种");
|
||||
String changeType = resolveChangeType(request.getChangeType());
|
||||
boolean settlementRuleOnly = Objects.equals(changeType, CHANGE_TYPE_SETTLEMENT);
|
||||
String changeReason = TransportBusinessSupport.trimToNull(request.getChangeReason());
|
||||
if (Func.isEmpty(changeReason) && Objects.equals(source.getApprovalStatus(), STATUS_CHANGE_REJECTED)) {
|
||||
changeReason = resolveResubmitChangeReason(source);
|
||||
}
|
||||
TransportBusinessSupport.validateLength(changeReason, 500, "变更原因不能超过500字");
|
||||
ContractManage candidate = new ContractManage();
|
||||
BeanUtil.copyProperties(source, candidate);
|
||||
candidate.setPartyB(TransportBusinessSupport.trimToNull(request.getPartyB()));
|
||||
validateContractPartyCombinationUnique(candidate);
|
||||
validateBillingPlans(request.getBillingPlanJson());
|
||||
validatePaymentRatios(request.getPaymentRatioJson());
|
||||
Map<String, Object> beforeData = buildContractChangeSnapshot(source);
|
||||
applyContractNo(source, request.getContractNo(), false);
|
||||
source.setContractName(request.getContractName()); source.setPartyB(request.getPartyB());
|
||||
source.setStartDate(request.getStartDate()); source.setEndDate(request.getEndDate()); source.setContractFormat(request.getContractFormat());
|
||||
source.setSettlementMode(request.getSettlementMode()); source.setLegalSealFlag(request.getLegalSealFlag()); source.setCopyCount(request.getCopyCount());
|
||||
source.setSettlementCurrency(TransportBusinessSupport.trimToNull(request.getSettlementCurrency())); source.setInvoiceCycle(request.getInvoiceCycle());
|
||||
source.setPaymentDays(request.getPaymentDays()); source.setRemark(request.getRemark()); source.setBillingEnabled(request.getBillingEnabled()); source.setFeeGenerationMode(request.getFeeGenerationMode());
|
||||
source.setContractAmount(request.getContractAmount()); source.setTemplateFlag(request.getTemplateFlag());
|
||||
source.setOriginalContractNo(TransportBusinessSupport.trimToNull(request.getOriginalContractNo()));
|
||||
source.setElectronicSealFlag(request.getElectronicSealFlag());
|
||||
normalizeOptionalIntegerFields(source);
|
||||
validateContractAmountRequired(source);
|
||||
validateAdditionalFields(source);
|
||||
source.setBillingPlanJson(request.getBillingPlanJson()); source.setSettlementRuleJson(request.getSettlementRuleJson()); source.setPreSettlementConfigJson(request.getPreSettlementConfigJson()); source.setFormalSettlementConfigJson(request.getFormalSettlementConfigJson()); source.setPaymentRatioJson(request.getPaymentRatioJson());
|
||||
source.setContractFileJson(request.getContractFileJson()); source.setAttachmentsJson(request.getAttachmentsJson());
|
||||
source.setChangeAttachmentsJson(TransportBusinessSupport.trimToNull(request.getChangeAttachmentsJson()));
|
||||
if (settlementRuleOnly) {
|
||||
applySettlementRuleChange(source, request);
|
||||
} else {
|
||||
applyContractInfoChange(source, request);
|
||||
}
|
||||
Map<String, Object> afterData = buildContractChangeSnapshot(source);
|
||||
retainChangedSnapshotFields(beforeData, afterData);
|
||||
source.setApprovalStatus(STATUS_CHANGE_REVIEWING);
|
||||
source.setChangeContent(TransportBusinessSupport.trimToNull(request.getChangeContent()));
|
||||
source.setChangeReason(changeReason);
|
||||
source.setChangeAttachmentsJson(TransportBusinessSupport.trimToNull(request.getChangeAttachmentsJson()));
|
||||
source.setCurrentNode("合同变更审批");
|
||||
source.setCurrentProcessor("待处理");
|
||||
appendChangeRecord(source, "合同信息变更", changeReason, STATUS_CHANGE_REVIEWING, "审核中", beforeData, afterData);
|
||||
appendChangeRecord(source, changeType, changeReason, STATUS_CHANGE_REVIEWING, "审核中", beforeData, afterData);
|
||||
return updateById(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析并校验合同变更类型,兼容历史未传类型的请求。
|
||||
*/
|
||||
private String resolveChangeType(String changeType) {
|
||||
String normalized = TransportBusinessSupport.trimToNull(changeType);
|
||||
if (Func.isEmpty(normalized)) {
|
||||
return CHANGE_TYPE_INFO;
|
||||
}
|
||||
if (!List.of(CHANGE_TYPE_INFO, CHANGE_TYPE_SETTLEMENT).contains(normalized)) {
|
||||
throw new ServiceException("请选择变更类型");
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
/**
|
||||
* 结算规则变更:仅允许更新计费信息与结算单规则。
|
||||
*/
|
||||
private void applySettlementRuleChange(ContractManage source, ContractManage request) {
|
||||
source.setBillingEnabled(request.getBillingEnabled());
|
||||
source.setFeeGenerationMode(request.getFeeGenerationMode());
|
||||
source.setBillingPlanJson(request.getBillingPlanJson());
|
||||
source.setSettlementRuleJson(request.getSettlementRuleJson());
|
||||
source.setPreSettlementConfigJson(request.getPreSettlementConfigJson());
|
||||
source.setFormalSettlementConfigJson(request.getFormalSettlementConfigJson());
|
||||
}
|
||||
|
||||
/**
|
||||
* 合同信息变更:更新合同基本信息、计费/结算规则、付款比例及附件。
|
||||
*/
|
||||
private void applyContractInfoChange(ContractManage source, ContractManage request) {
|
||||
TransportBusinessSupport.validateRequired(request.getSettlementCurrency(), "请选择结算币种");
|
||||
ContractManage candidate = new ContractManage();
|
||||
BeanUtil.copyProperties(source, candidate);
|
||||
candidate.setPartyB(TransportBusinessSupport.trimToNull(request.getPartyB()));
|
||||
validateContractPartyCombinationUnique(candidate);
|
||||
validatePaymentRatios(request.getPaymentRatioJson());
|
||||
applyContractNo(source, request.getContractNo(), false);
|
||||
source.setContractName(request.getContractName());
|
||||
source.setPartyB(request.getPartyB());
|
||||
source.setStartDate(request.getStartDate());
|
||||
source.setEndDate(request.getEndDate());
|
||||
source.setContractFormat(request.getContractFormat());
|
||||
source.setSettlementMode(request.getSettlementMode());
|
||||
source.setLegalSealFlag(request.getLegalSealFlag());
|
||||
source.setCopyCount(request.getCopyCount());
|
||||
source.setSettlementCurrency(TransportBusinessSupport.trimToNull(request.getSettlementCurrency()));
|
||||
source.setInvoiceCycle(request.getInvoiceCycle());
|
||||
source.setPaymentDays(request.getPaymentDays());
|
||||
source.setRemark(request.getRemark());
|
||||
source.setBillingEnabled(request.getBillingEnabled());
|
||||
source.setFeeGenerationMode(request.getFeeGenerationMode());
|
||||
source.setContractAmount(request.getContractAmount());
|
||||
source.setTemplateFlag(request.getTemplateFlag());
|
||||
source.setOriginalContractNo(TransportBusinessSupport.trimToNull(request.getOriginalContractNo()));
|
||||
source.setElectronicSealFlag(request.getElectronicSealFlag());
|
||||
normalizeOptionalIntegerFields(source);
|
||||
validateContractAmountRequired(source);
|
||||
validateAdditionalFields(source);
|
||||
source.setBillingPlanJson(request.getBillingPlanJson());
|
||||
source.setSettlementRuleJson(request.getSettlementRuleJson());
|
||||
source.setPreSettlementConfigJson(request.getPreSettlementConfigJson());
|
||||
source.setFormalSettlementConfigJson(request.getFormalSettlementConfigJson());
|
||||
source.setPaymentRatioJson(request.getPaymentRatioJson());
|
||||
source.setContractFileJson(request.getContractFileJson());
|
||||
source.setAttachmentsJson(request.getAttachmentsJson());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean updateAttachments(ContractManage contractManage) {
|
||||
|
||||
+23
-7
@@ -107,6 +107,7 @@ public class DriverWaybillServiceImpl implements IDriverWaybillService {
|
||||
private static final String STATUS_WAITING_DISPATCH = "waiting_dispatch";
|
||||
private static final String STATUS_DISPATCHING = "dispatching";
|
||||
private static final String STATUS_RUNNING = "running";
|
||||
private static final String STATUS_PENDING_RETURN = WaybillProcessSupport.STATUS_PENDING_RETURN;
|
||||
private static final String STATUS_COMPLETED = "completed";
|
||||
private static final String STATUS_CANCELLED = "cancelled";
|
||||
|
||||
@@ -118,9 +119,10 @@ public class DriverWaybillServiceImpl implements IDriverWaybillService {
|
||||
private static final List<String> PENDING_STATUSES = Arrays.asList(
|
||||
STATUS_PENDING, STATUS_WAITING_DISPATCH, STATUS_DISPATCHING
|
||||
);
|
||||
/** Tab「全部」统计口径:待接 + 运输中 + 已完成(不含已取消) */
|
||||
/** Tab「全部」统计口径:待接 + 运输中 + 待确认回单 + 已完成(不含已取消) */
|
||||
private static final List<String> TAB_ALL_STATUSES = Arrays.asList(
|
||||
STATUS_PENDING, STATUS_WAITING_DISPATCH, STATUS_DISPATCHING, STATUS_RUNNING, STATUS_COMPLETED
|
||||
STATUS_PENDING, STATUS_WAITING_DISPATCH, STATUS_DISPATCHING, STATUS_RUNNING,
|
||||
STATUS_PENDING_RETURN, STATUS_COMPLETED
|
||||
);
|
||||
/** 允许完成运单的业务状态 */
|
||||
private static final List<String> COMPLETABLE_STATUSES = Arrays.asList(
|
||||
@@ -520,22 +522,35 @@ public class DriverWaybillServiceImpl implements IDriverWaybillService {
|
||||
nodePunchMapper.insert(punch);
|
||||
|
||||
advanceCurrentProcessNode(waybill, nodeCfg);
|
||||
// 末位打卡节点是到货/卸货/签收、且回单无需确认完成时,本次打卡一并把运单置为完成;
|
||||
// 末位打卡节点是到货/卸货/签收时:
|
||||
// - 回单无需确认 → 直接完成;
|
||||
// - 回单需确认 → 进入「待确认回单」,等运管员批量/单条完成后才变已完成。
|
||||
// isLastDriverPunchNode 与 returnNeedsNoConfirmation 传的就是上面那份 processJson,未再调 resolveProcessJson 取过程配置。
|
||||
String nodeKey = WaybillProcessSupport.nodeKey(nodeCfg);
|
||||
String nodeName = WaybillProcessSupport.nodeName(nodeCfg);
|
||||
boolean completed = false;
|
||||
if (WaybillProcessSupport.isLastDriverPunchNode(processJson, nodeKey)
|
||||
&& WaybillProcessSupport.isDeliveryNode(nodeKey, nodeName)
|
||||
&& WaybillProcessSupport.returnNeedsNoConfirmation(processJson)
|
||||
&& canAutoCompleteWaybill(waybill)) {
|
||||
completed = waybillService.completeWithoutDeptCheck(waybill.getId());
|
||||
if (WaybillProcessSupport.returnNeedsNoConfirmation(processJson)) {
|
||||
completed = waybillService.completeWithoutDeptCheck(waybill.getId());
|
||||
} else {
|
||||
markPendingReturn(waybill);
|
||||
}
|
||||
}
|
||||
DriverNodePunchVO vo = toNodePunchVO(punch);
|
||||
vo.setWaybillCompleted(completed);
|
||||
return vo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 司机末位打卡完成且回单需内部确认时,将运单置为待确认回单。
|
||||
*/
|
||||
private void markPendingReturn(Waybill waybill) {
|
||||
waybill.setBusinessStatus(STATUS_PENDING_RETURN);
|
||||
waybillService.updateById(waybill);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean accept(Long id) {
|
||||
@@ -844,7 +859,7 @@ public class DriverWaybillServiceImpl implements IDriverWaybillService {
|
||||
switch (status) {
|
||||
case 0 -> wrapper.in(Waybill::getBusinessStatus, PENDING_STATUSES);
|
||||
case 1 -> wrapper.in(Waybill::getBusinessStatus, COMPLETABLE_STATUSES);
|
||||
case 2 -> wrapper.eq(Waybill::getBusinessStatus, STATUS_COMPLETED);
|
||||
case 2 -> wrapper.in(Waybill::getBusinessStatus, STATUS_COMPLETED, STATUS_PENDING_RETURN);
|
||||
case 3 -> wrapper.eq(Waybill::getBusinessStatus, STATUS_CANCELLED);
|
||||
default -> wrapper.in(Waybill::getBusinessStatus, TAB_ALL_STATUSES);
|
||||
}
|
||||
@@ -2004,7 +2019,8 @@ public class DriverWaybillServiceImpl implements IDriverWaybillService {
|
||||
return switch (businessStatus) {
|
||||
case STATUS_PENDING, STATUS_WAITING_DISPATCH, STATUS_DISPATCHING -> 0;
|
||||
case STATUS_RUNNING -> 1;
|
||||
case STATUS_COMPLETED -> 2;
|
||||
// 待确认回单:司机侧节点已打完,对司机按已完成展示
|
||||
case STATUS_PENDING_RETURN, STATUS_COMPLETED -> 2;
|
||||
case STATUS_CANCELLED -> 3;
|
||||
default -> null;
|
||||
};
|
||||
|
||||
+181
-4
@@ -20,9 +20,11 @@ import org.springblade.system.pojo.entity.Dept;
|
||||
import org.springblade.transport.excel.LoadingManageExcel;
|
||||
import org.springblade.transport.mapper.LoadingManageMapper;
|
||||
import org.springblade.transport.mapper.WaybillMapper;
|
||||
import org.springblade.transport.mapper.WaybillNodePunchMapper;
|
||||
import org.springblade.transport.pojo.entity.ContractManage;
|
||||
import org.springblade.transport.pojo.entity.LoadingManage;
|
||||
import org.springblade.transport.pojo.entity.Waybill;
|
||||
import org.springblade.transport.pojo.entity.WaybillNodePunch;
|
||||
import org.springblade.transport.pojo.vo.BusinessRemoveResultVO;
|
||||
import org.springblade.transport.pojo.vo.LoadingCarrierContractVO;
|
||||
import org.springblade.transport.pojo.vo.LoadingManageVO;
|
||||
@@ -74,6 +76,9 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
|
||||
@Resource
|
||||
private WaybillMapper waybillMapper;
|
||||
|
||||
@Resource
|
||||
private WaybillNodePunchMapper waybillNodePunchMapper;
|
||||
|
||||
@Resource
|
||||
private IContractManageService contractManageService;
|
||||
|
||||
@@ -139,10 +144,26 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
|
||||
loadingManage.setLoadingNo(nextCode());
|
||||
}
|
||||
validateCarrierContract(loadingManage, false);
|
||||
if (STATUS_RUNNING.equals(businessStatus) && Func.isNotEmpty(loadingManage.getId())) {
|
||||
LoadingManage oldRecord = getById(loadingManage.getId());
|
||||
if (oldRecord != null) {
|
||||
validateRunningImmutableTaskFields(oldRecord, loadingManage);
|
||||
Set<Long> nextIds = new HashSet<>(waybillIds(loadingManage.getWaybillIdsJson()));
|
||||
for (Long oldId : oldWaybillIds) {
|
||||
if (oldId != null && !nextIds.contains(oldId) && hasLoadOrUnloadPunch(oldId)) {
|
||||
throw new ServiceException("已打卡的子运单不可从进行中配载单移除");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
boolean result = saveOrUpdate(loadingManage);
|
||||
// 草稿仅预占运单号,不把运单业务状态改成 draft;正式确认时再完整同步为待执行
|
||||
if (STATUS_DRAFT.equals(businessStatus)) {
|
||||
syncDraftWaybillReservation(loadingManage, oldWaybillIds);
|
||||
} else if (STATUS_RUNNING.equals(businessStatus)) {
|
||||
// 进行中暂存:不重置原有子单状态/接单,仅同步任务信息与新增子单
|
||||
List<Waybill> waybills = loadWaybills(waybillIds(loadingManage.getWaybillIdsJson()));
|
||||
writeWaybillsForRunningEdit(loadingManage, oldWaybillIds, waybills);
|
||||
} else {
|
||||
syncAssociatedWaybills(loadingManage, businessStatus, oldWaybillIds);
|
||||
}
|
||||
@@ -156,28 +177,103 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
|
||||
validate(loadingManage, false);
|
||||
List<Long> oldWaybillIds = new ArrayList<>();
|
||||
boolean ownChildrenAdmitted = false;
|
||||
boolean runningEdit = false;
|
||||
LoadingManage oldRecord = null;
|
||||
if (Func.isNotEmpty(loadingManage.getId())) {
|
||||
LoadingManage oldRecord = loadEditable(loadingManage.getId(), true);
|
||||
oldRecord = loadEditable(loadingManage.getId(), true);
|
||||
oldWaybillIds = waybillIds(oldRecord.getWaybillIdsJson());
|
||||
// 草稿只预占运单号、未过判据,草稿转正式不得沿用本单豁免
|
||||
ownChildrenAdmitted = !STATUS_DRAFT.equals(oldRecord.getBusinessStatus());
|
||||
runningEdit = STATUS_RUNNING.equals(oldRecord.getBusinessStatus());
|
||||
loadingManage.setLoadingNo(oldRecord.getLoadingNo());
|
||||
loadingManage.setDeptId(oldRecord.getDeptId());
|
||||
loadingManage.setDeptName(oldRecord.getDeptName());
|
||||
}
|
||||
prepareCreateOrUpdate(loadingManage);
|
||||
// 确认提交:草稿/新建统一生成正式配载单(待执行)
|
||||
loadingManage.setBusinessStatus(STATUS_PENDING);
|
||||
// 进行中编辑:保持 running;草稿/新建确认后统一为待执行
|
||||
loadingManage.setBusinessStatus(runningEdit ? STATUS_RUNNING : STATUS_PENDING);
|
||||
if (Func.isEmpty(loadingManage.getLoadingNo())) {
|
||||
loadingManage.setLoadingNo(nextCode());
|
||||
}
|
||||
List<Waybill> waybills = validateWaybillsAvailable(loadingManage, waybillIds(loadingManage.getWaybillIdsJson()), ownChildrenAdmitted);
|
||||
validateCarrierContract(loadingManage, true, waybills);
|
||||
if (runningEdit && oldRecord != null) {
|
||||
validateRunningEdit(oldRecord, loadingManage, waybills, oldWaybillIds);
|
||||
}
|
||||
boolean result = saveOrUpdate(loadingManage);
|
||||
writeWaybillsForDriver(loadingManage, oldWaybillIds, waybills);
|
||||
// 进行中编辑:保留原有子单状态与接单事实,仅对新加入子单做派车同步
|
||||
if (runningEdit) {
|
||||
writeWaybillsForRunningEdit(loadingManage, oldWaybillIds, waybills);
|
||||
} else {
|
||||
writeWaybillsForDriver(loadingManage, oldWaybillIds, waybills);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 进行中配载编辑校验:必填任务字段不可改;已装/卸打卡的子运单不可移除。
|
||||
*/
|
||||
private void validateRunningEdit(LoadingManage oldRecord, LoadingManage incoming,
|
||||
List<Waybill> waybills, List<Long> oldWaybillIds) {
|
||||
validateRunningImmutableTaskFields(oldRecord, incoming);
|
||||
Set<Long> nextIds = waybills.stream().map(Waybill::getId).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||
for (Long oldId : oldWaybillIds) {
|
||||
if (oldId == null || nextIds.contains(oldId)) {
|
||||
continue;
|
||||
}
|
||||
if (hasLoadOrUnloadPunch(oldId)) {
|
||||
throw new ServiceException("已打卡的子运单不可从进行中配载单移除");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validateRunningImmutableTaskFields(LoadingManage oldRecord, LoadingManage incoming) {
|
||||
if (!Objects.equals(trimText(oldRecord.getCarrierType()), trimText(incoming.getCarrierType()))) {
|
||||
throw new ServiceException("进行中配载单不允许修改承运类型");
|
||||
}
|
||||
if (Objects.equals(oldRecord.getCarrierType(), "承运商")
|
||||
&& !Objects.equals(oldRecord.getCarrierContractId(), incoming.getCarrierContractId())) {
|
||||
throw new ServiceException("进行中配载单不允许修改承运商");
|
||||
}
|
||||
if (!Objects.equals(trimText(oldRecord.getVehicleNo()), trimText(incoming.getVehicleNo()))) {
|
||||
throw new ServiceException("进行中配载单不允许修改车牌号");
|
||||
}
|
||||
if (Objects.equals(oldRecord.getCarrierType(), CARRIER_SELF)) {
|
||||
if (!Objects.equals(trimText(oldRecord.getDriverName()), trimText(incoming.getDriverName()))) {
|
||||
throw new ServiceException("进行中配载单不允许修改司机");
|
||||
}
|
||||
if (!Objects.equals(trimText(oldRecord.getDriverPhone()), trimText(incoming.getDriverPhone()))) {
|
||||
throw new ServiceException("进行中配载单不允许修改手机号");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasLoadOrUnloadPunch(Long waybillId) {
|
||||
if (waybillId == null) {
|
||||
return false;
|
||||
}
|
||||
List<WaybillNodePunch> punches = waybillNodePunchMapper.selectList(Wrappers.<WaybillNodePunch>lambdaQuery()
|
||||
.eq(WaybillNodePunch::getWaybillId, waybillId)
|
||||
.eq(WaybillNodePunch::getIsDeleted, 0));
|
||||
return punches.stream().anyMatch(this::isLoadOrUnloadPunch);
|
||||
}
|
||||
|
||||
private boolean isLoadOrUnloadPunch(WaybillNodePunch punch) {
|
||||
if (punch == null) {
|
||||
return false;
|
||||
}
|
||||
String code = Func.toStr(punch.getNodeCode(), "").trim().toLowerCase();
|
||||
String name = Func.toStr(punch.getNodeName(), "").trim();
|
||||
return "load".equals(code) || name.contains("装货")
|
||||
|| "unload".equals(code) || name.contains("卸货")
|
||||
|| "arrival".equals(code) || name.contains("到货")
|
||||
|| "sign".equals(code) || name.contains("签收");
|
||||
}
|
||||
|
||||
private String trimText(String value) {
|
||||
return Func.toStr(value, "").trim();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void createFromImportedWaybills(String loadingNo, List<Waybill> waybills) {
|
||||
@@ -910,6 +1006,87 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
|
||||
clearAssociatedWaybillAcceptRecords(loadingManage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 进行中配载编辑同步:原有子单只更新任务可选信息,保留业务状态与接单事实;
|
||||
* 新加入子单按正常派车逻辑推导状态并清接单;被移除且未打卡的子单释放回待执行。
|
||||
*/
|
||||
private void writeWaybillsForRunningEdit(LoadingManage loadingManage, List<Long> oldWaybillIds, List<Waybill> waybills) {
|
||||
List<Long> newWaybillIds = waybillIds(loadingManage.getWaybillIdsJson());
|
||||
Set<Long> oldIdSet = new HashSet<>(oldWaybillIds);
|
||||
List<Long> removedIds = oldWaybillIds.stream()
|
||||
.filter(id -> id != null && !newWaybillIds.contains(id))
|
||||
.toList();
|
||||
releaseAssociatedWaybills(removedIds, STATUS_PENDING);
|
||||
List<Long> keptIds = newWaybillIds.stream()
|
||||
.filter(oldIdSet::contains)
|
||||
.toList();
|
||||
if (Func.isNotEmpty(keptIds)) {
|
||||
updateAssociatedWaybillTaskFields(loadingManage, keptIds, null);
|
||||
}
|
||||
List<Long> addedIds = newWaybillIds.stream()
|
||||
.filter(id -> id != null && !oldIdSet.contains(id))
|
||||
.toList();
|
||||
if (Func.isEmpty(addedIds)) {
|
||||
return;
|
||||
}
|
||||
List<Waybill> addedWaybills = waybills.stream()
|
||||
.filter(waybill -> waybill.getId() != null && addedIds.contains(waybill.getId()))
|
||||
.toList();
|
||||
Map<Long, String> statusByWaybillId = deriveWaybillBusinessStatuses(addedWaybills);
|
||||
Map<String, List<Long>> waybillIdsByStatus = new LinkedHashMap<>();
|
||||
for (Long waybillId : addedIds) {
|
||||
waybillIdsByStatus
|
||||
.computeIfAbsent(statusByWaybillId.getOrDefault(waybillId, STATUS_PENDING), key -> new ArrayList<>())
|
||||
.add(waybillId);
|
||||
}
|
||||
waybillIdsByStatus.forEach((status, ids) -> updateAssociatedWaybillFields(loadingManage, ids, status));
|
||||
clearWaybillAcceptRecords(addedIds);
|
||||
}
|
||||
|
||||
private void updateAssociatedWaybillTaskFields(LoadingManage loadingManage, List<Long> waybillIds, String status) {
|
||||
if (Func.isEmpty(waybillIds)) {
|
||||
return;
|
||||
}
|
||||
var update = Wrappers.<Waybill>lambdaUpdate()
|
||||
.in(Waybill::getId, waybillIds)
|
||||
.set(Waybill::getLoadingNo, loadingManage.getLoadingNo())
|
||||
.set(Waybill::getCarrierType, loadingManage.getCarrierType())
|
||||
.set(Waybill::getCarrierContractId, loadingManage.getCarrierContractId())
|
||||
.set(Waybill::getCarrierName, loadingManage.getCarrierName())
|
||||
.set(Waybill::getDriverName, loadingManage.getDriverName())
|
||||
.set(Waybill::getDriverPhone, loadingManage.getDriverPhone())
|
||||
.set(Waybill::getVehicleNo, loadingManage.getVehicleNo())
|
||||
.set(Waybill::getTrailerVehicleNo, loadingManage.getTrailerVehicleNo())
|
||||
.set(Waybill::getEscortName, loadingManage.getEscortName())
|
||||
.set(Waybill::getEscortPhone, loadingManage.getEscortPhone())
|
||||
.set(Waybill::getMileage, loadingManage.getMileage())
|
||||
.set(Waybill::getEstimatedStartTime, toDateTime(loadingManage.getEstimatedStartDate()))
|
||||
.set(Waybill::getEstimatedEndTime, toDateTime(loadingManage.getEstimatedEndDate()))
|
||||
.set(Waybill::getTaskRemark, loadingManage.getTaskRemark())
|
||||
.set(Waybill::getTaskInfoJson, loadingManage.getTaskInfoJson())
|
||||
.set(Waybill::getCurrentProcessNode, loadingManage.getCurrentProcessNode());
|
||||
if (Func.isNotEmpty(status)) {
|
||||
update.set(Waybill::getBusinessStatus, status);
|
||||
if (STATUS_COMPLETED.equals(status)) {
|
||||
update.set(Waybill::getEndDate, LocalDate.now());
|
||||
}
|
||||
}
|
||||
waybillMapper.update(null, update);
|
||||
}
|
||||
|
||||
private void clearWaybillAcceptRecords(List<Long> waybillIds) {
|
||||
if (Func.isEmpty(waybillIds)) {
|
||||
return;
|
||||
}
|
||||
waybillMapper.update(null, Wrappers.<Waybill>lambdaUpdate()
|
||||
.in(Waybill::getId, waybillIds)
|
||||
.set(Waybill::getDriverAcceptStatus, WaybillProcessSupport.ACCEPT_PENDING)
|
||||
.set(Waybill::getDriverAcceptTime, null)
|
||||
.set(Waybill::getDriverAcceptDriverId, null)
|
||||
.set(Waybill::getDriverRejectTime, null)
|
||||
.set(Waybill::getDriverRejectReason, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* 子运单业务状态逐张按各自项目的实时过程配置推导:需要接单 → 待执行,不需要 → 进行中。
|
||||
* <p>
|
||||
|
||||
+1
-1
@@ -1069,7 +1069,7 @@ public class ManageWaybillServiceImpl implements IManageWaybillService {
|
||||
return switch (businessStatus) {
|
||||
case STATUS_PENDING, "waiting_dispatch", "dispatching" -> 0;
|
||||
case STATUS_RUNNING -> 1;
|
||||
case STATUS_COMPLETED -> 2;
|
||||
case WaybillProcessSupport.STATUS_PENDING_RETURN, STATUS_COMPLETED -> 2;
|
||||
case STATUS_CANCELLED -> 3;
|
||||
default -> null;
|
||||
};
|
||||
|
||||
-45
@@ -2563,44 +2563,11 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
private void validateBill(BillLedger ledger, Long deptId, BigDecimal amount, boolean checkMaturity,
|
||||
Long paymentApplicationId, Long settlementId, Long preSettlementId) {
|
||||
if (ledger == null || Objects.equals(ledger.getIsDeleted(), 1)) throw new ServiceException("所选汇票台账不存在");
|
||||
boolean partyMatched = settlementPartiesMatch(ledger, settlementId, preSettlementId);
|
||||
if (!"received".equals(ledger.getBillType()) && !partyMatched) {
|
||||
throw new ServiceException("汇票付款仅可选择收票类型的汇票,或出票单位与收票单位均为当前结算收付款方的汇票");
|
||||
}
|
||||
if (checkMaturity && (ledger.getMaturityDate() == null || ledger.getMaturityDate().isBefore(LocalDate.now()))) {
|
||||
throw new ServiceException("所选汇票已到期");
|
||||
}
|
||||
BigDecimal available = money(ledger.getAvailableBalance()).add(occupiedAmount(paymentApplicationId, ledger.getId()));
|
||||
if (money(amount).compareTo(available) > 0) throw new ServiceException("申请付款金额超过汇票可用余额");
|
||||
if (!partyMatched && !departmentAvailable(ledger, deptId)) throw new ServiceException("当前使用部门不在汇票可用部门范围内");
|
||||
}
|
||||
|
||||
/** 出票单位、收票单位与结算付款方、收款方一致(顺序不限) */
|
||||
private boolean settlementPartiesMatch(BillLedger ledger, Long settlementId, Long preSettlementId) {
|
||||
String payerName = null;
|
||||
String payeeName = null;
|
||||
if (settlementId != null) {
|
||||
FormalSettlement settlement = formalSettlementMapper.selectById(settlementId);
|
||||
if (settlement != null && !Objects.equals(settlement.getIsDeleted(), 1)) {
|
||||
payerName = settlement.getPayerName();
|
||||
payeeName = settlement.getPayeeName();
|
||||
}
|
||||
}
|
||||
if ((payerName == null || payeeName == null) && preSettlementId != null) {
|
||||
PreSettlement settlement = preSettlementMapper.selectById(preSettlementId);
|
||||
if (settlement != null && !Objects.equals(settlement.getIsDeleted(), 1)) {
|
||||
payerName = settlement.getPayerName();
|
||||
payeeName = settlement.getPayeeName();
|
||||
}
|
||||
}
|
||||
String issuer = ledger.getIssuerName() == null ? "" : ledger.getIssuerName().trim();
|
||||
String receiver = ledger.getReceiverName() == null ? "" : ledger.getReceiverName().trim();
|
||||
String payer = payerName == null ? "" : payerName.trim();
|
||||
String payee = payeeName == null ? "" : payeeName.trim();
|
||||
if (issuer.isEmpty() || receiver.isEmpty() || payer.isEmpty() || payee.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return (issuer.equals(payer) && receiver.equals(payee)) || (issuer.equals(payee) && receiver.equals(payer));
|
||||
}
|
||||
|
||||
private void useBillBalance(PaymentApplication entity) {
|
||||
@@ -2756,18 +2723,6 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
return entity;
|
||||
}
|
||||
|
||||
private boolean departmentAvailable(BillLedger ledger, Long deptId) {
|
||||
if (Func.isEmpty(ledger.getAvailableDeptIdsJson())) return false;
|
||||
try {
|
||||
Object parsed = JsonUtil.parse(ledger.getAvailableDeptIdsJson(), List.class);
|
||||
if (!(parsed instanceof List<?> values)) return false;
|
||||
if (values.stream().anyMatch(value -> "all".equals(String.valueOf(value)))) return true;
|
||||
return deptId != null && values.stream().anyMatch(value -> String.valueOf(deptId).equals(String.valueOf(value)));
|
||||
} catch (Exception exception) {
|
||||
throw new ServiceException("汇票可用部门配置不正确");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBillPayment(String paymentMethod) {
|
||||
if (Func.isEmpty(paymentMethod)) return false;
|
||||
|
||||
+45
-3
@@ -34,6 +34,7 @@ import org.springblade.core.tenant.annotation.TenantIgnore;
|
||||
import org.springblade.core.tool.jackson.JsonUtil;
|
||||
import org.springblade.core.tool.utils.BeanUtil;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.system.cache.SysCache;
|
||||
import org.springblade.system.cache.UserCache;
|
||||
import org.springblade.system.pojo.entity.Dept;
|
||||
import org.springblade.transport.excel.ProjectApplyExcel;
|
||||
@@ -488,8 +489,7 @@ public class ProjectApplyServiceImpl extends BaseServiceImpl<ProjectApplyMapper,
|
||||
projectApply.setUndertakeDeptName(dept.getDeptName());
|
||||
}
|
||||
if (Func.isEmpty(projectApply.getBusinessDeptId())) {
|
||||
projectApply.setBusinessDeptId(firstUndertakeDeptId(projectApply.getUndertakeDeptId()));
|
||||
projectApply.setBusinessDeptName(firstUndertakeDeptName(projectApply.getUndertakeDeptName()));
|
||||
fillDefaultBusinessDept(projectApply);
|
||||
}
|
||||
if (Func.isEmpty(projectApply.getHandlerUserId())) {
|
||||
projectApply.setHandlerUserId(AuthUtil.getUserId());
|
||||
@@ -748,7 +748,7 @@ public class ProjectApplyServiceImpl extends BaseServiceImpl<ProjectApplyMapper,
|
||||
private void validateSubmit(ProjectApply projectApply) {
|
||||
validateDraft(projectApply);
|
||||
TransportBusinessSupport.validateRequired(projectApply.getProjectShortName(), "请输入项目简称");
|
||||
TransportBusinessSupport.validateRequired(projectApply.getBusinessDeptName(), "请选择业务部门");
|
||||
validateBusinessDept(projectApply);
|
||||
TransportBusinessSupport.validateRequired(projectApply.getUndertakeDeptName(), "请选择平台公司");
|
||||
TransportBusinessSupport.validateRequired(projectApply.getBusinessMode(), "请选择业务模式");
|
||||
TransportBusinessSupport.validateRequired(projectApply.getCustomerNames(), "请选择客户");
|
||||
@@ -1066,6 +1066,48 @@ public class ProjectApplyServiceImpl extends BaseServiceImpl<ProjectApplyMapper,
|
||||
return exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增时默认业务部门:取当前用户所属部门中第一个「是否业务部门=是」的组织。
|
||||
*/
|
||||
private void fillDefaultBusinessDept(ProjectApply projectApply) {
|
||||
List<Long> deptIds = Func.toLongList(AuthUtil.getDeptId());
|
||||
if (Func.isEmpty(deptIds)) {
|
||||
return;
|
||||
}
|
||||
for (Long deptId : deptIds) {
|
||||
if (Func.isEmpty(deptId) || deptId <= 0) {
|
||||
continue;
|
||||
}
|
||||
Dept dept = SysCache.getDept(deptId);
|
||||
if (dept != null && Objects.equals(dept.getIsBusinessDept(), 1)) {
|
||||
projectApply.setBusinessDeptId(dept.getId());
|
||||
projectApply.setBusinessDeptName(dept.getDeptName());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验业务部门必须是组织中标记为「是否业务部门=是」的部门。
|
||||
*/
|
||||
private void validateBusinessDept(ProjectApply projectApply) {
|
||||
Long businessDeptId = projectApply.getBusinessDeptId();
|
||||
if (Func.isEmpty(businessDeptId)) {
|
||||
throw new ServiceException("请选择业务部门");
|
||||
}
|
||||
Dept dept = SysCache.getDept(businessDeptId);
|
||||
if (dept == null || Objects.equals(dept.getIsDeleted(), 1)) {
|
||||
throw new ServiceException("业务部门不存在");
|
||||
}
|
||||
if (!Objects.equals(dept.getIsBusinessDept(), 1)) {
|
||||
throw new ServiceException("请选择组织中标记为业务部门的部门");
|
||||
}
|
||||
if (Func.isNotEmpty(dept.getDeptName())) {
|
||||
projectApply.setBusinessDeptName(dept.getDeptName());
|
||||
}
|
||||
TransportBusinessSupport.validateRequired(projectApply.getBusinessDeptName(), "请选择业务部门");
|
||||
}
|
||||
|
||||
private void normalizeUndertakeDept(ProjectApply projectApply) {
|
||||
if (projectApply == null) {
|
||||
return;
|
||||
|
||||
+1
@@ -3295,6 +3295,7 @@ public class ReceivablePayableDetailServiceImpl
|
||||
private String waybillStatusName(String status) {
|
||||
return switch (status == null ? "" : status) {
|
||||
case "completed" -> "已完成";
|
||||
case "pending_return" -> "待确认回单";
|
||||
case "processing", "running", "in_progress", "inProgress" -> "进行中";
|
||||
case "pending", "created" -> "待执行";
|
||||
case "cancelled", "canceled" -> "已取消";
|
||||
|
||||
+14
-1
@@ -967,6 +967,7 @@ public class WaybillServiceImpl extends BaseServiceImpl<WaybillMapper, Waybill>
|
||||
*/
|
||||
private static boolean passedAcceptStage(String businessStatus) {
|
||||
return "running".equals(businessStatus)
|
||||
|| WaybillProcessSupport.STATUS_PENDING_RETURN.equals(businessStatus)
|
||||
|| "completed".equals(businessStatus)
|
||||
|| "cancelled".equals(businessStatus);
|
||||
}
|
||||
@@ -1507,6 +1508,13 @@ public class WaybillServiceImpl extends BaseServiceImpl<WaybillMapper, Waybill>
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean confirmReturnReceipt(Long id) {
|
||||
Waybill waybill = loadEditable(id, true);
|
||||
String status = waybill.getBusinessStatus();
|
||||
// pending_return 为正规待确认态;running/processing 兼容历史「打完卡仍停在进行中」的数据
|
||||
if (!WaybillProcessSupport.STATUS_PENDING_RETURN.equals(status)
|
||||
&& !"running".equals(status)
|
||||
&& !"processing".equals(status)) {
|
||||
throw new ServiceException("当前状态不允许确认回单");
|
||||
}
|
||||
String processJson = LiveProcessConfigSupport.resolve(
|
||||
LiveProcessConfigSupport.byProject(processConfigService, waybill.getProjectId()),
|
||||
waybill.getProcessJson());
|
||||
@@ -1585,7 +1593,12 @@ public class WaybillServiceImpl extends BaseServiceImpl<WaybillMapper, Waybill>
|
||||
BusinessRemoveResultVO result = new BusinessRemoveResultVO();
|
||||
for (Waybill waybill : listByIds(idList)) {
|
||||
try {
|
||||
complete(waybill.getId());
|
||||
// 待确认回单走确认回单校验(打卡节点 + 未了结异常);其它状态仍走普通完成
|
||||
if (WaybillProcessSupport.STATUS_PENDING_RETURN.equals(waybill.getBusinessStatus())) {
|
||||
confirmReturnReceipt(waybill.getId());
|
||||
} else {
|
||||
complete(waybill.getId());
|
||||
}
|
||||
result.setSuccessCount(result.getSuccessCount() + 1);
|
||||
} catch (Exception exception) {
|
||||
log.error("批量完成运单失败,waybillId:{}, waybillNo:{}, failureReason:{}",
|
||||
|
||||
+14
-5
@@ -49,6 +49,8 @@ public final class WaybillProcessSupport {
|
||||
|
||||
public static final String STATUS_PENDING = "pending";
|
||||
public static final String STATUS_RUNNING = "running";
|
||||
/** 司机打卡已完成、待运管员确认回单 */
|
||||
public static final String STATUS_PENDING_RETURN = "pending_return";
|
||||
public static final String ACCEPT_PENDING = "pending";
|
||||
public static final String ACCEPT_ACCEPTED = "accepted";
|
||||
public static final String ACCEPT_REJECTED = "rejected";
|
||||
@@ -134,14 +136,17 @@ public final class WaybillProcessSupport {
|
||||
}
|
||||
|
||||
/**
|
||||
* 运单已结束:已完成或已取消。此后不再接受司机打卡。
|
||||
* 运单已结束:已完成、已取消,或待确认回单。此后不再接受司机打卡。
|
||||
* <p>
|
||||
* 只认这两个状态,大小写不敏感。草稿、待执行、待调度、调度中的运单司机仍要能打卡,
|
||||
* 待确认回单表示司机侧节点已打完,等待运管确认,不能再打卡。
|
||||
* 草稿、待执行、待调度、调度中的运单司机仍要能打卡,
|
||||
* 所以不能按 {@link #isTerminalBusinessStatus} 的「终态或调度中间态」口径判定。
|
||||
*/
|
||||
public static boolean isPunchEnded(String businessStatus) {
|
||||
String status = stringVal(businessStatus);
|
||||
return "completed".equalsIgnoreCase(status) || "cancelled".equalsIgnoreCase(status);
|
||||
return "completed".equalsIgnoreCase(status)
|
||||
|| "cancelled".equalsIgnoreCase(status)
|
||||
|| STATUS_PENDING_RETURN.equalsIgnoreCase(status);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,6 +160,9 @@ public final class WaybillProcessSupport {
|
||||
if ("cancelled".equalsIgnoreCase(status)) {
|
||||
return "运单已取消";
|
||||
}
|
||||
if (STATUS_PENDING_RETURN.equalsIgnoreCase(status)) {
|
||||
return "运单待确认回单";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -213,7 +221,8 @@ public final class WaybillProcessSupport {
|
||||
|| "completed".equals(businessStatus)
|
||||
|| "cancelled".equals(businessStatus)
|
||||
|| "waiting_dispatch".equals(businessStatus)
|
||||
|| "dispatching".equals(businessStatus);
|
||||
|| "dispatching".equals(businessStatus)
|
||||
|| STATUS_PENDING_RETURN.equals(businessStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -221,7 +230,7 @@ public final class WaybillProcessSupport {
|
||||
* <p>
|
||||
* 需要接单(接单节点 confirmMode=yes)且尚未接单(未响应 / 已拒绝)→ pending(待执行);
|
||||
* 已接单 → running(进行中);不需要接单 → running(仅当当前为空或 pending 时提升)。
|
||||
* draft / completed / cancelled 等终态或调度中间态不改动。
|
||||
* draft / completed / cancelled / pending_return 等终态或调度中间态不改动。
|
||||
*/
|
||||
public static String normalizeBusinessStatus(String businessStatus, String processJson) {
|
||||
return normalizeBusinessStatus(businessStatus, processJson, null);
|
||||
|
||||
+1
@@ -122,6 +122,7 @@ public class WaybillWrapper extends BaseEntityWrapper<Waybill, WaybillVO> {
|
||||
case "waiting_dispatch" -> "待调度";
|
||||
case "dispatching" -> "调度中";
|
||||
case "running", "processing", "in_progress", "inProgress" -> "进行中";
|
||||
case "pending_return" -> "待确认回单";
|
||||
case "completed" -> "已完成";
|
||||
case "cancelled" -> "已取消";
|
||||
case "closed" -> "已关闭";
|
||||
|
||||
+5
-2
@@ -337,12 +337,14 @@ class WaybillProcessSupportTest {
|
||||
// ------------------------------------------------------------ 结束门禁
|
||||
|
||||
@Test
|
||||
@DisplayName("结束门禁:只认已完成与已取消,大小写不敏感")
|
||||
@DisplayName("结束门禁:已完成、已取消、待确认回单,大小写不敏感")
|
||||
void punchEndedOnlyForCompletedAndCancelled() {
|
||||
assertTrue(WaybillProcessSupport.isPunchEnded("completed"));
|
||||
assertTrue(WaybillProcessSupport.isPunchEnded("COMPLETED"));
|
||||
assertTrue(WaybillProcessSupport.isPunchEnded("cancelled"));
|
||||
assertTrue(WaybillProcessSupport.isPunchEnded("Cancelled"));
|
||||
assertTrue(WaybillProcessSupport.isPunchEnded("pending_return"));
|
||||
assertTrue(WaybillProcessSupport.isPunchEnded("PENDING_RETURN"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -358,11 +360,12 @@ class WaybillProcessSupportTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("结束门禁文案:完成与取消各一句,非结束态没有文案")
|
||||
@DisplayName("结束门禁文案:完成、取消、待确认回单各一句,非结束态没有文案")
|
||||
void punchEndedReasonOnlyForEndedStatuses() {
|
||||
assertEquals("运单已完成", WaybillProcessSupport.punchEndedReason("completed"));
|
||||
assertEquals("运单已完成", WaybillProcessSupport.punchEndedReason(" COMPLETED "));
|
||||
assertEquals("运单已取消", WaybillProcessSupport.punchEndedReason("cancelled"));
|
||||
assertEquals("运单待确认回单", WaybillProcessSupport.punchEndedReason("pending_return"));
|
||||
assertNull(WaybillProcessSupport.punchEndedReason(null));
|
||||
assertNull(WaybillProcessSupport.punchEndedReason(""));
|
||||
assertNull(WaybillProcessSupport.punchEndedReason(" "));
|
||||
|
||||
@@ -311,6 +311,7 @@ CREATE TABLE `blade_dept` (
|
||||
`mnemonic_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '助记码',
|
||||
`carrier_customer_id` bigint NULL DEFAULT NULL COMMENT '承运商客商档案主键',
|
||||
`is_platform_company` tinyint NOT NULL DEFAULT 0 COMMENT '是否平台公司:0否,1是',
|
||||
`is_business_dept` tinyint NOT NULL DEFAULT 0 COMMENT '是否业务部门:0否,1是',
|
||||
`oa_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'OA主键',
|
||||
`oa_sup_sub_com_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'OA上级主键',
|
||||
`sort` int NULL DEFAULT NULL COMMENT '排序',
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
-- 机构表:新增「是否业务部门」字段,默认否
|
||||
-- 全量 OA 同步时须保留本地已配置值,不得覆盖
|
||||
|
||||
ALTER TABLE `blade_dept`
|
||||
ADD COLUMN `is_business_dept` tinyint NOT NULL DEFAULT 0 COMMENT '是否业务部门:0否,1是' AFTER `is_platform_company`;
|
||||
@@ -7,8 +7,12 @@
|
||||
-- 3. 只统计各功能列表对应的主表。随主单保存的明细、联系人、附件、变更流水不重复计数。
|
||||
-- 4. 含已逻辑删除的数据,因为这些记录确实被创建过。
|
||||
-- 5. 客商档案菜单挂在「车/船务管理」下,这里按统计口径单独计入「客商管理」。
|
||||
-- 6. 未纳入:结算管理、首付款管理、在途管理,以及系统管理下的开票项目。
|
||||
-- 6. 未纳入:在途管理,以及系统管理下的开票项目。
|
||||
-- 7. 导入运单产生的运单计入「业务模块-运单管理」,不另计导入批次。
|
||||
-- 导入结算单产生的正式结算单计入「结算管理」的付款结算单或收款结算单,不另计导入批次。
|
||||
-- 8. 付款结算单、收款结算单共用 blade_formal_settlement,按 settlement_type 区分(payable/receivable)。
|
||||
-- 应收、应付共用 blade_receivable_payable_detail,同样按 settlement_type 区分。
|
||||
-- 9. 菜单名称为「收付款管理」,统计模块名与菜单一致。
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
@@ -396,7 +400,124 @@ SELECT t.create_user, 8, '运力模块', 4, '车辆调度', 'blade_transport_veh
|
||||
FROM blade_transport_vehicle_dispatch t
|
||||
INNER JOIN tmp_stat_user u ON u.id = t.create_user
|
||||
WHERE t.create_time >= @stat_start AND t.create_time < @stat_end_exclusive
|
||||
GROUP BY t.create_user;
|
||||
GROUP BY t.create_user
|
||||
;
|
||||
|
||||
INSERT INTO tmp_stat_detail (create_user, module_sort, module_name, biz_sort, biz_name, table_name, cnt)
|
||||
SELECT t.create_user, 9, '结算管理', 1, '应收', 'blade_receivable_payable_detail', COUNT(*)
|
||||
FROM blade_receivable_payable_detail t
|
||||
INNER JOIN tmp_stat_user u ON u.id = t.create_user
|
||||
WHERE t.create_time >= @stat_start AND t.create_time < @stat_end_exclusive
|
||||
AND t.settlement_type = 'receivable'
|
||||
GROUP BY t.create_user
|
||||
;
|
||||
|
||||
INSERT INTO tmp_stat_detail (create_user, module_sort, module_name, biz_sort, biz_name, table_name, cnt)
|
||||
SELECT t.create_user, 9, '结算管理', 2, '应付', 'blade_receivable_payable_detail', COUNT(*)
|
||||
FROM blade_receivable_payable_detail t
|
||||
INNER JOIN tmp_stat_user u ON u.id = t.create_user
|
||||
WHERE t.create_time >= @stat_start AND t.create_time < @stat_end_exclusive
|
||||
AND t.settlement_type = 'payable'
|
||||
GROUP BY t.create_user
|
||||
;
|
||||
|
||||
INSERT INTO tmp_stat_detail (create_user, module_sort, module_name, biz_sort, biz_name, table_name, cnt)
|
||||
SELECT t.create_user, 9, '结算管理', 3, '预付结算单', 'blade_pre_settlement', COUNT(*)
|
||||
FROM blade_pre_settlement t
|
||||
INNER JOIN tmp_stat_user u ON u.id = t.create_user
|
||||
WHERE t.create_time >= @stat_start AND t.create_time < @stat_end_exclusive
|
||||
GROUP BY t.create_user
|
||||
;
|
||||
|
||||
INSERT INTO tmp_stat_detail (create_user, module_sort, module_name, biz_sort, biz_name, table_name, cnt)
|
||||
SELECT t.create_user, 9, '结算管理', 4, '付款结算单', 'blade_formal_settlement', COUNT(*)
|
||||
FROM blade_formal_settlement t
|
||||
INNER JOIN tmp_stat_user u ON u.id = t.create_user
|
||||
WHERE t.create_time >= @stat_start AND t.create_time < @stat_end_exclusive
|
||||
AND t.settlement_type = 'payable'
|
||||
GROUP BY t.create_user
|
||||
;
|
||||
|
||||
INSERT INTO tmp_stat_detail (create_user, module_sort, module_name, biz_sort, biz_name, table_name, cnt)
|
||||
SELECT t.create_user, 9, '结算管理', 5, '收款结算单', 'blade_formal_settlement', COUNT(*)
|
||||
FROM blade_formal_settlement t
|
||||
INNER JOIN tmp_stat_user u ON u.id = t.create_user
|
||||
WHERE t.create_time >= @stat_start AND t.create_time < @stat_end_exclusive
|
||||
AND t.settlement_type = 'receivable'
|
||||
GROUP BY t.create_user
|
||||
;
|
||||
|
||||
INSERT INTO tmp_stat_detail (create_user, module_sort, module_name, biz_sort, biz_name, table_name, cnt)
|
||||
SELECT t.create_user, 9, '结算管理', 6, '运输对账', 'blade_transport_reconciliation', COUNT(*)
|
||||
FROM blade_transport_reconciliation t
|
||||
INNER JOIN tmp_stat_user u ON u.id = t.create_user
|
||||
WHERE t.create_time >= @stat_start AND t.create_time < @stat_end_exclusive
|
||||
GROUP BY t.create_user
|
||||
;
|
||||
|
||||
INSERT INTO tmp_stat_detail (create_user, module_sort, module_name, biz_sort, biz_name, table_name, cnt)
|
||||
SELECT t.create_user, 9, '结算管理', 7, '结算调整单', 'blade_settlement_adjustment', COUNT(*)
|
||||
FROM blade_settlement_adjustment t
|
||||
INNER JOIN tmp_stat_user u ON u.id = t.create_user
|
||||
WHERE t.create_time >= @stat_start AND t.create_time < @stat_end_exclusive
|
||||
GROUP BY t.create_user
|
||||
;
|
||||
|
||||
INSERT INTO tmp_stat_detail (create_user, module_sort, module_name, biz_sort, biz_name, table_name, cnt)
|
||||
SELECT t.create_user, 10, '收付款管理', 1, '付款管理', 'blade_payment_application', COUNT(*)
|
||||
FROM blade_payment_application t
|
||||
INNER JOIN tmp_stat_user u ON u.id = t.create_user
|
||||
WHERE t.create_time >= @stat_start AND t.create_time < @stat_end_exclusive
|
||||
GROUP BY t.create_user
|
||||
;
|
||||
|
||||
INSERT INTO tmp_stat_detail (create_user, module_sort, module_name, biz_sort, biz_name, table_name, cnt)
|
||||
SELECT t.create_user, 10, '收付款管理', 2, '开票管理', 'blade_invoice_application', COUNT(*)
|
||||
FROM blade_invoice_application t
|
||||
INNER JOIN tmp_stat_user u ON u.id = t.create_user
|
||||
WHERE t.create_time >= @stat_start AND t.create_time < @stat_end_exclusive
|
||||
GROUP BY t.create_user
|
||||
;
|
||||
|
||||
INSERT INTO tmp_stat_detail (create_user, module_sort, module_name, biz_sort, biz_name, table_name, cnt)
|
||||
SELECT t.create_user, 10, '收付款管理', 3, '收票管理', 'blade_invoice_receipt', COUNT(*)
|
||||
FROM blade_invoice_receipt t
|
||||
INNER JOIN tmp_stat_user u ON u.id = t.create_user
|
||||
WHERE t.create_time >= @stat_start AND t.create_time < @stat_end_exclusive
|
||||
GROUP BY t.create_user
|
||||
;
|
||||
|
||||
INSERT INTO tmp_stat_detail (create_user, module_sort, module_name, biz_sort, biz_name, table_name, cnt)
|
||||
SELECT t.create_user, 10, '收付款管理', 4, '收款流水', 'blade_kingdee_receipt_flow', COUNT(*)
|
||||
FROM blade_kingdee_receipt_flow t
|
||||
INNER JOIN tmp_stat_user u ON u.id = t.create_user
|
||||
WHERE t.create_time >= @stat_start AND t.create_time < @stat_end_exclusive
|
||||
GROUP BY t.create_user
|
||||
;
|
||||
|
||||
INSERT INTO tmp_stat_detail (create_user, module_sort, module_name, biz_sort, biz_name, table_name, cnt)
|
||||
SELECT t.create_user, 10, '收付款管理', 5, '认领记录', 'blade_receipt_claim', COUNT(*)
|
||||
FROM blade_receipt_claim t
|
||||
INNER JOIN tmp_stat_user u ON u.id = t.create_user
|
||||
WHERE t.create_time >= @stat_start AND t.create_time < @stat_end_exclusive
|
||||
GROUP BY t.create_user
|
||||
;
|
||||
|
||||
INSERT INTO tmp_stat_detail (create_user, module_sort, module_name, biz_sort, biz_name, table_name, cnt)
|
||||
SELECT t.create_user, 10, '收付款管理', 6, '汇票台账', 'blade_bill_ledger', COUNT(*)
|
||||
FROM blade_bill_ledger t
|
||||
INNER JOIN tmp_stat_user u ON u.id = t.create_user
|
||||
WHERE t.create_time >= @stat_start AND t.create_time < @stat_end_exclusive
|
||||
GROUP BY t.create_user
|
||||
;
|
||||
|
||||
INSERT INTO tmp_stat_detail (create_user, module_sort, module_name, biz_sort, biz_name, table_name, cnt)
|
||||
SELECT t.create_user, 10, '收付款管理', 7, '汇票付款', 'blade_bill_payment', COUNT(*)
|
||||
FROM blade_bill_payment t
|
||||
INNER JOIN tmp_stat_user u ON u.id = t.create_user
|
||||
WHERE t.create_time >= @stat_start AND t.create_time < @stat_end_exclusive
|
||||
GROUP BY t.create_user
|
||||
;
|
||||
|
||||
-- 结果 1:账号匹配情况。用户 ID 为空表示库中没有该账号。
|
||||
SELECT
|
||||
@@ -422,6 +543,8 @@ SELECT
|
||||
IFNULL(SUM(CASE WHEN d.module_name = '业务模块' THEN d.cnt ELSE 0 END), 0) AS `业务模块`,
|
||||
IFNULL(SUM(CASE WHEN d.module_name = '车/船务模块' THEN d.cnt ELSE 0 END), 0) AS `车/船务模块`,
|
||||
IFNULL(SUM(CASE WHEN d.module_name = '运力模块' THEN d.cnt ELSE 0 END), 0) AS `运力模块`,
|
||||
IFNULL(SUM(CASE WHEN d.module_name = '结算管理' THEN d.cnt ELSE 0 END), 0) AS `结算管理`,
|
||||
IFNULL(SUM(CASE WHEN d.module_name = '收付款管理' THEN d.cnt ELSE 0 END), 0) AS `收付款管理`,
|
||||
IFNULL(SUM(d.cnt), 0) AS `合计`
|
||||
FROM tmp_stat_account a
|
||||
LEFT JOIN tmp_stat_user u ON u.account = a.account
|
||||
|
||||
Reference in New Issue
Block a user