1.搭建Visual Studio编写BPM的环境
a.共享或复制服务端Server文件
BPM是运行在Epicor服务器上的,因此编写BPM代码是需要服务端文件支持的,
所以需要把服务端Server文件夹共享或复制到编程的电脑上,使其能够访问,服务端文件路径如下:
b.引用编写BPM所需要的文件
在VS中新建一个类库项目,并引用编写BPM所需要的文件,文件列表如下图所示,
这些文件可以在Server目录下的Assemblies和Bin文件夹中找到.
因为Ice.Data.Model文件会在APP服务Regenerate Data Model后重新生成,
所以如果你是复制文件到编程的电脑上,需要在APP服务Regenerate Data Model后,重新复制Ice.Data.Model文件,
否则新添加的UD字段,在使用时会提示错误.
添加完文件后,编码环境就已经基本搭建好,我们就可以编写BPM代码了.
2.编写BPM代码
a. 新建类和方法.
我们最终需要把代码复制到Epicor的BPM客制代码控件里面,
所以VS中的类名和方法名称自己随便定义,方便自己查看就好.
b. 定义BPM中的变量
BPM中有些变量是可以直接使用的(如Db,Session,对应的tt表等),而VS环境中是没有的,
所以这就需要在方法外面定义BPM中的可以使用变量,如下面的代码.
public class Class1
{
Erp.ErpContext Db=new Erp.ErpContext();
Session Session = new Session("","");
public void TestFun() {
}
}
c. 添加代码中需要服务端BO文件
如下图所示,我添加了生成总账凭证所需要的两个BO文件.
3.BPM代码例子
下面是根据UD30表中维护的数据,生成总账凭证并过账的代码例子.
using System;
using System.Linq;
using Ice.Tables;
using System.Data.Entity.Core.Objects;
using Ice;
using System.Data;
namespace BPM
{
public class Class1
{
//定义BPM中已有的变量,方便在方法中使用
Erp.ErpContext Db = new Erp.ErpContext();
ObjectSet<UD30> ttUD30 = new Erp.ErpContext().UD30;
public void Approved()
{
foreach (var ttUD30Row in ttUD30)
{
//UD30表用于存储业务数据,当批核状态为Approved时,生成总账凭证
string ApprovalStatus_c = ttUD30Row.ApprovalStatus_c;
if (ApprovalStatus_c == "Approved")
{
//过去Company表中配置好的科目段落值
string InterGLNatureAcc = (from Company_Row in Db.Company
where (Company_Row.Company1 == ttUD30Row.Company)
select Company_Row.InterGLNatureAcc_c).FirstOrDefault();
if (string.IsNullOrEmpty(InterGLNatureAcc))
{
throw new Ice.BLException("Inter GL Nature account is empty in company configuration!");
}
string SourceP = ttUD30Row.SourceP_c;
string SourceT = ttUD30Row.SourceT_c;
string TargetP = ttUD30Row.TargetP_c;
string TargetT = ttUD30Row.TargetT_c;
decimal TranAmount = ttUD30Row.TranAmount_c;
using (var txScope = IceContext.CreateDefaultTransactionScope())
{
string groupID = "I" + DateTime.Now.ToString("yyyyMMdd");//生成凭证GroupID
var svc = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.GLJrnGrpSvcContract>(Db);
Erp.Tablesets.GLJrnGrpTableset ds = new Erp.Tablesets.GLJrnGrpTableset();
//新建凭证群组
svc.GetNewGLJrnGrp(ref ds);
Erp.Tablesets.GLJrnGrpRow glJrnGrpRow = ds.GLJrnGrp.LastOrDefault();
glJrnGrpRow.GroupID = groupID;
glJrnGrpRow.JournalCode = "GJ";
svc.Update(ref ds);
var svc1 = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.GLJournalEntrySvcContract>(Db);
Erp.Tablesets.GLJournalEntryTableset ds1 = new Erp.Tablesets.GLJournalEntryTableset();
//在凭证群组下添加凭证
svc1.GetNewGlJrnHedTran(ref ds1, groupID);
Erp.Tablesets.GLJrnHedRow glJrnHedRow = ds1.GLJrnHed.LastOrDefault();
glJrnHedRow.Description = "xxxxxxx";
bool requiresUserInput;
svc1.PreUpdate(ref ds1, out requiresUserInput);
svc1.Update(ref ds1);
string journalCode = glJrnHedRow.JournalCode;
int journalNum = glJrnHedRow.JournalNum;
DateTime? jEDate = glJrnHedRow.JEDate;
string legalNumber = glJrnHedRow.LegalNumber;
int fiscalYear = glJrnHedRow.FiscalYear;
int fiscalPeriod = glJrnHedRow.FiscalPeriod;
//生成第一条凭证明细记录
svc1.GetNewGLJrnDtlMnl(ref ds1, glJrnHedRow.BookID, glJrnHedRow.FiscalYear,
glJrnHedRow.FiscalYearSuffix, glJrnHedRow.JournalCode, glJrnHedRow.JournalNum, 0);
Erp.Tablesets.GLJrnDtlMnlRow glJrnDtlMnlRow1 = ds1.GLJrnDtlMnl.LastOrDefault();
glJrnDtlMnlRow1.GLAccount = InterGLNatureAcc + "||" + SourceP + "|" + SourceT;//拼接总账科目
glJrnDtlMnlRow1.SegValue1 = InterGLNatureAcc;//段落值
glJrnDtlMnlRow1.SegValue3 = SourceP;
glJrnDtlMnlRow1.SegValue4 = SourceT;
glJrnDtlMnlRow1.TotDebit = TranAmount;
svc1.ChangeGlAcct(1, ref ds1);
svc1.Update(ref ds1);
//生成第二条凭证明细记录
svc1.GetNewGLJrnDtlMnl(ref ds1, glJrnHedRow.BookID, glJrnHedRow.FiscalYear,
glJrnHedRow.FiscalYearSuffix, glJrnHedRow.JournalCode, glJrnHedRow.JournalNum, 0);
Erp.Tablesets.GLJrnDtlMnlRow glJrnDtlMnlRow2 = ds1.GLJrnDtlMnl.LastOrDefault();
glJrnDtlMnlRow2.GLAccount = InterGLNatureAcc + "||" + TargetP + "|" + TargetT;
glJrnDtlMnlRow2.SegValue1 = InterGLNatureAcc;
glJrnDtlMnlRow2.SegValue3 = TargetP;
glJrnDtlMnlRow2.SegValue4 = TargetT;
glJrnDtlMnlRow2.TotCredit = TranAmount;
svc1.ChangeGlAcct(2, ref ds1);
svc1.Update(ref ds1);
string NotAllPostedMessage;
//凭证过账
svc.PostGroupJournals(groupID, out NotAllPostedMessage);
//回写总账凭证数据到UD30表
UD30 UD30Row = (from UD30_Row in Db.UD30
where (UD30_Row.Company == ttUD30Row.Company
&& string.Compare(UD30_Row.Key1, ttUD30Row.Key1, true) == 0
&& string.Compare(UD30_Row.Key2, ttUD30Row.Key2, true) == 0
&& string.Compare(UD30_Row.Key3, ttUD30Row.Key3, true) == 0
&& string.Compare(UD30_Row.Key4, ttUD30Row.Key4, true) == 0
&& string.Compare(UD30_Row.Key5, ttUD30Row.Key5, true) == 0)
select UD30_Row).FirstOrDefault();
UD30Row.GroupID_c = groupID;
UD30Row.JournalCode_c = journalCode;
UD30Row.JournalNum_c = journalNum;
UD30Row.ApplyDate_c = jEDate;
UD30Row.LegalNumer_c = legalNumber;
Db.Validate();
txScope.Complete();
}
}
}
}
}
}
4.复制代码到BPM控件中
a.复制代码到到BPM控件中,点击"Check Syntax"按钮之后会发现一大串错误,这是因为在BPM控件中没有添加BO文件的引用
b.添加BO文件和命名空间
i.点击"Using & References…"按钮,如下图:
ii.点击"添加"按钮,筛选需要的BO文件
iii.如果在VS使用特殊的命名空间,需在如下图位置添加
c.添加BO文件和命名空间后,再次点击"Check Syntax"按钮,如果没有错误,会弹出"Syntax is OK"的提示.
5.BPM调试
Epicor官方BPM文档中有提到在VS中调试BPM代码,但是需要将VS安装在服务器上,这在大部分时候都不太可行
,所以我也就没有使用这种方法了.
我经常用的就是用PublishInfoMessage方法,弹出一个提示,然后根据提示来调试代码.
PublishInfoMessage方法参数如下:
PublishInfoMessage("YourMessage", Ice.Common.BusinessObjectMessageType.Information,
Ice.Bpm.InfoMessageDisplayMode.Individual, "YourBO", "YourMethod");