This commit is contained in:
@@ -81,16 +81,17 @@ namespace AyaNova.Biz
|
|||||||
}
|
}
|
||||||
PurchaseOrder newObject = new PurchaseOrder();
|
PurchaseOrder newObject = new PurchaseOrder();
|
||||||
CopyObject.Copy(dbObject, newObject, "Wiki,Serial");
|
CopyObject.Copy(dbObject, newObject, "Wiki,Serial");
|
||||||
foreach(var item in newObject.Items){
|
foreach (var item in newObject.Items)
|
||||||
item.QuantityReceived=0;
|
{
|
||||||
item.ReceivedCost=0;
|
item.QuantityReceived = 0;
|
||||||
item.ReceivedDate=null;
|
item.ReceivedCost = 0;
|
||||||
item.PurchaseOrderId=0;
|
item.ReceivedDate = null;
|
||||||
|
item.PurchaseOrderId = 0;
|
||||||
}
|
}
|
||||||
newObject.Id = 0;
|
newObject.Id = 0;
|
||||||
newObject.Concurrency = 0;
|
newObject.Concurrency = 0;
|
||||||
await ct.PurchaseOrder.AddAsync(newObject);
|
await ct.PurchaseOrder.AddAsync(newObject);
|
||||||
await ct.SaveChangesAsync();
|
await ct.SaveChangesAsync();
|
||||||
await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, newObject.Id, BizType, AyaEvent.Created), ct);
|
await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, newObject.Id, BizType, AyaEvent.Created), ct);
|
||||||
await SearchIndexAsync(newObject, true);
|
await SearchIndexAsync(newObject, true);
|
||||||
await TagBiz.ProcessUpdateTagsInRepositoryAsync(ct, newObject.Tags, null);
|
await TagBiz.ProcessUpdateTagsInRepositoryAsync(ct, newObject.Tags, null);
|
||||||
@@ -278,107 +279,187 @@ namespace AyaNova.Biz
|
|||||||
//A PO can now be edited in any way user wishes at any time so this method is to fix up
|
//A PO can now be edited in any way user wishes at any time so this method is to fix up
|
||||||
//any changes they make in affected objects and inventory
|
//any changes they make in affected objects and inventory
|
||||||
//
|
//
|
||||||
private async Task BizActionsAsync(AyaEvent ayaEvent, PurchaseOrder proposedObj, PurchaseOrder currentObj, IDbContextTransaction transaction)
|
private async Task BizActionsAsync(AyaEvent ayaEvent, PurchaseOrder newObj, PurchaseOrder oldObj, IDbContextTransaction transaction)
|
||||||
{
|
{
|
||||||
//MIGRATE_OUTSTANDING - woitempart request update
|
//MIGRATE_OUTSTANDING - woitempart request update
|
||||||
//if received on woitempartrequest then need to update woitempartrequest (notification separate not a concern here)
|
//if received on woitempartrequest then need to update woitempartrequest (notification separate not a concern here)
|
||||||
//if workorderitempartrequest item removed, need to fixup woitempartrequest
|
//if workorderitempartrequest item removed, need to fixup woitempartrequest
|
||||||
//BUT *only* if the woitempartrequest still exists and isn't completed already
|
//BUT *only* if the woitempartrequest still exists and isn't completed already
|
||||||
|
|
||||||
|
//todo: BizActionsAsync - handle user changing a part and/or warehouse in an item just as with quantity, forgot about that one
|
||||||
|
//todo: BizActionsAsync - VendorPartNumber automatically set this if teh vendorid has changed from the list of parts there is
|
||||||
|
//todo: if vendorid has changed, need to update all part values into poitems
|
||||||
|
|
||||||
|
//Get inventory object for updating
|
||||||
PartInventoryBiz pib = new PartInventoryBiz(ct, UserId, UserTranslationId, CurrentUserRoles);
|
PartInventoryBiz pib = new PartInventoryBiz(ct, UserId, UserTranslationId, CurrentUserRoles);
|
||||||
|
|
||||||
switch (ayaEvent)
|
//DELETED
|
||||||
|
if (ayaEvent == AyaEvent.Deleted)
|
||||||
{
|
{
|
||||||
case AyaEvent.Created:
|
//REVERSE ENTIRE PO
|
||||||
{
|
//any received remove from inventory
|
||||||
//any received go into inventory
|
var inventoryAffectingItems = oldObj.Items.Where(z => z.QuantityReceived > 0).ToList();
|
||||||
var inventoryAffectingItems = proposedObj.Items.Where(z => z.QuantityReceived > 0).ToList();
|
foreach (var poItem in inventoryAffectingItems)
|
||||||
foreach (var poItem in inventoryAffectingItems)
|
{
|
||||||
{
|
//make reversing inventory adjustment here
|
||||||
//make inventory adjustment here
|
dtPOPartInventory i = new dtPOPartInventory();
|
||||||
dtPOPartInventory i = new dtPOPartInventory();
|
i.PartId = poItem.PartId;
|
||||||
i.PartId = poItem.PartId;
|
i.PartWarehouseId = poItem.PartWarehouseId;
|
||||||
i.PartWarehouseId = poItem.PartWarehouseId;
|
i.Quantity = poItem.QuantityReceived *= -1;
|
||||||
i.Quantity = poItem.QuantityReceived;
|
i.SourceType = AyaType.PurchaseOrder;
|
||||||
i.SourceType = AyaType.PurchaseOrder;
|
i.SourceId = newObj.Id;
|
||||||
i.SourceId = proposedObj.Id;
|
await pib.CreateAsync(i);
|
||||||
await pib.CreateAsync(i);
|
|
||||||
|
|
||||||
//MIGRATE_OUTSTANDING - update workorderitempart here if applicable
|
//MIGRATE_OUTSTANDING - update workorderitempart here if applicable
|
||||||
}
|
}
|
||||||
}
|
return;//done, nothing more to do here
|
||||||
break;
|
|
||||||
case AyaEvent.Modified:
|
|
||||||
{
|
|
||||||
//any changes that will affect inventory get processed here
|
|
||||||
foreach (var newItem in proposedObj.Items)
|
|
||||||
{
|
|
||||||
//get the matching currentPoItem
|
|
||||||
var oldItem = currentObj.Items.FirstOrDefault(z => z.Id == newItem.Id);
|
|
||||||
//NEW ITEM?
|
|
||||||
if (oldItem == null && newItem.QuantityReceived > 0)
|
|
||||||
{
|
|
||||||
//It's a new receipt with received amounts - add to inventory
|
|
||||||
dtPOPartInventory i = new dtPOPartInventory();
|
|
||||||
i.PartId = newItem.PartId;
|
|
||||||
i.PartWarehouseId = newItem.PartWarehouseId;
|
|
||||||
i.Quantity = newItem.QuantityReceived;
|
|
||||||
i.SourceType = AyaType.PurchaseOrder;
|
|
||||||
i.SourceId = proposedObj.Id;
|
|
||||||
await pib.CreateAsync(i);
|
|
||||||
|
|
||||||
//MIGRATE_OUTSTANDING - update workorderitempart here if applicable
|
|
||||||
}
|
|
||||||
//UPDATED ITEM WITH NEW RECEIVED AMOUNT?
|
|
||||||
else if (oldItem.QuantityReceived != newItem.QuantityReceived)
|
|
||||||
{
|
|
||||||
decimal netChange = 0;
|
|
||||||
if (oldItem.QuantityReceived < newItem.QuantityReceived)
|
|
||||||
{
|
|
||||||
//More received
|
|
||||||
netChange = newItem.QuantityReceived - oldItem.QuantityReceived;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//less received
|
|
||||||
netChange = newItem.QuantityReceived - oldItem.QuantityReceived;
|
|
||||||
}
|
|
||||||
|
|
||||||
dtPOPartInventory i = new dtPOPartInventory();
|
|
||||||
i.PartId = newItem.PartId;
|
|
||||||
i.PartWarehouseId = newItem.PartWarehouseId;
|
|
||||||
i.Quantity = netChange;
|
|
||||||
i.SourceType = AyaType.PurchaseOrder;
|
|
||||||
i.SourceId = proposedObj.Id;
|
|
||||||
await pib.CreateAsync(i);
|
|
||||||
|
|
||||||
//MIGRATE_OUTSTANDING - update workorderitempart here if applicable
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case AyaEvent.Deleted:
|
|
||||||
{
|
|
||||||
//REVERSE ENTIRE PO
|
|
||||||
//any received remove from inventory
|
|
||||||
var inventoryAffectingItems = currentObj.Items.Where(z => z.QuantityReceived > 0).ToList();
|
|
||||||
foreach (var poItem in inventoryAffectingItems)
|
|
||||||
{
|
|
||||||
//make reversing inventory adjustment here
|
|
||||||
dtPOPartInventory i = new dtPOPartInventory();
|
|
||||||
i.PartId = poItem.PartId;
|
|
||||||
i.PartWarehouseId = poItem.PartWarehouseId;
|
|
||||||
i.Quantity = poItem.QuantityReceived *= -1;
|
|
||||||
i.SourceType = AyaType.PurchaseOrder;
|
|
||||||
i.SourceId = proposedObj.Id;
|
|
||||||
await pib.CreateAsync(i);
|
|
||||||
|
|
||||||
//MIGRATE_OUTSTANDING - update workorderitempart here if applicable
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Some kind of update so fetch the parts so the default part values can be set on the poItem if necessary
|
||||||
|
var PoParts = await ct.Part.AsNoTracking().Where(x => newObj.Items.Any(z => z.PartId == x.Id)).ToListAsync();
|
||||||
|
|
||||||
|
//CREATED
|
||||||
|
if (ayaEvent == AyaEvent.Created)
|
||||||
|
{
|
||||||
|
//any received go into inventory
|
||||||
|
var inventoryAffectingItems = newObj.Items.Where(z => z.QuantityReceived > 0).ToList();
|
||||||
|
foreach (var poItem in inventoryAffectingItems)
|
||||||
|
{
|
||||||
|
//make inventory adjustment here
|
||||||
|
dtPOPartInventory i = new dtPOPartInventory();
|
||||||
|
i.PartId = poItem.PartId;
|
||||||
|
i.PartWarehouseId = poItem.PartWarehouseId;
|
||||||
|
i.Quantity = poItem.QuantityReceived;
|
||||||
|
i.SourceType = AyaType.PurchaseOrder;
|
||||||
|
i.SourceId = newObj.Id;
|
||||||
|
await pib.CreateAsync(i);
|
||||||
|
|
||||||
|
//MIGRATE_OUTSTANDING - update workorderitempart here if applicable
|
||||||
|
}
|
||||||
|
|
||||||
|
//All new so set them all
|
||||||
|
foreach (var poItem in newObj.Items)
|
||||||
|
SetPoItemDefaultPartValues(poItem, PoParts, newObj.VendorId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//MODIFIED
|
||||||
|
if (ayaEvent == AyaEvent.Modified)
|
||||||
|
{
|
||||||
|
foreach (var newItem in newObj.Items)
|
||||||
|
{
|
||||||
|
//get the matching currentPoItem
|
||||||
|
var oldItem = oldObj.Items.FirstOrDefault(z => z.Id == newItem.Id);
|
||||||
|
|
||||||
|
//NEW ITEM ADDED
|
||||||
|
if (oldItem == null)
|
||||||
|
{
|
||||||
|
if (newItem.QuantityReceived > 0)
|
||||||
|
{
|
||||||
|
//It's a new receipt with received amounts - add to inventory
|
||||||
|
dtPOPartInventory i = new dtPOPartInventory();
|
||||||
|
i.PartId = newItem.PartId;
|
||||||
|
i.PartWarehouseId = newItem.PartWarehouseId;
|
||||||
|
i.Quantity = newItem.QuantityReceived;
|
||||||
|
i.SourceType = AyaType.PurchaseOrder;
|
||||||
|
i.SourceId = newObj.Id;
|
||||||
|
await pib.CreateAsync(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetPoItemDefaultPartValues(newItem, PoParts, newObj.VendorId);
|
||||||
|
|
||||||
|
//MIGRATE_OUTSTANDING - update workorderitempart here if applicable
|
||||||
|
continue;//on to next item
|
||||||
|
}
|
||||||
|
|
||||||
|
//CHANGED PART OR WAREHOUSE ID
|
||||||
|
if (oldItem.PartId != newItem.PartId || oldItem.PartWarehouseId != newItem.PartWarehouseId)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (oldItem.QuantityReceived > 0)
|
||||||
|
{
|
||||||
|
//reverse inventory
|
||||||
|
dtPOPartInventory i = new dtPOPartInventory();
|
||||||
|
i.PartId = oldItem.PartId;
|
||||||
|
i.PartWarehouseId = oldItem.PartWarehouseId;
|
||||||
|
i.Quantity = oldItem.QuantityReceived *= -1;
|
||||||
|
i.SourceType = AyaType.PurchaseOrder;
|
||||||
|
i.SourceId = newObj.Id;
|
||||||
|
await pib.CreateAsync(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newItem.QuantityReceived > 0)
|
||||||
|
{
|
||||||
|
//set new inventory
|
||||||
|
dtPOPartInventory i = new dtPOPartInventory();
|
||||||
|
i.PartId = newItem.PartId;
|
||||||
|
i.PartWarehouseId = newItem.PartWarehouseId;
|
||||||
|
i.Quantity = newItem.QuantityReceived;
|
||||||
|
i.SourceType = AyaType.PurchaseOrder;
|
||||||
|
i.SourceId = newObj.Id;
|
||||||
|
await pib.CreateAsync(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Update part values into poitem if the part or vendor has changed
|
||||||
|
if (oldItem.PartId != newItem.PartId || oldObj.VendorId != newObj.VendorId)
|
||||||
|
SetPoItemDefaultPartValues(newItem, PoParts, newObj.VendorId);
|
||||||
|
|
||||||
|
continue;//on to next item
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//CHANGED ONLY THE RECEIVED AMOUNT
|
||||||
|
if (oldItem.QuantityReceived != newItem.QuantityReceived)
|
||||||
|
{
|
||||||
|
decimal netChange = 0;
|
||||||
|
if (oldItem.QuantityReceived < newItem.QuantityReceived)
|
||||||
|
netChange = newItem.QuantityReceived - oldItem.QuantityReceived;//More received
|
||||||
|
else
|
||||||
|
netChange = newItem.QuantityReceived - oldItem.QuantityReceived;//less received
|
||||||
|
|
||||||
|
dtPOPartInventory i = new dtPOPartInventory();
|
||||||
|
i.PartId = newItem.PartId;
|
||||||
|
i.PartWarehouseId = newItem.PartWarehouseId;
|
||||||
|
i.Quantity = netChange;
|
||||||
|
i.SourceType = AyaType.PurchaseOrder;
|
||||||
|
i.SourceId = newObj.Id;
|
||||||
|
await pib.CreateAsync(i);
|
||||||
|
|
||||||
|
//MIGRATE_OUTSTANDING - update workorderitempart here if applicable
|
||||||
|
|
||||||
|
//Update part values into poitem if the vendor has changed
|
||||||
|
if (oldObj.VendorId != newObj.VendorId)
|
||||||
|
SetPoItemDefaultPartValues(newItem, PoParts, newObj.VendorId);
|
||||||
|
continue;//on to next
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//CHANGED ONLY THE VENDOR
|
||||||
|
if (oldObj.VendorId != newObj.VendorId)
|
||||||
|
{
|
||||||
|
SetPoItemDefaultPartValues(newItem, PoParts, newObj.VendorId);
|
||||||
|
continue;//on to next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}//modified block
|
||||||
|
}
|
||||||
|
|
||||||
|
//Called to update Part values into poitem like VendorNumber and costs etc
|
||||||
|
private void SetPoItemDefaultPartValues(PurchaseOrderItem poItem, List<Part> poParts, long vendorId)
|
||||||
|
{
|
||||||
|
var ThisPart = poParts.Single(x => x.Id == poItem.PartId);//part should always be there, if it isn't we have deeper problems
|
||||||
|
//VendorPartNumber
|
||||||
|
if (ThisPart.ManufacturerId == vendorId)
|
||||||
|
poItem.VendorPartNumber = ThisPart.ManufacturerNumber;
|
||||||
|
else if (ThisPart.WholeSalerId == vendorId)
|
||||||
|
poItem.VendorPartNumber = ThisPart.WholeSalerNumber;
|
||||||
|
else if (ThisPart.AlternativeWholeSalerId == vendorId)
|
||||||
|
poItem.VendorPartNumber = ThisPart.AlternativeWholeSalerNumber;
|
||||||
|
|
||||||
|
//Cost
|
||||||
|
poItem.PurchaseOrderCost = ThisPart.Cost;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ namespace AyaNova.Models
|
|||||||
public long? PartRequestedById { get; set; }
|
public long? PartRequestedById { get; set; }
|
||||||
public long? WorkorderItemPartRequestId { get; set; }
|
public long? WorkorderItemPartRequestId { get; set; }
|
||||||
public long? PurchaseTaxCodeId { get; set; }
|
public long? PurchaseTaxCodeId { get; set; }
|
||||||
|
public string VendorPartNumber { get; set; }
|
||||||
|
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
|
|||||||
@@ -742,7 +742,7 @@ $BODY$ LANGUAGE PLPGSQL STABLE");
|
|||||||
await ExecQueryAsync("CREATE TABLE apurchaseorderitem (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, purchaseorderid BIGINT NOT NULL REFERENCES apurchaseorder ON DELETE CASCADE, " +
|
await ExecQueryAsync("CREATE TABLE apurchaseorderitem (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, purchaseorderid BIGINT NOT NULL REFERENCES apurchaseorder ON DELETE CASCADE, " +
|
||||||
"partid BIGINT NOT NULL REFERENCES apart, partwarehouseid BIGINT NOT NULL REFERENCES apartwarehouse, quantityordered DECIMAL(19,4) NOT NULL default 0, " +
|
"partid BIGINT NOT NULL REFERENCES apart, partwarehouseid BIGINT NOT NULL REFERENCES apartwarehouse, quantityordered DECIMAL(19,4) NOT NULL default 0, " +
|
||||||
"quantityreceived DECIMAL(19,4) NOT NULL default 0, purchaseordercost DECIMAL(19,4) NOT NULL default 0, receivedcost DECIMAL(19,4) NOT NULL default 0, " +
|
"quantityreceived DECIMAL(19,4) NOT NULL default 0, purchaseordercost DECIMAL(19,4) NOT NULL default 0, receivedcost DECIMAL(19,4) NOT NULL default 0, " +
|
||||||
"receiveddate TIMESTAMP, partrequestedbyid BIGINT REFERENCES auser, purchasetaxcodeid BIGINT REFERENCES ataxcode " +
|
"receiveddate TIMESTAMP, partrequestedbyid BIGINT REFERENCES auser, purchasetaxcodeid BIGINT REFERENCES ataxcode, vendorpartnumber TEXT " +
|
||||||
")");
|
")");
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user