Update Ship Head UD Field

I am trying to use a UD column of type boolean to track whether or not I’ve sent a shipment notification for each PackNum. I send the notification using a Standard Data Directive and I’m trying to update this field after the email is sent. Everytime I try to fire an Update or UpdateMaster through the BO, I somehow end up deleting the existing PackNum and creating a new one whose UD column is set to true. Is there a trick to messing with the ShipHead table?

Hi Dan,
If you can supply your data directive I can take a look.
Thanks
Mark

var packInfo = (from p in ttShipHead
               where p.RowMod == "U"
               select p).FirstOrDefault();

if (packInfo != null)
{
  var packNum = 0;
  var trackingNumber = "";
  var shipMethod = "";
  var shipMethodDesc = "";
  var trackUrl = "";

  packNum = packInfo.PackNum;
  trackingNumber = packInfo.TrackingNumber;
  
  shipMethodDesc = (from sv in Db.ShipVia
                        where sv.ShipViaCode == packInfo.ShipViaCode
                        select sv.Description).FirstOrDefault() ?? String.Empty;
  
  if (shipMethodDesc.Contains("UPS "))
  {
    trackUrl = "https://www.ups.com/track?tracknum=" + trackingNumber;
  }
  else if (shipMethodDesc.Contains("FEDEX "))
  {
    trackUrl = "https://www.fedex.com/fedextrack/?trknbr=" + trackingNumber;
  }
  
  var mailer = this.GetMailer(async:false);
  var message = new Ice.Mail.SmtpMail();
  var subject = "";
  var body = "";
  var bodyShipDetails = "";
  var msg = "";
  int orderNum = 0;
  var poNum = "";
  int custNum = 0;
  int BTCustNum = 0;
  int prcCon = 0;
  var attnName = "";
  var attnEmail = "";
  var firstLetter = "";
  var otherLetters = "";
  var formattedName = "";
  var formattedGreeting = "";
  DateTime? shipBy = DateTime.Today;
  
  var cssBody = "background-color: #FFFFFE; margin: 0px; padding: 5px; font-family: Arial, Helvetica, sans-serif";
  var cssAButton = "text-decoration: none; color: white; font-weight: bold; margin: 0 auto;";
  var cssTdMain = "padding: 10px; max-width: 500px;";
  var cssTdDetails = "padding: 4px; max-width: 300px;";
  var cssThDetails = "padding: 4px;";
  var cssTdButton = "background-color: dodgerblue; padding: 14px; text-align: center;";
  var cssTableLine = "border-bottom: 1px solid darkgrey; height: 1px; padding: 0px; margin: 0px; width: 80%;";
  var cssTableOuter = "width: 100%; max-width: 500px; margin: 0px; padding: 0px; margin-left: auto; margin-right: auto;";
  var cssTableButton = "width: auto; margin: 0px; padding: 3px;";
  var cssTdFooter = "font-size: 80%;";
  var cssImg = "margin: 2px;";
  var cssH = "color: #333333; padding-top: 0px;";
  
  var ShipmentDetails = (from s in Db.ShipDtl
                         where s.PackNum == packNum
                         select s);
                         
  
  if (ShipmentDetails.Any())
  {
    bodyShipDetails += "<tr><th style='" + cssThDetails + "'>QTY</th><th style='" + cssThDetails + " text-align: left;'>ITEM</th><th style='" + cssThDetails + " text-align: left;'>PART #</th></tr>";
    foreach (var eachDtl in ShipmentDetails)
    {
      decimal shipQty = eachDtl.OurJobShipQty + eachDtl.OurInventoryShipQty;
      decimal rndShipQty = 0;
      if (shipQty % 1 == 0)
      {
        rndShipQty = Math.Round(shipQty, 0);
      }
      else
      {
        rndShipQty = Math.Round(shipQty, 2);
      }
      
      var desc = "";
      if  (!String.IsNullOrEmpty(eachDtl.LineDesc))
      {
        if (eachDtl.LineDesc.Length <=30)
        {
          desc = eachDtl.LineDesc;
        }
        else
        {
          desc = eachDtl.LineDesc.Substring(0, 27) + "...";
        }
      }
      
      bodyShipDetails += "<tr>";
      bodyShipDetails += "<td style='" + cssTdDetails + " text-align: center;'>";
      bodyShipDetails += rndShipQty.ToString() + "</td><td style='" + cssTdDetails + "'>" + desc + "</td><td style='" + cssTdDetails + "'>" + eachDtl.PartNum + "</td>";
      bodyShipDetails += "</tr>";
      
      orderNum = eachDtl.OrderNum;
    }
  }
  
  var orderInfo = (from o in Db.OrderHed
                   where o.OrderNum == orderNum
                   select o).FirstOrDefault();
  
  if (orderInfo != null)
  {
    poNum = orderInfo.PONum;
    shipBy = orderInfo.RequestDate;
    custNum = orderInfo.CustNum;
    BTCustNum = orderInfo.BTCustNum;
    prcCon = orderInfo.PrcConNum;
    
    if (Preference == "ORDERATTN")
    {
      var attn = (from cc in Db.CustCnt
                  where cc.CustNum == custNum
                  && cc.ConNum == prcCon
                  select cc).FirstOrDefault();
      
      if (attn != null)
      {
        attnName = attn.Name.Split(' ').FirstOrDefault();
        firstLetter = attnName.Substring(0, 1).ToUpper();
        otherLetters = attnName.Substring(1, attnName.Length - 1).ToLower();
        formattedName = firstLetter + otherLetters;
        attnEmail = attn.EMailAddress;
        
        if (!String.IsNullOrEmpty(formattedName) && formattedName != "(INVOICES)")
        {
          formattedGreeting = formattedName + ", y";
        }
        else
        {
          formattedGreeting = "Y";
        }
      }
    }
    else if (!String.IsNullOrEmpty(CustomerSpecifiedEmail))
    {
      attnEmail = CustomerSpecifiedEmail;
      formattedGreeting = "Y";
    }
  }
  
  if (attnEmail.Contains('@'))
  {
    var htmlLine = "<tr><td align='center' style='" + cssTdMain + "'><hr style='width: 80%; background-color: darkgrey; color: darkgrey; height: 1px; border-width: 0px; margin: 0px;'></td></tr>";
    
    if (shipMethodDesc.Contains("PICKUP"))
    {
      msg = formattedGreeting + "our items are ready to be picked up!"; 
      subject = "Your order " + orderNum.ToString() + " from Vanair is ready for pickup!";    
    }
    else
    {
      if (shipBy > DateTime.Today)
      {
        msg = formattedGreeting + "our items are on their way ahead of schedule!";
      }
      else if (shipBy == DateTime.Today)
      {
        msg = formattedGreeting + "our items are on their way right on time!";
      }
      else
      {
        msg = formattedGreeting + "our items are on their way!";
      }
      
      subject = "Your order " + orderNum.ToString() + " from Vanair has shipped!";
    }
    
    body += "<body style='" + cssBody + "'>";
    body += "<table style='width: 100%;'>";
    body += "<tbody>";
    body += "<tr>";
    body += "<td align='center'>";
    body += "<table style='" + cssTableOuter + "'>";
    body += "<tbody>";
    body += "<tr>";
    body += "<td align='center' style='" + cssTdMain + "'>";
    body += "<a href='http://www.vanair.com'>";
    body += "<img src='https://www.autoecn.com/vanair/images/vanair-logo-black-300.png'/>";
    body += "</a>";
    body += "</td>";
    body += "</tr>";
    body += "<tr>";
    body += "<td align='center' style='" + cssTdMain + "'>";
    body += "<h3 style='" + cssH + "'>";
    body += msg;
    body += "</h3>";
    body += "</td>";
    body += "</tr>";
    
    if (!String.IsNullOrEmpty(trackUrl))
    {    
      body += "<tr>";
      body += "<td align='center' style='" + cssTdMain + "'>";
      body += "<table style='" + cssTableButton + "'>";
      body += "<tbody>";
      body += "<tr>";
      body += "<td align='center' style='" + cssTdButton + "'>";
      body += "<a href='" + trackUrl + "' style=' " + cssAButton + "'><strong>Track My Shipment</strong></a>";
      body += "</td>";
      body += "</tr>";
      body += "</tbody>";
      body += "</table>";
      body += "</td>";
      body += "</tr>";
    }
    
    body += htmlLine;
    body += "<tr>";
    body += "<td align='center' style='" + cssTdMain + "'>";
    body += "<h2 style='" + cssH + "'>";
    body += "Shipment Details";
    body += "</h2>";
    body += "<table>";
    body += "<tbody>";
    body += bodyShipDetails;
    body += "</tbody>";
    body += "</table>";
    body += "</td>";
    body += "</tr>";
    body += htmlLine;
    body += "<tr>";
    body += "<td align='center' style='" + cssTdMain + "'>";
    body += "<h2 style='" + cssH + "'>Order Details</h2>";
    body += "<table>";
    body += "<tbody>";
    body += "<tr>";
    body += "<td style='" + cssTdDetails + "'><b>ORDER NUMBER</b></td>";
    body += "<td style='" + cssTdDetails + "'>" + orderNum.ToString() + "</td>";
    body += "</td>";
    body += "</tr>";
    if (!String.IsNullOrEmpty(poNum))
    {
      body += "<tr>";
      body += "<td style='" + cssTdDetails + "'><b>PURCHASE ORDER</b></td>";
      body += "<td style='" + cssTdDetails + "'>" + poNum + "</td>";
      body += "</td>";
      body += "</tr>";
    }
    
    if (!String.IsNullOrEmpty(shipMethodDesc))
    {
      body += "<tr>";
      body += "<td style='" + cssTdDetails + "'><b>SHIPPING METHOD</b></td>";
      body += "<td style='" + cssTdDetails + "'>" + shipMethodDesc.ToUpper() + "</td>";
      body += "</td>";
      body += "</tr>";
    }
    
    if (!String.IsNullOrEmpty(trackingNumber))
    {
      body += "<tr>";
      body += "<td style='" + cssTdDetails + "'><b>TRACKING NUMBER</b></td>";
      body += "<td style='" + cssTdDetails + "'>" + trackingNumber + "</td>";
      body += "</td>";
      body += "</tr>";
    }
      body += "</tbody>";
      body += "</table>";
      body += "<p><i>Don't forget to <a href='https://vanair.com/support/registration.html'>register</a> your products for their warranty!</i></p>";
      body += "<p><i>Have a question? <a href='https://www.vanair.com/contact.html'>Contact Us!</a></i></p>";
      body += "</td>";
      body += "</tr>";
  
    
    body += htmlLine;
    body += "<tr>";
    body += "<td align='center' style='" + cssTdMain + cssTdFooter + "'><a href='https://tue21.mapyourshow.com/8_0/exhibitor/exhibitor-details.cfm?exhid=1025887'><img src='https://www.autoecn.com/vanair/images/icuee.png'/></a>";
    body += "</td>";
    body += "</tr>"; 
    body += "<tr>";
    body += "<td align='center' style='" + cssTdMain + "'><table><tbody><tr>";
    body += "<td align='center' style='" + cssTdMain + "'><a href='https://www.facebook.com/VanairManufacturing?fref=ts'><img style='" + cssImg + "' src='https://www.autoecn.com/vanair/images/icon_fb2.png'/></a></td>";
    body += "<td align='center' style='" + cssTdMain + "'><a href='https://www.linkedin.com/company/vanair'><img style='" + cssImg + "' src='https://www.autoecn.com/vanair/images/icon_li.png'/></a></td>";
    body += "<td align='center' style='" + cssTdMain + "'><a href='https://twitter.com/Vanair_Mfg'><img style='" + cssImg + "' src='https://www.autoecn.com/vanair/images/icon_tw.png'/></td>";
    body += "<td align='center' style='" + cssTdMain + "'><a href='https://www.youtube.com/user/VanairManufacturing'><img style='" + cssImg + "' src='https://www.autoecn.com/vanair/images/icon_yt.png'/></td>";
    body += "</tr></tbody></table></td>";
    body += "</tr>";
    body += "<tr>";
    body += "<td align='center' style='" + cssTdMain + cssTdFooter + "'>© " + DateTime.Today.Year + " Vanair Manufacturing, Inc. • 10896 West 300 North • Michigan City • IN 46360<br>800-526-8817 • 219-879-5100 • Service: 844-826-7378 • Fax: 219-879-5800";
    body += "</td>";
    body += "</tr>"; 
    body += "</tbody> "; 
    body += "</table>";
    body += "</td>";
    body += "</tr>";
    body += "</tbody>";
    body += "</table>";
    body += "</body>";
  

    message.SetFrom("Vanair <sales@vanair.com>");
    message.SetTo(attnEmail);
    message.SetBcc("dan.ramirez@vanair.com");
    message.SetSubject(subject);
    message.SetBody(body);
    
    message.IsBodyHtml = true;
    mailer.Send(message);
    
    Erp.Contracts.CustShipSvcContract boCustShip = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.CustShipSvcContract>(Db);
    Erp.Tablesets.CustShipTableset dsCustShip = new Erp.Tablesets.CustShipTableset();
    
    dsCustShip = boCustShip.GetByID(packNum);
    
    var UpdateShipHead = (from sh in dsCustShip.ShipHead
                          where sh.PackNum == packNum
                          select sh).FirstOrDefault();
    
    if (UpdateShipHead != null)
    {
      string opReleaseMessage;
      string opCompleteMessage;
      string opShippingMessage;
      string opLotMessage;
      string opInventoryMessage;
      string opLockQtyMessage;
      string opAllocationMessage;    
      string opPartListNeedsAttr;
      string opLotListNeedsAttr;
      string shipCreditMsg;
      bool cError = false;
      bool compError = false;
      string msgg;
      string opPostUpdMessage;
      bool updateComplete = false;
      bool checkComplianceError = false;
      bool changeStatusError = false;
      bool checkShipDtlAgain = false;      
      UpdateShipHead["TrackingEmailSent_c"] = true;
      UpdateShipHead.RowMod = "U";
      boCustShip.Update(ref dsCustShip);
//      , false, false, false, false, false, false, false, packNum, BTCustNum, out opReleaseMessage, out opCompleteMessage, out opShippingMessage, out opLotMessage, out opInventoryMessage, out opLockQtyMessage, out opAllocationMessage, out opPartListNeedsAttr, out opLotListNeedsAttr, out shipCreditMsg, out cError, out compError, out msgg, out opPostUpdMessage, out updateComplete, out checkComplianceError, out changeStatusError, out checkShipDtlAgain);
    }
  }
}

Hi Dan,

Sorry - I cant see anything wrong with what you have done. I know when adding rows I have had to use the buffercopy to keeps things right - is it worth givinbg this a go:

var UpdateShipHead = (from sh in dsCustShip.ShipHead
                          where sh.PackNum == packNum
                          select sh).FirstOrDefault();
    
	var shipHead = tsCustShip.ShipHead.FirstOrDefault();
          
    var bShipHead = new ShipHeadRow();
          
    BufferCopy.Copy(shipHead, bShipHead);
	
	
    if (bShipHead != null)
    {
      string opReleaseMessage;
      string opCompleteMessage;
      string opShippingMessage;
      string opLotMessage;
      string opInventoryMessage;
      string opLockQtyMessage;
      string opAllocationMessage;    
      string opPartListNeedsAttr;
      string opLotListNeedsAttr;
      string shipCreditMsg;
      bool cError = false;
      bool compError = false;
      string msgg;
      string opPostUpdMessage;
      bool updateComplete = false;
      bool checkComplianceError = false;
      bool changeStatusError = false;
      bool checkShipDtlAgain = false;      
      bShipHead["TrackingEmailSent_c"] = true;
      bShipHead.RowMod = "U";
      boCustShip.Update(ref dsCustShip);

Thanks. I’m giving it a shot. It doesn’t like the new ShipHeadRow().

Techincally, I shouldn’t be adding a row. I’m just updating an existing one. I was suspicious that it was not letting me because once the ShipHead is marked Shipped, most things (if not all of them) are disabled from being edited. But in the case that it wasn’t allowing me to edit, I would’ve expected it to error out - not proceed and delete that shipment and create a new one haha.

Sorry - I copied the code incorrectly. Can’t promise anything!:

var UpdateShipHead = (from sh in dsCustShip.ShipHead
                          where sh.PackNum == packNum
                          select sh).FirstOrDefault();
              
    var bShipHead = new ShipHeadRow();
          
    BufferCopy.Copy(UpdateShipHead, bShipHead);
	
	
    if (bShipHead != null)
    {
      string opReleaseMessage;
      string opCompleteMessage;
      string opShippingMessage;
      string opLotMessage;
      string opInventoryMessage;
      string opLockQtyMessage;
      string opAllocationMessage;    
      string opPartListNeedsAttr;
      string opLotListNeedsAttr;
      string shipCreditMsg;
      bool cError = false;
      bool compError = false;
      string msgg;
      string opPostUpdMessage;
      bool updateComplete = false;
      bool checkComplianceError = false;
      bool changeStatusError = false;
      bool checkShipDtlAgain = false;      
      bShipHead["TrackingEmailSent_c"] = true;
      bShipHead.RowMod = "U";
      boCustShip.Update(ref dsCustShip);

Some of the ShipHead fields can be updated after it is marked SHIPPED. Experiment with changing the ShipHead.TrackingNumber field in a BPM to see if it does the same (deleting the record).

And one thing to keep in mind if you’re multi-site, is that the ShipHead can only be accessed from within the site it was created.

Still not liking that new ShipHeadRow().

And a side note. You should use a StringBuilder object in place of the above.

edit:

See the following for why:

Wow I never knew this! That would really come into play with the way I’m structuring the body of the email then!! I’m sure this is an extreme example, but I do this often with messages/notes that get created. I’ll start using this methodology. Thanks!

Regarding trying to update the Tracking Number. First, I tried to set the Tracking Number using my existing code (instead of the UD field). I got the same result. Deleted existing row and created new one.
image
However, I am using a standard data directive. I do not get a widget to set fields in that tool - so I am trying to do it by using the BO in custom code. Perhaps it’s too late at this stage to change it?

So I changed to an in-transaction data directive and just used the widget to set the field, it had no problem. However, I can see that field remains read/write in the UI. So I also tried to change one that I know goes to read only… that also let me change it with no problem.

Could it be because I am using a standard data directive?

Yes. A Standard DD fires after the transaction has happened I.E - “Hey, this just happened”. The record the DD is fired from can’t be changed by the widgets (except maybe by code in an Exec Custom Code widget).

An In-Tran DD fires before as in “Hey, this is about to happen. Want to tweak anything before I do it?”

In either case, querying the directives table will show the data as it is currently is. In a Std DD, the table has already been updated. In an In-Tran, the table will still have the data prior to the update.

OK talking this out, then, going back to the original intent…
Is there a better way (or is this still possible but I am goofing something up) to set the UD field I’ve created “TrackingEmailSent_c” to true when the email is sent? If I understand, I want to send the email as a std DD. But that doesn’t seem to lend itself to setting a field in the table we just reacted to.

How do I get the String Builder to work? I tried using System.Text like the tutorial suggested. That isn’t working, though.

Unless you have a really good reason to keep it as a Standard, change your directive that sends the email to an in-transaction, and add in a step that updates the UD field at the same time.

1 Like

A Method Direct (often called BPM’s here) might be the better place.

And to be clear, I didn’t look at your custom code to see how you were trying to update the ShipHead record. the root of why the original is being deleted and then a new record created might be in there.

Search this site for some posts on String Builder

Great observation. At one time, I had fear that if I was processing like 75 emails, it might cause the UI to hang while it fired off emails and I didn’t want it to lag the user. But I don’t think it will be an issue anymore because I am firing it when the Ship Status changes from Any to Shipped, instead of Any to Invoiced. I also had it set to ASYNC which I was told by Epicor not to do so basically the whole point of trying to get it offfline is moot.

Also if you do it as an In-Transaction you can update your UD field with a widget instead of code.

1 Like

Just what I needed - another site to teach me technology. Thanks a lot, @ckrusen! Lol, I get overwhelmed with all the teacher-site/course options…How does everyone here keep up to date on things? Is there any site that you like over the others, and why? Currently, I’m using Udemy and LinkedIn Learning the most, but I’m members of so many I’ve lost count.

I was trying to add the using statement at the top of my code block. I learned today that is not where it goes in a DD! It goes in the Usings and References popup window. Just in case anyone else missed this obvious little caveat.
image

BTW, that String Builder seems to have sped up the email generation considerably. It used to be close to 5 seconds before I’d hear my phone buzz… now it’s like 1-2 seconds. So I would recommend it to anyone who isn’t aware of it.