Erp.Contract.BO.Quote.dll Issue in Custom Code

I’m confused though in the original code you reference a
Quote quote
Which suggests there is some “Quote” object type while the WCFImpl would be QuoteImpl (as you’ve shown above)
So what is Quote (object) and where does it come from?

There is a cs file called “Quote” that creates it. The cs file is about 250 lines so I don’t know if you want me to post the whole thing in here…

Is this generated though? How was that file made?

I think I misspoke in my post above. This Quote folder holds all the code relating to creating the quote and adding rows inside the QuoteHed table in SQL.

So you are writing straight to SQL?

QuoteFactory, DataConverter… this looks to be completely custom.

Yes the code is completely custom. The original author of the code had a complete career change from programmer to pastor and the company he works for is no longer supporting it at this time. We were told by the owner that this code was written in a way to where any changes would not be needed besides changing the config files and recompiling the program with new dlls plus any small changes we would want to make to the import services.

So I have my work cut out for me…

Eeeeek - hopefully not writing quotes direct to SQL :confused:

Looking back at some of your previous posts. Can you step thru that function and find the exact source of your trouble? If so, what line?

Yikes! so the reason why that isn’t working is because well… who knows haha but in the Quote.cs there is a definition of HedRow
Your issue will be inthere.

1 Like

Exactly!

Yeah I have been poking through the Quote.cs and the QuoteFactory,cs. The errors on the logger are actually happening in the RolledUpQuoteFactory and another called ConvertRollupServices on the lines are specifically say:

var hed = CreateQuoteHedRow(quote, job);

and

hed[“CheckBox01”] = true;

This is exact error the logger is outputting:

Omni.E10Solutions.Cam.QuoteLibrary.QuoteMapException: Job DCSSHOP091318KB VM failed to map to a Quote. —> System.ArgumentException: Column ‘CheckBox01’ does not belong to table QuoteHed.
at System.Data.DataRow.GetDataColumn(String columnName)
at System.Data.DataRow.set_Item(String columnName, Object value)
at Omni.E10Solutions.Cam.QuoteLibrary.RolledUpQuoteFactory.CreateQuoteHedRow(Quote quote, CamductJob job) in C:\Users\ICastellanos\Desktop\Omni.E10Solutions\Omni.E10Solutions.Cam.QuoteLibrary\Quote\RolledUpQuoteFactory.cs:line 112
at Omni.E10Solutions.Cam.QuoteLibrary.RolledUpQuoteFactory.CreateQuote(CamductJob job) in C:\Users\ICastellanos\Desktop\Omni.E10Solutions\Omni.E10Solutions.Cam.QuoteLibrary\Quote\RolledUpQuoteFactory.cs:line 30
at Omni.E10Solutions.Cam.QuoteLibrary.ConvertRollupService.Convert(CamductJobCollection jobs) in C:\Users\ICastellanos\Desktop\Omni.E10Solutions\Omni.E10Solutions.Cam.QuoteLibrary\Services\ConvertRollupService.cs:line 30
— End of inner exception stack trace —

Need def for the QuoteClass - however… i wouldnt use:
image

I use a QuoteDataSet and the BO to get a new Quote as I mentioned earlier

There are instances of code like this and similar to this all over. Should be fun.

I suppose there is a possibility he had all that encapsulated. For example, perhaps Quote is just a wrapper for a QuoteBO.

It is possible the NewHedRow() does everything I mentioned. You’d just need to peek at the Quote class

I might as well post the whole class at this point. You guys might see something that I don’t.

Also the code is not directly writing to SQL. Please don’t get mad at the wall below…

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Erp.BO;
using Ice.BO;

namespace Omni.E10Solutions.Cam.QuoteLibrary
{
    class Quote : IQuote
    {
        public Quote(CamductJob job)
        {
            Job = job;

            QuoteDataSet = new UpdExtQuoteDataSet();
            QuoteAsmDataSet = new UpdExtQuoteAsmDataSet();

            AsmReferences = new Dictionary<string, UpdExtQuoteAsmDataSet.QuoteAsmRow>();
            MtlReferences = new Dictionary<string, ICollection<UpdExtQuoteAsmDataSet.QuoteMtlRow>>();
            OprReferences = new Dictionary<string, ICollection<UpdExtQuoteAsmDataSet.QuoteOprRow>>();
        }

        public CamductJob Job { get; protected set; }

        private UpdExtQuoteDataSet QuoteDataSet;
        private UpdExtQuoteAsmDataSet QuoteAsmDataSet;

        private Dictionary<string, UpdExtQuoteAsmDataSet.QuoteAsmRow> AsmReferences;
        private Dictionary<string, ICollection<UpdExtQuoteAsmDataSet.QuoteMtlRow>> MtlReferences;
        private Dictionary<string, ICollection<UpdExtQuoteAsmDataSet.QuoteOprRow>> OprReferences;

        public UpdExtQuoteDataSet.QuoteHedRow NewHedRow()
        {
            return this.QuoteDataSet.QuoteHed.NewQuoteHedRow();
        }

        public UpdExtQuoteDataSet.QuoteDtlRow NewDtlRow()
        {
            return this.QuoteDataSet.QuoteDtl.NewQuoteDtlRow();
        }

        public UpdExtQuoteAsmDataSet.QuoteAsmRow NewAsmRow()
        {
            return this.QuoteAsmDataSet.QuoteAsm.NewQuoteAsmRow();
        }

        public UpdExtQuoteAsmDataSet.QuoteOprRow NewOprRow()
        {
            return this.QuoteAsmDataSet.QuoteOpr.NewQuoteOprRow();
        }

        public UpdExtQuoteAsmDataSet.QuoteMtlRow NewMtlRow()
        {
            return this.QuoteAsmDataSet.QuoteMtl.NewQuoteMtlRow();
        }

        public void AddHedRow(UpdExtQuoteDataSet.QuoteHedRow row)
        {
            this.QuoteDataSet.QuoteHed.AddQuoteHedRow(row);
        }

        public void AddDtlRow(UpdExtQuoteDataSet.QuoteDtlRow row)
        {
            this.QuoteDataSet.QuoteDtl.AddQuoteDtlRow(row);
        }

        public void AddAsmRow(string key, UpdExtQuoteAsmDataSet.QuoteAsmRow row)
        {
            this.QuoteAsmDataSet.QuoteAsm.AddQuoteAsmRow(row);
            this.AsmReferences.Add(key, row);
        }

        public void AddOprRow(string key, UpdExtQuoteAsmDataSet.QuoteOprRow row)
        {
            QuoteAsmDataSet.QuoteOpr.AddQuoteOprRow(row);

            // add the row to the references key.
            ICollection<UpdExtQuoteAsmDataSet.QuoteOprRow> oprRows;
            if (OprReferences.TryGetValue(key, out oprRows))
            {
                oprRows.Add(row);
                return;
            }

            // or create a new key-collection.
            oprRows = new List<UpdExtQuoteAsmDataSet.QuoteOprRow>() { row };
            OprReferences.Add(key,  oprRows);     
        }

        public void AddMtlRow(string key, UpdExtQuoteAsmDataSet.QuoteMtlRow row)
        {
            QuoteAsmDataSet.QuoteMtl.AddQuoteMtlRow(row);

            // add the row to the references key.
            ICollection<UpdExtQuoteAsmDataSet.QuoteMtlRow> mtlRows;
            if (MtlReferences.TryGetValue(key, out mtlRows))
            {
                mtlRows.Add(row);
                return;
            }

            // or create a new key-collection.
            mtlRows = new List<UpdExtQuoteAsmDataSet.QuoteMtlRow>() { row };
            MtlReferences.Add(key, mtlRows);
        }

        public UpdExtQuoteDataSet GetQuoteDataSet()
        {
            return QuoteDataSet;
        }

        public UpdExtQuoteAsmDataSet GetQuoteAsmDataSet()
        {
            return QuoteAsmDataSet;
        }

        public IEnumerable<UpdExtQuoteDataSet.QuoteDtlRow> GetDtls()
        {
            return QuoteDataSet.QuoteDtl.Rows.Cast<UpdExtQuoteDataSet.QuoteDtlRow>();
        }

        public IEnumerable<UpdExtQuoteAsmDataSet.QuoteMtlRow> GetMtls(string reference)
        {
            ICollection<UpdExtQuoteAsmDataSet.QuoteMtlRow> mtlRows;
            if (MtlReferences.TryGetValue(reference, out mtlRows))
            {
                return mtlRows;
            }

            return new List<UpdExtQuoteAsmDataSet.QuoteMtlRow>();
        }

        public IEnumerable<UpdExtQuoteAsmDataSet.QuoteOprRow> GetOprs(string reference)
        {
            ICollection<UpdExtQuoteAsmDataSet.QuoteOprRow> oprRows;
            if (OprReferences.TryGetValue(reference, out oprRows))
            {
                return oprRows;
            }

            return new List<UpdExtQuoteAsmDataSet.QuoteOprRow>();
        }

        UpdExtQuoteDataSet.QuoteHedRow _cachedFirstHed = null;
        public int GetQuoteNum()
        {
            var hed = _cachedFirstHed ?? this.QuoteDataSet.QuoteHed.Rows
                .Cast<UpdExtQuoteDataSet.QuoteHedRow>()
                .FirstOrDefault();

            if (hed != null)
            {
                return hed.QuoteNum;
            }

            return 0;
        }

        public void SetAsmLinks(string referenceKey, int quoteNum, int quoteLine)
        {
            // get asm, set ids.
            UpdExtQuoteAsmDataSet.QuoteAsmRow asm;
            AsmReferences.TryGetValue(referenceKey, out asm);
            asm.QuoteNum = quoteNum;
            asm.QuoteLine = quoteLine;

            // get oprs, iterate, set ids on each.
            ICollection<UpdExtQuoteAsmDataSet.QuoteOprRow> oprs;
            OprReferences.TryGetValue(referenceKey, out oprs);
            foreach (var opr in oprs ?? new List<UpdExtQuoteAsmDataSet.QuoteOprRow>())
            {
                opr.QuoteNum = quoteNum;
                opr.QuoteLine = quoteLine;
            }

            // get mtls, iterate, set ids on each.
            ICollection<UpdExtQuoteAsmDataSet.QuoteMtlRow> mtls;
            MtlReferences.TryGetValue(referenceKey, out mtls);
            foreach (var mtl in mtls ?? new List<UpdExtQuoteAsmDataSet.QuoteMtlRow>())
            {
                mtl.QuoteNum = quoteNum;
                mtl.QuoteLine = quoteLine;
            }
        }

        public void MakeUDCompatible(UdService udService)
        {
            udService.PrepDataSet(QuoteDataSet);
        }

        public void MarkQuoteAsImported()
        {
            this.QuoteDataSet.QuoteHed.Rows[0]["CheckBox02"] = true;
        }

        public void MarkLinesEngineered()
        {
            foreach (var dtl in this.GetDtls())
            {
                dtl.ReadyToQuote = true;
                dtl.Engineer = true;
            }
        }

        public void MarkMtlsAsRelatedToFirstOperation()
        {
            var allMtls = MtlReferences.SelectMany(s => s.Value);
            foreach (var mtl in allMtls)
            {
                mtl.RelatedOperation = 10;
            }
        }

        public UpdExtUD03DataSet GetReportingDataSet()
        {
            var ds = new UpdExtUD03DataSet();
            foreach (var line in this.Job.OFile)
            {
                var row = ds.UD03.NewUD03Row();

                /* From the email from Quartz:
                Key1 = Job File Name
                Key2 = Entry
                ShortChar01 = Epicor Group
                Character01 = Item Alias
                Character02 = Item Description + Size - End 1 + Size - End 2 + Size - End 3 + Size - End 4
                Number01 = Qty
                Number02 = Base Weight
                ShortChar02 = Insulation Material
                Number03 = Insulation Thickness
                Number04 = Insulation Area
                Number05 = Wire Gauge
                Number06 = Length
                ShortChar03 = Material
                */

                row.Key1 = this.Job.Plant + "-" + this.Job.Name;
                row.Key2 = line.ItemNoField.GetTextValue();
                row.ShortChar01 = line.EpicorGroupField.GetValue();
                row.Character01 = line.ItemAliasField.GetValue();
                row.Character02 = string.Join(" ", new string[] { line.ItemDescriptionField.GetValue(), line.SizeEnd1Field.GetValue(), line.SizeEnd2Field.GetValue(), line.SizeEnd3Field.GetValue(), line.SizeEnd4Field.GetValue() });
                row.Number01 = line.QtyField.GetValue();
                row.Number02 = line.BaseWeightField.GetValue() ?? 0m;
                row.ShortChar02 = line.InsulationMaterialField.GetValue();
                row.Number03 = line.InsulationThicknessField.GetValue() ?? 0m;
                row.Number04 = line.InsulationAreaField.GetValue() ?? 0m;
                row.Number05 = line.WireGaugeField.GetValue() ?? 0m;
                row.Number06 = line.ItemLengthOrAngleField.GetValue() ?? 0m;
                row.ShortChar03 = line.MaterialField.GetValue();

                row.ShortChar04 = "Quote";
                row.Number07 = this.GetQuoteNum();

                // add the row to the table
                ds.UD03.AddUD03Row(row);
            }

            return ds;
        }
    }
}

I can confirm that your way of just instanciating a row doesnt work. This does though:

using(var bo = Ice.Assemblies.ServiceRenderer.GetService<QuoteSvcContract>())
  {
QuoteTableset qds = new QuoteTableset();
bo.GetNewQuoteHed(ref qds);
var row = qds.QuoteHed[0];
row["CheckBox01"] = true;
}


Note this is in a BPM, so it will be a little different for you as far as getting your BO instance

1 Like

Hmm I wonder what changed form 10.1.600 to 10.2 that would have caused it to no longer work.

Looking at your custom Quote class and comparing it to a decompiled Erp.Contracts.BO.Quote, the object types and methods check out.

The custom NewHedRow() method references this.QuoteDataSet (type: UpdExtQuoteDataSet), gets its QuoteHed object (type: QuoteHedDataTable), and from there calls the NewQuoteHedRow() method (verified to exist in the 10.2.100.0 dll) to return an empty QuoteHedRow (which it does).

I also checked a copy of the same dll from version 10.1.400.0 and confirmed that the types and methods work in the same way. So, this particular behavior shouldn’t change between 10.1.400 and 10.2.200.

Unfortunately, the dlls don’t contain the UD fields as objects. To do so would mean that they would have to recompile every time a UD field was added or changed - which is an understandably insurmountable task for the Epicor devs on any kind of scale. However, your stack trace from the logger is telling you that there was an error in the CreateQuoteHedRow method related to the “CheckBox01” column.

This also means that the NewHedRow() method has to be working or we would have never reached the subsequent code attempting to assign a value to QuoteHed.CheckBox01.

So… tldr: your error explicitly states that there is no “CheckBox01” column on the QuoteHed table. Have you actually verified that the column exists through SQL and/or through the User Defined Column Maintenance? Your screenshot and and original description keep referencing OrderHed.CheckBox01, which may be where the data ultimately ends up, but the Quote BO in the code is pointing at the QuoteHed table.

1 Like

The column exists in the QuoteHed_UD table on all environments we have.

I have 3 environments currently running a 10.1.400.38, 10.1.600.23, and 10.2.200.13.

This is in all my 3 environments.

Table/Data Model are all in sync as well.

I think you might have grabbed the wrong sceenshot by accident - that’s the OrderHed table again. Your code looks like it should work, but I’d really like to verify that the QuoteHed table has a CheckBox01 column because that’s what the code and error reference. Can you show us a screenshot of the QuoteHed_UD columns?

Been staring at code too long today…

Here you go.

image