From f523e8c517b03b2bd681592449c559b11a9c32ac Mon Sep 17 00:00:00 2001 From: John Cardinal Date: Thu, 30 Jun 2022 20:21:38 +0000 Subject: [PATCH] --- AyaNovaQBI/MainForm.cs | 2 +- AyaNovaQBI/util.cs | 607 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 607 insertions(+), 2 deletions(-) diff --git a/AyaNovaQBI/MainForm.cs b/AyaNovaQBI/MainForm.cs index 471781e..31ca135 100644 --- a/AyaNovaQBI/MainForm.cs +++ b/AyaNovaQBI/MainForm.cs @@ -34,7 +34,7 @@ namespace AyaNovaQBI else { //check if setup is required - if (string.IsNullOrWhiteSpace(util.QBIntegration.IntegrationData) || util.QBIntegration.Items.Count == 0) + if (util.QBIntegration.Items.Count == 0) { MessageBox.Show("STUB: mainform, SETUP is required for qbi, no maps, no integration data set"); } diff --git a/AyaNovaQBI/util.cs b/AyaNovaQBI/util.cs index 1e41530..dac622e 100644 --- a/AyaNovaQBI/util.cs +++ b/AyaNovaQBI/util.cs @@ -42,6 +42,7 @@ namespace AyaNovaQBI internal static AyaNovaLicense ALicense { get; set; } = null; internal static Integration QBIntegration { get; set; } = null; + internal static QBIIntegrationData QDat { get; set; } = null; internal static bool LOG_AVAILABLE { get; set; } = false; @@ -600,7 +601,8 @@ namespace AyaNovaQBI QBIntegration.IntegrationAppId = QBI_INTEGRATION_ID; QBIntegration.Active = true; QBIntegration.Name = "QBI - QuickBooks Desktop integration"; - QBIntegration.IntegrationData = Newtonsoft.Json.JsonConvert.SerializeObject(new QBIIntegrationData());//default empty integration data object + QDat = new QBIIntegrationData(); + QBIntegration.IntegrationData = Newtonsoft.Json.JsonConvert.SerializeObject(QDat);//default empty integration data object r = await PostAsync("integration", Newtonsoft.Json.JsonConvert.SerializeObject(QBIntegration)); QBIntegration.Id = IdFromResponse(r); await IntegrationLog("AyaNova QBI Integration installed to AyaNova"); @@ -616,6 +618,7 @@ namespace AyaNovaQBI initErrors.AppendLine("QBI Integration data is empty which should not happen normally and indicates corruption of some kind with the QBI setttings data stored in AyaNova.\r\nThe QBI settings should be removed and re-created by deleting the QBI Integration object in AyaNova\r\nSee the Administration section -> Integrations -> QuickBooks Desktop integration record in AyaNova\r\nThis record should be deleted then restart QBI to start setup again and create a fresh QBI integration settings object in AyaNova"); return false; } + QDat = Newtonsoft.Json.JsonConvert.DeserializeObject(QBIntegration.IntegrationData); if (!QBIntegration.Active) { @@ -734,6 +737,608 @@ namespace AyaNovaQBI public static async Task IntegrationLog(string logLine) => await PostAsync("integration/log", Newtonsoft.Json.JsonConvert.SerializeObject(new NameIdItem { Id = QBIntegration.Id, Name = logLine })); + + #region Validate User settings are completed and valid + + //case 3268 + public static string TRANSACTION_CLASS_NO_CLASS_SELECTED = ""; + + /// + /// Validate the users preferences + /// if any are missing or invalid prompt for them + /// + /// + 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 (QDat.NothingSet) + { + SetEverything = true; + MessageBox.Show( + "AyaNova QBI has now connected sucessfully to both AyaNova and QuickBooks.\r\n\r\n" + + "The next step is to set preferences for how AyaNova QBI will operate.\r\n\r\n" + + "AyaNova QBI will now step through each setting and get your preference\r\n" + + "in order to integrate AyaNova with QuickBooks.\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.QBCompanyName = QCompanyName.Replace("&", "&&"); + s0.QBCompanyPath = QCompanyFile; + + if (s0.ShowDialog() == DialogResult.Cancel) + { + IntegrationLog.Log(QBID, "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 && QDat.PreWOStatus != Guid.Empty) + { + if (WorkorderStatus.Exists(QDat.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 QBI setup - Choose billable Workorder Status"; + s1.OptionTitle = "Billable workorder status"; + s1.OptionDescription = "One of AyaNova QBI'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 QBI 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 QBI \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 = QDat.PreWOStatus; + s1.PreStatus = true; + if (s1.ShowDialog() == DialogResult.Cancel) + { + return pfstat.Cancel; + + } + else + QDat.PreWOStatus = s1.SelectedStatus; + + + PRESTATUSOK: + #endregion + + #region WO POST status + + //Validate any existing status + if (SetEverything == false && QDat.PostWOStatus != Guid.Empty) + { + if (WorkorderStatus.Exists(QDat.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 QBI setup - Choose post billed Workorder Status"; + s1.OptionTitle = "Post billing workorder status"; + s1.OptionDescription = "After QBI has billed out a work order, it can change the \r\n" + + "work order status for you automatically if desired."; + s1.SelectedStatus = QDat.PostWOStatus; + s1.PreStatus = false; + if (s1.ShowDialog() == DialogResult.Cancel) + { + return pfstat.Cancel; + + } + else + QDat.PostWOStatus = s1.SelectedStatus; + s1.Dispose(); + s1 = null; + + POSTSTATUSOK: + #endregion + + #region Outside service charge as + //Validate any existing status + if (SetEverything == false && QDat.OutsideServiceChargeAs != null && QDat.OutsideServiceChargeAs != "") + { + if (QBItems.Rows.Contains(QDat.OutsideServiceChargeAs)) + goto OUTSIDESERVICECHARGEASOK; + else + { + MessageBox.Show("The QuickBooks 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" + + "QuickBooks Item."); + } + } + + + //We've arrived here because there is no valid setting for OutsideServiceChargeAs + SetQBChargeAs s2 = new SetQBChargeAs(); + s2.DialogTitle = "AyaNova QBI setup - Charge outside service as?"; + s2.OptionTitle = "Outside service"; + s2.OptionDescription = "QBI needs to know what QuickBooks 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.QBItems = QBItems; + s2.SelectedQBItem = QDat.OutsideServiceChargeAs; + //s2.SelectedQBItem=QDat.PreWOStatus; + if (s2.ShowDialog() == DialogResult.Cancel) + { + return pfstat.Cancel; + + } + else + QDat.OutsideServiceChargeAs = s2.SelectedQBItem; + s2.Dispose(); + s2 = null; + + OUTSIDESERVICECHARGEASOK: + + #endregion + + #region Misc expense charge as + //Validate any existing + if (SetEverything == false && QDat.MiscExpenseChargeAs != null && QDat.MiscExpenseChargeAs != "") + { + //if(QBItems.Rows.Contains(QDat.MiscExpenseChargeAs)) + goto MISCCHARGEASOK; + // else + // { + // MessageBox.Show("The QuickBooks 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" + + // "QuickBooks Item."); + // } + } + + + //We've arrived here because there is no valid setting for Misc expense + s2 = new SetQBChargeAs(); + s2.DialogTitle = "AyaNova QBI setup - Charge Misc. Expense as?"; + s2.OptionTitle = "Miscellaneous expenses"; + s2.OptionDescription = "QBI needs to know what QuickBooks 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.QBItems = QBItems; + s2.SelectedQBItem = QDat.MiscExpenseChargeAs; + + if (s2.ShowDialog() == DialogResult.Cancel) + { + return pfstat.Cancel; + + } + else + QDat.MiscExpenseChargeAs = s2.SelectedQBItem; + s2.Dispose(); + s2 = null; + + MISCCHARGEASOK: + + #endregion + + #region Workorder item loan charge as + //Validate any existing + if (SetEverything == false && QDat.WorkorderItemLoanChargeAs != null && QDat.WorkorderItemLoanChargeAs != "") + { + //if(QBItems.Rows.Contains(QDat.MiscExpenseChargeAs)) + goto LOANCHARGEASOK; + // else + // { + // MessageBox.Show("The QuickBooks 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" + + // "QuickBooks Item."); + // } + } + + + //We've arrived here because there is no valid setting for Misc expense + s2 = new SetQBChargeAs(); + s2.DialogTitle = "AyaNova QBI setup - Charge loan item as?"; + s2.OptionTitle = "Work order loans"; + s2.OptionDescription = "QBI needs to know what QuickBooks 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.QBItems = QBItems; + s2.SelectedQBItem = QDat.WorkorderItemLoanChargeAs; + if (s2.ShowDialog() == DialogResult.Cancel) + { + return pfstat.Cancel; + + } + else + QDat.WorkorderItemLoanChargeAs = s2.SelectedQBItem; + s2.Dispose(); + s2 = null; + + LOANCHARGEASOK: + + #endregion + + #region QB Transaction class + //Validate any existing + if (SetEverything == false && QDat.TransactionClass != null && QDat.TransactionClass != "") + { + //if something is set but there are no tr classes + //then just clear it and move along + if (QBClasses.Rows.Count == 1) + { + QDat.TransactionClass = TRANSACTION_CLASS_NO_CLASS_SELECTED;//case 3268 + goto TRCLASSOK; + } + + //Something is set and there *are* tr classes so + //let's validate it... + + if (QBClasses.Rows.Contains(QDat.TransactionClass)) + goto TRCLASSOK; + else + { + MessageBox.Show("The QuickBooks transaction class previously set for invoicing\r\n" + + "no longer appears to be valid. You will next be prompted to re-select it."); + } + } + + //Perhaps there are no transaction classes, this is the default + //if not then don't prompt for it obviously :) + //also if it was empty and were not in first setup mode then + //don't bother prompting it might be the users choice. + + //case 3228 commented out the following as it's a bad idea + //if (QBClasses.Rows.Count == 1 || SetEverything == false) + // goto TRCLASSOK; + + + //We've arrived here because there is no setting for transaction classes + //but there are some defined in QB + SetQBClass s3 = new SetQBClass(); + s3.DialogTitle = "AyaNova QBI setup - Transaction class"; + s3.OptionTitle = "Transaction class"; + s3.OptionDescription = "QBI needs to know what QuickBooks Transaction Class you want \r\n" + + "to use when invoicing Work orders.\r\n\r\n" + + "If you do not use transaction classes or are not sure what they are\r\n" + + "select < Do not use classes> from the list below. Classes are off by default in QuickBooks.\r\n\r\n" + + "This setting is Optional and not required."; + s3.QBClasses = QBClasses; + + if (s3.ShowDialog() == DialogResult.Cancel) + { + return pfstat.Cancel; + + } + else + QDat.TransactionClass = s3.SelectedQBClass; + s3.Dispose(); + s3 = null; + + TRCLASSOK: + + #endregion + + #region QB InvoiceTemplate + //Templates are only supported in xml 3 or greater (all countries) + //if Set everything (first run) then display a dialog about it + if (QVersion < 3 && SetEverything == true) + { + + SetInfoOnly s3a = new SetInfoOnly(); + s3a.DialogTitle = "AyaNova QBI setup - Invoice template"; + s3a.OptionTitle = "Invoice template - NOT SUPPORTED"; + s3a.OptionDescription = + "QBI can use a specific QuickBooks Invoice template for printing work orders.\r\n" + + "However, your version of QuickBooks does not support integrating this \r\n" + + "feature with 3rd party applications such as AyaNova QBI.\r\n" + + + "Supported versions of QuickBooks for using Invoice templates with QBI are:\r\n\r\n" + + "U.S., Canadian or U.K. QuickBooks 2004 or newer\r\n\r\n" + + + "If you upgrade your QuickBooks in future you will be able to select this option\r\n" + + "for now it is disabled and the default invoice template will be used"; + + s3a.ShowDialog(); + + goto TRInvoiceTemplateOK; + } + + //Subsequent, non-setup, runs with unsupported version + if (QVersion < 3) + goto TRInvoiceTemplateOK; + + + //Validate any existing + if (QDat.QBInvoiceTemplate != null && QDat.QBInvoiceTemplate != "") + { + //if something is set but there are no InvoiceTemplates + //then just clear it and move along + if (QBInvoiceTemplates.Rows.Count == 1) + { + QDat.QBInvoiceTemplate = ""; + goto TRInvoiceTemplateOK; + } + + //Something is set and there *are* tr InvoiceTemplates so + //let's validate it... + if (QBInvoiceTemplates.Rows.Contains(QDat.QBInvoiceTemplate)) + { + if (!SetEverything) + goto TRInvoiceTemplateOK; + } + else + { + MessageBox.Show("The QuickBooks Invoice Template previously set for invoicing\r\n" + + "no longer appears to be valid. You will next be prompted to re-select it."); + } + } + + //Perhaps there are no InvoiceTemplates, this is the default + //if not then don't prompt for it obviously :) + //also if it was empty and were not in first setup mode then + //don't bother prompting it might be the users choice. + //todo: make something besides and empty string to indicate + //deliberately non selected items + if (QBInvoiceTemplates.Rows.Count == 1 || SetEverything == false) + goto TRInvoiceTemplateOK; + + + //We've arrived here because there is no setting for InvoiceTemplates + //Or the user want's to change it + //and there are some defined in QB + SetQBInvoiceTemplate s3b = new SetQBInvoiceTemplate(); + s3b.DialogTitle = "AyaNova QBI setup - Invoice template"; + s3b.OptionTitle = "Invoice template"; + s3b.OptionDescription = "QBI needs to know what QuickBooks Invoice template you want \r\n" + + "QBI to set for invoices created from Work orders.\r\n\r\n" + + "QuickBooks Invoice templates are used in QuickBooks to specify different print formats\r\n" + + "for invoices. If you do not use Invoice templates or are not sure what they are\r\n" + + "select < Use default > from the list below.\r\n\r\n" + + "This setting is required."; + s3b.QBInvoiceTemplates = QBInvoiceTemplates; + + s3b.SelectedQBInvoiceTemplate = QDat.QBInvoiceTemplate; + + if (s3b.ShowDialog() == DialogResult.Cancel) + { + return pfstat.Cancel; + + } + else + QDat.QBInvoiceTemplate = s3b.SelectedQBInvoiceTemplate; + s3b.Dispose(); + s3b = null; + + TRInvoiceTemplateOK: + + + #endregion + + #region QB Terms + + + + //Validate any existing + //case 3228 added extra condition set everything is false + if (SetEverything == false && !string.IsNullOrEmpty(QDat.TermsDefault)) + { + //if something is set but there are no terms + //then just clear it and move along + if (QBTerms.Rows.Count == 1) + { + QDat.TermsDefault = ""; + goto TermsOK; + } + + //Something is set and there *are* terms so + //let's validate it... + if (QBTerms.Rows.Contains(QDat.TermsDefault)) + { + if (!SetEverything) + goto TermsOK; + } + else + { + MessageBox.Show("The QuickBooks default terms previously set for invoicing\r\n" + + "no longer appears to be valid. You will next be prompted to re-select it."); + } + } + + + + + //We've arrived here because there is no setting for Terms + //Or the user want's to change it + //and there are some defined in QB + SetQBTerms termsdialog = new SetQBTerms(); + termsdialog.DialogTitle = "AyaNova QBI setup - Customer default invoice terms"; + termsdialog.OptionTitle = "Default terms"; + termsdialog.OptionDescription = "QBI needs to know what QuickBooks terms you want \r\n" + + "QBI to set for customers imported from AyaNova.\r\n\r\n" + + "When an invoice for a customer is created the selected terms will be applied.\r\n\r\n" + + "This setting is required."; + termsdialog.QBTerms = QBTerms; + + termsdialog.SelectedQBTerm = QDat.TermsDefault; + + if (termsdialog.ShowDialog() == DialogResult.Cancel) + { + return pfstat.Cancel; + + } + else + QDat.TermsDefault = termsdialog.SelectedQBTerm; + termsdialog.Dispose(); + termsdialog = null; + + TermsOK: + + + #endregion + + #region ToBePrinted + //No validation possible + //so prompt only if not setup yet + if (!SetEverything) + { + //if(QBItems.Rows.Contains(QDat.MiscExpenseChargeAs)) + goto TBPOK; + // else + // { + // MessageBox.Show("The QuickBooks 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" + + // "QuickBooks Item."); + // } + } + + + + + + SetToBePrinted s4 = new SetToBePrinted(); + s4.DialogTitle = "AyaNova QBI setup - Set invoice to be printed?"; + s4.OptionTitle = "Invoice to be printed"; + s4.OptionDescription = "QBI needs to know if you want invoices that it creates \r\n" + + "in QuickBooks to be set to \"To be printed\".\r\n\r\n" + + "(Please note that \"To be emailed\" which is available in some\r\n" + + "versions of QuickBooks is not an option at this time as\r\n" + + "QuickBooks has not exposed that property to developers)"; + s4.ToBePrinted = QDat.ToBePrinted; + + if (s4.ShowDialog() == DialogResult.Cancel) + { + return pfstat.Cancel; + + } + else + QDat.ToBePrinted = s4.ToBePrinted; + s4.Dispose(); + s4 = null; + + TBPOK: + + #endregion + + #region SetMemoField + //No validation possible + //so prompt only if not setup yet + if (!SetEverything) + { + //if(QBItems.Rows.Contains(QDat.MiscExpenseChargeAs)) + goto SETMEMOOK; + // else + // { + // MessageBox.Show("The QuickBooks 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" + + // "QuickBooks Item."); + // } + } + + + + + + SetMemoField s5 = new SetMemoField(); + s5.DialogTitle = "AyaNova QBI setup - Set Memo field?"; + s5.OptionTitle = "Invoice memo field"; + s5.OptionDescription = + "QBI needs to know if you want invoices that it creates \r\n" + + "in QuickBooks to have their \"Memo\" 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 = QDat.SetMemoField; + + if (s5.ShowDialog() == DialogResult.Cancel) + { + return pfstat.Cancel; + + } + else + QDat.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 QBI setup - Close when invoiced?"; + s6.OptionTitle = "Close work order after invoicing"; + s6.OptionDescription = + "QBI needs to know if you want work orders that it invoices \r\n" + + "automatically set to closed"; + s6.AutoClose = QDat.AutoClose; + + if (s6.ShowDialog() == DialogResult.Cancel) + { + return pfstat.Cancel; + + } + else + QDat.AutoClose = s6.AutoClose; + s6.Dispose(); + s6 = null; + + SETAUTOCLOSEOK: + + #endregion + + + //Save if changes made + if (QDat.IsDirty) + { + //Case 299 + QBI.AIObject = QDat.XMLData; + //QBI.AIObject=QDat; + + QBI = (Integration)QBI.Save(); + QDat.IsDirty = false; + } + + return pfstat.OK; + } + #endregion validate user settings + + + #region PFC QB side /// /// Open QB connection