diff --git a/AyaNovaQBI/MainForm.Designer.cs b/AyaNovaQBI/MainForm.Designer.cs index 475ea82..579f145 100644 --- a/AyaNovaQBI/MainForm.Designer.cs +++ b/AyaNovaQBI/MainForm.Designer.cs @@ -50,7 +50,7 @@ this.lblStatus = new System.Windows.Forms.Label(); this.id = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.customer = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.wonumber = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.Serial = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.ProjectName = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.ServiceDate = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.status = new System.Windows.Forms.DataGridViewTextBoxColumn(); @@ -212,7 +212,7 @@ this.grid.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { this.id, this.customer, - this.wonumber, + this.Serial, this.ProjectName, this.ServiceDate, this.status, @@ -243,6 +243,7 @@ // // id // + this.id.DataPropertyName = "Id"; this.id.HeaderText = "id"; this.id.Name = "id"; this.id.ReadOnly = true; @@ -255,12 +256,12 @@ this.customer.Name = "customer"; this.customer.ReadOnly = true; // - // wonumber + // Serial // - this.wonumber.DataPropertyName = "Serial"; - this.wonumber.HeaderText = "Service number"; - this.wonumber.Name = "wonumber"; - this.wonumber.ReadOnly = true; + this.Serial.DataPropertyName = "Serial"; + this.Serial.HeaderText = "Service number"; + this.Serial.Name = "Serial"; + this.Serial.ReadOnly = true; // // ProjectName // @@ -353,7 +354,7 @@ private System.Windows.Forms.Label lblStatus; private System.Windows.Forms.DataGridViewTextBoxColumn id; private System.Windows.Forms.DataGridViewTextBoxColumn customer; - private System.Windows.Forms.DataGridViewTextBoxColumn wonumber; + private System.Windows.Forms.DataGridViewTextBoxColumn Serial; private System.Windows.Forms.DataGridViewTextBoxColumn ProjectName; private System.Windows.Forms.DataGridViewTextBoxColumn ServiceDate; private System.Windows.Forms.DataGridViewTextBoxColumn status; diff --git a/AyaNovaQBI/MainForm.cs b/AyaNovaQBI/MainForm.cs index b827398..b9d6964 100644 --- a/AyaNovaQBI/MainForm.cs +++ b/AyaNovaQBI/MainForm.cs @@ -44,7 +44,6 @@ namespace AyaNovaQBI } Text = "AyaNova QBI - " + util.QCompanyName; - InitializeGrid(); //See if there are *any* data mappings, if not then we will prompt the user to start that process if (util.QBIntegration.Items.Count == 0) { @@ -172,165 +171,6 @@ namespace AyaNovaQBI b.Dispose(); } - - #region DataSet stuff - //private DataSet dsInvoices; - //private DataTable Invoices; - //private DataColumn Client; - //private DataColumn WorkingID; - //private DataColumn Linked; - //private DataColumn ClientID; - //private DataTable Workorders; - //private DataColumn InvoiceWorkingID; - //private DataColumn WorkorderID; - //private DataColumn wostatus; - //private DataColumn ServiceNumber; - //private DataColumn ServiceDate; - //private DataColumn Project; - //private DataColumn StatusARGB; - //private DataColumn dataColumn1; - //private void InitDataSet() - //{ - // dsInvoices = new DataSet(); - // Invoices = new DataTable(); - // Client = new DataColumn(); - // WorkingID = new DataColumn(); - // Linked = new DataColumn(); - // ClientID = new DataColumn(); - // Workorders = new DataTable(); - // InvoiceWorkingID = new DataColumn(); - // WorkorderID = new DataColumn(); - // wostatus = new DataColumn(); - // ServiceNumber = new DataColumn(); - // ServiceDate = new DataColumn(); - // Project = new DataColumn(); - // StatusARGB = new DataColumn(); - // dataColumn1 = new DataColumn(); - // // - // // dsInvoices - // // - // dsInvoices.DataSetName = "Invoices"; - // dsInvoices.Locale = new System.Globalization.CultureInfo("en-US"); - // dsInvoices.Relations.AddRange(new DataRelation[] { - // new DataRelation("Relation1", "Invoices", "Workorders", new string[] { - // "WorkingID"}, new string[] { - // "InvoiceWorkingID"}, false)}); - // dsInvoices.Tables.AddRange(new DataTable[] { - // Invoices, - // Workorders}); - // // - // // Invoices - // // - // Invoices.Columns.AddRange(new DataColumn[] { - // Client, - // WorkingID, - // Linked, - // ClientID}); - // Invoices.Constraints.AddRange(new Constraint[] { - // new UniqueConstraint("Constraint1", new string[] { - // "WorkingID"}, true)}); - // Invoices.PrimaryKey = new DataColumn[] { - //WorkingID}; - // Invoices.TableName = "Invoices"; - // // - // // Client - // // - // Client.ColumnName = "Client"; - // // - // // WorkingID - // // - // WorkingID.AllowDBNull = false; - // WorkingID.AutoIncrement = true; - // WorkingID.Caption = "WorkingID"; - // WorkingID.ColumnName = "WorkingID"; - // WorkingID.DataType = typeof(int); - // WorkingID.ReadOnly = true; - // // - // // Linked - // // - // Linked.Caption = "Linked"; - // Linked.ColumnName = "Linked"; - // Linked.DataType = typeof(bool); - // Linked.DefaultValue = false; - // // - // // ClientID - // // - // ClientID.Caption = "ClientID"; - // ClientID.ColumnName = "ClientID"; - // ClientID.DataType = typeof(System.Guid); - // // - // // Workorders - // // - // Workorders.Columns.AddRange(new DataColumn[] { - // InvoiceWorkingID, - // WorkorderID, - // wostatus, - // ServiceNumber, - // ServiceDate, - // Project, - // StatusARGB, - // dataColumn1}); - // Workorders.Constraints.AddRange(new Constraint[] { - // new UniqueConstraint("Constraint1", new string[] { - // "WorkorderID"}, true), - // new ForeignKeyConstraint("Relation1", "Invoices", new string[] { - // "WorkingID"}, new string[] { - // "InvoiceWorkingID"}, AcceptRejectRule.None, Rule.None, Rule.None)}); - // Workorders.PrimaryKey = new DataColumn[] { - //WorkorderID}; - // Workorders.TableName = "Workorders"; - // // - // // InvoiceWorkingID - // // - // InvoiceWorkingID.Caption = "InvoiceWorkingID"; - // InvoiceWorkingID.ColumnName = "InvoiceWorkingID"; - // InvoiceWorkingID.DataType = typeof(int); - // // - // // WorkorderID - // // - // WorkorderID.AllowDBNull = false; - // WorkorderID.Caption = "WorkorderID"; - // WorkorderID.ColumnName = "WorkorderID"; - // WorkorderID.DataType = typeof(System.Guid); - // // - // // wostatus - // // - // wostatus.Caption = "Status"; - // wostatus.ColumnName = "Status"; - // // - // // ServiceNumber - // // - // ServiceNumber.Caption = "ServiceNumber"; - // ServiceNumber.ColumnName = "ServiceNumber"; - // ServiceNumber.DataType = typeof(int); - // // - // // ServiceDate - // // - // ServiceDate.Caption = "ServiceDate"; - // ServiceDate.ColumnName = "ServiceDate"; - // ServiceDate.DataType = typeof(object); - // // - // // Project - // // - // Project.Caption = "Project"; - // Project.ColumnName = "Project"; - // // - // // StatusARGB - // // - // StatusARGB.Caption = "StatusARGB"; - // StatusARGB.ColumnName = "StatusARGB"; - // StatusARGB.DataType = typeof(int); - // // - // // dataColumn1 - // // - // dataColumn1.ColumnName = "Linked"; - // dataColumn1.DataType = typeof(bool); - // dataColumn1.DefaultValue = false; - //} - - #endregion dataset stuff - - #region Main workorder grid /// @@ -376,20 +216,7 @@ namespace AyaNovaQBI lblStatus.Visible = true; } } - /* - - POST /api/v8.0/data-list - {"offset":0,"limit":10,"dataListKey":"WorkOrderDataList","filterId":6,"clientTimeStamp":"2022-07-08T10:49:18.715-07:00"} - - data-list-column-view: - {"userId":1,"listKey":"WorkOrderDataList","columns":"[\"WorkOrderSerialNumber\",\"Customer\",\"WorkOrderServiceDate\",\"WorkOrderCloseByDate\",\"WorkOrderStatus\",\"Project\",\"WorkOrderAge\",\"WorkOrderInvoiceNumber\"]","sort":"{\"WorkOrderSerialNumber\":\"-\"}"} - - data-list-filter - filter "[{\"column\":\"WorkOrderInvoiceNumber\",\"any\":false,\"items\":[{\"op\":\"=\",\"value\":\"*NULL*\"}]}]" - - */ - - //private BindingList _WorkOrderGridListItems = new BindingList(); + private DataTable _GridTable = null; private List _MisMatches = new List(); private List _PartPriceOverrides = new List(); @@ -411,15 +238,19 @@ namespace AyaNovaQBI //datatable is required to support sorting in dgv without writing a lot of extra code _GridTable = new DataTable(); _GridTable.Columns.Add(new DataColumn("CustomerName")); - _GridTable.Columns.Add(new DataColumn("Serial")); + _GridTable.Columns.Add(new DataColumn("Serial", typeof(long))); _GridTable.Columns.Add(new DataColumn("ServiceDate", typeof(DateTime))); _GridTable.Columns.Add(new DataColumn("WorkorderStatusName")); _GridTable.Columns.Add(new DataColumn("ProjectName")); _GridTable.Columns.Add(new DataColumn("Color")); - _GridTable.Columns.Add(new DataColumn("CustomerId")); - _GridTable.Columns.Add(new DataColumn("Id")); + _GridTable.Columns.Add(new DataColumn("CustomerId", typeof(long))); + _GridTable.Columns.Add(new DataColumn("Id", typeof(long))); _GridTable.Columns.Add(new DataColumn("Linked", typeof(bool))); } + else + { + _GridTable.Clear(); + } _MisMatches.Clear(); //[HttpGet("accounting-list-billable/{workOrderStatusId}")] @@ -439,86 +270,14 @@ namespace AyaNovaQBI row["CustomerId"] = z.CustomerId; row["Id"] = z.Id; row["Linked"]= util.ScanLinksOK(z.Id, _MisMatches, _PartPriceOverrides); - _GridTable.Rows.Add(row); } - grid.DataSource = _GridTable; - - //foreach (WorkOrderAccountingListItem z in v) - //{ - // _WorkOrderGridListItems.Add(new WorkOrderGridListItem - // { - // Color = z.Color, - // CustomerId = z.CustomerId, - // CustomerName = z.CustomerName, - // Id = z.Id, - // ProjectName = z.ProjectName, - // Serial = z.Serial, - // ServiceDate = z.ServiceDate, - // WorkorderStatusName = z.WorkorderStatusName - // }); - //} - - - - - - //foreach (WorkOrderGridListItem i in _WorkOrderGridListItems) - //{ - // w.Step = "WO: " + i.Serial; - // i.Linked = util.ScanLinksOK(i.Id, _MisMatches, _PartPriceOverrides); - // //DataRow dri = InvoiceRowForClientID(i.ClientID); - - // //if (dri == null) - // //{ - // // dri = dtInvoice.NewRow(); - // // dri["Client"] = i.Client; - // // dri["ClientID"] = i.ClientID; - // // dtInvoice.Rows.Add(dri); - //} - - //If any one single workorder is linked - //then the invoice is flagged as linked because - //you can invoice out anything under it that is linked and the - //not linked items simply won't invoice - //if (bLinked) - // dri["Linked"] = true; - - //DataRow drw = dtWorkorder.NewRow(); - //drw["InvoiceWorkingID"] = (int)dri["WorkingID"]; - //drw["WorkorderID"] = i.ID; - //drw["Status"] = i.Status; - //drw["ServiceNumber"] = i.ServiceNumber; - //drw["ServiceDate"] = i.ServiceDate; - //drw["Project"] = i.Project; - //drw["StatusARGB"] = i.StatusARGB; - - //drw["Linked"] = bLinked; - //dtWorkorder.Rows.Add(drw); - - - - - - // grid.DisplayLayout.Rows.CollapseAll(false); - //foreach (UltraGridRow r in grid.Rows) - //{ - // foreach (UltraGridRow rr in r.ChildBands[0].Rows) - // { - // if ((bool)rr.Cells["Linked"].Value == false) - // r.Expanded = true; - // } - - //} - //grid.EndUpdate(); - } finally { w.Close(); } - await SetState(); } @@ -545,34 +304,6 @@ namespace AyaNovaQBI - private void InitializeGrid() - { - - //grid.DataSource = _GridTable; - //grid.Columns["WorkingID"].Visible = false; - //grid.Columns["ClientID"].Visible = false; - //grid.Columns["Linked"].Visible = false; - //grid.Columns["Client"].Visible = false; - //grid.Columns["InvoiceWorkingID"].Visible = false; - //grid.Columns["WorkorderID"].Visible = false; - //grid.Columns["StatusARGB"].Visible = false; - //grid.Columns["WorkingID"].Visible = false; - //string currentAssemblyDirectoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - - //Load the grid layout from file - //if (System.IO.File.Exists(currentAssemblyDirectoryName + "\\MainGrid.lyt")) - // grid.DisplayLayout.Load(currentAssemblyDirectoryName + "\\MainGrid.lyt"); - //grid.DisplayLayout.Bands[0].Columns["WorkingID"].Hidden = true; - //grid.DisplayLayout.Bands[0].Columns["ClientID"].Hidden = true; - //grid.DisplayLayout.Bands[0].Columns["Linked"].Hidden = true; - //grid.DisplayLayout.Bands[0].Columns["Client"].Header.Caption = "Invoice"; - - //grid.DisplayLayout.Bands[1].Columns["InvoiceWorkingID"].Hidden = true; - //grid.DisplayLayout.Bands[1].Columns["WorkorderID"].Hidden = true; - //grid.DisplayLayout.Bands[1].Columns["StatusARGB"].Hidden = true; - //grid.DisplayLayout.Bands[1].Columns["Linked"].Hidden = true; - } - //private void grid_InitializeRow(object sender, Infragistics.Win.UltraWinGrid.InitializeRowEventArgs e) //{ // if (e.Row.Band.Index == 0) diff --git a/AyaNovaQBI/MainForm.resx b/AyaNovaQBI/MainForm.resx index 738e304..fcafcaf 100644 --- a/AyaNovaQBI/MainForm.resx +++ b/AyaNovaQBI/MainForm.resx @@ -126,7 +126,7 @@ True - + True diff --git a/AyaNovaQBI/util.cs b/AyaNovaQBI/util.cs index ee1f461..ce7d836 100644 --- a/AyaNovaQBI/util.cs +++ b/AyaNovaQBI/util.cs @@ -996,7 +996,7 @@ namespace AyaNovaQBI #region Workorder item loan charge as //Validate any existing - if (SetEverything == false && QDat.WorkorderItemLoanChargeAs != null && QDat.WorkorderItemLoanChargeAs != "") + if (SetEverything == false && QDat.WorkOrderItemLoanChargeAs != null && QDat.WorkOrderItemLoanChargeAs != "") { goto LOANCHARGEASOK; } @@ -1010,14 +1010,14 @@ namespace AyaNovaQBI "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; + s2.SelectedQBItem = QDat.WorkOrderItemLoanChargeAs; if (s2.ShowDialog() == DialogResult.Cancel) { return pfstat.Cancel; } else - QDat.WorkorderItemLoanChargeAs = s2.SelectedQBItem; + QDat.WorkOrderItemLoanChargeAs = s2.SelectedQBItem; s2.Dispose(); s2 = null; @@ -5691,217 +5691,215 @@ namespace AyaNovaQBI /// and on any error found adds them to the /// mismatched object array list /// - /// Id of workorder being scanned + /// Id of workorder being scanned /// An list of mismatch objects /// An list of id 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 /// True if all links ok, false if there are any mismatches at all - public static bool ScanLinksOK(long WorkorderID, List MisMatches, List PriceOverrides) + public static async Task ScanLinksOK(long workOrderId, List MisMatches, List PriceOverrides) { bool bReturn = true; bool bSomethingToInvoice = false; - - //WorkOrder w = Workorder.GetItem(WorkorderID); - - ////Client ok? - //if (!QBIntegration.Items.Any(z=>z.AType==AyaType.Customer && z.ObjectId==w.CustomerId)) - //{ - // bReturn = false; - // AddMisMatch(AyaClientList[w.ClientID].Name, w.ClientID, AyaType.Customer, MisMatchReason.NotLinkedToQB, 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 QBI and needs to be rectified before QBI can be used.\r\n"); - - // if (!QBI.Maps.Contains(wl.ServiceRateID)) - // { - // bReturn = false; - // AddMisMatch(AyaRateList[wl.ServiceRateID].Name, wl.ServiceRateID, RootObjectTypes.Rate, MisMatchReason.NotLinkedToQB, 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 QBI and needs to be rectified before QBI can be used.\r\n"); - - // if (!QBI.Maps.Contains(wt.TravelRateID)) - // { - // bReturn = false; - // AddMisMatch(AyaRateList[wt.TravelRateID].Name, wt.TravelRateID, RootObjectTypes.Rate, MisMatchReason.NotLinkedToQB, 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 (!QBI.Maps.Contains(wp.PartID) || QBItems.Rows.Find(QBI.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.NotLinkedToQB, MisMatches); - - // } - // else - // { - // //check the price - // if (!PriceOverrides.Contains(wp.ID)) - // { - - // decimal qbPrice = (decimal)QBItems.Rows.Find(QBI.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, - // QBI.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 QB charge defined for outside service - // if (QDat.OutsideServiceChargeAs == null || - // QDat.OutsideServiceChargeAs == "" || - // !QBItems.Rows.Contains(QDat.OutsideServiceChargeAs)) - // { - // bReturn = false; - // AddMisMatch("Outside service", Guid.Empty, RootObjectTypes.WorkorderItemOutsideService, MisMatchReason.NotLinkedToQB, MisMatches); - - // } - // } - // } - // #endregion - - // #region Workorder item loan charges - - // if (wi.HasLoans) - // { - // foreach (WorkorderItemLoan wil in wi.Loans) - // { - - // if (wil.Charges != 0) - // { - // //case 772 - // bSomethingToInvoice = true; - - // //there is something billable, just need to make sure - // //that there is a QB charge defined for loaned item charges - // if (QDat.WorkorderItemLoanChargeAs == null || - // QDat.WorkorderItemLoanChargeAs == "" || - // !QBItems.Rows.Contains(QDat.WorkorderItemLoanChargeAs)) - // { - // bReturn = false; - // AddMisMatch("Workorder item loan", Guid.Empty, RootObjectTypes.WorkorderItemLoan, MisMatchReason.NotLinkedToQB, MisMatches); - // break; - - // } - // } - // } - // } - // #endregion - - // #region Workorder item misc expenses - - // if (wi.HasExpenses) - // { - // foreach (WorkorderItemMiscExpense wie in wi.Expenses) - // { + var a = await GetAsync($"workorder/{workOrderId}"); + WorkOrder w = a.ObjectResponse["data"].ToObject(); + if (w == null) + throw new Exception($"ScanLinksOK: WorkOrder with id {workOrderId} was not found in AyaNova and may have just been deleted.\r\nUnable to proceed."); - // if (wie.ChargeToClient) - // { - // bSomethingToInvoice = true; - // //there is something billable, just need to make sure - // //that there is a QB charge defined for misc expense item charges - // if (QDat.MiscExpenseChargeAs == null || - // QDat.MiscExpenseChargeAs == "" || - // !QBItems.Rows.Contains(QDat.MiscExpenseChargeAs)) - // { - // bReturn = false; - // AddMisMatch("Workorder item expense", Guid.Empty, RootObjectTypes.WorkorderItemMiscExpense, MisMatchReason.NotLinkedToQB, MisMatches); - // break; + //Client ok? + if (!QBIntegration.Items.Any(z => z.AType == AyaType.Customer && z.ObjectId == w.CustomerId)) + { + bReturn = false; + AddMisMatch(AyaClientList.FirstOrDefault(z=>z.Id==w.CustomerId).Name, w.CustomerId, AyaType.Customer, MisMatchReason.NotLinkedToQB, MisMatches); + } - // } - // } - // } - // } - // #endregion + //Service rates: + foreach (WorkOrderItem wi in w.Items) + { + #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 (null== wl.ServiceRateId || wl.ServiceRateId == 0) + throw new System.ApplicationException($"ERROR: Workorder {w.Serial} has a Labor item with no rate selected\r\nThis is a serious problem for QBI and needs to be rectified before QBI can be used.\r\n"); + + if (!QBIntegration.Items.Any(z => z.AType == AyaType.ServiceRate && z.ObjectId == wl.ServiceRateId)) + { + bReturn = false; + AddMisMatch(AyaServiceRateList.FirstOrDefault(z => z.Id == wl.ServiceRateId).Name, (long)wl.ServiceRateId, AyaType.ServiceRate, MisMatchReason.NotLinkedToQB, 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 empty + //it's possible that some users have not selected a rate on the workorder + if (null==wt.TravelRateId || wt.TravelRateId == 0) + throw new System.ApplicationException($"ERROR: Workorder {w.Serial} has a Travel item with no rate selected\r\nThis is a serious problem for QBI and needs to be rectified before QBI can be used.\r\n"); + + if (!QBIntegration.Items.Any(z => z.AType == AyaType.TravelRate && z.ObjectId == wt.TravelRateId)) + { + bReturn = false; + AddMisMatch(AyaTravelRateList.FirstOrDefault(z => z.Id == wt.TravelRateId).Name, (long)wt.TravelRateId, AyaType.TravelRate, MisMatchReason.NotLinkedToQB, 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 (!QBI.Maps.Contains(wp.PartID) || QBItems.Rows.Find(QBI.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, AyaType.Part, MisMatchReason.NotLinkedToQB, MisMatches); + + } + else + { + //check the price + if (!PriceOverrides.Contains(wp.ID)) + { + + decimal qbPrice = (decimal)QBItems.Rows.Find(QBI.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, AyaType.Part, MisMatchReason.PriceDifferent, MisMatches, qbPrice, charge, wp.ID, + QBI.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 QB charge defined for outside service + if (QDat.OutsideServiceChargeAs == null || + QDat.OutsideServiceChargeAs == "" || + !QBItems.Rows.Contains(QDat.OutsideServiceChargeAs)) + { + bReturn = false; + AddMisMatch("Outside service", Guid.Empty, AyaType.WorkOrderItemOutsideService, MisMatchReason.NotLinkedToQB, MisMatches); + + } + } + } + #endregion + + #region Workorder item loan charges + + if (wi.HasLoans) + { + foreach (WorkOrderItemLoan wil in wi.Loans) + { + + if (wil.Charges != 0) + { + //case 772 + bSomethingToInvoice = true; + + //there is something billable, just need to make sure + //that there is a QB charge defined for loaned item charges + if (QDat.WorkOrderItemLoanChargeAs == null || + QDat.WorkOrderItemLoanChargeAs == "" || + !QBItems.Rows.Contains(QDat.WorkOrderItemLoanChargeAs)) + { + bReturn = false; + AddMisMatch("Workorder item loan", Guid.Empty, AyaType.WorkOrderItemLoan, MisMatchReason.NotLinkedToQB, MisMatches); + break; + + } + } + } + } + #endregion + + #region Workorder item misc expenses + + if (wi.HasExpenses) + { + foreach (WorkOrderItemMiscExpense wie in wi.Expenses) + { - //}//workorder items loop + if (wie.ChargeToClient) + { + bSomethingToInvoice = true; + //there is something billable, just need to make sure + //that there is a QB charge defined for misc expense item charges + if (QDat.MiscExpenseChargeAs == null || + QDat.MiscExpenseChargeAs == "" || + !QBItems.Rows.Contains(QDat.MiscExpenseChargeAs)) + { + bReturn = false; + AddMisMatch("Workorder item expense", Guid.Empty, AyaType.WorkOrderItemMiscExpense, MisMatchReason.NotLinkedToQB, MisMatches); + break; - ////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); + } + } + } + } + #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, AyaType.Nothing, MisMatchReason.NothingToInvoice, MisMatches); + + } return bReturn; @@ -5910,13 +5908,13 @@ namespace AyaNovaQBI - private static void AddMisMatch(string Name, long ObjectId, AyaType ObjectType, MisMatchReason Reason, ArrayList Mismatches) + private static void AddMisMatch(string Name, long ObjectId, AyaType ObjectType, MisMatchReason Reason, List Mismatches) { AddMisMatch(Name, ObjectId, ObjectType, Reason, Mismatches, 0m, 0m, 0, ""); } private static void AddMisMatch(string Name, long ObjectId, AyaType ObjectType, - MisMatchReason Reason, ArrayList Mismatches, decimal QBPrice, decimal AyaPrice, long WorkOrderItemPartId, string QBListID) + MisMatchReason Reason, List Mismatches, decimal QBPrice, decimal AyaPrice, long WorkOrderItemPartId, string QBListID) { bool bDuplicate = false; //scan through list of existing mismatches, @@ -5927,9 +5925,8 @@ namespace AyaNovaQBI if (Reason == MisMatchReason.NotLinkedToQB) { - foreach (object o in Mismatches) - { - MisMatch m = (MisMatch)o; + foreach (var m in Mismatches) + { //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