WM-Synergy Business Objects SDK Information

WM-Synergy Business Objects SDK Information

WM-Synergy Business Objects

WM-Synergy Business Objects, SBO, is a comprehensive transaction library built on the both the .net standard and .net framework platforms.  This library allows the developer to quickly read/write/update transactional data with the Visual ERP database.
  1. Ensures that all tables required for a data transaction are properly updated.
  2. Synergy supports this product, if you find a bug, we will fix it at no cost to you.
  3. The code base allows you as a developer to write your own SQL code as needed.
  4. The code allows for roll back of transactions if a record does not complete properly.

Warning
As an end user you must apply your licensee code to be able to use WM-Synergy Business Objects. 
If you are using https:\\ to the authenticator, make sure the certificate on the site is valid.
Otherwise you might see something similar to the following:

For customers that purchased SBO a license manager server is installed.  This is a local installation running in IIS  AuthenticationServer on port 8089 - it is a webservice that evaluates the domain against the license key.  During the initial database connection (passing in the URL from the implemented application)  the webservice is called and evaluated


The SBO installer package comes with sample programs on how to use the SynergyBusinessObjects.dll library see your installed Examples subfolder.  
As Microsoft moves away from standard system libraries included with Windows, it becomes important to include in your developer project any and all libraries that are provided with this SDK kit. 
With updates for support of Visual 11 the SynergyBusinessObjects.dll relies on Oracle.ManagedDataAccess.dll, even if you are a Microsoft SQL only facility. 
Notes
The following libraries may also be required, in a customer created project: the version may not matter if your project is a .exe you should be able to use the latest from nuget.

  1. Microsoft.Data.SqlClient.dll
  2. Oracle.ManagedDataAccess.dll  (min 21.18.0)
  3. System.Configuration.ConfigurationManager (min 6.0.1)
  4. <-- might be needed. -->
  5. Azure.Core (min 1.38.0)
  6. Azure.Identity (min 1.11.4)
  7. Microsoft.CSharp
  8. Microsoft.Identity.Client (min 4.6.1.3)
  9. Microsoft.BclAsyncInterfaces (min 9.0.3)
  10. Microsoft.Data.SqlClient.SNI (min 5.2.0)
  11. Microsoft.Identity.Client (min 4.61.3)
  12. Microsoft.Identity.Client.Extensions.Msal (min 4.61.3)
  13. Microsoft.IdentityModel.JsonWebTokens (min 6.35.0)
  14. Microsoft.IdentityModel.Abstractions (min 6.35.0)
  15. Microsoft.IdentityModel.JsonWebTokens(min 6.35.0)
  16. Microsoft.IdentityModel.Logging (min 6.35.0)
  17. Microsoft.IdentityModel.Protcols (min 6.35.0)
  18. Microsoft.IdentityModel.Protcols.OpenIdConnection (v6.35.0)
  19. Microsoft.IdentityModel.Tokens (min 6.35.0)
  20. System.Buffers.dll  min (4.6.1)
  21. System.ClientModel (min 1.0.0)
  22. System.Diagnostics.DiagnosticSource (min 6.0.1)
  23. System.Diagnostics.PerformanceCounter(min 6.0.2)
  24. System.DirectoryServices.Protocols(min 6.0.2) 
  25. System.formats.Asn1.dll (min 9.0.3)
  26. System.IdentityModel.Tokens.Jwt (min 6.35.0)
  27. System.IO.FileSystem.AccessControl (min 5.0.0)
  28. System.IO.Pipelines.dll ( v9.0.3)
  29. System.Memory.dll (min 4.6.2)
  30. System.Memory.Data (min 1.0.2)
  31. System.Net.Http (min 4.3.4)
  32. System.Numerics.Vectors.dll (min 4.6.1)
  33. System.Runtime.InteropServices.Unsafe (min 6.1.1)
  34. System.Runtime.InteropServices.RuntimeInformation(min 4.3.0)
  35. System.Security.AccessControls (min 6.0.0)
  36. System.Security.Cryptography.Algorithms (min 4.3.0)
  37. System.Security.Cryptography.Encoding(min 4.3.0)
  38. System.Security.Cryptography.Primitives (min 4.3.0)
  39. System.Security.Cryptography.ProtectedData (min 4.7.0)
  40. System.Security.Cryptography.X509Certificates (min 4.3.0)
  41. System.Security.Permissions (min 6.0.0)
  42. System.Security.Principal.Windows (min 5.0.0)
  43. System.Text.Encoding (min 4.3.0)
  44. Sytem.Text.Encodings.Web.dll (min 9.0.3)
  45. System.Text.Json.dll (min9.0.3)
  46. System.Threading.Tasks.Extensions.dll (min4.6.2)
  47. System.Value.Tuple.dll (min 4.6.1)
For .net standard make sure to include:  
  1. Oracle.ManagedDataAccess (nuget)
  2. Microsoft.Data.SqlClient  (nuget Use the correct version for your build)
  3. System.Configuration.ConfigurationManager (min 6.0.1)
  4. <<< might be needed as well >>>
  5. System.Net.Http
  6. System.ServiceModel
  7. System.ServiceModel.Duplex
  8. System.ServiceModel.Http
  9. System.ServiceModel.NetTcp
  10. System.ServiceModel.Primitives
  11. System.ServiceModel.Security
Alert
Please note, the .net framework version of sbo objects will be retired as .net standard will replace it.
Starting with Visual 11 support for single site, Visual ERP 7 and below, is no longer supported or provided with sbo objects.  
We can provide a non-supported version SynergyBusinessObjects70.dll  (available upon request).

Connection Test

  1.     [TestClass]
  2.     public class ConnectionTest
  3.     {
  4.         #region Private Methods
  5.         /// <summary>
  6.         /// <c>GetSBOAuthenticator</c> url as specified in the app.config.
  7.         /// </summary>
  8.         /// <returns></returns>
  9.         private Uri GetSBOAuthenticator()
  10.         {
  11.             Uri Url = null;
  12.             SBOServer.AuthenticationService Svc = new SBOServer.AuthenticationService();

  13.             ConfigurationManager.AppSettings["SchemaPath"] = Environment.CurrentDirectory + "\\";
  14.             string SBOServer = ConfigurationManager.AppSettings["SBOServer"].ToString();
  15.             string SBOPort = ConfigurationManager.AppSettings["SBOPort"].ToString();

  16.             Url = new Uri(string.Format("http://{0}:{1}/AuthenticationService.asmx", SBOServer, SBOPort));

  17.             return Url;
  18.         }
  19.         /// <summary>
  20.         /// <c>ConnectToDbase</c> using the values set in the App.config file.
  21.         /// </summary>
  22.         /// <returns>Database connection</returns>
  23.         private Synergy.BusinessObjects.DatabaseConnection ConnectToDbase()
  24.         {
  25.             Uri Url = GetSBOAuthenticator();
  26.             Synergy.BusinessObjects.DatabaseConnection DataBase = new Synergy.BusinessObjects.DatabaseConnection(Url);
  27.             //Connection information
  28.             string DBType = ConfigurationManager.AppSettings["DBType"].ToString();
  29.             string DBServer = ConfigurationManager.AppSettings["DBServer"].ToString();
  30.             string DBDatabase = ConfigurationManager.AppSettings["DBDatabase"].ToString();
  31.             string DBUser = ConfigurationManager.AppSettings["DBUserId"].ToString();
  32.             string DBPassword = ConfigurationManager.AppSettings["DBPassword"].ToString();

  33.             DataBase.UserCredentials.UseBlind = true; //Default Value = true
  34.             DataBase.UserCredentials.DatabaseType = (DBType == "SqlServer" ? Synergy.BusinessObjects.DatabaseEngineType.SqlServer : Synergy.BusinessObjects.DatabaseEngineType.Oracle);
  35.             DataBase.UserCredentials.Server = DBServer; //Enter the Server (and instance name for SqlsErver)
  36.             DataBase.UserCredentials.Database = DBDatabase;
  37.             DataBase.UserCredentials.UserID = DBUser;
  38.             DataBase.UserCredentials.Password = DBPassword;

  39.             DataBase.Connect();

  40.             return DataBase;
  41.         }
  42.         #endregion
  43.         #region Unit Tests
  44.         [TestMethod]
  45.         public void AuthenticationTest()
  46.         {
  47.             Uri Url = null;
  48.             SBOServer.AuthenticationService Svc = new SBOServer.AuthenticationService();
  49.             try
  50.             {
  51.                 Url = GetSBOAuthenticator();
  52.                 Svc.Url = Url.ToString();
  53.                 Svc.AuthenticateNode("Test");
  54.                 Svc.Dispose();
  55.                 Assert.AreEqual(1, 1); // Success 
  56.             }
  57.             catch (Exception ex)
  58.             {
  59.                 Assert.Fail(ex.Message);
  60.             }
  61.         }

  62.         [TestMethod]
  63.         public void ConnectToDatabase()
  64.         {
  65.             try
  66.             {
  67.                 //Create the Database Connection – define the Connection Manager Server
  68.                 Synergy.BusinessObjects.DatabaseConnection Database = ConnectToDbase();
  69.                 if (Database.Connected)
  70.                 {
  71.                     Assert.IsTrue(1 == 1, "Database Connection is a Success!");
  72.                     Database.CloseConnection();
  73.                 }
  74.                 else
  75.                     Assert.Fail("Check the app.config settings.");
  76.             }
  77.             catch (Exception ex)
  78.             {
  79.                 Assert.Fail(ex.Message);
  80.             }
  81.         }
  82.         #endregion
  83.     }

Connect To Database

  1.  /// <summary>
  2.  /// <c>ConnectToDbase</c> using the values set in the App.config file.
  3.  /// </summary>
  4.  /// <returns>Database connection</returns>
  5.  private Synergy.BusinessObjects.DatabaseConnection ConnectToDbase()
  6.  {
  7.      Uri Url = GetSBOAuthenticator();
  8.      Synergy.BusinessObjects.DatabaseConnection DataBase = new Synergy.BusinessObjects.DatabaseConnection(Url);
  9.      //Connection information
  10.      string DBType = ConfigurationManager.AppSettings["DBType"].ToString();
  11.      string DBServer = ConfigurationManager.AppSettings["DBServer"].ToString();
  12.      string DBDatabase = ConfigurationManager.AppSettings["DBDatabase"].ToString();
  13.      string DBUser = ConfigurationManager.AppSettings["DBUserId"].ToString();
  14.      string DBPassword = ConfigurationManager.AppSettings["DBPassword"].ToString();

  15.      DataBase.UserCredentials.UseBlind = true; //Default Value = true
  16.      DataBase.UserCredentials.DatabaseType = (DBType == "SqlServer" ? Synergy.BusinessObjects.DatabaseEngineType.SqlServer : Synergy.BusinessObjects.DatabaseEngineType.Oracle);
  17.      DataBase.UserCredentials.Server = DBServer; //Enter the Server (and instance name for SqlsErver)
  18.      DataBase.UserCredentials.Database = DBDatabase;
  19.      DataBase.UserCredentials.UserID = DBUser;
  20.      DataBase.UserCredentials.Password = DBPassword;

  21.      DataBase.Connect();

  22.      return DataBase;
  23.  }

Code Example with SQL.INI

(See: Sample Programs/Starter MultiSite for detailed code usage in your sdk kit)
Incorporate the SQL INI code to your database connection.
  1. private static void ParseSqlIni(string database, ref AuthenticationCredentials authCreds)
  2.         {
  3.             SqlINIEntry sqlINIEntry = new SqlINI().ParseSqlIni(database);
  4.             if (sqlINIEntry.HasWarning) throw (new Exception("'sql.ini' File error: " + sqlINIEntry.WarningMessage));

  5.             if (sqlINIEntry.DatabaseType == DatabaseTypeEnum.SqlServer || sqlINIEntry.DatabaseType == DatabaseTypeEnum.Oracle)
  6.             {
  7.                 if (sqlINIEntry.DatabaseType == DatabaseTypeEnum.SqlServer)
  8.                     authCreds.DatabaseType = DatabaseEngineType.SqlServer;
  9.                 else
  10.                     authCreds.DatabaseType = DatabaseEngineType.Oracle;

  11.                 authCreds.Server = sqlINIEntry.ServerName;
  12.                 authCreds.Database = sqlINIEntry.DatabaseName;
  13.             }
  14.         }

SqlINI.cs

  1. using System;
  2. using System.IO;
  3. using System.Runtime.InteropServices;
  4. using System.Text;

  5. namespace Synergy.INI
  6. {
  7.     public class SqlINI
  8.     {
  9.         #region Externals
  10.         internal static class NativeMethods
  11.         {
  12.             [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
  13.             internal static extern uint GetPrivateProfileString(
  14.                 string lpAppName,
  15.                 string lpKeyName,
  16.                 string lpDefault,
  17.                 StringBuilder lpReturnedString,
  18.                 uint nSize,
  19.                 string lpFileName);

  20.             [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
  21.             internal static extern uint GetPrivateProfileSection(
  22.                 string lpAppName,
  23.                 IntPtr lpReturnedString,
  24.                 uint nSize,
  25.                 string lpFileName);
  26.         }
  27.         #endregion

  28.         #region Enums
  29.         public enum DatabaseTypeEnum
  30.         {
  31.             None,
  32.             Oracle,
  33.             SqlServer
  34.         }
  35.         #endregion

  36.         #region SqlINIEntry class
  37.         public class SqlINIEntry
  38.         {
  39.             public DatabaseTypeEnum DatabaseType = DatabaseTypeEnum.None;
  40.             public string ServerName = string.Empty;
  41.             public string DatabaseName = string.Empty;
  42.             public string WarningMessage = string.Empty;
  43.             public bool HasWarning
  44.             {
  45.                 get
  46.                 {
  47.                     return !string.IsNullOrEmpty(WarningMessage);
  48.                 }
  49.             }
  50.         }
  51.         #endregion

  52.         #region Methods
  53.         private static string[] GetPrivateProfileSection(string sectionName, string iniFileName)
  54.         {
  55.             string[] sectionKeyArray = null;

  56.             if (!File.Exists(iniFileName)) return null;

  57.             uint MAX_BUFFER = 32767;

  58.             IntPtr pReturnedString = Marshal.AllocCoTaskMem((int)MAX_BUFFER * sizeof(char));

  59.             uint bytesReturned = NativeMethods.GetPrivateProfileSection(sectionName, pReturnedString, MAX_BUFFER, iniFileName);

  60.             if ((bytesReturned == MAX_BUFFER - 2) || (bytesReturned == 0))
  61.             {
  62.                 Marshal.FreeCoTaskMem(pReturnedString);
  63.                 return null;
  64.             }

  65.             // bytesReturned -1 to remove trailing \0

  66.             // NOTE: Calling Marshal.PtrToStringAuto(pReturnedString) will
  67.             //       result in only the first pair being returned
  68.             string returnedString = Marshal.PtrToStringAuto(pReturnedString, (int)bytesReturned - 1);

  69.             sectionKeyArray = returnedString.Split('\0');

  70.             Marshal.FreeCoTaskMem(pReturnedString);
  71.             return sectionKeyArray;
  72.         }

  73.         private string INIRead(string sectionName, string sKeyName, string iniFileName)
  74.         {
  75.             StringBuilder sb = new StringBuilder(500);
  76.             uint charCount = NativeMethods.GetPrivateProfileString(sectionName, sKeyName, string.Empty, sb, (uint)sb.Capacity, iniFileName);
  77.             if (charCount > 0) return sb.ToString().Substring(0, (int)charCount);
  78.             else return string.Empty;
  79.         }

  80.         public SqlINIEntry ParseSqlIni(string database)
  81.         {
  82.             SqlINIEntry sqlINIEntry = new SqlINIEntry();
  83.             try
  84.             {
  85.                 // sql.ini search order
  86.                 // current working dir i.e. the Visual program dir
  87.                 // %windir%\system32
  88.                 // %windir%\system
  89.                 // %windir%
  90.                 // %PATH% order

  91.                 string[] sysPaths = new string[4];
  92.                 sysPaths[0] = Path.Combine(Environment.CurrentDirectory, "sql.ini");
  93.                 sysPaths[1] = Path.Combine(Environment.GetEnvironmentVariable("windir"), @"system32\sql.ini");
  94.                 sysPaths[2] = Path.Combine(Environment.GetEnvironmentVariable("windir"), @"system\sql.ini");
  95.                 sysPaths[3] = Path.Combine(Environment.GetEnvironmentVariable("windir"), "sql.ini");

  96.                 string iniPath = string.Empty;
  97.                 for (int i = 0; i < sysPaths.Length; i++)
  98.                 {
  99.                     if (File.Exists(sysPaths[i]))
  100.                     {
  101.                         iniPath = sysPaths[i];
  102.                         break;
  103.                     }
  104.                 }

  105.                 if (string.IsNullOrEmpty(iniPath)) // We haven't found the SQL.ini file yet...
  106.                 {
  107.                     string[] environmentPaths = Environment.GetEnvironmentVariable("PATH").Split(';');
  108.                     for (int i = 0; i < environmentPaths.Length; i++)
  109.                     {
  110.                         if (File.Exists(Path.Combine(environmentPaths[i], "sql.ini")))
  111.                         {
  112.                             iniPath = Path.Combine(environmentPaths[i], "sql.ini");
  113.                             break;
  114.                         }
  115.                     }
  116.                 }

  117.                 if (!string.IsNullOrEmpty(iniPath))
  118.                 {
  119.                     // Test Name in SqlServer
  120.                     string connstring = INIRead("sqlserver", database, iniPath);
  121.                     string[] strs = connstring.Split(',');
  122.                     if (strs.Length == 2)
  123.                     {
  124.                         sqlINIEntry.DatabaseType = DatabaseTypeEnum.SqlServer;
  125.                         sqlINIEntry.ServerName = strs[0];
  126.                         sqlINIEntry.DatabaseName = strs[1];
  127.                         return sqlINIEntry; // Return if found
  128.                     }

  129.                     // Test Oracle next
  130.                     string[] oraGtwy = GetPrivateProfileSection("oragtwy", iniPath);
  131.                     if (oraGtwy != null)
  132.                     {
  133.                         foreach (string section in oraGtwy)
  134.                         {
  135.                             string REMOTEDBNAMEString = "REMOTEDBNAME=" + database.ToUpper() + ",@";
  136.                             if (section.ToUpper().StartsWith(REMOTEDBNAMEString))
  137.                             {
  138.                                 sqlINIEntry.DatabaseType = DatabaseTypeEnum.Oracle;
  139.                                 string dbName = section.ToUpper().Replace(REMOTEDBNAMEString, "");
  140.                                 sqlINIEntry.ServerName = dbName;
  141.                                 sqlINIEntry.DatabaseName = dbName;
  142.                                 return sqlINIEntry; // Return if found
  143.                             }
  144.                         }
  145.                     }

  146.                     sqlINIEntry.WarningMessage = "Can't find database name: '" + database + "' in file: " + iniPath;
  147.                 }
  148.                 else
  149.                     sqlINIEntry.WarningMessage = "Can't find 'sql.ini' file.";

  150.                 return sqlINIEntry;
  151.             }
  152.             catch (Exception ex)
  153.             {
  154.                 throw new Exception("Can't find or parse 'sql.ini' file in ParseSqlIni!" + Environment.NewLine + ex.Message + Environment.NewLine + ex.Source);
  155.             }
  156.         }
  157.         #endregion
  158.     }
  159. }

Run your own SQL Query

  1.  [TestMethod]
  2.  public void TestSQLCommand()
  3.  {
  4.      Synergy.BusinessObjects.DatabaseConnection Database = null;
  5.      try
  6.      {
  7.          Database = ConnectToDbase();
  8.          if (Database.Connected)
  9.          {
  10.              IDbCommand SQLCmd = Database.CreateNewCommand;
  11.              SQLCmd.CommandText = "SELECT COUNT(*) FROM PART";
  12.              object CmdReturn = SQLCmd.ExecuteScalar();      // Oracle returns a decimal, sql an int
  13.              if (CmdReturn != DBNull.Value)
  14.              {
  15.                  int PartCnt = 0;
  16.                  int.TryParse(CmdReturn.ToString(), out PartCnt);
  17.                  Assert.IsTrue(PartCnt > 0, "Fail, Perhaps you have no parts in dbo.PART?");
  18.              }
  19.              else
  20.                  Assert.Fail("Perhaps you have no Parts.");
  21.          }
  22.          else
  23.              Assert.Fail("Datbase Connection Failed, Check App.config");
  24.      }
  25.      catch (Exception ex)
  26.      {
  27.          Assert.Fail(ex.Message);
  28.      }
  29.      finally
  30.      {
  31.          if (Database != null) Database.Transaction = null;
  32.      }
  33.  }

Read Site Information

  1.    [TestMethod]
  2.    public void ReadSite()
  3.    {
  4.        Synergy.BusinessObjects.DatabaseConnection Database = null;
  5.        try
  6.        {
  7.            Database = ConnectToDbase();
  8.            if (Database.Connected)
  9.            {
  10.                Synergy.BusinessObjects.VE.SITE Site = new Synergy.BusinessObjects.VE.SITE(Database);
  11.                Site.ID = "%";
  12.                int Count = 0;
  13.                foreach (Synergy.BusinessObjects.VE.SITE Rec in Site.LoadLike(Site))
  14.                {
  15.                    Count += 1;
  16.                }
  17.                Assert.IsTrue(Count > 0, "Fail, did not find any Site records");
  18.            }
  19.            else
  20.                Assert.Fail("Datbase Connection Failed, Check App.config");
  21.        }
  22.        catch (Exception ex)
  23.        {
  24.            Assert.Fail(ex.Message);
  25.        }
  26.        finally
  27.        {
  28.            if (Database != null) Database.Transaction = null;
  29.        }
  30.    }

Read a Customer Record

In this sample the code will read all customer records.  Including the ones that are no longer active.
  1.   [TestMethod]
  2.   public void ReadCustomer()
  3.   {
  4.       Synergy.BusinessObjects.DatabaseConnection Database = null;
  5.       try
  6.       {
  7.           Database = ConnectToDbase();
  8.           if (Database.Connected)
  9.           {
  10.               Synergy.BusinessObjects.VE.CUSTOMER Customer = new Synergy.BusinessObjects.VE.CUSTOMER(Database);
  11.               Customer.ID = "%";
  12.               int Count = 0;
  13.               foreach (Synergy.BusinessObjects.VE.CUSTOMER Rec in Customer.LoadLike(Customer))
  14.               {
  15.                   Count += 1;
  16.               }
  17.               Assert.IsTrue(Count > 0, "Fail! Could not find any Customer records.");
  18.           }
  19.           else
  20.               Assert.Fail("Datbase Connection Failed, Check App.config");
  21.       }
  22.       catch (Exception ex)
  23.       {
  24.           Assert.Fail(ex.Message);
  25.       }
  26.       finally
  27.       {
  28.           if (Database != null) Database.Transaction = null;
  29.       }

  30.   }

Read Application Global

  1.   [TestMethod]
  2.   public void ReadApplication_Global()
  3.   {
  4.       Synergy.BusinessObjects.DatabaseConnection Database = null;
  5.       try
  6.       {
  7.           Database = ConnectToDbase();
  8.           if (Database.Connected)
  9.           {
  10.               APPLICATION_GLOBAL AppGlobal = new APPLICATION_GLOBAL(Database);
  11.               AppGlobal = AppGlobal.Load(1);

  12.               Assert.IsTrue(!string.IsNullOrEmpty(AppGlobal.COMPANY_NAME), "Fail!  Check app global for a company name");
  13.           }
  14.           else
  15.               Assert.Fail("Datbase Connection Failed, Check App.config");
  16.       }
  17.       catch (Exception ex)
  18.       {
  19.           Assert.Fail(ex.Message);
  20.       }
  21.       finally
  22.       {
  23.           if (Database != null) Database.Transaction = null;
  24.       }
  25.   }

Create a Customer Order

  1.  [TestMethod]
  2.  public void CreateCustomerOrder()
  3.  {
  4.      Synergy.BusinessObjects.DatabaseConnection Database = null;
  5.      try
  6.      {
  7.          Database = ConnectToDbase();
  8.          if (Database.Connected)
  9.          {
  10.              CUSTOMER_ORDER CustOrd = new CUSTOMER_ORDER(Database)
  11.              {
  12.                  SITE_ID = "101AMC",
  13.                  CUSTOMER_ID = "C-00001",
  14.                  STATUS = "R" //release it so we can ship it below.
  15.              };
  16.              CustOrd.Save();                   //Save it and you get the auto-generated ID
  17.              Assert.IsTrue(!string.IsNullOrEmpty(CustOrd.ID), "Fail!  Did not create an order for customer 'C-00001'");
  18.          }
  19.          else
  20.              Assert.Fail("Datbase Connection Failed, Check App.config");
  21.      }
  22.      catch (Exception ex)
  23.      {
  24.          Assert.Fail(ex.Message);
  25.      }
  26.      finally
  27.      {
  28.          if (Database != null) Database.Transaction = null;
  29.      }
  30.  }

Create a Voucher

There is a sample program, StarterMultiSite, that includes, or may be similar to,  the following code:

  1.    PAYABLE Voucher = new PAYABLE(_Database);
  2.    Voucher.SITE_ID = txtSiteId.Text;
  3.    Voucher.INVOICE_ID = txtInvoiceId.Text;
  4.    Voucher.VENDOR_ID = txtVendorId.Text;
  5.    Voucher.INVOICE_DATE = dtInvoiceDate.Value;
  6.    Voucher.TOTAL_AMOUNT = Convert.ToDecimal(txtTotalAmount.Text);

  7.    //   Voucher.POSTING_DATE = dtPostingDate.Value;       // This should be set at time of posting

  8.    PAYABLE_LINE Line = new PAYABLE_LINE(_Database);
  9.    Line.PURC_ORDER_ID = txtPOrder.Text; ;
  10.    Line.PURC_ORDER_LINE_NO = Convert.ToDecimal(txtLineNmbr.Text);
  11.    Line.QTY = Convert.ToDecimal(txtLineQty.Text);
  12.    Line.PO_UNIT_PRICE = Convert.ToDecimal(txtPOUnitPrice.Text);
  13.    Line.AMOUNT = Convert.ToDecimal(txtPOUnitPrice.Text) * Line.QTY;        // Calculate the total line amount

  14.    Line.RECEIVER_ID = txtReceiverId.Text;
  15.    Line.RECEIVER_LINE_NO = Convert.ToDecimal(txtReceiverLine.Text);
  16.    // Line.GL_ACCOUNT_ID = 

  17.    Voucher.Lines.Add(Line);
  18.    Voucher.Save();

  19.    MessageBox.Show(this, "Voucher Created", "Create Voucher", MessageBoxButtons.OK);

Create Customer Order with a Work Order

There is a sample program, StarterMultiSite, that includes, or may be similar to,  the following code:
  1.             using (new HourGlass())
  2.             {
  3.                 try
  4.                 {
  5.                     // Create a Customer Order
  6.                     CUSTOMER_ORDER co = new CUSTOMER_ORDER(_Database)
  7.                     {
  8. #if MultiSite
  9.                         SITE_ID = "MMC",
  10. #endif
  11.                         CUSTOMER_ID = "FINMAN",
  12.                         STATUS = "R" //release it so we can ship it below.
  13.                     };
  14.                     co.Save();                   //Save it and you get the auto-generated ID

  15.                     txtCustOrderId.Text = co.ID;
  16.                     txtCustOrderToShip.Text = co.ID;

  17.                     //Create an Order Line
  18.                     CUST_ORDER_LINE col = new CUST_ORDER_LINE(co)
  19.                     {
  20. #if MultiSite
  21.                         SITE_ID = co.SITE_ID,
  22. #endif
  23.                         PART_ID = "PRODUCT_P",
  24.                         USER_ORDER_QTY = 3,
  25.                         SELLING_UM = "EA"
  26.                     };
  27.                     col.Save();

  28.                     CUSTOMER_ORDER co1 = co.Load(co.ID);
  29.                     int foo = co1.Lines.Count;

  30.                     CUSTOMER_ORDER coLoader = new CUSTOMER_ORDER(_Database) { ID = "0200%" };
  31.                     List<CUSTOMER_ORDER> CoList = co.LoadLike(coLoader);
  32.                     foreach (CUSTOMER_ORDER c in CoList)
  33.                     {
  34.                         int foo2 = c.Lines.Count;
  35.                     }

  36.                     //Create a Work Order with an operation and a material 
  37.                     WORK_ORDER wo = new WORK_ORDER(_Database)
  38.                     {
  39. #if MultiSite
  40.                         SITE_ID = "MMC",
  41. #endif
  42.                         TYPE = "W",
  43.                         //wo.BASE_ID = "00_SS1"; //Don't set for auto number gen - NEXT_NUMBER_GEN table
  44.                         LOT_ID = "0",
  45.                         SPLIT_ID = "0",
  46.                         SUB_ID = "0",
  47.                         PART_ID = col.PART_ID
  48.                     };
  49.                     wo.DESIRED_QTY = wo.DESIRED_QTY;
  50.                     //wo.Save();

  51.                     //Create an operation on the WO
  52.                     OPERATION op = new OPERATION(wo)
  53.                     {
  54. #if MultiSite
  55.                         SITE_ID = wo.SITE_ID,
  56. #endif
  57.                         SEQUENCE_NO = 10,
  58.                         RESOURCE_ID = "DRILL"
  59.                     };
  60.                     //op.Save();
  61.                     wo.OPERATIONS.Add(op);

  62.                     //Add a material to the OPERATION
  63.                     REQUIREMENT req = new REQUIREMENT(op)
  64.                     {
  65. #if MultiSite
  66.                         SITE_ID = op.SITE_ID,
  67. #endif
  68.                         PART_ID = "1/4plate"
  69.                     };
  70.                     //req.Save();
  71.                     op.REQUIREMENTS.Add(req);

  72.                     wo.Save();

  73.                     txtWorkOrderId.Text = wo.BASE_ID;

  74.                     //
  75.                     //Connect the Demand fron the CO Line to the Supply from the WO
  76.                     //
  77.                     DEMAND_SUPPLY_LINK dsl = new DEMAND_SUPPLY_LINK(_Database)
  78.                     {
  79.                         SUPPLY_TYPE = "WO",
  80. #if MultiSite
  81.                         SUPPLY_SITE_ID = wo.SITE_ID,
  82. #endif
  83.                         SUPPLY_BASE_ID = wo.BASE_ID,
  84.                         SUPPLY_LOT_ID = wo.LOT_ID,
  85.                         SUPPLY_SPLIT_ID = wo.SPLIT_ID,
  86.                         SUPPLY_SUB_ID = wo.SUB_ID,

  87.                         DEMAND_TYPE = "CO",
  88. #if MultiSite
  89.                         DEMAND_SITE_ID = co.SITE_ID,
  90. #endif
  91.                         DEMAND_BASE_ID = co.ID,
  92.                         DEMAND_SEQ_NO = col.LINE_NO,
  93.                         ALLOCATED_QTY = wo.DESIRED_QTY
  94.                     };

  95.                     dsl.Save();                          //Save and the link is made
  96.                 }
  97.                 catch (Exception ex)
  98.                 {
  99.                     MessageBox.Show(ex.ToString());
  100.                 }
  101.             }

Delete a Packlist with SBO

The following code snippet demonstrates how to delete a Shipper, (Pack list), from the Infor Visual ERP database.
  1.  public bool Delete_Packlist(string packlist_id)
  2.         {
  3.             DatabaseConnection _Database;
  4.             bool result = true;
  5.             try
  6.             {
  7.                 // Add DB connection specific code here.

  8.                 using (IDbConnection conn = _Database.Connection)
  9.                 {
  10.                     conn.Open();
  11.                     SHIPPER s = new SHIPPER(_Database).Load(packlist_id);
  12.                     s.Delete();
  13.                     s.Save();
  14.                 }
  15.             }
  16.             catch (Exception ex)
  17.             {
  18.                 _Database.Transaction?.Rollback();
  19.                 result = false;
  20.             }
  21.             finally
  22.             {
  23.                 _Database.Transaction?.Dispose();
  24.                 _Database.Transaction = null;
  25.             }

  26.             return result;
  27.         }

Working with Authentication Server

For customers who have a licensed version of sbo objects,  you will need to go through Authentication server for credentials.  you will then communicate with the sbo objects using this _Database (sample connection below) connection.
  1.   private DatabaseConnection _Database;
  2.   public DatabaseConnection Database
  3.   {
  4.       get
  5.       {
  6.           if (_Database == null)
  7.           {

  8.               _Database = new DatabaseConnection("http://localhost/AuthenticationService.asmx");
  9.               _Database.UserCredentials.DatabaseType = DatabaseEngineType.SqlServer;
  10.               _Database.UserCredentials.Server = "yourservernamehere";
  11.               _Database.UserCredentials.Database = "your database VMFG here";
  12.               _Database.UserCredentials.UserID = "your program UserId here";
  13.               _Database.UserCredentials.Password = "your program UserId password here";
  14.               _Database.UserCredentials.ConnectionStringAppend = "Trusted_Connection=False;Encrypt=False;";
  15.           }
  16.           if (!_Database.Connected) _Database.Connect();
  17.              if (!_Database.Connected) MessageBox.Show(this,"No Connection","Database Connection", MessageBoxButtons.OK);
  18.           return _Database;
  19.       }
  20.   }
A call would look similar to:
  1.    CUSTOMER_ORDER CustOrder = new CUSTOMER_ORDER(Database)


Working with WM-Synergy Macro Server

Creating a callable library


When creating a library, (.dll), module the important thing to know is that there are 2 required Public Properties that must be a part of the class file.
  1.  public class MyClass
  2. {       
  3.        #region MacroServer        
  4.         public string ServerURL { get; set; }                               //Url to ServerLib of MacroServer
  5.         public string Key { get; set; }                                          // Encrypted Database Key
  6.         internal MacroServer MacroServer
  7.         {
  8.             get
  9.             {
  10.                 if (_MacroServer == null)
  11.                 {
  12.                     _MacroServer = new MacroServer(ServerURL, Key);
  13.                 }
  14.                 return _MacroServer;
  15.             }
  16.         }
  17.         #endregion
A typical WM-Synergy macro call would look like the following:
  1. dim obj
  2. lib.ActivateObject "obj", "MyFamousibrary.dll", "MyFamouslibrary.MyClass"
  3. set obj = lib.GetObject("obj")
  4. obj.Key = util.authenticationHash
  5. obj.ServerURL = util.ServerURL & "/ServerLib.asmx"
  6. obj.DatabaseType = "SQLServer"
  7. obj.MyMethod
It will be important to store your library in the working directory for the Macro Server Web API.

Create a .dll for a Macro

A Visual ERP Macro must be made as a COM compliant .dll.  In order to do this, the developer should set the following at the project level:

The next step is to set some compile directives on your base class for the .dll
Notes
It is suggested to avoid a Constructor as it may cause issues when loading the .dll (you should validate if it is an issue with your design)
  1.    [ComVisible(true)]   // Expose the class
  2.    [ClassInterface(ClassInterfaceType.None)]  // Select None, as we want to specify what is to be exposed.
  3.    [Guid("5b37be8d-293c-46ba-9503-a4ac961b7101")]  // not required would auto pull from project guid
  4.    [ProgId("CreatePPGSRequests.CreatePPGSRequests")] // suggested, should match with how it would be evoked.
  5.    public class CreatePPGSRequests
  6.    {
  7.        #region Private Variables
  8.        private MacroServer _MacroServer = null;
  9.        private DatabaseConnection _Database = null;

  10.        #endregion
  11.        #region MacroServer Required Properties
  12.        [ComVisible(true)]   // Place these here to ensure the program is making visible to com call those items you want visible
  13.        public string Key { get; set; }             // Key for Authenticator
  14.        [ComVisible(true)]
  15.        public string ServerURL { get; set; }       // MacroServer Authenticator
  16.        [ComVisible(true)]
  17.        public string DatabaseType { get; set; }    // SQLServer vs Oracle

  18.        internal MacroServer MacroServer
  19.        {
  20.            get
  21.            {
  22.                if (_MacroServer == null)
  23.                {
  24.                    _MacroServer = new MacroServer(ServerURL, Key);
  25.                }
  26.                return _MacroServer;
  27.            }
  28.        }
  29.        internal string ServerXMLURL
  30.        {
  31.            get
  32.            {
  33.                return string.Format("{0}/Credentials/{1}.xml", Regex.Replace(ServerURL, "/Serverlib.asmx", "", RegexOptions.IgnoreCase), Key);
  34.            }
  35.        }
  36.        #endregion
For each public method, make sure to add the [ComVisible(true)], this ensures that this method will be available to the vbscript. 
Notes
These extra steps help to ensure that when the project Make project com visible, is actually making visible those objects that you as a developer need exposed to the calling vbscript code base.
  1.         #region Public Methods
  2.         /// <summary>
  3.         /// <c>ProcessWorkOrder</c> 
  4.         /// <para>Create the PPGS OrderImport requests, and move inentory to a temporary holding area, 
  5.         /// until the PPGS has completed all the pulls for the given Pick.</para>
  6.         /// </summary>
  7.         /// <param name="SiteId"></param>
  8.         /// <param name="WorkOrder"></param>
  9.         /// <returns>true if success</returns>
  10.         [ComVisible(true)]
  11.         public bool ProcessWorkOrder(string SiteId, string WorkOrder, string UserId)
  12.         { ...

Sample Macro Call

When creating an SRI style macro for use with Visual ERP, make sure your .dll can be found from a directory withing Macro Server Web API directory.
  1.        Dim obj
  2. lib.ActivateObject "obj","YourSubDirectory/MyFamousDll.dll","MyFamousDll.Client"   // Note the direction of the '/' as this is going through MacroServerer API.
  3. set obj  = lib.GetObject ( "obj" )                              // Instantiate the Reflection into your .dll method
  4. obj.Key = util.authenticationHash                         // Your .dll must have a propert for Key
  5. obj.ServerUrl = util.ServerURL                              // Your .dll must have a property for ServerUrl

  6. obj.LoadForm ORDER_ID

.dll Code Template for your Visual ERP Macro method call

  1.  #region MacroServer Required Properties
  2.  public string Key { get; set; }                        // Key for Authenticator
  3.  public string ServerURL { get; set; }           // MacroServer Authenticator
  4. #endregion

If using sbo objects with your .dll then use the following code snippet to connect sbo objects
  1. private DataBaseConnection _Database = null;

  2. public bool Client()
  3. {
  4.                     _Database = new DatabaseConnection();
  5.                     _Database.UserCredentials.MacroServerXmlUrl = $"{ServerURL.Replace("/Serverlib.asmx", "")}/Credentials/{Key}.xml";
  6.                    _Database.Connect();
  7.                   using (SqlCommand SqlCmd = (SqlCommand)_Database.CreateNewCommand)
  8.                     {
  9.                       SqlCmd.CommandText = $@"SELECT DBVERSION FROM APPLICATION_GLOBAL";
  10.                      if (Convert.ToString(SqlCmd.ExecuteScalar()) != "9.0.8")
  11.                              {
  12.                               MessageBox.Show(this,"This code only works with Visual ERP 9.0.8","Connect to Server");
  13.                               return false;
  14.                            }
  15. ...

Interface with Database Server

There are two methods that can be used when your application needs to connect to the database
  1. Connect through MacroServer
  2. Connect through Synergy BusinessObjects

MacroServer

Given a connection to the Macro Server, try the following:

  1.             string SqlCmd = $@"
  2. SELECT CODE, DESCRIPTION
  3. FROM {TablePrefix}.SRI_TAX_ENTITY_USE_CODES
  4. ";
  5.             SRIMacroServer.ExecuteQueryResults Results = MacroServer.ExecuteQuery(SqlCmd);

SynergyBusinessObjects

Given a MacroServer connection one can try the following:
  1.   
         _Database = new DatabaseConnection(ServerURL);
  2.         #region MacroServer Required Properties
  3.         public string Key { get; set; }                 // Key for Authenticator
  4.         public string ServerURL { get; set; }           // MacroServer Authenticator
  5.         public string DatabaseType { get; set; }        // SQLServer vs Oracle
  6.         internal MacroServer MacroServer
  7.         {
  8.             get
  9.             {
  10.                 if (_MacroServer == null)
  11.                 {
  12.                     _MacroServer = new MacroServer(ServerURL, Key);
  13.                 }
  14.                 return _MacroServer;
  15.             }
  16.         }
  17.         internal string ServerXMLURL
  18.         {
  19.             get
  20.             {
  21.                 return string.Format("{0}/Credentials/{1}.xml", Regex.Replace(ServerURL, "/Serverlib.asmx", "", RegexOptions.IgnoreCase), Key);
  22.             }
  23.         }
  24.         #endregion
  25. public void myMethod()
    {
  26.        _Database = new DatabaseConnection();
  27.        _Database.UserCredentials.MacroServerXmlUrl = ServerXMLURL;
  28.       _Database.UserCredentials.ConnectionStringAppend = "TrustServerCertificate=True";
  29.       _Database.Connect();
  30.      _Database.Transaction = _Database.Connection.BeginTransaction();

  31.      StringBuilder SqlCmd = new StringBuilder();
  32.      SqlCmd.Append("SELECT TOP(1) [TempWarehouse], [TempLocation], [AutoProcess], [AutoEmail] FROM dbo.[SRI_TravelerConfig]");
  33.      IDbCommand GetCommand = _Database.CreateNewCommand;
  34.      GetCommand.CommandText = SqlCmd.ToString();
  35.      IDataReader RecReader = GetCommand.ExecuteReader();

Errors

A connection was successfully established with the server, but then an error occurred during the login process. (provider: SSL Provider, error: 0 - The certificate chain was issued by an authority that is not trusted.)

Causes and Solutions

1. Using a Self-Signed Certificate

If your SQL Server is using a self-signed certificate, it won't be trusted by default. You can either disable encryption or trust the self-signed certificate.

Solution: Add TrustServerCertificate=True to your connection string.

Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword;TrustServerCertificate=True;

2. Using a Certificate from a Non-Trusted Authority

If the certificate is from a non-trusted authority, you need to add it to the Trusted Root Certification Authorities store on the client machine.

Solution: Export the server certificate and install it on the client machine2.

  1. Export the server certificate using MMC.

  2. Import it into the Trusted Root Certification Authorities store on the client machine.

3. Disabling Encryption (Not Recommended)

As a quick fix, you can disable encryption in your connection string, but this is not recommended for production environments.

Solution: Add Encrypt=False to your connection string3.

Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword;Encrypt=False;

By following these steps, you can resolve the SSL provider error and establish a secure connection to your SQL Server.

    • Related Articles

    • WM-Synergy - Avalara Tax Connector - Version Info

      To Find the version of Synergy Tax. Launch Visual Manufacturing Navigate to Sales > Customer Maintenance > Macros Menu >Tax Configuration The bottom of the Tax Configuration Screen will have the version number.
    • WM-Synergy SBO - Release Notes

      Unless otherwise noted all Versions should work with a prior release of Visual ERP. The .net framework version will be discontinued. Please begin your transition over to the .net standard version of sbo objects. .Net Standard Compatibility Chart: (as ...
    • WM-Synergy - Avalara Tax - Release Notes

      v1100.1003 2025.05.11 Add more diagnostic to validate the shipping address sent mod to SRI Macros SRITAX/SRITAXC to better handle an empty Avalara return data packet Add <line1><line2><line3> to the request packet information for traceability in ...
    • WM-Synergy Macro Editor

      WM-Synergy Macro Editor This is rich client user interface, which allows for the maintenance of Synergy Created Macros that support the Infor Visual ERP Manufacturing, (VE), Visual Basic Scripts (VBScript) typically used in a VE Macro situation. Each ...
    • WM-Synergy - Avalara Tax - Visual to Avalara Mapping