This commit is contained in:
@@ -26,6 +26,7 @@ namespace AyaNova.Biz
|
|||||||
CurrentUserType = currentUserType;
|
CurrentUserType = currentUserType;
|
||||||
|
|
||||||
//Sub-role rights flags
|
//Sub-role rights flags
|
||||||
|
UserHasInventoryFullRole = CurrentUserRoles.HasFlag(AuthorizationRoles.Inventory);
|
||||||
UserIsTechRestricted = CurrentUserRoles.HasFlag(AuthorizationRoles.TechRestricted);
|
UserIsTechRestricted = CurrentUserRoles.HasFlag(AuthorizationRoles.TechRestricted);
|
||||||
UserIsSubContractorFull = CurrentUserType == UserType.ServiceContractor && CurrentUserRoles.HasFlag(AuthorizationRoles.SubContractor);
|
UserIsSubContractorFull = CurrentUserType == UserType.ServiceContractor && CurrentUserRoles.HasFlag(AuthorizationRoles.SubContractor);
|
||||||
UserIsSubContractorRestricted = CurrentUserType == UserType.ServiceContractor && CurrentUserRoles.HasFlag(AuthorizationRoles.SubContractorRestricted);
|
UserIsSubContractorRestricted = CurrentUserType == UserType.ServiceContractor && CurrentUserRoles.HasFlag(AuthorizationRoles.SubContractorRestricted);
|
||||||
@@ -88,6 +89,7 @@ namespace AyaNova.Biz
|
|||||||
internal bool UserCanViewPartCosts { get; set; }
|
internal bool UserCanViewPartCosts { get; set; }
|
||||||
internal bool UserCanViewLaborOrTravelRateCosts { get; set; }
|
internal bool UserCanViewLaborOrTravelRateCosts { get; set; }
|
||||||
internal bool UserCanViewLoanerCosts { get; set; }
|
internal bool UserCanViewLoanerCosts { get; set; }
|
||||||
|
internal bool UserHasInventoryFullRole { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -145,18 +147,21 @@ namespace AyaNova.Biz
|
|||||||
await ct.SaveChangesAsync();
|
await ct.SaveChangesAsync();
|
||||||
|
|
||||||
//INVENTORY ADJUSTMENTS
|
//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);
|
foreach (WorkOrderItemPart wip in wi.Parts)
|
||||||
if (HasErrors)
|
|
||||||
{
|
{
|
||||||
await transaction.RollbackAsync();
|
await PartInventoryAdjustmentAsync(AyaEvent.Created, wip, null, transaction);
|
||||||
return null;
|
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
|
//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.WorkOrderItemPart.AddAsync(newObject);
|
||||||
await ct.SaveChangesAsync();
|
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)
|
if (HasErrors)
|
||||||
{
|
{
|
||||||
await transaction.RollbackAsync();
|
await transaction.RollbackAsync();
|
||||||
@@ -3750,7 +3756,8 @@ namespace AyaNova.Biz
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
await ct.SaveChangesAsync();
|
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)
|
if (HasErrors)
|
||||||
{
|
{
|
||||||
await transaction.RollbackAsync();
|
await transaction.RollbackAsync();
|
||||||
@@ -3787,7 +3794,8 @@ namespace AyaNova.Biz
|
|||||||
await PartBizActionsAsync(AyaEvent.Deleted, null, dbObject);
|
await PartBizActionsAsync(AyaEvent.Deleted, null, dbObject);
|
||||||
ct.WorkOrderItemPart.Remove(dbObject);
|
ct.WorkOrderItemPart.Remove(dbObject);
|
||||||
await ct.SaveChangesAsync();
|
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)
|
if (HasErrors)
|
||||||
{
|
{
|
||||||
await transaction.RollbackAsync();
|
await transaction.RollbackAsync();
|
||||||
@@ -4001,64 +4009,126 @@ namespace AyaNova.Biz
|
|||||||
{
|
{
|
||||||
PartInventoryBiz pib = new PartInventoryBiz(ct, UserId, UserTranslationId, CurrentUserRoles);
|
PartInventoryBiz pib = new PartInventoryBiz(ct, UserId, UserTranslationId, CurrentUserRoles);
|
||||||
|
|
||||||
//DELETED, HANDLE INVENTORY / RETURN SERIALS
|
//DELETED, HANDLE INVENTORY / SERIALS
|
||||||
if (ayaEvent == AyaEvent.Deleted && oldObj.Quantity != 0)
|
if (ayaEvent == AyaEvent.Deleted && oldObj.Quantity != 0)
|
||||||
{
|
{
|
||||||
dtInternalPartInventory pi =
|
//NEGATIVE BLOCK >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||||
new dtInternalPartInventory
|
//was originally a return of inventory so needs reversal
|
||||||
{
|
if (oldObj.Quantity < 0)
|
||||||
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()}");
|
dtInternalPartInventory pi =
|
||||||
return;
|
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
|
else
|
||||||
{ //return serial numbers to part
|
{
|
||||||
if (!string.IsNullOrWhiteSpace(oldObj.Serials))
|
//was consumed inventory so return it
|
||||||
await PartBiz.AppendSerialsAsync(oldObj.PartId, oldObj.Serials, ct, UserId);
|
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
|
//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
|
if (ayaEvent == AyaEvent.Created && newObj.Quantity != 0)//allow zero quantity parts on workorder as placeholder, serials will not be consumed
|
||||||
{
|
{
|
||||||
dtInternalPartInventory pi =
|
|
||||||
new dtInternalPartInventory
|
if (newObj.Quantity < 0)
|
||||||
{
|
|
||||||
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)
|
//NEGATIVE BLOCK >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||||
{
|
|
||||||
foreach (var e in pib.Errors)
|
//RETURN INVENTORY
|
||||||
{
|
dtInternalPartInventory pi =
|
||||||
if (e.Code == ApiErrorCode.INSUFFICIENT_INVENTORY)
|
new dtInternalPartInventory
|
||||||
AddError(e.Code, "Quantity", e.Message);
|
{
|
||||||
else
|
PartId = newObj.PartId,
|
||||||
AddError(e.Code, e.Target, e.Message);
|
PartWarehouseId = newObj.PartWarehouseId,
|
||||||
}
|
Quantity = newObj.Quantity * -1,
|
||||||
}
|
SourceType = AyaType.WorkOrderItemPart,
|
||||||
//AddError(ApiErrorCode.API_SERVER_ERROR, "generalerror", $"Error updating inventory ({pi.Description}):{pib.GetErrorsAsString()}");
|
SourceId = newObj.Id,
|
||||||
return;
|
Description = await Translate("WorkOrderItemPart") + $" {newObj.Serials} " + await Translate("EventCreated")
|
||||||
|
};
|
||||||
|
|
||||||
|
//<<<<<<<<<<<<<<<<<<<<<< NEGATIVE BLOCK
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ //Consume serial numbers from part
|
{
|
||||||
if (!string.IsNullOrWhiteSpace(newObj.Serials))
|
//CONSUME INVENTORY
|
||||||
await PartBiz.RemoveSerialsAsync(newObj.PartId, newObj.Serials, ct, UserId);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proposedObj.Quantity < 0)//negative quantities are not allowed
|
if (proposedObj.Quantity < 0 && !UserHasInventoryFullRole)//negative quantities are not allowed unless the user has inventory full role
|
||||||
AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "Quantity");
|
AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "Quantity", await Translate("InventoryRoleRequired"));
|
||||||
|
|
||||||
//Any form customizations to validate?
|
//Any form customizations to validate?
|
||||||
var FormCustomization = await ct.FormCustom.AsNoTracking().SingleOrDefaultAsync(z => z.FormKey == AyaType.WorkOrderItemPart.ToString());
|
var FormCustomization = await ct.FormCustom.AsNoTracking().SingleOrDefaultAsync(z => z.FormKey == AyaType.WorkOrderItemPart.ToString());
|
||||||
|
|||||||
@@ -2301,5 +2301,6 @@
|
|||||||
"ExcludeDaysOfWeek":"Wochentage ausschließen",
|
"ExcludeDaysOfWeek":"Wochentage ausschließen",
|
||||||
"ErrorGenBeforeTooSmall":"Muss kleiner sein als Wiederholungsintervall",
|
"ErrorGenBeforeTooSmall":"Muss kleiner sein als Wiederholungsintervall",
|
||||||
"ErrorRepeatIntervalTooSmall":"Mindestens eine Stunde",
|
"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",
|
"ExcludeDaysOfWeek":"Exclude days of week",
|
||||||
"ErrorGenBeforeTooSmall":"Must be smaller than Repeat interval",
|
"ErrorGenBeforeTooSmall":"Must be smaller than Repeat interval",
|
||||||
"ErrorRepeatIntervalTooSmall":"Minimum one hour",
|
"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",
|
"ExcludeDaysOfWeek":"Excluir días de la semana",
|
||||||
"ErrorGenBeforeTooSmall":"Debe ser menor que el intervalo de repetición",
|
"ErrorGenBeforeTooSmall":"Debe ser menor que el intervalo de repetición",
|
||||||
"ErrorRepeatIntervalTooSmall":"Mínimo una hora",
|
"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",
|
"ExcludeDaysOfWeek":"Exclure les jours de la semaine",
|
||||||
"ErrorGenBeforeTooSmall":"Doit être inférieur à l'intervalle de répétition",
|
"ErrorGenBeforeTooSmall":"Doit être inférieur à l'intervalle de répétition",
|
||||||
"ErrorRepeatIntervalTooSmall":"Au moins une heure",
|
"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