This commit is contained in:
@@ -257,6 +257,7 @@
|
|||||||
<Compile Include="WorkOrderItemTaskCompletionType.cs" />
|
<Compile Include="WorkOrderItemTaskCompletionType.cs" />
|
||||||
<Compile Include="WorkOrderItemTravel.cs" />
|
<Compile Include="WorkOrderItemTravel.cs" />
|
||||||
<Compile Include="WorkOrderItemUnit.cs" />
|
<Compile Include="WorkOrderItemUnit.cs" />
|
||||||
|
<Compile Include="WorkOrderState.cs" />
|
||||||
<Compile Include="WorkOrderStatus.cs" />
|
<Compile Include="WorkOrderStatus.cs" />
|
||||||
<Compile Include="SetQBImportInventoryAccounts.cs">
|
<Compile Include="SetQBImportInventoryAccounts.cs">
|
||||||
<SubType>Form</SubType>
|
<SubType>Form</SubType>
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ namespace AyaNovaQBI
|
|||||||
|
|
||||||
var wip = w.Items.First(z => z.Id == mm.WorkOrderItemId).Parts.First(z => z.Id == mm.WorkOrderItemPartId);
|
var wip = w.Items.First(z => z.Id == mm.WorkOrderItemId).Parts.First(z => z.Id == mm.WorkOrderItemPartId);
|
||||||
wip.PriceOverride = mm.QBPrice;
|
wip.PriceOverride = mm.QBPrice;
|
||||||
await util.PostAsync("workorder", Newtonsoft.Json.JsonConvert.SerializeObject(w));
|
await PutAsync("workorder/items/parts", Newtonsoft.Json.JsonConvert.SerializeObject(wip));
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -98,7 +98,7 @@ namespace AyaNovaQBI
|
|||||||
var wip = w.Items.First(z => z.Id == mm.WorkOrderItemId).Parts.First(z => z.Id == mm.WorkOrderItemPartId);
|
var wip = w.Items.First(z => z.Id == mm.WorkOrderItemId).Parts.First(z => z.Id == mm.WorkOrderItemPartId);
|
||||||
long PartId = wip.PartId;
|
long PartId = wip.PartId;
|
||||||
wip.PriceOverride = mm.QBPrice;
|
wip.PriceOverride = mm.QBPrice;
|
||||||
await util.PostAsync("workorder", Newtonsoft.Json.JsonConvert.SerializeObject(w));
|
await PutAsync("workorder/items/parts", Newtonsoft.Json.JsonConvert.SerializeObject(wip));
|
||||||
|
|
||||||
if (PartId != 0)
|
if (PartId != 0)
|
||||||
{
|
{
|
||||||
|
|||||||
32
AyaNovaQBI/WorkOrderState.cs
Normal file
32
AyaNovaQBI/WorkOrderState.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AyaNovaQBI
|
||||||
|
{
|
||||||
|
public class WorkOrderState
|
||||||
|
{
|
||||||
|
public long Id { get; set; }
|
||||||
|
public uint Concurrency { get; set; }
|
||||||
|
|
||||||
|
public long WorkOrderId { get; set; }
|
||||||
|
|
||||||
|
public long WorkOrderStatusId { get; set; }
|
||||||
|
|
||||||
|
public DateTime Created { get; set; } = DateTime.UtcNow;
|
||||||
|
|
||||||
|
public long UserId { get; set; }
|
||||||
|
|
||||||
|
public string UserViz { get; set; }
|
||||||
|
|
||||||
|
public string NameViz { get; set; }
|
||||||
|
|
||||||
|
public string ColorViz { get; set; }
|
||||||
|
|
||||||
|
public bool CompletedViz { get; set; }
|
||||||
|
|
||||||
|
public bool LockedViz { get; set; }
|
||||||
|
|
||||||
|
public uint NewWOConcurrency { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
}//eoc
|
||||||
|
}
|
||||||
@@ -21,6 +21,9 @@ namespace AyaNovaQBI
|
|||||||
{
|
{
|
||||||
get { return new Guid("{82CD3609-4601-4C1A-9633-7836F92D2D06}"); }
|
get { return new Guid("{82CD3609-4601-4C1A-9633-7836F92D2D06}"); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private const string ACCOUNTING_INTEGRATION_WORK_ORDER_STATUS_NAME = "z_ACCOUNTING_INTEGRATION_REQUIRED_STATUS";
|
||||||
|
|
||||||
public const string TEST_ROUTE = "notify/hello";
|
public const string TEST_ROUTE = "notify/hello";
|
||||||
public const string API_BASE_ROUTE = "api/v8/";
|
public const string API_BASE_ROUTE = "api/v8/";
|
||||||
private const int MAX_TRIES = 3;//max times to retry an api call before giving up
|
private const int MAX_TRIES = 3;//max times to retry an api call before giving up
|
||||||
@@ -47,6 +50,9 @@ namespace AyaNovaQBI
|
|||||||
|
|
||||||
internal static bool USE_INVENTORY { get; set; } = false;
|
internal static bool USE_INVENTORY { get; set; } = false;
|
||||||
|
|
||||||
|
internal static long ACCOUNTING_INTEGRATION_WORKORDER_STATUS_ID { get; set; } = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static void InitClient()
|
public static void InitClient()
|
||||||
@@ -561,6 +567,8 @@ namespace AyaNovaQBI
|
|||||||
return false;
|
return false;
|
||||||
LOG_AVAILABLE = true;
|
LOG_AVAILABLE = true;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//PFC - get global setttings for use inventory and others await window.$gz.api.get("global-biz-setting/client");
|
//PFC - get global setttings for use inventory and others await window.$gz.api.get("global-biz-setting/client");
|
||||||
r = await GetAsync("global-biz-setting/client");
|
r = await GetAsync("global-biz-setting/client");
|
||||||
USE_INVENTORY = r.ObjectResponse["data"]["useInventory"].Value<bool>();
|
USE_INVENTORY = r.ObjectResponse["data"]["useInventory"].Value<bool>();
|
||||||
@@ -608,6 +616,10 @@ namespace AyaNovaQBI
|
|||||||
//PFC - verify integration mapped objects still exist in QB
|
//PFC - verify integration mapped objects still exist in QB
|
||||||
if (!await ValidateQuickBooksHasMappedItems(initErrors))
|
if (!await ValidateQuickBooksHasMappedItems(initErrors))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (!await EnsureAccountingIntegrationWorkOrderStatus(initErrors))
|
||||||
|
return false;
|
||||||
|
|
||||||
await IntegrationLog("PFC: QBI initialized and ready for use");
|
await IntegrationLog("PFC: QBI initialized and ready for use");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -678,6 +690,88 @@ namespace AyaNovaQBI
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ensure existance of special work order status for accounting integration modification purposes
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="initErrors"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static async Task<bool> EnsureAccountingIntegrationWorkOrderStatus(StringBuilder initErrors)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* var a = await util.GetAsync($"workorder/{mm.WorkOrderId}");
|
||||||
|
WorkOrder w = a.ObjectResponse["data"].ToObject<WorkOrder>();
|
||||||
|
if (w == null)
|
||||||
|
throw new Exception($"FixInvoiceProblems:CHANGEAYA:PRICE: WorkOrder with id {mm.WorkOrderId} was not found in AyaNova and may have just been deleted.\r\nUnable to update wo.");
|
||||||
|
|
||||||
|
var wip = w.Items.First(z => z.Id == mm.WorkOrderItemId).Parts.First(z => z.Id == mm.WorkOrderItemPartId);
|
||||||
|
long PartId = wip.PartId;
|
||||||
|
wip.PriceOverride = mm.QBPrice;
|
||||||
|
await PutAsync("workorder/items/parts", Newtonsoft.Json.JsonConvert.SerializeObject(wip));
|
||||||
|
|
||||||
|
CREATE STATUS: {"data":{"id":0, "name":"z_ACCOUNTING_INTEGRATION_REQUIRED_STATUS","active":true,
|
||||||
|
"notes":"Special status required for Accounting integration applications to enable modifying locked work orders.",
|
||||||
|
"color":"#000000FF","selectRoles":64,"removeRoles":64,"completed":false,"locked":false}}
|
||||||
|
POST STATE TO WO: {"workOrderId":557,"workOrderStatusId":8,"userId":5,"userViz":"Marian Green - Service","created":"2022-07-11T22:54:11.528Z"}
|
||||||
|
*/
|
||||||
|
//see if we already have an integration status set
|
||||||
|
WorkOrderStatus AccountingStatus = _woStatuslist.FirstOrDefault(z => z.Name == ACCOUNTING_INTEGRATION_WORK_ORDER_STATUS_NAME);
|
||||||
|
|
||||||
|
//validate accounting status
|
||||||
|
if (AccountingStatus != null)
|
||||||
|
{
|
||||||
|
ACCOUNTING_INTEGRATION_WORKORDER_STATUS_ID = AccountingStatus.Id;
|
||||||
|
bool hasError = false;
|
||||||
|
|
||||||
|
if (!AccountingStatus.SelectRoles.HasFlag(AuthorizationRoles.Accounting))
|
||||||
|
{
|
||||||
|
hasError = true;
|
||||||
|
initErrors.AppendLine($"Work order Status \"{AccountingStatus.Name}\" SELECT Roles must include Accounting Role");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!AccountingStatus.RemoveRoles.HasFlag(AuthorizationRoles.Accounting))
|
||||||
|
{
|
||||||
|
hasError = true;
|
||||||
|
initErrors.AppendLine($"Work order Status \"{AccountingStatus.Name}\" REMOVE Roles must include Accounting Role");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!AccountingStatus.Active)
|
||||||
|
{
|
||||||
|
hasError = true;
|
||||||
|
initErrors.AppendLine($"Work order Status \"{AccountingStatus.Name}\" must be set to Active=true");
|
||||||
|
}
|
||||||
|
return !hasError;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Create accounting status
|
||||||
|
ApiResponse r = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
AccountingStatus.Name = ACCOUNTING_INTEGRATION_WORK_ORDER_STATUS_NAME;
|
||||||
|
AccountingStatus.Active = true;
|
||||||
|
AccountingStatus.Completed = false;
|
||||||
|
AccountingStatus.Locked = false;
|
||||||
|
AccountingStatus.SelectRoles = AuthorizationRoles.Accounting;
|
||||||
|
AccountingStatus.RemoveRoles = AuthorizationRoles.Accounting;
|
||||||
|
AccountingStatus.Notes = "DO NOT MODIFY - Special status required for Accounting integration applications to modify locked Work orders.";
|
||||||
|
AccountingStatus.Color = "#6D3C2176";//ugly transparentish brown
|
||||||
|
r = await PostAsync($"work-order-status", Newtonsoft.Json.JsonConvert.SerializeObject(AccountingStatus));
|
||||||
|
ACCOUNTING_INTEGRATION_WORKORDER_STATUS_ID = IdFromResponse(r);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
initErrors.AppendLine($"Error creating required Work order Status \"{AccountingStatus.Name}\"");
|
||||||
|
initErrors.AppendLine(ex.Message);
|
||||||
|
initErrors.AppendLine(r.CompactResponse);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ensure mapped items still existing in QuickBooks
|
/// Ensure mapped items still existing in QuickBooks
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -5659,8 +5753,6 @@ namespace AyaNovaQBI
|
|||||||
|
|
||||||
#endregion export to quickbooks
|
#endregion export to quickbooks
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#region Workorder mismatch scanning
|
#region Workorder mismatch scanning
|
||||||
|
|
||||||
public enum MisMatchReason
|
public enum MisMatchReason
|
||||||
@@ -6117,7 +6209,6 @@ namespace AyaNovaQBI
|
|||||||
if (w == null)
|
if (w == null)
|
||||||
throw new Exception($"util.Invoice: WorkOrder with record id {SelectedWorkOrderId} was not found in AyaNova and may have just been deleted.\r\nUnable to invoice this wo.");
|
throw new Exception($"util.Invoice: WorkOrder with record id {SelectedWorkOrderId} was not found in AyaNova and may have just been deleted.\r\nUnable to invoice this wo.");
|
||||||
|
|
||||||
|
|
||||||
var OrderedWorkOrderItems = w.Items.OrderBy(z => z.Sequence).ToList();
|
var OrderedWorkOrderItems = w.Items.OrderBy(z => z.Sequence).ToList();
|
||||||
|
|
||||||
if (bFirstLoop)
|
if (bFirstLoop)
|
||||||
@@ -6402,7 +6493,7 @@ namespace AyaNovaQBI
|
|||||||
|
|
||||||
if (s.IndexOf("~SERVICE_START~") != -1)
|
if (s.IndexOf("~SERVICE_START~") != -1)
|
||||||
{
|
{
|
||||||
s = s.Replace("~SERVICE_START~",DateToLocalString(wl.ServiceStartDate));
|
s = s.Replace("~SERVICE_START~", DateToLocalString(wl.ServiceStartDate));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s.IndexOf("~SERVICE_STOP~") != -1)
|
if (s.IndexOf("~SERVICE_STOP~") != -1)
|
||||||
@@ -6578,12 +6669,12 @@ namespace AyaNovaQBI
|
|||||||
|
|
||||||
if (s.IndexOf("~ITEM~") != -1)
|
if (s.IndexOf("~ITEM~") != -1)
|
||||||
{
|
{
|
||||||
s = s.Replace("~ITEM~",l.LoanUnitViz);
|
s = s.Replace("~ITEM~", l.LoanUnitViz);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s.IndexOf("~LOANED~") != -1)
|
if (s.IndexOf("~LOANED~") != -1)
|
||||||
{
|
{
|
||||||
s = s.Replace("~LOANED~",DateToLocalString(l.OutDate));
|
s = s.Replace("~LOANED~", DateToLocalString(l.OutDate));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s.IndexOf("~LOAN_RETURNED~") != -1)
|
if (s.IndexOf("~LOAN_RETURNED~") != -1)
|
||||||
@@ -6655,23 +6746,55 @@ namespace AyaNovaQBI
|
|||||||
//Loop through all workorders again and set their invoice number, status and close them
|
//Loop through all workorders again and set their invoice number, status and close them
|
||||||
|
|
||||||
//Loop through alworkorders
|
//Loop through alworkorders
|
||||||
foreach (object o in selectedWorkOrderIdList)
|
foreach (long WorkOrderId in selectedWorkOrderIdList)
|
||||||
{
|
{
|
||||||
Workorder w = Workorder.GetItem((Guid)o);
|
/*
|
||||||
if (QDat.PostWOStatus != Guid.Empty)
|
* var a = await util.GetAsync($"workorder/{mm.WorkOrderId}");
|
||||||
|
WorkOrder w = a.ObjectResponse["data"].ToObject<WorkOrder>();
|
||||||
|
if (w == null)
|
||||||
|
throw new Exception($"FixInvoiceProblems:CHANGEAYA:PRICE: WorkOrder with id {mm.WorkOrderId} was not found in AyaNova and may have just been deleted.\r\nUnable to update wo.");
|
||||||
|
|
||||||
|
var wip = w.Items.First(z => z.Id == mm.WorkOrderItemId).Parts.First(z => z.Id == mm.WorkOrderItemPartId);
|
||||||
|
long PartId = wip.PartId;
|
||||||
|
wip.PriceOverride = mm.QBPrice;
|
||||||
|
await PutAsync("workorder/items/parts", Newtonsoft.Json.JsonConvert.SerializeObject(wip));
|
||||||
|
|
||||||
|
CREATE STATUS: {"data":{"id":0, "name":"zACCOUNTING_INTEGRATION_REQUIRED_STATUS","active":true,"notes":"Special status required for Accounting integration applications to enable modifying locked work orders.","color":"#000000FF","selectRoles":64,"removeRoles":64,"completed":false,"locked":false}}
|
||||||
|
POST STATE TO WO: {"workOrderId":557,"workOrderStatusId":8,"userId":5,"userViz":"Marian Green - Service","created":"2022-07-11T22:54:11.528Z"}
|
||||||
|
*/
|
||||||
|
//First, set status to editable one and also to show that QBI made changes
|
||||||
|
|
||||||
|
var a = await GetAsync($"workorder/{WorkOrderId}");
|
||||||
|
WorkOrder w = a.ObjectResponse["data"].ToObject<WorkOrder>();
|
||||||
|
if (w != null)
|
||||||
{
|
{
|
||||||
|
long? StatusOfWorkOrderBeforeModifications = w.LastStatusId;
|
||||||
|
//set work order state to accounting status
|
||||||
|
var newState = (await PostAsync("workorder/states", Newtonsoft.Json.JsonConvert.SerializeObject(new WorkOrderState { WorkOrderId = w.Id, UserId = 0, WorkOrderStatusId = ACCOUNTING_INTEGRATION_WORKORDER_STATUS_ID }))).ObjectResponse["data"].ToObject<WorkOrderState>();
|
||||||
|
w.Concurrency = newState.NewWOConcurrency;
|
||||||
|
|
||||||
|
//set invoice number
|
||||||
|
w.InvoiceNumber = InvoiceNumber;
|
||||||
|
//only allowed to put header not rest of wo
|
||||||
|
w.Items.Clear();
|
||||||
|
|
||||||
|
await PutAsync("workorder", Newtonsoft.Json.JsonConvert.SerializeObject(w));
|
||||||
|
|
||||||
|
|
||||||
|
if (QDat.PostWOStatus != 0)
|
||||||
|
{
|
||||||
|
await PostAsync("workorder/states", Newtonsoft.Json.JsonConvert.SerializeObject(new WorkOrderState { WorkOrderId = w.Id, UserId = 0, WorkOrderStatusId = QDat.PostWOStatus }));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//put it back to the status it was before we modified it as user has selected no status change
|
||||||
|
if (StatusOfWorkOrderBeforeModifications != null)
|
||||||
|
await PostAsync("workorder/states", Newtonsoft.Json.JsonConvert.SerializeObject(new WorkOrderState { WorkOrderId = w.Id, UserId = 0, WorkOrderStatusId = (long)StatusOfWorkOrderBeforeModifications }));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
w.WorkorderService.WorkorderStatusID = QDat.PostWOStatus;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
w.WorkorderService.InvoiceNumber = InvoiceNumber;
|
|
||||||
|
|
||||||
//Case 7
|
|
||||||
if (QDat.AutoClose)
|
|
||||||
w.Closed = true;
|
|
||||||
|
|
||||||
w.Save();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}//end try block
|
}//end try block
|
||||||
@@ -6694,7 +6817,7 @@ namespace AyaNovaQBI
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user