I killed a label tree & a BPM question

What do you do on a 3 day weekend? Apparently, I killed a label tree…

With some pointers from epiUser.Help and @amurdock, I managed to get Bartender installed, setup and semi-functional. Still a work in progress, but happy with the status thus far.

I’ve managed to get correct labels, depending on PurchaseType, to print automatically when a receipt line is marked as received. Still, need to figure out a few things before implementing this is production, but it’s a start!

BPM Question
Does anyone have any tricks/ideas/code snippets to find the next operation on a job? Meaning if a SubContracting operation is received, I want to display the next operation, assuming the SubCon op isn’t marked as final.

5 Likes

Great job! You are well on your way.

Does your job have operations within an operation, or said different sub assembly operations that need to be evaluated?

**Josh Owings **| JR Automation

ERP Applications Manager

O: +1
(864) 397-9193 | C: +1 (864) 884-6587

This situation is relatively simple, I know there are more complicated situations I’ll need to program for as well, but small steps first.

The structure of the job looks like this:

  • Op 10 - Cut
  • Op 20 - Machine
  • Op 30 - OV Plating (subcontracting on PO)
  • Op 40 - Assembly

When the PO related to Op 30 is received, I need to be able to find the next Op (40) and print that on the label.

Two thoughts come to mind;

  1. Find a programmatical way to find the next op; loop through the possible options CurrentOp +1, until a match is found.
  2. Find a “NextOp” field in the database, that I’m not aware of, and yes I hunted a bit. I would think the scheduling engine & work queues would need that data.

Any help would be much appreciated.

I’ll have to dig around, I recall building a baq report to print a move ticket that printed out the next operation. It’s a relatively straight forward query.

1 Like

We done this and utilised MTL Tags Report.

I use a setter in the BPM work flow to find the next op number for example:

(from row in Db.JobOper
where row.Company == ttRcvDtlRow.Company
&& row.JobNum == ttRcvDtlRow.JobNum
&& row.AssemblySeq == ttRcvDtlRow.AssemblySeq
&& row.OprSeq > ttRcvDtlRow.JobSeq
select row.OprSeq). FirstOrDefault()

Then push that into the report parameters.

I’m sure we modified the data definition here also to bind the MtlTags To Job Oper so we could extract the next operations op comments.

WIP%20Tags

Hi @nhutchins,
not sure if there is a ‘NextOp’ filed within any BO, but my conventional programmatic way to find next operation is to do foreach loop within your table, add condition to exclude any operation seq. smaller than your tt JobOper.Oprseq., then compare each matched records to variable (declared to start with zero) with another condition to update it only if Oprseq_iterator value is smaller than the saved variable value, and that is it, i remember some one asked about finding the final operation within JobOper table, and i have posted the code, cant find it now, but it is the same logical principle.

your code will give you the first record found, not necessarily the Next operation in sequence.
image

Hi Al,

Indeed it will but the row above filters out all preceding operations prior to the current op being receipted in :wink: row.OprSeq > ttRcvDtlRow.JobSeq

i can see that, and that is why the code will call any operation from the rest, unless your routing has only one record after the tt current operation which is not always the case

Indeed you are right but the FirstOfDefault statement after this selects the first Record returned.

On another note its a small world. I know a few guys from your company from a previous life :slight_smile:

with regards to the code, if you use foreach loop instead as i explained to Norman, it will get the right records in all cases

with regard to the last sentences, sorry, i am not following,

You could retrieve the results of the query into an array, then loop through the contents of the array, find your current op, then the next op (if exists) would be index + 1.

2 Likes

i would like to see the code of assigning selected Epicor Db.Table.Filed to a defined array withing the BPM class, i have tried before with no luck, however could you explain what do you mean by indexing by +1, will it work when gap between operation sequence is more than 1

Yes, because the index refers to the array and its contents, not the job sequence.
I’ll see if I can dig up some code where I did that. Stand by.

var ttLaborDtlR = ttLaborDtl.FirstOrDefault(r=>r.Added() || r.Updated());

if( ttLaborDtlR != null )
{
  string job = (string)ttLaborDtlR.JobNum;
  int op = (int)ttLaborDtlR.OprSeq;
  int nextOp = 0;
  int ass = (int)ttLaborDtlR.AssemblySeq;

  //Get an ascending list of job operations
  int[] jobOps = (
    from j in Db.JobOper.With(LockHint.NoLock)
    where j.Company == Session.CompanyID &&
          j.JobNum == job &&
          j.AssemblySeq == ass
    orderby j.OprSeq
    select j.OprSeq).ToArray();    

  for( int i = 0; i < jobOps.Count(); i ++ )  
  {
    if( jobOps[i] == op )
    {
      int nextAvail = i + 1;
      
      if( nextAvail < jobOps.Count() ) //Check to see if the next index is real
        nextOp = jobOps[nextAvail];        
    }      
  }
  
  //Set the next operations 'PrevOpComp' to true
  foreach(var jobs in(
    from jo in Db.JobOper.With(LockHint.UpdLock)
    where jo.Company == Session.CompanyID && 
          jo.JobNum == job &&
          jo.AssemblySeq == ass &&
          jo.OprSeq == nextOp
    select new {jo}))
  using( var scope = IceDataContext.CreateDefaultTransactionScope() )
  {
    if( jobs.jo != null )
      jobs.jo["PrevOpComp_c"] = true;    

    scope.Complete();    
  }
}
2 Likes

Thanks @hmwillett! I’ll give this code a shoot, when/if I ever get a free moment…

1 Like

Good morning @nhutchins,
many thanks to @hmwillett i found what i needed in terms of using Array structure within Epicor,

added this command to your code @ridgea if you interested,

int iNextAvailabJobOperOprSeq = 0;
var ttRcvDtl_xRow = (from ttRcvDtl_Row in ttRcvDtl
where ttRcvDtl_Row.Company == Session.CompanyID
select ttRcvDtl_Row).FirstOrDefault();
if(ttRcvDtl_xRow != null)
{
int[] list = (from JobOper_Row in Db.JobOper
where JobOper_Row.Company == ttRcvDtl_xRow.Company
&& JobOper_Row.JobNum == ttRcvDtl_xRow.JobNum
&& JobOper_Row.AssemblySeq == ttRcvDtl_xRow.AssemblySeq
&& JobOper_Row.OprSeq > ttRcvDtl_xRow.JobSeq 
select JobOper_Row.OprSeq).ToArray();

iNextAvailabJobOperOprSeq=list.Min();

PublishInfoMessage("Next Available Job Operation Sequence is:"+iNextAvailabJobOperOprSeq,Ice.Common.BusinessObjectMessageType.Error,Ice.Bpm.InfoMessageDisplayMode.Individual,"BO","BOMethod");
}
1 Like

Nice work @A.Baeisa

This worked perfectly for me! Thank you both @hmwillett & @ridgea!

1 Like