qliang-cloud

金蝶云星空实时库存专题

通过向金蝶库存单据注册Python脚本,用于实时监听库存单据审核/反审核,并且将数据发送到轻易云系统集成平台
。通过集成平台将数据分发到对应的目标系统。

向金蝶的库存单据注册脚本

注意修改脚本中的三个变量参数,MAIN_NAME表描述,MAIN_TABLE主表名,ENTRY_TABLE分录表名。关键库存单据表名参考:

库存变动表单 表头 表体
采购入库单 t_STK_InStock T_STK_INSTOCKENTRY
采购退料单 t_PUR_MRB T_PUR_MRBENTRY
销售出库单 T_SAL_OUTSTOCK T_SAL_OUTSTOCKENTRY
销售退货单 T_SAL_RETURNSTOCK T_SAL_RETURNSTOCKENTRY

更多表单名与字段可以自行查阅金蝶BOS平台,不在此赘述。
注意正式运行时将python脚本中的 SHOW_DEBUG 设置为 False 当然这不是必需的

注册金蝶列表插件

ListViewBarItemClick.py

import clr
clr.AddReference("System")
clr.AddReference("System.Web.Extensions")
clr.AddReference("Kingdee.BOS.Core")
clr.AddReference("Kingdee.BOS")
clr.AddReference(\'Kingdee.BOS.App\')
clr.AddReference("Kingdee.BOS.DataEntity")
clr.AddReference("Kingdee.BOS.ServiceHelper")
clr.AddReference("Newtonsoft.Json")
import sys
from System import *
from System.Collections.Generic import *
from System.Web.Script.Serialization import *
from System.Security.Cryptography import *
from System.Text import *
from System.Net import *
from System.IO import *
from System.Threading import *
from System.Collections.Generic import Dictionary
from Newtonsoft.Json import *
from Newtonsoft.Json.Linq import *
from Kingdee.BOS.ServiceHelper import *
from Kingdee.BOS.Core.DynamicForm import *
from Kingdee.BOS.App.Data import *
reload(sys)
sys.setdefaultencoding(\'utf-8\')

# 金蝶Cloud列表插件
# 用于监听审核、反审核事件后查询变动物料的库存数据,并将数据发送到DATAHUB
# 在应用到需要监听的不同表单时,注意需要更换 MAIN_NAME,MAIN_TABLE,ENTRY_TABLE 三个变量

# 开启debug调试消息提醒
SHOW_DEBUG = True

# DataHub Host 服务器主机
DATAHUB_HOST = \'https://www.qliang.cloud\'

# StrategyId 集线器ID
STRATEGY_ID = \'2509d92a-a91e-30a3-ae4e-33eead036a97\'


# 当前表名
MAIN_NAME = \'外购入库\';
# 当前表的主表名
MAIN_TABLE = \'t_STK_InStock\'
# 当前表的分录表名
ENTRY_TABLE = \'T_STK_INSTOCKENTRY\'

# 当前表的单据编码字段
BILL_FIELD = \'FBILLNO\';
# 物料字段名,通常情况下应该是 FMATERIALID 不需要修改
MATERIAL_FIELD = \'FMATERIALID\'
# 仓库字段名,通常情况下应该是 FSTOCKID 不需要修改
STOCK_FIELD = \'FSTOCKID\'
# 库位字段名,通常情况下应该是 FSTOCKLOCID 不需要修改
STOCKLOC_FIELD = \'FSTOCKLOCID\'
# 批次号字段名,通常情况下应该是 FLOT 不需要修改
LOT_FIELD = \'FLOT\'
# 货主字段名,通常情况下应该是 FOWNERID 不需要修改
OWNER_FIELD = \'FOWNERID\'

class Inventory:

    def __init__(self,BarItemKey):
        keys = this.ListView.SelectedRowsInfo.GetPrimaryKeyValues()
        self.BarItemKey = BarItemKey
        self.PKS = \',\'.join(keys)

    def fetch(self):
        return DBServiceHelper.ExecuteDynamicObject(
            this.Context, self.__generateSQL())
    
    def collectionToJson(self, collection):
        json = \'[\'
        for row in collection:
            json += \'{"FID":"\'+row[0].ToString() + \'"\' \
                \',"FStockId":"\'+row[1].ToString()+\'"\' \
                \',"FMaterialId":"\'+row[2].ToString()+\'"\' \
                \',"FBaseQty":"\'+row[3].ToString()+\'"\' \
                \',"FBaseAVBQty":"\'+row[4].ToString()+\'"\' \
                \',"FLot":"\'+row[5].ToString()+\'"\' \
                \',"FUpdateTime":"\'+row[6].ToString()+\'"\' \
                \',"FOwnerId":"\'+row[7].ToString()+\'"\' \
                \',"FKeeperId":"\'+row[8].ToString()+\'"\' \
                \',"FStockOrgId":"\'+row[9].ToString()+\'"\' \
                \',"FOwnerTypeId":"\'+row[10].ToString()+\'"\' \
                \',"FMaterialId_FNumber":"\'+row[11].ToString()+\'"\' \
                \',"FOwnerId_FNumber":"\'+row[12].ToString()+\'"\' \
                \',"FKeeperId_FNumber":"\'+row[13].ToString()+\'"\' \
                \',"FStockOrgId_FNumber":"\'+row[14].ToString()+\'"\' \
                \',"FProduceDate":"\'+row[15].ToString()+\'"\' \
                \',"FMtoNo":"\'+row[16].ToString()+\'"\' \
                \',"FStockStatusId":"\'+row[17].ToString()+\'"\' \
                \',"FBILLNO":"\'+row[18].ToString()+\'"\' \
                \',"id":"\'+row[0].ToString()+\'"\' \
                \',"FormName":"\'+MAIN_NAME+\'"},\'
        json = json.rstrip(\',\') + \']\'
        return \'{"idCheck":false,"content":\'+json+\',"multiple":true,"id":1}\';

    def __generateSQL(self):
        sqlArray = [
            \'SELECT DISTINCT\',
            \'INV.FID,\',
            \'INV.FStockId,\',
            \'INV.FMaterialId,\',
            \'INV.FBaseQty,\',
            \'INV.FBaseAVBQty,\',
            \'INV.FLot,\',
            \'INV.FUpdateTime,\',
            \'INV.FOwnerId,\',
            \'INV.FKeeperId,\',
            \'INV.FStockOrgId,\',
            \'INV.FOwnerTypeId,\',
            \'MATE.FNUMBER AS FMaterialId_FNumber,\',
            \'ORG1.FNUMBER AS FOwnerId_FNumber,\',
            \'ORG2.FNUMBER AS FKeeperId_FNumber,\',
            \'ORG3.FNUMBER AS FStockOrgId_FNumber,\',
            \'INV.FProduceDate,\',
            \'INV.FMtoNo,\',
            \'INV.FStockStatusId,\',
            # 如果现实单据号,则可能导致会重复发送多一些数据.但是这并不影响真实库存.如果非要传入单号,可以开启
            # \'MAIN.\'+BILL_FIELD,
            # 将单号现实为0,避免POST数据中存在重复
            "\'0\' AS FBillNo",
            \'FROM T_STK_INVENTORY INV\',
            \'LEFT JOIN \'+ENTRY_TABLE+\' BILL ON\',
            \'INV.FMATERIALID = BILL.\'+MATERIAL_FIELD,
            \'AND INV.FSTOCKID = BILL.\'+STOCK_FIELD,
            \'AND INV.FSTOCKLOCID = BILL.\'+STOCKLOC_FIELD,
            \'AND INV.FLOT = BILL.\'+LOT_FIELD,
            \'AND INV.FOWNERID = BILL.\'+OWNER_FIELD,
            \'LEFT JOIN t_bd_material   MATE  ON INV.FMATERIALID = MATE.FMATERIALID\',
            \'LEFT JOIN t_ORG_Organizations ORG1 ON INV.FOwnerId = ORG1.FORGID\',
            \'LEFT JOIN t_ORG_Organizations ORG2 ON INV.FKeeperId = ORG2.FORGID\',
            \'LEFT JOIN t_ORG_Organizations ORG3 ON INV.FStockOrgId = ORG3.FORGID\',
            \'LEFT JOIN \'+MAIN_TABLE+\' MAIN ON BILL.FID = MAIN.FID\',
            \'WHERE BILL.FID IN (\'+self.PKS+\')\',
        ]
        sql = \' \'.join(sqlArray)
        if self.BarItemKey == \'tbApprove\':
            sql += " AND MAIN.FDOCUMENTSTATUS = \'C\'"
        else:
            sql += " AND MAIN.FDOCUMENTSTATUS = \'D\'"
        # this.View.ShowMessage(sql)
        return sql

def AfterBarItemClick(e):
    if e.BarItemKey == \'tbApprove\' or e.BarItemKey == \'tbReject\':
        if len(this.ListView.SelectedRowsInfo.GetPrimaryKeyValues()) > 0:
            handle(e.BarItemKey)

def handle(BarItemKey):
    inv = Inventory(BarItemKey)
    url = DATAHUB_HOST + \'/api/open/operation/\'+STRATEGY_ID
    collection = inv.fetch()
    if len(collection) == 0:
        return;
    webRequest = post(url, inv.collectionToJson(collection))
    result = JObject.Parse(webRequest)
    if SHOW_DEBUG == True:
        this.View.ShowMessage(webRequest)

def get(url):
    webRequest = WebRequest.Create(url)
    webRequest.Method = "GET"
    webResponse = webRequest.GetResponse()
    stream = webResponse.GetResponseStream()
    streamReader = StreamReader(stream, Encoding.GetEncoding("utf-8"))
    result = streamReader.ReadToEnd()
    return result

def post(url, postdata):
    webRequest = HttpWebRequest.Create(url)
    webRequest.Method = "POST"
    webRequest.Accept = "application/json, text/plain, */*"
    webRequest.ContentType = "application/json;charset=UTF-8"
    data = Encoding.ASCII.GetBytes(postdata)
    webRequest.ContentLength = data.Length
    webRequest.GetRequestStream().Write(data, 0, data.Length)
    webRequest.GetRequestStream().Flush()
    webRequest.GetRequestStream().Close()
    webResponse = webRequest.GetResponse()
    streamReader = StreamReader(
        webResponse .GetResponseStream(), Encoding.GetEncoding("utf-8"))
    result = streamReader.ReadToEnd()
    return result

注册金蝶表单插件

DynamicFormDataChanged.py

import clr
clr.AddReference("System")
clr.AddReference("System.Web.Extensions")
clr.AddReference("Kingdee.BOS.Core")
clr.AddReference("Kingdee.BOS")
clr.AddReference(\'Kingdee.BOS.App\')
clr.AddReference("Kingdee.BOS.DataEntity")
clr.AddReference("Kingdee.BOS.ServiceHelper")
clr.AddReference("Newtonsoft.Json")
import sys
from System import *
from System.Collections.Generic import *
from System.Web.Script.Serialization import *
from System.Security.Cryptography import *
from System.Text import *
from System.Net import *
from System.IO import *
from System.Threading import *
from System.Collections.Generic import Dictionary
from Newtonsoft.Json import *
from Newtonsoft.Json.Linq import *
from Kingdee.BOS.ServiceHelper import *
from Kingdee.BOS.Core.DynamicForm import *
from Kingdee.BOS.App.Data import *
reload(sys)
sys.setdefaultencoding(\'utf-8\')

# 金蝶Cloud表单插件
# 用于监听数据变动审核、反审核事件后查询变动物料的库存数据,并将数据发送到DATAHUB
# 在应用到需要监听的不同表单时,注意需要更换 MAIN_NAME,MAIN_TABLE,ENTRY_TABLE 三个变量

# 开启debug调试消息提醒
SHOW_DEBUG = True

# DataHub Host 服务器主机
DATAHUB_HOST = \'https://www.qliang.cloud\'

# StrategyId 集线器ID
STRATEGY_ID = \'2509d92a-a91e-30a3-ae4e-33eead036a97\'


# 当前表名
MAIN_NAME = \'外购入库\';
# 当前表的主表名
MAIN_TABLE = \'t_STK_InStock\'
# 当前表的分录表名
ENTRY_TABLE = \'T_STK_INSTOCKENTRY\'
# 当前表的单据编码字段
BILL_FIELD = \'FBILLNO\';

# 物料字段名,通常情况下应该是 FMATERIALID 不需要修改
MATERIAL_FIELD = \'FMATERIALID\'
# 仓库字段名,通常情况下应该是 FSTOCKID 不需要修改
STOCK_FIELD = \'FSTOCKID\'
# 库位字段名,通常情况下应该是 FSTOCKLOCID 不需要修改
STOCKLOC_FIELD = \'FSTOCKLOCID\'
# 批次号字段名,通常情况下应该是 FLOT 不需要修改
LOT_FIELD = \'FLOT\'
# 货主字段名,通常情况下应该是 FOWNERID 不需要修改
OWNER_FIELD = \'FOWNERID\'


class Inventory:

    def __init__(self):
        self.PK = this.View.Model.GetPKValue().ToString()

    def fetch(self):
        return DBServiceHelper.ExecuteDynamicObject(
            this.Context, self.__generateSQL())

    def collectionToJson(self, collection):
        json = \'[\'
        for row in collection:
            json += \'{"FID":"\'+row[0].ToString() + \'"\' \
                \',"FStockId":"\'+row[1].ToString()+\'"\' \
                \',"FMaterialId":"\'+row[2].ToString()+\'"\' \
                \',"FBaseQty":"\'+row[3].ToString()+\'"\' \
                \',"FBaseAVBQty":"\'+row[4].ToString()+\'"\' \
                \',"FLot":"\'+row[5].ToString()+\'"\' \
                \',"FUpdateTime":"\'+row[6].ToString()+\'"\' \
                \',"FOwnerId":"\'+row[7].ToString()+\'"\' \
                \',"FKeeperId":"\'+row[8].ToString()+\'"\' \
                \',"FStockOrgId":"\'+row[9].ToString()+\'"\' \
                \',"FOwnerTypeId":"\'+row[10].ToString()+\'"\' \
                \',"FMaterialId_FNumber":"\'+row[11].ToString()+\'"\' \
                \',"FOwnerId_FNumber":"\'+row[12].ToString()+\'"\' \
                \',"FKeeperId_FNumber":"\'+row[13].ToString()+\'"\' \
                \',"FStockOrgId_FNumber":"\'+row[14].ToString()+\'"\' \
                \',"FProduceDate":"\'+row[15].ToString()+\'"\' \
                \',"FMtoNo":"\'+row[16].ToString()+\'"\' \
                \',"FStockStatusId":"\'+row[17].ToString()+\'"\' \
                \',"FBILLNO":"\'+row[18].ToString()+\'"\' \
                \',"id":"\'+row[0].ToString()+\'"\' \
                \',"FormName":"\'+MAIN_NAME+\'"},\'
        json = json.rstrip(\',\') + \']\'
        return \'{"idCheck":false,"content":\'+json+\',"multiple":true,"id":1}\';

    def __generateSQL(self):
        sqlArray = [
            \'SELECT DISTINCT\',
            \'INV.FID,\',
            \'INV.FStockId,\',
            \'INV.FMaterialId,\',
            \'INV.FBaseQty,\',
            \'INV.FBaseAVBQty,\',
            \'INV.FLot,\',
            \'INV.FUpdateTime,\',
            \'INV.FOwnerId,\',
            \'INV.FKeeperId,\',
            \'INV.FStockOrgId,\',
            \'INV.FOwnerTypeId,\',
            \'MATE.FNUMBER AS FMaterialId_FNumber,\',
            \'ORG1.FNUMBER AS FOwnerId_FNumber,\',
            \'ORG2.FNUMBER AS FKeeperId_FNumber,\',
            \'ORG3.FNUMBER AS FStockOrgId_FNumber,\',
            \'INV.FProduceDate,\',
            \'INV.FMtoNo,\',
            \'INV.FStockStatusId,\',
            \'MAIN.\'+BILL_FIELD,
            \'FROM T_STK_INVENTORY INV\',
            \'LEFT JOIN \'+ENTRY_TABLE+\' BILL ON\',
            \'INV.FMATERIALID = BILL.\'+MATERIAL_FIELD,
            \'AND INV.FSTOCKID = BILL.\'+STOCK_FIELD,
            \'AND INV.FSTOCKLOCID = BILL.\'+STOCKLOC_FIELD,
            \'AND INV.FLOT = BILL.\'+LOT_FIELD,
            \'AND INV.FOWNERID = BILL.\'+OWNER_FIELD,
            \'LEFT JOIN t_bd_material   MATE  ON INV.FMATERIALID = MATE.FMATERIALID\',
            \'LEFT JOIN t_ORG_Organizations ORG1 ON INV.FOwnerId = ORG1.FORGID\',
            \'LEFT JOIN t_ORG_Organizations ORG2 ON INV.FKeeperId = ORG2.FORGID\',
            \'LEFT JOIN t_ORG_Organizations ORG3 ON INV.FStockOrgId = ORG3.FORGID\',
            \'LEFT JOIN \'+MAIN_TABLE+\' MAIN ON BILL.FID = MAIN.FID\',
            \'WHERE BILL.FID = \'+self.PK,
        ]
        return \' \'.join(sqlArray)


def DataChanged(e):
    if e.Key.ToString() == \'FDocumentStatus\' and e.OldValue.ToString() == \'B\' and e.NewValue.ToString() == \'C\':
        handle()
    elif e.Key.ToString() == \'FDocumentStatus\' and e.OldValue.ToString() == \'C\' and e.NewValue.ToString() == \'D\':
        handle()


def handle():
    inv = Inventory()
    url = DATAHUB_HOST + \'/api/open/operation/\'+STRATEGY_ID
    collection = inv.fetch()
    if len(collection) == 0:
        return;
    webRequest = post(url, inv.collectionToJson(collection))
    result = JObject.Parse(webRequest)
    if SHOW_DEBUG == True:
        this.View.ShowMessage(webRequest)


def get(url):
    webRequest = WebRequest.Create(url)
    webRequest.Method = "GET"
    webResponse = webRequest.GetResponse()
    stream = webResponse.GetResponseStream()
    streamReader = StreamReader(stream, Encoding.GetEncoding("utf-8"))
    result = streamReader.ReadToEnd()
    return result


def post(url, postdata):
    webRequest = HttpWebRequest.Create(url)
    webRequest.Method = "POST"
    webRequest.Accept = "application/json, text/plain, */*"
    webRequest.ContentType = "application/json;charset=UTF-8"
    data = Encoding.ASCII.GetBytes(postdata)
    webRequest.ContentLength = data.Length
    webRequest.GetRequestStream().Write(data, 0, data.Length)
    webRequest.GetRequestStream().Flush()
    webRequest.GetRequestStream().Close()
    webResponse = webRequest.GetResponse()
    streamReader = StreamReader(
        webResponse .GetResponseStream(), Encoding.GetEncoding("utf-8"))
    result = streamReader.ReadToEnd()
    return result

分类:

技术点:

相关文章: