1、票据管理:开票/收票登记、开票申请,票据类型根据单据发布应用决定票据类型过滤、默认票据类型BUG处理
2、开票登记触发下推计息单,下推反写开票登记、费用明细 3、计息单删除校验及删除上游两表关联记录
This commit is contained in:
parent
4af45886af
commit
b5c75191ee
|
|
@ -38,15 +38,10 @@ public class CdmBillTypeBillPlugin extends AbstractBillPlugIn implements Plugin,
|
||||||
String appId = showParameter.getAppId();
|
String appId = showParameter.getAppId();
|
||||||
//信用证、供应链金融 票据类型赋默认值
|
//信用证、供应链金融 票据类型赋默认值
|
||||||
String billTypeNum = "";
|
String billTypeNum = "";
|
||||||
switch (appId){
|
if (TYPE_XYZ.equals(appId)){
|
||||||
//信用证
|
billTypeNum = XZY_NUM;
|
||||||
case TYPE_XYZ:
|
} else if (TYPE_GYL.equals(appId)) {
|
||||||
billTypeNum = XZY_NUM;
|
billTypeNum = GYL_NUM;
|
||||||
break;
|
|
||||||
//供应链金融
|
|
||||||
case TYPE_GYL:
|
|
||||||
billTypeNum = GYL_NUM;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (StringUtils.isNotBlank(billTypeNum)){
|
if (StringUtils.isNotBlank(billTypeNum)){
|
||||||
DynamicObject billType = BusinessDataServiceHelper.loadSingle("cdm_billtype", "id",
|
DynamicObject billType = BusinessDataServiceHelper.loadSingle("cdm_billtype", "id",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,247 @@
|
||||||
|
package kdsz.zyf25.tmc.cfm.plugin.operate;
|
||||||
|
|
||||||
|
import kd.bos.dataentity.OperateOption;
|
||||||
|
import kd.bos.dataentity.entity.DynamicObject;
|
||||||
|
import kd.bos.dataentity.entity.DynamicObjectCollection;
|
||||||
|
import kd.bos.entity.EntityMetadataCache;
|
||||||
|
import kd.bos.entity.botp.runtime.TableDefine;
|
||||||
|
import kd.bos.entity.operate.result.IOperateInfo;
|
||||||
|
import kd.bos.entity.operate.result.OperationResult;
|
||||||
|
import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
|
||||||
|
import kd.bos.entity.plugin.PreparePropertysEventArgs;
|
||||||
|
import kd.bos.entity.plugin.args.BeforeOperationArgs;
|
||||||
|
import kd.bos.orm.query.QCP;
|
||||||
|
import kd.bos.orm.query.QFilter;
|
||||||
|
import kd.bos.servicehelper.BusinessDataServiceHelper;
|
||||||
|
import kd.bos.servicehelper.QueryServiceHelper;
|
||||||
|
import kd.bos.servicehelper.operation.OperationServiceHelper;
|
||||||
|
import kd.bos.servicehelper.operation.SaveServiceHelper;
|
||||||
|
import kd.sdk.plugin.Plugin;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.YearMonth;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 票据管理计息
|
||||||
|
*/
|
||||||
|
public class CdmInterestAccrualPlugin extends AbstractOperationServicePlugIn implements Plugin {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(CdmInterestAccrualPlugin.class);
|
||||||
|
private static HashSet<String> feeTypeNumSet = new HashSet<>();
|
||||||
|
private static final String FeeBill_KEY = "cfm_feebill";//费用明细标识
|
||||||
|
private static final String INTERESTACCRUAL_KEY = "kdsz_interestaccrual";//计息单标识
|
||||||
|
private static Long FeeBill_TableID = 0L;
|
||||||
|
static {
|
||||||
|
feeTypeNumSet.add("FY_011");
|
||||||
|
feeTypeNumSet.add("FY_012");
|
||||||
|
feeTypeNumSet.add("FY_013");
|
||||||
|
TableDefine tableDefine = EntityMetadataCache.loadTableDefine("cfm_feebill", "cfm_feebill");
|
||||||
|
FeeBill_TableID = tableDefine.getTableId();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onPreparePropertys(PreparePropertysEventArgs e) {
|
||||||
|
super.onPreparePropertys(e);
|
||||||
|
e.getFieldKeys().add("billno");
|
||||||
|
e.getFieldKeys().add("issuedate");
|
||||||
|
e.getFieldKeys().add("draftbillexpiredate");
|
||||||
|
e.getFieldKeys().add("kdsz_payentry.kdsz_interestbill");
|
||||||
|
e.getFieldKeys().add("kdsz_payentry.kdsz_interestbillno");
|
||||||
|
e.getFieldKeys().add("kdsz_payentry.kdsz_interestbillid");
|
||||||
|
e.getFieldKeys().add("kdsz_payentry.kdsz_interestbillstatus");
|
||||||
|
e.getFieldKeys().add("kdsz_payentry.kdsz_valuedate");
|
||||||
|
e.getFieldKeys().add("kdsz_payentry.kdsz_settledate");
|
||||||
|
e.getFieldKeys().add("kdsz_payentry.kdsz_paydate");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeExecuteOperationTransaction(BeforeOperationArgs e) {
|
||||||
|
super.beforeExecuteOperationTransaction(e);
|
||||||
|
DynamicObject[] bills = e.getDataEntities();
|
||||||
|
for (DynamicObject bill : bills) {
|
||||||
|
String billNo = bill.getString("billno");
|
||||||
|
Date issueDate = bill.getDate("issuedate");//出票日
|
||||||
|
Date draftbillexpireDate = bill.getDate("draftbillexpiredate");//票据到期日
|
||||||
|
//生成计息单除费用明细外的参数
|
||||||
|
HashMap<String, Object> dataMap = new HashMap<>();
|
||||||
|
dataMap.put("issueDate",issueDate);
|
||||||
|
dataMap.put("draftbillexpireDate",draftbillexpireDate);
|
||||||
|
|
||||||
|
QFilter filter = new QFilter("entry.srcbillno", QCP.equals, billNo);
|
||||||
|
filter.and("feetype.number",QCP.in, feeTypeNumSet).and("kdsz_pushjx",QCP.not_equals,"B");
|
||||||
|
//费用明细所需字段
|
||||||
|
String FeeBillSelectField = "id,billno,org,feetype,currency,amountrate,payamt,kdsz_pushjx";
|
||||||
|
DynamicObject[] feeBills = BusinessDataServiceHelper.load(FeeBill_KEY, FeeBillSelectField, new QFilter[]{filter});
|
||||||
|
if (feeBills == null || feeBills.length == 0){
|
||||||
|
logger.info("应付票据:" + billNo + "没有费用明细无需下推!");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
OperationResult result = genJXBill(dataMap,feeBills);
|
||||||
|
if (result.isSuccess()){
|
||||||
|
List<Object> successPkIds = result.getSuccessPkIds();
|
||||||
|
if (successPkIds.size() == feeBills.length){
|
||||||
|
logger.info("应付票据:" + billNo + "下推计息单成功!");
|
||||||
|
DynamicObjectCollection payEntries = bill.getDynamicObjectCollection("kdsz_payentry");
|
||||||
|
int size = payEntries.size();
|
||||||
|
//开票登记(应付票据)记录下推信息
|
||||||
|
for (Object successPkId : successPkIds) {
|
||||||
|
DynamicObject jxBill = BusinessDataServiceHelper.loadSingle(successPkId, INTERESTACCRUAL_KEY);
|
||||||
|
if (jxBill == null)continue;
|
||||||
|
DynamicObject payEntry = payEntries.addNew();
|
||||||
|
payEntry.set("seq", ++size);
|
||||||
|
payEntry.set("kdsz_interestbill",successPkId);
|
||||||
|
payEntry.set("kdsz_interestbillno",jxBill.getString("billno"));
|
||||||
|
payEntry.set("kdsz_interestbillid",successPkId);
|
||||||
|
// payEntry.set("",);
|
||||||
|
// payEntry.set("",);
|
||||||
|
// payEntry.set("",);
|
||||||
|
}
|
||||||
|
SaveServiceHelper.save(new DynamicObject[]{bill});
|
||||||
|
for (DynamicObject feeBill : feeBills) {
|
||||||
|
feeBill.set("kdsz_pushjx", "B");
|
||||||
|
}
|
||||||
|
SaveServiceHelper.update(feeBills);
|
||||||
|
}
|
||||||
|
// else {
|
||||||
|
// //部分生成则删除
|
||||||
|
// OperationResult deleteResult = deleteBills(successPkIds);
|
||||||
|
// if (!deleteResult.isSuccess()){
|
||||||
|
// logger.info("应付票据:" + billNo + "下推计息单部分成功的单据删除失败!");
|
||||||
|
// }else {
|
||||||
|
// logger.info("应付票据:" + billNo + "下推计息单部分成功的单据删除成功!");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}else {
|
||||||
|
List<IOperateInfo> errors = result.getAllErrorOrValidateInfo();
|
||||||
|
StringBuilder errorStr = new StringBuilder();
|
||||||
|
for (IOperateInfo error : errors) {
|
||||||
|
String message = error.getMessage();
|
||||||
|
errorStr.append(message).append("\n");
|
||||||
|
}
|
||||||
|
logger.error("应付票据:" + billNo + "下推计息单失败!\n" + errorStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private OperationResult genJXBill(HashMap<String,Object> dataMap,DynamicObject[] feeBills) {
|
||||||
|
DynamicObjectCollection JXBills = new DynamicObjectCollection();
|
||||||
|
Date issueDate = (Date)dataMap.get("issueDate");
|
||||||
|
Date draftbillexpireDate = (Date)dataMap.get("draftbillexpireDate");
|
||||||
|
for (DynamicObject feeBill : feeBills) {
|
||||||
|
DynamicObject JXBill = BusinessDataServiceHelper.newDynamicObject(INTERESTACCRUAL_KEY);
|
||||||
|
//参数组装
|
||||||
|
DynamicObject org = feeBill.getDynamicObject("org");//组织
|
||||||
|
DynamicObject feeType = feeBill.getDynamicObject("feetype");//费用类型
|
||||||
|
DynamicObject currency = feeBill.getDynamicObject("currency");//币种
|
||||||
|
BigDecimal amountRate = feeBill.getBigDecimal("amountrate");//费率
|
||||||
|
BigDecimal feeAmt = feeBill.getBigDecimal("payamt");//费用金额
|
||||||
|
// 将 Date 转换为 LocalDate(忽略时间部分)
|
||||||
|
LocalDate localIssueDate = issueDate.toInstant()
|
||||||
|
.atZone(ZoneId.systemDefault())
|
||||||
|
.toLocalDate();
|
||||||
|
|
||||||
|
LocalDate localExpireDate = draftbillexpireDate.toInstant()
|
||||||
|
.atZone(ZoneId.systemDefault())
|
||||||
|
.toLocalDate();
|
||||||
|
// 计算天数差
|
||||||
|
long term = Math.abs(ChronoUnit.DAYS.between(localIssueDate, localExpireDate));
|
||||||
|
BigDecimal payAmt = feeAmt.multiply(new BigDecimal(term)).multiply(amountRate)
|
||||||
|
.divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);//付息金额
|
||||||
|
|
||||||
|
JXBill.set("billstatus","A");
|
||||||
|
JXBill.set("org", org);//业务组织
|
||||||
|
JXBill.set("kdsz_valuedate", issueDate);//计息开始日
|
||||||
|
JXBill.set("kdsz_maturitydate", draftbillexpireDate);//计息结束日
|
||||||
|
JXBill.set("kdsz_feetype", feeType);//费用类型
|
||||||
|
JXBill.set("kdsz_currency", currency);//付息币别
|
||||||
|
JXBill.set("kdsz_feerate", amountRate);//费率
|
||||||
|
JXBill.set("kdsz_totalamount", payAmt);//付息金额
|
||||||
|
JXBill.set("kdsz_srcentity",FeeBill_KEY);//源单类型
|
||||||
|
JXBill.set("kdsz_srcbillno",feeBill.getString("billno"));//源单编号
|
||||||
|
JXBill.set("kdsz_srcbillid",feeBill.getPkValue());//源单id
|
||||||
|
//生成按月计息明细
|
||||||
|
DynamicObjectCollection entries = JXBill.getDynamicObjectCollection("entryentity");
|
||||||
|
ArrayList<HashMap<String, Date>> dateList = genJXEntry(issueDate, draftbillexpireDate);
|
||||||
|
int monthCount = dateList.size();
|
||||||
|
int seq = entries.size();
|
||||||
|
for (HashMap<String, Date> map : dateList) {
|
||||||
|
Date startDate = map.get("start");
|
||||||
|
Date endDate = map.get("end");
|
||||||
|
DynamicObject entry = entries.addNew();
|
||||||
|
entry.set("seq", ++seq);
|
||||||
|
entry.set("kdsz_e_valuedate",startDate);
|
||||||
|
entry.set("kdsz_e_maturitydate",endDate);
|
||||||
|
entry.set("kdsz_e_principal",payAmt.divide(new BigDecimal(monthCount),2, RoundingMode.HALF_UP));
|
||||||
|
entry.set("kdsz_e_feerate",amountRate);
|
||||||
|
}
|
||||||
|
//关联费用明细
|
||||||
|
DynamicObjectCollection billheadLk = JXBill.getDynamicObjectCollection("billhead_lk");
|
||||||
|
DynamicObject lk = billheadLk.addNew();
|
||||||
|
lk.set("billhead_lk_stableid",FeeBill_TableID);
|
||||||
|
lk.set("billhead_lk_sbillid",feeBill.getPkValue());
|
||||||
|
lk.set("billhead_lk_sid",feeBill.getPkValue());
|
||||||
|
JXBills.add(JXBill);
|
||||||
|
}
|
||||||
|
if (JXBills.size() > 0){
|
||||||
|
DynamicObject[] JXBillArray = JXBills.toArray(new DynamicObject[0]);
|
||||||
|
return OperationServiceHelper.executeOperate("save", INTERESTACCRUAL_KEY, JXBillArray, OperateOption.create());
|
||||||
|
}
|
||||||
|
OperationResult failResult = new OperationResult();
|
||||||
|
failResult.setSuccess(false);
|
||||||
|
return failResult;
|
||||||
|
}
|
||||||
|
private ArrayList<HashMap<String,Date>> genJXEntry(Date start, Date end) {
|
||||||
|
ArrayList<HashMap<String,Date>> dateList = new ArrayList<>();
|
||||||
|
LocalDate startDate = start.toInstant()
|
||||||
|
.atZone(ZoneId.systemDefault())
|
||||||
|
.toLocalDate();
|
||||||
|
LocalDate endDate = end.toInstant()
|
||||||
|
.atZone(ZoneId.systemDefault())
|
||||||
|
.toLocalDate();
|
||||||
|
if (startDate == null || endDate == null || startDate.isAfter(endDate)) {
|
||||||
|
return dateList;
|
||||||
|
}
|
||||||
|
LocalDate currentStart = startDate;
|
||||||
|
while (currentStart.isBefore(endDate) || currentStart.isEqual(endDate)) {
|
||||||
|
HashMap<String, Date> map = new HashMap<>();
|
||||||
|
// 获取当前月份的最后一天
|
||||||
|
YearMonth currentMonth = YearMonth.from(currentStart);
|
||||||
|
LocalDate monthEnd = currentMonth.atEndOfMonth();
|
||||||
|
// 如果月份结束日期大于结束日期,则使用结束日期
|
||||||
|
LocalDate rangeEnd = monthEnd.isBefore(endDate) ? monthEnd : endDate;
|
||||||
|
map.put("start", Date.from(currentStart.atStartOfDay()
|
||||||
|
.atZone(ZoneId.systemDefault())
|
||||||
|
.toInstant()));
|
||||||
|
map.put("end", Date.from(rangeEnd.atStartOfDay()
|
||||||
|
.atZone(ZoneId.systemDefault())
|
||||||
|
.toInstant()));
|
||||||
|
dateList.add(map);
|
||||||
|
// 下一段从下个月的第一天开始
|
||||||
|
currentStart = rangeEnd.plusDays(1);
|
||||||
|
// 如果已经到达结束日期,退出循环
|
||||||
|
if (rangeEnd.isEqual(endDate)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dateList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private OperationResult deleteBills(List<Object> ids) {
|
||||||
|
OperationResult result = new OperationResult();
|
||||||
|
if (ids == null || ids.size() == 0){
|
||||||
|
result.setSuccess(false);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
DynamicObject[] deleteBills = BusinessDataServiceHelper.load(INTERESTACCRUAL_KEY, "id",
|
||||||
|
new QFilter[]{new QFilter("id", QCP.in, ids)});
|
||||||
|
for (int i = 0; i < deleteBills.length; i++) {
|
||||||
|
deleteBills[i] = BusinessDataServiceHelper.loadSingle(deleteBills[i].getPkValue(), INTERESTACCRUAL_KEY);
|
||||||
|
}
|
||||||
|
return OperationServiceHelper.executeOperate("delete", INTERESTACCRUAL_KEY, deleteBills, OperateOption.create());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
package kdsz.zyf25.tmc.cfm.plugin.operate;
|
||||||
|
|
||||||
|
import kd.bos.dataentity.entity.DynamicObject;
|
||||||
|
import kd.bos.dataentity.entity.DynamicObjectCollection;
|
||||||
|
import kd.bos.entity.ExtendedDataEntity;
|
||||||
|
import kd.bos.entity.filter.QFilterDto;
|
||||||
|
import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
|
||||||
|
import kd.bos.entity.plugin.AddValidatorsEventArgs;
|
||||||
|
import kd.bos.entity.plugin.PreparePropertysEventArgs;
|
||||||
|
import kd.bos.entity.plugin.args.AfterOperationArgs;
|
||||||
|
import kd.bos.entity.validate.AbstractValidator;
|
||||||
|
import kd.bos.orm.query.QFilter;
|
||||||
|
import kd.bos.servicehelper.BusinessDataServiceHelper;
|
||||||
|
import kd.bos.servicehelper.operation.SaveServiceHelper;
|
||||||
|
import kd.sdk.plugin.Plugin;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计息单删除校验以及反写上游开票登记、费用明细下推状态
|
||||||
|
*/
|
||||||
|
public class InterestAccrualDeletePlugin extends AbstractOperationServicePlugIn implements Plugin {
|
||||||
|
@Override
|
||||||
|
public void onPreparePropertys(PreparePropertysEventArgs e) {
|
||||||
|
super.onPreparePropertys(e);
|
||||||
|
e.getFieldKeys().add("kdsz_srcentity");
|
||||||
|
e.getFieldKeys().add("kdsz_srcbillid");
|
||||||
|
e.getFieldKeys().add("id");
|
||||||
|
e.getFieldKeys().add("entryentity.kdsz_e_paybill");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAddValidators(AddValidatorsEventArgs e) {
|
||||||
|
e.addValidator(new AbstractValidator() {
|
||||||
|
@Override
|
||||||
|
public void validate() {
|
||||||
|
ExtendedDataEntity[] extBills = this.getDataEntities();
|
||||||
|
for (ExtendedDataEntity extBill : extBills) {
|
||||||
|
DynamicObject bill = extBill.getDataEntity();
|
||||||
|
DynamicObjectCollection entries = bill.getDynamicObjectCollection("entryentity");
|
||||||
|
for (DynamicObject entry : entries) {
|
||||||
|
DynamicObject payBill = entry.getDynamicObject("kdsz_e_paybill");
|
||||||
|
if (payBill != null) {
|
||||||
|
addErrorMessage(extBill, "计息单:"+extBill.getBillNo()+"已生成付款单,不允许删除");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterExecuteOperationTransaction(AfterOperationArgs e) {
|
||||||
|
super.afterExecuteOperationTransaction(e);
|
||||||
|
DynamicObject[] bills = e.getDataEntities();
|
||||||
|
for (DynamicObject bill : bills) {
|
||||||
|
String srcEntity = bill.getString("kdsz_srcentity");
|
||||||
|
Object srcBillId = bill.get("kdsz_srcbillid");
|
||||||
|
DynamicObject feeBill = BusinessDataServiceHelper.loadSingle(srcBillId, srcEntity);
|
||||||
|
if (feeBill != null) {
|
||||||
|
feeBill.set("kdsz_pushjx","A");
|
||||||
|
SaveServiceHelper.update(feeBill);
|
||||||
|
DynamicObjectCollection feeEntries = feeBill.getDynamicObjectCollection("entry");
|
||||||
|
HashSet<Long> srcBillIds = new HashSet<>();
|
||||||
|
for (DynamicObject feeEntry : feeEntries) {
|
||||||
|
long pjId = feeEntry.getLong("srcbillid");
|
||||||
|
srcBillIds.add(pjId);
|
||||||
|
}
|
||||||
|
QFilter filter = new QFilter("id", "in", srcBillIds);
|
||||||
|
// TODO: 2025/12/10 暂时定为开票登记
|
||||||
|
DynamicObject[] srcBills = BusinessDataServiceHelper.load("cdm_payablebill",
|
||||||
|
"id,kdsz_payentry.kdsz_interestbillid", new QFilter[]{filter});
|
||||||
|
for (DynamicObject srcBill : srcBills) {
|
||||||
|
DynamicObjectCollection srcPayEntries = srcBill.getDynamicObjectCollection("kdsz_payentry");
|
||||||
|
for (int i = srcPayEntries.size() - 1; i > 0 ; i--) {
|
||||||
|
DynamicObject srcPayEntry = srcPayEntries.get(i);
|
||||||
|
long srcJXBillId = srcPayEntry.getLong("kdsz_interestbillid");
|
||||||
|
long id = bill.getLong("id");
|
||||||
|
if (srcJXBillId == id){
|
||||||
|
srcPayEntries.remove( i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SaveServiceHelper.save(srcBills);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue