业务背景:企业的采购订单,已入库,确认应付,未付款给对方,财务认为生成财务应付后需要控制申请付款的金额,但是系统的金额控制在付款单。
二开解决方案:在付款申请单保存按钮增加一个金额的校验。校验逻辑:申请付款最大金额=采购预付-(财务应付+付款申请关联金额-已结算金额)
场景A:
采购订单预付100
处理前:
采购订单 → 入库80 → 暂估应付80 → 财务应付80
采购订单 → 付款申请A 100
财务应付80 → 付款申请B 80
处理后:
采购订单 → 入库80 → 暂估应付80 → 财务应付80
采购订单 → 付款申请20(Max)
控制逻辑:申请付款最大金额=采购预付-(财务应付+付款申请关联金额-已结算金额)
此时由于财务应付未继续下推付款申请和付款,已结算金额为0
即申请付款金额<=100-(80+0-0)=20
场景B:
采购订单预付100
处理前:
采购订单 → 入库80 → 暂估应付80 → 财务应付80
采购订单 → 付款申请A 10
采购订单 → 付款申请B 90(Max)
采购订单预付100
处理后:
采购订单 → 入库80 → 暂估应付80 → 财务应付80
采购订单 → 付款申请A 10
采购订单 → 付款申请B 10(Max)
控制逻辑:申请付款最大金额=采购预付-(财务应付+付款申请关联金额-已结算金额)
此时由于财务应付未继续下推付款申请和付款,已结算金额为0
即申请付款金额<=100-(80+10-0)=10
后续流程1:财务应付80 → 付款申请C 80 → 付款80(与财务应付核销80)
此时付款申请关联金额为80,已结算金额为80,申请付款最大金额为10不变
后续流程2:付款申请A 10 → 付款 10(与财务应付核销10)
此时付款申请关联金额为10,已结算金额为10,申请付款最大金额为100-(80+10-10)=20
场景C:
采购订单预付100
处理前:
采购订单 → 付款申请A 10
采购订单 → 入库80 → 暂估应付80 → 财务应付80
采购订单 → 付款申请B 90(Max)
处理后:
采购订单 → 付款申请A 10
采购订单 → 入库80 → 暂估应付80 → 财务应付80
采购订单 → 付款申请B 10(Max)
控制逻辑与场景B相同
二开参考代码实现:
using Kingdee.BOS.Core.Validation;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using Kingdee.BOS.Core;
using Kingdee.BOS.Orm.DataEntity;
using Kingdee.BOS.Core.Metadata.ConvertElement;
using Kingdee.K3.FIN.Core;
using Kingdee.BOS.App.Data;
using Kingdee.BOS;
namespace MyPlugin.ServicePlugIn
{
public class MyOperationPlugin : AbstractOperationServicePlugIn
{
/// <summary>
/// 添加校验器
/// </summary>
/// <param name="e"></param>
public override void OnAddValidators(AddValidatorsEventArgs e)
{
var saveValidatorForAPAndApply = new SaveValidatorForAPAndApply();
operValidator.AlwaysValidate = true;
operValidator.EntityKey = "FBillHead";
e.Validators.Add(saveValidatorForAPAndApply);
}
/// <summary>
/// 当前操作的校验器
/// </summary>
private class SaveValidatorForAPAndApply : AbstractValidator
{
public override void Validate(ExtendedDataEntity[] dataEntities, ValidateContext validateContext, BOS.Context ctx)
{
if (dataEntities == null)
{
return;
}
string strErrorMsg = string.Empty;
foreach (ExtendedDataEntity entityData in dataEntities)
{
DynamicObjectCollection entryList = entityData["FPAYAPPLYENTRY"] as DynamicObjectCollection;
if (entryList == null)
{
continue;
}
foreach (var entry in entryList)
{
//申请付款金额
decimal applyAmountFor = Convert.ToDecimal(entry["FAPPLYAMOUNTFOR"]);
string purBillNo = Convert.ToString(entry["FSRCBILLNO"]);
string entryId = Convert.ToString(entry["Id"]);
if (!Convert.ToString(entry["FSOURCETYPE"]).Equals("PUR_PurchaseOrder") || purBillNo == "")
{
continue;
}
decimal[] amount = new decimal[4];
if (applyAmountFor > getDecimal(ctx, purBillNo, entryId, out amount))
{
ValidationErrorInfo validationErrorInfo = new ValidationErrorInfo(
string.Empty,
Convert.ToString(entityData["id"]),
entityData.DataEntityIndex,
entityData.RowIndex,
Convert.ToString(entityData["id"]),
string.Format("第{0}行分录申请付款金额{1}>采购预付金额{2}-(财务应付金额{3}+(付款申请关联金额{4}-当前分录付款关联金额{5})-财务应付已结算金额{6})",
entry["seq"], applyAmountFor, amount[0], amount[1], amount[2], amount[4], amount[3]),
string.Empty);
validateContext.AddError(entityData, validationErrorInfo);
}
}
}
}
/// <summary>
///
/// </summary>
/// <param name="ctx"></param>
/// <param name="purBillNo"></param>
/// <param name="entryId"></param>
/// <param name="amount"></param>
/// <returns></returns>
public decimal getDecimal(Context ctx, string purBillNo, string entryId, out decimal[] amount)
{
string sql1 = string.Format(@"select sum(apEntry.FALLAMOUNTFOR) as AmountAPAll,sum(apEntry.FPAYMENTAMOUNT) as AmountPayMent from T_AP_PAYABLEENTRY apEntry
inner join T_AP_PAYABLE apMain on apEntry.fid = apMain.fid
where FORDERNUMBER = '{0}' and apMain.FSETACCOUNTTYPE = '3'", purBillNo);
string sql2 = string.Format(@"select payPlan.FAPPLYAMOUNT as AmountApply,payPlan.FYFAMOUNT as AmountAll from T_PUR_POORDERINSTALLMENT payPlan
inner join t_PUR_POOrder purMain on payPlan.FID = purMain.FID
where purMain.FBILLNO = '{0}'", purBillNo);
string sql3 = string.Format(@"select FAPPLYAMOUNTFOR from T_CN_PayApplyentry where fentryid={0} and FSRCBILLNO='{1}'", entryId, purBillNo);
var amountAP = DBUtils.ExecuteDynamicObject(ctx, sql1);
decimal amountAPAll = 0, amountPayMent = 0;
if (amountAP.Count > 0)
{
amountAPAll = Convert.ToDecimal(DBUtils.ExecuteDynamicObject(ctx, sql1).FirstOrDefault()["AmountAPAll"]);
amountPayMent = Convert.ToDecimal(DBUtils.ExecuteDynamicObject(ctx, sql1).FirstOrDefault()["AmountPayMent"]);
}
var amountPurPlan = DBUtils.ExecuteDynamicObject(ctx, sql2);
decimal amountApply = 0, amountAll = 0;
if (amountPurPlan.Count > 0)
{
amountApply = Convert.ToDecimal(amountPurPlan.FirstOrDefault()["AmountApply"]);
amountAll = Convert.ToDecimal(amountPurPlan.FirstOrDefault()["AmountAll"]);
}
//当前分录付款关联金额
var amountPayApply = DBUtils.ExecuteDynamicObject(ctx, sql3);
decimal amountThis = 0;
if (amountPayApply.Count > 0)
{
amountThis = Convert.ToDecimal(amountPayApply.FirstOrDefault()["FAPPLYAMOUNTFOR"]);
}
amount = new decimal[5];
amount[0] = amountAll;
amount[1] = amountAPAll;
amount[2] = amountApply;
amount[3] = amountPayMent;
amount[4] = amountThis;
return amountAll - (amountAPAll + (amountApply - amountThis) - amountPayMent);
}
}
}
附件↓
MyOperationPlugin.doc(6.10KB)
推荐阅读