Click or drag to resize

ERPExportBase Class

Export Base without any custom settings objects.
Inheritance Hierarchy
SystemObject
  CTExtensionsCTExtension
    CTBuiltInExtension
      CTExtensions.ExportCoreExportBaseDummy, ExportSettingsBaseDummy, Dummy, Dummy
        CTExtensions.ExportCore.ExportBaseTypesERPExportBase

Namespace:  CTExtensions.ExportCore.ExportBaseTypes
Assembly:  CTInterface (in CTInterface.dll)
Syntax
public abstract class ERPExportBase : ExportBase<Dummy, ExportSettingsBase<Dummy>, Dummy, Dummy>

The ERPExportBase type exposes the following members.

Constructors
  NameDescription
Protected methodERPExportBase
Initializes a new instance of the ERPExportBase class
Top
Examples
This example shows how to utilize classes of CTExtensions.ExportCore, CTExtensions.ExportCore.Config, CTExtensions.ExportCore.ExportBaseTypes and CTExtensions.ExportCore.EXTs namespaces for creating a custom Export ERP integration that supports custom data storing on CT Profile, current User, Export Profile and Export Profile Field levels, as well as very powerful GenericExportHandlerT, E, I for the actual export process.

Language: C#
Class name: MyCustomErpIntegration
C#
// @AUTO-REFERENCE { [CT_INSTALL_PATH]\CTInterface.dll }
// @AUTO-REFERENCE { [CT_INSTALL_PATH]\Interop.CTEngineLib.dll }
// @AUTO-REFERENCE { [CT_INSTALL_PATH]\ATRControls2.dll }
// @AUTO-REFERENCE { [CT_INSTALL_PATH]\Interop.ATRControlsXLib.dll }
// @AUTO-REFERENCE { c:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.Windows.Forms.dll }
// @AUTO-REFERENCE { c:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.Drawing.dll }

using ATR.CT.CTInterface;
using CTEngineLib;
using CTExtensions.ExportCore.Config;           /* SettingsObject, ControlAdapter, StreamExtensions, PropertyGridAdapter */
using CTExtensions.ExportCore.EXTs;             /* EventExtension */
using CTExtensions.ExportCore.ExportBaseTypes;  /* ERPExportBaseExtraOptsWithUserSettings */
using System.Windows.Forms;                     /* MyExportSettingsGUI */
using System.IO;                                /* Stream */
using ATRControls2;                             /* MyUserSettingsGUI (GenericLoginCtrl) */
using System.Collections.Generic;               /* List */
using CTExtensions.ExportCore.ExportHandler;    /* GenericExportHandler */
using ATRControlsXLib;
using System.Linq;

/*
 * NOTE: This add-in requires CUSTOMTOOLS 2024 SP1 or newer to work properly.
 */ 

namespace CustomErpIntegrationDemo
{

  // THIS is the main class that ties it all together. In its simplicity,
  // it just defines the stong types for all custom objects and returns 
  // the MyExportHandler than handles the actual export.
  // All data is stored using IdentifyingName, so changing it will 
  // cause all previous data of this integration to be lost.
  // FriendlyName is shown all of the UI and messages related to this integration.
  public class MyCustomErpIntegration : ERPExportBaseExtraOptsWithUserAndProfileSettings<MyExportFieldSettings, MyExportSettings, MyUserSettings, MyProfileSettings>
  {
    public override string FriendlyName()
    {
      return "My Custom Integration"; // This is shown in the UI.
    }

    public override string IdentifyingName()
    {
      return "MY-CUSTOM-ERP-INTEGRATION-12345"; // Just something that is unique and constant.
    }

    public override List<EventExtension> GetEventExtensions()
    {
      return new List<EventExtension>() { new MyExportHandler() };
    }

    // Override to add PDM context support.
    protected override ExportTypeExt<MyExportSettings, MyExportFieldSettings> CreateExportType()
    {
      return new ExportWithFullPDMSupport();
    }

    // This class adds full PDM support, both 2-phased export (= export on client; conversions and writebacks on task host machine),
    // and silent execution (= completely on task host machine with no user interaction).
    // MyExportHandler should investigate MyExportHandler.CurrentExportCase variable to know the context.
    public class ExportWithFullPDMSupport : ExportTypeExt<MyExportSettings, MyExportFieldSettings>
    {
      public override bool AllowUseInSWPDM()
      {
        return true;
      }

      public override bool SupportsSilentExecution()
      {
        return true;
      }
    }
  }

  // This is the class that does all the magic in Export.
  public class MyExportHandler : GenericExportHandler<MyCustomErpIntegration, MyExportItem, MyRowItemizer>
  {

    // Do anything you like for the 'data' before it's being itemized by 'MyRowItemizer'. For example if you need to 
    // send PDM checkbox values as Yes/No instead of 1/0, or do some unit conversions, this is perfect place to do it.
    // But you need to known which fields you should handle. You could e.g. utilize MyExportFieldSettings.
    // Note that this is invoked for all exported configurations separately.
    protected override void ManipulateExportDataBeforeItemization(ICTExportProfile profile, ICTExportProfileData data, string conf, bool bLastConfiguration)
    {

      // As an example, lets assume "MyExportFieldSettings.MyFieldBoolData" is an option "To Uppercase".

      // Get the field settings from export settings
      MyExportSettings exportsettings = (GetParent() as MyCustomErpIntegration).GetExportSettings(profile as CTExportProfile);
      foreach (var fieldSettings in exportsettings.FieldSettings)
      {
        string field = fieldSettings.Key;
        MyExportFieldSettings settings = fieldSettings.Value;


        if (settings.MyFieldBoolData) // If the setting is on, convert the value in each row to uppercase.
        {
          for (int i = 0; i < data.Rows; i++)
            data.SetValue(i, field, data.GetValueByName(field, i).ToUpper());
        }
      }
    }

    // You might want to have some "control columns" that are hidden, or additional columns that hold e.g. status of the item.
    protected override void GetAdditionalColumnsSetup(IListViewEx oList, string configuration, out Dictionary<string, bool> oColsToAdd, out List<string> oColsToHide)
    {
      oColsToAdd = null;
      oColsToHide = null;

      // Lets add 'Item Status' column so we have a field to show the status for user.
      oColsToAdd = new Dictionary<string, bool>() { { "Item Status", true } };
    }


    // Do possible queries to target systems to map the items etc.
    // Supports setting field and bom field values, colors and everything even before
    // the actual list view items are added to the list.
    protected override void UpdateItemsPreFilling(List<MyExportItem> items)
    {
      // Get all the settings
      MyExportSettings exportsettings = (GetParent() as MyCustomErpIntegration).GetExportSettings(moExportProfile as CTExportProfile);
      MyUserSettings userSettings = (GetParent() as MyCustomErpIntegration).GetUserSettings();
      MyProfileSettings profileSettings = (GetParent() as MyCustomErpIntegration).GetProfileSettings();


      // It's important to know in which context you are and what you can do.
      // If you are outside SOLIDWORKS, then you cannot use SOLIDWORKS API. 
      if (CurrentExportCase == ExportCase.SOLIDWORKS)
      {
        // This Export is being called from SOLIDWORKS
        Log("This goes to %TEMP%\\MY-CUSTOM-ERP-INTEGRATION-12345.log"); // Log file name is IdentifyingName
      }
      else if (CurrentExportCase == ExportCase.PDM)
      {
        // This Export is being called (usually) from PDM

        Log("This goes to Task Details"); // Or to some other system that can do task-like executions in the future.
      }
      else if (CurrentExportCase == ExportCase.SOLIDWORKS_Silent)
      {
        // This Export started outside solidworks (usually from PDM) but is now being performed inside SOLIDWORKS
        // SILENTLY, which means user add-ins like this SHOULD NOT HAVE ANY USER INTERACTION!

        // It's not guaranteed that the files are open in SOLIDWORKS as that depends on the task settings.

        Log("This goes to Task Details and the operation is silent."); // Or to some other system that can do task-like executions in the future.
      }



      // TODO: item mapping to existing items & BOMs in target ERP.


      // As an example, lets assume all items except the first one are new after the mapping and we should indicate that for the user.
      if (items.Count > 0)
      {
        items.First().RowColorController.ClearColors();
        items.First().SetValue("Item Status", "EXISTING");
        items.First().RowColorController.SetFieldBGColor("Item Status", ExportItemColorController.COLOR_WHITE);


        items.First().WillGetItemNumberAfterExport = false; // let's also control our custom logic here.

      }

      foreach (var item in items.Skip(1))
      {
        item.RowColorController.ClearColors();
        item.SetValue("Item Status", "NEW");
        item.RowColorController.SetFieldBGColor("Item Status", ExportItemColorController.COLOR_NEW);

        item.WillGetItemNumberAfterExport = true; // let's also control our custom logic here.
      }

      // Lets also add "Ghost line" for the first item. Ghost lines can be used to show user that the BOM in target ERP
      // has items that are not present in the current structure.
      if (items.Count > 0)
      {

        var ghostItem = items.First().AddGhostItem<MyExportItem>("Item '12345' in target ERP");
        ghostItem.SetQuantityIn(items.First(), 1); // Must have quantity, otherwise it gets excluded.

        ghostItem.SetValue("Item Status", "Exists in ERP but not in CAD");
        ghostItem.RowColorController.SetRowFGColor(ExportItemColorController.COLOR_GHOST);
      }

    }

    // This is the actual export that happens after clicking that Export button in Export dialog.
    protected override bool Export(List<MyExportItem> items)
    {
      MyExportSettings exportsettings = (GetParent() as MyCustomErpIntegration).GetExportSettings(moExportProfile as CTExportProfile);
      MyUserSettings userSettings = (GetParent() as MyCustomErpIntegration).GetUserSettings();
      MyProfileSettings profileSettings = (GetParent() as MyCustomErpIntegration).GetProfileSettings();

      // Do the actual export.

      // Here we'd set the Writeback for all items that have 
      foreach (var item in items.Where(x => x.WillGetItemNumberAfterExport))
      {
        //item.CacheWriteBack("item number field", "item number from ERP");
        item.WillGetItemNumberAfterExport = false; // now there is actual writeback so remove the flag.
      }

      // As an example, let's fake success and just set the status here
      foreach (var item in items)
      {

        if (Itemizer.GetRowType(item.DataRows.First().Item1) == RowItemizer.RowType.Ghost)
          continue; // Skip ghost rows.


        item.RowColorController.ClearColors();
        item.SetValue("Item Status", "OK");
        item.RowColorController.SetFieldBGColor("Item Status", ExportItemColorController.COLOR_WHITE);

      }




      return true; // Success
    }


    /// This function is called during the second phase Export. At this point
    /// all conversions are done and collected, and writebacks are already done to files. This is mostly desined for
    /// sending converted documents to the target system, however, it is also possible to handle the whole Export Process
    /// silently within this function. 
    /// To write addtitional writebacks to files, call "PerformWritebacksWithCheckoutAndCheckin(...)" after
    /// caching the writebacks to items. Note that "PerformWritebacksWithCheckoutAndCheckin(...)" is already
    /// called once during "SecondPhaseInitialized(...)" so if there were writebacks added at the first
    /// export phase, some items might get multiple versions checked-in. You can override "SecondPhaseInitialized(...)"
    /// to not call.
    protected override bool SecondPhaseExport(List<MyExportItem> items)
    {
      // This ERP integration does nothing in "Second phase" or the Export that is usually
      // caused by PDM Task Add-in's run phase.

      return true; // Report success
    }

  }

  // ExportItem represents one or multiple rows in Export, and handles
  // all UI<->ExportData interaction as well as value writeback to files.
  // It support all Export options such as multiple configration export,
  // configuration grouping etc. and also conversions and writebacks in PDM context.
  // You'd normally add mapping information of the target ERP item to you Export Item.
  // And perform the mapping in MyExportHandler.UpdateItemsPreFilling.
  // You can also provide right-click menu actions for your items.
  public class MyExportItem : ExportItem
  {
    public bool WillGetItemNumberAfterExport { get; set; }

    public MyExportItem()
    {
      WillGetItemNumberAfterExport = false;
    }

    // We know this item requires writeback if it has writebacks
    // OR if it will get item number generated after the export (which is quite common).
    public override bool RequiresWriteBack()
    {
      return base.RequiresWriteBack() || WillGetItemNumberAfterExport;
    }
  }


  // This class allows you to override how rows in Export are itemized into
  // ExportItems (MyExportItems). For example, drawings, custom scopes and revision rows
  // are not recognized as items by default, so they will be collected in
  // parent items' "MyExportItem.Attachments".
  public class MyRowItemizer : RowItemizer
  {

  }

  // Object representing my custom settings (MyFieldStringData and MyFieldBoolData)
  // for Export Profile Fields of Export Profiles that are bound to my Erp Integration.
  public class MyExportFieldSettings : SettingsObject
  {

    // -- My data --
    public string MyFieldStringData { get; set; }
    public bool MyFieldBoolData { get; set; }
    // -- -- -- --


    // -- Serialization of my data
    protected override void Deserialize(Stream s)
    {
      MyFieldStringData = s.PopString();
      MyFieldBoolData = s.PopBool();
    }

    protected override void Serialize(Stream s)
    {
      s.PushString(MyFieldStringData);
      s.PushBool(MyFieldBoolData);
    }
    // -- -- -- --


    // -- return GUI control capable of showing and modifying my data
    //    when editing Export Profile Fields at Options.
    public override ControlAdapter CreateAdapter(ICTExtension parent)
    {
      // PropertyGridAdapter just utilizes System.Windows.Forms.PropertyGrid
      // to enable editing of data object values. It could be custom control too, 
      // but this is a quick solution.
      return new PropertyGridAdapter<MyExportFieldSettings>(parent);
    }
    // -- -- -- --

  }

  // Object representing my custom settings
  // for each individual CT user.
  public class MyUserSettings : SettingsObject
  {

    // -- My data --
    public bool Enabled { get; set; }
    public string UserName { get; set; }
    public string PassWord { get; set; }
    // -- -- -- --

    // -- Serialization of my data
    protected override void Serialize(Stream s)
    {
      s.PushBool(Enabled);
      s.PushString(UserName);
      s.PushString(PassWord);
    }

    protected override void Deserialize(Stream s)
    {
      Enabled = s.PopBool();
      UserName = s.PopString();
      PassWord = s.PopString();
    }
    // -- -- -- --

    // -- return GUI control capable of showing and modifying my data
    //    at User Options.
    public override ControlAdapter CreateAdapter(ICTExtension parent)
    {
      // Custom control "MyUserSettingsGUI" declared below
      return new MyUserSettingsGUI(parent);
    }
    // -- -- -- --
  }

  // Custom control that accesses "MyUserSettings", shown as
  // an individual page at User Options
  public class MyUserSettingsGUI : ControlAdapter<MyUserSettings>
  {

    // Utilizing generic login control from ATRControls2
    ATRControls2.WinForm.GenericLoginCtrl moCtrl;

    public MyUserSettingsGUI(ICTExtension parent) : base(parent)
    {
      // Load and configure the control.
      moCtrl = new ATRControls2.WinForm.GenericLoginCtrl();
      moCtrl.BackColor = System.Drawing.Color.White;
      moCtrl.ShowEnableCheck(true);
      moCtrl.ShowUsernameField(true);
      moCtrl.ShowPasswordField(true);

      moCtrl.ShowDatabaseField(false);
      moCtrl.ShowTestConnectionButton(false);
      moCtrl.ShowCommunicationPointField(false);

      moCtrl.Dock = System.Windows.Forms.DockStyle.Fill;
      Controls.Add(moCtrl);
    }

    // -- Couple the data object values with GUI elements
    //    back and forth.
    public override void LoadFrom(MyUserSettings settings)
    {
      moCtrl.LoginEnabled = settings.Enabled;
      moCtrl.Username = settings.UserName;
      moCtrl.Password = settings.PassWord;

    }
    public override void SaveTo(MyUserSettings settings)
    {
      settings.Enabled = moCtrl.LoginEnabled;
      settings.UserName = moCtrl.Username;
      settings.PassWord = moCtrl.Password;
    }
    // -- -- -- --
  }


  // Object representing my custom Export Profile specific settings.
  // Accessed from [...] button at Export Profile settings.
  // Internally, ExportSettingsBase holds also Export Profile Field
  // settings of our custom type (MyExportFieldSettings)
  public class MyExportSettings : ExportSettingsBase<MyExportFieldSettings>
  {

    // -- My data --
    public string TargetCompany { get; set; }
    // -- -- -- --

    // -- Serialization of my data
    protected override void Deserialize(Stream s)
    {
      base.Deserialize(s);  // Important to remember base object serialization!

      TargetCompany = s.PopString();
    }

    protected override void Serialize(Stream s)
    {
      base.Serialize(s); // Important to remember base object serialization!

      s.PushString(TargetCompany);
    }
    // -- -- -- --


    // -- return GUI control capable of showing and modifying
    //    TargetCompany Export Profile options.
    public override ControlAdapter CreateAdapter(ICTExtension extension)
    {
      return new MyExportSettingsGUI(extension);
    }
  }

  // GUI control that accesses "MyExportSettings", shown 
  // with [...] button at Export Profile settings
  // Just a simple text box.
  public class MyExportSettingsGUI : ControlAdapter<MyExportSettings>
  {
    System.Windows.Forms.TextBox tb;

    public MyExportSettingsGUI(ICTExtension ext) : base(ext)
    {
      tb = new System.Windows.Forms.TextBox();
      tb.Dock = System.Windows.Forms.DockStyle.Top;
      Controls.Add(tb);
    }

    // -- Couple the data object values with GUI elements
    //    back and forth.
    public override void LoadFrom(MyExportSettings settings)
    {
      tb.Text = settings.TargetCompany;
    }

    public override void SaveTo(MyExportSettings settings)
    {
      settings.TargetCompany = tb.Text;
    }
    // -- -- -- --
  }

  // Object representing my custom settings
  // in the scope of the current CT Profile
  public class MyProfileSettings : SettingsObject
  {

    // -- My data --
    public string ConnectionString { get; set; }
    // -- -- -- --


    // -- Serialization of my data
    protected override void Deserialize(Stream s)
    {
      ConnectionString = s.PopString();
    }

    protected override void Serialize(Stream s)
    {
      s.PushString(ConnectionString);
    }
    // -- -- -- --


    // -- return GUI control capable of showing and modifying my data
    //    when visiting this integration's page at Profile Options
    public override ControlAdapter CreateAdapter(ICTExtension parent)
    {
      // PropertyGridAdapter just utilizes System.Windows.Forms.PropertyGrid
      // to enable editing of data object values.
      return new PropertyGridAdapter<MyProfileSettings>(parent);
    }
    // -- -- -- --
  }

}
Availability

CUSTOMTOOLS 2022 SP0


See Also