采购价格管控
思路
(项目🔶-任务🟥-工作🔺)
-
🔶通过下推财务应付控制采购价格。发票价格等于采购价格。如果不同需要修改采购订单
-
🟥采购订单创建时 管理价格
- 使用价目表
- 没有价目表 单价可修改
-
🟥应付单时管理价格 (单据页)
-
保存后可获取采购订单价格
- 🔺制作 单据页获取价格按钮
- 🔺 捕获事件 执行修改数据并刷新
- 🔺制作 单据页获取价格按钮
-
🔺价格和应付价格不相等可以保存,但是不能提交
- 🔺通过插件拦截提交,除非价格和应付一样
-
-
🟥应付单时管理价格 (单据页)
- 批量获取
-
建议用插件实现,不用实体规则
目标通过 对指定物料开启 价格管控来
- 确保发票价格=采购价格
首先选出2个物料代码,一个启用价格管控(3.02.01.0008),一个没有启用价格管控(3.99.01.0035)
有管控物料编码
3.02.01.0008
- 带管控
- 有价目表
无管控物料编码
3.99.01.0035
- 不管控
- 无价目表
价目表
被管控物料 必须有价目表
采购下单
可手动修改
自动获取价目表 (无法修改)
价格变更
参数【已关闭订单可以变更】未勾选,订单已关闭不能变更。
【 供应链 】->【 采购管理】->【采购管理系统参数】
临时改价
通过新变更单
- 新变更单要求能改价格
永久改价
通过价目表
应付对价
bos设置
插件模式
通过列表插件 / 表单插件来完成。
菜单点击事件
通过插件来处理数据建立以一个无操作按钮
通过表单点击菜单 判断点击按钮表示 如: “XJPT_tbButton_2” 来执行内容
简单处理
import clr
#添加对cloud插件开发的常用组件的引用
clr.AddReference('System')
clr.AddReference('System.Data')
clr.AddReference('Kingdee.BOS')
clr.AddReference('Kingdee.BOS.Core')
clr.AddReference('Kingdee.BOS.App')
clr.AddReference('Kingdee.BOS.ServiceHelper')
#clr.AddReference('Kingdee.BOS.KDSReportEntity')
#clr.AddReference('Kingdee.BOS.App.KDSService')
clr.AddReference('Newtonsoft.Json')
def BarItemClick(e):
key=e.BarItemKey;
this.View.ShowMessage("欢迎回来 {0} ".format (key));
修改数据并刷新
import clr
import sys
clr.AddReference('System')
clr.AddReference('Kingdee.BOS.Core')
clr.AddReference('Newtonsoft.Json')
clr.AddReference('Kingdee.BOS.App')
from Kingdee.BOS import *
from Kingdee.BOS.Core import *
from Kingdee.BOS.Core.Bill import *
from Kingdee.BOS.Core.DynamicForm.PlugIn import *
from Kingdee.BOS.Core.DynamicForm.PlugIn.ControlModel import *
from Kingdee.BOS.JSON import *
from Newtonsoft.Json import JsonConvert
from System import *
import System
import System.IO
from Kingdee.BOS.App.Data import *
def getDt():
""" 获取事件 """
current_date = System.DateTime.Now
date_string = current_date.ToString("MM-dd HH:mm:ss")
return date_string
def myLog(msg):
""" 写日志到文件 """
current_date = System.DateTime.Now
# 格式化输出(例如:2023-11-20)
date_string = current_date.ToString("yyyy-MM-dd")
logWriter = System.IO.StreamWriter("d:\jack\debug_output-{}.txt".format(date_string), True)
# 重定向到文件
original_out = System.Console.Out
System.Console.SetOut(logWriter)
# 4. 使用Console.WriteLine输出(会被重定向到文件)
System.Console.WriteLine(msg)
# 恢复并关闭
System.Console.SetOut(original_out)
logWriter.Close()
def showObj(obj):
""" 显示对象内容 """
myLog("{0} {1} dir( obj ) {1} {2}\t".format(getDt(), '-'*10, type(obj).__name__))
for i in dir(obj):
try:
cobj = getattr(obj,i,None)
except Exception as e:
myLog("Error: {}".format(e))
myLog(" {0} , type = {1} value = {2} ".format(i , type(cobj).__name__, cobj ))
def BarItemClick(e):
key=e.BarItemKey;
if(key !="XJPT_tbButton_2" ):
return
showObj(e)
showObj(this.View.Model.DataObject)
iD = this.View.Model.DataObject.Id
if(iD <= 0 ):
this.View.ShowMessage("未保存单据不能获取 {} ".format ( '' ));
else:
fsql="/*dialect*/ exec z_fxfph {0}".format(iD);
DBUtils.Execute(this.Context,fsql);
this.View.ShowMessage("完成操作 {0} ".format ( "" ));
this.View.InvokeFormOperation("Refresh")
myLog(" this.View.Model.DataObject.Id =={0} ".format(this.View.Model.DataObject.Id ))
def OnLoad(e):
return
#---------
myLog("{0}OnLoad e {0} {1}\t".format('-'*10, type(e).__name__))
for i in dir(e):
myLog("\t{}".format(i))
提交判断提示
表单数据路径 this.View.Model.DataObject.表单名ENTRY ,其中AP_PAYABLE应付单
this.View.Model.DataObject.AP_PAYABLEENTRY
导出数据模型
文件》数据模型》查找》导出 ,参考表格中的实体属性一列 ,非表格字段标识
采购订单含税单价==含税单价 and 采购订单单价==单价
F_XJPT_Price==TaxPrice and F_XJPT_Price1==FPrice
import clr
import sys
clr.AddReference('System')
clr.AddReference('Kingdee.BOS.Core')
clr.AddReference('Newtonsoft.Json')
clr.AddReference('Kingdee.BOS.App')
from Kingdee.BOS import *
from Kingdee.BOS.Core import *
from Kingdee.BOS.Core.Bill import *
from Kingdee.BOS.Core.DynamicForm.PlugIn import *
from Kingdee.BOS.Core.DynamicForm.PlugIn.ControlModel import *
from Kingdee.BOS.JSON import *
from Newtonsoft.Json import JsonConvert
from System import *
import System
import System.IO
from Kingdee.BOS.App.Data import *
pName = "保存和提交时检查价格是否相同"
def getDt():
""" 获取时间 """
current_date = System.DateTime.Now
date_string = current_date.ToString("MM-dd HH:mm:ss")
return date_string
def myLog(msg):
""" 写日志到文件 """
current_date = System.DateTime.Now
# 格式化输出(例如:2023-11-20)
date_string = current_date.ToString("yyyy-MM-dd")
logWriter = System.IO.StreamWriter("d:\jack\debug_output-{}.txt".format(date_string), True)
# 重定向到文件
original_out = System.Console.Out
System.Console.SetOut(logWriter)
# 4. 使用Console.WriteLine输出(会被重定向到文件)
System.Console.WriteLine(msg)
# 恢复并关闭
System.Console.SetOut(original_out)
logWriter.Close()
def showObj(obj):
""" 显示对象内容 到log文件 """
myLog("{0} {1} dir( obj ) {1} {2}\t".format(getDt(), '-'*10, type(obj).__name__))
for i in dir(obj):
try:
cobj = getattr(obj,i,None)
except Exception as e:
myLog("Error: {}".format(e))
myLog(" {0} , type = {1} value = {2} ".format(i , type(cobj).__name__, cobj ))
#-----------------
def BeforeDoOperation(e):
""" 捕获所以操作事件 """
showObj(e)
tmp = "myLog:str(e.Operation) {0} , type = {1} value = {2} "
tmp = tmp.format(str(e.Operation) , type(e.Operation).__name__ , e.Operation )
myLog(tmp)
# 判断是否为提交操作
if type(e.Operation).__name__ == "Submit":
提交操作(e)
return
def 提交操作(e):
""" 提交操作 """
#this.View.Model.DataObject
#showObj(this.View.Model.DataObject)
entry_list = this.View.Model.DataObject.AP_PAYABLEENTRY
for ir in entry_list:
# 打印条目
#msg = "{}\n".format(JsonConvert.SerializeObject( ir ))
#myLog(msg)
tmp = "myLog:F_XJPT_Price= {0} , FTaxPrice = {1} F_XJPT_Price1 = {2} FPrice = {3}"
tmp = tmp.format( ir["F_XJPT_Price"] , ir["TaxPrice"] , ir["F_XJPT_Price1"] , ir["FPrice"] )
myLog(tmp)
if ir.F_XJPT_Price==ir.TaxPrice and ir.F_XJPT_Price1==ir.FPrice:
# 采购订单含税单价==含税单价 and 采购订单单价==单价
return
# 禁止提交
e.Cancel=True # 取消当前操作
raise Exception("采购价格和应付价格不同,请上下查单据的价格!")
#key=e.BarItemKey;
#this.View.ShowMessage("完成操作 {0} ".format ( 123 ));
def BeforeSave(e):
showObj(e)
#e.Cancel=True # 这个怎么写
#raise Exception("采购价格和应付价格不同,请上下查单据的价格!")
#key=e.BarItemKey;
#this.View.ShowMessage("完成操作 {0} ".format ( 123 ));
通用事件处理
import clr
import sys
clr.AddReference('System')
clr.AddReference('Kingdee.BOS.Core')
clr.AddReference('Newtonsoft.Json')
clr.AddReference('Kingdee.BOS.App')
from Kingdee.BOS import *
from Kingdee.BOS.Core import *
from Kingdee.BOS.Core.Bill import *
from Kingdee.BOS.Core.DynamicForm.PlugIn import *
from Kingdee.BOS.Core.DynamicForm.PlugIn.ControlModel import *
from Kingdee.BOS.JSON import *
from Newtonsoft.Json import JsonConvert
from System import *
import System
import System.IO
from Kingdee.BOS.App.Data import *
def getDt():
""" 获取事件 """
current_date = System.DateTime.Now
date_string = current_date.ToString("MM-dd HH:mm:ss")
return date_string
def myLog(msg):
""" 写日志到文件 """
current_date = System.DateTime.Now
# 格式化输出(例如:2023-11-20)
date_string = current_date.ToString("yyyy-MM-dd")
logWriter = System.IO.StreamWriter("d:\jack\debug_output-{}.txt".format(date_string), True)
# 重定向到文件
original_out = System.Console.Out
System.Console.SetOut(logWriter)
# 4. 使用Console.WriteLine输出(会被重定向到文件)
System.Console.WriteLine(msg)
# 恢复并关闭
System.Console.SetOut(original_out)
logWriter.Close()
def showObj(obj):
""" 显示对象内容 """
myLog("{0} {1} dir( obj ) {1} {2}\t".format(getDt(), '-'*10, type(obj).__name__))
for i in dir(obj):
try:
cobj = getattr(obj,i,None)
except Exception as e:
myLog("Error: {}".format(e))
myLog(" {0} , type = {1} value = {2} ".format(i , type(cobj).__name__, cobj ))
#-----------------
def BeforeDoOperation(e):
showObj(e)
myLog("myLog:str(e.Operation) {0} , type = {1} value = {2} ".format(str(e.Operation), type(e.Operation).__name__, e.Operation ))
# 判断是否为提交操作
if type(e.Operation).__name__ != "Submit":
return
e.Cancel=True # 这个怎么写
raise Exception("采购价格和应付价格不同,请上下查单据的价格!")
#key=e.BarItemKey;
#this.View.ShowMessage("完成操作 {0} ".format ( 123 ));
def BeforeSave(e):
showObj(e)
#e.Cancel=True # 这个怎么写
#raise Exception("采购价格和应付价格不同,请上下查单据的价格!")
#key=e.BarItemKey;
#this.View.ShowMessage("完成操作 {0} ".format ( 123 ));
空操作技术(不推荐)
- 配置前端点击事件
- 通过点击事件空操作+python脚本
- 调用存储过程更新数据
添加菜单
工具条右击->按钮->单击事件
-
新增/修改【服务编辑】->改服务描述->新增
- 新增/修改【操作编辑】->操作类型=空操作->修改操作代码->修改名称
- 其他控制->服务插件
- 注册脚本->编辑脚本
这种方法过于麻烦不如 插件模式
alter PROCEDURE [dbo].[z_fxfph]--exec z_fxfph '100039'
@fid int
AS
BEGIN
update b set b.F_XJPT_PRICE1=g.FPRICE,b.F_XJPT_PRICE=g.FTAXPRICE
from T_AP_PAYABLE a
join T_AP_PAYABLEENTRY b on b.fid=a.fid
join T_AP_PAYABLE_LK c on c.fentryid=b.fentryid
join T_AP_PAYABLEENTRY i on i.fentryid=c.fsid
join T_AP_PAYABLE j on j.fid=c.fsbillid
join T_AP_PAYABLE_LK k on k.fentryid=i.fentryid
join T_STK_INSTOCKENTRY d on d.fentryid=k.fsid
join T_STK_INSTOCK e on e.fid=k.fsbillid
join T_STK_INSTOCKENTRY_LK f on f.fentryid=d.fentryid --and a.fbillno='AP00026516'
join T_PUR_POORDERENTRY_F g on g.fentryid=f.fsid
join T_PUR_POORDER h on h.fid=f.fsbillid
where a.FSETACCOUNTTYPE=3 and a.fid=@fid
end
exec z_fxfph '100039'
# 引入CLR运行库
import clr
# 添加插件开发必要组件
clr.AddReference('Kingdee.BOS')
clr.AddReference('Kingdee.BOS.Core')
clr.AddReference('Kingdee.BOS.App')
# 导入命名空间
from Kingdee.BOS import *
from Kingdee.BOS.Core import *
from Kingdee.BOS.Core.Bill import *
from Kingdee.BOS.Core.DynamicForm.PlugIn import *
from Kingdee.BOS.Core.DynamicForm.PlugIn.ControlModel import *
from System import *
from Kingdee.BOS.App.Data import *
def AfterExecuteOperationTransaction(e):
try:
# 确保操作对象有效
if e.DataEntitys is None or e.DataEntitys.Count == 0:
this.View.ShowMessage("未获取到有效数据!")
return
# 遍历数据实体
for item in e.DataEntitys:
# 获取主键ID,注意字段名区分大小写(通常为"Id")
fid = str(item["Id"]) if "Id" in item and item["Id"] else None
if not fid:
this.View.ShowMessage("主键ID为空,无法执行操作!")
continue # 跳过当前项
# 方案1:安全参数化查询(推荐,若DBUtils支持)
# fsql = "/*dialect*/ EXEC z_fxfph @FID=?"
# params = (fid,)
# DBUtils.Execute(this.Context, fsql, params)
# 方案2:直接拼接(需防注入,确保fid安全)
fsql = "/*dialect*/ EXEC z_fxfph @FID='{}'".format(fid)
DBUtils.Execute(this.Context, fsql)
# 可选:记录执行日志
this.Logger.Info("成功执行存储过程,单据ID: {}".format(fid))
except Exception as ex:
# 异常处理
this.View.ShowMessage("执行出错: " + str(ex))
this.Logger.Error("插件执行错误", ex)
return
提醒
合法性检查
提交时检查
条件
FPrice != F_XJPT_Price1 OR FPriceWithTax != F_XJPT_Price