1.费用报销单发票金额精确调整插件

2.对公报销单发票金额精确调整插件
This commit is contained in:
zhangzhiguo 2025-09-08 09:41:22 +08:00
parent b92ccaffde
commit ffef2c8de3
3 changed files with 269 additions and 0 deletions

View File

@ -0,0 +1,57 @@
package zcgj.zcdev.zcdev.fs.plugin.operate;
import kd.bos.context.RequestContext;
import kd.bos.entity.plugin.AddValidatorsEventArgs;
import kd.bos.entity.validate.AbstractValidator;
import kd.bos.servicehelper.user.UserServiceHelper;
import kd.fi.er.common.field.writeoffmoney.DailyReimburseWriteOffFields;
import kd.fi.er.common.field.writeoffmoney.WithholdingWriteFields;
import kd.fi.er.opplugin.daily.web.ReimSubmitCheckAmountValidator;
import kd.fi.er.opplugin.daily.web.ReimSubmitCheckProxyTaxValidator;
import kd.fi.er.opplugin.daily.web.ReimburseBillSubmitOp;
import kd.fi.er.validator.*;
import org.apache.commons.lang3.StringUtils;
import zcgj.zcdev.zcdev.fs.plugin.validator.ReimSubmitCheckInvoiceValidatorExt;
import zcgj.zcdev.zcdev.fs.utils.OrgCheckUtils;
import java.util.List;
/**
* 费用报销单发票金额精确调整插件
* 对公报销单发票金额精确调整插件
*/
public class ReimburseBillSubmitOpExt extends ReimburseBillSubmitOp {
public void onAddValidators(AddValidatorsEventArgs e) {
Long currentUserId = UserServiceHelper.getCurrentUserId();
// 当前用户所属组织
Long mainOrgId = UserServiceHelper.getUserMainOrgId(currentUserId);
//当前切换选择的组织
Long currentOrgId = RequestContext.get().getOrgId();
//当前所在的组织是属于矿山下的
if(OrgCheckUtils.isKS(currentOrgId)){
e.addValidator(new ReimburseBillSubmitValidator());
if (StringUtils.equalsIgnoreCase((String)this.operateMeta.get("key"), "submit")) {
e.addValidator(new ReimSubmitCheckInvoiceValidatorExt());
e.addValidator(new ReimSubmitCheckProxyTaxValidator());
e.addValidator(new ReimBillOverApplySubmitValidator());
e.addValidator(new LoanClearAmountSubmitValidator(DailyReimburseWriteOffFields.getInstance()));
e.addValidator(new LoanAndAccountCurrencyUniqueValidator());
e.addValidator(new ReimSubmitCheckAmountValidator());
List<AbstractValidator> validators = e.getValidators();
if (validators.stream().noneMatch((validator) -> validator.getClass() == ErBillCheckExpItemCanUseValidator.class)) {
e.addValidator(new ErBillCheckExpItemCanUseValidator());
}
}
if (StringUtils.equalsIgnoreCase((String)this.operateMeta.get("key"), "saveapprove")) {
e.addValidator(new LoanClearAmountSubmitValidator(WithholdingWriteFields.getInstance()));
}
}else{
super.onAddValidators(e);
}
}
}

View File

@ -0,0 +1,75 @@
package zcgj.zcdev.zcdev.fs.plugin.validator;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.resource.ResManager;
import kd.bos.entity.datamodel.IDataModel;
import kd.bos.logging.Log;
import kd.bos.logging.LogFactory;
import kd.bos.orm.query.QFilter;
import kd.bos.servicehelper.BusinessDataServiceHelper;
import kd.fi.er.business.utils.InvoiceUtils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class InvoiceUtilsExt extends InvoiceUtils {
private static final Log log = LogFactory.getLog(InvoiceUtilsExt.class);
// 定义容差范围
private static final BigDecimal TOLERANCE = new BigDecimal("0.05");
public static <T> List<String> checkAmount(T bill, BillEntityType type) {
if (bill instanceof IDataModel) {
return checkKeyAmountDiff((IDataModel)bill, type, type.getAmountKey(), ResManager.loadKDString("报销金额", "InvoiceUtils_2", "fi-er-business", new Object[0]));
} else {
return (List<String>)(bill instanceof DynamicObject ? checkKeyAmountDiff((DynamicObject)bill, type, type.getAmountKey(), ResManager.loadKDString("报销金额", "InvoiceUtils_2", "fi-er-business", new Object[0])) : new ArrayList());
}
}
public static List<String> checkKeyAmountDiff(DynamicObject bill, BillEntityType type, String key, String keyName) {
List<String> resultList = Lists.newArrayList();
Map<String, BigDecimal> itemMap = itemOfInvoice((DynamicObject)bill, type, Sets.newHashSet(new String[]{key}));
Map<String, BigDecimal> invoiceMap = invoiceInfo((DynamicObject)bill, type, Sets.newHashSet(new String[]{"totalamount"}));
BigDecimal itemAmout = (BigDecimal)itemMap.get(key);
BigDecimal invoiceAmout = (BigDecimal)invoiceMap.get("totalamount");
log.info("单据编号:" + bill.getString("billno") + " 费用" + key + "总和: " + itemAmout + " 发票报销金额总和:" + invoiceAmout);
BigDecimal differAmount = itemAmout.subtract(invoiceAmout).abs();
QFilter queryFilter = new QFilter("id", "=", 1);
String selectPropties = "id,sign,amtprecision";
DynamicObject currency = BusinessDataServiceHelper.loadSingleFromCache("bd_currency", selectPropties, new QFilter[]{queryFilter});
String sign = currency.getString("sign");
int amtprecision = currency.getInt("amtprecision");
StringBuilder sb = (new StringBuilder(keyName)).append(ResManager.loadKDString("超出发票金额%s", "InvoiceUtils_1", "fi-er-business", new Object[0]));
if (differAmount.compareTo(TOLERANCE) > 0) {
resultList.add(String.format(sb.toString(), sign + differAmount.setScale(amtprecision, RoundingMode.HALF_EVEN)));
}
return resultList;
}
public static List<String> checkKeyAmountDiff(IDataModel model, BillEntityType type, String key, String keyName) {
List<String> resultList = Lists.newArrayList();
Map<String, BigDecimal> itemMap = itemOfInvoice((IDataModel)model, type, Sets.newHashSet(new String[]{key}));
Map<String, BigDecimal> invoiceMap = invoiceInfo((IDataModel)model, type, Sets.newHashSet(new String[]{"totalamount"}));
BigDecimal itemAmout = (BigDecimal)itemMap.get(key);
BigDecimal invoiceAmout = (BigDecimal)invoiceMap.get("totalamount");
log.info("单据编号:" + model.getValue("billno") + " 费用" + key + "总和: " + itemAmout + " 发票报销金额总和:" + invoiceAmout);
BigDecimal differAmount = itemAmout.subtract(invoiceAmout).abs();
QFilter queryFilter = new QFilter("id", "=", 1);
String selectPropties = "id,sign,amtprecision";
DynamicObject currency = BusinessDataServiceHelper.loadSingleFromCache("bd_currency", selectPropties, new QFilter[]{queryFilter});
String sign = currency.getString("sign");
int amtprecision = currency.getInt("amtprecision");
StringBuilder sb = (new StringBuilder(keyName)).append(ResManager.loadKDString("超出发票金额%s", "InvoiceUtils_1", "fi-er-business", new Object[0]));
if (differAmount.compareTo(TOLERANCE) > 0) {
resultList.add(String.format(sb.toString(), sign + differAmount.setScale(amtprecision, RoundingMode.HALF_EVEN)));
}
return resultList;
}
}

View File

@ -0,0 +1,137 @@
package zcgj.zcdev.zcdev.fs.plugin.validator;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.dataentity.resource.ResManager;
import kd.bos.entity.ExtendedDataEntity;
import kd.bos.entity.validate.AbstractValidator;
import kd.bos.logging.Log;
import kd.bos.logging.LogFactory;
import kd.fi.er.business.image.ImageServiceHelper;
import kd.fi.er.business.utils.*;
import org.apache.commons.lang3.StringUtils;
import zcgj.zcdev.zcdev.fs.utils.OrgCheckUtils;
import java.math.BigDecimal;
import java.util.Objects;
public class ReimSubmitCheckInvoiceValidatorExt extends AbstractValidator {
private static final Log log = LogFactory.getLog(ReimSubmitCheckInvoiceValidatorExt.class);
public void validate() {
ExtendedDataEntity[] dataEntities = this.getDataEntities();
for(ExtendedDataEntity dataEntity : dataEntities) {
DynamicObject bill = dataEntity.getDataEntity();
DynamicObject company = bill.getDynamicObject("company");
DynamicObject costcompany = bill.getDynamicObject("costcompany");
if (company == null || costcompany == null) {
return;
}
Long companyId = (Long)company.getPkValue();
this.chechInvoiceImageTemp(bill, dataEntity);
this.checkNoInvoice(bill, dataEntity);
if (ErStdConfig.getInvoiceMustWithExpense()) {
for(String result : InvoiceUtils.checkUnbindInvoice(bill, dataEntity)) {
this.addErrorMessage(dataEntity, result);
}
}
DynamicObjectCollection invoiceItemEntryDOs = bill.getDynamicObjectCollection("invoiceitementry");
if (!invoiceItemEntryDOs.isEmpty()) {
Boolean mustCheck = SystemParamterUtil.isAmountOverInvoice(companyId);
if (!mustCheck) {
//如果是矿山下面的组织
long costcompanyId = costcompany.getLong("id");
if(OrgCheckUtils.isKS(costcompanyId)){
for(String result : InvoiceUtilsExt.checkAmount(bill, InvoiceUtils.BillEntityType.DailyReimburse)) {
this.addErrorMessage(dataEntity, result);
}
}else{
for(String result : InvoiceUtils.checkAmount(bill, InvoiceUtils.BillEntityType.DailyReimburse)) {
this.addErrorMessage(dataEntity, result);
}
}
}
DynamicObject invoicOrgDO = bill.getDynamicObject("costcompany");
for(String result : InvoiceUtils.checkBuyerNameAndTaxNo(bill, ErCommonUtils.getPk(invoicOrgDO), false)) {
this.addErrorMessage(dataEntity, result);
}
}
}
}
private void checkNoInvoice(DynamicObject bill, ExtendedDataEntity dataEntity) {
DynamicObject company = bill.getDynamicObject("company");
if (company != null) {
Long companyId = (Long)company.getPkValue();
Boolean invoiceIsMust = ReimburseControlUtils.invoiceIsMust(companyId);
if (invoiceIsMust) {
boolean supplementinvoice = bill.getBoolean("needsuppleinvoice");
if (!supplementinvoice) {
Boolean billHeadNoInvocie = bill.getBoolean("noinvoice");
if (!billHeadNoInvocie) {
Long invoiceCurrency = SystemParamterUtil.getInvoiceEntryCurrency(companyId);
DynamicObjectCollection expenseEntrys = bill.getDynamicObjectCollection("expenseentryentity");
int length = expenseEntrys.size();
for(int entryIndex = 0; entryIndex < length; ++entryIndex) {
DynamicObject expenseEntry = (DynamicObject)expenseEntrys.get(entryIndex);
BigDecimal expeAmount = expenseEntry.getBigDecimal("expenseamount");
if (expeAmount.compareTo(BigDecimal.ZERO) != 0) {
DynamicObject expense = expenseEntry.getDynamicObject("expenseitem");
if (expense != null && Objects.equals(invoiceCurrency, ErCommonUtils.getPk(expenseEntry.getDynamicObject("entrycurrency")))) {
boolean bool = expense.getDynamicObjectType().getProperty("noinvoice") != null;
if (bool) {
Boolean noinvoice = expense.getBoolean("noinvoice");
if (noinvoice) {
continue;
}
}
String invoiceno_entry = expenseEntry.getString("invoiceno_entry");
if (StringUtils.isBlank(invoiceno_entry)) {
String fmt = ResManager.loadKDString("第%s行费用明细分录需要导入发票或关联发票。", "ReimSubmitCheckInvoiceValidator_1", "fi-er-opplugin", new Object[0]);
this.addErrorMessage(dataEntity, String.format(fmt, entryIndex + 1));
}
}
}
}
}
}
}
}
}
private void chechInvoiceImageTemp(DynamicObject bill, ExtendedDataEntity dataEntity) {
DynamicObjectCollection invoiceEntrys = bill.getDynamicObjectCollection("invoiceentry");
if (invoiceEntrys.size() <= 0) {
log.info("发票分录没有发票,不进行校验");
} else {
DynamicObject company = bill.getDynamicObject("company");
String mainEntityId = bill.getDataEntityType().getName();
Long companyId = 0L;
if (company == null) {
log.info("申请人公司为空,不进行校验");
} else {
companyId = (Long)company.getPkValue();
boolean isImageTemp = SystemParamterUtil.isMapInvoiceCloudImage(companyId);
if (isImageTemp) {
String configedPrintTemplateFormId = ImageServiceHelper.getConfigedPrintTplFormNumber(bill, mainEntityId, companyId);
if (StringUtils.isBlank(configedPrintTemplateFormId)) {
this.addErrorMessage(dataEntity, ResManager.loadKDString("未设置单据影像模板,请联系管理员设置!", "ReimSubmitCheckInvoiceValidator_2", "fi-er-opplugin", new Object[0]));
}
} else {
log.info("没有集成发票云影像,不进行校验");
}
}
}
}
}