Question: How to handle BO Method calls with input-output parameters?

10.2.200.16
I’m having a problem calling methods in the CostAdjustment BO through the following code. I’ve already run a trace, and these appear to be the only methods I need to call. I’m getting an error when trying to make the CostAdjustment.OnChangeStdMtlUnitCost call that says the ttCostAdjustment table was not found. Can anyone help on what I’m doing wrong here? This is the first time I’m trying to call methods in code!

bool RequiresUserInput = false;
decimal SPLCost;
decimal SPLBurCost;
string PartTranPK = "";

this.PublishInfoMessage("In NewPartCostUpdate..",
                              Ice.Common.BusinessObjectMessageType.Information,
                              Ice.Bpm.InfoMessageDisplayMode.Individual, "", "");

Erp.Tablesets.CostAdjustmentTableset cats = new CostAdjustmentTableset();

Erp.Contracts.CostAdjustmentSvcContract hCostAdjustment = null;

var ttVendPart_xRow = (from ttVendPart_Row in ttVendPart
                                     where ttVendPart_Row.RowMod == "A" && ttVendPart_Row.UDField<decimal>("Number01") > 0
                                     select ttVendPart_Row).FirstOrDefault();

if (ttVendPart_xRow != null)
{
   SPLCost = ttVendPart_xRow.UDField<decimal>("Number01");

   this.PublishInfoMessage("Part Num: " + ttVendPart_xRow.PartNum + " Curr. Cost: " + SPLCost.ToString(),
                           Ice.Common.BusinessObjectMessageType.Information,
                           Ice.Bpm.InfoMessageDisplayMode.Individual, "", "");
      
   hCostAdjustment = Ice.Assemblies.ServiceRenderer.GetService<CostAdjustmentSvcContract>(this.Db);

   if (hCostAdjustment != null)
   {
      hCostAdjustment.GetCostAdjustment(ttVendPart_xRow.PartNum, ref cats);    
 
      var CostAdjTest = (from row in cats.CostAdjustment
                         select row).FirstOrDefault();
      
      this.PublishInfoMessage("Part Num: " + CostAdjTest.PartNum,
                              Ice.Common.BusinessObjectMessageType.Information,
                              Ice.Bpm.InfoMessageDisplayMode.Individual, "", "");
      
      hCostAdjustment.OnChangeStdMtlUnitCost(SPLCost, ref cats);
   
      var CostAdjustment_xRow = cats.CostAdjustment.FirstOrDefault();
   
      this.PublishInfoMessage("Std Mtl Cost: " + CostAdjustment_xRow.StdMtlUnitCost.ToString() + " Std Bur Cost: " + CostAdjustment_xRow.StdBurUnitCost.ToString(),
                              Ice.Common.BusinessObjectMessageType.Information,
                              Ice.Bpm.InfoMessageDisplayMode.Individual, "", "");
      
      CostAdjustment_xRow.ReasonCode = "621";
      CostAdjustment_xRow.ReasonCodeDesc = "Cost Build Adjustment";

      hCostAdjustment.PreSetCostAdjustment(ref cats, out RequiresUserInput);
      hCostAdjustment.SetCostAdjustment(ref cats, out PartTranPK);       
   }
}

what is the error?

sorry the code doesn’t reference ttCostAdjustment so I am confused.

In general you’ll modify the dataset and then submit the method call

What you can try and do is create this with a widget.

See how epicor codes it. then mimic that.

I just created a few widgets and here is the code.

You are close.

using Epicor.Customization.Bpm;
using Epicor.Data;
using Epicor.Hosting;
using Epicor.Utilities;
using Erp.Contracts;
using Erp.Tables;
using Erp.Tablesets;
using Ice;
using Ice.Contracts;
using Ice.ExtendedData;
using Ice.Tables;
using Ice.Tablesets;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.ServiceModel;

namespace Epicor.Customization.Bpm.BO2D984BC781EE41DA8EC736A64A61AA7F
{
    internal sealed class UpdatePreProcessingDirective_test_CF7C5902285C4609812430E53D51EDB1 : UpdateDirectiveBase
    {
        #region Local variables

        private Erp.Tablesets.CostAdjustmentTableset tsCA;

        private System.Boolean blnOutPut;

        private System.String rtnString;

        #endregion // Local variables

        public UpdatePreProcessingDirective_test_CF7C5902285C4609812430E53D51EDB1(UpdateImpl owner, Erp.ErpContext ctx, Epicor.Hosting.Session session)
            : base(
                owner,
                ctx,
                session,
                new Epicor.Customization.Bpm.DirectiveDescription
                {
                    Id = new Guid("cf7c5902-285c-4609-8124-30e53d51edb1"),
                    Name = "test",
                    Type = Ice.BO.BpMethod.MethodDirectiveType.PreProcessing,
                    TypeName = "PreProcessing",
                    VisibilityScope = Ice.BO.BpMethod.DirectiveScope.CompanySpecific,
                    Company = "EmbedTek",
                    TenantId = null,
                })
        {
        }

        protected override void InitializeLocalVariables(bool preparation)
        {
            this.tsCA = TablesetFactory.Create<Erp.Tablesets.CostAdjustmentTableset>();
            this.blnOutPut = default(System.Boolean);
            this.rtnString = default(System.String);
        }

        protected override void TeardownLocalVariables()
        {
            this.tsCA = null;
            this.blnOutPut = default(System.Boolean);
            this.rtnString = default(System.String);
        }

        protected override bool ExecuteCore()
        {
            var conditionBlockValue = false;

            if (this.BpmFormJump != null)
            {
                if (this.BpmFormJump.JumpToConditionId == "d6ebba8a-7ad1-49eb-a9fb-e0fe031db251") goto start;
                throw new Ice.Common.BusinessObjectException("Unexpected BpmForm jump block");
            }

start: // Name = "Condition 0", Id = "d6ebba8a-7ad1-49eb-a9fb-e0fe031db251"
            this.ClearDataFilter();
            if (this.BpmFormJump != null)
                conditionBlockValue = true;
            else
            conditionBlockValue =
                this.C001_FieldCondition();
            if (!conditionBlockValue) goto finish;
            this.FilterData(row =>
                {
                    var isOk =
                        this.C001_FieldCondition(row);
                    return isOk;
                });
            this.CurrentConditionId = "d6ebba8a-7ad1-49eb-a9fb-e0fe031db251";
            if (this.BpmFormJump != null)
            {
                if (this.BpmFormJump.JumpToActionId == "9dab4482-d6d4-4be9-8d9f-13bc1ce98102") goto block001;
                if (this.BpmFormJump.JumpToActionId == "6d482f26-3f68-4ad7-a455-c8dc8b8fbd5e") goto block002;
                if (this.BpmFormJump.JumpToActionId == "c5974e0c-4821-4b8b-b89f-59f75458eac5") goto block003;
                if (this.BpmFormJump.JumpToActionId == "4d2bea74-55a5-43fa-9472-362d4b9df311") goto block004;
                if (this.BpmFormJump.JumpToActionId == "a31544fa-18b0-4a92-b90f-f62a56f5fa09") goto block005;
                throw new Ice.Common.BusinessObjectException("Unexpected BpmForm jump block in condition");
            }
            

block001: // Name = "Invoke BO Method 0", Id = "9dab4482-d6d4-4be9-8d9f-13bc1ce98102"
            this.UseDataFilter = true;
            try
            {
                this.A001_InvokeBOMethodAction();
                if (this.BpmDataFormIsPublished())
                {
                    this.BpmDataFormSerializeInterimPoint("9dab4482-d6d4-4be9-8d9f-13bc1ce98102");
                    return false;
                }
            }
            catch (Ice.Common.BusinessObjectException ex)
            {
                this.RememberException(ex);
            }
            this.RefreshData(matched: false);

block002: // Name = "Invoke BO Method 1", Id = "6d482f26-3f68-4ad7-a455-c8dc8b8fbd5e"
            this.UseDataFilter = true;
            try
            {
                this.A002_InvokeBOMethodAction();
                if (this.BpmDataFormIsPublished())
                {
                    this.BpmDataFormSerializeInterimPoint("6d482f26-3f68-4ad7-a455-c8dc8b8fbd5e");
                    return false;
                }
            }
            catch (Ice.Common.BusinessObjectException ex)
            {
                this.RememberException(ex);
            }
            this.RefreshData(matched: false);

block003: // Name = "Invoke BO Method 2", Id = "c5974e0c-4821-4b8b-b89f-59f75458eac5"
            this.UseDataFilter = true;
            try
            {
                this.A003_InvokeBOMethodAction();
                if (this.BpmDataFormIsPublished())
                {
                    this.BpmDataFormSerializeInterimPoint("c5974e0c-4821-4b8b-b89f-59f75458eac5");
                    return false;
                }
            }
            catch (Ice.Common.BusinessObjectException ex)
            {
                this.RememberException(ex);
            }
            this.RefreshData(matched: false);

block004: // Name = "Invoke BO Method 3", Id = "4d2bea74-55a5-43fa-9472-362d4b9df311"
            this.UseDataFilter = true;
            try
            {
                this.A004_InvokeBOMethodAction();
                if (this.BpmDataFormIsPublished())
                {
                    this.BpmDataFormSerializeInterimPoint("4d2bea74-55a5-43fa-9472-362d4b9df311");
                    return false;
                }
            }
            catch (Ice.Common.BusinessObjectException ex)
            {
                this.RememberException(ex);
            }
            this.RefreshData(matched: false);

block005: // Name = "Invoke BO Method 4", Id = "a31544fa-18b0-4a92-b90f-f62a56f5fa09"
            this.UseDataFilter = true;
            try
            {
                this.A005_InvokeBOMethodAction();
                if (this.BpmDataFormIsPublished())
                {
                    this.BpmDataFormSerializeInterimPoint("a31544fa-18b0-4a92-b90f-f62a56f5fa09");
                    return false;
                }
            }
            catch (Ice.Common.BusinessObjectException ex)
            {
                this.RememberException(ex);
            }
            this.RefreshData(matched: false);

finish:
            return true;
        }

        private bool C001_FieldCondition(object currentRow = null)
        {
            if (currentRow == null)
            {
                return ds.VendPart.Any(r => r.Added() && string.Compare(r.PartNum, ("0"), StringComparison.OrdinalIgnoreCase) > 0);
            }
        
            var typedRow = currentRow as Erp.Tablesets.VendPartRow;
            if (typedRow != null)
            {
                return typedRow.Added() && string.Compare(typedRow.PartNum, ("0"), StringComparison.OrdinalIgnoreCase) > 0;
            }
        
            return true;
        }

        private void A001_InvokeBOMethodAction()
        {
            var bo = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.CostAdjustmentSvcContract>(this.Db);
            if (bo == null)
            {
                throw new Ice.Common.EpicorServerException("Can't resolve instance of 'Erp.CostAdjustment' service.");
            }
        
            using (bo)
            {
                bo.GetNewCostAdjustment(
                    ref this.tsCA);
            }
        }

        private void A002_InvokeBOMethodAction()
        {
            var bo = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.CostAdjustmentSvcContract>(this.Db);
            if (bo == null)
            {
                throw new Ice.Common.EpicorServerException("Can't resolve instance of 'Erp.CostAdjustment' service.");
            }
        
            using (bo)
            {
                var ttVendPartRow = Epicor.Customization.Bpm.EnumerableExtensions.GetSingleRow(ds.VendPart, "ttVendPart");
        
                System.String arg01 = (ttVendPartRow.PartNum);
        
                bo.OnChangePartNum(
                    arg01,
                    ref this.tsCA);
            }
        }

        private void A003_InvokeBOMethodAction()
        {
            var bo = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.CostAdjustmentSvcContract>(this.Db);
            if (bo == null)
            {
                throw new Ice.Common.EpicorServerException("Can't resolve instance of 'Erp.CostAdjustment' service.");
            }
        
            using (bo)
            {
                System.Decimal arg01 = (System.Decimal)(0);
        
                bo.OnChangeStdMtlUnitCost(
                    arg01,
                    ref this.tsCA);
            }
        }

        private void A004_InvokeBOMethodAction()
        {
            var bo = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.CostAdjustmentSvcContract>(this.Db);
            if (bo == null)
            {
                throw new Ice.Common.EpicorServerException("Can't resolve instance of 'Erp.CostAdjustment' service.");
            }
        
            using (bo)
            {
                bo.PreSetCostAdjustment(
                    ref this.tsCA,
                    out this.blnOutPut);
            }
        }

        private void A005_InvokeBOMethodAction()
        {
            var bo = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.CostAdjustmentSvcContract>(this.Db);
            if (bo == null)
            {
                throw new Ice.Common.EpicorServerException("Can't resolve instance of 'Erp.CostAdjustment' service.");
            }
        
            using (bo)
            {
                bo.SetCostAdjustment(
                    ref this.tsCA,
                    out this.rtnString);
            }
        }

        protected override void StoreVariables(Epicor.Customization.Bpm.ISerializationBufferBuilder builder)
        {
            builder
                .AddVariable("tsCA", this.tsCA)
                .AddVariable("blnOutPut", this.blnOutPut)
                .AddVariable("rtnString", this.rtnString);
        }

        protected override void BpmDataFormRestoreVariables(IReadOnlyDictionary<string, object> variables)
        {
            this.VerifyNumberOfStoredVariables(3, variables.Count);

            this.tsCA = this.GetStoredValue<Erp.Tablesets.CostAdjustmentTableset>(variables, "tsCA");
            this.blnOutPut = this.GetStoredValue<System.Boolean>(variables, "blnOutPut");
            this.rtnString = this.GetStoredValue<System.String>(variables, "rtnString");
        }
    }
}
1 Like

Thanks, Ken! I’ll go over the code and let you know how it goes.

John

Thanks again, Ken! Apparently I needed to create the CostAdjustment tableset first instead of using the GetCostAdjustment call. Boy, do I feel dumb :slightly_frowning_face:

Don’t feel dumb, you didn’t know.

If this is a new BPM, give the widgets a try instead of code. That way there is less code to manage, but that is just me.

2 Likes

Ken, from what I’ve been reading on this and other groups, people have been saying it’s just as easy to learn how to do it in code instead of going through using
the widgets. Since I’ve been working with C# for a while now and we’ve already done a fair amount of coding in our BPMs, coding is consistent with our environment. I greatly appreciate the help!

That could go either way. It really depends on what you are doing. For simple things that don’t need looping, widgets are pretty easy. As you get more complex, it’s easier to manage it in code. But it’s not an all or none thing. There is a line somewhere, and both are useful.