This commit is contained in:
@@ -26,6 +26,7 @@ namespace AyaNova.Biz
|
||||
CurrentUserType = currentUserType;
|
||||
|
||||
//Sub-role rights flags
|
||||
UserHasInventoryFullRole = CurrentUserRoles.HasFlag(AuthorizationRoles.Inventory);
|
||||
UserIsTechRestricted = CurrentUserRoles.HasFlag(AuthorizationRoles.TechRestricted);
|
||||
UserIsSubContractorFull = CurrentUserType == UserType.ServiceContractor && CurrentUserRoles.HasFlag(AuthorizationRoles.SubContractor);
|
||||
UserIsSubContractorRestricted = CurrentUserType == UserType.ServiceContractor && CurrentUserRoles.HasFlag(AuthorizationRoles.SubContractorRestricted);
|
||||
@@ -88,6 +89,7 @@ namespace AyaNova.Biz
|
||||
internal bool UserCanViewPartCosts { get; set; }
|
||||
internal bool UserCanViewLaborOrTravelRateCosts { get; set; }
|
||||
internal bool UserCanViewLoanerCosts { get; set; }
|
||||
internal bool UserHasInventoryFullRole { get; set; }
|
||||
|
||||
|
||||
|
||||
@@ -145,18 +147,21 @@ namespace AyaNova.Biz
|
||||
await ct.SaveChangesAsync();
|
||||
|
||||
//INVENTORY ADJUSTMENTS
|
||||
foreach (WorkOrderItem wi in newObject.Items)
|
||||
if (AyaNova.Util.ServerGlobalBizSettings.Cache.UseInventory)
|
||||
{
|
||||
foreach (WorkOrderItemPart wip in wi.Parts)
|
||||
foreach (WorkOrderItem wi in newObject.Items)
|
||||
{
|
||||
await PartInventoryAdjustmentAsync(AyaEvent.Created, wip, null, transaction);
|
||||
if (HasErrors)
|
||||
foreach (WorkOrderItemPart wip in wi.Parts)
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
return null;
|
||||
await PartInventoryAdjustmentAsync(AyaEvent.Created, wip, null, transaction);
|
||||
if (HasErrors)
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//NOTE: not running individual notification here for children, seeder won't require it and that's all that posts an entire wo currently
|
||||
@@ -3694,7 +3699,8 @@ namespace AyaNova.Biz
|
||||
|
||||
await ct.WorkOrderItemPart.AddAsync(newObject);
|
||||
await ct.SaveChangesAsync();
|
||||
await PartInventoryAdjustmentAsync(AyaEvent.Created, newObject, null, transaction);
|
||||
if (AyaNova.Util.ServerGlobalBizSettings.Cache.UseInventory)
|
||||
await PartInventoryAdjustmentAsync(AyaEvent.Created, newObject, null, transaction);
|
||||
if (HasErrors)
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
@@ -3750,7 +3756,8 @@ namespace AyaNova.Biz
|
||||
try
|
||||
{
|
||||
await ct.SaveChangesAsync();
|
||||
await PartInventoryAdjustmentAsync(AyaEvent.Modified, putObject, dbObject, transaction);
|
||||
if (AyaNova.Util.ServerGlobalBizSettings.Cache.UseInventory)
|
||||
await PartInventoryAdjustmentAsync(AyaEvent.Modified, putObject, dbObject, transaction);
|
||||
if (HasErrors)
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
@@ -3787,7 +3794,8 @@ namespace AyaNova.Biz
|
||||
await PartBizActionsAsync(AyaEvent.Deleted, null, dbObject);
|
||||
ct.WorkOrderItemPart.Remove(dbObject);
|
||||
await ct.SaveChangesAsync();
|
||||
await PartInventoryAdjustmentAsync(AyaEvent.Deleted, null, dbObject, transaction);
|
||||
if (AyaNova.Util.ServerGlobalBizSettings.Cache.UseInventory)
|
||||
await PartInventoryAdjustmentAsync(AyaEvent.Deleted, null, dbObject, transaction);
|
||||
if (HasErrors)
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
@@ -4001,64 +4009,126 @@ namespace AyaNova.Biz
|
||||
{
|
||||
PartInventoryBiz pib = new PartInventoryBiz(ct, UserId, UserTranslationId, CurrentUserRoles);
|
||||
|
||||
//DELETED, HANDLE INVENTORY / RETURN SERIALS
|
||||
//DELETED, HANDLE INVENTORY / SERIALS
|
||||
if (ayaEvent == AyaEvent.Deleted && oldObj.Quantity != 0)
|
||||
{
|
||||
dtInternalPartInventory pi =
|
||||
new dtInternalPartInventory
|
||||
{
|
||||
PartId = oldObj.PartId,
|
||||
PartWarehouseId = oldObj.PartWarehouseId,
|
||||
Quantity = oldObj.Quantity,
|
||||
SourceType = null,//null because the po no longer exists so this is technically a manual adjustment
|
||||
SourceId = null,//''
|
||||
Description = await Translate("WorkOrderItemPart") + $" {oldObj.Serials} " + await Translate("EventDeleted")
|
||||
};
|
||||
if (await pib.CreateAsync(pi) == null)
|
||||
//NEGATIVE BLOCK >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
//was originally a return of inventory so needs reversal
|
||||
if (oldObj.Quantity < 0)
|
||||
{
|
||||
AddError(ApiErrorCode.API_SERVER_ERROR, "generalerror", $"Error updating inventory ({pi.Description}):{pib.GetErrorsAsString()}");
|
||||
return;
|
||||
dtInternalPartInventory pi =
|
||||
new dtInternalPartInventory
|
||||
{
|
||||
PartId = oldObj.PartId,
|
||||
PartWarehouseId = oldObj.PartWarehouseId,
|
||||
Quantity = oldObj.Quantity * -1,//was originally returned so needs to be removed
|
||||
SourceType = AyaType.WorkOrderItemPart,
|
||||
SourceId = oldObj.Id,
|
||||
Description = await Translate("WorkOrderItemPart") + $" {oldObj.Serials} " + await Translate("EventDeleted")
|
||||
};
|
||||
if (await pib.CreateAsync(pi) == null)
|
||||
{
|
||||
if (pib.HasErrors)
|
||||
{
|
||||
foreach (var e in pib.Errors)
|
||||
{
|
||||
if (e.Code == ApiErrorCode.INSUFFICIENT_INVENTORY)
|
||||
AddError(e.Code, "Quantity", e.Message);
|
||||
else
|
||||
AddError(e.Code, e.Target, e.Message);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{ //Consume serial numbers from part
|
||||
if (!string.IsNullOrWhiteSpace(oldObj.Serials))
|
||||
await PartBiz.RemoveSerialsAsync(oldObj.PartId, oldObj.Serials, ct, UserId);
|
||||
}
|
||||
//<<<<<<<<<<<<<<<<<<<<<< NEGATIVE BLOCK
|
||||
}
|
||||
else
|
||||
{ //return serial numbers to part
|
||||
if (!string.IsNullOrWhiteSpace(oldObj.Serials))
|
||||
await PartBiz.AppendSerialsAsync(oldObj.PartId, oldObj.Serials, ct, UserId);
|
||||
{
|
||||
//was consumed inventory so return it
|
||||
dtInternalPartInventory pi =
|
||||
new dtInternalPartInventory
|
||||
{
|
||||
PartId = oldObj.PartId,
|
||||
PartWarehouseId = oldObj.PartWarehouseId,
|
||||
Quantity = oldObj.Quantity,
|
||||
SourceType = null,//null because the po no longer exists so this is technically a manual adjustment
|
||||
SourceId = null,//''
|
||||
Description = await Translate("WorkOrderItemPart") + $" {oldObj.Serials} " + await Translate("EventDeleted")
|
||||
};
|
||||
if (await pib.CreateAsync(pi) == null)
|
||||
{
|
||||
AddError(ApiErrorCode.API_SERVER_ERROR, "generalerror", $"Error updating inventory ({pi.Description}):{pib.GetErrorsAsString()}");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{ //return serial numbers to part
|
||||
if (!string.IsNullOrWhiteSpace(oldObj.Serials))
|
||||
await PartBiz.AppendSerialsAsync(oldObj.PartId, oldObj.Serials, ct, UserId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//CREATED, HANDLE INVENTORY / CONSUME SERIALS
|
||||
if (ayaEvent == AyaEvent.Created && newObj.Quantity != 0)//allow zero quantity parts on workorder as placeholder, serials will not be consumed
|
||||
{
|
||||
dtInternalPartInventory pi =
|
||||
new dtInternalPartInventory
|
||||
{
|
||||
PartId = newObj.PartId,
|
||||
PartWarehouseId = newObj.PartWarehouseId,
|
||||
Quantity = newObj.Quantity * -1,
|
||||
SourceType = AyaType.WorkOrderItemPart,
|
||||
SourceId = newObj.Id,
|
||||
Description = await Translate("WorkOrderItemPart") + $" {newObj.Serials} " + await Translate("EventCreated")
|
||||
};
|
||||
if (await pib.CreateAsync(pi) == null)
|
||||
|
||||
if (newObj.Quantity < 0)
|
||||
{
|
||||
if (pib.HasErrors)
|
||||
{
|
||||
foreach (var e in pib.Errors)
|
||||
{
|
||||
if (e.Code == ApiErrorCode.INSUFFICIENT_INVENTORY)
|
||||
AddError(e.Code, "Quantity", e.Message);
|
||||
else
|
||||
AddError(e.Code, e.Target, e.Message);
|
||||
}
|
||||
}
|
||||
//AddError(ApiErrorCode.API_SERVER_ERROR, "generalerror", $"Error updating inventory ({pi.Description}):{pib.GetErrorsAsString()}");
|
||||
return;
|
||||
//NEGATIVE BLOCK >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
|
||||
//RETURN INVENTORY
|
||||
dtInternalPartInventory pi =
|
||||
new dtInternalPartInventory
|
||||
{
|
||||
PartId = newObj.PartId,
|
||||
PartWarehouseId = newObj.PartWarehouseId,
|
||||
Quantity = newObj.Quantity * -1,
|
||||
SourceType = AyaType.WorkOrderItemPart,
|
||||
SourceId = newObj.Id,
|
||||
Description = await Translate("WorkOrderItemPart") + $" {newObj.Serials} " + await Translate("EventCreated")
|
||||
};
|
||||
|
||||
//<<<<<<<<<<<<<<<<<<<<<< NEGATIVE BLOCK
|
||||
}
|
||||
else
|
||||
{ //Consume serial numbers from part
|
||||
if (!string.IsNullOrWhiteSpace(newObj.Serials))
|
||||
await PartBiz.RemoveSerialsAsync(newObj.PartId, newObj.Serials, ct, UserId);
|
||||
{
|
||||
//CONSUME INVENTORY
|
||||
dtInternalPartInventory pi =
|
||||
new dtInternalPartInventory
|
||||
{
|
||||
PartId = newObj.PartId,
|
||||
PartWarehouseId = newObj.PartWarehouseId,
|
||||
Quantity = newObj.Quantity * -1,
|
||||
SourceType = AyaType.WorkOrderItemPart,
|
||||
SourceId = newObj.Id,
|
||||
Description = await Translate("WorkOrderItemPart") + $" {newObj.Serials} " + await Translate("EventCreated")
|
||||
};
|
||||
if (await pib.CreateAsync(pi) == null)
|
||||
{
|
||||
if (pib.HasErrors)
|
||||
{
|
||||
foreach (var e in pib.Errors)
|
||||
{
|
||||
if (e.Code == ApiErrorCode.INSUFFICIENT_INVENTORY)
|
||||
AddError(e.Code, "Quantity", e.Message);
|
||||
else
|
||||
AddError(e.Code, e.Target, e.Message);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{ //Consume serial numbers from part
|
||||
if (!string.IsNullOrWhiteSpace(newObj.Serials))
|
||||
await PartBiz.RemoveSerialsAsync(newObj.PartId, newObj.Serials, ct, UserId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4183,8 +4253,8 @@ namespace AyaNova.Biz
|
||||
return;
|
||||
}
|
||||
|
||||
if (proposedObj.Quantity < 0)//negative quantities are not allowed
|
||||
AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "Quantity");
|
||||
if (proposedObj.Quantity < 0 && !UserHasInventoryFullRole)//negative quantities are not allowed unless the user has inventory full role
|
||||
AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "Quantity", await Translate("InventoryRoleRequired"));
|
||||
|
||||
//Any form customizations to validate?
|
||||
var FormCustomization = await ct.FormCustom.AsNoTracking().SingleOrDefaultAsync(z => z.FormKey == AyaType.WorkOrderItemPart.ToString());
|
||||
|
||||
@@ -2301,5 +2301,6 @@
|
||||
"ExcludeDaysOfWeek":"Wochentage ausschließen",
|
||||
"ErrorGenBeforeTooSmall":"Muss kleiner sein als Wiederholungsintervall",
|
||||
"ErrorRepeatIntervalTooSmall":"Mindestens eine Stunde",
|
||||
"QuantityRequired":"Erforderliche Menge"
|
||||
"QuantityRequired":"Erforderliche Menge",
|
||||
"InventoryRoleRequired":"Der Benutzer muss für diesen Vorgang eine Inventarrolle haben"
|
||||
}
|
||||
@@ -2301,6 +2301,7 @@
|
||||
"ExcludeDaysOfWeek":"Exclude days of week",
|
||||
"ErrorGenBeforeTooSmall":"Must be smaller than Repeat interval",
|
||||
"ErrorRepeatIntervalTooSmall":"Minimum one hour",
|
||||
"QuantityRequired":"Quantity required"
|
||||
"QuantityRequired":"Quantity required",
|
||||
"InventoryRoleRequired":"User must have Inventory Role for this operation"
|
||||
|
||||
}
|
||||
@@ -2301,5 +2301,6 @@
|
||||
"ExcludeDaysOfWeek":"Excluir días de la semana",
|
||||
"ErrorGenBeforeTooSmall":"Debe ser menor que el intervalo de repetición",
|
||||
"ErrorRepeatIntervalTooSmall":"Mínimo una hora",
|
||||
"QuantityRequired":"Cantidad requerida"
|
||||
"QuantityRequired":"Cantidad requerida",
|
||||
"InventoryRoleRequired":"El usuario debe tener un rol de inventario para esta operación"
|
||||
}
|
||||
@@ -2301,5 +2301,6 @@
|
||||
"ExcludeDaysOfWeek":"Exclure les jours de la semaine",
|
||||
"ErrorGenBeforeTooSmall":"Doit être inférieur à l'intervalle de répétition",
|
||||
"ErrorRepeatIntervalTooSmall":"Au moins une heure",
|
||||
"QuantityRequired":"Quantité Nécessaire"
|
||||
"QuantityRequired":"Quantité Nécessaire",
|
||||
"InventoryRoleRequired":"L'utilisateur doit avoir un rôle d'inventaire pour cette opération"
|
||||
}
|
||||
Reference in New Issue
Block a user