4571 lines
182 KiB
C#
4571 lines
182 KiB
C#
#define PEACHW13//For now using lowest common denominator pt 2006
|
|
|
|
using System;
|
|
using System.Windows.Forms;
|
|
using GZTW.AyaNova.BLL;
|
|
using System.Data;
|
|
using System.Drawing;
|
|
using System.Reflection;
|
|
using System.Collections;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Runtime.InteropServices;
|
|
using System.Xml;
|
|
using PeachtreeAccounting;
|
|
using System.Text.RegularExpressions;
|
|
|
|
|
|
|
|
namespace AyaNova.PlugIn.PTI
|
|
{
|
|
/// <summary>
|
|
/// Summary description for Util.
|
|
/// </summary>
|
|
public class Util
|
|
{
|
|
public enum pfstat
|
|
{
|
|
OK = 0,
|
|
Failed = 1,
|
|
Cancel = 2
|
|
|
|
}
|
|
|
|
#region Attributes and properties
|
|
//case 952
|
|
public static System.Resources.ResourceManager AyaResource = null;
|
|
|
|
public static Global GlobalSettings = null;
|
|
//public static GZTW.AyaNova.BLL.Region RegionalSettings = null;
|
|
public static LocalizedTextTable LocaleText = null;
|
|
public static Integration PTI = null;
|
|
public static PTIDataEx PDat = null;
|
|
|
|
|
|
public static string QCountry = "US";
|
|
public static double QBVersion = 1.1;
|
|
public static string QCompanyFile = "";
|
|
public static string sLastRequestXML = "";
|
|
|
|
public static string PTCompany = "";
|
|
public static string PTVersion = "";
|
|
public static string PTCompanyGUID = "";
|
|
public static string PTPath = "";
|
|
//For future in case need to specify
|
|
//a particular storage location for temp files
|
|
//re: security
|
|
public static string TempFilePath
|
|
{
|
|
get { return System.IO.Path.GetTempPath(); }
|
|
}
|
|
|
|
//flagged as false if any import or export exceptions thrown
|
|
//used by mainform close method to determine of xml files
|
|
//should be deleted or not at exit
|
|
public static bool ErrorFree = true;
|
|
|
|
//Used to track if wo should be closed even if error
|
|
//as some exceptions still result in a invoice during invoicing
|
|
public static bool invoiceGenerated = true;
|
|
|
|
public static Connect ptApp = null;
|
|
|
|
|
|
/// <summary>
|
|
/// The official and unchanging integration ID for
|
|
/// PTI ({0B937F64-7BC4-4b7d-A1CF-46BD14F49918})
|
|
/// </summary>
|
|
public static Guid PTID
|
|
{
|
|
get
|
|
{
|
|
return new Guid("{0B937F64-7BC4-4b7d-A1CF-46BD14F49918}");
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
static Util()
|
|
{
|
|
|
|
}
|
|
|
|
#region General helper methods
|
|
//case 952
|
|
static public Image AyaImage(string sImageResourceName)
|
|
{
|
|
if (AyaResource == null) return new Bitmap(10, 10);//this is strictly for design mode because forms based on setbase throw exception during design
|
|
return (Image)AyaResource.GetObject(sImageResourceName);
|
|
}
|
|
static public Icon AyaIcon(string sImageResourceName)
|
|
{
|
|
return (Icon)AyaResource.GetObject(sImageResourceName);
|
|
}
|
|
|
|
|
|
static public void OpenWebURL(object oUrl)
|
|
{
|
|
|
|
if (oUrl == null) return;
|
|
string sUrl = oUrl.ToString();
|
|
if (sUrl == "") return;
|
|
|
|
|
|
if (sUrl.ToLower().StartsWith("http://"))
|
|
System.Diagnostics.Process.Start(sUrl);
|
|
else
|
|
System.Diagnostics.Process.Start("http://" + sUrl);
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Invert a color so it's readable against the passed
|
|
/// in color
|
|
/// </summary>
|
|
/// <param name="col"></param>
|
|
/// <returns></returns>
|
|
static public Color InvertColor(Color col)
|
|
{
|
|
// if(log.IsDebugEnabled)
|
|
// //case 1039 //log.Debug("InvertColor("+col.ToString()+")");
|
|
|
|
int nSourceColor = col.R + col.G + col.B;
|
|
|
|
int r = 255 - col.R;
|
|
int g = 255 - col.G;
|
|
int b = 255 - col.B;
|
|
|
|
int nInvertColor = r + g + b;
|
|
|
|
Color invert;
|
|
if (nSourceColor - nInvertColor < 28)
|
|
invert = Color.White;
|
|
else
|
|
invert = Color.FromArgb(r, g, b);
|
|
return invert;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Pre flight check
|
|
|
|
|
|
/// <summary>
|
|
/// Pre flight check, prompt user as required to repair
|
|
/// or add missing settings / failed ones
|
|
///
|
|
/// This method is called AFTER login.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public static pfstat PreFlightCheck()
|
|
{
|
|
//Go through each item sequentially, keep calling it
|
|
//while return status if fail, this way user keeps at it
|
|
//until the situation is corrected or cancels
|
|
|
|
|
|
//Peachtree initial connection here
|
|
try
|
|
{
|
|
Connect ptApp = new Connect();
|
|
bool bOpen = ptApp.app.CompanyIsOpen;
|
|
|
|
}
|
|
catch (COMException e)
|
|
{
|
|
MessageBox.Show(e.Message);
|
|
return pfstat.Failed;
|
|
}
|
|
|
|
|
|
|
|
|
|
//=====================================================
|
|
|
|
if (PTValidate() == pfstat.Cancel)
|
|
{
|
|
IntegrationLog.Log(PTID, "PFC: Unable to validate Peachtree connection, user selected cancel");
|
|
return pfstat.Cancel;
|
|
}
|
|
else
|
|
{
|
|
IntegrationLog.Log(PTID, "PFC: PT validated PTVersion=" + PTVersion + ", Company=" + PTCompany);
|
|
|
|
PopulatePTListCache();
|
|
PopulateAyaListCache();
|
|
|
|
}
|
|
|
|
|
|
|
|
IntegrationObjectCheck();
|
|
|
|
if (ValidateSettings(false) == pfstat.Cancel)
|
|
{
|
|
IntegrationLog.Log(PTID, "PFC: User settings not completed, user selected cancel");
|
|
return pfstat.Cancel;
|
|
}
|
|
|
|
|
|
//Added: 18-Nov-2006 CASE 163
|
|
//check that linked items in integration map exist in PT
|
|
if (PTI.Maps.Count == 0) return pfstat.OK;
|
|
|
|
//Missing links table:
|
|
DataTable dtTemp = new DataTable();
|
|
dtTemp.Columns.Add("MAPID", typeof(Guid));
|
|
dtTemp.Columns.Add("Name", typeof(string));
|
|
|
|
bool present = true;
|
|
foreach (IntegrationMap m in PTI.Maps)
|
|
{
|
|
present = true;
|
|
|
|
switch (m.RootObjectType)
|
|
{
|
|
case RootObjectTypes.Client:
|
|
present = PTClients.Rows.Contains(m.ForeignID);
|
|
break;
|
|
case RootObjectTypes.Vendor:
|
|
present = PTVendors.Rows.Contains(m.ForeignID);
|
|
break;
|
|
case RootObjectTypes.Rate:
|
|
case RootObjectTypes.Part:
|
|
present = PTItems.Rows.Contains(m.ForeignID);
|
|
break;
|
|
}
|
|
|
|
if (!present)
|
|
dtTemp.Rows.Add(new object[] { m.ID, m.RootObjectType.ToString() + ": " + m.Name });
|
|
|
|
}
|
|
|
|
if (dtTemp.Rows.Count > 0)
|
|
{
|
|
if (dtTemp.Rows.Count == PTI.Maps.Count)
|
|
{
|
|
//None of the items mapped match offer to remove them all
|
|
#region Nothing matches
|
|
IntegrationLog.Log(PTID, "PFC: No integration maps match PT database objects!");
|
|
|
|
DialogResult dr = MessageBox.Show("None of the mapped items in AyaNova were found in the \r\n" +
|
|
"Currently open Peachtree database.\r\n" +
|
|
"It's possible you have the wrong database open.\r\n\r\n" +
|
|
"Do you want to remove all mappings from AyaNova?", "", MessageBoxButtons.YesNoCancel,
|
|
MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button3);
|
|
|
|
if (dr == DialogResult.Yes)
|
|
{
|
|
dr = MessageBox.Show("If you select YES all mappings will be removed from AyaNova.", "", MessageBoxButtons.YesNoCancel,
|
|
MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button3);
|
|
if (dr == DialogResult.Yes)
|
|
{
|
|
IntegrationLog.Log(PTID, "PFC: User opted to remove all mappings after double warning.");
|
|
foreach (DataRow row in dtTemp.Rows)
|
|
{
|
|
PTI.Maps.Remove(row["MAPID"].ToString());
|
|
}
|
|
PTI = (Integration)PTI.Save();
|
|
return pfstat.Cancel;
|
|
}
|
|
|
|
}
|
|
#endregion
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
//some items match so iterate them and offer to delete one by one
|
|
|
|
IntegrationLog.Log(PTID, "PFC: Some integration maps do not match PT database objects");
|
|
foreach (DataRow row in dtTemp.Rows)
|
|
{
|
|
|
|
DialogResult dr = MessageBox.Show("Linked object: " + row["Name"].ToString() + "\r\n" +
|
|
"Is missing or set Inactive in Peachtree.\r\n\r\nRemove it's link from AyaNova?", "", MessageBoxButtons.YesNoCancel,
|
|
MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button3);
|
|
if (dr == DialogResult.Cancel) return pfstat.Cancel;
|
|
if (dr == DialogResult.Yes)
|
|
PTI.Maps.Remove(row["MAPID"].ToString());
|
|
}
|
|
|
|
PTI = (Integration)PTI.Save();
|
|
}
|
|
}
|
|
|
|
return pfstat.OK;
|
|
}
|
|
|
|
#region PFC AyaNova side
|
|
/// <summary>
|
|
/// Check if integration object is present in database, if not then
|
|
/// add it.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public static pfstat IntegrationObjectCheck()
|
|
{
|
|
if (PTI == null)
|
|
{
|
|
if (Integration.IntegrationExists(PTID))
|
|
{
|
|
PTI = Integration.GetItem(PTID);
|
|
//Get the Peachtree settings object
|
|
|
|
//Block below completely modified for
|
|
//Case 299
|
|
PDat = new PTIDataEx();
|
|
|
|
if (PTI.AIObject == null || PTI.AIObject.ToString() == "")
|
|
{
|
|
PTI.AIObject = PDat.XMLData;
|
|
PTI = (Integration)PTI.Save();
|
|
}
|
|
else
|
|
{
|
|
//All normal, parse xml and move on
|
|
PDat.XMLData = (string)PTI.AIObject;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PTI = Integration.NewItem(PTID);
|
|
PTI.Active = true;
|
|
PTI.AppVersion = "3.x";
|
|
PTI.Name = "AyaNova PTI - Peachtree integration";
|
|
//Case 299
|
|
PDat = new PTIDataEx();
|
|
PTI.AIObject = PDat.XMLData;
|
|
|
|
PTI = (Integration)PTI.Save();
|
|
IntegrationLog.Log(PTID, "PFC: PTI Integration object created");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
return pfstat.OK;
|
|
}
|
|
#endregion
|
|
|
|
#region PFC PT side
|
|
/// <summary>
|
|
/// Open Peachtree connection
|
|
/// gather info required for future
|
|
/// transactions
|
|
/// </summary>
|
|
public static pfstat PTValidate()
|
|
{
|
|
// We want to know if we begun a session so we can end it if an
|
|
// error happens
|
|
bool bSessionBegun = false;
|
|
|
|
|
|
|
|
while (!bSessionBegun)
|
|
{
|
|
try
|
|
{
|
|
ptApp = new Connect();
|
|
|
|
if (!ptApp.app.CompanyIsOpen)
|
|
{
|
|
if (MessageBox.Show(
|
|
"Peachtree doesn't appear to be running with a company file open on this computer.\r\n" +
|
|
"Start Peachtree (if it hasn't started already) and open your company file now before proceeding.",
|
|
"AyaNova PTI: Pre flight check",
|
|
MessageBoxButtons.RetryCancel, MessageBoxIcon.Information) == DialogResult.Cancel) return pfstat.Cancel;
|
|
|
|
}
|
|
else
|
|
bSessionBegun = true;
|
|
|
|
}
|
|
catch (System.Runtime.InteropServices.COMException ex)
|
|
{
|
|
|
|
IntegrationLog.Log(PTID, "PFC: PTValidate connect unanticipated exception: " + ex.Message);
|
|
MessageBox.Show(ex.Message);
|
|
return pfstat.Cancel;
|
|
|
|
}
|
|
}
|
|
|
|
PTCompany = ptApp.app.CurrentCompanyName;
|
|
PTVersion = ptApp.app.ProductVersion;
|
|
PTCompanyGUID = ptApp.app.CurrentCompanyGUID;
|
|
PTPath = ptApp.app.CompanyPath;
|
|
return pfstat.OK;
|
|
}
|
|
#endregion
|
|
|
|
#region PFC Check if user settings are completed and valid
|
|
/// <summary>
|
|
/// Validate the users preferences
|
|
/// if any are missing or invalid prompt for them
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public static pfstat ValidateSettings(bool ForceReset)
|
|
{
|
|
bool SetEverything = false;
|
|
if (ForceReset)
|
|
SetEverything = true;
|
|
//Display user friendly dialog
|
|
//explaining that configuration needs to be set
|
|
if (PDat.NothingSet)
|
|
{
|
|
SetEverything = true;
|
|
MessageBox.Show(
|
|
"AyaNova PTI has now connected sucessfully to both AyaNova and Peachtree.\r\n\r\n" +
|
|
"The next step is to set preferences for how AyaNova PTI will operate.\r\n\r\n" +
|
|
"AyaNova PTI will now step through each setting and get your preference\r\n" +
|
|
"in order to integrate AyaNova with Peachtree.\r\n\r\n" +
|
|
"These settings can be changed later.",
|
|
"Setup wizard", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
}
|
|
|
|
#region confirm company file
|
|
|
|
ApproveCompanyFile s0 = new ApproveCompanyFile();
|
|
|
|
s0.PTCompanyName = PTCompany.Replace("&", "&&");
|
|
s0.PTCompanyPath = PTPath;
|
|
|
|
if (s0.ShowDialog() == DialogResult.Cancel)
|
|
{
|
|
IntegrationLog.Log(PTID, "PFC: User cancelled when shown company file currently open - " + QCompanyFile);
|
|
|
|
return pfstat.Cancel;
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region WO Pre status
|
|
|
|
//Validate any existing status
|
|
if (SetEverything == false && PDat.PreWOStatus != Guid.Empty)
|
|
{
|
|
if (WorkorderStatus.Exists(PDat.PreWOStatus))
|
|
goto PRESTATUSOK;
|
|
}
|
|
else
|
|
{
|
|
//Empty pre status is valid if not first
|
|
//time setup as user can opt for selecting
|
|
//workorders of any status
|
|
if (SetEverything == false)
|
|
goto PRESTATUSOK;
|
|
}
|
|
|
|
//We've arrived here because there is no valid setting for Pre workorder status
|
|
//or it's the first time through and needs to be selected on way or another
|
|
SetWOStatus s1 = new SetWOStatus();
|
|
s1.DialogTitle = "AyaNova PTI setup - Choose billable Workorder Status";
|
|
s1.OptionTitle = "Billable workorder status";
|
|
s1.OptionDescription = "One of AyaNova PTI's tasks is to look for work orders in AyaNova \r\n" +
|
|
"that are ready to be billed out and put them in a list for your selection. \r\n" +
|
|
" \r\n" +
|
|
"By default PTI will consider work orders that are set to service completed \r\n" +
|
|
"and are not closed as it's selection criteria. \r\n" +
|
|
" \r\n" +
|
|
"In addition, you can further refine the types of work orders that PTI \r\n" +
|
|
"considers ready for billing by specifying here a particular workorder Status \r\n" +
|
|
"you want to include in addition to the default criteria. ";
|
|
s1.SelectedStatus = PDat.PreWOStatus;
|
|
s1.PreStatus = true;
|
|
if (s1.ShowDialog() == DialogResult.Cancel)
|
|
{
|
|
return pfstat.Cancel;
|
|
|
|
}
|
|
else
|
|
PDat.PreWOStatus = s1.SelectedStatus;
|
|
|
|
|
|
PRESTATUSOK:
|
|
#endregion
|
|
|
|
#region WO POST status
|
|
|
|
//Validate any existing status
|
|
if (SetEverything == false && PDat.PostWOStatus != Guid.Empty)
|
|
{
|
|
if (WorkorderStatus.Exists(PDat.PostWOStatus))
|
|
goto POSTSTATUSOK;
|
|
}
|
|
else
|
|
{
|
|
//Empty post status is valid if not first
|
|
//time setup
|
|
if (SetEverything == false)
|
|
goto POSTSTATUSOK;
|
|
}
|
|
|
|
//We've arrived here because there is no valid setting for POST workorder status
|
|
//or it's the first time through and needs to be selected on way or another
|
|
s1 = new SetWOStatus();
|
|
s1.DialogTitle = "AyaNova PTI setup - Choose post billed Workorder Status";
|
|
s1.OptionTitle = "Post billing workorder status";
|
|
s1.OptionDescription = "After PTI has billed out a work order, it can change the \r\n" +
|
|
"work order status for you automatically if desired.";
|
|
s1.SelectedStatus = PDat.PostWOStatus;
|
|
s1.PreStatus = false;
|
|
if (s1.ShowDialog() == DialogResult.Cancel)
|
|
{
|
|
return pfstat.Cancel;
|
|
|
|
}
|
|
else
|
|
PDat.PostWOStatus = s1.SelectedStatus;
|
|
s1.Dispose();
|
|
s1 = null;
|
|
|
|
POSTSTATUSOK:
|
|
#endregion
|
|
|
|
#region Outside service charge as
|
|
//Validate any existing status
|
|
if (SetEverything == false && PDat.OutsideServiceChargeAs != null && PDat.OutsideServiceChargeAs != "")
|
|
{
|
|
if (PTItems.Rows.Contains(PDat.OutsideServiceChargeAs))
|
|
goto OUTSIDESERVICECHARGEASOK;
|
|
else
|
|
{
|
|
MessageBox.Show("The Peachtree Item previously set for invoicing Outside Service items\r\n" +
|
|
"No longer appears to be valid. You will next be prompted to re-select a valid \r\n" +
|
|
"Peachtree Item.");
|
|
}
|
|
}
|
|
|
|
|
|
//We've arrived here because there is no valid setting for OutsideServiceChargeAs
|
|
SetPTChargeAs s2 = new SetPTChargeAs();
|
|
s2.DialogTitle = "AyaNova PTI setup - Charge outside service as?";
|
|
s2.OptionTitle = "Outside service";
|
|
s2.OptionDescription = "PTI needs to know what Peachtree Item you want \r\n" +
|
|
"to use when invoicing the AyaNova \"Outside service\" portion of a work order.\r\n\r\n" +
|
|
"Outside service is any 3rd party repair that is billable to the customer.\r\n\r\n" +
|
|
"This setting is mandatory / required.";
|
|
s2.PTItems = PTItems;
|
|
s2.SelectedPTItem = PDat.OutsideServiceChargeAs;
|
|
//s2.SelectedPTItem=QDat.PreWOStatus;
|
|
if (s2.ShowDialog() == DialogResult.Cancel)
|
|
{
|
|
return pfstat.Cancel;
|
|
|
|
}
|
|
else
|
|
PDat.OutsideServiceChargeAs = s2.SelectedPTItem;
|
|
s2.Dispose();
|
|
s2 = null;
|
|
|
|
OUTSIDESERVICECHARGEASOK:
|
|
|
|
#endregion
|
|
|
|
#region Misc expense charge as
|
|
//Validate any existing
|
|
if (SetEverything == false && PDat.MiscExpenseChargeAs != null && PDat.MiscExpenseChargeAs != "")
|
|
{
|
|
//if(PTItems.Rows.Contains(QDat.MiscExpenseChargeAs))
|
|
goto MISCCHARGEASOK;
|
|
// else
|
|
// {
|
|
// MessageBox.Show("The Peachtree Item previously set for invoicing Misc. Expense items\r\n" +
|
|
// "No longer appears to be valid. You will next be prompted to re-select a valid \r\n" +
|
|
// "Peachtree Item.");
|
|
// }
|
|
}
|
|
|
|
|
|
//We've arrived here because there is no valid setting for Misc expense
|
|
s2 = new SetPTChargeAs();
|
|
s2.DialogTitle = "AyaNova PTI setup - Charge Misc. Expense as?";
|
|
s2.OptionTitle = "Miscellaneous expenses";
|
|
s2.OptionDescription = "PTI needs to know what Peachtree Item you want \r\n" +
|
|
"to use when invoicing the AyaNova \"Miscellaneous expense\" portion of a work order.\r\n\r\n" +
|
|
"This setting is mandatory / required.";
|
|
s2.PTItems = PTItems;
|
|
s2.SelectedPTItem = PDat.MiscExpenseChargeAs;
|
|
|
|
if (s2.ShowDialog() == DialogResult.Cancel)
|
|
{
|
|
return pfstat.Cancel;
|
|
|
|
}
|
|
else
|
|
PDat.MiscExpenseChargeAs = s2.SelectedPTItem;
|
|
s2.Dispose();
|
|
s2 = null;
|
|
|
|
MISCCHARGEASOK:
|
|
|
|
#endregion
|
|
|
|
#region Workorder item loan charge as
|
|
//Validate any existing
|
|
if (SetEverything == false && PDat.WorkorderItemLoanChargeAs != null && PDat.WorkorderItemLoanChargeAs != "")
|
|
{
|
|
//if(PTItems.Rows.Contains(QDat.MiscExpenseChargeAs))
|
|
goto LOANCHARGEASOK;
|
|
// else
|
|
// {
|
|
// MessageBox.Show("The Peachtree Item previously set for invoicing Misc. Expense items\r\n" +
|
|
// "No longer appears to be valid. You will next be prompted to re-select a valid \r\n" +
|
|
// "Peachtree Item.");
|
|
// }
|
|
}
|
|
|
|
|
|
//We've arrived here because there is no valid setting for Misc expense
|
|
s2 = new SetPTChargeAs();
|
|
s2.DialogTitle = "AyaNova PTI setup - Charge loan item as?";
|
|
s2.OptionTitle = "Work order loans";
|
|
s2.OptionDescription = "PTI needs to know what Peachtree Item you want \r\n" +
|
|
"to use when invoicing the AyaNova \"Workorder item loan\" portion of a work order.\r\n\r\n" +
|
|
"This setting is mandatory / required.";
|
|
s2.PTItems = PTItems;
|
|
s2.SelectedPTItem = PDat.WorkorderItemLoanChargeAs;
|
|
if (s2.ShowDialog() == DialogResult.Cancel)
|
|
{
|
|
return pfstat.Cancel;
|
|
|
|
}
|
|
else
|
|
PDat.WorkorderItemLoanChargeAs = s2.SelectedPTItem;
|
|
s2.Dispose();
|
|
s2 = null;
|
|
|
|
LOANCHARGEASOK:
|
|
|
|
#endregion
|
|
|
|
|
|
#region SetMemoField
|
|
//No validation possible
|
|
//so prompt only if not setup yet
|
|
if (!SetEverything)
|
|
{
|
|
//if(PTItems.Rows.Contains(QDat.MiscExpenseChargeAs))
|
|
goto SETMEMOOK;
|
|
// else
|
|
// {
|
|
// MessageBox.Show("The Peachtree Item previously set for invoicing Misc. Expense items\r\n" +
|
|
// "No longer appears to be valid. You will next be prompted to re-select a valid \r\n" +
|
|
// "Peachtree Item.");
|
|
// }
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SetMemoField s5 = new SetMemoField();
|
|
s5.DialogTitle = "AyaNova PTI setup - Set internal note field?";
|
|
s5.OptionTitle = "Invoice internal notes field";
|
|
s5.OptionDescription =
|
|
"PTI needs to know if you want invoices that it creates \r\n" +
|
|
"in Peachtree to have their \"internal notes\" field set with\r\n" +
|
|
"information about the work order(s) that were the basis for\r\n" +
|
|
"the invoice and the name of the AyaNova user who generated them.\r\n\r\n" +
|
|
"This may be useful as a back reference, this setting is optional";
|
|
s5.FillMemoField = PDat.SetMemoField;
|
|
|
|
if (s5.ShowDialog() == DialogResult.Cancel)
|
|
{
|
|
return pfstat.Cancel;
|
|
|
|
}
|
|
else
|
|
PDat.SetMemoField = s5.FillMemoField;
|
|
s5.Dispose();
|
|
s5 = null;
|
|
|
|
SETMEMOOK:
|
|
|
|
#endregion
|
|
|
|
|
|
#region SetAutoCloseField Case 7
|
|
//No validation possible
|
|
//so prompt only if not setup yet
|
|
if (!SetEverything)
|
|
{
|
|
goto SETAUTOCLOSEOK;
|
|
|
|
}
|
|
|
|
SetAutoClose s6 = new SetAutoClose();
|
|
s6.DialogTitle = "AyaNova PTI setup - Close when invoiced?";
|
|
s6.OptionTitle = "Close work order after invoicing";
|
|
s6.OptionDescription =
|
|
"PTI needs to know if you want work orders that it invoices \r\n" +
|
|
"automatically set to closed";
|
|
s6.AutoClose = PDat.AutoClose;
|
|
|
|
if (s6.ShowDialog() == DialogResult.Cancel)
|
|
{
|
|
return pfstat.Cancel;
|
|
|
|
}
|
|
else
|
|
PDat.AutoClose = s6.AutoClose;
|
|
s6.Dispose();
|
|
s6 = null;
|
|
|
|
SETAUTOCLOSEOK:
|
|
|
|
#endregion
|
|
|
|
|
|
//Save if changes made
|
|
if (PDat.IsDirty)
|
|
{
|
|
//Case 299
|
|
PTI.AIObject = PDat.XMLData;
|
|
//PTI.AIObject=QDat;
|
|
|
|
PTI = (Integration)PTI.Save();
|
|
PDat.IsDirty = false;
|
|
}
|
|
|
|
return pfstat.OK;
|
|
}
|
|
#endregion
|
|
|
|
#endregion pfc
|
|
|
|
#region AyaNova cached lists
|
|
public static void PopulateAyaListCache()
|
|
{
|
|
//Get the cached PT data
|
|
Waiting w = new Waiting();
|
|
w.Show();
|
|
w.Ops = "Reading from AyaNova...";
|
|
|
|
w.Step = "Clients";
|
|
PopulateAyaClientList();
|
|
|
|
w.Step = "Vendors";
|
|
PopulateAyaVendorList();
|
|
|
|
w.Step = "Rates";
|
|
PopulateAyaRateList();
|
|
|
|
w.Step = "Parts";
|
|
PopulateAyaPartList();
|
|
|
|
w.Close();
|
|
}
|
|
|
|
#region AyaNova clients
|
|
|
|
private static ClientPickList _clientlist = null;
|
|
/// <summary>
|
|
/// AyaNova ClientPickList
|
|
/// </summary>
|
|
public static ClientPickList AyaClientList
|
|
{
|
|
get
|
|
{
|
|
return _clientlist;
|
|
}
|
|
}
|
|
|
|
public static void PopulateAyaClientList()
|
|
{
|
|
_clientlist = ClientPickList.GetList();
|
|
}
|
|
|
|
#endregion ayanova clients
|
|
|
|
#region AyaNova Vendors
|
|
|
|
private static VendorPickList _vendorlist = null;
|
|
/// <summary>
|
|
/// AyaNova vendor list
|
|
/// </summary>
|
|
public static VendorPickList AyaVendorList
|
|
{
|
|
get
|
|
{
|
|
return _vendorlist;
|
|
}
|
|
}
|
|
|
|
public static void PopulateAyaVendorList()
|
|
{
|
|
_vendorlist = VendorPickList.GetList();
|
|
}
|
|
|
|
#endregion ayanova vendors
|
|
|
|
#region AyaNova Rates
|
|
|
|
private static RatePickList _ratelist = null;
|
|
/// <summary>
|
|
/// AyaNova rate list
|
|
/// </summary>
|
|
public static RatePickList AyaRateList
|
|
{
|
|
get
|
|
{
|
|
return _ratelist;
|
|
}
|
|
}
|
|
|
|
public static void PopulateAyaRateList()
|
|
{
|
|
_ratelist = RatePickList.GetListAllActiveRates();
|
|
}
|
|
|
|
#endregion ayanova rates
|
|
|
|
#region AyaNova Parts
|
|
|
|
private static PartPickList _partlist = null;
|
|
/// <summary>
|
|
/// AyaNova part list
|
|
/// </summary>
|
|
public static PartPickList AyaPartList
|
|
{
|
|
get
|
|
{
|
|
return _partlist;
|
|
}
|
|
}
|
|
|
|
public static void PopulateAyaPartList()
|
|
{
|
|
_partlist = PartPickList.GetAllParts();
|
|
}
|
|
|
|
#endregion ayanova parts
|
|
|
|
#endregion
|
|
|
|
#region Peachtree cached lists / API helper methods/ attributes
|
|
/// <summary>
|
|
/// Populate or repopulate the list of
|
|
/// </summary>
|
|
public static void PopulatePTListCache()
|
|
{
|
|
//Get the cached PT data
|
|
Waiting w = new Waiting();
|
|
w.Show();
|
|
w.Ops = "Reading from Peachtree...";
|
|
|
|
w.Step = "Vendors";
|
|
PopulatePTVendorCache();
|
|
|
|
w.Step = "Customers";
|
|
PopulatePTClientCache();
|
|
|
|
w.Step = "Items";
|
|
PopulatePTItemCache();
|
|
|
|
w.Step = "Default GL Accounts";
|
|
PopulatePTDefaultAccountsCache();
|
|
|
|
w.Step = "Tax Authorities";
|
|
PopulatePTTaxAuthorityCache();
|
|
|
|
w.Step = "Tax Codes";
|
|
PopulatePTTaxCodeCache();
|
|
|
|
w.Step = "Item tax types";
|
|
PopulatePTItemTaxTypesCache();
|
|
|
|
#if(DEBUG)
|
|
w.Step = "Test export";
|
|
TestExport();
|
|
#endif
|
|
w.Close();
|
|
}
|
|
|
|
#region xml helpers
|
|
private static XmlNode CurrentNode = null;
|
|
private static string v(string xpath)
|
|
{
|
|
|
|
XmlNode n = CurrentNode.SelectSingleNode(xpath);
|
|
if (n == null) return "";
|
|
return n.InnerText;
|
|
}
|
|
|
|
|
|
|
|
private static bool vBool(string xpath)
|
|
{
|
|
|
|
XmlNode n = CurrentNode.SelectSingleNode(xpath);
|
|
if (n == null) return false;
|
|
if (n.InnerText.ToLowerInvariant() == "true")
|
|
return true;
|
|
else
|
|
return false;
|
|
|
|
}
|
|
|
|
private static int vInt(string xpath)
|
|
{
|
|
|
|
XmlNode n = CurrentNode.SelectSingleNode(xpath);
|
|
if (n == null) return 0;
|
|
return ParseInt(n.InnerText);
|
|
}
|
|
|
|
public static int ParseInt(object s)
|
|
{
|
|
if (s == null) return 0;
|
|
int d = 0;
|
|
if (!int.TryParse(s.ToString(), out d)) return 0;
|
|
return d;
|
|
}
|
|
|
|
private static decimal vDecimal(string xpath)
|
|
{
|
|
|
|
XmlNode n = CurrentNode.SelectSingleNode(xpath);
|
|
if (n == null) return 0;
|
|
|
|
return ParseDecimal(n.InnerText);
|
|
}
|
|
|
|
public static decimal ParseDecimal(object s)
|
|
{
|
|
if (s == null) return 0;
|
|
decimal d = 0;
|
|
if (!decimal.TryParse(s.ToString(), out d)) return 0;
|
|
return d;
|
|
}
|
|
#endregion
|
|
|
|
#region Peachtree "items"
|
|
public enum ptitemtype
|
|
{
|
|
Inventory,
|
|
NonInventory,
|
|
Service,
|
|
OtherCharge,
|
|
Assembly
|
|
|
|
}
|
|
|
|
private static DataTable _dtPTItems = null;
|
|
|
|
/// <summary>
|
|
/// qb items
|
|
/// </summary>
|
|
public static DataTable PTItems
|
|
{
|
|
get
|
|
{
|
|
return _dtPTItems;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Given a PT Item ID, return the
|
|
/// AyaNova Vendor ID linked to that items
|
|
/// PT preferred Vendor ID or
|
|
/// Guid empty on any problem or not found
|
|
/// </summary>
|
|
/// <param name="PTItemID"></param>
|
|
/// <returns></returns>
|
|
public static Guid AyaVendorForPTItem(string PTItemID)
|
|
{
|
|
if (PTItemID == null || PTItemID == "") return Guid.Empty;
|
|
DataRow dr = _dtPTItems.Rows.Find(PTItemID);
|
|
if (dr == null || dr["VendorID"] == null || dr["VendorID"].ToString() == "") return Guid.Empty;
|
|
|
|
DataRow drVendor = _dtPTVendors.Rows.Find(dr["VendorID"].ToString());
|
|
if (drVendor == null) return Guid.Empty;
|
|
|
|
if (!PTI.Maps.Contains(drVendor["ID"].ToString(), RootObjectTypes.Vendor)) return Guid.Empty;
|
|
|
|
//Ok we have a matching vendor in the list, return the guid of it
|
|
return PTI.Maps[drVendor["ID"].ToString(), RootObjectTypes.Vendor].RootObjectID;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Populate the cached qb data
|
|
/// billable
|
|
/// </summary>
|
|
private static void PopulatePTItemCache()
|
|
{
|
|
if (_dtPTItems == null)
|
|
{
|
|
_dtPTItems = new DataTable("PTItems");
|
|
//setup the columns
|
|
_dtPTItems.Columns.Add("ID", typeof(string));
|
|
_dtPTItems.Columns.Add("FullName", typeof(string));
|
|
_dtPTItems.Columns.Add("Type", typeof(ptitemtype));
|
|
_dtPTItems.Columns.Add("Modified", typeof(DateTime));
|
|
_dtPTItems.Columns.Add("Price", typeof(decimal));
|
|
|
|
_dtPTItems.Columns.Add("Cost", typeof(decimal));
|
|
_dtPTItems.Columns.Add("SalesDesc", typeof(string));
|
|
_dtPTItems.Columns.Add("ReorderPoint", typeof(decimal));
|
|
_dtPTItems.Columns.Add("VendorID", typeof(string));
|
|
_dtPTItems.Columns.Add("SalesAccountId", typeof(string));
|
|
_dtPTItems.Columns.Add("SalesTaxType", typeof(string));
|
|
|
|
|
|
|
|
_dtPTItems.PrimaryKey = new DataColumn[] { _dtPTItems.Columns[0] };
|
|
|
|
//Case 237
|
|
_dtPTItems.DefaultView.Sort = "FullName asc";
|
|
}
|
|
else
|
|
_dtPTItems.Clear();
|
|
|
|
try
|
|
{
|
|
|
|
#region Export
|
|
|
|
|
|
|
|
PeachtreeAccounting.Export exporter = (PeachtreeAccounting.Export)ptApp.app.CreateExporter(PeachwIEObj.peachwIEObjInventoryItemsList);
|
|
|
|
exporter.ClearExportFieldList();
|
|
exporter.AddToExportFieldList((short)PeachwIEObjInventoryItemsListField.peachwIEObjInventoryItemsListField_ItemId);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjInventoryItemsListField.peachwIEObjInventoryItemsListField_ItemDescription);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjInventoryItemsListField.peachwIEObjInventoryItemsListField_SalesDesc);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjInventoryItemsListField.peachwIEObjInventoryItemsListField_Class);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjInventoryItemsListField.peachwIEObjInventoryItemsListField_ClassDescription);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjInventoryItemsListField.peachwIEObjInventoryItemsListField_UnitPrice1);
|
|
//Last unit cost:
|
|
exporter.AddToExportFieldList((short)PeachwIEObjInventoryItemsListField.peachwIEObjInventoryItemsListField_LaborCost);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjInventoryItemsListField.peachwIEObjInventoryItemsListField_PrimeVendor);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjInventoryItemsListField.peachwIEObjInventoryItemsListField_ReorderPoint);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjInventoryItemsListField.peachwIEObjInventoryItemsListField_Inactive);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjInventoryItemsListField.peachwIEObjInventoryItemsListField_SalesAccountId);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjInventoryItemsListField.peachwIEObjInventoryItemsListField_SalesTaxType);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
exporter.SetFileType(PeachwIEFileType.peachwIEFileTypeXML);
|
|
exporter.SetFilename(TempFilePath + "PTitems.xml");
|
|
exporter.Export();
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
#region Load from export file
|
|
XmlDocument items = new XmlDocument();
|
|
|
|
items.Load(TempFilePath + "PTitems.xml");
|
|
XmlNodeList reader = items.GetElementsByTagName("PAW_Item");
|
|
|
|
for (int i = 0; i <= reader.Count - 1; i++)
|
|
{
|
|
CurrentNode = reader[i];
|
|
if (v("isInactive") == "TRUE") continue;
|
|
|
|
//skip over non ayanova related inventory items like
|
|
//text only and internal activity items and master stock items which are just a group not an actual item
|
|
if (v("Class") == "2" || v("Class") == "6" || v("Class") == "8") continue;
|
|
|
|
DataRow dr = _dtPTItems.NewRow();
|
|
|
|
dr["ID"] = v("ID");
|
|
dr["FullName"] = v("Description");
|
|
|
|
/*
|
|
* Inventory classes:
|
|
* 0 - NON stock item
|
|
* 1 - Stock item
|
|
* 2 - Text only ("Have a nice day", "thank you for your business") WTF?
|
|
* 3 - Assembly
|
|
* 4 - Service
|
|
* 5 - Labor
|
|
* 6 - Activity item (seems to be internal stuff only, for example: "(Internal) Bookkeeping and Administrative Duties for Front Office"
|
|
* 7 - Charge class item (not sure what it is, will go in other category for now)
|
|
* 8 - Master stock item (A grouping item for substock items.)
|
|
* 9 - Substock item (regular inventory item but grouped under a master stock item for easier selection I guess)
|
|
* 10 - Serialized stock item
|
|
* 11 - serialized assembly
|
|
*
|
|
* */
|
|
ptitemtype itemtype = ptitemtype.OtherCharge;
|
|
switch (v("Class"))
|
|
{
|
|
case "0":
|
|
itemtype = ptitemtype.OtherCharge;
|
|
break;
|
|
case "1":
|
|
itemtype = ptitemtype.Inventory;
|
|
break;
|
|
case "3":
|
|
itemtype = ptitemtype.Assembly;
|
|
break;
|
|
case "4":
|
|
itemtype = ptitemtype.Service;
|
|
break;
|
|
case "5":
|
|
itemtype = ptitemtype.Service;
|
|
break;
|
|
case "7":
|
|
itemtype = ptitemtype.OtherCharge;
|
|
break;
|
|
case "9":
|
|
itemtype = ptitemtype.Inventory;
|
|
break;
|
|
case "10":
|
|
itemtype = ptitemtype.Inventory;
|
|
break;
|
|
case "11":
|
|
itemtype = ptitemtype.Inventory;
|
|
break;
|
|
|
|
default://still don't know what some of the items are so they will fall into here by default
|
|
itemtype = ptitemtype.OtherCharge;
|
|
break;
|
|
|
|
}
|
|
|
|
dr["Type"] = itemtype;
|
|
dr["Modified"] = DateTime.Now;
|
|
dr["Price"] = ParseDecimal(v("Sales_Prices/Sales_Price_Info[@Key='1']"));
|
|
dr["Cost"] = ParseDecimal(v("Last_Unit_Cost"));
|
|
|
|
//Get sales description (could be empty so sub description if empty)
|
|
if (string.IsNullOrEmpty(v("Description_for_Sales")))
|
|
dr["SalesDesc"] = v("Description");
|
|
else
|
|
dr["SalesDesc"] = v("Description_for_Sales");
|
|
|
|
dr["ReorderPoint"] = ParseDecimal(v("Minimum_Stock"));
|
|
dr["VendorID"] = v("Vendor_ID");
|
|
dr["SalesAccountId"] = v("GL_Sales_Account");
|
|
dr["SalesTaxType"] = (int.Parse(v("Tax_Type")) + 1).ToString();//tax types are zero based here and 1 based in tax types xml
|
|
|
|
_dtPTItems.Rows.Add(dr);
|
|
}
|
|
#endregion
|
|
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
IntegrationLog.Log(PTID, "PopulatePTItemCache: Failed with exception:" + ex.Message);
|
|
ErrorFree = false;
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
CurrentNode = null;
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion Peachtree items
|
|
|
|
#region Peachtree "Customers"
|
|
|
|
|
|
private static DataTable _dtPTClients = null;
|
|
|
|
/// <summary>
|
|
/// PT Transaction Clients
|
|
/// </summary>
|
|
public static DataTable PTClients
|
|
{
|
|
get
|
|
{
|
|
return _dtPTClients;
|
|
}
|
|
}
|
|
|
|
#region Address structure
|
|
/// <summary>
|
|
/// Address properties
|
|
/// </summary>
|
|
public struct Address
|
|
{
|
|
|
|
public string DeliveryAddress;
|
|
public string City;
|
|
public string StateProv;
|
|
public string Country;
|
|
public string Postal;
|
|
}
|
|
|
|
#endregion
|
|
/// <summary>
|
|
/// Populate the cached qb data
|
|
/// of customers / clients
|
|
/// </summary>
|
|
private static void PopulatePTClientCache()
|
|
{
|
|
if (_dtPTClients == null)
|
|
{
|
|
_dtPTClients = new DataTable("PTClients");
|
|
|
|
//setup the columns
|
|
_dtPTClients.Columns.Add("ID", typeof(string));
|
|
_dtPTClients.Columns.Add("FullName", typeof(string));
|
|
_dtPTClients.Columns.Add("MailAddress", typeof(Address));
|
|
_dtPTClients.Columns.Add("StreetAddress", typeof(Address));
|
|
_dtPTClients.Columns.Add("Phone", typeof(string));
|
|
_dtPTClients.Columns.Add("Fax", typeof(string));
|
|
_dtPTClients.Columns.Add("AltPhone", typeof(string));
|
|
_dtPTClients.Columns.Add("Email", typeof(string));
|
|
_dtPTClients.Columns.Add("Contact", typeof(string));
|
|
_dtPTClients.Columns.Add("Created", typeof(DateTime));
|
|
_dtPTClients.Columns.Add("Modified", typeof(DateTime));
|
|
_dtPTClients.Columns.Add("Account", typeof(string));
|
|
_dtPTClients.Columns.Add("WebAddress", typeof(string));
|
|
_dtPTClients.Columns.Add("Sales_Tax_Code", typeof(string));
|
|
|
|
//Case 539
|
|
_dtPTClients.Columns.Add("Due_Days", typeof(int));
|
|
_dtPTClients.Columns.Add("Discount_Percent", typeof(decimal));
|
|
_dtPTClients.Columns.Add("Discount_Days", typeof(int));
|
|
_dtPTClients.Columns.Add("Terms_Type", typeof(bool));//If true means due on day (Due_days) of next month
|
|
_dtPTClients.Columns.Add("Use_Due_Month_End_Terms", typeof(bool));//If true means due at this month end.
|
|
|
|
_dtPTClients.PrimaryKey = new DataColumn[] { _dtPTClients.Columns[0] };
|
|
|
|
//Case 237
|
|
_dtPTClients.DefaultView.Sort = "FullName asc";
|
|
}
|
|
else
|
|
_dtPTClients.Clear();
|
|
|
|
|
|
|
|
try
|
|
{
|
|
|
|
#region Export
|
|
PeachtreeAccounting.Export exporter = (PeachtreeAccounting.Export)ptApp.app.CreateExporter(PeachwIEObj.peachwIEObjCustomerList);
|
|
|
|
exporter.ClearExportFieldList();
|
|
exporter.AddToExportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerId);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerName);
|
|
|
|
//Physical (and maybe mail) address
|
|
exporter.AddToExportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerShipTo1AddressLine1);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerShipTo1AddressLine2);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerShipTo1City);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerShipTo1State);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerShipTo1Country);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerShipTo1Zip);
|
|
|
|
|
|
|
|
//Bill to address (mailing)
|
|
exporter.AddToExportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerBillToAddressLine1);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerBillToAddressLine2);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerBillToCity);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerBillToState);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerBillToCountry);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerBillToZip);
|
|
|
|
exporter.AddToExportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerPhone1);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerFax);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerPhone2);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerEmail);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerContact);
|
|
|
|
|
|
exporter.AddToExportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerAccountNumber);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerInactive);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerURL);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerBillToTaxCode);
|
|
|
|
//Case 539
|
|
exporter.AddToExportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerDueDays);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerDiscountPercent);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerDiscountDays);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerDayIsActual);//Terms type
|
|
exporter.AddToExportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerDueMonthEnd);//useduemonthendterms
|
|
|
|
exporter.SetFileType(PeachwIEFileType.peachwIEFileTypeXML);
|
|
exporter.SetFilename(TempFilePath + "PTcustomers.xml");
|
|
exporter.Export();
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
#region Load from export file
|
|
XmlDocument customers = new XmlDocument();
|
|
customers.Load(TempFilePath + "PTcustomers.xml");
|
|
XmlNodeList reader = customers.GetElementsByTagName("PAW_Customer");
|
|
|
|
for (int i = 0; i <= reader.Count - 1; i++)
|
|
{
|
|
CurrentNode = reader[i];
|
|
if (v("isInactive") == "TRUE") continue;
|
|
DataRow dr = _dtPTClients.NewRow();
|
|
|
|
dr["ID"] = v("ID");
|
|
dr["FullName"] = v("Name");
|
|
dr["Contact"] = v("ContactName");
|
|
|
|
|
|
//Bill to (mail address) cluster
|
|
Address mail = new Address();
|
|
mail.DeliveryAddress = v("BillToAddress/Line1");
|
|
if (!string.IsNullOrEmpty(v("BillToAddress/Line2")))
|
|
mail.DeliveryAddress = mail.DeliveryAddress + "\r\n" + v("BillToAddress/Line2");
|
|
mail.City = v("BillToAddress/City");
|
|
mail.StateProv = v("BillToAddress/State");
|
|
mail.Postal = v("BillToAddress/Zip");
|
|
mail.Country = v("BillToAddress/Country");
|
|
|
|
dr["Sales_Tax_Code"] = v("BillToAddress/Sales_Tax_Code");
|
|
|
|
Address physical = new Address();
|
|
if (string.IsNullOrEmpty(v("Line1")))
|
|
{
|
|
//then copy the mail address because there is no physical address
|
|
physical.City = mail.City;
|
|
physical.Country = mail.Country;
|
|
physical.DeliveryAddress = mail.DeliveryAddress;
|
|
physical.Postal = mail.Postal;
|
|
physical.StateProv = mail.StateProv;
|
|
}
|
|
else
|
|
{
|
|
physical.DeliveryAddress = v("Line1");
|
|
if (!string.IsNullOrEmpty(v("Line2")))
|
|
physical.DeliveryAddress = physical.DeliveryAddress + "\r\n" + v("Line2");//case 813
|
|
physical.City = v("City");
|
|
physical.StateProv = v("State");
|
|
physical.Country = v("Country");
|
|
physical.Postal = v("Zip");
|
|
|
|
}
|
|
dr["MailAddress"] = mail;
|
|
dr["StreetAddress"] = physical;
|
|
|
|
dr["Phone"] = v("PhoneNumbers/PhoneNumber[@Key='1']");
|
|
dr["AltPhone"] = v("PhoneNumbers/PhoneNumber[@Key='2']");
|
|
dr["Fax"] = v("FaxNumber");
|
|
dr["Email"] = v("EMail_Address");
|
|
dr["Account"] = v("Account_Number");
|
|
dr["Created"] = DateTime.Now;
|
|
dr["Modified"] = DateTime.Now;
|
|
dr["WebAddress"] = v("Web_Address");
|
|
|
|
//Case 539
|
|
dr["Due_Days"] = vInt("Due_Days");
|
|
dr["Discount_Percent"] = vDecimal("Discount_Percent");
|
|
dr["Discount_Days"] = vInt("Discount_Days");
|
|
dr["Terms_Type"] = vBool("Terms_Type");
|
|
dr["Use_Due_Month_End_Terms"] = vBool("Use_Due_Month_End_Terms");
|
|
|
|
_dtPTClients.Rows.Add(dr);
|
|
}
|
|
#endregion
|
|
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
IntegrationLog.Log(PTID, "PopulatePTClientCache: Failed with exception:" + ex.Message);
|
|
ErrorFree = false;
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
CurrentNode = null;
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion pt clients
|
|
|
|
#region Peachtree "Vendors"
|
|
|
|
|
|
private static DataTable _dtPTVendors = null;
|
|
|
|
/// <summary>
|
|
/// PT Vendors
|
|
/// </summary>
|
|
public static DataTable PTVendors
|
|
{
|
|
get
|
|
{
|
|
return _dtPTVendors;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Populate the cached qb data
|
|
/// of Vendors
|
|
/// </summary>
|
|
private static void PopulatePTVendorCache()
|
|
{
|
|
if (_dtPTVendors == null)
|
|
{
|
|
_dtPTVendors = new DataTable("PTVendors");
|
|
|
|
//setup the columns
|
|
_dtPTVendors.Columns.Add("ID", typeof(string));
|
|
_dtPTVendors.Columns.Add("FullName", typeof(string));
|
|
_dtPTVendors.Columns.Add("MailAddress", typeof(Address));
|
|
_dtPTVendors.Columns.Add("StreetAddress", typeof(Address));
|
|
_dtPTVendors.Columns.Add("Phone", typeof(string));
|
|
_dtPTVendors.Columns.Add("Fax", typeof(string));
|
|
_dtPTVendors.Columns.Add("AltPhone", typeof(string));
|
|
_dtPTVendors.Columns.Add("Email", typeof(string));
|
|
_dtPTVendors.Columns.Add("Contact", typeof(string));
|
|
_dtPTVendors.Columns.Add("Created", typeof(DateTime));
|
|
_dtPTVendors.Columns.Add("Modified", typeof(DateTime));
|
|
_dtPTVendors.Columns.Add("Account", typeof(string));
|
|
_dtPTVendors.Columns.Add("WebAddress", typeof(string));
|
|
_dtPTVendors.PrimaryKey = new DataColumn[] { _dtPTVendors.Columns[0] };
|
|
|
|
//Case 237
|
|
_dtPTVendors.DefaultView.Sort = "FullName asc";
|
|
}
|
|
else
|
|
_dtPTVendors.Clear();
|
|
|
|
|
|
try
|
|
{
|
|
|
|
#region Export
|
|
PeachtreeAccounting.Export exporter = (PeachtreeAccounting.Export)ptApp.app.CreateExporter(PeachwIEObj.peachwIEObjVendorList);
|
|
|
|
exporter.ClearExportFieldList();
|
|
|
|
exporter.AddToExportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_VendorId);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_VendorName);
|
|
|
|
//Physical (and maybe mail) address
|
|
exporter.AddToExportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_VendorAddressLine1);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_VendorAddressLine2);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_VendorCity);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_VendorState);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_VendorCountry);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_VendorZip);
|
|
|
|
|
|
//Remit address (mailing)
|
|
exporter.AddToExportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_RemitTo1AddressLine1);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_RemitTo1AddressLine2);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_RemitTo1City);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_RemitTo1State);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_RemitTo1Country);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_RemitTo1Zip);
|
|
|
|
exporter.AddToExportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_VendorPhone1);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_VendorFax);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_VendorPhone2);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_VendorEmail);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_VendorContact);
|
|
|
|
exporter.AddToExportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_VendorOurAccountId);
|
|
|
|
exporter.AddToExportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_VendorInactive);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_byVendorURL);
|
|
|
|
|
|
exporter.SetFileType(PeachwIEFileType.peachwIEFileTypeXML);
|
|
exporter.SetFilename(TempFilePath + "PTvendors.xml");
|
|
exporter.Export();
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
#region Load from export file
|
|
XmlDocument vendors = new XmlDocument();
|
|
vendors.Load(TempFilePath + "PTvendors.xml");
|
|
XmlNodeList reader = vendors.GetElementsByTagName("PAW_Vendor");
|
|
|
|
for (int i = 0; i <= reader.Count - 1; i++)
|
|
{
|
|
CurrentNode = reader[i];
|
|
if (v("isInactive") == "TRUE") continue;
|
|
|
|
DataRow dr = _dtPTVendors.NewRow();
|
|
|
|
dr["ID"] = v("ID");
|
|
dr["FullName"] = v("Name");
|
|
dr["Contact"] = v("ContactName");
|
|
|
|
//Remit to (mail address) cluster
|
|
Address mail = new Address();
|
|
mail.DeliveryAddress = v("RemitToAddress/Line1");
|
|
if (!string.IsNullOrEmpty(v("RemitToAddress/Line2")))
|
|
mail.DeliveryAddress = mail.DeliveryAddress + "\r\n" + v("RemitToAddress/Line2");
|
|
mail.City = v("RemitToAddress/City");
|
|
mail.StateProv = v("RemitToAddress/State");
|
|
mail.Postal = v("RemitToAddress/Zip");
|
|
mail.Country = v("RemitToAddress/Country");
|
|
|
|
Address physical = new Address();
|
|
if (string.IsNullOrEmpty(v("Line1")))
|
|
{
|
|
//then copy the mail address because there is no physical address
|
|
physical.City = mail.City;
|
|
physical.Country = mail.Country;
|
|
physical.DeliveryAddress = mail.DeliveryAddress;
|
|
physical.Postal = mail.Postal;
|
|
physical.StateProv = mail.StateProv;
|
|
}
|
|
else
|
|
{
|
|
physical.DeliveryAddress = v("Line1");
|
|
if (!string.IsNullOrEmpty(v("Line2")))
|
|
physical.DeliveryAddress = mail.DeliveryAddress + "\r\n" + v("Line2");
|
|
physical.City = v("City");
|
|
physical.StateProv = v("State");
|
|
physical.Country = v("Country");
|
|
physical.Postal = v("Zip");
|
|
|
|
}
|
|
dr["MailAddress"] = mail;
|
|
dr["StreetAddress"] = physical;
|
|
|
|
dr["Phone"] = v("PhoneNumbers/PhoneNumber[@Key='1']");
|
|
dr["AltPhone"] = v("PhoneNumbers/PhoneNumber[@Key='2']");
|
|
dr["Fax"] = v("FaxNumber");
|
|
dr["Email"] = v("EMail_Address");
|
|
dr["Account"] = v("AccountNumber");
|
|
dr["Created"] = DateTime.Now;
|
|
dr["Modified"] = DateTime.Now;
|
|
dr["WebAddress"] = v("Web_Address");
|
|
_dtPTVendors.Rows.Add(dr);
|
|
}
|
|
#endregion
|
|
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
IntegrationLog.Log(PTID, "PopulatePTVendors: Failed with exception:" + ex.Message);
|
|
ErrorFree = false;
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
CurrentNode = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion pt Vendors
|
|
|
|
#region Peachtree Default gl accounts
|
|
|
|
public static string DefaultARAccount = "";
|
|
public static string DefaultSalesAccount = "";
|
|
|
|
/// Populate the cached qb data
|
|
/// of Vendors
|
|
/// </summary>
|
|
private static void PopulatePTDefaultAccountsCache()
|
|
{
|
|
|
|
|
|
|
|
try
|
|
{
|
|
|
|
#region Export
|
|
PeachtreeAccounting.Export exporter = (PeachtreeAccounting.Export)ptApp.app.CreateExporter(PeachwIEObj.peachwIEObjDefaultAccounts);
|
|
|
|
exporter.ClearExportFieldList();
|
|
|
|
exporter.AddToExportFieldList((short)PeachwIEObjDefaultAccountsField.peachwIEObjDefaultAccountsField_SalesAccountId);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjDefaultAccountsField.peachwIEObjDefaultAccountsField_ARAccountId);
|
|
|
|
|
|
exporter.SetFileType(PeachwIEFileType.peachwIEFileTypeXML);
|
|
exporter.SetFilename(TempFilePath + "PTdefaccounts.xml");
|
|
exporter.Export();
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
#region Load from export file
|
|
XmlDocument defaccounts = new XmlDocument();
|
|
defaccounts.Load(TempFilePath + "PTdefaccounts.xml");
|
|
XmlNodeList reader = defaccounts.GetElementsByTagName("PAW_DefaultAccount");
|
|
//this xml file only ever has one record in it
|
|
CurrentNode = reader[0];
|
|
DefaultARAccount = v("AR");
|
|
DefaultSalesAccount = v("Sales");
|
|
|
|
#endregion
|
|
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
IntegrationLog.Log(PTID, "PopulatePTDefaultAccountsCache: Failed with exception:" + ex.Message);
|
|
ErrorFree = false;
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
CurrentNode = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion pt default accounts
|
|
|
|
#region Peachtree "Tax Authorities"
|
|
|
|
|
|
private static DataTable _dtPTTaxAuthorities = null;
|
|
|
|
/// <summary>
|
|
/// PT Taxes
|
|
/// </summary>
|
|
public static DataTable PTTaxAuthorities
|
|
{
|
|
get
|
|
{
|
|
return _dtPTTaxAuthorities;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Populate the cached qb data
|
|
/// of Tax authorities and taxes
|
|
/// </summary>
|
|
private static void PopulatePTTaxAuthorityCache()
|
|
{
|
|
if (_dtPTTaxAuthorities == null)
|
|
{
|
|
_dtPTTaxAuthorities = new DataTable("PTTaxAuthorities");
|
|
|
|
//setup the columns
|
|
_dtPTTaxAuthorities.Columns.Add("ID", typeof(string));
|
|
_dtPTTaxAuthorities.Columns.Add("FullName", typeof(string));
|
|
_dtPTTaxAuthorities.Columns.Add("Rate", typeof(decimal));
|
|
_dtPTTaxAuthorities.Columns.Add("AccountID", typeof(string));
|
|
_dtPTTaxAuthorities.Columns.Add("VendorID", typeof(string));
|
|
_dtPTTaxAuthorities.Columns.Add("Rate2", typeof(decimal));
|
|
_dtPTTaxAuthorities.Columns.Add("UsesFormula", typeof(string));
|
|
_dtPTTaxAuthorities.Columns.Add("TaxBasis", typeof(decimal));
|
|
_dtPTTaxAuthorities.Columns.Add("TaxLimit", typeof(decimal));
|
|
|
|
_dtPTTaxAuthorities.PrimaryKey = new DataColumn[] { _dtPTTaxAuthorities.Columns[0] };
|
|
|
|
//Case 237
|
|
_dtPTTaxAuthorities.DefaultView.Sort = "FullName asc";
|
|
}
|
|
else
|
|
_dtPTTaxAuthorities.Clear();
|
|
|
|
|
|
try
|
|
{
|
|
|
|
#region Export
|
|
PeachtreeAccounting.Export exporter = (PeachtreeAccounting.Export)ptApp.app.CreateExporter(PeachwIEObj.peachwIEObjSalesTaxAuthorities);
|
|
exporter.ClearExportFieldList();
|
|
exporter.AddToExportFieldList((short)PeachwIEObjSalesTaxAuthoritiesField.peachwIEObjSalesTaxAuthoritiesField_SalesTaxAuthorityCodeId);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjSalesTaxAuthoritiesField.peachwIEObjSalesTaxAuthoritiesField_SalesTaxAuthorityCodeDescription);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjSalesTaxAuthoritiesField.peachwIEObjSalesTaxAuthoritiesField_TaxRate);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjSalesTaxAuthoritiesField.peachwIEObjSalesTaxAuthoritiesField_AccountId);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjSalesTaxAuthoritiesField.peachwIEObjSalesTaxAuthoritiesField_VendorId);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjSalesTaxAuthoritiesField.peachwIEObjSalesTaxAuthoritiesField_TaxRate2);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjSalesTaxAuthoritiesField.peachwIEObjSalesTaxAuthoritiesField_TaxUsesFormula);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjSalesTaxAuthoritiesField.peachwIEObjSalesTaxAuthoritiesField_TaxBasis);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjSalesTaxAuthoritiesField.peachwIEObjSalesTaxAuthoritiesField_TaxChangeAt);
|
|
|
|
|
|
|
|
exporter.SetFileType(PeachwIEFileType.peachwIEFileTypeXML);
|
|
exporter.SetFilename(TempFilePath + "PTtaxauth.xml");
|
|
exporter.Export();
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
#region Load from export file
|
|
XmlDocument vendors = new XmlDocument();
|
|
vendors.Load(TempFilePath + "PTtaxauth.xml");
|
|
XmlNodeList reader = vendors.GetElementsByTagName("PAW_Sales_Tax_Authority");
|
|
|
|
for (int i = 0; i <= reader.Count - 1; i++)
|
|
{
|
|
CurrentNode = reader[i];
|
|
|
|
DataRow dr = _dtPTTaxAuthorities.NewRow();
|
|
|
|
dr["ID"] = v("ID");
|
|
dr["FullName"] = v("Name");
|
|
dr["Rate"] = decimal.Parse(v("Rate"));
|
|
dr["AccountID"] = v("AccountID");
|
|
dr["VendorID"] = v("VendorID");
|
|
dr["Rate2"] = decimal.Parse(v("Rate2"));
|
|
dr["UsesFormula"] = v("UsesFormula");
|
|
dr["TaxBasis"] = decimal.Parse(v("TaxBasis"));
|
|
dr["TaxLimit"] = decimal.Parse(v("TaxLimit"));
|
|
_dtPTTaxAuthorities.Rows.Add(dr);
|
|
}
|
|
#endregion
|
|
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
IntegrationLog.Log(PTID, "PopulatePTTaxAuthorities: Failed with exception:" + ex.Message);
|
|
ErrorFree = false;
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
CurrentNode = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion pt Taxes
|
|
|
|
#region Peachtree "Tax Codes"
|
|
|
|
|
|
private static DataTable _dtPTTaxCodes = null;
|
|
|
|
/// <summary>
|
|
/// PT Taxes
|
|
/// </summary>
|
|
public static DataTable PTTaxCodes
|
|
{
|
|
get
|
|
{
|
|
return _dtPTTaxCodes;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Populate the cached qb data
|
|
/// of Tax Codes
|
|
/// </summary>
|
|
private static void PopulatePTTaxCodeCache()
|
|
{
|
|
if (_dtPTTaxCodes == null)
|
|
{
|
|
_dtPTTaxCodes = new DataTable("PTTaxCodes");
|
|
|
|
//setup the columns
|
|
_dtPTTaxCodes.Columns.Add("ID", typeof(string));
|
|
_dtPTTaxCodes.Columns.Add("FullName", typeof(string));
|
|
_dtPTTaxCodes.Columns.Add("Freight", typeof(string));//No idea what this is for
|
|
_dtPTTaxCodes.Columns.Add("Authorities", typeof(string));//comma separate list of authority id's
|
|
|
|
|
|
_dtPTTaxCodes.PrimaryKey = new DataColumn[] { _dtPTTaxCodes.Columns[0] };
|
|
|
|
//Case 237
|
|
_dtPTTaxCodes.DefaultView.Sort = "FullName asc";
|
|
}
|
|
else
|
|
_dtPTTaxCodes.Clear();
|
|
|
|
|
|
try
|
|
{
|
|
|
|
#region Export
|
|
PeachtreeAccounting.Export exporter = (PeachtreeAccounting.Export)ptApp.app.CreateExporter(PeachwIEObj.peachwIEObjSalesTaxCodes);
|
|
exporter.ClearExportFieldList();
|
|
exporter.AddToExportFieldList((short)PeachwIEObjSalesTaxCodesField.peachwIEObjSalesTaxCodesField_SalesTaxCodeId);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjSalesTaxCodesField.peachwIEObjSalesTaxCodesField_SalesTaxCodeDescription);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjSalesTaxCodesField.peachwIEObjSalesTaxCodesField_TaxFreight);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjSalesTaxCodesField.peachwIEObjSalesTaxCodesField_AuthId);
|
|
exporter.SetFileType(PeachwIEFileType.peachwIEFileTypeXML);
|
|
exporter.SetFilename(TempFilePath + "PTtaxcodes.xml");
|
|
exporter.Export();
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
#region Load from export file
|
|
XmlDocument vendors = new XmlDocument();
|
|
vendors.Load(TempFilePath + "PTtaxcodes.xml");
|
|
XmlNodeList reader = vendors.GetElementsByTagName("PAW_Sales_Tax_Code");
|
|
|
|
for (int i = 0; i <= reader.Count - 1; i++)
|
|
{
|
|
CurrentNode = reader[i];
|
|
|
|
DataRow dr = _dtPTTaxCodes.NewRow();
|
|
|
|
dr["ID"] = v("ID");
|
|
dr["FullName"] = v("Description");
|
|
dr["Freight"] = v("Freight");
|
|
XmlNode n = CurrentNode.SelectSingleNode("Authorities");
|
|
XmlNodeList subreader = n.ChildNodes;
|
|
string sAuthorities = "";
|
|
foreach (XmlNode nsub in subreader)
|
|
{
|
|
sAuthorities += nsub.SelectSingleNode("ID").InnerText + ",";
|
|
}
|
|
dr["Authorities"] = sAuthorities.TrimEnd(',');
|
|
|
|
_dtPTTaxCodes.Rows.Add(dr);
|
|
}
|
|
#endregion
|
|
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
IntegrationLog.Log(PTID, "PopulatePTTaxCodes: Failed with exception:" + ex.Message);
|
|
ErrorFree = false;
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
CurrentNode = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion pt Taxes
|
|
|
|
#region Peachtree "ItemTaxTypes"
|
|
|
|
|
|
private static DataTable _dtPTItemTaxTypes = null;
|
|
|
|
/// <summary>
|
|
/// PT Taxes
|
|
/// </summary>
|
|
public static DataTable PTItemTaxTypes
|
|
{
|
|
get
|
|
{
|
|
return _dtPTItemTaxTypes;
|
|
}
|
|
}
|
|
|
|
//Case 559
|
|
public static string firstNonTaxableTaxCode = "";
|
|
public static string FirstNonTaxableTaxCode
|
|
{
|
|
get
|
|
{
|
|
if (firstNonTaxableTaxCode == "")
|
|
{
|
|
firstNonTaxableTaxCode = "2";//just a default in case something else goes wrong
|
|
}
|
|
|
|
return firstNonTaxableTaxCode;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines if a particular item has a taxable tax type set
|
|
/// </summary>
|
|
/// <param name="Item"></param>
|
|
/// <returns></returns>
|
|
public static bool IsTaxable(string Item)
|
|
{
|
|
|
|
DataRow drItem = PTItems.Rows.Find(Item);
|
|
DataRow drTaxType = PTItemTaxTypes.Rows.Find(drItem["SalesTaxType"]);
|
|
if (drTaxType == null) return false;
|
|
|
|
return (drTaxType["IsTaxable"].ToString() == "TRUE");
|
|
|
|
// ["SalesTaxType"]
|
|
//
|
|
// PTItems.Rows.Find(
|
|
// dr["ID"].ToString()
|
|
// )["SalesTaxType"]
|
|
// )["IsTaxable"].ToString()=="TRUE"
|
|
}
|
|
|
|
/// <summary>
|
|
/// Populate the cached qb data
|
|
/// of Item Tax type codes (is taxable)
|
|
/// </summary>
|
|
private static void PopulatePTItemTaxTypesCache()
|
|
{
|
|
if (_dtPTItemTaxTypes == null)
|
|
{
|
|
_dtPTItemTaxTypes = new DataTable("PTItemTaxTypes");
|
|
//setup the columns
|
|
_dtPTItemTaxTypes.Columns.Add("Number", typeof(string));
|
|
_dtPTItemTaxTypes.Columns.Add("IsTaxable", typeof(string));
|
|
_dtPTItemTaxTypes.PrimaryKey = new DataColumn[] { _dtPTItemTaxTypes.Columns[0] };
|
|
}
|
|
else
|
|
_dtPTItemTaxTypes.Clear();
|
|
try
|
|
{
|
|
|
|
#region Export
|
|
PeachtreeAccounting.Export exporter = (PeachtreeAccounting.Export)ptApp.app.CreateExporter(PeachwIEObj.peachwIEObjItemTaxTypes);
|
|
exporter.ClearExportFieldList();
|
|
exporter.AddToExportFieldList((short)PeachwIEObjItemTaxTypesField.peachwIEObjItemTaxTypesField_Number);
|
|
exporter.AddToExportFieldList((short)PeachwIEObjItemTaxTypesField.peachwIEObjItemTaxTypesField_IsTaxable);
|
|
exporter.SetFileType(PeachwIEFileType.peachwIEFileTypeXML);
|
|
exporter.SetFilename(TempFilePath + "PTitemtaxtypes.xml");
|
|
exporter.Export();
|
|
#endregion
|
|
|
|
#region Load from export file
|
|
XmlDocument vendors = new XmlDocument();
|
|
vendors.Load(TempFilePath + "PTitemtaxtypes.xml");
|
|
XmlNodeList reader = vendors.GetElementsByTagName("PAW_Item_Tax_Type");
|
|
for (int i = 0; i <= reader.Count - 1; i++)
|
|
{
|
|
CurrentNode = reader[i];
|
|
|
|
DataRow dr = _dtPTItemTaxTypes.NewRow();
|
|
|
|
dr["Number"] = v("Number");
|
|
dr["IsTaxable"] = v("IsTaxable");
|
|
//Case 559
|
|
//get the lowest non taxable tax code because pt barfs if you use the highest
|
|
if (firstNonTaxableTaxCode == "" && dr["IsTaxable"].ToString() == "TRUE")
|
|
firstNonTaxableTaxCode = dr["Number"].ToString();
|
|
_dtPTItemTaxTypes.Rows.Add(dr);
|
|
}
|
|
#endregion
|
|
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
IntegrationLog.Log(PTID, "PopulatePTItemTaxTypes: Failed with exception:" + ex.Message);
|
|
ErrorFree = false;
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
CurrentNode = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion pt item tax types
|
|
|
|
#region Peachtree Test for viewing xml file structure
|
|
/// <summary>
|
|
/// Text export from peachtree
|
|
/// </summary>
|
|
private static void TestExport()
|
|
{
|
|
try
|
|
{
|
|
#region Export
|
|
PeachtreeAccounting.Export exporter = (PeachtreeAccounting.Export)ptApp.app.CreateExporter(PeachwIEObj.peachwIEObjSalesJournal);
|
|
|
|
exporter.ClearExportFieldList();
|
|
|
|
|
|
exporter.SetFileType(PeachwIEFileType.peachwIEFileTypeXML);
|
|
exporter.SetFilename(TempFilePath + "PTtestexport.xml");
|
|
exporter.Export();
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
IntegrationLog.Log(PTID, "TestExport: Failed with exception:" + ex.Message);
|
|
ErrorFree = false;
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
CurrentNode = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion TESTING
|
|
|
|
#endregion
|
|
|
|
#region Import to AyaNova
|
|
|
|
#region customer
|
|
/// <summary>
|
|
/// Import the indicated customer
|
|
/// to an AyaNova client record
|
|
/// </summary>
|
|
/// <param name="PeachtreeID"></param>
|
|
/// <param name="alErrors">An arraylist to hold strings indicating errors on fail</param>
|
|
public static void ImportPTCustomer(string PeachtreeID, ArrayList alErrors)
|
|
{
|
|
|
|
DataRow dr = _dtPTClients.Rows.Find(PeachtreeID);
|
|
//PTListID not found in client list?
|
|
if (dr == null)
|
|
{
|
|
alErrors.Add("ImportPTCustomer: ID not found " + PeachtreeID);
|
|
return;
|
|
}
|
|
|
|
string sName = dr["FullName"].ToString();
|
|
if (sName.Length > 255)
|
|
{
|
|
alErrors.Add("ImportPTCustomer: Peachtree customer name exceeds 255 character limit for AyaNova\r\n" +
|
|
"Name: " + dr["FullName"].ToString() + "\r\n" +
|
|
"was imported as: " + sName);
|
|
sName = sName.Substring(0, 255);
|
|
}
|
|
try
|
|
{
|
|
//already a client by that name
|
|
if (Client.Exists(Guid.Empty, dr["FullName"].ToString()))
|
|
{
|
|
alErrors.Add("ImportPTCustomer: " + dr["FullName"].ToString() + " already exists in AyaNova");
|
|
return;
|
|
}
|
|
|
|
//Import seems safe...
|
|
|
|
Client c = Client.NewItem();
|
|
c.Name = sName;//1
|
|
Address a = (Address)dr["MailAddress"];
|
|
c.MailToAddress.DeliveryAddress = a.DeliveryAddress;//2
|
|
c.MailToAddress.City = a.City;//3
|
|
c.MailToAddress.StateProv = a.StateProv;//4
|
|
c.MailToAddress.Country = a.Country;//5
|
|
c.MailToAddress.Postal = a.Postal;//6
|
|
|
|
a = (Address)dr["StreetAddress"];
|
|
c.GoToAddress.DeliveryAddress = a.DeliveryAddress;//7
|
|
c.GoToAddress.City = a.City;//8
|
|
c.GoToAddress.StateProv = a.StateProv;//9
|
|
c.GoToAddress.Country = a.Country;//10
|
|
c.GoToAddress.Postal = a.Postal;//11
|
|
|
|
//Case 518
|
|
c.PopulateBothAddresses();
|
|
|
|
c.Contact = dr["Contact"].ToString();
|
|
|
|
|
|
//Phone field
|
|
if (dr["Phone"].ToString() != "")
|
|
{
|
|
|
|
c.Phone1 = dr["Phone"].ToString();//14
|
|
|
|
}
|
|
|
|
//Fax field
|
|
if (dr["Fax"].ToString() != "")
|
|
{
|
|
|
|
c.Phone2 = dr["Fax"].ToString();//15
|
|
}
|
|
|
|
//AltPhone field
|
|
if (dr["AltPhone"].ToString() != "")
|
|
{
|
|
c.Phone3 = dr["AltPhone"].ToString();//16
|
|
}
|
|
|
|
//Email field
|
|
if (dr["Email"].ToString() != "")
|
|
{
|
|
c.Email = dr["Email"].ToString();//17
|
|
}
|
|
|
|
//Account number field
|
|
if (dr["Account"].ToString() != "")
|
|
{
|
|
c.AccountNumber = dr["Account"].ToString();//18
|
|
}
|
|
|
|
if (!c.IsSavable)
|
|
{
|
|
alErrors.Add("ImportPTCustomer: AyaNova won't allow import of " + c.Name + "\r\n" +
|
|
"Due to the following broken rules:\r\n" + c.GetBrokenRulesString());
|
|
return;
|
|
}
|
|
|
|
c.WebAddress = dr["WebAddress"].ToString();
|
|
|
|
c = (Client)c.Save();
|
|
//Link
|
|
IntegrationMap m = PTI.Maps.Add(PTI);
|
|
m.Name = sName;
|
|
m.RootObjectID = c.ID;
|
|
m.RootObjectType = RootObjectTypes.Client;
|
|
m.LastSync = DateTime.Now;
|
|
m.ForeignID = PeachtreeID;
|
|
PTI = (Integration)PTI.Save();
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
//crack the exception in case it's a generic dataportal one
|
|
//and it is if it's got an inner exception of any kind
|
|
|
|
alErrors.Add("ImportPTCustomer: AyaNova won't allow import / link of " + sName + "\r\n" +
|
|
"Due to the following error:\r\n" + CrackException(ex));
|
|
ErrorFree = false;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Vendor
|
|
|
|
/// <summary>
|
|
/// Import the indicated Vendor
|
|
/// to an AyaNova vendor record
|
|
/// </summary>
|
|
/// <param name="PeachtreeID"></param>
|
|
/// <param name="alErrors">An arraylist to hold strings indicating errors on fail</param>
|
|
public static void ImportPTVendor(string PeachtreeID, VendorTypes AsVendorType, ArrayList alErrors)
|
|
{
|
|
|
|
DataRow dr = _dtPTVendors.Rows.Find(PeachtreeID);
|
|
//PTListID not found in Vendor list?
|
|
if (dr == null)
|
|
{
|
|
alErrors.Add("ImportPTVendor: ID not found " + PeachtreeID);
|
|
return;
|
|
}
|
|
|
|
string sName = dr["FullName"].ToString();
|
|
if (sName.Length > 255)
|
|
{
|
|
alErrors.Add("ImportPTVendor: Peachtree Vendor name exceeds 255 character limit for AyaNova\r\n" +
|
|
"Name: " + dr["FullName"].ToString() + "\r\n" +
|
|
"was imported as: " + sName);
|
|
sName = sName.Substring(0, 255);
|
|
}
|
|
try
|
|
{
|
|
//already a Vendor by that name
|
|
if (Vendor.Exists(Guid.Empty, dr["FullName"].ToString()))
|
|
{
|
|
alErrors.Add("ImportPTVendor: " + dr["FullName"].ToString() + " already exists in AyaNova");
|
|
return;
|
|
}
|
|
|
|
//Import seems safe...
|
|
|
|
Vendor c = Vendor.NewItem();
|
|
c.VendorType = AsVendorType;
|
|
c.Name = sName;
|
|
|
|
|
|
Address a = (Address)dr["MailAddress"];
|
|
c.MailToAddress.DeliveryAddress = a.DeliveryAddress;
|
|
c.MailToAddress.City = a.City;
|
|
c.MailToAddress.StateProv = a.StateProv;
|
|
c.MailToAddress.Country = a.Country;
|
|
c.MailToAddress.Postal = a.Postal;
|
|
|
|
a = (Address)dr["StreetAddress"];
|
|
c.GoToAddress.DeliveryAddress = a.DeliveryAddress;
|
|
c.GoToAddress.City = a.City;
|
|
c.GoToAddress.StateProv = a.StateProv;
|
|
c.GoToAddress.Country = a.Country;
|
|
c.GoToAddress.Postal = a.Postal;
|
|
|
|
c.Contact = dr["Contact"].ToString();
|
|
|
|
//Phone field
|
|
if (dr["Phone"].ToString() != "")
|
|
{
|
|
c.Phone1 = dr["Phone"].ToString();
|
|
}
|
|
|
|
//Fax field
|
|
if (dr["Fax"].ToString() != "")
|
|
{
|
|
c.Phone2 = dr["Fax"].ToString();
|
|
}
|
|
|
|
//AltPhone field
|
|
if (dr["AltPhone"].ToString() != "")
|
|
{
|
|
c.Phone3 = dr["AltPhone"].ToString();
|
|
}
|
|
|
|
//Email field
|
|
if (dr["Email"].ToString() != "")
|
|
{
|
|
c.Email = dr["Email"].ToString();
|
|
}
|
|
|
|
//Account number
|
|
if (dr["Account"].ToString() != "")
|
|
{
|
|
c.AccountNumber = dr["Account"].ToString();
|
|
}
|
|
|
|
c.WebAddress = dr["WebAddress"].ToString();
|
|
|
|
if (!c.IsSavable)
|
|
{
|
|
alErrors.Add("ImportPTVendor: AyaNova won't allow import of " + c.Name + "\r\n" +
|
|
"Due to the following broken rules:\r\n" + c.GetBrokenRulesString());
|
|
return;
|
|
}
|
|
|
|
|
|
c = (Vendor)c.Save();
|
|
//Link
|
|
IntegrationMap m = PTI.Maps.Add(PTI);
|
|
m.Name = sName;
|
|
m.RootObjectID = c.ID;
|
|
m.RootObjectType = RootObjectTypes.Vendor;
|
|
m.LastSync = DateTime.Now;
|
|
m.ForeignID = PeachtreeID;
|
|
PTI = (Integration)PTI.Save();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
//crack the exception in case it's a generic dataportal one
|
|
//and it is if it's got an inner exception of any kind
|
|
if (ex.InnerException != null) ex = ex.InnerException;
|
|
alErrors.Add("ImportPTVendor: AyaNova won't allow import / link of " + sName + "\r\n" +
|
|
"Due to the following error:\r\n" + ex.Message);
|
|
ErrorFree = false;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Rate
|
|
|
|
/// <summary>
|
|
/// Import the indicated PT Item
|
|
/// to an AyaNova Rate record
|
|
/// </summary>
|
|
/// <param name="PeachtreeID"></param>
|
|
/// <param name="alErrors">An arraylist to hold strings indicating errors on fail</param>
|
|
public static void ImportPTRate(string PeachtreeID, RateTypes AsRateType, Guid MostLikelyRateUnitChargeDescriptionID, ArrayList alErrors)
|
|
{
|
|
|
|
DataRow dr = _dtPTItems.Rows.Find(PeachtreeID);
|
|
//PTListID not found in Rate list?
|
|
if (dr == null)
|
|
{
|
|
alErrors.Add("ImportPTRate: ID not found " + PeachtreeID);
|
|
return;
|
|
}
|
|
|
|
string sName = dr["FullName"].ToString();
|
|
if (sName.Length > 255)
|
|
{
|
|
alErrors.Add("ImportPTRate: Peachtree Rate name exceeds 255 character limit for AyaNova\r\n" +
|
|
"Name: " + dr["FullName"].ToString() + "\r\n" +
|
|
"was imported as: " + sName);
|
|
sName = sName.Substring(0, 255);
|
|
}
|
|
try
|
|
{
|
|
//already a Rate by that name
|
|
if (Rate.Exists(Guid.Empty, dr["FullName"].ToString()))
|
|
{
|
|
alErrors.Add("ImportPTRate: " + dr["FullName"].ToString() + " already exists in AyaNova");
|
|
return;
|
|
}
|
|
|
|
//Import seems safe...
|
|
Rates rates = Rates.GetItems(false);
|
|
Rate c = rates.Add();
|
|
c.RateType = AsRateType;
|
|
c.Name = sName;
|
|
c.Charge = (decimal)dr["Price"];
|
|
c.ContractRate = false;
|
|
c.Cost = (decimal)dr["Cost"];
|
|
c.Description = T(255, dr["SalesDesc"].ToString());
|
|
c.RateUnitChargeDescriptionID = MostLikelyRateUnitChargeDescriptionID;
|
|
|
|
|
|
|
|
if (!c.IsSavable)
|
|
{
|
|
alErrors.Add("ImportPTRate: AyaNova won't allow import of " + c.Name + "\r\n" +
|
|
"Due to the following broken rules:\r\n" + c.GetBrokenRulesString());
|
|
return;
|
|
}
|
|
|
|
|
|
rates = (Rates)rates.Save();
|
|
//Link
|
|
IntegrationMap m = PTI.Maps.Add(PTI);
|
|
m.Name = sName;
|
|
m.RootObjectID = c.ID;
|
|
m.RootObjectType = RootObjectTypes.Rate;
|
|
m.LastSync = DateTime.Now;
|
|
m.ForeignID = PeachtreeID;
|
|
PTI = (Integration)PTI.Save();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
//crack the exception in case it's a generic dataportal one
|
|
//and it is if it's got an inner exception of any kind
|
|
if (ex.InnerException != null) ex = ex.InnerException;
|
|
alErrors.Add("ImportPTRate: AyaNova won't allow import / link of " + sName + "\r\n" +
|
|
"Due to the following error:\r\n" + ex.Message);
|
|
ErrorFree = false;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Part
|
|
|
|
/// <summary>
|
|
/// Import the indicated PT Item
|
|
/// to an AyaNova Part record
|
|
/// </summary>
|
|
/// <param name="PeachtreeID"></param>
|
|
/// <param name="alErrors">An arraylist to hold strings indicating errors on fail</param>
|
|
public static void ImportPTPart(string PeachtreeID, ArrayList alErrors)
|
|
{
|
|
|
|
DataRow dr = _dtPTItems.Rows.Find(PeachtreeID);
|
|
//PTListID not found in Part list?
|
|
if (dr == null)
|
|
{
|
|
alErrors.Add("ImportPTPart: ID not found " + PeachtreeID);
|
|
return;
|
|
}
|
|
|
|
string sName = dr["SalesDesc"].ToString();
|
|
if (sName.Length > 255)
|
|
{
|
|
sName = sName.Substring(0, 255);
|
|
alErrors.Add("ImportPTPart: Peachtree Part name exceeds 255 character limit for AyaNova part name\r\n" +
|
|
"Name: " + dr["SalesDesc"].ToString() + "\r\n" +
|
|
"was imported as: " + sName);
|
|
|
|
}
|
|
try
|
|
{
|
|
//already a Part by that number?
|
|
if (Part.Exists(Guid.Empty, dr["ID"].ToString()))
|
|
{
|
|
alErrors.Add("ImportPTPart: Part number " + dr["ID"].ToString() + " already exists in AyaNova");
|
|
return;
|
|
}
|
|
|
|
//Import seems safe...
|
|
Part c = Part.NewItem();
|
|
c.PartNumber = dr["ID"].ToString();
|
|
c.Name = sName;
|
|
c.WholesalerID = AyaVendorForPTItem(PeachtreeID);
|
|
c.Retail = (decimal)dr["Price"];
|
|
c.Cost = (decimal)dr["Cost"];
|
|
|
|
|
|
|
|
if (!c.IsSavable)
|
|
{
|
|
alErrors.Add("ImportPTPart: AyaNova won't allow import of " + c.Name + "\r\n" +
|
|
"Due to the following broken rules:\r\n" + c.GetBrokenRulesString());
|
|
return;
|
|
}
|
|
|
|
//Save and get ready to provide the ID
|
|
c = (Part)c.Save();
|
|
|
|
//Link
|
|
IntegrationMap m = PTI.Maps.Add(PTI);
|
|
m.Name = sName;
|
|
m.RootObjectID = c.ID;
|
|
m.RootObjectType = RootObjectTypes.Part;
|
|
m.LastSync = DateTime.Now;
|
|
m.ForeignID = PeachtreeID;
|
|
PTI = (Integration)PTI.Save();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
//crack the exception in case it's a generic dataportal one
|
|
//and it is if it's got an inner exception of any kind
|
|
if (ex.InnerException != null) ex = ex.InnerException;
|
|
alErrors.Add("ImportPTPart: AyaNova won't allow import / link of " + sName + "\r\n" +
|
|
"Due to the following error:\r\n" + ex.Message);
|
|
ErrorFree = false;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#endregion Import to AyaNova
|
|
|
|
#region Export to Peachtree
|
|
#region ID builder
|
|
/// <summary>
|
|
/// Given a fullname generate a unique ID for Peachtree
|
|
/// </summary>
|
|
/// <param name="FullName">Full name of object</param>
|
|
/// <param name="dtDest">Table to scan for uniqueness</param>
|
|
/// <returns></returns>
|
|
private static string BuildID(string FullName, DataTable dtDest)
|
|
{
|
|
string sID = "";
|
|
//generate an id similar to how peachtree sample data is set up
|
|
//first split the full name into separate groups based on whitespace
|
|
//Then keep adding to the id the next batch of non whitespace characters
|
|
//check if already exists, if it does then keep going until it's unique or
|
|
//the limit of 20 characters has been reached
|
|
//If the limit has been reached use the first 18 characters plus an incrementing int
|
|
//up to 99, if it still doesn't come out unique then just throw an exception and bomb out
|
|
Regex r = new Regex(
|
|
@"\w+",
|
|
RegexOptions.IgnoreCase
|
|
| RegexOptions.Multiline
|
|
| RegexOptions.IgnorePatternWhitespace
|
|
| RegexOptions.Compiled
|
|
);
|
|
|
|
bool bGotUniqueID = false;
|
|
MatchCollection mc = r.Matches(FullName.ToUpper());
|
|
foreach (Match m in mc)
|
|
{
|
|
if (bGotUniqueID) break;
|
|
sID = sID + m.Value;
|
|
|
|
if (sID.Length > 20)
|
|
{
|
|
sID = sID.Substring(0, 20);
|
|
|
|
//first time in, try it cut off at 20, if unique then bob's your uncle
|
|
bGotUniqueID = !dtDest.Rows.Contains(sID);
|
|
if (bGotUniqueID) break;
|
|
|
|
//still not unique so start appending different numbers until it is
|
|
for (int x = 1; x < 100; x++)
|
|
{
|
|
sID = sID.Substring(0, 18) + x.ToString();
|
|
bGotUniqueID = !dtDest.Rows.Contains(sID);
|
|
if (bGotUniqueID) break;
|
|
}
|
|
if (!bGotUniqueID)
|
|
throw new System.ApplicationException("BuildID: Unable to come up with unique ID value for " + FullName + "\r\nCan't import");
|
|
}
|
|
|
|
bGotUniqueID = !dtDest.Rows.Contains(sID);
|
|
|
|
|
|
}
|
|
|
|
//Case 342
|
|
if (!bGotUniqueID)
|
|
{
|
|
//We're here because we've run out of matches (as above) and still not got a unique name
|
|
//and also the item is under 20 characters in length
|
|
//still not unique so start appending different numbers until it is
|
|
for (int x = 1; x < 100; x++)
|
|
{
|
|
bGotUniqueID = !dtDest.Rows.Contains(sID + x.ToString());
|
|
if (bGotUniqueID)
|
|
{
|
|
sID = sID + x.ToString();
|
|
break;
|
|
}
|
|
}
|
|
if (!bGotUniqueID)
|
|
throw new System.ApplicationException("BuildID: Unable to come up with unique ID value for " + FullName + "\r\nCan't import");
|
|
|
|
}
|
|
|
|
return sID;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Customer
|
|
/// <summary>
|
|
/// Import the indicated client
|
|
/// to Peachtree customer record
|
|
/// </summary>
|
|
/// <param name="ClientID"></param>
|
|
/// <param name="alErrors">An arraylist to hold strings indicating errors on fail</param>
|
|
public static void ImportAyaClient(Guid ClientID, ArrayList alErrors)
|
|
{
|
|
|
|
|
|
if (!Client.Exists(ClientID, ""))
|
|
{
|
|
alErrors.Add("ImportAyaClient: Client not found in AyaNova (deleted recently?) (" + ClientID.ToString() + ")");
|
|
return;
|
|
|
|
}
|
|
Client c = Client.GetItem(ClientID);
|
|
|
|
|
|
//Case 523
|
|
//Note that this is temporary as client is not saved so won't change AyaNova data
|
|
c.PopulateBothAddresses();
|
|
|
|
string sName = c.Name;
|
|
if (sName.Length > 39)
|
|
{
|
|
sName = sName.Substring(0, 39);
|
|
alErrors.Add("ImportAyaClient: AyaNova client name exceeds 39 character limit for Peachtree\r\n" +
|
|
"Name: " + c.Name + "\r\n" +
|
|
"will be imported as: " + sName);
|
|
|
|
}
|
|
|
|
string sID = BuildID(sName, PTClients);
|
|
|
|
|
|
|
|
try
|
|
{
|
|
#region Generate import file
|
|
XmlTextWriter Writer = new XmlTextWriter(TempFilePath + "PTimpcustomers.xml", System.Text.Encoding.UTF8);
|
|
|
|
Writer.WriteStartElement("PAW_Customers");
|
|
Writer.WriteAttributeString("xmlns:paw", "urn:schemas-peachtree-com/paw8.02-datatypes");
|
|
Writer.WriteAttributeString("xmlns:xsi", "http://www.w3.org/2000/10/XMLSchema-instance");
|
|
Writer.WriteAttributeString("xmlns:xsd", "http://www.w3.org/2000/10/XMLSchema-datatypes");
|
|
|
|
Writer.WriteStartElement("PAW_Customer");
|
|
Writer.WriteAttributeString("xsi:type", "paw:customer");
|
|
|
|
Writer.WriteStartElement("ID");
|
|
Writer.WriteAttributeString("xsi:type", "paw:ID");
|
|
Writer.WriteString(sID);
|
|
Writer.WriteEndElement();
|
|
|
|
Writer.WriteElementString("Name", sName);
|
|
Writer.WriteElementString("Account_Number", T(32, c.AccountNumber));
|
|
Writer.WriteElementString("Web_Address", T(255, c.WebAddress));
|
|
|
|
Writer.WriteElementString("ContactName", T(20, c.Contact));
|
|
Writer.WriteStartElement("PhoneNumbers");
|
|
Writer.WriteStartElement("PhoneNumber");
|
|
Writer.WriteAttributeString("Key", "1");
|
|
Writer.WriteString(T(20, c.Phone1));
|
|
Writer.WriteEndElement();
|
|
Writer.WriteStartElement("PhoneNumber");
|
|
Writer.WriteAttributeString("Key", "2");
|
|
Writer.WriteString(T(20, c.Phone3));
|
|
Writer.WriteEndElement();
|
|
Writer.WriteEndElement();
|
|
Writer.WriteElementString("FaxNumber", T(20, c.Phone2));
|
|
Writer.WriteElementString("EMail_Address", T(64, c.Email));
|
|
|
|
|
|
|
|
|
|
//Bill to address
|
|
bool bHasBillAddress = false;
|
|
if (c.MailToAddress.DeliveryAddress != "")
|
|
{
|
|
Writer.WriteStartElement("BillToAddress");
|
|
bHasBillAddress = true;
|
|
string[] sad = c.MailToAddress.DeliveryAddress.Replace("\r\n", "\n").Split('\n');
|
|
|
|
if (sad.GetLength(0) > 0)
|
|
Writer.WriteElementString("Line1", T(30, sad[0].TrimEnd()));
|
|
|
|
if (sad.GetLength(0) > 1)
|
|
Writer.WriteElementString("Line2", T(30, sad[1].TrimEnd()));
|
|
|
|
Writer.WriteElementString("City", T(20, c.MailToAddress.City));
|
|
Writer.WriteElementString("State", T(2, c.MailToAddress.StateProv));
|
|
Writer.WriteElementString("Zip", T(12, c.MailToAddress.Postal));
|
|
Writer.WriteElementString("Country", T(15, c.MailToAddress.Country));
|
|
Writer.WriteEndElement();
|
|
|
|
}
|
|
|
|
//Ship to address
|
|
bool bHasShipAddress = false;
|
|
if (!string.IsNullOrEmpty(c.GoToAddress.DeliveryAddress))
|
|
{
|
|
bHasShipAddress = true;
|
|
string[] sad = c.GoToAddress.DeliveryAddress.Replace("\r\n", "\n").Split('\n');
|
|
|
|
if (sad.GetLength(0) > 0)
|
|
Writer.WriteElementString("Line1", T(30, sad[0].TrimEnd()));
|
|
|
|
if (sad.GetLength(0) > 1)
|
|
Writer.WriteElementString("Line2", T(30, sad[1].TrimEnd()));
|
|
|
|
Writer.WriteElementString("City", T(20, c.GoToAddress.City));
|
|
Writer.WriteElementString("State", T(2, c.GoToAddress.StateProv));
|
|
Writer.WriteElementString("Zip", T(12, c.GoToAddress.Postal));
|
|
Writer.WriteElementString("Country", T(15, c.GoToAddress.Country));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Writer.Close();
|
|
#endregion generate import file
|
|
|
|
#region Import
|
|
|
|
PeachtreeAccounting.Import importer = (PeachtreeAccounting.Import)ptApp.app.CreateImporter(PeachwIEObj.peachwIEObjCustomerList);
|
|
importer.ClearImportFieldList();
|
|
importer.AddToImportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerName);
|
|
importer.AddToImportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerAccountNumber);
|
|
importer.AddToImportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerURL);
|
|
|
|
|
|
//stuff related to ayanova contact (phone numbers email contact name etc)
|
|
|
|
importer.AddToImportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerContact);
|
|
importer.AddToImportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerPhone1);
|
|
importer.AddToImportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerPhone2);
|
|
importer.AddToImportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerFax);
|
|
importer.AddToImportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerEmail);
|
|
|
|
|
|
//Bill to address (mailing)
|
|
if (bHasBillAddress)
|
|
{
|
|
importer.AddToImportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerBillToAddressLine1);
|
|
importer.AddToImportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerBillToAddressLine2);
|
|
importer.AddToImportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerBillToCity);
|
|
importer.AddToImportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerBillToState);
|
|
importer.AddToImportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerBillToZip);
|
|
importer.AddToImportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerBillToCountry);
|
|
}
|
|
|
|
//Physical SHIP TO address
|
|
if (bHasShipAddress)
|
|
{
|
|
importer.AddToImportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerShipTo1AddressLine1);
|
|
importer.AddToImportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerShipTo1AddressLine2);
|
|
importer.AddToImportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerShipTo1City);
|
|
importer.AddToImportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerShipTo1State);
|
|
importer.AddToImportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerShipTo1Zip);
|
|
importer.AddToImportFieldList((short)PeachwIEObjCustomerListField.peachwIEObjCustomerListField_CustomerShipTo1Country);
|
|
}
|
|
|
|
importer.SetFilename(TempFilePath + "PTimpcustomers.xml");
|
|
importer.SetFileType(PeachwIEFileType.peachwIEFileTypeXML);
|
|
|
|
|
|
#if(PEACHW14)
|
|
Array arout;
|
|
importer.ImportAndReturnGUIDs(out arout);
|
|
if (arout.GetLength(0) < 1)
|
|
throw new System.ApplicationException("Peachtree did not accept customer " + sName + " - no error given");
|
|
#else
|
|
importer.Import();
|
|
#endif
|
|
#endregion
|
|
|
|
#region Add to cache and link
|
|
|
|
//create a new row to add to the client cache datatable
|
|
DataRow dr = PTClients.NewRow();
|
|
|
|
dr["ID"] = sID;
|
|
dr["FullName"] = sName;
|
|
dr["MailAddress"] = new Address();
|
|
dr["StreetAddress"] = new Address();
|
|
dr["Phone"] = "";
|
|
dr["Fax"] = "";
|
|
dr["AltPhone"] = "";
|
|
dr["Email"] = "";
|
|
dr["Contact"] = "";
|
|
dr["Created"] = DateTime.MinValue;//flag indicating fresh record incomplete
|
|
dr["Modified"] = DateTime.MinValue;//ditto
|
|
dr["Account"] = "";
|
|
|
|
//add the new row for the newly imported object
|
|
PTClients.Rows.Add(dr);
|
|
|
|
//Link
|
|
IntegrationMap m = PTI.Maps.Add(PTI);
|
|
m.Name = sName;
|
|
m.RootObjectID = c.ID;
|
|
m.RootObjectType = RootObjectTypes.Client;
|
|
m.LastSync = DateTime.Now;
|
|
m.ForeignID = sID;
|
|
PTI = (Integration)PTI.Save();
|
|
#endregion
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
IntegrationLog.Log(PTID, "ImportAyaClient: Failed with exception:" + ex.Message);
|
|
ErrorFree = false;
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
CurrentNode = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion customer
|
|
|
|
#region Vendor
|
|
/// <summary>
|
|
/// Import the indicated Vendor
|
|
/// to Peachtree Vendor record
|
|
/// </summary>
|
|
/// <param name="VendorID"></param>
|
|
/// <param name="alErrors">An arraylist to hold strings indicating errors on fail</param>
|
|
public static void ImportAyaVendor(Guid VendorID, ArrayList alErrors)
|
|
{
|
|
|
|
if (!Vendor.Exists(VendorID, ""))
|
|
{
|
|
alErrors.Add("ImportAyaVendor: Vendor not found in AyaNova (deleted recently?) (" + VendorID.ToString() + ")");
|
|
return;
|
|
|
|
}
|
|
Vendor c = Vendor.GetItem(VendorID);
|
|
|
|
|
|
|
|
|
|
string sName = c.Name;
|
|
if (sName.Length > 39)
|
|
{
|
|
sName = sName.Substring(0, 39);
|
|
alErrors.Add("ImportAyaVendor: AyaNova Vendor name exceeds 39 character limit for Peachtree\r\n" +
|
|
"Name: " + c.Name + "\r\n" +
|
|
"will be imported as: " + sName);
|
|
|
|
}
|
|
|
|
string sID = BuildID(sName, PTVendors);
|
|
|
|
try
|
|
{
|
|
#region Generate import file
|
|
XmlTextWriter Writer = new XmlTextWriter(TempFilePath + "PTimpvendors.xml", System.Text.Encoding.UTF8);
|
|
|
|
Writer.WriteStartElement("PAW_Vendors");
|
|
Writer.WriteAttributeString("xmlns:paw", "urn:schemas-peachtree-com/paw8.02-datatypes");
|
|
Writer.WriteAttributeString("xmlns:xsi", "http://www.w3.org/2000/10/XMLSchema-instance");
|
|
Writer.WriteAttributeString("xmlns:xsd", "http://www.w3.org/2000/10/XMLSchema-datatypes");
|
|
|
|
Writer.WriteStartElement("PAW_Vendor");
|
|
Writer.WriteAttributeString("xsi:type", "paw:vendor");
|
|
|
|
Writer.WriteStartElement("ID");
|
|
Writer.WriteAttributeString("xsi:type", "paw:ID");
|
|
Writer.WriteString(sID);
|
|
Writer.WriteEndElement();
|
|
|
|
Writer.WriteElementString("Name", sName);
|
|
Writer.WriteElementString("Web_Address", T(255, c.WebAddress));
|
|
Writer.WriteElementString("AccountNumber", T(32, c.AccountNumber));
|
|
|
|
|
|
Writer.WriteElementString("ContactName", T(20, c.Contact));
|
|
Writer.WriteStartElement("PhoneNumbers");
|
|
Writer.WriteStartElement("PhoneNumber");
|
|
Writer.WriteAttributeString("Key", "1");
|
|
Writer.WriteString(T(20, c.Phone1));
|
|
Writer.WriteEndElement();
|
|
Writer.WriteStartElement("PhoneNumber");
|
|
Writer.WriteAttributeString("Key", "2");
|
|
Writer.WriteString(T(20, c.Phone3));
|
|
Writer.WriteEndElement();
|
|
Writer.WriteEndElement();
|
|
Writer.WriteElementString("FaxNumber", T(20, c.Phone2));
|
|
Writer.WriteElementString("EMail_Address", T(64, c.Email));
|
|
|
|
|
|
|
|
//Bill to address
|
|
bool bHasBillAddress = false;
|
|
if (c.MailToAddress.DeliveryAddress != "")
|
|
{
|
|
Writer.WriteStartElement("RemitToAddress");
|
|
bHasBillAddress = true;
|
|
string[] sad = c.MailToAddress.DeliveryAddress.Replace("\r\n", "\n").Split('\n');
|
|
|
|
if (sad.GetLength(0) > 0)
|
|
Writer.WriteElementString("Line1", T(30, sad[0].TrimEnd()));
|
|
|
|
if (sad.GetLength(0) > 1)
|
|
Writer.WriteElementString("Line2", T(30, sad[1].TrimEnd()));
|
|
|
|
Writer.WriteElementString("City", T(20, c.MailToAddress.City));
|
|
Writer.WriteElementString("State", T(2, c.MailToAddress.StateProv));
|
|
Writer.WriteElementString("Zip", T(12, c.MailToAddress.Postal));
|
|
Writer.WriteElementString("Country", T(15, c.MailToAddress.Country));
|
|
Writer.WriteEndElement();
|
|
|
|
}
|
|
|
|
//Ship to address
|
|
bool bHasShipAddress = false;
|
|
if (!string.IsNullOrEmpty(c.GoToAddress.DeliveryAddress))
|
|
{
|
|
bHasShipAddress = true;
|
|
string[] sad = c.GoToAddress.DeliveryAddress.Replace("\r\n", "\n").Split('\n');
|
|
|
|
if (sad.GetLength(0) > 0)
|
|
Writer.WriteElementString("Line1", T(30, sad[0].TrimEnd()));
|
|
|
|
if (sad.GetLength(0) > 1)
|
|
Writer.WriteElementString("Line2", T(30, sad[1].TrimEnd()));
|
|
|
|
Writer.WriteElementString("City", T(20, c.GoToAddress.City));
|
|
Writer.WriteElementString("State", T(2, c.GoToAddress.StateProv));
|
|
Writer.WriteElementString("Zip", T(12, c.GoToAddress.Postal));
|
|
Writer.WriteElementString("Country", T(15, c.GoToAddress.Country));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Writer.Close();
|
|
#endregion generate import file
|
|
|
|
#region Import
|
|
|
|
PeachtreeAccounting.Import importer = (PeachtreeAccounting.Import)ptApp.app.CreateImporter(PeachwIEObj.peachwIEObjVendorList);
|
|
importer.ClearImportFieldList();
|
|
importer.AddToImportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_VendorName);
|
|
importer.AddToImportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_byVendorURL);
|
|
importer.AddToImportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_VendorOurAccountId);
|
|
|
|
//stuff related to ayanova contact (phone numbers email contact name etc)
|
|
importer.AddToImportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_VendorContact);
|
|
importer.AddToImportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_VendorPhone1);
|
|
importer.AddToImportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_VendorPhone2);
|
|
importer.AddToImportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_VendorFax);
|
|
importer.AddToImportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_VendorEmail);
|
|
|
|
|
|
|
|
//Remit to address (mailing)
|
|
if (bHasBillAddress)
|
|
{
|
|
importer.AddToImportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_RemitTo1AddressLine1);
|
|
importer.AddToImportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_RemitTo1AddressLine2);
|
|
importer.AddToImportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_RemitTo1City);
|
|
importer.AddToImportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_RemitTo1State);
|
|
importer.AddToImportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_RemitTo1Zip);
|
|
importer.AddToImportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_RemitTo1Country);
|
|
}
|
|
|
|
//Physical SHIP TO address
|
|
if (bHasShipAddress)
|
|
{
|
|
importer.AddToImportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_VendorAddressLine1);
|
|
importer.AddToImportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_VendorAddressLine2);
|
|
importer.AddToImportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_VendorCity);
|
|
importer.AddToImportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_VendorState);
|
|
importer.AddToImportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_VendorZip);
|
|
importer.AddToImportFieldList((short)PeachwIEObjVendorListField.peachwIEObjVendorListField_VendorCountry);
|
|
}
|
|
|
|
importer.SetFilename(TempFilePath + "PTimpvendors.xml");
|
|
importer.SetFileType(PeachwIEFileType.peachwIEFileTypeXML);
|
|
|
|
|
|
|
|
|
|
#if(PEACHW14)
|
|
Array arout;
|
|
importer.ImportAndReturnGUIDs(out arout);
|
|
if (arout.GetLength(0) < 1)
|
|
throw new System.ApplicationException("Peachtree did not accept vendor " + sName + " - no error given");
|
|
#else
|
|
importer.Import();
|
|
#endif
|
|
|
|
#endregion
|
|
|
|
#region Add to cache and link
|
|
|
|
//create a new row to add to the vendor cache datatable
|
|
DataRow dr = PTVendors.NewRow();
|
|
|
|
dr["ID"] = sID;
|
|
dr["FullName"] = sName;
|
|
dr["MailAddress"] = new Address();
|
|
dr["StreetAddress"] = new Address();
|
|
dr["Phone"] = "";
|
|
dr["Fax"] = "";
|
|
dr["AltPhone"] = "";
|
|
dr["Email"] = "";
|
|
dr["Contact"] = "";
|
|
dr["Created"] = DateTime.MinValue;//flag indicating fresh record incomplete
|
|
dr["Modified"] = DateTime.MinValue;//ditto
|
|
dr["Account"] = "";
|
|
|
|
//add the new row for the newly imported object
|
|
PTVendors.Rows.Add(dr);
|
|
|
|
//Link
|
|
IntegrationMap m = PTI.Maps.Add(PTI);
|
|
m.Name = sName;
|
|
m.RootObjectID = c.ID;
|
|
m.RootObjectType = RootObjectTypes.Vendor;
|
|
m.LastSync = DateTime.Now;
|
|
m.ForeignID = sID;
|
|
PTI = (Integration)PTI.Save();
|
|
#endregion
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
IntegrationLog.Log(PTID, "ImportAyaVendor: Failed with exception:" + ex.Message);
|
|
ErrorFree = false;
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
CurrentNode = null;
|
|
|
|
}
|
|
|
|
|
|
}
|
|
#endregion vendor
|
|
|
|
|
|
|
|
private static string T(int nLength, string s)
|
|
{
|
|
if (s == null || s == "") return "";
|
|
if (s.Length <= nLength) return s;
|
|
else
|
|
return s.Substring(0, nLength);
|
|
}
|
|
|
|
#endregion export to peachtree
|
|
|
|
#region Workorder mismatch scanning
|
|
|
|
public enum MisMatchReason
|
|
{
|
|
NotLinkedToPT = 0,
|
|
PriceDifferent = 1,
|
|
NothingToInvoice = 2
|
|
|
|
}
|
|
/// <summary>
|
|
/// Mismatch properties
|
|
/// A structure for storing mismatches identified
|
|
///so user can resolve them.
|
|
/// </summary>
|
|
public struct MisMatch
|
|
{
|
|
//public Guid WorkorderID;
|
|
public Guid mRootObjectID;
|
|
public RootObjectTypes mObjectType;
|
|
public string mName;
|
|
public MisMatchReason mReason;
|
|
public decimal mAyaPrice;
|
|
public decimal mPTPrice;
|
|
public Guid mWorkorderItemPartID;
|
|
public string mPTListID;
|
|
|
|
public Guid RootObjectID
|
|
{
|
|
get
|
|
{
|
|
return mRootObjectID;
|
|
}
|
|
}
|
|
|
|
public RootObjectTypes ObjectType
|
|
{
|
|
get
|
|
{
|
|
return mObjectType;
|
|
}
|
|
}
|
|
|
|
public string Name
|
|
{
|
|
get
|
|
{
|
|
return mName;
|
|
}
|
|
}
|
|
|
|
public MisMatchReason Reason
|
|
{
|
|
get
|
|
{
|
|
return mReason;
|
|
}
|
|
}
|
|
|
|
public decimal AyaPrice
|
|
{
|
|
get
|
|
{
|
|
return mAyaPrice;
|
|
}
|
|
}
|
|
|
|
public decimal PTPrice
|
|
{
|
|
get
|
|
{
|
|
return mPTPrice;
|
|
}
|
|
}
|
|
|
|
public Guid WorkorderItemPartID
|
|
{
|
|
get
|
|
{
|
|
return mWorkorderItemPartID;
|
|
}
|
|
}
|
|
|
|
public string PTListID
|
|
{
|
|
get
|
|
{
|
|
return mPTListID;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Given a workorder ID
|
|
/// scans the objects in the workorder
|
|
/// that need to be linked to PT for invoicing
|
|
/// and on any error found adds them to the
|
|
/// mismatched object array list
|
|
/// </summary>
|
|
/// <param name="WorkorderID">Id of workorder being scanned</param>
|
|
/// <param name="MisMatches">An arraylist of mismatch objects</param>
|
|
/// <param name="PriceOverrides">An array of GUID values of workorderitemparts that have been set by
|
|
/// user to forcibly use the price set on the workorderitem part even though
|
|
/// it differs from the quickbooks price</param>
|
|
/// <returns>True if all links ok, false if there are any mismatches at all</returns>
|
|
public static bool ScanLinksOK(Guid WorkorderID, ArrayList MisMatches, ArrayList PriceOverrides)
|
|
{
|
|
bool bReturn = true;
|
|
bool bSomethingToInvoice = false;
|
|
|
|
|
|
Workorder w = Workorder.GetItem(WorkorderID);
|
|
|
|
//Client ok?
|
|
if (!PTI.Maps.Contains(w.ClientID))
|
|
{
|
|
bReturn = false;
|
|
AddMisMatch(AyaClientList[w.ClientID].Name, w.ClientID, RootObjectTypes.Client, MisMatchReason.NotLinkedToPT, MisMatches);
|
|
}
|
|
|
|
//Service rates:
|
|
foreach (WorkorderItem wi in w.WorkorderItems)
|
|
{
|
|
#region Labor
|
|
foreach (WorkorderItemLabor wl in wi.Labors)
|
|
{
|
|
|
|
//If there's *any* labor then there is something to invoice
|
|
bSomethingToInvoice = true;
|
|
|
|
//Check that rate isn't actually guid.empty
|
|
//it's possible that some users have not selected a rate on the workorder
|
|
if (wl.ServiceRateID == Guid.Empty)
|
|
throw new System.ApplicationException("ERROR: Workorder " + w.WorkorderService.ServiceNumber.ToString() + " has a labor item with no rate selected\r\n" +
|
|
"This is a serious problem for PTI and needs to be rectified before PTI can be used.\r\n");
|
|
|
|
if (!PTI.Maps.Contains(wl.ServiceRateID))
|
|
{
|
|
bReturn = false;
|
|
AddMisMatch(AyaRateList[wl.ServiceRateID].Name, wl.ServiceRateID, RootObjectTypes.Rate, MisMatchReason.NotLinkedToPT, MisMatches);
|
|
|
|
}
|
|
|
|
}
|
|
#endregion
|
|
|
|
#region Travel
|
|
foreach (WorkorderItemTravel wt in wi.Travels)
|
|
{
|
|
//If there's *any* travel then there is something to invoice
|
|
bSomethingToInvoice = true;
|
|
|
|
//Check that rate isn't actually guid.empty
|
|
//it's possible that some users have not selected a rate on the workorder
|
|
if (wt.TravelRateID == Guid.Empty)
|
|
throw new System.ApplicationException("ERROR: Workorder " + w.WorkorderService.ServiceNumber.ToString() + " has a travel item with no rate selected\r\n" +
|
|
"This is a serious problem for PTI and needs to be rectified before PTI can be used.\r\n");
|
|
|
|
if (!PTI.Maps.Contains(wt.TravelRateID))
|
|
{
|
|
bReturn = false;
|
|
AddMisMatch(AyaRateList[wt.TravelRateID].Name, wt.TravelRateID, RootObjectTypes.Rate, MisMatchReason.NotLinkedToPT, MisMatches);
|
|
|
|
}
|
|
|
|
}
|
|
#endregion
|
|
|
|
#region Parts
|
|
foreach (WorkorderItemPart wp in wi.Parts)
|
|
{
|
|
//If there's *any* parts then there is something to invoice
|
|
bSomethingToInvoice = true;
|
|
|
|
//Changed: 14-Nov-2006 to check that linked item id exists in qb
|
|
if (!PTI.Maps.Contains(wp.PartID) || PTItems.Rows.Find(PTI.Maps[wp.PartID].ForeignID) == null)
|
|
{
|
|
bReturn = false;
|
|
//Changed: 21-June-2006 to use display formatted name
|
|
AddMisMatch(AyaPartList[wp.PartID].DisplayName(Util.GlobalSettings.DefaultPartDisplayFormat), wp.PartID, RootObjectTypes.Part, MisMatchReason.NotLinkedToPT, MisMatches);
|
|
|
|
}
|
|
else
|
|
{
|
|
//check the price
|
|
if (!PriceOverrides.Contains(wp.ID))
|
|
{
|
|
|
|
decimal qbPrice = (decimal)PTItems.Rows.Find(PTI.Maps[wp.PartID].ForeignID)["Price"];
|
|
|
|
//------------DISCOUNT-----------------
|
|
string disco = "";
|
|
//Added:20-July-2006 to incorporate discounts on parts into qb invoice
|
|
decimal charge;
|
|
|
|
//Changed: 18-Nov-2006 CASE 158
|
|
//this is all wrong, it was multiplying price by quantity to calculate charge when it shouldn't
|
|
//removed quanty * price in next line to just price
|
|
charge = decimal.Round(wp.Price, 2, MidpointRounding.AwayFromZero);
|
|
charge = charge - (decimal.Round(charge * wp.Discount, 2, MidpointRounding.AwayFromZero));
|
|
if (wp.Discount != 0)
|
|
{
|
|
disco = " (Price " + wp.Price.ToString("c") + " discounted on workorder " + wp.Discount.ToString("p") + ") \r\n";
|
|
}
|
|
|
|
//-----------------------------
|
|
|
|
//It's a match, let's see if the price matches as well
|
|
if (charge != qbPrice)
|
|
{
|
|
bReturn = false;
|
|
AddMisMatch("WO: " + w.WorkorderService.ServiceNumber.ToString() + disco + " Part: " + AyaPartList[wp.PartID].DisplayName(Util.GlobalSettings.DefaultPartDisplayFormat),//Changed: 21-June-2006 to use display formatted name
|
|
wp.PartID, RootObjectTypes.Part, MisMatchReason.PriceDifferent, MisMatches, qbPrice, charge, wp.ID,
|
|
PTI.Maps[wp.PartID].ForeignID);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
#endregion
|
|
|
|
#region Outside service charges
|
|
|
|
if (wi.HasOutsideService)
|
|
{
|
|
if (wi.OutsideService.RepairPrice != 0 || wi.OutsideService.ShippingPrice != 0)
|
|
{
|
|
bSomethingToInvoice = true;
|
|
//there is something billable, just need to make sure
|
|
//that there is a PT charge defined for outside service
|
|
if (PDat.OutsideServiceChargeAs == null ||
|
|
PDat.OutsideServiceChargeAs == "" ||
|
|
!PTItems.Rows.Contains(PDat.OutsideServiceChargeAs))
|
|
{
|
|
bReturn = false;
|
|
AddMisMatch("Outside service", Guid.Empty, RootObjectTypes.WorkorderItemOutsideService, MisMatchReason.NotLinkedToPT, MisMatches);
|
|
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Workorder item loan charges
|
|
|
|
if (wi.HasLoans)
|
|
{
|
|
foreach (WorkorderItemLoan wil in wi.Loans)
|
|
{
|
|
|
|
if (wil.Charges != 0)
|
|
{
|
|
//case 733
|
|
bSomethingToInvoice = true;
|
|
|
|
//there is something billable, just need to make sure
|
|
//that there is a PT charge defined for loaned item charges
|
|
if (PDat.WorkorderItemLoanChargeAs == null ||
|
|
PDat.WorkorderItemLoanChargeAs == "" ||
|
|
!PTItems.Rows.Contains(PDat.WorkorderItemLoanChargeAs))
|
|
{
|
|
bReturn = false;
|
|
AddMisMatch("Workorder item loan", Guid.Empty, RootObjectTypes.WorkorderItemLoan, MisMatchReason.NotLinkedToPT, MisMatches);
|
|
break;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Workorder item misc expenses
|
|
|
|
if (wi.HasExpenses)
|
|
{
|
|
foreach (WorkorderItemMiscExpense wie in wi.Expenses)
|
|
{
|
|
|
|
|
|
if (wie.ChargeToClient)
|
|
{
|
|
bSomethingToInvoice = true;
|
|
//there is something billable, just need to make sure
|
|
//that there is a PT charge defined for misc expense item charges
|
|
if (PDat.MiscExpenseChargeAs == null ||
|
|
PDat.MiscExpenseChargeAs == "" ||
|
|
!PTItems.Rows.Contains(PDat.MiscExpenseChargeAs))
|
|
{
|
|
bReturn = false;
|
|
AddMisMatch("Workorder item expense", Guid.Empty, RootObjectTypes.WorkorderItemMiscExpense, MisMatchReason.NotLinkedToPT, MisMatches);
|
|
break;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
|
|
}//workorder items loop
|
|
|
|
//If there are no mismatches so far,
|
|
//maybe it's because it's got nothing to invoice?
|
|
if (bReturn && !bSomethingToInvoice)
|
|
{
|
|
bReturn = false;
|
|
AddMisMatch("WO: " + w.WorkorderService.ServiceNumber.ToString() + " - Nothing chargeable on it, will not be invoiced",
|
|
Guid.Empty, RootObjectTypes.Nothing, MisMatchReason.NothingToInvoice, MisMatches);
|
|
|
|
}
|
|
|
|
return bReturn;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void AddMisMatch(string Name, Guid RootObjectID, RootObjectTypes RootObjectType, MisMatchReason Reason, ArrayList Mismatches)
|
|
{
|
|
AddMisMatch(Name, RootObjectID, RootObjectType, Reason, Mismatches, 0m, 0m, Guid.Empty, "");
|
|
}
|
|
|
|
private static void AddMisMatch(string Name, Guid RootObjectID, RootObjectTypes RootObjectType,
|
|
MisMatchReason Reason, ArrayList Mismatches, decimal PTPrice, decimal AyaPrice, Guid WorkorderItemPartID, string PTListID)
|
|
{
|
|
bool bDuplicate = false;
|
|
//scan through list of existing mismatches,
|
|
//only add a not linked item if it's
|
|
//not there already
|
|
//other types of mismatches need to be added because
|
|
//they need to be resolved on a case by case basis or are unresolvable
|
|
if (Reason == MisMatchReason.NotLinkedToPT)
|
|
{
|
|
|
|
foreach (object o in Mismatches)
|
|
{
|
|
MisMatch m = (MisMatch)o;
|
|
//Have to check ID and type here because for outside service
|
|
//and loans and misc expenses the id is always empty so type is
|
|
//the only way to differentiate
|
|
if (m.RootObjectID == RootObjectID && m.ObjectType == RootObjectType)
|
|
{
|
|
bDuplicate = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bDuplicate)
|
|
{
|
|
MisMatch m = new MisMatch();
|
|
m.mName = Name;
|
|
m.mRootObjectID = RootObjectID;
|
|
m.mObjectType = RootObjectType;
|
|
m.mReason = Reason;
|
|
m.mAyaPrice = AyaPrice;
|
|
m.mPTPrice = PTPrice;
|
|
m.mWorkorderItemPartID = WorkorderItemPartID;
|
|
m.mPTListID = PTListID;
|
|
Mismatches.Add(m);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
#endregion wo_mismatch_scan
|
|
|
|
#region Invoice
|
|
/// <summary>
|
|
/// Invoice out the workorders contained in the array list
|
|
/// as one single invoice
|
|
///
|
|
/// Put in descriptive text as necessary and when sucessfully invoiced
|
|
/// set workorders in list to status selected for post invoicing and
|
|
/// set invoice number and then close them if autoclose option selected
|
|
/// </summary>
|
|
/// <param name="alWorkorders"></param>
|
|
/// <returns></returns>
|
|
public static void Invoice(ArrayList alWorkorders, ArrayList alErrors)
|
|
{
|
|
|
|
|
|
if (alWorkorders.Count == 0) return;
|
|
|
|
|
|
|
|
|
|
//a string to hold the memo field
|
|
StringBuilder sbInternalNotes = new StringBuilder();
|
|
if (PDat.SetMemoField)
|
|
{
|
|
sbInternalNotes.Append("Imported by: " + Thread.CurrentPrincipal.Identity.Name);
|
|
if (alWorkorders.Count > 1)
|
|
{
|
|
sbInternalNotes.Append(" Workorders: ");
|
|
}
|
|
else
|
|
{
|
|
sbInternalNotes.Append(" Workorder: ");
|
|
}
|
|
}
|
|
|
|
//Notes stringbuilder to hold text that will
|
|
//be constructed from templates
|
|
StringBuilder sbNotes = new StringBuilder();
|
|
|
|
DataTable i = new DataTable("InvoiceLines");
|
|
//setup the columns
|
|
i.Columns.Add("ID", typeof(string));
|
|
i.Columns.Add("Description", typeof(string));
|
|
i.Columns.Add("Quantity", typeof(decimal));
|
|
i.Columns.Add("Price", typeof(decimal));
|
|
i.Columns.Add("Amount", typeof(decimal));
|
|
|
|
//Case 533
|
|
i.Columns.Add("Serial_Number", typeof(string));
|
|
|
|
|
|
string sInvoiceNumber = "";
|
|
Workorder w = null;
|
|
try
|
|
{
|
|
#region Generate import file
|
|
XmlTextWriter Writer = new XmlTextWriter(TempFilePath + "PTimpinvoices.xml", System.Text.Encoding.UTF8);
|
|
|
|
Writer.WriteStartElement("PAW_Invoices");
|
|
Writer.WriteAttributeString("xmlns:paw", "urn:schemas-peachtree-com/paw8.02-datatypes");
|
|
Writer.WriteAttributeString("xmlns:xsi", "http://www.w3.org/2000/10/XMLSchema-instance");
|
|
Writer.WriteAttributeString("xmlns:xsd", "http://www.w3.org/2000/10/XMLSchema-datatypes");
|
|
|
|
Writer.WriteStartElement("PAW_Invoice");
|
|
Writer.WriteAttributeString("xsi:type", "paw:invoice");
|
|
|
|
|
|
//Get first workorder for setting header stuff
|
|
w = Workorder.GetItem((Guid)alWorkorders[0]);
|
|
|
|
Writer.WriteStartElement("Customer_ID");
|
|
Writer.WriteAttributeString("xsi:type", "paw:id");
|
|
Writer.WriteString(PTI.Maps[w.ClientID].ForeignID);
|
|
Writer.WriteEndElement();
|
|
//Set invoice number, it was decided to use first workorder's number even if
|
|
//multiple wo's on invoice (probably no other way to do it really)
|
|
// string sInvoiceNumber = "WO" + w.WorkorderService.ServiceNumber + "TEST" + DateTime.Now.ToString("T");
|
|
//sInvoiceNumber = sInvoiceNumber.Replace(" ", "").Replace(":", "");
|
|
|
|
sInvoiceNumber = "WO" + w.WorkorderService.ServiceNumber;
|
|
Writer.WriteElementString("Invoice_Number", sInvoiceNumber);
|
|
|
|
Writer.WriteStartElement("Date");
|
|
Writer.WriteAttributeString("xsi:type", "paw:date");
|
|
Writer.WriteString(DateTime.Now.ToString("M/d/yy"));//Date - Date of the transaction. Must be in ##/##/## (month/day/yr) format.
|
|
Writer.WriteEndElement();
|
|
|
|
Writer.WriteStartElement("Accounts_Receivable_Account");
|
|
Writer.WriteAttributeString("xsi:type", "paw:id");
|
|
Writer.WriteString(DefaultARAccount);
|
|
Writer.WriteEndElement();
|
|
|
|
string poField = "";
|
|
|
|
|
|
|
|
#region Build Invoice line items
|
|
|
|
|
|
//Loop through alworkorders
|
|
foreach (object o in alWorkorders)
|
|
{
|
|
w = Workorder.GetItem((Guid)o);
|
|
|
|
if (!string.IsNullOrEmpty(w.CustomerReferenceNumber))
|
|
poField += w.CustomerReferenceNumber + ",";
|
|
|
|
string sWONum = w.WorkorderService.ServiceNumber.ToString();
|
|
InvoiceAddTextLine(i, "WO#: " + sWONum);
|
|
|
|
if (PDat.SetMemoField)
|
|
sbInternalNotes.Append(sWONum + ",");
|
|
|
|
|
|
|
|
#region Invoice header text
|
|
if (PDat.HasInvoiceHeaderTemplate)
|
|
{
|
|
string s = PDat.InvoiceHeaderTemplate;
|
|
|
|
if (s.IndexOf("~WO#~") != -1)
|
|
{
|
|
s = s.Replace("~WO#~", w.WorkorderService.ServiceNumber.ToString());
|
|
}
|
|
|
|
if (s.IndexOf("~CONTACT~") != -1)
|
|
{
|
|
s = s.Replace("~CONTACT~", w.CustomerContactName);
|
|
}
|
|
|
|
if (s.IndexOf("~CREF#~") != -1)
|
|
{
|
|
s = s.Replace("~CREF#~", w.CustomerReferenceNumber);
|
|
}
|
|
|
|
if (s.IndexOf("~OURREF#~") != -1)
|
|
{
|
|
s = s.Replace("~OURREF#~", w.InternalReferenceNumber);
|
|
}
|
|
|
|
if (s.IndexOf("~PROJ~") != -1)
|
|
{
|
|
if (w.ProjectID == Guid.Empty)
|
|
s = s.Replace("~PROJ~", "");
|
|
else
|
|
s = s.Replace("~PROJ~", NameFetcher.GetItem("aProject", "aName", w.ProjectID).RecordName);
|
|
}
|
|
|
|
if (s.IndexOf("~CLIENT~") != -1)
|
|
{
|
|
s = s.Replace("~CLIENT~", NameFetcher.GetItem("aClient", "aName", w.ClientID).RecordName);
|
|
}
|
|
|
|
if (s.IndexOf("~SERVDATE~") != -1)
|
|
{
|
|
s = s.Replace("~SERVDATE~", w.WorkorderService.ServiceDate.ToString());
|
|
}
|
|
|
|
if (s.IndexOf("~STAT~") != -1)
|
|
{
|
|
if (w.WorkorderService.WorkorderStatusID == Guid.Empty)
|
|
s = s.Replace("~STAT~", "");
|
|
else
|
|
s = s.Replace("~STAT~", NameFetcher.GetItem("aWorkorderStatus", "aName", w.WorkorderService.WorkorderStatusID).RecordName);
|
|
}
|
|
|
|
if (s.IndexOf("~DESC~") != -1)
|
|
{
|
|
s = s.Replace("~DESC~", w.Summary);
|
|
}
|
|
|
|
InvoiceAddNote(sbNotes, s);
|
|
}
|
|
#endregion header text
|
|
|
|
#region Part charges
|
|
foreach (WorkorderItem it in w.WorkorderItems)
|
|
{
|
|
foreach (WorkorderItemPart p in it.Parts)
|
|
{
|
|
//------------DISCOUNT-----------------
|
|
//Added:20-July-2006 to incorporate discounts on parts into qb invoice
|
|
decimal charge;
|
|
|
|
//Case 269 this is incorrect:
|
|
//charge = decimal.Round(p.Quantity * p.Price, 2, MidpointRounding.AwayFromZero);
|
|
charge = decimal.Round(1 * p.Price, 2, MidpointRounding.AwayFromZero);
|
|
|
|
|
|
charge = charge - (decimal.Round(charge * p.Discount, 2, MidpointRounding.AwayFromZero));
|
|
//-----------------------------
|
|
|
|
|
|
|
|
string sn = "";
|
|
if (p.PartSerialID != Guid.Empty)
|
|
{
|
|
sn = PartSerial.GetSerialNumberFromPartSerialID(p.PartSerialID);
|
|
|
|
}
|
|
else if (!string.IsNullOrEmpty(p.Description) && p.Description.Length < 31)//Case 533
|
|
{
|
|
//No serial number but there is a description so were going to call it the sn
|
|
//Note that PT appears to only allow a max sn of 30 characters so sanity check of 31
|
|
sn = p.Description;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Case 533
|
|
InvoiceAddCharge(i, PTI.Maps[p.PartID].ForeignID, p.Quantity, charge, sn);
|
|
|
|
if (sn != "")
|
|
InvoiceAddTextLine(i, "SN: " + sn);
|
|
|
|
//Added:18-Nov-2006 case 125
|
|
//checks for nonempty description, also checks to see if description is
|
|
//same as serial number because it's copied there in some cases and no sense
|
|
//in showing it twice
|
|
if (p.Description != "" && sn != p.Description)
|
|
InvoiceAddTextLine(i, p.Description);
|
|
|
|
}
|
|
}
|
|
#endregion part charges
|
|
|
|
#region Service charges
|
|
foreach (WorkorderItem it in w.WorkorderItems)
|
|
{
|
|
foreach (WorkorderItemLabor l in it.Labors)
|
|
{
|
|
//Added 20-July-2006 to not charge for banked hours
|
|
if (l.ServiceBankID != Guid.Empty)
|
|
{
|
|
InvoiceAddCharge(i, PTI.Maps[l.ServiceRateID].ForeignID, l.ServiceRateQuantity, 0);
|
|
|
|
}
|
|
else
|
|
InvoiceAddCharge(i, PTI.Maps[l.ServiceRateID].ForeignID, l.ServiceRateQuantity,
|
|
AyaRateList[l.ServiceRateID].Charge);
|
|
|
|
}
|
|
}
|
|
#endregion Service charges
|
|
|
|
#region Travel charges
|
|
foreach (WorkorderItem it in w.WorkorderItems)
|
|
{
|
|
foreach (WorkorderItemTravel l in it.Travels)
|
|
{
|
|
InvoiceAddCharge(i, PTI.Maps[l.TravelRateID].ForeignID, l.TravelRateQuantity, AyaRateList[l.TravelRateID].Charge);
|
|
|
|
|
|
}
|
|
}
|
|
#endregion Travel charges
|
|
|
|
#region MiscExpense charges
|
|
foreach (WorkorderItem it in w.WorkorderItems)
|
|
{
|
|
foreach (WorkorderItemMiscExpense l in it.Expenses)
|
|
{
|
|
if (l.ChargeToClient)
|
|
{
|
|
InvoiceAddCharge(i, PDat.MiscExpenseChargeAs, 1, l.ChargeAmount);
|
|
}
|
|
|
|
}
|
|
}
|
|
#endregion MiscExpense charges
|
|
|
|
#region Loaner charges
|
|
foreach (WorkorderItem it in w.WorkorderItems)
|
|
{
|
|
foreach (WorkorderItemLoan l in it.Loans)
|
|
{
|
|
InvoiceAddCharge(i, PDat.WorkorderItemLoanChargeAs, 1, l.Charges);
|
|
|
|
}
|
|
}
|
|
#endregion Loaner charges
|
|
|
|
#region OutsideService charges
|
|
foreach (WorkorderItem it in w.WorkorderItems)
|
|
{
|
|
if (it.HasOutsideService && (it.OutsideService.ShippingPrice != 0 || it.OutsideService.RepairPrice != 0))
|
|
{
|
|
InvoiceAddCharge(i, PDat.OutsideServiceChargeAs, 1, it.OutsideService.ShippingPrice + it.OutsideService.RepairPrice);
|
|
|
|
}
|
|
|
|
}
|
|
#endregion OutsideService charges
|
|
|
|
#region Invoice footer text
|
|
|
|
//Loop through workorder items
|
|
//inserting descriptive text as required
|
|
if (PDat.HasAnyInvoiceFooterTemplateFields)
|
|
{
|
|
foreach (WorkorderItem it in w.WorkorderItems)
|
|
{
|
|
#region Item (footer) fields
|
|
if (PDat.InvoiceFooterTemplate != "")
|
|
{
|
|
string s = PDat.InvoiceFooterTemplate;
|
|
|
|
if (s.IndexOf("~ITEM_SUMMARY~") != -1)
|
|
{
|
|
s = s.Replace("~ITEM_SUMMARY~", it.Summary);
|
|
}
|
|
|
|
if (s.IndexOf("~ITEM_SERVICE_NOTES~") != -1)
|
|
{
|
|
s = s.Replace("~ITEM_SERVICE_NOTES~", it.TechNotes);
|
|
}
|
|
|
|
if (s.IndexOf("~ITEM_TYPE~") != -1)
|
|
{
|
|
if (it.TypeID == Guid.Empty)
|
|
s = s.Replace("~ITEM_TYPE~", "");
|
|
else
|
|
s = s.Replace("~ITEM_TYPE~", NameFetcher.GetItem("aWorkorderItemType", "aName", it.TypeID).RecordName);
|
|
}
|
|
|
|
if (s.IndexOf("~ITEM_REQUEST_DATE~") != -1)
|
|
{
|
|
s = s.Replace("~ITEM_REQUEST_DATE~", it.RequestDate.ToString());
|
|
}
|
|
|
|
if (s.IndexOf("~ITEM_STATUS~") != -1)
|
|
{
|
|
if (it.WorkorderStatusID == Guid.Empty)
|
|
s = s.Replace("~ITEM_STATUS~", "");
|
|
else
|
|
s = s.Replace("~ITEM_STATUS~", NameFetcher.GetItem("aWorkorderStatus", "aName", it.WorkorderStatusID).RecordName);
|
|
}
|
|
|
|
InvoiceAddNote(sbNotes, s);
|
|
}
|
|
#endregion item
|
|
|
|
#region Unit fields
|
|
if (PDat.InvoiceUnitTemplate != "" && it.UnitID != Guid.Empty)
|
|
{
|
|
string s = PDat.InvoiceUnitTemplate;
|
|
|
|
UnitPickList up = UnitPickList.GetListOfOneSpecificUnit(it.UnitID);
|
|
|
|
|
|
if (s.IndexOf("~AYAFORMAT~") != -1)
|
|
{
|
|
s = s.Replace("~AYAFORMAT~", up[0].UnitName());
|
|
}
|
|
|
|
|
|
if (s.IndexOf("~UNIT_SN~") != -1)
|
|
{
|
|
s = s.Replace("~UNIT_SN~", up[0].Serial);
|
|
}
|
|
|
|
if (s.IndexOf("~UNIT_METER~") != -1)
|
|
{
|
|
if (!up[0].Metered)
|
|
s = s.Replace("~UNIT_METER~", "");
|
|
else
|
|
s = s.Replace("~UNIT_METER~", Unit.LastMeterReading(up[0].ID).ToString());
|
|
}
|
|
|
|
if (s.IndexOf("~UNIT_MAKE~") != -1)
|
|
{
|
|
s = s.Replace("~UNIT_MAKE~", up[0].VendorName);
|
|
}
|
|
|
|
if (s.IndexOf("~UNIT_MODEL_NAME~") != -1)
|
|
{
|
|
s = s.Replace("~UNIT_MODEL_NAME~", up[0].ModelName);
|
|
}
|
|
|
|
if (s.IndexOf("~UNIT_MODEL_NUMBER~") != -1)
|
|
{
|
|
s = s.Replace("~UNIT_MODEL_NUMBER~", up[0].ModelNumber);
|
|
}
|
|
|
|
InvoiceAddNote(sbNotes, s);
|
|
}
|
|
#endregion unit
|
|
|
|
#region Labor fields
|
|
if (PDat.InvoiceServiceTemplate != "" && it.HasLabor)
|
|
{
|
|
foreach (WorkorderItemLabor wl in it.Labors)
|
|
{
|
|
string s = PDat.InvoiceServiceTemplate;
|
|
|
|
if (s.IndexOf("~SERVICE_START~") != -1)
|
|
{
|
|
s = s.Replace("~SERVICE_START~", wl.ServiceStartDate.ToString());
|
|
}
|
|
|
|
if (s.IndexOf("~SERVICE_STOP~") != -1)
|
|
{
|
|
s = s.Replace("~SERVICE_STOP~", wl.ServiceStopDate.ToString());
|
|
}
|
|
|
|
if (s.IndexOf("~SERVICE_QUANTITY~") != -1)
|
|
{
|
|
s = s.Replace("~SERVICE_QUANTITY~", wl.ServiceRateQuantity.ToString());
|
|
}
|
|
|
|
|
|
if (s.IndexOf("~NO_CHARGE_QUANTITY~") != -1)
|
|
{
|
|
s = s.Replace("~NO_CHARGE_QUANTITY~", wl.NoChargeQuantity.ToString());
|
|
}
|
|
|
|
if (s.IndexOf("~RATE_NAME~") != -1)
|
|
{
|
|
s = s.Replace("~RATE_NAME~", AyaRateList[wl.ServiceRateID].Name);
|
|
}
|
|
|
|
if (s.IndexOf("~SERVICE_TECH~") != -1)
|
|
{
|
|
s = s.Replace("~SERVICE_TECH~", UserPickList.GetListOfOneSpecificUser(wl.UserID)[0].Name);
|
|
}
|
|
|
|
if (s.IndexOf("~DETAILS~") != -1)
|
|
{
|
|
s = s.Replace("~DETAILS~", wl.ServiceDetails);
|
|
}
|
|
|
|
|
|
|
|
|
|
InvoiceAddNote(sbNotes, s);
|
|
}
|
|
}
|
|
#endregion service
|
|
|
|
#region Travel fields
|
|
if (PDat.InvoiceTravelTemplate != "" && it.HasTravel)
|
|
{
|
|
foreach (WorkorderItemTravel wt in it.Travels)
|
|
{
|
|
string s = PDat.InvoiceTravelTemplate;
|
|
|
|
if (s.IndexOf("~TRAVEL_START~") != -1)
|
|
{
|
|
s = s.Replace("~TRAVEL_START~", wt.TravelStartDate.ToString());
|
|
}
|
|
|
|
if (s.IndexOf("~TRAVEL_STOP~") != -1)
|
|
{
|
|
s = s.Replace("~TRAVEL_STOP~", wt.TravelStopDate.ToString());
|
|
}
|
|
|
|
if (s.IndexOf("~TRAVEL_QUANTITY~") != -1)
|
|
{
|
|
s = s.Replace("~TRAVEL_QUANTITY~", wt.TravelRateQuantity.ToString());
|
|
}
|
|
|
|
if (s.IndexOf("~TRAVEL_NO_CHARGE_QUANTITY~") != -1)
|
|
{
|
|
s = s.Replace("~TRAVEL_NO_CHARGE_QUANTITY~", wt.NoChargeQuantity.ToString());
|
|
}
|
|
|
|
if (s.IndexOf("~TRAVEL_RATE_NAME~") != -1)
|
|
{
|
|
s = s.Replace("~TRAVEL_RATE_NAME~", AyaRateList[wt.TravelRateID].Name);
|
|
}
|
|
|
|
if (s.IndexOf("~TRAVEL_TECH~") != -1)
|
|
{
|
|
s = s.Replace("~TRAVEL_TECH~", UserPickList.GetListOfOneSpecificUser(wt.UserID)[0].Name);
|
|
}
|
|
|
|
if (s.IndexOf("~TRAVEL_DETAILS~") != -1)
|
|
{
|
|
s = s.Replace("~TRAVEL_DETAILS~", wt.TravelDetails);
|
|
}
|
|
|
|
if (s.IndexOf("~TRAVEL_DISTANCE~") != -1)
|
|
{
|
|
s = s.Replace("~TRAVEL_DISTANCE~", wt.Distance.ToString());
|
|
}
|
|
|
|
|
|
InvoiceAddNote(sbNotes, s);
|
|
}
|
|
}
|
|
#endregion travel fields
|
|
|
|
#region Outside fields
|
|
if (PDat.OutsideServiceChargeAs != "" && it.HasOutsideService)
|
|
{
|
|
string s = PDat.InvoiceOutsideServiceTemplate;
|
|
|
|
if (s.IndexOf("~REPAIR_PRICE~") != -1)
|
|
{
|
|
s = s.Replace("~REPAIR_PRICE~", it.OutsideService.RepairPrice.ToString("c"));
|
|
}
|
|
|
|
if (s.IndexOf("~SHIP_CHARGE~") != -1)
|
|
{
|
|
s = s.Replace("~SHIP_CHARGE~", it.OutsideService.ShippingPrice.ToString("c"));
|
|
}
|
|
|
|
if (s.IndexOf("~SENT~") != -1)
|
|
{
|
|
s = s.Replace("~SENT~", it.OutsideService.DateSent.ToString());
|
|
}
|
|
|
|
if (s.IndexOf("~RETURNED~") != -1)
|
|
{
|
|
s = s.Replace("~RETURNED~", it.OutsideService.DateReturned.ToString());
|
|
}
|
|
|
|
if (s.IndexOf("~NOTES~") != -1)
|
|
{
|
|
s = s.Replace("~NOTES~", it.OutsideService.Notes);
|
|
}
|
|
|
|
|
|
|
|
InvoiceAddNote(sbNotes, s);
|
|
}
|
|
#endregion outside service
|
|
|
|
#region Misc expense fields
|
|
if (PDat.InvoiceMiscExpenseTemplate != "" && it.HasExpenses)
|
|
{
|
|
foreach (WorkorderItemMiscExpense e in it.Expenses)
|
|
{
|
|
string s = PDat.InvoiceMiscExpenseTemplate;
|
|
|
|
if (s.IndexOf("~CHARGES~") != -1)
|
|
{
|
|
s = s.Replace("~CHARGES~", e.ChargeAmount.ToString("c"));
|
|
}
|
|
|
|
if (s.IndexOf("~SUMMARY~") != -1)
|
|
{
|
|
s = s.Replace("~SUMMARY~", e.Name);
|
|
}
|
|
|
|
if (s.IndexOf("~DESCRIQBION~") != -1)
|
|
{
|
|
s = s.Replace("~DESCRIQBION~", e.Description);
|
|
}
|
|
|
|
if (s.IndexOf("~TECH~") != -1)
|
|
{
|
|
s = s.Replace("~TECH~", UserPickList.GetListOfOneSpecificUser(e.UserID)[0].Name);
|
|
}
|
|
|
|
InvoiceAddNote(sbNotes, s);
|
|
}
|
|
}
|
|
#endregion misc expense
|
|
|
|
#region Loan item fields
|
|
if (PDat.InvoiceLoanItemTemplate != "" && it.HasLoans)
|
|
{
|
|
foreach (WorkorderItemLoan l in it.Loans)
|
|
{
|
|
string s = PDat.InvoiceLoanItemTemplate;
|
|
|
|
if (s.IndexOf("~CHARGE~") != -1)
|
|
{
|
|
s = s.Replace("~CHARGE~", l.Charges.ToString("c"));
|
|
}
|
|
|
|
if (s.IndexOf("~ITEM~") != -1)
|
|
{
|
|
s = s.Replace("~ITEM~", NameFetcher.GetItem("aLoanItem", "aName", l.LoanItemID).RecordName);
|
|
}
|
|
|
|
if (s.IndexOf("~LOANED~") != -1)
|
|
{
|
|
s = s.Replace("~LOANED~", l.OutDate.ToString());
|
|
}
|
|
|
|
if (s.IndexOf("~LOAN_RETURNED~") != -1)
|
|
{
|
|
s = s.Replace("~LOAN_RETURNED~", l.ReturnDate.ToString());
|
|
}
|
|
|
|
if (s.IndexOf("~LOAN_NOTES~") != -1)
|
|
{
|
|
s = s.Replace("~LOAN_NOTES~", l.Notes);
|
|
}
|
|
|
|
InvoiceAddNote(sbNotes, s);
|
|
}
|
|
}
|
|
#endregion loan item expense
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
#endregion
|
|
|
|
}//Bottom of foreach workorder loop
|
|
|
|
|
|
if (!string.IsNullOrEmpty(poField))
|
|
{
|
|
Writer.WriteElementString("Customer_PO", T(20, poField.TrimEnd(',')));
|
|
}
|
|
|
|
if (sbNotes.Length > 0)
|
|
{
|
|
//write out a max of 2000 chars to the internal notes element
|
|
Writer.WriteElementString("Note", T(2000, sbNotes.ToString()));
|
|
Writer.WriteElementString("Note_Prints_After_Line_Items", "TRUE");
|
|
}
|
|
|
|
//Set memo field
|
|
if (PDat.SetMemoField)
|
|
{
|
|
//write out a max of 2000 chars to the internal notes element
|
|
Writer.WriteElementString("Internal_Note", T(2000, sbInternalNotes.ToString()).TrimEnd(','));
|
|
}
|
|
|
|
#endregion Build line items
|
|
|
|
decimal totalamount = 0;
|
|
decimal taxableamount = 0;
|
|
bool IsTax = false;
|
|
foreach (DataRow dr in i.Rows)
|
|
{
|
|
if (dr["ID"].ToString() != "") //only if id is not empty (which means a text only line)
|
|
{
|
|
totalamount += Convert.ToDecimal(dr["Amount"].ToString());
|
|
if (IsTaxable(dr["ID"].ToString()))
|
|
taxableamount += Convert.ToDecimal(dr["Amount"].ToString());
|
|
}
|
|
}
|
|
|
|
if (taxableamount != 0) IsTax = true;
|
|
|
|
#region Case 539 - Terms
|
|
DataRow drTerms = _dtPTClients.Rows.Find(PTI.Maps[w.ClientID].ForeignID);
|
|
if (drTerms == null)
|
|
{
|
|
alErrors.Add("Invoice, add payment terms: Peachtree client not found " + PTI.Maps[w.ClientID].Name);
|
|
return;
|
|
}
|
|
|
|
|
|
DateTime dateDue;
|
|
DateTime discountDate;
|
|
decimal discountAmount;
|
|
string displayedTerms = "";
|
|
int nDueDays = (int)drTerms["Due_Days"];
|
|
//Due Date
|
|
if ((bool)drTerms["Use_Due_Month_End_Terms"] == true)
|
|
{
|
|
//set for last day of this month
|
|
dateDue = new DateTime(DateTime.Today.Year, DateTime.Today.Month, DateTime.DaysInMonth(DateTime.Today.Year, DateTime.Today.Month));
|
|
displayedTerms = "Net " + dateDue.ToString("M/d/yy");
|
|
}
|
|
else if ((bool)drTerms["Terms_Type"] == true)
|
|
{
|
|
//Due on specific day of next month
|
|
//in this scenario PT uses the due days field to indicate which day of the month
|
|
dateDue = DateTime.Today.AddMonths(1);
|
|
dateDue = new DateTime(dateDue.Year, dateDue.Month, nDueDays);
|
|
displayedTerms = "Net " + dateDue.ToString("M/d/yy");
|
|
}
|
|
else
|
|
{
|
|
//due in today plus due days time
|
|
|
|
dateDue = DateTime.Today.AddDays(nDueDays);
|
|
displayedTerms = "Net " + nDueDays.ToString() + " days";
|
|
|
|
}
|
|
|
|
//Discount date
|
|
discountDate = DateTime.Today.AddDays((int)drTerms["Discount_Days"]);
|
|
|
|
//Discount amount
|
|
discountAmount = 0;
|
|
if ((decimal)drTerms["Discount_Percent"] != 0)
|
|
{
|
|
decimal percentage = (decimal)drTerms["Discount_Percent"] / 100;
|
|
discountAmount = percentage * Math.Abs(totalamount);
|
|
discountAmount = decimal.Round(discountAmount, 2, MidpointRounding.AwayFromZero);
|
|
displayedTerms = ((decimal)drTerms["Discount_Percent"]).ToString("G29") + "% " + drTerms["Discount_Days"].ToString() + ", " + displayedTerms;
|
|
}
|
|
|
|
|
|
|
|
|
|
Writer.WriteStartElement("Date_Due");
|
|
Writer.WriteAttributeString("xsi:type", "paw:date");
|
|
Writer.WriteString(dateDue.ToString("M/d/yy"));
|
|
Writer.WriteEndElement();
|
|
|
|
Writer.WriteElementString("Discount_Amount", discountAmount.ToString());//PT's sample data shows this as the percentage off the after tax invoice total
|
|
|
|
Writer.WriteStartElement("Discount_Date");
|
|
Writer.WriteAttributeString("xsi:type", "paw:date");
|
|
Writer.WriteString(discountDate.ToString("M/d/yy"));
|
|
Writer.WriteEndElement();
|
|
|
|
Writer.WriteElementString("Displayed_Terms", displayedTerms);
|
|
#endregion
|
|
|
|
|
|
//Determine the number of gl distributions needed (why? Who freakin knows, it should be self evident to Peachtree but it's required)
|
|
int nNumberOfDistributions = i.Rows.Count;
|
|
|
|
#region Taxes
|
|
DataRow drTaxCode = null;
|
|
string[] taxauthorities = null;
|
|
//Need to do taxes?
|
|
if (IsTax)
|
|
{
|
|
//Determine the tax authorities
|
|
|
|
drTaxCode = PTTaxCodes.Rows.Find(PTClients.Rows.Find(PTI.Maps[w.ClientID].ForeignID)["Sales_Tax_Code"]);
|
|
if (drTaxCode == null)
|
|
throw new System.ApplicationException("Can not invoice because customer " + PTI.Maps[w.ClientID].Name + "\r\n does not have a default sales tax code set in Peachtree");
|
|
|
|
|
|
//Determine the number of distributions this will add (count the tax authorities)
|
|
//these are stored as a comma delimited list of Peachtree ID's in the drtaxauthority table
|
|
//so just need to split them out
|
|
taxauthorities = drTaxCode["Authorities"].ToString().Split(',');
|
|
|
|
//Ensure no tax authorities are using formulaic tax codes
|
|
//We could support that in future if enough people would use it but for now
|
|
//no dice
|
|
foreach (string s in taxauthorities)
|
|
{
|
|
DataRow drTaxAuthority = PTTaxAuthorities.Rows.Find(s);
|
|
|
|
if (drTaxAuthority == null)
|
|
throw new System.ApplicationException("Can not invoice: TaxAuthority " + s + " used by tax code " + drTaxCode["FullName"].ToString() + " could not be found");
|
|
|
|
|
|
if (drTaxAuthority["UsesFormula"].ToString() == "TRUE")
|
|
throw new System.ApplicationException(
|
|
"Can not invoice because customer " + PTI.Maps[w.ClientID].Name +
|
|
"\r\nuses a default tax code that uses tax authority " + s + " which uses \r\n" +
|
|
"a formula instead of a regular percentage for calculating taxes.\r\n" +
|
|
"Formula based tax codes are not currently supported by AyaNova PTI");
|
|
}
|
|
|
|
//Ok, at this point we are safely using tax codes and authorities correctly
|
|
|
|
//Each tax authority requires one distribution line for invoice
|
|
nNumberOfDistributions += taxauthorities.GetLength(0);
|
|
}
|
|
|
|
|
|
#endregion taxes
|
|
|
|
if (IsTax)
|
|
{
|
|
Writer.WriteStartElement("Sales_Tax_Code");
|
|
Writer.WriteAttributeString("xsi:type", "paw:id");
|
|
Writer.WriteString(drTaxCode["ID"].ToString());
|
|
Writer.WriteEndElement();
|
|
}
|
|
|
|
//Writer.WriteElementString("Accounts_Receivable_Amount", totalamount.ToString());
|
|
//Writer.WriteElementString("Accounts_Receivable_Amount", "190.80");
|
|
Writer.WriteElementString("CreditMemoType", "FALSE");
|
|
|
|
//Number of distributions (invoice detail lines)
|
|
Writer.WriteElementString("Number_of_Distributions", nNumberOfDistributions.ToString());
|
|
|
|
Writer.WriteStartElement("SalesLines");
|
|
|
|
|
|
|
|
#region Tax
|
|
if (IsTax)
|
|
{
|
|
foreach (string s in taxauthorities)
|
|
{
|
|
DataRow drTaxAuthority = PTTaxAuthorities.Rows.Find(s);
|
|
|
|
|
|
Writer.WriteStartElement("SalesLine");
|
|
Writer.WriteElementString("SalesOrderDistributionNumber", "0");
|
|
Writer.WriteElementString("InvoiceCMDistribution", "0");
|
|
Writer.WriteElementString("Quantity", "0.00000");
|
|
//Writer.WriteStartElement("Item_ID");
|
|
//Writer.WriteAttributeString("xsi:type", "paw:ID");
|
|
//Writer.WriteString(dr["ID"].ToString());
|
|
//Writer.WriteEndElement();
|
|
//Writer.WriteElementString("Description", dr["Description"].ToString());
|
|
|
|
Writer.WriteStartElement("GL_Account");
|
|
Writer.WriteAttributeString("xsi:type", "paw:ID");
|
|
Writer.WriteString(drTaxAuthority["AccountID"].ToString());
|
|
Writer.WriteEndElement();
|
|
|
|
Writer.WriteElementString("Unit_Price", "0.00000");
|
|
Writer.WriteElementString("Tax_Type", "0");
|
|
decimal dTaxPercentage = decimal.Parse(drTaxAuthority["Rate"].ToString()) / 100;
|
|
Writer.WriteElementString("Amount", (taxableamount * dTaxPercentage).ToString());
|
|
Writer.WriteElementString("Sales_Tax_Authority", drTaxAuthority["ID"].ToString());
|
|
Writer.WriteEndElement();
|
|
|
|
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Billable items
|
|
int nCurrentLineDistributionNumber = 0;
|
|
foreach (DataRow dr in i.Rows)
|
|
{
|
|
nCurrentLineDistributionNumber++;
|
|
Writer.WriteStartElement("SalesLine");
|
|
Writer.WriteElementString("SalesOrderDistributionNumber", "0");
|
|
Writer.WriteElementString("InvoiceCMDistribution", nCurrentLineDistributionNumber.ToString());
|
|
Writer.WriteElementString("Quantity", dr["Quantity"].ToString());
|
|
Writer.WriteStartElement("Item_ID");
|
|
Writer.WriteAttributeString("xsi:type", "paw:ID");
|
|
Writer.WriteString(dr["ID"].ToString());
|
|
Writer.WriteEndElement();
|
|
Writer.WriteElementString("Description", dr["Description"].ToString());
|
|
|
|
if (dr["ID"].ToString() != "")//Not a description only line
|
|
{
|
|
Writer.WriteStartElement("GL_Account");
|
|
Writer.WriteAttributeString("xsi:type", "paw:ID");
|
|
Writer.WriteString(PTItems.Rows.Find(dr["ID"].ToString())["SalesAccountId"].ToString());
|
|
Writer.WriteEndElement();
|
|
}
|
|
else
|
|
{//A description only line, still requires gl account, but will use default instead
|
|
Writer.WriteStartElement("GL_Account");
|
|
Writer.WriteAttributeString("xsi:type", "paw:ID");
|
|
Writer.WriteString(DefaultSalesAccount);
|
|
Writer.WriteEndElement();
|
|
}
|
|
|
|
Writer.WriteElementString("Unit_Price", dr["Price"].ToString());
|
|
|
|
//case 559
|
|
//for some reason this line was already here but commented out and set to 2 always?!$%
|
|
if (dr["ID"].ToString() != "")//Not a description only line
|
|
Writer.WriteElementString("Tax_Type", PTItems.Rows.Find(dr["ID"].ToString())["SalesTaxType"].ToString());
|
|
else
|
|
Writer.WriteElementString("Tax_Type", FirstNonTaxableTaxCode);
|
|
|
|
Writer.WriteElementString("Amount", dr["Amount"].ToString());
|
|
|
|
//Case 533
|
|
if (!string.IsNullOrEmpty(dr["Serial_Number"].ToString()))
|
|
Writer.WriteElementString("Serial_Number", dr["Serial_Number"].ToString());
|
|
|
|
Writer.WriteEndElement();
|
|
}
|
|
#endregion
|
|
|
|
|
|
//close Sales Lines
|
|
Writer.WriteEndElement();
|
|
|
|
//Close pawInvoice
|
|
Writer.WriteEndElement();
|
|
//close pawinvoices
|
|
Writer.WriteEndElement();
|
|
|
|
|
|
Writer.Close();
|
|
#endregion generate import file
|
|
|
|
#region Import
|
|
|
|
PeachtreeAccounting.Import importer = (PeachtreeAccounting.Import)ptApp.app.CreateImporter(PeachwIEObj.peachwIEObjSalesJournal);
|
|
importer.ClearImportFieldList();
|
|
importer.AddToImportFieldList((short)PeachwIEObjSalesJournalField.peachwIEObjSalesJournalField_CustomerId);
|
|
importer.AddToImportFieldList((short)PeachwIEObjSalesJournalField.peachwIEObjSalesJournalField_InvoiceNumber);
|
|
importer.AddToImportFieldList((short)PeachwIEObjSalesJournalField.peachwIEObjSalesJournalField_Date);
|
|
importer.AddToImportFieldList((short)PeachwIEObjSalesJournalField.peachwIEObjSalesJournalField_ARAccountId);
|
|
|
|
//Case 528
|
|
importer.AddToImportFieldList((short)PeachwIEObjSalesJournalField.peachwIEObjSalesJournalField_CustomerPurchaseOrder);
|
|
|
|
if (IsTax)
|
|
importer.AddToImportFieldList((short)PeachwIEObjSalesJournalField.peachwIEObjSalesJournalField_SalesTaxCode);
|
|
importer.AddToImportFieldList((short)PeachwIEObjSalesJournalField.peachwIEObjSalesJournalField_IsCreditMemo);
|
|
|
|
if (sbNotes.Length > 0)
|
|
{
|
|
importer.AddToImportFieldList((short)PeachwIEObjSalesJournalField.peachwIEObjSalesJournalField_InvoiceNote);
|
|
importer.AddToImportFieldList((short)PeachwIEObjSalesJournalField.peachwIEObjSalesJournalField_NotePrintsAfterLineItems);
|
|
}
|
|
|
|
if (PDat.SetMemoField)
|
|
importer.AddToImportFieldList((short)PeachwIEObjSalesJournalField.peachwIEObjSalesJournalField_InvoiceNote2);
|
|
|
|
importer.AddToImportFieldList((short)PeachwIEObjSalesJournalField.peachwIEObjSalesJournalField_NumberOfDistributions);
|
|
|
|
//Invoice line items (distributions)
|
|
importer.AddToImportFieldList((short)PeachwIEObjSalesJournalField.peachwIEObjSalesJournalField_SalesOrderDistNum);
|
|
importer.AddToImportFieldList((short)PeachwIEObjSalesJournalField.peachwIEObjSalesJournalField_InvoiceDistNum);
|
|
importer.AddToImportFieldList((short)PeachwIEObjSalesJournalField.peachwIEObjSalesJournalField_Quantity);
|
|
importer.AddToImportFieldList((short)PeachwIEObjSalesJournalField.peachwIEObjSalesJournalField_ItemId);
|
|
importer.AddToImportFieldList((short)PeachwIEObjSalesJournalField.peachwIEObjSalesJournalField_Description);
|
|
importer.AddToImportFieldList((short)PeachwIEObjSalesJournalField.peachwIEObjSalesJournalField_GLAccountId);
|
|
importer.AddToImportFieldList((short)PeachwIEObjSalesJournalField.peachwIEObjSalesJournalField_UnitPrice);
|
|
importer.AddToImportFieldList((short)PeachwIEObjSalesJournalField.peachwIEObjSalesJournalField_TaxType);
|
|
importer.AddToImportFieldList((short)PeachwIEObjSalesJournalField.peachwIEObjSalesJournalField_Amount);
|
|
|
|
//Case 533
|
|
importer.AddToImportFieldList((short)PeachwIEObjSalesJournalField.peachwIEObjSalesJournalField_enSerialNumber);
|
|
|
|
if (IsTax)
|
|
importer.AddToImportFieldList((short)PeachwIEObjSalesJournalField.peachwIEObjSalesJournalField_SalesTaxAuthority);
|
|
|
|
//Case 539
|
|
importer.AddToImportFieldList((short)PeachwIEObjSalesJournalField.peachwIEObjSalesJournalField_DateDue);
|
|
importer.AddToImportFieldList((short)PeachwIEObjSalesJournalField.peachwIEObjSalesJournalField_DiscountAmount);
|
|
importer.AddToImportFieldList((short)PeachwIEObjSalesJournalField.peachwIEObjSalesJournalField_DiscountDate);
|
|
importer.AddToImportFieldList((short)PeachwIEObjSalesJournalField.peachwIEObjSalesJournalField_DisplayedTerms);
|
|
|
|
importer.SetFilename(TempFilePath + "PTimpinvoices.xml");
|
|
importer.SetFileType(PeachwIEFileType.peachwIEFileTypeXML);
|
|
|
|
|
|
#if(PEACHW14)
|
|
Array arout;
|
|
importer.ImportAndReturnGUIDs(out arout);
|
|
if (arout.GetLength(0) < 1)
|
|
throw new System.ApplicationException("Peachtree did not import invoice " + sInvoiceNumber + " - no error given");
|
|
#else
|
|
importer.Import();
|
|
#endif
|
|
|
|
#endregion
|
|
invoiceGenerated = true;
|
|
|
|
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
//crack the exception in case it's a generic dataportal one
|
|
//and it is if it's got an inner exception of any kind
|
|
if (ex.InnerException != null) ex = ex.InnerException;
|
|
|
|
|
|
invoiceGenerated = false;
|
|
|
|
//check for errors that still result in an invoice being generated
|
|
if (ex.Message.Contains("This transaction will cause the balance"))
|
|
invoiceGenerated = true;
|
|
|
|
if (invoiceGenerated)
|
|
{
|
|
alErrors.Add("Invoice: Invoicing completed with warning:\r\n" + ex.Message.Replace("Do you want to continue?", ""));
|
|
}
|
|
else
|
|
{
|
|
alErrors.Add("Invoice: Invoicing failed due to the following error:\r\n" + ex.Message);
|
|
ErrorFree = false;
|
|
}
|
|
|
|
//{"WARNING! The reference number 'WO46' has already been used."} - Did not result in an invoice
|
|
//{"This transaction will cause the balance of customer [MOLLYS] to go over the credit limit by $7,008.96. Do you want to continue?"} - Did result in an invoice
|
|
}
|
|
finally
|
|
{
|
|
CurrentNode = null;
|
|
#if(!DEBUG)
|
|
if (invoiceGenerated)
|
|
{
|
|
//Loop through alworkorders
|
|
foreach (object o in alWorkorders)
|
|
{
|
|
w = Workorder.GetItem((Guid)o);
|
|
if (PDat.PostWOStatus != Guid.Empty)
|
|
{
|
|
w.WorkorderService.WorkorderStatusID = PDat.PostWOStatus;
|
|
}
|
|
|
|
w.WorkorderService.InvoiceNumber = sInvoiceNumber;
|
|
|
|
//Case 7
|
|
if (PDat.AutoClose)
|
|
w.Closed = true;
|
|
|
|
w.Save();
|
|
|
|
}
|
|
}
|
|
#else
|
|
if (!invoiceGenerated)
|
|
MessageBox.Show("DEBUG: Workorder could NOT be closed due to error");
|
|
#endif
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Add text to the invoice
|
|
/// chopping into chunks less than the max 4095 characters limit
|
|
/// as necessary
|
|
/// </summary>
|
|
private static void InvoiceAddNote(StringBuilder i, string Text)
|
|
{
|
|
if (Text == null || Text == "") return;
|
|
|
|
i.Append(Text);
|
|
i.Append(" ");
|
|
|
|
|
|
|
|
}
|
|
|
|
private static void InvoiceAddTextLine(DataTable dtLines, string TextLineToAdd)
|
|
{
|
|
DataRow dr = dtLines.NewRow();
|
|
dr["ID"] = "";
|
|
dr["Description"] = TextLineToAdd;
|
|
dr["Quantity"] = 0;
|
|
dr["Price"] = 0;
|
|
dr["Amount"] = 0;
|
|
dtLines.Rows.Add(dr);
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Case 533 overload
|
|
/// </summary>
|
|
/// <param name="dtLines"></param>
|
|
/// <param name="PTListID"></param>
|
|
/// <param name="Quantity"></param>
|
|
/// <param name="rate"></param>
|
|
/// <param name="sn"></param>
|
|
private static void InvoiceAddCharge(DataTable dtLines, string PTListID, decimal Quantity, decimal rate)
|
|
{
|
|
InvoiceAddCharge(dtLines, PTListID, Quantity, rate, "");
|
|
}
|
|
/// <summary>
|
|
/// Add charge line to the invoice
|
|
///
|
|
/// </summary>
|
|
private static void InvoiceAddCharge(DataTable dtLines, string PTListID, decimal Quantity, decimal rate, string sn)//case 533
|
|
{
|
|
DataRow dr = dtLines.NewRow();
|
|
dr["ID"] = PTListID;
|
|
dr["Description"] = PTItems.Rows.Find(PTListID)["SalesDesc"].ToString();
|
|
|
|
dr["Quantity"] = Quantity.ToString();
|
|
dr["Price"] = (rate * -1).ToString();
|
|
dr["Amount"] = ((rate * Quantity) * -1).ToString();
|
|
//case 533
|
|
dr["Serial_Number"] = sn;
|
|
dtLines.Rows.Add(dr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
#region Change PT Item price
|
|
|
|
public static void ChangePTItemPrice(string PTListID, decimal NewPrice)
|
|
{
|
|
try
|
|
{
|
|
#region Generate import file
|
|
XmlTextWriter Writer = new XmlTextWriter(TempFilePath + "PTchgItem.xml", System.Text.Encoding.UTF8);
|
|
|
|
Writer.WriteStartElement("PAW_Items");
|
|
Writer.WriteAttributeString("xmlns:paw", "urn:schemas-peachtree-com/paw8.02-datatypes");
|
|
Writer.WriteAttributeString("xmlns:xsi", "http://www.w3.org/2000/10/XMLSchema-instance");
|
|
Writer.WriteAttributeString("xmlns:xsd", "http://www.w3.org/2000/10/XMLSchema-datatypes");
|
|
|
|
Writer.WriteStartElement("PAW_Item");
|
|
Writer.WriteAttributeString("xsi:type", "paw:item");
|
|
|
|
Writer.WriteStartElement("ID");
|
|
Writer.WriteAttributeString("xsi:type", "paw:ID");
|
|
Writer.WriteString(PTListID);
|
|
Writer.WriteEndElement();
|
|
|
|
Writer.WriteStartElement("Sales_Prices");
|
|
Writer.WriteStartElement("Sales_Price_Info");
|
|
Writer.WriteAttributeString("Key", "1");
|
|
Writer.WriteElementString("Sales_Price", NewPrice.ToString());//NEWPRICE
|
|
Writer.WriteEndElement();
|
|
Writer.WriteEndElement();
|
|
|
|
Writer.Close();
|
|
#endregion generate import file
|
|
|
|
#region Import
|
|
|
|
PeachtreeAccounting.Import importer = (PeachtreeAccounting.Import)ptApp.app.CreateImporter(PeachwIEObj.peachwIEObjInventoryItemsList);
|
|
importer.ClearImportFieldList();
|
|
importer.AddToImportFieldList((short)PeachwIEObjInventoryItemsListField.peachwIEObjInventoryItemsListField_ItemId);
|
|
importer.AddToImportFieldList((short)PeachwIEObjInventoryItemsListField.peachwIEObjInventoryItemsListField_UnitPrice1);
|
|
|
|
|
|
|
|
|
|
|
|
importer.SetFilename(TempFilePath + "PTchgItem.xml");
|
|
importer.SetFileType(PeachwIEFileType.peachwIEFileTypeXML);
|
|
//Array arout;
|
|
importer.Import();
|
|
// importer.ImportAndReturnGUIDs(out arout);
|
|
//if (arout.GetLength(0) < 1)
|
|
// throw new System.ApplicationException("Peachtree did not accept price change on item " + PTListID + " - no error given");
|
|
#endregion
|
|
|
|
//Update cached list with new price
|
|
PTItems.Rows.Find(PTListID)["Price"] = NewPrice;
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
IntegrationLog.Log(PTID, "ChangePTItemPrice: Failed with exception:" + ex.Message);
|
|
ErrorFree = false;
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
CurrentNode = null;
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#region various utils and helper methods
|
|
public static string CrackException(Exception ex)
|
|
{
|
|
while (ex.InnerException != null)
|
|
{
|
|
ex = ex.InnerException;
|
|
}
|
|
return ex.Message + "\r\n-------TRACE------\r\n" + ex.StackTrace;
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Case 262 addition
|
|
/// Convert a string to a double handling french canadian locale
|
|
/// , since qb is not locale aware in it's api
|
|
/// conversion can fail because .net expects a comma that isn't there
|
|
///
|
|
/// </summary>
|
|
/// <param name="s"></param>
|
|
/// <returns></returns>
|
|
public static double SafeToDouble(string s)
|
|
{
|
|
if (string.IsNullOrEmpty(s)) return 0;
|
|
|
|
try
|
|
{
|
|
return Convert.ToDouble(s, System.Globalization.CultureInfo.InvariantCulture);
|
|
}
|
|
catch (System.FormatException)
|
|
{
|
|
throw new System.ApplicationException("SafeToDouble: Can't parse PT string double value number: \"" + s + "\"");
|
|
}
|
|
|
|
|
|
}
|
|
|
|
#endregion various
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
}
|
|
}
|