feat: 结算调整单审批自动推送与冲销后重推新单
This commit is contained in:
+34
-1
@@ -17,7 +17,40 @@ public interface ISettlementAdjustmentService {
|
||||
Long saveDraft(SettlementAdjustmentSaveRequest request);
|
||||
void removeDraft(Long id);
|
||||
void submit(SettlementAdjustmentStatusRequest request);
|
||||
void approve(SettlementAdjustmentStatusRequest request);
|
||||
/**
|
||||
* 审批通过:未推送场景回写原单并发布金蝶自动推送事件;已推送场景原单零改动仅追加变更记录。
|
||||
*
|
||||
* @param request 审批请求
|
||||
* @return 已推送场景的手工冲销提示文案,未推送场景返回 null
|
||||
*/
|
||||
String approve(SettlementAdjustmentStatusRequest request);
|
||||
void returnBill(SettlementAdjustmentStatusRequest request);
|
||||
String repush(Long adjustmentId);
|
||||
|
||||
/**
|
||||
* 选单后金蝶冲销预检(软提示,不阻断建单):未推送 / 已推送已冲销 / 已推送未冲销;
|
||||
* 金蝶查询异常降级返回「未校验」,由审批分流与重推闸门兜底
|
||||
*
|
||||
* @param formalSettlementId 选定正式结算单id
|
||||
* @return syncStatus / writtenOff / message
|
||||
*/
|
||||
Map<String, Object> kingdeeWriteOffPrecheck(Long formalSettlementId);
|
||||
|
||||
/**
|
||||
* 推送金蝶(未推送/生成失败场景):推送关联正式结算单,成功后由正式结算单回填调整单金蝶单号与同步状态
|
||||
*
|
||||
* @param adjustmentId 结算调整单id
|
||||
* @return 金蝶单据编号
|
||||
*/
|
||||
String syncKingdee(Long adjustmentId);
|
||||
|
||||
/**
|
||||
* 重推克隆+应用(独立事务,由 repush 经自代理调用):克隆原单为新正式结算单并应用调整,
|
||||
* 供推送失败重试时幂等复用
|
||||
*
|
||||
* @param originalSettlementId 原正式结算单id
|
||||
* @param adjustmentId 结算调整单id
|
||||
* @return 新正式结算单id
|
||||
*/
|
||||
Long cloneAndApplyForRepush(Long originalSettlementId, Long adjustmentId);
|
||||
}
|
||||
|
||||
+3
@@ -32,6 +32,9 @@ public final class KingdeeLockConstant {
|
||||
/** 来源操作类型:单据删除(解锁回调携带 DELETE 时 WLTMS 废除源单并还原关联数据) */
|
||||
public static final String OPERATION_DELETE = "DELETE";
|
||||
|
||||
/** 来源操作类型:结算调整重推(结算调整单重推后解锁原结算单旧锁记录,非金蝶回调) */
|
||||
public static final String OPERATION_ADJUST_REPUSH = "ADJUST_REPUSH";
|
||||
|
||||
/** 系统标识:WLTMS(运输管理系统,即本系统) */
|
||||
public static final String SYSTEM_WLTMS = "WLTMS";
|
||||
|
||||
|
||||
+16
-1
@@ -7,6 +7,8 @@ import org.springblade.core.mp.support.Condition;
|
||||
import org.springblade.core.mp.support.Query;
|
||||
import org.springblade.core.secure.annotation.PreAuth;
|
||||
import org.springblade.core.tool.api.R;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.transport.listener.KingdeeApprovalSyncListener;
|
||||
import org.springblade.transport.pojo.dto.SettlementAdjustmentSaveRequest;
|
||||
import org.springblade.transport.pojo.dto.SettlementAdjustmentStatusRequest;
|
||||
import org.springblade.transport.pojo.entity.SettlementAdjustment;
|
||||
@@ -33,7 +35,20 @@ public class SettlementAdjustmentController extends BladeController {
|
||||
@PostMapping("/save") public R<Long> save(@RequestBody SettlementAdjustmentSaveRequest request) { return R.data(service.saveDraft(request)); }
|
||||
@PostMapping("/remove") public R remove(@RequestParam Long id) { service.removeDraft(id); return R.success("删除成功"); }
|
||||
@PostMapping("/submit") public R submit(@RequestBody SettlementAdjustmentStatusRequest request) { service.submit(request); return R.success("提交成功"); }
|
||||
@PostMapping("/approve") public R approve(@RequestBody SettlementAdjustmentStatusRequest request) { service.approve(request); return R.success("审批通过"); }
|
||||
@PostMapping("/approve") public R approve(@RequestBody SettlementAdjustmentStatusRequest request) {
|
||||
String hint = service.approve(request);
|
||||
// 未推送场景自动推送失败原因以警告文案返回(data=false 供前端区分提示样式)
|
||||
String syncFailure = KingdeeApprovalSyncListener.pollSyncFailure();
|
||||
if (Func.isNotBlank(syncFailure)) {
|
||||
return R.data(Boolean.FALSE, "审批通过,但自动同步金蝶失败:" + syncFailure);
|
||||
}
|
||||
if (Func.isNotBlank(hint)) {
|
||||
return R.data(Boolean.TRUE, "审批通过;" + hint);
|
||||
}
|
||||
return R.success("审批通过");
|
||||
}
|
||||
@PostMapping("/return") public R returnBill(@RequestBody SettlementAdjustmentStatusRequest request) { service.returnBill(request); return R.success("已驳回"); }
|
||||
@PostMapping("/repush") public R<String> repush(@RequestParam Long id) { return R.data(service.repush(id)); }
|
||||
@GetMapping("/kingdee-writeoff-precheck") public R<Map<String, Object>> kingdeeWriteOffPrecheck(@RequestParam Long formalSettlementId) { return R.data(service.kingdeeWriteOffPrecheck(formalSettlementId)); }
|
||||
@PostMapping("/sync-kingdee") public R<String> syncKingdee(@RequestParam Long id) { return R.data(service.syncKingdee(id)); }
|
||||
}
|
||||
|
||||
+11
@@ -60,6 +60,17 @@ public interface IKingdeeBillLockService extends IService<KingdeeBillLock> {
|
||||
*/
|
||||
void checkEditable(String sourceBillType, Long sourceBillId);
|
||||
|
||||
/**
|
||||
* 结算调整重推解锁:把源单当前「锁定中」的锁记录标记为 unlocked(非金蝶回调,仅本地解锁留痕),
|
||||
* 供原结算单被调整重推生成新单后解除旧锁使用;新单另行落新锁记录
|
||||
*
|
||||
* @param sourceBillType WLTMS 单据类型
|
||||
* @param sourceBillId WLTMS 业务主键
|
||||
* @param operator 操作人
|
||||
* @return 解锁的记录数
|
||||
*/
|
||||
int unlockByAdjustRepush(String sourceBillType, Long sourceBillId, String operator);
|
||||
|
||||
/**
|
||||
* 批量查源单当前锁状态(供列表/详情页填充展示标识):
|
||||
* 每源单取最新一条非终态锁记录(locked/failed),unlocked 为终态不返回(前端视为无锁/已解锁)
|
||||
|
||||
+27
-2
@@ -251,6 +251,28 @@ public class KingdeeBillLockServiceImpl extends ServiceImpl<KingdeeBillLockMappe
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int unlockByAdjustRepush(String sourceBillType, Long sourceBillId, String operator) {
|
||||
List<KingdeeBillLock> lockedRecords = this.list(Wrappers.<KingdeeBillLock>lambdaQuery()
|
||||
.eq(KingdeeBillLock::getSourceBillType, sourceBillType)
|
||||
.eq(KingdeeBillLock::getSourceBillId, sourceBillId)
|
||||
.eq(KingdeeBillLock::getLockStatus, KingdeeLockConstant.STATUS_LOCKED));
|
||||
if (Func.isEmpty(lockedRecords)) {
|
||||
return 0;
|
||||
}
|
||||
LocalDateTime unlockTime = LocalDateTime.now();
|
||||
for (KingdeeBillLock lockRecord : lockedRecords) {
|
||||
lockRecord.setLockStatus(KingdeeLockConstant.STATUS_UNLOCKED);
|
||||
lockRecord.setOperationType(KingdeeLockConstant.OPERATION_ADJUST_REPUSH);
|
||||
lockRecord.setUnlockTime(unlockTime);
|
||||
lockRecord.setNotifyOperator(Func.isEmpty(operator) ? "system" : operator);
|
||||
}
|
||||
this.updateBatchById(lockedRecords);
|
||||
log.info("结算调整重推解锁旧锁:源单[{}:{}],解锁{}张,操作人={}", sourceBillType, sourceBillId, lockedRecords.size(), operator);
|
||||
return lockedRecords.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkEditable(String sourceBillType, Long sourceBillId) {
|
||||
long lockedCount = this.count(Wrappers.<KingdeeBillLock>lambdaQuery()
|
||||
@@ -309,8 +331,11 @@ public class KingdeeBillLockServiceImpl extends ServiceImpl<KingdeeBillLockMappe
|
||||
}
|
||||
row.setKingdeeUnlockTime(unlockRecord.getUnlockTime());
|
||||
row.setKingdeeUnlockOperator(unlockRecord.getNotifyOperator());
|
||||
row.setKingdeeUnlockOperationName(KingdeeLockConstant.OPERATION_DELETE.equals(unlockRecord.getOperationType())
|
||||
? "金蝶删单" : "金蝶锁单");
|
||||
row.setKingdeeUnlockOperationName(switch (Func.toStr(unlockRecord.getOperationType())) {
|
||||
case KingdeeLockConstant.OPERATION_DELETE -> "金蝶删单";
|
||||
case KingdeeLockConstant.OPERATION_ADJUST_REPUSH -> "结算调整重推";
|
||||
default -> "金蝶锁单";
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+170
-16
@@ -4,12 +4,18 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.utils.Func;
|
||||
import org.springblade.core.tool.utils.SpringUtil;
|
||||
import org.springblade.system.cache.UserCache;
|
||||
import org.springblade.transport.constant.KingdeeBfiConstant;
|
||||
import org.springblade.transport.constant.TransportBusiConstant;
|
||||
import org.springblade.transport.event.KingdeeBillApprovedEvent;
|
||||
import org.springblade.transport.support.KingdeeApBillSyncSupport;
|
||||
import org.springblade.transport.support.KingdeeArBillSyncSupport;
|
||||
import org.springblade.transport.mapper.FormalSettlementDetailFeeMapper;
|
||||
import org.springblade.transport.mapper.FormalSettlementDetailMapper;
|
||||
import org.springblade.transport.mapper.FormalSettlementChangeRecordMapper;
|
||||
@@ -33,7 +39,9 @@ import org.springblade.transport.pojo.entity.PaymentApplicationSettlement;
|
||||
import org.springblade.transport.pojo.entity.SettlementAdjustment;
|
||||
import org.springblade.transport.pojo.entity.SettlementAdjustmentDetail;
|
||||
import org.springblade.transport.pojo.vo.SettlementAdjustmentVO;
|
||||
import org.springblade.transport.service.IFormalSettlementService;
|
||||
import org.springblade.transport.service.ISettlementAdjustmentService;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -51,6 +59,7 @@ import java.util.Set;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class SettlementAdjustmentServiceImpl extends BaseServiceImpl<SettlementAdjustmentMapper, SettlementAdjustment>
|
||||
implements ISettlementAdjustmentService {
|
||||
private static final String PAID = "paid";
|
||||
@@ -63,6 +72,10 @@ public class SettlementAdjustmentServiceImpl extends BaseServiceImpl<SettlementA
|
||||
private final FormalSettlementPaymentMapper formalPaymentMapper;
|
||||
private final PaymentApplicationMapper paymentApplicationMapper;
|
||||
private final PaymentApplicationSettlementMapper paymentApplicationSettlementMapper;
|
||||
private final IFormalSettlementService formalSettlementService;
|
||||
private final KingdeeApBillSyncSupport kingdeeApBillSyncSupport;
|
||||
private final KingdeeArBillSyncSupport kingdeeArBillSyncSupport;
|
||||
private final ApplicationEventPublisher eventPublisher;
|
||||
|
||||
@Override
|
||||
public IPage<SettlementAdjustmentVO> selectPage(IPage<SettlementAdjustment> page, SettlementAdjustmentVO query) {
|
||||
@@ -204,24 +217,140 @@ public class SettlementAdjustmentServiceImpl extends BaseServiceImpl<SettlementA
|
||||
}
|
||||
@Override public void returnBill(SettlementAdjustmentStatusRequest request) { changeStatus(request.getId(), TransportBusiConstant.REVIEWING, TransportBusiConstant.RETURNED, "已驳回", limit(request.getReason(), 200)); }
|
||||
|
||||
/**
|
||||
* 重新推送(高危):原单已推送金蝶且旧单已在金蝶冲销后,克隆新正式结算单并应用调整,
|
||||
* 以新单号组成新防重键生成全新应付/应收单,调整单改挂新单、原单标记已调整并解锁旧锁。
|
||||
* <p>
|
||||
* 非事务编排:克隆+应用(独立事务)→ 推送(外部远程)→ 收尾回填,推送失败不回滚克隆,
|
||||
* 重试时按来源原单号幂等复用已克隆新单,从推送步骤续上。
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public String repush(Long adjustmentId) {
|
||||
SettlementAdjustment adjustment = existing(adjustmentId);
|
||||
if (!TransportBusiConstant.APPROVED.equals(adjustment.getApprovalStatus())) throw new ServiceException("仅审批通过的结算调整单允许重新推送");
|
||||
FormalSettlement formal = formalMapper.selectById(adjustment.getFormalSettlementId());
|
||||
if (formal == null || !"synced".equals(formal.getKingdeeSyncStatus())) throw new ServiceException("关联正式结算单尚未推送金蝶,无需重新推送");
|
||||
String kingdeeNo = "K3AP" + DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());
|
||||
formal.setKingdeeBillNo(kingdeeNo); formal.setSyncedTime(LocalDateTime.now()); formalMapper.updateById(formal);
|
||||
return kingdeeNo;
|
||||
if (!TransportBusiConstant.APPROVED.equals(adjustment.getApprovalStatus())) {
|
||||
throw new ServiceException("仅审批通过的结算调整单允许重新推送");
|
||||
}
|
||||
FormalSettlement original = formalMapper.selectById(adjustment.getFormalSettlementId());
|
||||
if (original == null) {
|
||||
throw new ServiceException("关联正式结算单不存在");
|
||||
}
|
||||
if (!KingdeeBfiConstant.KINGDEE_STATUS_SYNCED.equals(original.getKingdeeSyncStatus())) {
|
||||
throw new ServiceException("关联正式结算单尚未推送金蝶,请先执行「推送金蝶」");
|
||||
}
|
||||
// 冲销硬闸门:仅当金蝶侧原应付/应收单已被冲销(部分冲销放行)才允许以新单号重推,避免重复生成财务单据
|
||||
if (!this.kingdeeWrittenOff(original)) {
|
||||
throw new ServiceException("原应付/应收单尚未在金蝶冲销,禁止重推");
|
||||
}
|
||||
// 幂等:同一原单已克隆过新单则复用(重试从推送步骤续上),避免重复建单
|
||||
FormalSettlement clone = existingClone(original.getFormalSettlementNo());
|
||||
if (clone == null) {
|
||||
Long cloneId = self().cloneAndApplyForRepush(original.getId(), adjustment.getId());
|
||||
clone = formalMapper.selectById(cloneId);
|
||||
}
|
||||
// 推送新单:新单号天然组成新防重键,内部完成 A102-2/A302-2 推送 + 落锁 + 附件上传
|
||||
// shortcut: 成功后若再次点击重推,调整单已改挂新单且新单未冲销,会被冲销闸门拦截(无副作用);如需彻底隐藏由前端按「关联单是否克隆单」判断
|
||||
String billNo = formalSettlementService.syncKingdee(clone.getId());
|
||||
// 成功收尾:调整单改挂新单 + 回填金蝶单号/同步状态;原单标记已调整 + 旧锁解锁(业务数据不动)
|
||||
SettlementAdjustment patch = new SettlementAdjustment();
|
||||
patch.setId(adjustment.getId());
|
||||
patch.setFormalSettlementId(clone.getId());
|
||||
patch.setFormalSettlementNo(clone.getFormalSettlementNo());
|
||||
patch.setKingdeeSyncStatus(KingdeeBfiConstant.KINGDEE_STATUS_SYNCED);
|
||||
patch.setKingdeeBillNo(billNo);
|
||||
updateById(patch);
|
||||
formalSettlementService.markSettlementAdjusted(original.getId(), adjustment.getAdjustmentNo(), clone.getFormalSettlementNo());
|
||||
return billNo;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void approve(SettlementAdjustmentStatusRequest request) {
|
||||
public Long cloneAndApplyForRepush(Long originalSettlementId, Long adjustmentId) {
|
||||
IFormalSettlementService.CloneResult cloneResult = formalSettlementService.cloneFormalSettlement(originalSettlementId);
|
||||
FormalSettlement clone = formalMapper.selectById(cloneResult.settlementId());
|
||||
applyAdjustmentToSettlement(clone, existing(adjustmentId), cloneResult.detailIdMap(), cloneResult.feeIdMap());
|
||||
return cloneResult.settlementId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String syncKingdee(Long adjustmentId) {
|
||||
SettlementAdjustment adjustment = existing(adjustmentId);
|
||||
if (!TransportBusiConstant.APPROVED.equals(adjustment.getApprovalStatus())) {
|
||||
throw new ServiceException("仅审批通过的结算调整单允许推送金蝶");
|
||||
}
|
||||
// 未推送/生成失败场景:推送关联正式结算单,成功后由正式结算单回填调整单金蝶单号与同步状态
|
||||
return formalSettlementService.syncKingdee(adjustment.getFormalSettlementId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> kingdeeWriteOffPrecheck(Long formalSettlementId) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
FormalSettlement settlement = formalMapper.selectById(formalSettlementId);
|
||||
if (settlement == null) {
|
||||
throw new ServiceException("关联正式结算单不存在");
|
||||
}
|
||||
if (!KingdeeBfiConstant.KINGDEE_STATUS_SYNCED.equals(settlement.getKingdeeSyncStatus())) {
|
||||
result.put("syncStatus", KingdeeBfiConstant.KINGDEE_STATUS_UNSYNCED);
|
||||
result.put("writtenOff", null);
|
||||
result.put("message", "该结算单尚未推送金蝶,审批通过后将自动推送原单");
|
||||
return result;
|
||||
}
|
||||
result.put("syncStatus", KingdeeBfiConstant.KINGDEE_STATUS_SYNCED);
|
||||
try {
|
||||
boolean writtenOff = this.kingdeeWrittenOff(settlement);
|
||||
result.put("writtenOff", writtenOff);
|
||||
result.put("message", writtenOff
|
||||
? "该结算单已推送金蝶且旧单已冲销,审批后可直接重新推送新单"
|
||||
: "该结算单已推送金蝶且旧单尚未冲销,审批通过后需先由财务在金蝶完成冲销,才能重新推送");
|
||||
} catch (Exception exception) {
|
||||
// 预检为软提示:金蝶查询异常降级为「未校验」,不阻断建单,由审批分流与重推闸门兜底
|
||||
log.warn("结算调整单建单预检:金蝶冲销状态查询失败,降级未校验,正式结算单[{}]",
|
||||
settlement.getFormalSettlementNo(), exception);
|
||||
result.put("writtenOff", null);
|
||||
result.put("message", "金蝶冲销状态查询失败,未校验;审批后请以实际冲销情况为准");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public String approve(SettlementAdjustmentStatusRequest request) {
|
||||
SettlementAdjustment adjustment = existing(request.getId());
|
||||
if (!TransportBusiConstant.REVIEWING.equals(adjustment.getApprovalStatus())) throw new ServiceException("仅审批中的结算调整单允许审核");
|
||||
FormalSettlement formal = adjustableFormalSettlement(adjustment.getFormalSettlementId());
|
||||
boolean synced = KingdeeBfiConstant.KINGDEE_STATUS_SYNCED.equals(formal.getKingdeeSyncStatus());
|
||||
if (synced) {
|
||||
// 已推送场景:原单业务数据零改动,仅追加 1 条重推提示变更记录,待财务在金蝶手工冲销旧单后重推
|
||||
saveFormalChange(formal.getId(), "合计费用项", null, "调整",
|
||||
"结算调整单" + adjustment.getAdjustmentNo() + "审批通过,调整金额【" + money(adjustment.getAdjustmentAmount()) + "】,待重推金蝶",
|
||||
adjustment.getRemark());
|
||||
} else {
|
||||
// 未推送场景:回写原单费用/金额并重算结算金额,事务提交后由事件监听自动推送金蝶
|
||||
applyAdjustmentToSettlement(formal, adjustment, Map.of(), Map.of());
|
||||
saveFormalChange(formal.getId(), "合计费用项", null, "调整",
|
||||
"调整单" + adjustment.getAdjustmentNo() + "调整金额【" + money(adjustment.getAdjustmentAmount()) + "】",
|
||||
adjustment.getRemark());
|
||||
}
|
||||
adjustment.setKingdeeSyncStatus(formal.getKingdeeSyncStatus()); adjustment.setApprovalStatus(TransportBusiConstant.APPROVED); adjustment.setCurrentNode("审批通过"); adjustment.setCurrentProcessor(AuthUtil.getUserName()); adjustment.setApprovedTime(LocalDateTime.now()); updateById(adjustment);
|
||||
if (!synced) {
|
||||
// 审批事务提交后(AFTER_COMMIT)自动推原单,成功回填调整单 synced + 金蝶单号、失败置 failed
|
||||
eventPublisher.publishEvent(new KingdeeBillApprovedEvent(
|
||||
KingdeeBillApprovedEvent.BIZ_FORMAL_SETTLEMENT, formal.getId()));
|
||||
return null;
|
||||
}
|
||||
return "原结算单已推送金蝶,请财务人员在金蝶手工完成旧应付/应收单冲销处理后再重新推送";
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用调整到目标正式结算单(未推送场景作用于原单,重推场景作用于克隆新单):
|
||||
* 回写明细费项金额、汇总费用项、重算明细与结算金额;明细/费项 id 经映射转换(原单调整作用于原单时传空映射)。
|
||||
*
|
||||
* @param formal 目标正式结算单(改动后需落库)
|
||||
* @param adjustment 结算调整单
|
||||
* @param detailIdMap 原结算明细id -> 目标结算明细id(原单场景传空 Map)
|
||||
* @param feeIdMap 原明细费项id -> 目标明细费项id(原单场景传空 Map)
|
||||
*/
|
||||
private void applyAdjustmentToSettlement(FormalSettlement formal, SettlementAdjustment adjustment,
|
||||
Map<Long, Long> detailIdMap, Map<Long, Long> feeIdMap) {
|
||||
for (SettlementAdjustmentDetail item : detailMapper.selectList(Wrappers.<SettlementAdjustmentDetail>lambdaQuery().eq(SettlementAdjustmentDetail::getAdjustmentId, adjustment.getId()))) {
|
||||
if (money(item.getAdjustmentAmountTax()).signum() == 0) continue;
|
||||
if (isManualFee(item)) {
|
||||
@@ -229,12 +358,14 @@ public class SettlementAdjustmentServiceImpl extends BaseServiceImpl<SettlementA
|
||||
"新增【" + item.getFeeItem() + "】调整费用【" + money(item.getAdjustmentAmountTax()) + "】",
|
||||
Func.isEmpty(item.getRemark()) ? adjustment.getRemark() : item.getRemark());
|
||||
} else {
|
||||
FormalSettlementDetailFee fee = validateFee(formal.getId(), item.getFormalSettlementDetailId(), item.getFormalSettlementDetailFeeId());
|
||||
Long detailId = detailIdMap.getOrDefault(item.getFormalSettlementDetailId(), item.getFormalSettlementDetailId());
|
||||
Long feeId = feeIdMap.getOrDefault(item.getFormalSettlementDetailFeeId(), item.getFormalSettlementDetailFeeId());
|
||||
FormalSettlementDetailFee fee = validateFee(formal.getId(), detailId, feeId);
|
||||
BigDecimal beforeAmount = money(fee.getSettlementAmountTax());
|
||||
fee.setSettlementAmountTax(beforeAmount.add(money(item.getAdjustmentAmountTax())));
|
||||
if (item.getAdjustmentAmountNoTax() != null) fee.setSettlementAmountNoTax(money(fee.getSettlementAmountNoTax()).add(item.getAdjustmentAmountNoTax()));
|
||||
fee.setAdjustAmount(money(fee.getAdjustAmount()).add(item.getAdjustmentAmountTax())); formalFeeMapper.updateById(fee);
|
||||
FormalSettlementDetail formalDetail = formalDetailMapper.selectById(item.getFormalSettlementDetailId());
|
||||
FormalSettlementDetail formalDetail = formalDetailMapper.selectById(detailId);
|
||||
saveFormalChange(formal.getId(), "结算明细项", formalDetail == null ? null : formalDetail.getLineNo(),
|
||||
"调整", "【" + (Func.isEmpty(item.getFeeItem()) ? "结算费用" : item.getFeeItem())
|
||||
+ "】从【" + beforeAmount + "】调整为【" + fee.getSettlementAmountTax() + "】",
|
||||
@@ -251,13 +382,36 @@ public class SettlementAdjustmentServiceImpl extends BaseServiceImpl<SettlementA
|
||||
BigDecimal amount = money(formal.getSettlementAmount()).add(money(adjustment.getAdjustmentAmount()));
|
||||
formal.setSettlementAmount(amount);
|
||||
formal.setLocalSettlementAmount(amount.multiply(formal.getExchangeRate() == null ? BigDecimal.ONE : formal.getExchangeRate()));
|
||||
formal.setRemainingPayableAmount(amount.subtract(money(formal.getPaidAmount()))
|
||||
.max(BigDecimal.ZERO));
|
||||
formal.setRemainingPayableAmount(amount.subtract(money(formal.getPaidAmount())).max(BigDecimal.ZERO));
|
||||
formalMapper.updateById(formal);
|
||||
saveFormalChange(formal.getId(), "合计费用项", null, "调整",
|
||||
"调整单" + adjustment.getAdjustmentNo() + "调整金额【" + money(adjustment.getAdjustmentAmount()) + "】",
|
||||
adjustment.getRemark());
|
||||
adjustment.setKingdeeSyncStatus(formal.getKingdeeSyncStatus()); adjustment.setApprovalStatus(TransportBusiConstant.APPROVED); adjustment.setCurrentNode("审批通过"); adjustment.setCurrentProcessor(AuthUtil.getUserName()); adjustment.setApprovedTime(LocalDateTime.now()); updateById(adjustment);
|
||||
}
|
||||
|
||||
/** 涉事事务的自代理:跨方法调用确保 {@link #cloneAndApplyForRepush} 的事务注解生效 */
|
||||
private ISettlementAdjustmentService self() {
|
||||
return SpringUtil.getBean(ISettlementAdjustmentService.class);
|
||||
}
|
||||
|
||||
/** 按来源原正式结算单号查已克隆新单(重推幂等:同一原单不重复建单) */
|
||||
private FormalSettlement existingClone(String originFormalSettlementNo) {
|
||||
List<FormalSettlement> clones = formalMapper.selectList(Wrappers.<FormalSettlement>lambdaQuery()
|
||||
.eq(FormalSettlement::getOriginFormalSettlementNo, originFormalSettlementNo)
|
||||
.orderByDesc(FormalSettlement::getCreateTime));
|
||||
return clones.isEmpty() ? null : clones.get(0);
|
||||
}
|
||||
|
||||
/** 按原单旧防重键(原结算单号_明细单据号)查金蝶是否已冲销(应付 A102-4 / 应收 A302-4,部分冲销放行) */
|
||||
private boolean kingdeeWrittenOff(FormalSettlement settlement) {
|
||||
List<FormalSettlementDetail> details = formalDetailMapper.selectList(Wrappers.<FormalSettlementDetail>lambdaQuery()
|
||||
.eq(FormalSettlementDetail::getFormalSettlementId, settlement.getId())
|
||||
.eq(FormalSettlementDetail::getIsDeleted, 0)
|
||||
.orderByAsc(FormalSettlementDetail::getLineNo));
|
||||
if (Func.isEmpty(details)) {
|
||||
return false;
|
||||
}
|
||||
if ("receivable".equals(settlement.getSettlementType())) {
|
||||
return kingdeeArBillSyncSupport.queryArBillWrittenOff(kingdeeArBillSyncSupport.arBillSrcCode(settlement, details));
|
||||
}
|
||||
return kingdeeApBillSyncSupport.queryApBillWrittenOff(kingdeeApBillSyncSupport.apBillSrcCode(settlement, details));
|
||||
}
|
||||
|
||||
private void saveFormalChange(Long settlementId, String changeType, Integer lineNo,
|
||||
|
||||
Reference in New Issue
Block a user