Insert New Line on Quote at Creation

Good afternoon good people. What I’m trying to do is when a user creates a new quote, a new line item is automatically added through a BPM Method Directive. I’ve created the directive on Erp.Quote.GetNewQuoteHed in Post-Processing. That way the quote would be created and I could use that number to populate the new line in the QuoteDtl table. But, after I create a new Quote, nothing happens. My code is below. Can anyone point me in a direction with this? Thank you for your time and any help you can provide!

var quotHed = (from row in ttQuoteHed
							 where row.Added() || row.Updated()
							 select row).FirstOrDefault();

if (quotHed == null)
	return;

var proj = (from row in Db.Project
						where row.ProjectID == quotHed["ProjectID_c"]
						select row).FirstOrDefault();

var ts = new Erp.Tablesets.QuoteTableset();

// Insert "Code Research" line with $75 price into the QuoteDtl table...
using(var svc = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.QuoteSvcContract>(Db))
{
	var newPart = (from row in Db.Part
								 where row.PartNum == "CODE_RESEARCH"
								 select row).FirstOrDefault();

	svc.GetNewQuoteDtl(ref ts, quotHed.QuoteNum);

  var quoteNew = ts.QuoteDtl.FirstOrDefault();

	quoteNew.QuoteNum = quotHed.QuoteNum;
	quoteNew.PartNum = newPart.PartNum;
	quoteNew.LineDesc = newPart.PartDescription;
	quoteNew.ProdCode = newPart.ProdCode;
	quoteNew.TaxCatID = newPart.TaxCatID;
	quoteNew.CustNum = quotHed.CustNum;
	quoteNew.SellingExpectedQty = 1;
	quoteNew.SellingExpectedUM = "EA";
	quoteNew.LastUpdate = DateTime.Now;
	quoteNew.LastDcdUserID = callContextClient.CurrentUserId;
	quoteNew.OrderQty = 1;
	quoteNew.SellingExpFactor = 1;
	quoteNew.SalesCatID = proj.SalesCatID;
	quoteNew.TerritoryID = quotHed.TerritoryID;
	quoteNew.CurrentStage = quotHed.CurrentStage;
	quoteNew.CreatedFrom = "QUOTE";
	quoteNew.ExpPricePerCode = "E";
	quoteNew.MiscQtyNum = 1;
	//quoteNew.KitParentLine = ;
	//quoteNew.DisplaySeq = ;
	quoteNew.ProjectID = proj.ProjectID;
	//quoteNew.SellingFactorDirection = ;
	quoteNew.ChangedBy = quotHed.ChangedBy;
	quoteNew.ChangeDate = quotHed.ChangeDate;
	quoteNew.ChangeTime = quotHed.ChangeTime;
	quoteNew.LineType = "PART";
	quoteNew.Warranty = true;
	quoteNew.ProcessMode = "S";

	svc.Update(ref ts);
}

I think you are trying to fire this code too early by putting it on Quote.GetNewQuoteHed. I don’t think you have a QuoteNum in ttQuoteHed yet.

Can you try putting it on Quote.Update post proc, with a condition to only fire for added rows?

1 Like

Thank you @TomAlexander! I switched over to Quote.Update and added a small directive on the pre-proc side that looked for “at least one added row in the ttQuoteTable” and then enabled the Post Directive. On the post proc side, I added a “Set BPM Data Field” module that assigned the new QuoteNum to Number01. I did this because in my code, it was assigning the previous QuoteNum and not the current one in this block of code…

var quotHed = (from row in ttQuoteHed
							 where row.Added() || row.Updated()
							 select row).FirstOrDefault();

I changed the code a little (see below) to handle the changes above.

var quotHed = (from row in Db.QuoteHed
							 where row.QuoteNum == callContextBpmData.Number01
							 select row).FirstOrDefault();

if (quotHed == null)
	return;

string projid = quotHed["ProjectID_c"].ToString();//Assign custom field to variable to avoid errors

var proj = (from row in Db.Project
						where row.ProjectID == projid
						select row).FirstOrDefault();

var ts = new Erp.Tablesets.QuoteTableset();

// Insert "Code Research" line with $75 price into the QuoteDtl table...
using(var svc = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.QuoteSvcContract>(Db))
{
	var newPart = (from row in Db.Part
								 where row.PartNum == "CODE_RESEARCH"
								 select row).FirstOrDefault();

	svc.GetNewQuoteDtl(ref ts, quotHed.QuoteNum);

  var quoteNew = ts.QuoteDtl.FirstOrDefault();

	quoteNew.QuoteNum = quotHed.QuoteNum;
	quoteNew.PartNum = newPart.PartNum;
	quoteNew.LineDesc = newPart.PartDescription;
	quoteNew.ProdCode = newPart.ProdCode;
	quoteNew.TaxCatID = newPart.TaxCatID;
	quoteNew.CustNum = quotHed.CustNum;
	quoteNew.SellingExpectedQty = 1;
	quoteNew.SellingExpectedUM = "EA";
	quoteNew.LastUpdate = DateTime.Now;
	quoteNew.LastDcdUserID = callContextClient.CurrentUserId;
	quoteNew.OrderQty = 1;
	quoteNew.SellingExpFactor = 1;
	quoteNew.SalesCatID = proj.SalesCatID;
	quoteNew.TerritoryID = quotHed.TerritoryID;
	quoteNew.CurrentStage = quotHed.CurrentStage;
	quoteNew.CreatedFrom = "QUOTE";
	quoteNew.ExpPricePerCode = "E";
	quoteNew.MiscQtyNum = 1;
	quoteNew.ProjectID = proj.ProjectID;
	quoteNew.ChangedBy = quotHed.ChangedBy;
	quoteNew.ChangeDate = quotHed.ChangeDate;
	quoteNew.ChangeTime = quotHed.ChangeTime;
	quoteNew.LineType = "PART";
	quoteNew.Warranty = true;
	quoteNew.ProcessMode = "S";

	svc.Update(ref ts);
}

This worked perfectly! But now I need to find a way to auto-refresh the Quote Entry form so show the newly added line item.

Awesome! The refresh part is easy. I am on mobile and forget the exact syntax, but search this site for “this.dsholder.attach” or something like that. You will find many examples of how to use it

1 Like

Thank you so much! I did a search and found I just needed to add the code below to the end of my custom code and it refreshed the form.

this.dsHolder.Attach(ts);

1 Like

@TomAlexander I tried using “this.dsHolder.Attach(ts);”, along with similar code I used above, in a Data Directive for QuoteDtl in the In-Transaction. Everything checks out when I click the Check Syntax button, except it gives the following error for the dsHolder portion…

CS1061 'FakeDirective' does not contain a definition for 'dsHolder' and no extension method 'dsHolder' accepting a first argument of type 'FakeDirective' could be found (are you missing a using directive or an assembly reference?)

Any ideas why this works in a Method Directive and not a Data Directive?

I’m not sure I have a strong enough understanding of dsHolder to articulate why it seems to work in method directives but not data directives. But at a very vague/high level I would say it’s because method directives are more intertwined with the client. Data directives are more like database triggers.

Tagging some other folks who may have more light to shed - @Rich, @josecgomez, @timshuwy,

1 Like

You are correct.
There is no DSHolder that can be replaced on a DataDirective
Data Directive rows lower Level (DB Level) while DS holder refers to the Epicor DataSet (business object data set)

So DsHolder will not work down there.

2 Likes