Jose C Gomez on July 31st, 2015

Note that I am not affiliated with this company , nor have I been compensated for the below statement.

I was looking for a way to spruce up the office. Really I just wanted to break up the monotony and Annie suggested I added a poster or something to the wall. I decided to do a quote but didn’t want to mess with painting it, when I found www.letteringonthecheap.com. It was pretty easy to order online but the best part of working with them is the how to install videos. They talked about installing on walls, prepping the surface, how the letters would arrive and before I knew it, I was ready to add my quote before even receiving the product.

The folks there are nice so if you need vinyl letters for wall (or boats or windows I think they do everything), checkout www.letteringonthecheap.com

2015-07-31

William Asks:

Trying to fire off the ImportEDI demand process from VB.NET with:

  1. backup process checkbox checked
  2. Import folder being \\taf2k8edi1\epicor\edidata\inbound\demand.
  3. Continuous process is false.

This can be accomplished by establishing a session on the VB/C# application and creating an instance of the  ImportEDI process as shown below. After running a trace on Epicor you can see that the EDI Import Process runs 2 main methods.


	Epicor.Mfg.Proc.ImportEDI
	GetNewParameters
	Epicor.Mfg.Proc.ImportEDIDataSet
	7/2/2015 09:28:33:6255008 AM
	67
	
	

GetNewParameters: gets you an new instance of the EDI Process Import Data Set


	Epicor.Mfg.Proc.ImportEDI
	SubmitToAgent
	void
	7/2/2015 09:28:55:7313078 AM
	327
	
		
	
	
	
	
	

SubmitToAgent: schedules the process with the System Task Agent for Execution. This method requires that you fill in the appropriate values within the ImportEDIDataSet as shown on the FULL trace.

The code below is an implementation of calling these two methods in C# from an External application. You requested it in VB.NET but I don’t write VB.NET unless someone is holding a gun against my head… It makes me itchy and I break out in hives… so your homework is to convert the below code into VB.NET. You will need to reference the following DLL’s available within the Epicor Client Folder

  • Epicor.Mfg.Core.BLConnectionPool.dll
  • Epicor.Mfg.Core.Session.dll
  • Epicor.Mfg.Proc.IImportEDI.dll
  • Epicor.Mfg.Proc.ImportEDI.dll
using Epicor.Mfg.Core;
using Epicor.Mfg.Proc;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using(Session _session =  new Session("manager","manager","AppServerDC://E9P:9411",Session.LicenseType.Default))
{
       ImportEDI _importEDIPRoc = new ImportEDI(_session.ConnectionPool);

       ImportEDIDataSet importEDIDS = _importEDIPRoc.GetNewParameters();
       ImportEDIDataSet.ImportEDIParamRow newRow = importEDIDS.ImportEDIParam[0];

       newRow.ProcessingDelay=1;
       newRow.LogFilename=@"C:\Epicor\EpicorData\ImportEDI.log"; //EDI LOG
       newRow.Inactive=false;
       newRow.InboundPath=@"\\taf2k8edi1\epicor\edidata\inbound\demand"; //IMPUT PATH
       newRow.ProcessNum=0;
       newRow.BackupFile=true;
       newRow.AutoAction="";
       newRow.PrinterName="";
       newRow.AgentSchedNum=0;
       newRow.AgentID="SystemTaskAgent";
       newRow.AgentTaskNum=0;
       newRow.RecurringTask=false;
       newRow.RptPageSettings="";
       newRow.RptPrinterSettings="";
       newRow.RptVersion="";
       newRow.ReportStyleNum=0;
       newRow.WorkstationID = Environment.MachineName + " " + Process.GetCurrentProcess().SessionId; //TIS IS IMPORTANT
       newRow.TaskNote="";
       newRow.ArchiveCode=0;
       newRow.DateFormat="m/d/yyyy";
       newRow.NumericFormat=",.";
       newRow.AgentCompareString="";
       newRow.ProcessID="";
       newRow.ProcessTaskNum=0;
       newRow.DecimalsGeneral=2;
       newRow.DecimalsCost=5;
       newRow.DecimalsPrice=5;
       newRow.GlbDecimalsGeneral=2;
       newRow.GlbDecimalsCost=5;
       newRow.GlbDecimalsPrice=5;
       newRow.FaxSubject="";
       newRow.FaxTo="";
       newRow.FaxNumber="";
       newRow.EMailTo="";
       newRow.EMailCC="";
       newRow.EMailBCC="";
       newRow.EMailBody="";
       newRow.AttachmentType="";
       newRow.ReportCurrencyCode="";
       newRow.ReportCultureCode="";
       newRow.RowIdent="";
       newRow.RowMod="A";

       _importEDIPRoc.SubmitToAgent(importEDIDS,"SystemTaskAgent",0,0,"Epicor.Mfg.UIProc.ImportEDI");

}

Tags: , , , ,

Sometimes the libraries you need can not be compiled into the code you are writing. But this doesn’t mean that you can’t still use them, using reflection you can load any library dynamically into your code and execute any method within it.

The below example demonstrates how to dynamically load the Microsoft Interop Library for Outlook from a directory and subsequently invoke a new Email with an attachment. I’ve commented the code above each invocation with the equivalent code that would be used if this library had been loaded at compile time.


Assembly interopAssembly = Assembly.LoadFile(System.Environment.CurrentDirectory + @"\Microsoft.Office.Interop.Outlook.dll");

 //Microsoft.Office.Interop.Outlook.Application oApp = new Microsoft.Office.Interop.Outlook.Application();
 object outlookApplication = interopAssembly.CreateInstance("Microsoft.Office.Interop.Outlook.ApplicationClass");
 Type outlookApplicationType = interopAssembly.GetType("Microsoft.Office.Interop.Outlook.ApplicationClass");

 //Microsoft.Office.Interop.Outlook._MailItem oMailItem = (Microsoft.Office.Interop.Outlook._MailItem)oApp.CreateItem(Microsoft.Office.Interop.Outlook.OlItemType.olMailItem);
 dynamic mailItem = outlookApplicationType.InvokeMember("CreateItem", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, null, outlookApplication, new object[] { 0 });

 mailItem.To = "test@test.com";
 mailItem.Subject = "test@test.com";
 mailItem.Body = "test@test.com";

 //oMailItem.Attachments.Add(@"C:\Logs\ContractImpl_2.txt", Microsoft.Office.Interop.Outlook.OlAttachmentType.olByValue, Type.Missing, Type.Missing);
 object attachments = mailItem.Attachments;
 Type attachmentType = attachments.GetType();
 attachmentType.InvokeMember("Add", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, null, attachments, new object[] { @"C:\Logs\ContractImpl_2.txt", 1, Type.Missing, Type.Missing });

 //oMailItem.Display(true);
 Type mailItemType = mailItem.GetType();
 mailItemType.InvokeMember("Display", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, null, mailItem, new object[] { true });

Tags: , , ,

A question was asked on the mailing list regarding the ability to change the appearance (background, foreground, color) of an input control within the Epicor ERP10 configuration.

This was an unusual request and it took a few minutes to figure it out. Below is the code which when excecuted on field change will change the appearance of the given input control to have a red background. It is worth noting that because of the way that the configurator editor is written there are parts of the configurator which do not have access to the Infragistics controls / dlls. In this case you would have to load the DLL manually using reflection which I do not cover below.

However if done at the control level (OnChange, OnLeave) the Infragistic DLL seems to be available and the code below works. Please watch the companion video if you want more details.

The Input.InputName is an object called InputControlValueBound which contains a reference to a “Control” and the value of said control. Once you’ve figured this out, you can use the public property .Control to get a hold of the EpiXXX (EpiTextBox,EpiCombo,etc..) object and then set the Appearance as you normally would.

Please note that all Epicor EpiXXX controls have a default property called “UseAppStyling” if this property is set to true the control ignores any appearance changes because it assumes you want to load the default theme from the environment. This property needs to be set to false in order to allow the appearance changes to take effect.

 

Put this code in your OnChange , OnLeave event

Code to implement:

 Infragistics.Win.Appearance app1 = new Infragistics.Win.Appearance();
app1.BackColor =Color.Red;
((Ice.Lib.Framework.EpiTextBox)Inputs.MTPDESC.Control).UseAppStyling = false;
((Ice.Lib.Framework.EpiTextBox)Inputs.MTPDESC.Control).Appearance = app1;

//Done

Tags: , , ,

Jose C Gomez on July 1st, 2014

So it turns out that the DB for this blog had been filled up by a runaway plugin. So no one could comment or do much on here. This has been fixed… I guess I would have known this happened a long time ago if I posted more often. Oh well! Sorry guys!

Jose C Gomez on December 18th, 2013

A few years ago I wrote  an HTML Editor control that can be used with the .NET framework. Until recently it lay in obscurity being used from time to time by my and a few other people that found it online. Recently Joshua from Perficiency Development made some enhancements to it when he was trying to get it to work with Epicor. With this new enhancements and the fact that someone asked about it on the Epicor mailing list I decided to throw together this short tutorial on how to get it working in Epicor.

  1. Go download the appropriate version of the DLL from the original post
  2. Once you’ve downloaded the project, simply copy the DLL from the Release/Bin folder into the Epicor client folder where you’d like to use the control
  3. In the example code below I began by adding a new tab to the ABC Code form where I was going to place my editor
  4. Once the tab is added I drew a group box on the shape and size I want the editor to be in the new tab. This makes it much easier to position the editor without having to write much code
  5. Once this is done the code below takes care of the rest. I’ve commented the code where appropriate for clarity.

The final result of the below code can be seen below

// **************************************************
// Custom code for AbcCodeForm
// Created: 12/18/2013 12:19:03 PM
// **************************************************
using System;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Windows.Forms;
using Epicor.Mfg.BO;
using Epicor.Mfg.UI;
using Epicor.Mfg.UI.Adapters;
using Epicor.Mfg.UI.Customization;
using Epicor.Mfg.UI.ExtendedProps;
using Epicor.Mfg.UI.FormFunctions;
using Epicor.Mfg.UI.FrameWork;
using Epicor.Mfg.UI.Searches;
using HTMLWYSIWYG;

public class Script
{
	// ** Wizard Insert Location - Do Not Remove 'Begin/End Wizard Added Module Level Variables' Comments! **
	// Begin Wizard Added Module Level Variables **

	private EpiDataView edvAbcCode;
	// End Wizard Added Module Level Variables **

	// Add Custom Module Level Variables Here **

	//Declare a class level htmlwysiwyg
	htmlwysiwyg htmlEditor;

	public void InitializeCustomCode()
	{
		// ** Wizard Insert Location - Do not delete 'Begin/End Wizard Added Variable Initialization' lines **
		// Begin Wizard Added Variable Initialization

		this.edvAbcCode = ((EpiDataView)(this.oTrans.EpiDataViews["AbcCode"]));
		this.edvAbcCode.EpiViewNotification += new EpiViewNotification(this.edvAbcCode_EpiViewNotification);
		// End Wizard Added Variable Initialization

		// Begin Wizard Added Custom Method Calls

		// End Wizard Added Custom Method Calls

		//In your InitializeCustomCode() function initialize the editor and add it to your groupbox
		htmlEditor = new htmlwysiwyg();
		htmlEditor.ImagePasteToPath = @"\\GOMEZFAMILY\Users\Public\Pictures\";
		htmlEditor.allowEdit(true);

		//We have a need for triggering an event when validating the control to update the data view
		htmlEditor.Validating += htmlEditor_Validating;
		grpGroup.Controls.Add(htmlEditor);

	}

	public void DestroyCustomCode()
	{
		// ** Wizard Insert Location - Do not delete 'Begin/End Wizard Added Object Disposal' lines **
		// Begin Wizard Added Object Disposal

		this.edvAbcCode.EpiViewNotification -= new EpiViewNotification(this.edvAbcCode_EpiViewNotification);
		this.edvAbcCode = null;
		// End Wizard Added Object Disposal

		// Begin Custom Code Disposal

		// End Custom Code Disposal

		//Always be a good citizen and dispose of your extra objects
		htmlEditor.Validating -= htmlEditor_Validating;
		htmlEditor.Dispose();
		htmlEditor = null;
	}

	private void edvAbcCode_EpiViewNotification(EpiDataView view, EpiNotifyArgs args)
	{
		// ** Argument Properties and Uses **
		// view.dataView[args.Row]["FieldName"]
		// args.Row, args.Column, args.Sender, args.NotifyType
		// NotifyType.Initialize, NotifyType.AddRow, NotifyType.DeleteRow, NotifyType.InitLastView, NotifyType.InitAndResetTreeNodes

		// When the view initializes we must check if we have data
		// if  we do then we bind the control to the UD field where
		// we want to store the HTML. Please note that ShortChar01
		// is not a good choice since its only 50 characters long
		if ((args.NotifyType == EpiTransaction.NotifyType.Initialize))
		{
			if(args.Row >-1)
			{
				htmlEditor.DataBindings.Clear();
				htmlEditor.DataBindings.Add(new Binding("HTML",view.dataView[args.Row],"ShortChar01"));
			}
			else // If the DataView is empty then clear the control
			{
				htmlEditor.DataBindings.Clear();
				htmlEditor.setHTML("");
			}
		}

	}

	private void htmlEditor_Validating(object sender, CancelEventArgs args)
	{
		// When we make a change to the control, lets make sure we get the HTML
		// and update your dataview.
		EpiDataView edvDtl = oTrans.Factory("AbcCode");
		if(edvDtl.Row >-1)
		{
			edvDtl.dataView[edvDtl.Row].BeginEdit();
			edvDtl.dataView[edvDtl.Row]["ShortChar01"] = htmlEditor.getHTML();
			edvDtl.dataView[edvDtl.Row].EndEdit();
			edvDtl.Notify(new EpiNotifyArgs(oTrans, edvDtl.Row, edvDtl.Column));
		}

	}
}

Tags: , , ,

Jose C Gomez on December 2nd, 2013

Update 12/18/2013:

Added a few samples of how to implement in epicor / integrate with the data views. Please not that if you are going to paste images and use it with Epicor we recommend that you download the version which puts the images on a shared network drive. Most UD fields in epicor are too small to handle the Base64 encoded image.
This sample code is provided as is and it was created using Epicor 9.05


Update 12/3/2013:


Joshua Giese from Perficiency Development made some enhancements to the editor that he wanted to share back.

  1. Added the ability to copy / paste images.
    Images are pasted and embedded using the Base 64 Data URI
    or Images are placed on a Shared Folder in a Network Drive ( 2 different versions see below)
    2013-12-03 13_42_47-6lAYWRgVoJqMXSzcdRWj2plP5W0KN.jpg (950×627)
  2. Added a custom context menu for Copy , Cut and Paste which invokes the toolbar functions
    6lAYXWo8vaSq3lSI7XvEaW77UFdYD[1]
  3. Also the project has been upgraded to Visual Studio 2012

Download it here HTMLWYSIWYG (Base 64 Encoded Image)

Download it here HTMLWYSIWYG_sharedFolder (Shared folder Paste Image)


I’ve been busy at work lately one of the projects assigned to me is to create an application to redact and edit emails that will be sent to customers. This provided a great opportunity for me to get familiar with creating a custom control in C#. I needed a way to create rich content and although C# has the rich text control it provides everything in RTF which is difficult to work with and hard to embed. So I got to work on my very own WYSIWYG control that produces HTML. So I am making it open source and available to anyone have fun and enjoy if you make any cool modifications to it let me know. I would love to include spell check ability but I don’t have much time to work on it right now.

Download Here HTMLWYSIWYG (Original version)
wysiwyg

Sample Uses

 private void button1_Click_1(object sender, EventArgs e)
 {
 //Gets the HTML Code generated by the control
 Console.WriteLine( htmlwysiwyg1.getHTML())
 //Getts the PLain Tex code generated by the control.
 Console.WriteLine(htmlwysiwyg1.getPlainText());
 }
 

 

 private void frm_main_Load(object sender, EventArgs e)
 {
 //Sets the control to allow edits
 htmlwysiwyg1.allowEdit(true)
 //Loads the HTML into the control
 htmlwysiwyg1.setHTML("BOLD");
 //Loads aditional fonts into the control
 htmlwysiwyg1.addFont("Cambria");
 htmlwysiwyg1.ImagePasteToPath =@"\\YOUR_UNC_PATH"; //Only available in the Paste to Network Version
 }
 

Tags: , , , , ,

Jose C Gomez on October 8th, 2013

I decided to start sharing some of the recipes that I make every day, some of these I’ve adapter from others and some are recipes I just threw together, please let me know your thoughts and if you like or dislike any of the dishes.

Napa cabbage, sausage and white bean soup
Serves 6
A hearty, warm and inviting soup that can be paired with rice to make a complete meal.
Write a review
Print
Prep Time
30 min
Cook Time
45 min
Total Time
1 hr 15 min
Prep Time
30 min
Cook Time
45 min
Total Time
1 hr 15 min
Ingredients
  1. 1 Napa cabbage (chopped into strips)
  2. 4 carrots (chopped)
  3. 2 celery stalks (chopped)
  4. 4 small red potatoes (chopped)
  5. 1 lbs mild sausage
  6. 1/2 lbs pork stew meat
  7. 2 cans white bean (drained)
  8. 2 tbsp tomato sauce
  9. 1 tbsp olive oil
  10. 3 cloves of garlic
  11. 2 boxes of chicken or vegetable broth (low sodium)
Instructions
  1. Drizzle a nice size pot with olive oil and brown sausage on medium high heat until cooked through.
  2. Remove the sausage from the pot and set aside, add in the pork stew meat
  3. Season well with salt and pepper and cook until it has browned on all sides
  4. Remove the pork from the pot and set aside
  5. Add the Napa cabbage chopped into strips and cook until wilted and slightly brown.
  6. Remove the Napa cabbage, add a little bit more of oil and stir in the carrots, onions and celery
  7. Season generously with salt and pepper and cook until onions are translucent and carrots are glistening
  8. Add in the garlic and tomato sauce and cook for another minute stirring to make sure the garlic doesn't burn
  9. Add in the potatoes and stir to combine
  10. Add in the two boxes of broth, bring to a boil then reduce the heat to simmer
  11. Add in the sausage, and the pork and simmer until carrots and potatoes are nice and soft ( 15-20 minutes)
  12. Add in the cabbage and the rinsed white beans and simmer for another 10-15 minutes until the meat and all the veggies are fully cooked
  13. Adjust salt and paper to taste
  14. Serve over rice for a complete meal (veggies, protein and carbs)
Sausage
  1. If using sausage links simply chop them up before cooking them
Pork
  1. Note that you do not need to cook the pork all the way through when browning at first, we simply want to give it color at this point. It will finish cooking when the soup is simmering
Oil
  1. When doing the initial cooking / browning you may need to add a bit more oil here and there to keep things from sticking.
Garlic
  1. We add the garlic last because garlic can burn easily
josecgomez.com http://www.josecgomez.com/wordpress/

Tags: ,