This commit is contained in:
@@ -257,6 +257,7 @@
|
||||
<Compile Include="WorkOrderItemTaskCompletionType.cs" />
|
||||
<Compile Include="WorkOrderItemTravel.cs" />
|
||||
<Compile Include="WorkOrderItemUnit.cs" />
|
||||
<Compile Include="WorkOrderState.cs" />
|
||||
<Compile Include="WorkOrderStatus.cs" />
|
||||
<Compile Include="SetQBImportInventoryAccounts.cs">
|
||||
<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);
|
||||
wip.PriceOverride = mm.QBPrice;
|
||||
await util.PostAsync("workorder", Newtonsoft.Json.JsonConvert.SerializeObject(w));
|
||||
await PutAsync("workorder/items/parts", Newtonsoft.Json.JsonConvert.SerializeObject(wip));
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -98,7 +98,7 @@ namespace AyaNovaQBI
|
||||
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 util.PostAsync("workorder", Newtonsoft.Json.JsonConvert.SerializeObject(w));
|
||||
await PutAsync("workorder/items/parts", Newtonsoft.Json.JsonConvert.SerializeObject(wip));
|
||||
|
||||
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}"); }
|
||||
}
|
||||
|
||||
private const string ACCOUNTING_INTEGRATION_WORK_ORDER_STATUS_NAME = "z_ACCOUNTING_INTEGRATION_REQUIRED_STATUS";
|
||||
|
||||
public const string TEST_ROUTE = "notify/hello";
|
||||
public const string API_BASE_ROUTE = "api/v8/";
|
||||
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 long ACCOUNTING_INTEGRATION_WORKORDER_STATUS_ID { get; set; } = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
public static void InitClient()
|
||||
@@ -561,6 +567,8 @@ namespace AyaNovaQBI
|
||||
return false;
|
||||
LOG_AVAILABLE = true;
|
||||
|
||||
|
||||
|
||||
//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");
|
||||
USE_INVENTORY = r.ObjectResponse["data"]["useInventory"].Value<bool>();
|
||||
@@ -608,6 +616,10 @@ namespace AyaNovaQBI
|
||||
//PFC - verify integration mapped objects still exist in QB
|
||||
if (!await ValidateQuickBooksHasMappedItems(initErrors))
|
||||
return false;
|
||||
|
||||
if (!await EnsureAccountingIntegrationWorkOrderStatus(initErrors))
|
||||
return false;
|
||||
|
||||
await IntegrationLog("PFC: QBI initialized and ready for use");
|
||||
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>
|
||||
/// Ensure mapped items still existing in QuickBooks
|
||||
/// </summary>
|
||||
@@ -5659,8 +5753,6 @@ namespace AyaNovaQBI
|
||||
|
||||
#endregion export to quickbooks
|
||||
|
||||
|
||||
|
||||
#region Workorder mismatch scanning
|
||||
|
||||
public enum MisMatchReason
|
||||
@@ -6117,7 +6209,6 @@ namespace AyaNovaQBI
|
||||
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.");
|
||||
|
||||
|
||||
var OrderedWorkOrderItems = w.Items.OrderBy(z => z.Sequence).ToList();
|
||||
|
||||
if (bFirstLoop)
|
||||
@@ -6655,22 +6746,54 @@ namespace AyaNovaQBI
|
||||
//Loop through all workorders again and set their invoice number, status and close them
|
||||
|
||||
//Loop through alworkorders
|
||||
foreach (object o in selectedWorkOrderIdList)
|
||||
{
|
||||
Workorder w = Workorder.GetItem((Guid)o);
|
||||
if (QDat.PostWOStatus != Guid.Empty)
|
||||
foreach (long WorkOrderId in selectedWorkOrderIdList)
|
||||
{
|
||||
/*
|
||||
* 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.");
|
||||
|
||||
w.WorkorderService.WorkorderStatusID = QDat.PostWOStatus;
|
||||
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.InvoiceNumber = InvoiceNumber;
|
||||
|
||||
//Case 7
|
||||
if (QDat.AutoClose)
|
||||
w.Closed = true;
|
||||
|
||||
w.Save();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user