@@ -223,6 +223,14 @@
|
||||
<Compile Include="Waiting.Designer.cs">
|
||||
<DependentUpon>Waiting.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="WorkOrder.cs" />
|
||||
<Compile Include="WorkOrderItem.cs" />
|
||||
<Compile Include="WorkOrderItemExpense.cs" />
|
||||
<Compile Include="WorkOrderItemLabor.cs" />
|
||||
<Compile Include="WorkOrderItemLoan.cs" />
|
||||
<Compile Include="WorkOrderItemOutsideService.cs" />
|
||||
<Compile Include="WorkOrderItemPart.cs" />
|
||||
<Compile Include="WorkOrderItemTravel.cs" />
|
||||
<Compile Include="WorkOrderStatus.cs" />
|
||||
<Compile Include="SetQBImportInventoryAccounts.cs">
|
||||
<SubType>Form</SubType>
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace AyaNovaQBI
|
||||
public MainForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.Icon = AyaNovaQBI.Properties.Resources.logo;
|
||||
Icon = AyaNovaQBI.Properties.Resources.logo;
|
||||
}
|
||||
|
||||
async private void MainForm_Load(object sender, EventArgs e)
|
||||
@@ -32,28 +32,37 @@ namespace AyaNovaQBI
|
||||
await Task.Run(() => MessageBox.Show($"AyaNova QBI was unable to start:\r\n{initErrors.ToString()}"));
|
||||
}
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Confirm main settings and set any that are missing:
|
||||
if (await util.ValidateSettings(false) == util.pfstat.Cancel)
|
||||
{
|
||||
await util.IntegrationLog("PFC: User settings not completed, user selected cancel");
|
||||
Close();
|
||||
}
|
||||
|
||||
//check if setup is required
|
||||
//if (util.QBIntegration.Items.Count == 0)
|
||||
//{
|
||||
// MessageBox.Show("STUB: mainform,no maps, no integration data set");
|
||||
//}
|
||||
//Confirm main settings and set any that are missing:
|
||||
if (await util.ValidateSettings(false) == util.pfstat.Cancel)
|
||||
{
|
||||
await util.IntegrationLog("PFC: User settings not completed, user selected cancel");
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
Text = "AyaNova QBI - " + util.QCompanyName;
|
||||
|
||||
//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)
|
||||
{
|
||||
//show message about mapping
|
||||
MessageBox.Show(
|
||||
"AyaNova QBI now needs you to map data between QuickBooks and AyaNova.",
|
||||
"Setup mapping", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
|
||||
Map m = new Map();
|
||||
if (m.ShowDialog() == DialogResult.Abort)
|
||||
Close();
|
||||
|
||||
}
|
||||
//Display billable workorders
|
||||
InitInvoices();
|
||||
|
||||
grid.Visible = true;
|
||||
menuStrip1.Enabled = true;
|
||||
//MessageBox.Show("DONE / OK");
|
||||
|
||||
// grid.DataSource = util.GetInvoiceableItems();
|
||||
}
|
||||
|
||||
private void grid_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
|
||||
@@ -116,18 +125,17 @@ namespace AyaNovaQBI
|
||||
private async void preferencesToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
await util.ValidateSettings(true);
|
||||
//TODO: CODE THIS InitInvoices();
|
||||
}
|
||||
|
||||
private void mapAndImportToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Map m = new Map();
|
||||
if (m.ShowDialog() == DialogResult.Abort)
|
||||
this.Close();
|
||||
Close();
|
||||
else
|
||||
{
|
||||
m.Dispose();
|
||||
//todo: this.InitInvoices();
|
||||
InitInvoices();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,7 +150,7 @@ namespace AyaNovaQBI
|
||||
MessageBox.Show(sVersion, "About");
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void onlineManualToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
util.OpenWebURL("https://ayanova.com/qbi/docs");
|
||||
@@ -154,14 +162,224 @@ namespace AyaNovaQBI
|
||||
await util.PopulateAyaListCache();
|
||||
}
|
||||
|
||||
private async void invoiceDescriptiveTextTemplateToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
private async void invoiceDescriptiveTextTemplateToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
InvoiceTemplateBuilder b = new InvoiceTemplateBuilder();
|
||||
b.ShowDialog();
|
||||
if (util.QDat.IsDirty)
|
||||
if (util.QDat.IsDirty)
|
||||
await util.SaveIntegrationObject();
|
||||
|
||||
b.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#region Main workorder grid
|
||||
|
||||
/// <summary>
|
||||
/// Adjusts main form display to either show a list of billable workorders
|
||||
/// or a status indicating there are none and why
|
||||
/// </summary>
|
||||
private void SetState()
|
||||
{
|
||||
fixProblemsToolStripMenuItem.Enabled = _MisMatches.Count > 0;
|
||||
|
||||
if (grid.Rows.Count > 0)
|
||||
{
|
||||
|
||||
grid.Visible = true;
|
||||
this.lblStatus.Visible = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append("No invoiceable work orders found in AyaNova\r\n\r\n");
|
||||
sb.Append("A work order is invoiceable and will be listed here if it has:\r\n");
|
||||
sb.Append(" - \"Invoice number\" field empty\r\n");
|
||||
if (util.QDat.PreWOStatus != Guid.Empty)
|
||||
{
|
||||
sb.Append(" - \"Status\" field set to: ");
|
||||
sb.Append(NameFetcher.GetItem("aWorkorderStatus", "aName", util.QDat.PreWOStatus));
|
||||
sb.Append("\r\n");
|
||||
sb.Append(" (You can change this status under Tools->Preferences in the menu)");
|
||||
|
||||
}
|
||||
this.lblStatus.Text = sb.ToString();
|
||||
|
||||
grid.Visible = false;
|
||||
this.lblStatus.Visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
private WorkorderServiceBillableList _wolist = null;
|
||||
private ArrayList _MisMatches = new ArrayList();
|
||||
private ArrayList _PartPriceOverrides = new ArrayList();
|
||||
/// <summary>
|
||||
/// Initialize invoices dataset
|
||||
/// from scratch. If a previous
|
||||
/// initialize was done, wipe it and
|
||||
/// repopulate from scratch
|
||||
/// </summary>
|
||||
private void InitInvoices()
|
||||
{
|
||||
Waiting w = new Waiting();
|
||||
w.Show();
|
||||
w.Ops = "Validating invoices...";
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
_MisMatches.Clear();
|
||||
grid.BeginUpdate();
|
||||
dsInvoices.Clear();
|
||||
_wolist = WorkorderServiceBillableList.GetList(Util.QDat.PreWOStatus, true);
|
||||
DataTable dtInvoice = dsInvoices.Tables["Invoices"];
|
||||
DataTable dtWorkorder = dsInvoices.Tables["Workorders"];
|
||||
foreach (WorkorderServiceBillableList.WorkorderServiceBillableListInfo i in _wolist)
|
||||
{
|
||||
bool bLinked = Util.ScanLinksOK(i.ID, _MisMatches, _PartPriceOverrides);
|
||||
|
||||
DataRow dri = InvoiceRowForClientID(i.ClientID);
|
||||
w.Step = "WO: " + i.ServiceNumber;
|
||||
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();
|
||||
}
|
||||
|
||||
SetState();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Helper for grouping workorders by client
|
||||
/// </summary>
|
||||
/// <param name="ClientID"></param>
|
||||
/// <returns>null if not found else datarow containing invoice for client</returns>
|
||||
private DataRow InvoiceRowForClientID(Guid ClientID)
|
||||
{
|
||||
foreach (DataRow r in dsInvoices.Tables["Invoices"].Rows)
|
||||
{
|
||||
if ((Guid)r["ClientID"] == ClientID)
|
||||
{
|
||||
return r;
|
||||
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void InitializeGrid()
|
||||
{
|
||||
grid.DataSource = dsInvoices;
|
||||
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)
|
||||
{
|
||||
//Prepare invoice row
|
||||
if ((bool)e.Row.Cells["Linked"].Value == true)
|
||||
{
|
||||
e.Row.Cells["Client"].Appearance.Image = Util.AyaImage("OK16");//Util.Image("OK16.png");
|
||||
}
|
||||
else
|
||||
{
|
||||
e.Row.Cells["Client"].Appearance.Image = Util.AyaImage("Cancel16");//Util.Image("Cancel16.png");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//prepare workorder row
|
||||
|
||||
//if backcolor==0 that means no color was set
|
||||
int nColor = (int)e.Row.Cells["StatusARGB"].Value;
|
||||
if (nColor != 0)
|
||||
{
|
||||
e.Row.Cells["Status"].Appearance.BackColor = Color.FromArgb(nColor);
|
||||
e.Row.Cells["Status"].Appearance.ForeColor = Util.InvertColor(Color.FromArgb(nColor));
|
||||
|
||||
}
|
||||
|
||||
//flag whether billable (linked) or not
|
||||
if ((bool)e.Row.Cells["Linked"].Value == true)
|
||||
{
|
||||
e.Row.Cells["ServiceNumber"].Appearance.Image = Util.AyaImage("OK16");
|
||||
}
|
||||
else
|
||||
{
|
||||
e.Row.Cells["ServiceNumber"].Appearance.Image = Util.AyaImage("Cancel16");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}//eoc
|
||||
}//eons
|
||||
|
||||
131
AyaNovaQBI/WorkOrder.cs
Normal file
@@ -0,0 +1,131 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AyaNovaQBI
|
||||
{
|
||||
internal class WorkOrder
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public uint Concurrency { get; set; }
|
||||
|
||||
|
||||
public long Serial { get; set; }
|
||||
|
||||
public string Notes { get; set; }//WAS "SUMMARY"
|
||||
public string Wiki { get; set; }
|
||||
public string CustomFields { get; set; }
|
||||
public List<string> Tags { get; set; } = new List<string>();
|
||||
|
||||
|
||||
public long CustomerId { get; set; }
|
||||
|
||||
public string CustomerViz { get; set; }
|
||||
|
||||
|
||||
public string CustomerTechNotesViz { get; set; }
|
||||
|
||||
public string CustomerPhone1Viz { get; set; }
|
||||
|
||||
public string CustomerPhone2Viz { get; set; }
|
||||
|
||||
public string CustomerPhone3Viz { get; set; }
|
||||
|
||||
public string CustomerPhone4Viz { get; set; }
|
||||
|
||||
public string CustomerPhone5Viz { get; set; }
|
||||
|
||||
public string CustomerEmailAddressViz { get; set; }
|
||||
|
||||
public long? ProjectId { get; set; }
|
||||
|
||||
public string ProjectViz { get; set; }
|
||||
public string InternalReferenceNumber { get; set; }
|
||||
public string CustomerReferenceNumber { get; set; }
|
||||
public string CustomerContactName { get; set; }
|
||||
public long? FromQuoteId { get; set; }
|
||||
public long? FromPMId { get; set; }
|
||||
|
||||
public DateTime CreatedDate { get; set; } = DateTime.UtcNow;
|
||||
public DateTime? ServiceDate { get; set; }
|
||||
public DateTime? CompleteByDate { get; set; }
|
||||
public TimeSpan DurationToCompleted { get; set; } = TimeSpan.Zero;
|
||||
public string InvoiceNumber { get; set; }
|
||||
public string CustomerSignature { get; set; }
|
||||
public string CustomerSignatureName { get; set; }
|
||||
public DateTime? CustomerSignatureCaptured { get; set; }
|
||||
public string TechSignature { get; set; }
|
||||
public string TechSignatureName { get; set; }
|
||||
public DateTime? TechSignatureCaptured { get; set; }
|
||||
public bool Onsite { get; set; }
|
||||
public long? ContractId { get; set; }
|
||||
|
||||
public string ContractViz { get; set; }
|
||||
|
||||
//redundant field to speed up list queries
|
||||
//(added after status system already coded)
|
||||
public long? LastStatusId { get; set; }
|
||||
|
||||
|
||||
//POSTAL ADDRESS / "BILLING ADDRESS"
|
||||
public string PostAddress { get; set; }
|
||||
public string PostCity { get; set; }
|
||||
public string PostRegion { get; set; }
|
||||
public string PostCountry { get; set; }
|
||||
public string PostCode { get; set; }
|
||||
|
||||
//PHYSICAL ADDRESS / "SERVICE ADDRESS"
|
||||
public string Address { get; set; }
|
||||
public string City { get; set; }
|
||||
public string Region { get; set; }
|
||||
public string Country { get; set; }
|
||||
public decimal? Latitude { get; set; }
|
||||
public decimal? Longitude { get; set; }
|
||||
|
||||
public List<WorkOrderItem> Items { get; set; } = new List<WorkOrderItem>();
|
||||
public List<WorkOrderState> States { get; set; } = new List<WorkOrderState>();
|
||||
|
||||
|
||||
//UTILITY FIELDS
|
||||
|
||||
public bool IsLockedAtServer { get; set; } = false;//signal to client that it came from the server in a locked state
|
||||
|
||||
public string AlertViz { get; set; } = null;
|
||||
|
||||
public string FromQuoteViz { get; set; }
|
||||
|
||||
public string FromPMViz { get; set; }
|
||||
|
||||
|
||||
public string LastStateUserViz { get; set; }
|
||||
|
||||
public string LastStateNameViz { get; set; }
|
||||
|
||||
public string LastStateColorViz { get; set; }
|
||||
|
||||
public bool LastStateCompletedViz { get; set; }
|
||||
|
||||
public bool LastStateLockedViz { get; set; }
|
||||
|
||||
|
||||
|
||||
public bool IsCompleteRecord { get; set; } = true;//indicates if some items were removed due to user role / type restrictions (i.e. woitems they are not scheduled on)
|
||||
|
||||
|
||||
public bool UserIsRestrictedType { get; set; }
|
||||
|
||||
public bool UserIsTechRestricted { get; set; }
|
||||
|
||||
public bool UserIsSubContractorFull { get; set; }
|
||||
|
||||
public bool UserIsSubContractorRestricted { get; set; }
|
||||
|
||||
public bool UserCanViewPartCosts { get; set; }
|
||||
|
||||
public bool UserCanViewLaborOrTravelRateCosts { get; set; }
|
||||
|
||||
public bool UserCanViewLoanerCosts { get; set; }
|
||||
}
|
||||
}
|
||||
60
AyaNovaQBI/WorkOrderItem.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AyaNovaQBI
|
||||
{
|
||||
internal class WorkOrderItem
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public uint Concurrency { get; set; }
|
||||
public string Notes { get; set; }//"Summary" field
|
||||
public string Wiki { get; set; }
|
||||
public string CustomFields { get; set; }
|
||||
public List<string> Tags { get; set; } = new List<string>();
|
||||
|
||||
|
||||
public long WorkOrderId { get; set; }
|
||||
public string TechNotes { get; set; }
|
||||
public long? WorkOrderItemStatusId { get; set; }
|
||||
|
||||
public string WorkOrderItemStatusNameViz { get; set; }
|
||||
|
||||
public string WorkOrderItemStatusColorViz { get; set; }
|
||||
|
||||
public long? WorkOrderItemPriorityId { get; set; }
|
||||
|
||||
public string WorkOrderItemPriorityNameViz { get; set; }
|
||||
|
||||
public string WorkOrderItemPriorityColorViz { get; set; }
|
||||
|
||||
public DateTime? RequestDate { get; set; }
|
||||
public bool WarrantyService { get; set; } = false;
|
||||
public int Sequence { get; set; }
|
||||
|
||||
public long? FromCSRId { get; set; }
|
||||
|
||||
public string FromCSRViz { get; set; }
|
||||
|
||||
//workaround for notification
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
//Principle
|
||||
|
||||
public WorkOrder WorkOrder { get; set; }
|
||||
//dependents
|
||||
public List<WorkOrderItemExpense> Expenses { get; set; } = new List<WorkOrderItemExpense>();
|
||||
public List<WorkOrderItemLabor> Labors { get; set; } = new List<WorkOrderItemLabor>();
|
||||
public List<WorkOrderItemLoan> Loans { get; set; } = new List<WorkOrderItemLoan>();
|
||||
public List<WorkOrderItemPart> Parts { get; set; } = new List<WorkOrderItemPart>();
|
||||
public List<WorkOrderItemPartRequest> PartRequests { get; set; } = new List<WorkOrderItemPartRequest>();
|
||||
public List<WorkOrderItemScheduledUser> ScheduledUsers { get; set; } = new List<WorkOrderItemScheduledUser>();
|
||||
public List<WorkOrderItemTask> Tasks { get; set; } = new List<WorkOrderItemTask>();
|
||||
public List<WorkOrderItemTravel> Travels { get; set; } = new List<WorkOrderItemTravel>();
|
||||
public List<WorkOrderItemUnit> Units { get; set; } = new List<WorkOrderItemUnit>();
|
||||
public List<WorkOrderItemOutsideService> OutsideServices { get; set; } = new List<WorkOrderItemOutsideService>();
|
||||
}
|
||||
}
|
||||
41
AyaNovaQBI/WorkOrderItemExpense.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AyaNovaQBI
|
||||
{
|
||||
internal class WorkOrderItemExpense
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public uint Concurrency { get; set; }
|
||||
|
||||
public string Description { get; set; }
|
||||
public string Name { get; set; }
|
||||
|
||||
public decimal TotalCost { get; set; }
|
||||
|
||||
public decimal ChargeAmount { get; set; }
|
||||
|
||||
public decimal TaxPaid { get; set; }
|
||||
public long? ChargeTaxCodeId { get; set; }
|
||||
|
||||
public string TaxCodeViz { get; set; }
|
||||
|
||||
public bool ReimburseUser { get; set; } = false;
|
||||
public long? UserId { get; set; }
|
||||
|
||||
public string UserViz { get; set; }
|
||||
public bool ChargeToCustomer { get; set; } = false;
|
||||
|
||||
|
||||
public decimal TaxAViz { get; set; }
|
||||
|
||||
public decimal TaxBViz { get; set; }
|
||||
|
||||
public decimal LineTotalViz { get; set; }
|
||||
|
||||
public long WorkOrderItemId { get; set; }
|
||||
}
|
||||
}
|
||||
58
AyaNovaQBI/WorkOrderItemLabor.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AyaNovaQBI
|
||||
{
|
||||
internal class WorkOrderItemLabor
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public uint Concurrency { get; set; }
|
||||
|
||||
public long? UserId { get; set; }
|
||||
|
||||
public string UserViz { get; set; }
|
||||
public DateTime? ServiceStartDate { get; set; }
|
||||
public DateTime? ServiceStopDate { get; set; }
|
||||
public long? ServiceRateId { get; set; }
|
||||
|
||||
public string ServiceRateViz { get; set; }
|
||||
public string ServiceDetails { get; set; }
|
||||
|
||||
public decimal ServiceRateQuantity { get; set; }
|
||||
|
||||
public decimal NoChargeQuantity { get; set; }
|
||||
//public long? ServiceBankId { get; set; }
|
||||
public long? TaxCodeSaleId { get; set; }
|
||||
|
||||
public string TaxCodeViz { get; set; }
|
||||
|
||||
|
||||
//Standard pricing fields (mostly to support printed reports though some show in UI)
|
||||
//some not to be sent with record depending on role (i.e. cost and charge in some cases)
|
||||
public decimal? PriceOverride { get; set; }//user entered manually overridden price, if null then ignored in calcs otherwise this *is* the price even if zero
|
||||
|
||||
public decimal CostViz { get; set; }//cost from source record (e.g. serviceRate) or zero if no cost entered
|
||||
|
||||
public decimal ListPriceViz { get; set; }//List price from source record (e.g. serviceRate) or zero if no cost entered
|
||||
|
||||
public string UnitOfMeasureViz { get; set; }//"each", "hour" etc
|
||||
|
||||
public decimal PriceViz { get; set; }//per unit price used in calcs after discounts or manual price if non-null or just ListPrice if no discount or manual override
|
||||
|
||||
public decimal NetViz { get; set; }//quantity * price (before taxes line total essentially)
|
||||
|
||||
public decimal TaxAViz { get; set; }//total amount of taxA
|
||||
|
||||
public decimal TaxBViz { get; set; }//total amount of taxB
|
||||
|
||||
public decimal LineTotalViz { get; set; }//line total netViz + taxes
|
||||
|
||||
|
||||
public long WorkOrderItemId { get; set; }
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
69
AyaNovaQBI/WorkOrderItemLoan.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AyaNovaQBI
|
||||
{
|
||||
internal enum LoanUnitRateUnit : int
|
||||
{
|
||||
None = 0,
|
||||
Hours = 1,
|
||||
HalfDays = 2,
|
||||
Days = 3,
|
||||
Weeks = 4,
|
||||
Months = 5,
|
||||
Years = 6
|
||||
}
|
||||
internal class WorkOrderItemLoan
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public uint Concurrency { get; set; }
|
||||
public string Notes { get; set; }
|
||||
public DateTime? OutDate { get; set; }
|
||||
public DateTime? DueDate { get; set; }
|
||||
public DateTime? ReturnDate { get; set; }
|
||||
//
|
||||
// public decimal Charges { get; set; }//removed in favor of ListPRice snapshot which normalizes fields to other objects
|
||||
public long? TaxCodeId { get; set; }
|
||||
|
||||
public string TaxCodeViz { get; set; }
|
||||
|
||||
public long LoanUnitId { get; set; }
|
||||
|
||||
public string LoanUnitViz { get; set; }
|
||||
|
||||
public decimal Quantity { get; set; }
|
||||
|
||||
public LoanUnitRateUnit Rate { get; set; }
|
||||
|
||||
public decimal Cost { get; set; }//cost from source record (e.g. serviceRate) or zero if no cost entered
|
||||
public decimal ListPrice { get; set; }//List price from source record (e.g. serviceRate) or zero if no cost entered
|
||||
|
||||
//Standard pricing fields (mostly to support printed reports though some show in UI)
|
||||
//some not to be sent with record depending on role (i.e. cost and charge in some cases)
|
||||
public decimal? PriceOverride { get; set; }//user entered manually overridden price, if null then ignored in calcs otherwise this *is* the price even if zero
|
||||
|
||||
|
||||
public string UnitOfMeasureViz { get; set; }//"each", "hour" etc
|
||||
|
||||
public decimal PriceViz { get; set; }//per unit price used in calcs after discounts or manual price if non-null or just ListPrice if no discount or manual override
|
||||
|
||||
public decimal NetViz { get; set; }//quantity * price (before taxes line total essentially)
|
||||
|
||||
public decimal TaxAViz { get; set; }//total amount of taxA
|
||||
|
||||
public decimal TaxBViz { get; set; }//total amount of taxB
|
||||
|
||||
public decimal LineTotalViz { get; set; }//line total netViz + taxes
|
||||
|
||||
//workaround for notification
|
||||
|
||||
public List<string> Tags { get; set; } = new List<string>();
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public long WorkOrderItemId { get; set; }
|
||||
}
|
||||
}
|
||||
63
AyaNovaQBI/WorkOrderItemOutsideService.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AyaNovaQBI
|
||||
{
|
||||
internal class WorkOrderItemOutsideService
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public uint Concurrency { get; set; }
|
||||
public string Notes { get; set; }
|
||||
|
||||
|
||||
public long UnitId { get; set; }
|
||||
|
||||
public string UnitViz { get; set; }
|
||||
public long? VendorSentToId { get; set; }
|
||||
|
||||
public string VendorSentToViz { get; set; }
|
||||
public long? VendorSentViaId { get; set; }
|
||||
|
||||
public string VendorSentViaViz { get; set; }
|
||||
public string RMANumber { get; set; }
|
||||
public string TrackingNumber { get; set; }
|
||||
|
||||
public decimal RepairCost { get; set; }
|
||||
|
||||
public decimal RepairPrice { get; set; }
|
||||
|
||||
public decimal ShippingCost { get; set; }
|
||||
|
||||
public decimal ShippingPrice { get; set; }
|
||||
public DateTime? SentDate { get; set; }
|
||||
public DateTime? ETADate { get; set; }
|
||||
public DateTime? ReturnDate { get; set; }
|
||||
public long? TaxCodeId { get; set; }
|
||||
|
||||
public string TaxCodeViz { get; set; }
|
||||
|
||||
public decimal CostViz { get; set; }//Total cost shipping + repairs
|
||||
|
||||
public decimal PriceViz { get; set; }//Total price shipping + repairs
|
||||
|
||||
public decimal NetViz { get; set; }//=priceViz for standardization not because it's necessary (before taxes line total essentially)
|
||||
|
||||
public decimal TaxAViz { get; set; }//total amount of taxA
|
||||
|
||||
public decimal TaxBViz { get; set; }//total amount of taxB
|
||||
|
||||
public decimal LineTotalViz { get; set; }//line total netViz + taxes
|
||||
|
||||
//workaround for notification
|
||||
|
||||
public List<string> Tags { get; set; } = new List<string>();
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
|
||||
public long WorkOrderItemId { get; set; }
|
||||
}
|
||||
}
|
||||
65
AyaNovaQBI/WorkOrderItemPart.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AyaNovaQBI
|
||||
{
|
||||
internal class WorkOrderItemPart
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public uint Concurrency { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Serials { get; set; }
|
||||
|
||||
public long PartId { get; set; }
|
||||
|
||||
public string PartDescriptionViz { get; set; }
|
||||
|
||||
public string PartNameViz { get; set; }
|
||||
|
||||
public string UpcViz { get; set; }
|
||||
|
||||
public long PartWarehouseId { get; set; }
|
||||
|
||||
public string PartWarehouseViz { get; set; }
|
||||
|
||||
public decimal Quantity { get; set; }
|
||||
public decimal SuggestedQuantity { get; set; }
|
||||
public long? TaxPartSaleId { get; set; }
|
||||
|
||||
public string TaxCodeViz { get; set; }
|
||||
|
||||
//NOTE: part prices are volatile and expected to be frequently edited so snapshotted when newly added unlike other things like rates etc that are protected from change
|
||||
public decimal Cost { get; set; }//cost from source record (e.g. serviceRate) or zero if no cost entered
|
||||
public decimal ListPrice { get; set; }//List price from source record (e.g. serviceRate) or zero if no cost entered
|
||||
|
||||
//Standard pricing fields (mostly to support printed reports though some show in UI)
|
||||
//some not to be sent with record depending on role (i.e. cost and charge in some cases)
|
||||
public decimal? PriceOverride { get; set; }//user entered manually overridden price, if null then ignored in calcs otherwise this *is* the price even if zero
|
||||
|
||||
|
||||
|
||||
public string UnitOfMeasureViz { get; set; }//"each", "hour" etc
|
||||
|
||||
public decimal PriceViz { get; set; }//per unit price used in calcs after discounts or manual price if non-null or just ListPrice if no discount or manual override
|
||||
|
||||
public decimal NetViz { get; set; }//quantity * price (before taxes line total essentially)
|
||||
|
||||
public decimal TaxAViz { get; set; }//total amount of taxA
|
||||
|
||||
public decimal TaxBViz { get; set; }//total amount of taxB
|
||||
|
||||
public decimal LineTotalViz { get; set; }//line total netViz + taxes
|
||||
|
||||
//workaround for notification
|
||||
|
||||
public List<string> Tags { get; set; } = new List<string>();
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
|
||||
public long WorkOrderItemId { get; set; }
|
||||
}
|
||||
}
|
||||
61
AyaNovaQBI/WorkOrderItemTravel.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AyaNovaQBI
|
||||
{
|
||||
internal class WorkOrderItemTravel
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public uint Concurrency { get; set; }
|
||||
|
||||
public long? UserId { get; set; }
|
||||
|
||||
public string UserViz { get; set; }
|
||||
public DateTime? TravelStartDate { get; set; }
|
||||
public DateTime? TravelStopDate { get; set; }
|
||||
public long? TravelRateId { get; set; }
|
||||
|
||||
public string TravelRateViz { get; set; }
|
||||
public string TravelDetails { get; set; }
|
||||
public decimal TravelRateQuantity { get; set; }
|
||||
public decimal NoChargeQuantity { get; set; }
|
||||
//public long? ServiceBankId { get; set; }
|
||||
public long? TaxCodeSaleId { get; set; }
|
||||
|
||||
public string TaxCodeViz { get; set; }
|
||||
public decimal Distance { get; set; }
|
||||
|
||||
|
||||
//Standard pricing fields (mostly to support printed reports though some show in UI)
|
||||
//some not to be sent with record depending on role (i.e. cost and charge in some cases)
|
||||
public decimal? PriceOverride { get; set; }//user entered manually overridden price, if null then ignored in calcs otherwise this *is* the price even if zero
|
||||
|
||||
public decimal CostViz { get; set; }//cost from source record (e.g. serviceRate) or zero if no cost entered
|
||||
|
||||
public decimal ListPriceViz { get; set; }//List price from source record (e.g. serviceRate) or zero if no cost entered
|
||||
|
||||
public string UnitOfMeasureViz { get; set; }//"each", "hour" etc
|
||||
|
||||
public decimal PriceViz { get; set; }//per unit price used in calcs after discounts or manual price if non-null or just ListPrice if no discount or manual override
|
||||
|
||||
public decimal NetViz { get; set; }//quantity * price (before taxes line total essentially)
|
||||
|
||||
public decimal TaxAViz { get; set; }//total amount of taxA
|
||||
|
||||
public decimal TaxBViz { get; set; }//total amount of taxB
|
||||
|
||||
public decimal LineTotalViz { get; set; }//line total netViz + taxes
|
||||
|
||||
//workaround for notification
|
||||
|
||||
public List<string> Tags { get; set; } = new List<string>();
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
|
||||
public long WorkOrderItemId { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -5654,6 +5654,314 @@ namespace AyaNovaQBI
|
||||
|
||||
#endregion export to quickbooks
|
||||
|
||||
|
||||
|
||||
#region Workorder mismatch scanning
|
||||
|
||||
public enum MisMatchReason
|
||||
{
|
||||
NotLinkedToQB = 0,
|
||||
PriceDifferent = 1,
|
||||
NothingToInvoice = 2
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Mismatch properties
|
||||
/// A structure for storing mismatches identified
|
||||
///so user can resolve them.
|
||||
/// </summary>
|
||||
public class MisMatch
|
||||
{
|
||||
//public Guid WorkorderID;
|
||||
public long ObjectId { get; set; }
|
||||
public AyaType ObjectType { get; set; }
|
||||
public string Name { get; set; }
|
||||
public MisMatchReason mReason { get; set; }
|
||||
public decimal AyaPrice { get; set; }
|
||||
public decimal QBPrice { get; set; }
|
||||
public long WorkorderItemPartId { get; set; }
|
||||
public string QBListID { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Given a workorder ID
|
||||
/// scans the objects in the workorder
|
||||
/// that need to be linked to QB 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 list of mismatch objects</param>
|
||||
/// <param name="PriceOverrides">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</param>
|
||||
/// <returns>True if all links ok, false if there are any mismatches at all</returns>
|
||||
public static bool ScanLinksOK(long WorkorderID, List<MisMatch> MisMatches, List<long> 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)
|
||||
{
|
||||
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#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 QBPrice, decimal AyaPrice, Guid WorkorderItemPartID, string QBListID)
|
||||
{
|
||||
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.NotLinkedToQB)
|
||||
{
|
||||
|
||||
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.mQBPrice = QBPrice;
|
||||
m.mWorkorderItemPartID = WorkorderItemPartID;
|
||||
m.mQBListID = QBListID;
|
||||
Mismatches.Add(m);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion wo_mismatch_scan
|
||||
|
||||
|
||||
#endregion qbi stuff (anything not api)
|
||||
|
||||
#region general utils
|
||||
|
||||
BIN
docs/docs/img/main-menu-invoice-fix-problems-item.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
docs/docs/img/main-menu-invoice-refresh-invoices-item.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
docs/docs/img/main-menu-invoice-selected-multiple-item.png
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
docs/docs/img/main-menu-invoice-selected-one-item.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
BIN
docs/docs/img/main-menu-tools-invoice-template-item.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
docs/docs/img/main-menu-tools-item.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
docs/docs/img/main-menu-tools-link-and-sync-item.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
docs/docs/img/main-menu-tools-preferences-item.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
docs/docs/img/main-menu-tools-refresh-cached-data-item.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |