I'm creating a Process to import items from an external API source into records in Acumatica.
I've created an unbound DAC that is used to represent the entries available from the external API.
[Serializable]
public class ImportItem : IBqlTable
{
[PXBool]
[PXUIField(DisplayName = "Selected")]
public bool? Selected { get; set; }
public abstract class selected : IBqlField { }
[PXString]
[PXUIField(DisplayName = "External Ref Nbr")]
public string RefNbr { get; set; }
public abstract class refNbr : IBqlField { }
}
In a Process graph I implement the delegate of the main view to create and return the Resultset (normally generated from the API data). I then have a screen bound to this graph with a grid view that displays the items to allow the user to select the ones to import. The main Process delegate will then create the records in Acumatica for the selected items.
public class ImportItemsProcess : PXGraph<ImportItemsProcess>
{
public PXProcessing<ImportItem> ImportItems;
public PXCancel<ImportItem> Cancel;
public ImportItemsProcess()
{
ImportItems.SetProcessCaption("Import");
ImportItems.SetProcessAllCaption("Import All");
ImportItems.SetProcessDelegate(ProcessImportItems);
}
protected virtual IEnumerable importItems(PXAdapter adapter)
{
PXResultset<ImportItem> items = new PXResultset<ImportItem>();
/* Would create ImportItems from external API data here */
items.Add(new PXResult<ImportItem>(new ImportItem() { RefNbr = "1" }));
items.Add(new PXResult<ImportItem>(new ImportItem() { RefNbr = "2" }));
items.Add(new PXResult<ImportItem>(new ImportItem() { RefNbr = "3" }));
return items;
}
public static void ProcessImportItems(List<ImportItem> importItems)
{
throw new PXException("ProcessImportItems() has been called");
}
}
And the ASPX page:
<asp:Content ID="cont1" ContentPlaceHolderID="phDS" runat="Server">
<px:PXDataSource ID="ds" runat="server" Visible="True" Width="100%" PrimaryView="ImportItems" TypeName="APIImporter.ImportItemsProcess" >
</px:PXDataSource>
</asp:Content>
<asp:Content ID="cont2" ContentPlaceHolderID="phL" runat="Server">
<px:PXGrid ID="grid" runat="server" Height="400px" Width="100%" Style="z-index: 100"
AllowPaging="True" AllowSearch="True" AdjustPageSize="Auto" DataSourceID="ds" SkinID="Primary" TabIndex="1500" TemporaryFilterCaption="Filter Applied">
<Levels>
<px:PXGridLevel DataMember="ImportItems">
<RowTemplate>
<px:PXCheckBox ID="edSelected" runat="server" AlreadyLocalized="False" DataField="Selected" Text="Selected" CommitChanges="true">
</px:PXCheckBox>
<px:PXTextEdit ID="edRefNbr" runat="server" AlreadyLocalized="False" DataField="RefNbr" DefaultLocale="">
</px:PXTextEdit>
</RowTemplate>
<Columns>
<px:PXGridColumn DataField="Selected" TextAlign="Center" Type="CheckBox" Width="60px" CommitChanges="true">
</px:PXGridColumn>
<px:PXGridColumn DataField="RefNbr">
</px:PXGridColumn>
</Columns>
</px:PXGridLevel>
</Levels>
<AutoSize Container="Window" Enabled="True" MinHeight="200" />
</px:PXGrid>
</asp:Content>
When written as the simplified example here the Process delegate is never invoked. I suspect is has something to do with when the Process button is clicked the callback to the server runs the view's delegate function that re-creates the list of ImportItem objects and that the framework can not relate the newly created objects to the ones in the postback without a Key field. However, if I add an IsKey attribute to the RefNbr of the DAC...
[PXString(IsKey = true)]
[PXUIField(DisplayName = "External Ref Nbr")]
public string RefNbr { get; set; }
...now when selecting an item on the Screen I'm immediately given a line-level error with the message "Error: The argument is out of range. Parameter name: table".
In the data view delegate, you have to add the items to the Cache in addition to returning them. Try below:
protected virtual IEnumerable importItems()
{
int iCachedData = 0;
foreach (var row in ImportItems.Cache.Cached)
{
iCachedData++;
yield return row;
}
if (iCachedData == 0)
{
for (int iCounter = 1; iCounter <= 5; iCounter++)
{
ImportItem item = new ImportItem() { RefNbr = iCounter };
item = ImportItems.Insert(item);
ImportItems.Cache.SetStatus(item, PXEntryStatus.Held);
yield return item;
}
}
}
Good luck!
Try adding abstract classes for your DAC fields first.
If that doesn't resolve your issue please add your ASPX code to your question.
[Serializable]
public class ImportItem : IBqlTable
{
#region Selected
public abstract class selected : IBqlField { }
[PXBool]
[PXUIField(DisplayName = "Selected")]
public bool? Selected { get; set; }
#endregion
#region RefNbr
public abstract class refNbr : IBqlField { }
[PXString]
[PXUIField(DisplayName = "External Ref Nbr")]
public string RefNbr { get; set; }
#endregion
}
I have tried the Processing Graph functionality Using Bound DAC but not Database Table.
This is useful in the case when you want to Access some API and fetch the records in processing screen without saving into the Database. I am not including aspx code here.
The Highlight point in this code in [PXVirtualDAC] and the Key Field in DAC because of this we can achieve this functionality without creating a table. You can say that a Virtual DAC - without bound any database table.
public class TestUnboundProcessing : PXGraph<TestUnboundProcessing>
{
#region Unbound DAC
public class UnboundDAC : IBqlTable
{
#region Selected
[PXDBBool]
[PXUIField(DisplayName = "Selected")]
public virtual bool? Selected { get; set; }
public abstract class selected : PX.Data.IBqlField { }
#endregion
[PXDBString(50, IsUnicode = true,IsKey =true)]
[PXUIField(DisplayName = "Id")]
public string Id { get; set; }
public abstract class id : PX.Data.IBqlField { }
[PXDBString(100, IsUnicode = true)]
[PXUIField(DisplayName = "Author")]
public string Author { get; set; }
public abstract class author : PX.Data.IBqlField { }
[PXDBString(1000, IsUnicode = true)]
[PXUIField(DisplayName = "Body")]
public string Body { get; set; }
public abstract class body : PX.Data.IBqlField { }
}
#endregion
#region Processing Filter DAC
[Serializable]
public partial class TestFilter : PX.Data.IBqlTable
{
#region LastSyncDate
[PXDate()]
[PXDefault(typeof(AccessInfo.businessDate))]
[PXUIField(DisplayName = "Last Sync Date", Visibility = PXUIVisibility.Visible)]
public virtual DateTime? LastSyncDate { get; set; }
public abstract class lastSyncDate : PX.Data.IBqlField { }
#endregion
#region ProjectID
[PXDBString(10, IsUnicode = true)]
[PXUIField(DisplayName = "Project ID")]
public virtual String ProjectID { get; set; }
public abstract class projectID : PX.Data.IBqlField { }
#endregion
#region IssueID
[PXDBString(10, IsUnicode = true)]
[PXUIField(DisplayName = "Issue ID", Visibility = PXUIVisibility.SelectorVisible)]
public virtual String IssueID { get; set; }
public abstract class issueID : PX.Data.IBqlField { }
#endregion
}
#endregion
#region Filter + Delegate Overrides
public PXFilter<TestFilter> Filter;
public PXCancel<TestFilter> Cancel;
[PXVirtualDAC]
[PXFilterable]
public PXFilteredProcessing<UnboundDAC, TestFilter> UnboundView;
protected virtual IEnumerable unboundView()
{
GetUnboundDACList();
foreach (UnboundDAC item in UnboundView.Cache.Cached)
{
yield return item;
}
}
private void GetUnboundDACList()
{
UnboundView.Cache.Insert(new UnboundDAC() { Id = "1", Author = "Test 1", Body = "Comment 1" });
UnboundView.Cache.Insert(new UnboundDAC() { Id = "2", Author = "Test 2", Body = "Comment 2" });
UnboundView.Cache.Insert(new UnboundDAC() { Id = "3", Author = "Test 3", Body = "Comment 3" });
//return UnboundView.Cache;
}
#endregion
#region Constructor + Process
public TestUnboundProcessing()
{
TestFilter filter = Filter.Current;
UnboundView.SetProcessDelegate(delegate (List<UnboundDAC> docList)
{
UnboundProcessing(docList, filter);
}
);
}
#endregion
#region Processing functions
public static void UnboundProcessing(List<UnboundDAC> docList, TestFilter aFilter)
{
TestUnboundProcessing graph = CreateInstance<TestUnboundProcessing>();
graph.SaveRecords(graph, docList, aFilter);
}
public void SaveRecords(TestUnboundProcessing aProcessingGraph, List<UnboundDAC> docList, TestFilter aFilter)
{
bool isErrorOccured = false;
CRActivityMaint graph = PXGraph.CreateInstance<CRActivityMaint>();
foreach (UnboundDAC item in docList)
{
try
{
CRActivity addedActivity = new CRActivity();
addedActivity.UIStatus = ActivityStatusListAttribute.Completed;
addedActivity.Type = "N";
addedActivity.Location = item.Id;
addedActivity.Subject = item.Author;
addedActivity.Body = item.Body;
addedActivity.IsPrivate = true;
graph.Activities.Insert(addedActivity);
}
catch (Exception ex)
{
isErrorOccured = true;
PXProcessing<JRComment>.SetError(docList.IndexOf(item), ex.Message);
}
}
if (graph.Activities.Cache.Cached.Count() > 0)
{
graph.Actions.PressSave();
}
if (isErrorOccured)
{
throw new PXException("One or more record processed unsuccessful");
}
}
#endregion
#region Filter Events
protected virtual void TestFilter_LastSyncDate_FieldUpdated(PXCache sender, PXFieldUpdatedEventArgs e)
{
UnboundView.Cache.Clear();
}
protected virtual void TestFilter_ProjectID_FieldUpdated(PXCache sender, PXFieldUpdatedEventArgs e)
{
UnboundView.Cache.Clear();
}
protected virtual void TestFilter_IssueID_FieldUpdated(PXCache sender, PXFieldUpdatedEventArgs e)
{
UnboundView.Cache.Clear();
}
#endregion
Related
I have a processing screen in Acumatica ERP (2020R2). Whenever I run Process All, it executes the process delegate correctly. But whenever I select some of the records and run the Process action, the process delegate doesn't even get called.
I've implemented several processing screens, and I've never had this problem.
I did notice that, when I click the Selected checkbox, a red dot appears beside the row on the grid and doesn't go away. On other processing screens that I've implemented, the red dot appears then goes away.
Here is my graph:
public class StkItemUpdateProcess : PXGraph<StkItemUpdateProcess>
{
#region Fliter DAC
[PXHidden]
public class StkItemFilter : IBqlTable
{
#region UpdateID
[PXString(15, IsUnicode = true, InputMask = ">CCCCCCCCCCCCCCC")]
[PXUIField(DisplayName = "Update ID")]
[PXSelector(
typeof(SearchFor<StkItemUpdateHdr.updateID>),
typeof(StkItemUpdateHdr.updateID),
typeof(StkItemUpdateHdr.descr),
typeof(StkItemUpdateHdr.vendorID),
typeof(StkItemUpdateHdr.effectiveDate)
)]
public virtual string UpdateID { get; set; }
public abstract class updateID : PX.Data.BQL.BqlString.Field<updateID> { }
#endregion
#region VendorID
[PXInt]
[PXUIField(DisplayName = "Vendor")]
[PXSelector(
typeof(
SearchFor<Vendor.bAccountID>.
In<SelectFrom<Vendor>.
InnerJoin<Address>.
On<Address.addressID.IsEqual<Vendor.defAddressID>>.
Where<Vendor.status.IsEqual<BAccount.status.active>>>
),
typeof(Vendor.acctCD),
typeof(Vendor.acctName),
typeof(Address.city),
typeof(Address.state),
SubstituteKey = typeof(Vendor.acctCD),
DescriptionField = typeof(Vendor.acctName)
)]
public virtual int? VendorID { get; set; }
public abstract class vendorID : PX.Data.BQL.BqlInt.Field<vendorID> { }
#endregion
#region InventoryID
[PXInt]
[PXUIField(DisplayName = "Inventory ID")]
[PXSelector(
typeof(
SearchFor<InventoryItem.inventoryID>.
In<SelectFrom<InventoryItem>.
InnerJoin<POVendorInventory>.
On<POVendorInventory.inventoryID.IsEqual<InventoryItem.inventoryID>>.
Where<InventoryItem.stkItem.IsEqual<True>.
And<POVendorInventory.vendorID.IsEqual<StkItemUpdateHdr.vendorID.FromCurrent>>.
And<POVendorInventory.active.IsEqual<True>>>>
),
typeof(InventoryItem.inventoryCD),
typeof(InventoryItem.descr),
typeof(InventoryItem.itemClassID),
typeof(InventoryItem.itemType),
SubstituteKey = typeof(InventoryItem.inventoryCD)
)]
[PXRestrictor(
typeof(Where<InventoryItem.stkItem.IsEqual<True>.
And<POVendorInventory.vendorID.IsEqual<StkItemUpdateHdr.vendorID.FromCurrent>>.
And<POVendorInventory.active.IsEqual<True>>>),
Messages.InvalidVendorItemPair)]
public virtual int? InventoryID { get; set; }
public abstract class inventoryID : PX.Data.BQL.BqlInt.Field<inventoryID> { }
#endregion
#region FromEffectiveDate
[PXDate]
[PXUIField(DisplayName = "From Date")]
[PXUnboundDefault(typeof(AccessInfo.businessDate), PersistingCheck = PXPersistingCheck.Nothing)]
public virtual DateTime? FromEffectiveDate { get; set; }
public abstract class fromEffectiveDate : PX.Data.BQL.BqlDateTime.Field<fromEffectiveDate> { }
#endregion
#region ToEffectiveDate
[PXDate]
[PXUIField(DisplayName = "To Date")]
[PXUnboundDefault(typeof(AccessInfo.businessDate), PersistingCheck = PXPersistingCheck.Nothing)]
public virtual DateTime? ToEffectiveDate { get; set; }
public abstract class toEffectiveDate : PX.Data.BQL.BqlDateTime.Field<toEffectiveDate> { }
#endregion
}
#endregion
#region Selects / Views
public PXCancel<StkItemFilter> Cancel;
public PXFilter<StkItemFilter> Filter;
public PXFilteredProcessingJoin<StkItemUpdateDet, StkItemFilter,
InnerJoin<StkItemUpdateHdr,
On<StkItemUpdateHdr.updateID.IsEqual<StkItemUpdateDet.updateID>>,
InnerJoin<Vendor,
On<Vendor.bAccountID.IsEqual<StkItemUpdateHdr.vendorID>>,
InnerJoin<InventoryItem,
On<InventoryItem.inventoryID.IsEqual<StkItemUpdateDet.inventoryID>>>>>,
Where<Brackets<StkItemFilter.updateID.FromCurrent.IsNull.
Or<StkItemUpdateDet.updateID.IsEqual<StkItemFilter.updateID.FromCurrent>>>.
And<StkItemFilter.vendorID.FromCurrent.IsNull.
Or<StkItemUpdateHdr.vendorID.IsEqual<StkItemFilter.vendorID.FromCurrent>>>.
And<StkItemFilter.inventoryID.FromCurrent.IsNull.
Or<StkItemUpdateDet.inventoryID.IsEqual<StkItemFilter.inventoryID.FromCurrent>>>.
And<StkItemFilter.fromEffectiveDate.FromCurrent.IsNull.
Or<StkItemUpdateHdr.effectiveDate.IsGreaterEqual<StkItemFilter.fromEffectiveDate.FromCurrent>>>.
And<StkItemFilter.toEffectiveDate.FromCurrent.IsNull.
Or<StkItemUpdateHdr.effectiveDate.IsLessEqual<StkItemFilter.toEffectiveDate.FromCurrent>>>>,
OrderBy<Desc<StkItemUpdateHdr.effectiveDate, Asc<StkItemUpdateDet.updateID, Asc<Vendor.acctCD, Asc<InventoryItem.inventoryCD>>>>>>
StkItemUpdates;
#endregion
#region Constructor
public StkItemUpdateProcess()
{
StkItemUpdates.SetProcessCaption("Update");
StkItemUpdates.SetProcessTooltip("Update Selected Stock Items");
StkItemUpdates.SetProcessAllCaption("Update All");
StkItemUpdates.SetProcessAllTooltip("Update All Stock Items");
StkItemUpdates.SetProcessDelegate(UpdateStkItems);
StkItemUpdates.SetSelected<StkItemUpdateDet.selected>();
}
#endregion
#region Overrides
public override bool IsDirty => false;
#endregion
#region Event Handlers
protected virtual void _(Events.FieldUpdated<StkItemFilter, StkItemFilter.updateID> e)
{
if (e.Row == null) return;
StkItemFilter filter = Filter.Current;
if(filter.UpdateID != null)
{
StkItemUpdateHdr hdr =
SelectFrom<StkItemUpdateHdr>.
Where<StkItemUpdateHdr.updateID.IsEqual<#P.AsString>>.
View.ReadOnly.Select(e.Cache.Graph, filter.UpdateID);
e.Cache.SetValueExt<StkItemFilter.vendorID>(filter, hdr?.VendorID);
}
}
protected virtual void _(Events.FieldSelecting<StkItemUpdateDet, StkItemUpdateDet.defaultVendor> e)
{
if (e.Row == null) return;
StkItemUpdateDet det = e.Row;
PXResultset<POVendorInventory> existingVendors =
SelectFrom<POVendorInventory>.
Where<POVendorInventory.inventoryID.IsEqual<#P.AsInt>>.
View.ReadOnly.Select(e.Cache.Graph, det.InventoryID);
//IsDefault cannot be used in BQL statement because it is not bound.
foreach (POVendorInventory vendor in existingVendors)
{
if (vendor.IsDefault == true)
{
e.ReturnValue = vendor.VendorID;
break;
}
}
}
#endregion
#region Actions
public PXAction<StkItemFilter> OpenUpdate;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Open Update")]
public virtual void openUpdate()
{
StkItemUpdateDet det = StkItemUpdates.Current;
StkItemUpdateMaint stkItemUpdateMaint = PXGraph.CreateInstance<StkItemUpdateMaint>();
stkItemUpdateMaint.UpdateHdr.Current = stkItemUpdateMaint.UpdateHdr.Search<StkItemUpdateHdr.updateID>(det.UpdateID);
if (stkItemUpdateMaint.UpdateHdr.Current != null)
{
throw new PXRedirectRequiredException(stkItemUpdateMaint, true, "Stock Item Update")
{
Mode = PXBaseRedirectException.WindowMode.NewWindow
};
}
}
public PXAction<StkItemFilter> OpenStockItem;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Open Stock Item")]
public virtual void openStockItem()
{
StkItemUpdateDet det = StkItemUpdates.Current;
InventoryItemMaint invtItemMaint = PXGraph.CreateInstance<InventoryItemMaint>();
invtItemMaint.Item.Current = invtItemMaint.Item.Search<InventoryItem.inventoryID>(det.InventoryID);
if (invtItemMaint.Item.Current != null)
{
throw new PXRedirectRequiredException(invtItemMaint, true, "Stock Item")
{
Mode = PXBaseRedirectException.WindowMode.NewWindow
};
}
}
#endregion
#region Static Methods
public static void UpdateStkItems(List<StkItemUpdateDet> stkItemUpdateDets)
{
StkItemUpdateMaint stkItemUpdateMaint = PXGraph.CreateInstance<StkItemUpdateMaint>();
InventoryItemMaint invtItemMaint = PXGraph.CreateInstance<InventoryItemMaint>();
foreach (StkItemUpdateDet det in stkItemUpdateDets)
{
stkItemUpdateMaint.Clear();
invtItemMaint.Clear();
StkItemUpdateHdr hdr = stkItemUpdateMaint.UpdateHdr.Current = stkItemUpdateMaint.UpdateHdr.Search<StkItemUpdateHdr.updateID>(det.UpdateID);
InventoryItem invtItem = invtItemMaint.Item.Current = invtItemMaint.Item.Search<InventoryItem.inventoryID>(det.InventoryID);
if (hdr == null || invtItem == null) continue;
BasisPricing.BasisPricing_InventoryItemExt invtItemExt = PXCache<InventoryItem>.GetExtension<BasisPricing.BasisPricing_InventoryItemExt>(invtItem);
bool fieldUpdated = false;
if (invtItemExt.UsrManualCost != det.ManualCost)
{
invtItemMaint.Item.Cache.SetValueExt<BasisPricing.BasisPricing_InventoryItemExt.usrManualCost>(invtItem, det.ManualCost);
fieldUpdated = true;
}
if (invtItem.RecPrice != det.MSRP)
{
invtItemMaint.Item.Cache.SetValueExt<InventoryItem.recPrice>(invtItem, det.MSRP);
fieldUpdated = true;
}
if (fieldUpdated)
{
invtItemMaint.Item.Cache.Update(invtItem);
invtItemMaint.Actions.PressSave();
det.LastUpdatedDateTime = DateTime.Now;
stkItemUpdateMaint.UpdateDets.Cache.Update(det);
stkItemUpdateMaint.Actions.PressSave();
}
}
}
#endregion
}
Here is my ASPX code:
<%# Page Language="C#" MasterPageFile="~/MasterPages/FormView.master" AutoEventWireup="true" ValidateRequest="false" CodeFile="IN507500.aspx.cs" Inherits="Page_IN507500" Title="Untitled Page" %>
<%# MasterType VirtualPath="~/MasterPages/FormView.master" %>
<asp:Content ID="cont1" ContentPlaceHolderID="phDS" Runat="Server">
<px:PXDataSource ID="ds" runat="server" Visible="True" Width="100%"
TypeName="INCostPriceUpdate.StkItemUpdateProcess"
PrimaryView="Filter"
>
<CallbackCommands>
<px:PXDSCallbackCommand Name="OpenUpdate" Visible="false" />
<px:PXDSCallbackCommand Name="OpenStockItem" Visible="false" />
</CallbackCommands>
</px:PXDataSource>
</asp:Content>
<asp:Content ID="cont2" ContentPlaceHolderID="phF" Runat="Server">
<px:PXFormView ID="form" runat="server" DataSourceID="ds" DataMember="Filter" Width="100%" AllowAutoHide="false">
<Template>
<px:PXLayoutRule ID="PXLayoutRule1" runat="server" StartRow="True"/>
<px:PXLayoutRule ID="PXLayoutRule2" runat="server" StartColumn="True" LabelsWidth="85px" ControlSize="XM" />
<px:PXSelector ID="PXSelector1" runat="server" DataField="UpdateID" CommitChanges="true" />
<px:PXSelector ID="FilterVendorID" runat="server" DataField="VendorID" CommitChanges="true" />
<px:PXSelector ID="FilterInventoryID" runat="server" DataField="InventoryID" CommitChanges="true" />
<px:PXLayoutRule ID="PXLayoutRule3" runat="server" StartColumn="True" LabelsWidth="75px" />
<px:PXDateTimeEdit ID="FilterFromDate" runat="server" DataField="FromEffectiveDate" CommitChanges="true" />
<px:PXDateTimeEdit ID="FilterToDate" runat="server" DataField="ToEffectiveDate" CommitChanges="true" />
</Template>
<AutoSize Container="Window" Enabled="True" MinHeight="30" />
</px:PXFormView>
<px:PXGrid ID="StkItemUpdateDetGrid" runat="server" Width="100%" Height="650px" SyncPosition="true" AdjustPageSize="Auto" AllowPaging="false" SkinID="PrimaryInquire" DataSourceID="ds">
<Levels>
<px:PXGridLevel DataMember="StkItemUpdates">
<Columns>
<px:PXGridColumn DataField="Selected" Type="CheckBox" TextAlign="Center" CommitChanges="true" AllowCheckAll="true" AllowMove="false" AllowResize="false" AllowSort="false" AllowShowHide="false"></px:PXGridColumn>
<px:PXGridColumn DataField="StkItemUpdateHdr__VendorID" Width="140" ></px:PXGridColumn>
<px:PXGridColumn DataField="UpdateID" LinkCommand="OpenUpdate" ></px:PXGridColumn>
<px:PXGridColumn DataField="StkItemUpdateHdr__EffectiveDate" Width="90" />
<px:PXGridColumn DataField="InventoryID" CommitChanges="true" Width="150" LinkCommand="OpenStockItem" ></px:PXGridColumn>
<px:PXGridColumn DataField="InventoryDescr" Width="200" ></px:PXGridColumn>
<px:PXGridColumn DataField="ManualCost" Width="100" CommitChanges="true" ></px:PXGridColumn>
<px:PXGridColumn DataField="MSRP" Width="100" CommitChanges="true" ></px:PXGridColumn>
<px:PXGridColumn DataField="CurrManualCost" Width="100" ></px:PXGridColumn>
<px:PXGridColumn DataField="CurrMSRP" Width="100" ></px:PXGridColumn>
<px:PXGridColumn DataField="LastUpdatedDateTime" Width="150" DisplayFormat="g" ></px:PXGridColumn>
<px:PXGridColumn DataField="DefaultVendor" Width="150" ></px:PXGridColumn>
<px:PXGridColumn DataField="AvailVendors" Width="250" ></px:PXGridColumn></Columns>
<RowTemplate>
<px:PXSelector AllowEdit="True" runat="server" ID="CstPXSelector1" DataField="DefaultVendor" ></px:PXSelector>
<px:PXSelector runat="server" ID="CstPXSelector3" DataField="StkItemUpdateHdr__VendorID" AllowEdit="True" ></px:PXSelector></RowTemplate></px:PXGridLevel>
</Levels>
</px:PXGrid>
</asp:Content>
Here is the main DAC used on the Processing Screen:
public class StkItemUpdateDet : IBqlTable
{
#region Selected
[PXBool]
[PXUIField(DisplayName = "Selected")]
public virtual bool? Selected { get; set; }
public abstract class selected : PX.Data.BQL.BqlBool.Field<selected> { }
#endregion
#region UpdateID
[PXDBString(15, IsKey = true, IsUnicode = true, InputMask = ">CCCCCCCCCCCCCCC")]
[PXUIField(DisplayName = "Update ID", Enabled = false)]
[PXDBDefault(typeof(StkItemUpdateHdr.updateID))]
[PXParent(typeof(SelectFrom<StkItemUpdateHdr>.
Where<StkItemUpdateHdr.updateID.IsEqual<StkItemUpdateDet.updateID.FromCurrent>>)
)]
public virtual string UpdateID { get; set; }
public abstract class updateID : PX.Data.BQL.BqlString.Field<updateID> { }
#endregion
#region InventoryID
[PXDBInt(IsKey = true)]
[PXUIField(DisplayName = "Inventory ID")]
[PXDefault]
[PXSelector(
typeof(
SearchFor<InventoryItem.inventoryID>.
In<SelectFrom<InventoryItem>.
InnerJoin<POVendorInventory>.
On<POVendorInventory.inventoryID.IsEqual<InventoryItem.inventoryID>>.
Where<InventoryItem.stkItem.IsEqual<True>.
And<POVendorInventory.vendorID.IsEqual<StkItemUpdateHdr.vendorID.FromCurrent>>.
And<POVendorInventory.active.IsEqual<True>>>>
),
typeof(InventoryItem.inventoryCD),
typeof(InventoryItem.descr),
typeof(InventoryItem.itemClassID),
typeof(InventoryItem.itemType),
SubstituteKey = typeof(InventoryItem.inventoryCD)
)]
[PXRestrictor(
typeof(Where<InventoryItem.stkItem.IsEqual<True>.
And<POVendorInventory.vendorID.IsEqual<StkItemUpdateHdr.vendorID.FromCurrent>>.
And<POVendorInventory.active.IsEqual<True>>>),
Messages.InvalidVendorItemPair)]
public virtual int? InventoryID { get; set; }
public abstract class inventoryID : PX.Data.BQL.BqlInt.Field<inventoryID> { }
#endregion
#region InventoryDesc
[PXString]
[PXUIField(DisplayName = "Descr.", Enabled = false)]
[InventoryDescr]
public virtual string InventoryDescr { get; set; }
public abstract class inventoryDescr : PX.Data.BQL.BqlString.Field<inventoryDescr> { }
#endregion
#region ManualCost
[PXDBDecimal(6)]
[PXUIField(DisplayName = "New Manual Cost")]
[PXDefault(TypeCode.Decimal, "0.000000")]
public virtual decimal? ManualCost { get; set; }
public abstract class manualCost : PX.Data.BQL.BqlDecimal.Field<manualCost> { }
#endregion
#region MSRP
[PXDBDecimal(2)]
[PXUIField(DisplayName = "New MSRP")]
[PXDefault(TypeCode.Decimal, "0.00")]
public virtual decimal? MSRP { get; set; }
public abstract class msrp : PX.Data.BQL.BqlDecimal.Field<msrp> { }
#endregion
#region CurrManualCost
[PXDecimal(6)]
[PXUIField(DisplayName = "Current Manual Cost", Enabled = false)]
[ManualCost]
public virtual decimal? CurrManualCost { get; set; }
public abstract class currManualCost : PX.Data.BQL.BqlDecimal.Field<currManualCost> { }
#endregion
#region CurrMSRP
[PXDecimal(2)]
[PXUIField(DisplayName = "Current MSRP", Enabled = false)]
[MSRP]
public virtual decimal? CurrMSRP { get; set; }
public abstract class currMSRP : PX.Data.BQL.BqlDecimal.Field<currMSRP> { }
#endregion
#region LastUpdatedDateTime
[PXDBDate(PreserveTime = true, UseTimeZone = false)]
[PXUIField(DisplayName = "Update Last Executed", Enabled = false)]
public virtual DateTime? LastUpdatedDateTime { get; set; }
public abstract class lastUpdatedDateTime : PX.Data.BQL.BqlDateTime.Field<lastUpdatedDateTime> { }
#endregion
#region DefaultVendor
[PXInt]
[PXUIField(DisplayName = "Default Vendor", Enabled = false)]
[PXSelector(
typeof(SearchFor<Vendor.bAccountID>),
SubstituteKey = typeof(Vendor.acctCD)
)]
public int? DefaultVendor { get; set; }
public abstract class defaultVendor : PX.Data.BQL.BqlInt.Field<defaultVendor> { }
#endregion
#region AvailVendors
[PXString]
[PXUIField(DisplayName = "Available Vendors", Enabled = false)]
[AvailVendors]
public string AvailVendors { get; set; }
public abstract class availVendors : PX.Data.BQL.BqlString.Field<availVendors> { }
#endregion
#region System Fields
#region CreatedByID
[PXDBCreatedByID()]
public virtual Guid? CreatedByID { get; set; }
public abstract class createdByID : PX.Data.BQL.BqlGuid.Field<createdByID> { }
#endregion
#region CreatedByScreenID
[PXDBCreatedByScreenID()]
public virtual string CreatedByScreenID { get; set; }
public abstract class createdByScreenID : PX.Data.BQL.BqlString.Field<createdByScreenID> { }
#endregion
#region CreatedDateTime
[PXDBCreatedDateTime()]
public virtual DateTime? CreatedDateTime { get; set; }
public abstract class createdDateTime : PX.Data.BQL.BqlDateTime.Field<createdDateTime> { }
#endregion
#region LastModifiedByID
[PXDBLastModifiedByID()]
public virtual Guid? LastModifiedByID { get; set; }
public abstract class lastModifiedByID : PX.Data.BQL.BqlGuid.Field<lastModifiedByID> { }
#endregion
#region LastModifiedByScreenID
[PXDBLastModifiedByScreenID()]
public virtual string LastModifiedByScreenID { get; set; }
public abstract class lastModifiedByScreenID : PX.Data.BQL.BqlString.Field<lastModifiedByScreenID> { }
#endregion
#region LastModifiedDateTime
[PXDBLastModifiedDateTime()]
public virtual DateTime? LastModifiedDateTime { get; set; }
public abstract class lastModifiedDateTime : PX.Data.BQL.BqlDateTime.Field<lastModifiedDateTime> { }
#endregion
#region tstamp
[PXDBTimestamp()]
public virtual byte[] tstamp { get; set; }
public abstract class Tstamp : PX.Data.BQL.BqlByteArray.Field<Tstamp> { }
#endregion
#region Noteid
[PXNote()]
public virtual Guid? Noteid { get; set; }
public abstract class noteid : PX.Data.BQL.BqlGuid.Field<noteid> { }
#endregion
#endregion
}
Good day
I have a checkbox on my shipment page called Special Labels.
The client wants the field to display as a Yes/No dropdown box or something in that line.
Is this possible?
I think you could handle this a couple of ways:
Option 1 (PXDropdown):
Create a string field for a Yes/No dropdown and use its value to set your boolean field:
#region ActiveString
public abstract class activeString : PX.Data.IBqlField
{
}
[PXString]
[PXDefault("false")]
[YesNo.List()]
[PXUIField(DisplayName = "Active")]
public virtual string ActiveString { get; set; }
#endregion
#region Active
public abstract class active : PX.Data.IBqlField
{
}
[PXDBBool]
[PXDefault(true)]
[PXUIField(DisplayName = "Active", Visible = false, Enabled = false)]
public virtual bool? Active {
get { return Convert.ToBoolean(this.ActiveString ?? "false"); }
set { value = Convert.ToBoolean(this.ActiveString ?? "false"); }
}
#endregion
The dropdown ASPX markup:
<px:PXDropdown ID="edActive" runat="server"
DataField="ActiveString" Size="XS" >
<AutoCallBack Command="Save" Target="form">
</AutoCallBack>
</px:PXDropdown>
Option 2 (PXSelector):
Create a small table in the database for a selector, such as:
CREATE TABLE [dbo].[UsrTrueFalse]
(
[BoolValue] bit NOT NULL,
[TextValue] [varchar](3) NOT NULL
)
and create a DAC over the table:
[System.SerializableAttribute()]
public class UsrTrueFalse : IBqlTable
{
#region BoolValue
public abstract class boolValue : PX.Data.IBqlField
{
}
[PXDBBool]
[PXUIField(DisplayName = "Bool Value")]
public virtual bool? BoolValue { get; set; }
#endregion
#region TextValue
public abstract class textValue : PX.Data.IBqlField
{
}
[PXDBString(3)]
[PXUIField(DisplayName = "Text Value")]
public virtual string TextValue { get; set; }
#endregion
}
and then add a PXSelector attribute on your boolean field:
#region Active
public abstract class active : PX.Data.IBqlField
{
}
[PXDBBool]
[PXDefault(true)]
[PXSelector(typeof(Search<UsrTrueFalse.boolValue>),
DescriptionField = typeof(UsrTrueFalse.textValue))]
[PXUIField(DisplayName = "Active")]
public virtual bool? Active { get; set; }
#endregion
The PXSelector ASPX markup:
<px:PXSelector ID="edActive" runat="server" DataField="Active" DataSourceID="ds" Size="XS" DisplayMode="Text">
<AutoCallBack Command="Save" Target="form">
</AutoCallBack>
</px:PXSelector>
FormulaID is the identity field and it's new developed screen, but I am not able to get the selector. I have tried all the ways that I know to achieve that:
Maintaining parent and child relationships
Dataview with BQL Query
Below are the definitions of the FormulaID and FormulaCD from DAC:
#region FormulaID
public abstract class formulaID : PX.Data.IBqlField
{
}
protected int? _FormulaID;
[PXDBIdentity(IsKey =true)]
[PXUIField(Enabled = false)]
public virtual int? FormulaID
{
get
{
return this._FormulaID;
}
set
{
this._FormulaID = value;
}
#endregion
#region FormulaCD
public abstract class formulaCD : PX.Data.IBqlField
{
}
protected string _FormulaCD;
[PXDBString(30,IsUnicode = true)]
[PXUIField(DisplayName = "Formula ID", Visibility = PXUIVisibility.SelectorVisible)]
[PXSelector(typeof(Search<TSFormula.formulaCD>),
typeof(TSFormula.descr),SubstituteKey = typeof(TSFormula.formulaCD), ValidateValue = false)]
public virtual string FormulaCD
{
get
{
return this._FormulaCD;
}
set
{
this._FormulaCD = value;
}
}
#endregion
In my example below, the PXDBIdentity integer field is not enabled and not visible. The String field is marked isKey=true with the PXSelector described. The ASPX page markup offers the px:PXSelector tag for the String field as shown:
<px:PXSelector ID="edContractNumber" runat="server" DataField="ContractNumber"
AutoRefresh="True" DataSourceID="ds" NullText="<NEW>">
<GridProperties FastFilterFields="ShortName">
<Columns>
<px:PXGridColumn DataField="ContractNumber" Width="90px"></px:PXGridColumn>
<px:PXGridColumn DataField="ShortName" Width="120px"></px:PXGridColumn>
</Columns>
</GridProperties>
</px:PXSelector>
Here are the DAC fields:
#region ContractID
public abstract class contractID : PX.Data.IBqlField
{
}
[PXDBIdentity()]
[PXDefault(0)]
[PXUIField(Visible = false, Enabled = false)]
public virtual int? ContractID
{
get;
set;
}
#endregion
#region ContractNumber
public abstract class contractNumber : PX.Data.IBqlField
{
}
[PXDBString(IsKey = true)]
[PXDefault()]
[PXSelector(typeof(Search3<MyDAC.contractNumber,
OrderBy<Desc<MyDAC.contractID>>>),
new Type[] {
typeof(MyDAC.shortName),
typeof(MyDAC.contractNumber)},
DirtyRead = true)]
[PXUIField(DisplayName = "Contract Number", Required = true)]
public virtual string ContractNumber { get; set; }
#endregion
I'm attempting to add a Default Branch Location field to Branch. This field will allow the user to select a Branch Location to be the default and have this default in several future customizations. My problem is that when I populate my new extension field, the value is saved on all branch records instead of the selected branch.
I extend the Branch DAC (as that is where the data will be stored):
//Branch Extension
[PXTable(typeof(Branch.branchID), IsOptional = false)]
public class BranchExtension : PXCacheExtension<Branch>
{
#region DefaultBranchLocation
public abstract class defaultBranchLocation : IBqlField { }
[PXDBInt()]
[PXUIField(DisplayName = "Default Branch Location")]
[PXSelector(typeof(FSBranchLocation.branchLocationID),
DescriptionField = typeof(FSBranchLocation.descr),
SubstituteKey = typeof(FSBranchLocation.branchLocationCD))]
public virtual int? DefaultBranchLocation { get; set; }
#endregion
}
Here is the Branch extension table I created:
<Sql TableName="BranchExtension" TableSchemaXml="#CDATA">
<CDATA name="TableSchemaXml"><![CDATA[<table name="BranchExtension">
<col name="CompanyID" type="Int" default="Zero" />
<col name="BranchID" type="Int" />
<col name="DeletedDatabaseRecord" type="Bit" />
<col name="DefaultBranchLocation" type="Int" nullable="true" />
<index name="BranchExtension_PK" clustered="true" primary="true" unique="true">
<col name="CompanyID" />
<col name="BranchID" />
</index>
</table>]]></CDATA>
</Sql>
I created a backfill script (not included).
To handle the projection that is used on the branches page I created the following BranchBAccount extension:
//BranchBAccount Projection Extension
public class BranchBAccountExtension : PXCacheExtension<BranchMaint.BranchBAccount>
{
#region DefaultBranchLocation
public abstract class defaultBranchLocation : IBqlField { }
[PXDBInt(BqlField = typeof(BranchExtension.defaultBranchLocation))]
[PXUIField(DisplayName = "Default Branch Location")]
[PXSelector(typeof(
Search2<FSBranchLocation.branchLocationID,
InnerJoin<Branch, On<Branch.branchID, Equal<FSBranchLocation.branchID>>>,
Where<Branch.branchCD, Equal<Current<BranchMaint.BranchBAccount.branchBranchCD>>>>),
DescriptionField = typeof(FSBranchLocation.descr),
SubstituteKey = typeof(FSBranchLocation.branchLocationCD))]
public virtual int? DefaultBranchLocation { get; set; }
#endregion
}
For the aspx I simply added my extension field to the Branches page (CS102000) as the first field under General Info, MISC SETTINGS (SHARED). You can see how it is placed:
...
<px:PXLayoutRule runat="server" StartGroup="True" GroupCaption="Misc Settings (Shared)" ></px:PXLayoutRule>
<px:PXSelector runat="server" ID="edDefaultBranchLocation" DataField="DefaultBranchLocation" CommitChanges="True" AutoRefresh="True" />
<px:PXFormView ID="CommonSettings" runat="server" DataMember="commonsetup" DataSourceID="ds" RenderStyle="Simple">
...
In my test company I have 3 branches (Branch IDs 1, 2, & 3). I navigate to CS102000 (Branches) and select one of the Branches (we'll say Branch ID 3). The Default Branch Location field I added is present and the selector seems to work as desired (whichever Branch I have selected, only its locations are shown). No error is shown upon selecting a Branch Location. I click the Save button and everything looks okay. That is, until I look at any of the other branch records, they now have the branch default that I selected. All the other data on the screen changes upon changing the Branch. When looking in the database sure enough my extension table has the same DefaultBranchLocation value for Branch 1, 2, and 3. Doing a SQL Trace shows that it is simply running the following:
UPDATE BranchExtension SET [BranchExtension].[DefaultBranchLocation] = #P0 WHERE CompanyID = 2
Note that it isn't filtering on the key fields.
I've never had this problem with an extension table before, so I'm unsure of what I'm doing wrong. My guess would be is that it is related to the extension of the projection, but my field declaration in my extension looks no different that the fields declared on that projection which save properly.
Any help is greatly appreciated. Thank you in advance.
Really your issue is related to that you customize tail of a projection.
I recommend to consider storing your data in a BAccount extension. Then if it is needed you can map a field from BAccount to a Branch extension using PXDBScalarAttribute.
If you strongly need to avoid subselect or you have other requirements you can do the following hack: add BranchID field to branch extension and manually handle this field.
See both examples below
public class BranchMaintExt : PXGraphExtension<BranchMaint>
{
protected void BranchBAccount_BranchID_CommandPreparing(PXCache sender, PXCommandPreparingEventArgs e)
{
if ((e.Operation & PXDBOperation.Command) != PXDBOperation.Select && e.Table != typeof(BranchExtension))
{
e.Cancel = true;
}
else if ((e.Operation & PXDBOperation.Command) == PXDBOperation.Update && e.Value == null && e.Row != null)
{
decimal? ident = PXDatabase.SelectIdentity<PX.Objects.GL.Branch>(typeof(PX.Objects.GL.Branch.branchID).Name);
if (ident != null && ident.Value > 0)
{
sender.SetValue<BranchBAccountExtension.branchID>(e.Row, Convert.ToInt32(ident));
e.Value = ident;
}
}
}
protected void BranchBAccount_BAccountID_CommandPreparing(PXCache sender, PXCommandPreparingEventArgs e)
{
if (((e.Operation & PXDBOperation.Command) == PXDBOperation.Update)
&& sender.GetValue<BranchBAccountExtension.branchID>(e.Row) == null && e.Row != null)
{
decimal? ident = PXDatabase.SelectIdentity<PX.Objects.GL.Branch>(typeof(PX.Objects.GL.Branch.branchID).Name);
if (ident != null && ident.Value > 0)
{
sender.SetValue<BranchBAccountExtension.branchID>(e.Row, Convert.ToInt32(ident));
}
}
}
}
[PXTable(typeof(Branch.branchID), IsOptional = false)]
public class BranchExtension : PXCacheExtension<Branch>
{
#region DefaultBranchLocation
public abstract class defaultBranchLocation : IBqlField { }
[PXDBInt()]
[PXUIField(DisplayName = "Default Branch Location")]
public virtual int? DefaultBranchLocation { get; set; }
#endregion
#region BAccountDefaultBranchLocation
public abstract class bAccountDefaultBranchLocation : IBqlField { }
[PXDBScalar(typeof(Search<BAccountExtension.bAccountDefaultBranchLocation, Where<BAccount.bAccountID, Equal<Branch.bAccountID>>>))]
[PXInt()]
[PXUIField(DisplayName = "Default Branch Location")]
public virtual int? BAccountDefaultBranchLocation { get; set; }
#endregion
}
[PXTable(typeof(BAccount.bAccountID), IsOptional = false)]
public class BAccountExtension : PXCacheExtension<BAccount>
{
#region BAccountDefaultBranchLocation
public abstract class bAccountDefaultBranchLocation : IBqlField { }
[PXDBInt()]
[PXUIField(DisplayName = "Default Branch Location")]
public virtual int? BAccountDefaultBranchLocation { get; set; }
#endregion
}
public class BranchBAccountExtension : PXCacheExtension<BranchMaint.BranchBAccount>
{
#region BranchID
public abstract class branchID : PX.Data.IBqlField
{
}
[PXDBInt(BqlField = typeof(PX.Objects.GL.Branch.branchID))]
[PXUIField(DisplayName = "Branch ID", Visibility = PXUIVisibility.Invisible)]
public virtual int? BranchID { get; set; }
#endregion
#region DefaultBranchLocation
public abstract class defaultBranchLocation : IBqlField { }
[PXDBInt(BqlField = typeof(BranchExtension.defaultBranchLocation))]
[PXUIField(DisplayName = "Default Branch Location")]
public virtual int? DefaultBranchLocation { get; set; }
#endregion
#region BAccountDefaultBranchLocation
public abstract class bAccountDefaultBranchLocation : IBqlField { }
[PXDBInt]
[PXUIField(DisplayName = "Default Branch Location")]
public virtual int? BAccountDefaultBranchLocation { get; set; }
#endregion
}
I try to create Acumatica processing page.
I have following aspx code:
<%# Page Language="C#" MasterPageFile="~/MasterPages/TabView.master" AutoEventWireup="true"
ValidateRequest="false" CodeFile="SM102000.aspx.cs"
Inherits="Page_SM102000" Title="Untitled Page" %>
<%# MasterType VirtualPath="~/MasterPages/TabView.master" %>
<asp:Content ID="cont1" ContentPlaceHolderID="phDS" runat="Server">
<px:PXDataSource ID="ds" runat="server" Visible="True" Width="100%"
PrimaryView="StackOverflowProcess" TypeName="StackOverflowSync.UsrStackOverflowProcess">
</px:PXDataSource>
</asp:Content>
<asp:Content ID="cont2" ContentPlaceHolderID="phF" runat="server">
<px:PXGrid ID="grid" runat="server"
Height="400px"
Width="100%"
AllowPaging="True"
AdjustPageSize="Auto"
AutoAdjustColumns="True"
AllowSearch="True"
SkinID="Inquire"
DataSourceID="ds"
NoteIndicator="true"
TabIndex="3300"
TemporaryFilterCaption="Filter Applied">
<Levels>
<px:PXGridLevel DataMember="StackOverflowProcess">
<Columns>
<px:PXGridColumn DataField="Selected" TextAlign="Center" Width="20px" Type="CheckBox" AllowCheckAll="True">
</px:PXGridColumn>
<px:PXGridColumn DataField="FailInfo" Width="20px">
</px:PXGridColumn>
<px:PXGridColumn DataField="SynchronizationType" Width="80px">
</px:PXGridColumn>
<px:PXGridColumn DataField="LastFullSync" TextAlign="Right" Width="100px">
</px:PXGridColumn>
<px:PXGridColumn DataField="LastRunCmt" Width="80px">
</px:PXGridColumn>
<px:PXGridColumn DataField="LastRunFld" TextAlign="Right" Width="100px">
</px:PXGridColumn>
</Columns>
</px:PXGridLevel>
</Levels>
<AutoSize Container="Window" Enabled="True" MinHeight="400" />
</px:PXGrid>
</asp:Content>
Following DAC class:
using PX.Data;
using System;
namespace StackOverflowSync.DAC
{
[Serializable()]
public class UsrStackOverflowSettingItem: IBqlTable
{
#region SettingID
public abstract class settingID : PX.Data.IBqlField
{
}
protected int _SettingID;
[PXDBIdentity(IsKey = true)]
public virtual int SettingID
{
get
{
return this._SettingID;
}
set
{
this._SettingID = value;
}
}
#endregion
#region FailInfo
public abstract class failInfo : PX.Data.IBqlField
{
}
protected string _FailInfo;
[PXDBString(255, IsUnicode = true)]
[PXDefault()]
[PXUIField(DisplayName = "")]
public virtual string FailInfo
{
get
{
return this._FailInfo;
}
set
{
this._FailInfo = value;
}
}
#endregion
#region Selected
public abstract class selected : IBqlField
{
}
protected bool? _Selected = false;
/// <summary>
/// Indicates whether the record is selected for mass processing.
/// </summary>
[PXBool]
[PXDefault(false)]
[PXUIField(DisplayName = "Selected")]
public bool? Selected
{
get
{
return _Selected;
}
set
{
_Selected = value;
}
}
#endregion
#region SynchronizationType
public abstract class synchronizationType : PX.Data.IBqlField
{
}
protected string _SynchronizationType;
[PXDBString(255, IsUnicode = true)]
[PXDefault()]
[PXUIField(DisplayName = "Synchronization Type")]
public virtual string SynchronizationType
{
get
{
return this._SynchronizationType;
}
set
{
this._SynchronizationType = value;
}
}
#endregion
#region LastFullSync
public abstract class lastFullSync : PX.Data.IBqlField
{
}
protected DateTime? _LastFullSync;
[PXDBDate()]
[PXDefault()]
[PXUIField(DisplayName = "Last Full Sync")]
public virtual DateTime? LastFullSync
{
get
{
return this._LastFullSync;
}
set
{
this._LastFullSync = value;
}
}
#endregion
#region LastRunCmt
public abstract class lastRunCmt : PX.Data.IBqlField
{
}
protected decimal? _LastRunCmt;
[PXDBDecimal(2)]
[PXDefault(TypeCode.Decimal, "0.0")]
[PXUIField(DisplayName = "Last Run: Records Commited")]
public virtual decimal? LastRunCmt
{
get
{
return this._LastRunCmt;
}
set
{
this._LastRunCmt = value;
}
}
#endregion
#region LastRunFld
public abstract class lastRunFld : PX.Data.IBqlField
{
}
protected decimal? _LastRunFld;
[PXDBDecimal(2)]
[PXDefault(TypeCode.Decimal, "0.0")]
[PXUIField(DisplayName = "Last Run: Records Failed")]
public virtual decimal? LastRunFld
{
get
{
return this._LastRunFld;
}
set
{
this._LastRunFld = value;
}
}
#endregion
#region CreatedByID
public abstract class createdByID : PX.Data.IBqlField
{
}
protected Guid? _CreatedByID;
[PXDBCreatedByID()]
public virtual Guid? CreatedByID
{
get
{
return this._CreatedByID;
}
set
{
this._CreatedByID = value;
}
}
#endregion
#region Tstamp
public abstract class tstamp : PX.Data.IBqlField
{
}
protected byte[] _Tstamp;
[PXDBTimestamp()]
public virtual byte[] Tstamp
{
get
{
return this._Tstamp;
}
set
{
this._Tstamp = value;
}
}
#endregion
#region CreatedByScreenID
public abstract class createdByScreenID : PX.Data.IBqlField
{
}
protected string _CreatedByScreenID;
[PXDBCreatedByScreenID()]
public virtual string CreatedByScreenID
{
get
{
return this._CreatedByScreenID;
}
set
{
this._CreatedByScreenID = value;
}
}
#endregion
#region CreatedDateTime
public abstract class createdDateTime : PX.Data.IBqlField
{
}
protected DateTime? _CreatedDateTime;
[PXDBCreatedDateTime()]
public virtual DateTime? CreatedDateTime
{
get
{
return this._CreatedDateTime;
}
set
{
this._CreatedDateTime = value;
}
}
#endregion
#region LastModifiedByID
public abstract class lastModifiedByID : PX.Data.IBqlField
{
}
protected Guid? _LastModifiedByID;
[PXDBLastModifiedByID()]
[PXUIField(DisplayName = "Last Modified By")]
public virtual Guid? LastModifiedByID
{
get
{
return this._LastModifiedByID;
}
set
{
this._LastModifiedByID = value;
}
}
#endregion
#region LastModifiedDateTime
public abstract class lastModifiedDateTime : PX.Data.IBqlField
{
}
protected DateTime? _LastModifiedDateTime;
[PXDBLastModifiedDateTime()]
[PXUIField(DisplayName = "Modified At")]
public virtual DateTime? LastModifiedDateTime
{
get
{
return this._LastModifiedDateTime;
}
set
{
this._LastModifiedDateTime = value;
}
}
#endregion
#region LastModifiedByScreenID
public abstract class lastModifiedByScreenID : PX.Data.IBqlField
{
}
protected string _LastModifiedByScreenID;
[PXDBLastModifiedByScreenID()]
public virtual string LastModifiedByScreenID
{
get
{
return this._LastModifiedByScreenID;
}
set
{
this._LastModifiedByScreenID = value;
}
}
#endregion
}
}
And following graph:
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using PX.Data;
using PX.SM;
using StackOverflowSync.DAC;
namespace StackOverflowSync
{
public class UsrStackOverflowProcess:PXGraph<UsrStackOverflowProcess>
{
[PXFilterable]
public PXProcessing<UsrStackOverflowSettingItem> StackOverflowProcess;
public PXCancel<UsrStackOverflowSettingItem> Cancel;
public UsrStackOverflowProcess()
{
StackOverflowProcess.SetProcessDelegate(Process);
}
public static void Process(List<UsrStackOverflowSettingItem> syncItems)
{
foreach (UsrStackOverflowSettingItem usrStackOverflowPrcSt in syncItems)
{
//
}
}
public override bool IsDirty => false;
}
}
If I compile and open all of it in my Acumatica instance I see three buttons: Process, and Process All and Cancel, which is expected behavior. When I check "Process All" then method Process receives all items. But if I select few items, and press at Process, method Process doesn't receive any ( I've checked in debugger ). What else should I add/remove to my code in order make button Process work properly?
Reported issue is caused by the non-nullable SettingID field. All DAC fields must be of a nullable type. Your custom screen should operate as expected after you change type of the SettingID property and the _SettingID field to Nullable<int> (int?):
[Serializable()]
public class UsrScanCoSettingItem : IBqlTable
{
#region SettingID
public abstract class settingID : PX.Data.IBqlField
{
}
protected int? _SettingID;
[PXDBIdentity(IsKey = true)]
public virtual int? SettingID
{
get
{
return this._SettingID;
}
set
{
this._SettingID = value;
}
}
#endregion
...
}
The problem is that in aspx you have the first column defined as:
<px:PXGridColumn DataField="Seleted" ...
While the name of the column you want is Selected. Looks like it is as easy as that.
I've been where you are and I think to solve it I had to build the list. Try something like the following.
//Invoices.SetProcessDelegate(SendData);
Invoices.SetProcessDelegate(delegate(List<ARInvoice> list)
{
List<ARInvoice> newlist = new List<ARInvoice>(list.Count);
foreach (ARInvoice doc in list)
{
newlist.Add(doc);
}
SendData(newlist);
});