i can now get the configurator to write a price to the quotedtl table as required, however…
because of how we sell items, we also need to set the selling UOM to the correct one. so for example:
a steel coil is however long by 1.25m wide. and is used in our product configurator where the final output product will only be 1.19m wide.
this means the m2 value for the steel coil is 1LM = 0.8m2 @ 1.25m
but the final product is 1lm = 0.8403361 @ 1.19m
to add further complication to the issue, we sell our products in different widths, hence the requirement to set the UOM to the correct configured product width.
what is actually happening is if the unit price in the configurator is calculated at £50 per unit, when setting the UOM to 1.19m2 rate, it is reducing the price by the calculated value so is only writing 42.016807 to the unit price.
does anyone know if i can force write the unit price to be the £50 or willl we have to do this manually?
Are you selling the same part with different width UOM? That seems like a simple description change on the selling side. On the parts in the MoM, I assume it would be cut to different widths.
If you need to change the UOM and keep the price, I think it should work if you change the UOM in the doc rules before you set the unit price.
we manufacture composite panel (primarilly in 2 widths 1.19m and 0.9m wide)
the lenghts of these can vary massively depending on what a customer requires so from an epiicor point of view, the job just looks at the total LM of the job and we have a seperate list which creates the work instruction so the shop floor know what lengths to create.
our product configurator sets the width of the panel (and therefore the correct m2 UOM depending on the width chosen) different widths of panel also require different widths of raw materials which the configurator chooses.
i am already setting the UOM in the doc rules before the price and if i do it the other way, the price does not write to the configurator.
I think I’m missing something. Do you have different prices per m2 (I’m assuming this is Square Meters) based on the width? That is, if something is 3m^2, the price is different if its 1m x 3m vs if it’s .75m x 4m?
the prices vary massively because there is different steel grades, colours, thicknesses as well as different core grades, types thicknesses etc
but i cant say that 1m2 = 1lm because if its a 1.19m wide panel the UOM conversion is 0.840336LM to M2 but at 0.9 its 1.111111LM to M2 - this will also afffect raw material costs etc - UNLESS our system has been setup completely wrong, which given the issues we are working through, it would not surprise me!!
We do something very similar. We make conveyor belts of varying widths and lengths all day long. And we have all those variations in the steel being used, end treatments, special features, etc., etc.
What we’ve done is force all the math into the Configurator (materials, labor, etc.) to generate a unit cost to manufacture per linear foot (or meter). It also adds the appropriate markup % to get to the sales price per linear foot (or meter).
It will always do this the same way, so if you vary the width and thus vary in the cost of materials and labor - the unit mfg cost and sales price will vary accordingly.
The Quote document rules are then simplified to simply write the standard UOM of LF and the Unit Price. Plus, we have all the Configurator input variables to use later for reporting or analysis.
Finished goods UOMs won’t interfere with raw material UOMs. If your Finished Goods UOMs vary a bit, that can be integrated into the Configurator math. It may not be pretty but it’s just code
And you may have to reevaluate the sales side of this - a refactoring of how things look on the Quote/Order versus the Job Traveler. We sell in linear measure (Ft/M) but manufacture in imperial measure only - not metric. It causes some complication in the document rules but our machinery and engineering is all based on imperial.
I feel your pain, brotha. We had some heavy duty math in ours at a previous job.
This is what I was getting at @tonyb1986. It seems like you might be getting in your own way with the unit of measure on Finished Goods (Sales Order Part) vs your raw materials. You can do whatever you want in your Configurator Method Rules without affecting your pricing / DocRules and vice-versa.
On your specific problem of how to handle the pricing as it is set up, I have a couple ideas, but I need an idea of what the data looks like at the end. What are the values of the below fields when the price is off due to UOM change:
apologies Kevin for not getting back to you today on this - i will create a BAQ to pull this information and send it over either tonight or tomorrow AM. I appreciate your help on this one!
as a heads up we have decided to use a lookup table with the prices in for each raw material (not ideal when the costs are in the system already but its what works for our business), but the value being written to the quote is still rounding by the UOM value… again will get the details for the fields you require sent over either tonight or tomorrow
@tonyb1986, Why not use proper price lists in the system to drive pricing?
You should be able to target based on proper UOM conversion within Price Lists (this is why they exist). As for your configuration product you can create a Configurator User Defined pricing tool to lookup and set pricing for elements within the configured product as well if needed.
This will lookup price of configured base product and options as well against customer, groups & shiptos. Sample UD PriceLookup (written a few years ago to provide future order dated pricing lookups note: does not handle price breaks):
decimal returnPrice = 0;
string msg = String.Empty;
string ShipToID = ""; // For common code core needing normalization between company division scenarios.
string sStartWithChar = (Context.CompanyID == "EZCUST" ? "C" : "K");
string sUOM = (PartNum.StartsWith(sStartWithChar, true, null) ? "EAC" : "EA");
try
{
switch(Context.Entity)
{
case "OrderDtl":
ShipToID=(string)(Db.OrderHed
.Where(oh => oh.Company == Context.CompanyID && oh.OrderNum == Context.OrderNumber)
.Select(oh => oh.ShipToNum).FirstOrDefault() ?? "");
break;
case "QuoteDtl":
ShipToID=(string)(Db.QuoteHed
.Where(qh => qh.Company == Context.CompanyID && qh.QuoteNum == Context.QuoteNumber)
.Select(qh => qh.ShipToNum).FirstOrDefault() ?? "");
break;
case "PcStatus":
ShipToID="";
break;
};
// NEW : Find appropriate ListCodes for pricing based on date!
List<string> ListCodes =
(((from cust in Db.Customer
where cust.CustID == Customer && cust.Company == Context.CompanyID
join cpl in Db.CustomerPriceLst on new {cust.CustNum, STID=ShipToID} equals new {cpl.CustNum, STID=cpl.ShipToNum} into cpls
from cpl in cpls
where cpl.Company == Context.CompanyID
join pls in Db.PriceLst on cpl.ListCode equals pls.ListCode
where (pls.StartDate <= PricingDate && pls.EndDate >= PricingDate) || (pls.StartDate <= PricingDate && pls.EndDate == null)
select new
{
ListCode =(string)cpl.ListCode, Seq=(cpl.SeqNum)
}))
.Concat(
(from cust in Db.Customer
where cust.CustID == Customer && cust.Company == Context.CompanyID
join cpg in Db.CustGrupPriceLst on cust.GroupCode equals cpg.GroupCode into cpgs
from cpl in cpgs
where cpl.Company == Context.CompanyID
join pls in Db.PriceLst on cpl.ListCode equals pls.ListCode
where (pls.StartDate <= PricingDate && pls.EndDate >= PricingDate) || (pls.StartDate <= PricingDate && pls.EndDate == null)
select new
{
ListCode =(string)cpl.ListCode, Seq=(100+cpl.SeqNum)
})))
.OrderBy(r=>r.Seq)
.Select(r =>(string)r.ListCode).ToList();
var partPriceRecords = ListCodes.Join((from pl in Db.PriceLstParts
where pl.PartNum == PartNum && ListCodes.Contains(pl.ListCode)
select new { Price = pl.BasePrice, ListCode = pl.ListCode, PartNum = pl.PartNum }),
lc=>lc.ToUpper(),
pl=>pl.ListCode.ToUpper(),
(lc,pl)=> new {Price=pl.Price,PartNum=pl.PartNum,ListCode=pl.ListCode});
decimal dPrice = 0m;
if (partPriceRecords.Count() > 0)
{
dPrice = partPriceRecords.Select(r => r.Price).ToList().DefaultIfEmpty(0m).FirstOrDefault();
}
string ListCode = partPriceRecords.Select(r => r.ListCode).ToList().DefaultIfEmpty("Not found").FirstOrDefault();
msg = "\nCompany: "+Context.CompanyID+"'s Price List: " + ListCode + " used for customer: " + Customer + ((ShipToID!="")?"; ShipTo: " + ShipToID:"") + " for PartNum: " + PartNum + " giving price of: $" + dPrice.ToString() + " for date: " + PricingDate.ToShortDateString();
if(DebugLogToDisk) DiskLogMessage(msg, fileName, serverName, dbName);
returnPrice = dPrice;
}
catch (Exception ex)
{
DiskLogMessage(ex.Message + " in PriceLookup; Check if part: '" + PartNum + "' UOM: '" + sUOM + "' is valid.", fileName, serverName, dbName);
throw new Ice.BLException(ex.Message + " in PriceLookup\n\n Check if part: '" + PartNum + "' UOM: '" + sUOM + "' is valid.");
}
return returnPrice;
the price i am expecting to see written to the quote unit price field is 63.05 as shown in the image - the UOM conversion is whatever 1/1.19 is (M2 conversion and the UOM i am asking the configurator to set)
we have looked at price lists and tbh its probably something for the future, but where we are in terms of our ERP setup, we simply are not there yet, there has been a lot of working outside / around the system because of the lack of understanding of how the system needs to work vs how we work - myself and a couple of colleagues have the lovely task of driving that culture change and driving the changes needed to make the system work for us, not the other way round!!!
ill be brutally honest with you, we have been live for 3 years now, and the implementaton was awful and to this day very buggy and did not flow well at all… previous management of the time has since moved on and there is now myself and a colleague going through and fixing the system, this small part of it is part of a much bigger plan, however the buy in from the departments is already better as we are involving them with decision making rather than simply going this is what you have now work with it!
now if i can just get that configuration price to write to the unit price on the quote / order lol ill be sorted with this part!
Using Lookup tables is not a terrible idea as it reduces the need to change the code every time you need to fix something.
You could even write a function and trigger it after the configurator run to update the cost with same calculations if you don’t want to mess with configurator and triggering a MRP/Reconfigure challenge.
the method i have for getting the price is working flawlessly for us and the lookup table is the method we went for, however i need the unit price to be set as the configurator price, not the price it is adjusting based on the UOM value
as you can see in this image the unit price is different from the configurator price, but the price i want to be the unit price is the configurator price.
the difference is being caused by the UOM being set in the order.