Skip to content

Instantly share code, notes, and snippets.

@BrianMRO
Created October 26, 2021 14:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BrianMRO/b8e9a1bab9d047f44c461b11791257c9 to your computer and use it in GitHub Desktop.
Save BrianMRO/b8e9a1bab9d047f44c461b11791257c9 to your computer and use it in GitHub Desktop.
Create Purchase Orders Without Merging Demand Into Single PO Lines - Full Code
#region CreatePOOrders - Replace base version (clone and inject code)
public static PXRedirectRequiredException CreatePOOrders(List<POFixedDemand> list, DateTime? PurchDate, bool extSort)
{
POOrderEntry docgraph = PXGraph.CreateInstance<POOrderEntry>();
docgraph.Views.Caches.Add(typeof(SOLineSplit3));
POSetup setup = docgraph.POSetup.Current;
DocumentList<POOrder> created = new DocumentList<POOrder>(docgraph);
Dictionary<String, DocumentList<POLine>> orderedByPlantype = new Dictionary<String, DocumentList<POLine>>();
DocumentList<POLine> ordered;
list = docgraph.SortPOFixDemandList(list);
POOrder order = null;
bool hasErrors = false;
foreach (POFixedDemand demand in list)
{
if (demand.FixedSource != INReplenishmentSource.Purchased)
continue;
string OrderType =
demand.PlanType == INPlanConstants.Plan6D ? POOrderType.DropShip :
demand.PlanType == INPlanConstants.Plan6E ? POOrderType.DropShip :
POOrderType.RegularOrder;
string replanType = null;
if (demand.VendorID == null || demand.VendorLocationID == null)
{
PXProcessing<POFixedDemand>.SetWarning(list.IndexOf(demand), Messages.MissingVendorOrLocation);
continue;
}
PXErrorLevel ErrorLevel = PXErrorLevel.RowInfo;
string ErrorText = string.Empty;
try
{
SOOrder soorder = PXSelect<SOOrder, Where<SOOrder.noteID, Equal<Required<SOOrder.noteID>>>>.Select(docgraph, demand.RefNoteID);
SOLineSplit3 soline = PXSelect<SOLineSplit3, Where<SOLineSplit3.planID, Equal<Required<SOLineSplit3.planID>>>>.Select(docgraph, demand.PlanID);
if (soline?.POSource.IsIn(INReplenishmentSource.DropShipToOrder, INReplenishmentSource.BlanketDropShipToOrder) == true && soline.IsValidForDropShip != true)
{
throw new PXException(SO.Messages.DropShipSOLineCantHaveMultipleSplitsOrAllocation);
}
string BLType = null;
string BLOrderNbr = null;
if (demand.PlanType == INPlanConstants.Plan6B ||
demand.PlanType == INPlanConstants.Plan6E)
{
BLType = soline.POType;
BLOrderNbr = soline.PONbr;
}
var orderSearchValues = new List<FieldLookup>()
{
new FieldLookup<POOrder.orderType>(OrderType),
new FieldLookup<POOrder.vendorID>(demand.VendorID),
new FieldLookup<POOrder.vendorLocationID>(demand.VendorLocationID),
new FieldLookup<POOrder.bLOrderNbr>(BLOrderNbr),
};
if (OrderType == POOrderType.RegularOrder)
{
bool requireSingleProject = (docgraph.apsetup.Current.RequireSingleProjectPerDocument == true);
if (requireSingleProject)
{
int? project = demand.ProjectID ?? PM.ProjectDefaultAttribute.NonProject();
orderSearchValues.Add(new FieldLookup<POOrder.projectID>(project));
}
if (order != null && order.ShipDestType == POShippingDestination.CompanyLocation && order.SiteID == null)
{
//When previous order was shipped to Company then we would never find it if we search by POSiteID
}
else
{
orderSearchValues.Add(new FieldLookup<POOrder.siteID>(demand.POSiteID));
}
}
else if (OrderType == POOrderType.DropShip)
{
orderSearchValues.Add(new FieldLookup<POOrder.sOOrderType>(soline.OrderType));
orderSearchValues.Add(new FieldLookup<POOrder.sOOrderNbr>(soline.OrderNbr));
}
else
{
orderSearchValues.Add(new FieldLookup<POOrder.shipToBAccountID>(soorder.CustomerID));
orderSearchValues.Add(new FieldLookup<POOrder.shipToLocationID>(soorder.CustomerLocationID));
orderSearchValues.Add(new FieldLookup<POOrder.siteID>(demand.POSiteID));
}
order = created.Find(orderSearchValues.ToArray()) ?? new POOrder();
if (order.OrderNbr == null)
{
docgraph.Clear();
order.OrderType = OrderType;
order = PXCache<POOrder>.CreateCopy(docgraph.Document.Insert(order));
order.VendorID = demand.VendorID;
order.VendorLocationID = demand.VendorLocationID;
order.SiteID = demand.POSiteID;
if (demand.ProjectID != null)
{
order.ProjectID = demand.ProjectID;
}
order.OrderDate = PurchDate;
order.BLType = BLType;
order.BLOrderNbr = BLOrderNbr;
if (OrderType == POOrderType.DropShip || extSort)
{
order.SOOrderType = soline.OrderType;
order.SOOrderNbr = soline.OrderNbr;
}
if (!string.IsNullOrEmpty(order.BLOrderNbr))
{
POOrder blanket = PXSelect<POOrder, Where<POOrder.orderType, Equal<Current<POOrder.bLType>>, And<POOrder.orderNbr, Equal<Current<POOrder.bLOrderNbr>>>>>.SelectSingleBound(docgraph, new object[] { order });
if (blanket != null)
{
order.VendorRefNbr = blanket.VendorRefNbr;
}
}
if (OrderType == POOrderType.DropShip)
{
order.ShipDestType = POShippingDestination.Customer;
order.ShipToBAccountID = soorder.CustomerID;
order.ShipToLocationID = soorder.CustomerLocationID;
}
else if (setup.ShipDestType == POShipDestType.Site)
{
order.ShipDestType = POShippingDestination.Site;
order.SiteID = demand.POSiteID;
}
if (PXAccess.FeatureInstalled<FeaturesSet.multicurrency>())
{
//GetValuePending will fall in CurrencyInfo_CuryIdFieldSelecting()
docgraph.currencyinfo.Current.CuryID = null;
}
order = docgraph.Document.Update(order);
if (OrderType == POOrderType.DropShip)
{
SOAddress soAddress = PXSelect<SOAddress, Where<SOAddress.addressID, Equal<Required<SOOrder.shipAddressID>>>>.Select(docgraph, soorder.ShipAddressID);
if (soAddress.IsDefaultAddress == false)
{
AddressAttribute.CopyRecord<POOrder.shipAddressID>(docgraph.Document.Cache, order, soAddress, true);
}
SOContact soContact = PXSelect<SOContact, Where<SOContact.contactID, Equal<Required<SOOrder.shipContactID>>>>.Select(docgraph, soorder.ShipContactID);
if (soContact.IsDefaultContact == false)
{
ContactAttribute.CopyRecord<POOrder.shipContactID>(docgraph.Document.Cache, order, soContact, true);
}
if (order.ExpectedDate < soorder.RequestDate)
{
order = PXCache<POOrder>.CreateCopy(order);
order.ExpectedDate = soorder.RequestDate;
order = docgraph.Document.Update(order);
}
}
}
else if (docgraph.Document.Cache.ObjectsEqual(docgraph.Document.Current, order) == false)
{
docgraph.Document.Current = docgraph.Document.Search<POOrder.orderNbr>(order.OrderNbr, order.OrderType);
}
//we do not want vendor inventory updated in this case
order.UpdateVendorCost = false;
POLine line = null;
//Sales Orders to Blanket should not be grouped together
//Drop Ships to Blankets are not grouped either
if (!orderedByPlantype.TryGetValue(demand.PlanType, out ordered))
{
ordered = orderedByPlantype[demand.PlanType] = new DocumentList<POLine>(docgraph);
}
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
// Get MyField from Plan - stored in INItemPlanExt
INItemPlan plan = demand as INItemPlan;
INItemPlanExt planExt = plan.GetExtension<INItemPlanExt>();
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
if (OrderType == POOrderType.RegularOrder && demand.PlanType != INPlanConstants.Plan6B)
{
var lineSearchValues = new List<FieldLookup>()
{
new FieldLookup<POLine.vendorID>(demand.VendorID),
new FieldLookup<POLine.vendorLocationID>(demand.VendorLocationID),
new FieldLookup<POLine.siteID>(demand.POSiteID),
new FieldLookup<POLine.inventoryID>(demand.InventoryID),
new FieldLookup<POLine.subItemID>(demand.SubItemID),
new FieldLookup<POLine.requestedDate>(soline?.ShipDate),
new FieldLookup<POLine.projectID>(soline?.ProjectID),
new FieldLookup<POLine.taskID>(soline?.TaskID),
new FieldLookup<POLine.costCodeID>(soline?.CostCodeID),
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
//Add MyField to Search
new FieldLookup<POLineExt.usrXXMyField>(planExt?.UsrXXMyField),
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
};
if (setup.CopyLineDescrSO == true && soline != null)
{
lineSearchValues.Add(new FieldLookup<POLine.tranDesc>(soline.TranDesc));
line = ordered.Find(lineSearchValues.ToArray());
if (line != null && setup.CopyLineNoteSO == true &&
(PXNoteAttribute.GetNote(docgraph.Caches[typeof(POLine)], line) != null || PXNoteAttribute.GetNote(docgraph.Caches[typeof(SOLineSplit3)], soline) != null))
{
line = null;
}
}
else
line = ordered.Find(lineSearchValues.ToArray());
}
line = line ?? new POLine();
if (line.OrderNbr == null)
{
docgraph.FillPOLineFromDemand(line, demand, OrderType, soline);
line = docgraph.Transactions.Insert(line);
if (setup.CopyLineNoteSO == true && soline != null)
{
PXNoteAttribute.SetNote(docgraph.Transactions.Cache, line,
PXNoteAttribute.GetNote(docgraph.Caches[typeof(SOLineSplit3)], soline));
}
if (docgraph.onCopyPOLineFields != null)
{
docgraph.onCopyPOLineFields(demand, line);
}
line = PXCache<POLine>.CreateCopy(line);
ordered.Add(line);
}
else
{
line = (POLine)
PXSelect<POLine,
Where<POLine.orderType, Equal<Current<POOrder.orderType>>,
And<POLine.orderNbr, Equal<Current<POOrder.orderNbr>>,
And<POLine.lineNbr, Equal<Current<POLine.lineNbr>>>>>>
.SelectSingleBound(docgraph, new object[] { line });
line = PXCache<POLine>.CreateCopy(line);
line.OrderQty += demand.OrderQty;
}
if (demand.PlanType == INPlanConstants.Plan6B ||
demand.PlanType == INPlanConstants.Plan6E)
{
replanType =
demand.PlanType == INPlanConstants.Plan6B
? INPlanConstants.Plan66
: INPlanConstants.Plan6D;
demand.FixedSource = INReplenishmentSource.Purchased;
line.POType = soline.POType;
line.PONbr = soline.PONbr;
line.POLineNbr = soline.POLineNbr;
POLine blanket_line =
PXSelect<POLine,
Where<POLine.orderType, Equal<Current<POLine.pOType>>,
And<POLine.orderNbr, Equal<Current<POLine.pONbr>>,
And<POLine.lineNbr, Equal<Current<POLine.pOLineNbr>>>>>>
.SelectSingleBound(docgraph, new object[] { line });
if (blanket_line != null)
{
//POOrderEntry() is persisted on each loop, BaseOpenQty will include everything in List<POLine> ordered
if (demand.PlanQty > blanket_line.BaseOpenQty)
{
line.OrderQty -= demand.OrderQty;
if (string.Equals(line.UOM, blanket_line.UOM))
{
line.OrderQty += blanket_line.OpenQty;
}
else
{
PXDBQuantityAttribute.CalcBaseQty<POLine.orderQty>(docgraph.Transactions.Cache, line);
line.BaseOrderQty += blanket_line.BaseOpenQty;
PXDBQuantityAttribute.CalcTranQty<POLine.orderQty>(docgraph.Transactions.Cache, line);
}
ErrorLevel = PXErrorLevel.RowWarning;
ErrorText += PXMessages.LocalizeFormatNoPrefixNLA(Messages.QuantityReducedToBlanketOpen, line.PONbr);
}
line.CuryUnitCost = blanket_line.CuryUnitCost;
line.UnitCost = blanket_line.UnitCost;
}
}
line = docgraph.Transactions.Update(line);
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
// Save MyField to PO Line
POLineExt lineExt = line.GetExtension<POLineExt>();
lineExt.UsrXXMyField = planExt.UsrXXMyField;
docgraph.Caches[typeof(POLine)].Update(lineExt);
////////////////////////////////////////
////////////////////////////////////////
////////////////////////////////////////
var dsLinksExt = docgraph.GetExtension<DropShipLinksExt>();
if (soline != null && line.LineType.IsIn(POLineType.GoodsForDropShip, POLineType.NonStockForDropShip) && dsLinksExt != null)
{
DropShipLink newLink = new DropShipLink();
newLink.POOrderType = line.OrderType;
newLink.POOrderNbr = line.OrderNbr;
newLink.POLineNbr = line.LineNbr;
newLink.SOOrderType = soline.OrderType;
newLink.SOOrderNbr = soline.OrderNbr;
newLink.SOLineNbr = soline.LineNbr;
newLink.Active = true;
newLink.POInventoryID = soline.InventoryID;
newLink.POSiteID = soline.SiteID;
newLink.POBaseOrderQty = soline.BaseOrderQty;
newLink.SOInventoryID = soline.InventoryID;
newLink.SOSiteID = soline.SiteID;
newLink.SOBaseOrderQty = soline.BaseOrderQty;
dsLinksExt.DropShipLinks.Insert(newLink);
}
PXCache cache = docgraph.Caches[typeof(INItemPlan)];
CreateSplitDemand(cache, demand);
cache.SetStatus(demand, PXEntryStatus.Updated);
demand.SupplyPlanID = line.PlanID;
if (replanType != null)
{
cache.RaiseRowDeleted(demand);
demand.PlanType = replanType;
cache.RaiseRowInserted(demand);
}
if (soline != null)
{
if (demand.AlternateID != null && demand.InventoryID != null)
{
PXSelectBase<INItemXRef> xref = new PXSelect<INItemXRef,
Where<INItemXRef.inventoryID, Equal<Required<INItemXRef.inventoryID>>,
And<INItemXRef.alternateID, Equal<Required<INItemXRef.alternateID>>>>>(docgraph);
INItemXRef soXRef = xref.Select(demand.InventoryID, demand.AlternateID);
if (soXRef != null && soXRef.AlternateType == INAlternateType.Global)
{
if (line.AlternateID != null && line.InventoryID != null)
{
INItemXRef poXRef = xref.Select(line.InventoryID, line.AlternateID);
if (poXRef != null && poXRef.AlternateType == INAlternateType.Global)
{
line.AlternateID = demand.AlternateID;
}
}
else
{
line.AlternateID = demand.AlternateID;
}
}
}
soline.POType = line.OrderType;
soline.PONbr = line.OrderNbr;
soline.POLineNbr = line.LineNbr;
soline.RefNoteID = docgraph.Document.Current.NoteID;
string targetPOSource = soline.POSource == INReplenishmentSource.BlanketDropShipToOrder ? INReplenishmentSource.DropShipToOrder
: soline.POSource == INReplenishmentSource.BlanketPurchaseToOrder ? INReplenishmentSource.PurchaseToOrder
: null;
if (targetPOSource != null)
{
soline.POSource = targetPOSource;
POOrderEntry.SOLine5 origsoline = docgraph.FixedDemandOrigSOLine.Select(soline.OrderType, soline.OrderNbr, soline.LineNbr);
if (origsoline != null)
{
origsoline.POSource = targetPOSource;
docgraph.FixedDemandOrigSOLine.Cache.MarkUpdated(origsoline);
}
}
var docgraphext = docgraph.GetExtension<POOrderEntry_Extension>();
docgraphext.UpdateSOLine(soline, docgraph.Document.Current.VendorID, true);
docgraph.FixedDemand.Cache.SetStatus(soline, PXEntryStatus.Updated);
}
if (docgraph.Transactions.Cache.IsInsertedUpdatedDeleted)
{
using (PXTransactionScope scope = new PXTransactionScope())
{
docgraph.Save.Press();
if (demand.PlanType == INPlanConstants.Plan90)
{
docgraph.Replenihment.Current = docgraph.Replenihment.Search<INReplenishmentOrder.noteID>(demand.RefNoteID);
if (docgraph.Replenihment.Current != null)
{
INReplenishmentLine rLine =
PXCache<INReplenishmentLine>.CreateCopy(docgraph.ReplenishmentLines.Insert(new INReplenishmentLine()));
rLine.InventoryID = line.InventoryID;
rLine.SubItemID = line.SubItemID;
rLine.UOM = line.UOM;
rLine.VendorID = line.VendorID;
rLine.VendorLocationID = line.VendorLocationID;
rLine.Qty = line.OrderQty;
rLine.POType = line.OrderType;
rLine.PONbr = docgraph.Document.Current.OrderNbr;
rLine.POLineNbr = line.LineNbr;
rLine.SiteID = demand.POSiteID;
rLine.PlanID = demand.PlanID;
docgraph.ReplenishmentLines.Update(rLine);
docgraph.Caches[typeof(INItemPlan)].Delete(demand);
docgraph.Save.Press();
}
}
scope.Complete();
}
if (ErrorLevel == PXErrorLevel.RowInfo)
{
PXProcessing<POFixedDemand>.SetInfo(list.IndexOf(demand), PXMessages.LocalizeFormatNoPrefixNLA(Messages.PurchaseOrderCreated, docgraph.Document.Current.OrderNbr) + "\r\n" + ErrorText);
}
else
{
PXProcessing<POFixedDemand>.SetWarning(list.IndexOf(demand), PXMessages.LocalizeFormatNoPrefixNLA(Messages.PurchaseOrderCreated, docgraph.Document.Current.OrderNbr) + "\r\n" + ErrorText);
}
if (created.Find(docgraph.Document.Current) == null)
{
created.Add(docgraph.Document.Current);
}
}
}
catch (Exception e)
{
PXProcessing<POFixedDemand>.SetError(list.IndexOf(demand), e);
PXTrace.WriteError(e);
hasErrors = true;
}
}
if (!hasErrors && created.Count == 1)
{
using (new PXTimeStampScope(null))
{
docgraph.Clear();
docgraph.Document.Current = docgraph.Document.Search<POOrder.orderNbr>(created[0].OrderNbr, created[0].OrderType);
return new PXRedirectRequiredException(docgraph, Messages.POOrder);
}
}
return null;
}
#endregion
#region CreateSplitDemand - Copy Private Static Method From Base
private static void CreateSplitDemand(PXCache cache, POFixedDemand demand)
{
if (demand.OrderQty != demand.PlanUnitQty)
{
INItemPlan orig_demand = PXSelectReadonly<INItemPlan,
Where<INItemPlan.planID, Equal<Current<INItemPlan.planID>>>>
.SelectSingleBound(cache.Graph, new object[] { demand });
INItemPlan split = PXCache<INItemPlan>.CreateCopy(orig_demand);
split.PlanID = null;
split.PlanQty = demand.PlanUnitQty - demand.OrderQty;
if (demand.UnitMultDiv == MultDiv.Multiply)
split.PlanQty *= demand.UnitRate;
else
split.PlanQty /= demand.UnitRate;
cache.Insert(split);
cache.RaiseRowDeleted(demand);
demand.PlanQty = orig_demand.PlanQty - split.PlanQty;
cache.RaiseRowInserted(demand);
}
}
#endregion
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment