This is my first development after completing the Acumatica Developer training.
I am busy with a user approval on the Batch Payment screen (AP305000). The idea is when the current user opens the Batch Payment, the custom fields default to the current user name. I added 2 custom fields for the approver. There are 2 Approvers.
Batch Payment
public class CABatchExt : PXCacheExtension<PX.Objects.CA.CABatch>
{
#region UsrApprover1
[PXDBString(255, IsFixed = true)]
[PXUIField(DisplayName = "Approver 1")]
[PXDefault(false, PersistingCheck = PXPersistingCheck.Nothing)]
public virtual string UsrApprover1 { get; set; }
public abstract class usrApprover1 : PX.Data.BQL.BqlString.Field<usrApprover1> { }
#endregion
#region UsrApprover2
[PXDBString(255, IsFixed = true)]
[PXUIField(DisplayName = "Approver 2")]
[PXDefault(false, PersistingCheck = PXPersistingCheck.Nothing)]
public virtual string UsrApprover2 { get; set; }
public abstract class usrApprover2 : PX.Data.BQL.BqlString.Field<usrApprover2> { }
#endregion
}
The custom fields are never enabled and I populate them in the RowSelected event:
protected void _(Events.RowSelected<CABatch> e)
{
var row = (CABatch)e.Row;
CABatchExt batchExt = PXCache<CABatch>.GetExtension<CABatchExt>(row);
// disable approver 1 and 2
PXUIFieldAttribute.SetEnabled<CABatchExt.usrApprover1>(e.Cache, e.Row, false);
PXUIFieldAttribute.SetEnabled<CABatchExt.usrApprover2>(e.Cache, e.Row, false);
// get the current logged in user
Users currentUser = PXSelect<Users, Where<Users.username,
Equal<Current<AccessInfo.userName>>, And<Users.isApproved, Equal<True>>>,
OrderBy<Asc<Users.username>>>.Select(Base);
// populate the approver 1 with the current logged in user
if (currentUser != null && batchExt != null && row.Hold == false &&
string.IsNullOrEmpty(batchExt.UsrApprover1) &&
string.IsNullOrEmpty(batchExt.UsrApprover2))
{
batchExt.UsrApprover1 = currentUser.FullName;
}
// populate approver 2 with the current logged in user, it must be different than approver 2
if (currentUser != null && batchExt != null && row.Hold == false &&
!string.IsNullOrEmpty(batchExt.UsrApprover1) &&
string.IsNullOrEmpty(batchExt.UsrApprover2) && batchExt.UsrApprover1 != currentUser.FullName)
//(batchExt.UsrApprover1 != batchExt.UsrApprover2 && batchExt.UsrApprover1 != currentUser.FullName)))
{
batchExt.UsrApprover2 = currentUser.FullName;
}
// set the Release action
if (currentUser != null && batchExt != null && row.Hold == false)
base.Base.Release.SetEnabled(!string.IsNullOrEmpty(batchExt.UsrApprover1) && !string.IsNullOrEmpty(batchExt.UsrApprover2));
}
After the custom fields are updated in the RowSelected the Save button is not enabled. I can't Save the changes. If I make IsDirty = true the Save is enabled but no data is saved to the database. I also did a test to see if it actually writes to the database, if I change the description on the payment and Save the data is saved to the database. If the custom fields are enabled and I type something it saves to the database.
I also tried e.Cache.RaiseFieldUpdated<CABatchExt.usrApprover1>(row, currentUser.FullName); and e.Cache.SetValueExt<CABatchExt.usrApprover1>(row, currentUser.FullName); with same result.
I think the problem is because the field are never enabled and when a user opens the screen no modification takes place and no data is persisted. I need a way of simulating the tabbing out of a field or forcing a field change.
You can try updating the cache like this
this.Base.CABatchDetail.Update(row);
Add this code of your code
You can also try to allow for updates:
this.Base.CABatchDetail.AllowUpdate = true;
Related
I have a customization to the Sales Orders screen, where I've added a user field (non-bound / [PXString] to hold the value of a PO Receipt Nbr. I populate it with the RowSelected event, and I'm trying to launch the Purchase Receipts screen from that field with a PXAction tied to that field's Linked Command:
The Field:
public abstract class usrPOReceiptNbr : BqlString.Field<usrPOReceiptNbr> { }
[PXString(15, IsUnicode = true)]
[PXUIField(DisplayName = "PO Receipt Nbr", Enabled = true)]
public virtual string UsrPOReceiptNbr { get; set; }
The RowSelected event code to populate the field:
var soordershipment = e.Row as SOOrderShipment;
using (new PXConnectionScope())
{
//get the extension
var soordershipmentext = PXCache<SOOrderShipment>.GetExtension<SOOrderShipmentExt>(soordershipment);
//Get the soorder cache...
SOOrder soorder = Base.Document.Current;
if (soorder != null)
{
//Now get the POReceiptLine record:
PXResultset<POReceiptLine> res = PXSelectJoin<POReceiptLine,
InnerJoin<SOOrder,
On<SOOrder.orderNbr, Equal<POReceiptLine.sOOrderNbr>,
And<SOOrder.orderType, Equal<POReceiptLine.sOOrderType>>>>,
Where<SOOrder.orderNbr, Equal<Required<SOOrder.orderNbr>>>,
OrderBy<Desc<POReceiptLine.receiptNbr>>>.Select(Base, soorder.OrderNbr);
foreach (PXResult<POReceiptLine> rec in res)
{
POReceiptLine porl = (POReceiptLine)rec;
soordershipmentext.UsrPOReceiptNbr = porl.ReceiptNbr;
break; //Stop after the first record, since I only want the highest sorted field
}
}
}
The code to launch the Purchase Receipts screen is as follows:
public PXAction<SOOrder> LaunchPurchaseReceipts;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Launch Purchase Receipts", Enabled = true)]
protected virtual IEnumerable launchPurchaseReceipts(PXAdapter adapter)
{
var soorder = (SOOrder)Base.Document.Current;
POReceiptEntry graph = PXGraph.CreateInstance<POReceiptEntry>();
var soordershipment = (SOOrderShipment)Base.shipmentlist.Current;
var soordershipmentext = PXCache<SOOrderShipment>.GetExtension<SOOrderShipmentExt>(soordershipment);
graph.Document.Current = graph.Document.Search<POReceipt.receiptNbr, POReceipt.receiptType>(soordershipmentext.UsrPOReceiptNbr, soordershipment.ShipmentType);
throw new PXRedirectRequiredException(graph, "Purchase Receipts")
{
Mode = PXBaseRedirectException.WindowMode.NewWindow
};
}
The problem is that I continue to get this error when launching the hyperlink on the PO Receipt Nbr field for that screen (it never even gets to the code to launch the screen):
...and here's the error...
I've tried forcing the field to enabled with the RowSelected event, using:
PXUIFieldAttribute.SetEnabled<SOOrderShipmentExt.usrPOReceiptNbr>(e.Cache, null, true);
But that doesn't do anything.
Any ideas?
This issue has been resolved with a suggestion from Brendan (thanks much) by using the RowSelected event to set the method's enabled property to true:
LaunchPurchaseReceipts.SetEnabled(true);
I have a custom action on screen CR304000 - OpportunityMaint in the Quotes tab of the grid view that marks a field called IsPrimary in the CRQuote DAC as true for the current record in the Quotes view. These project Quotes are associated with the current opportunity as well as with a related PMQoute in the PMQuoteMaint BLC. The PMQuoteMaint BLC has a view called Activties that has all the CRActivities associated with the PMQuote. I created a custom field in the CRActivity called IsPrimary and added it to the Activities view in the PMQuoteMaint BLC grid.
My goal was to override the Action in the OpportunityMaint to update the IsPrimary field in CRActivity to true or false depending on what the Action in OpportunityMaint is toggling. However, my IsPrimary field in PMQuoteMaint is not toggling. My code attempts to get Current Quote OpportunityMain and then create a PMQuoteMaint graph and set the Current record. Then iterate though Activies view and set the IsPrimary field accordingly. Like I said, not having success because I'm not sure that my code is successfully retrieving the correct Activities.
There might be a better way to access CRActivity associated with a PMQuote, but I'm not sure. Any help would be appreciated. Here is code:
public virtual IEnumerable PrimaryQuote(PXAdapter adapter)
{
foreach (CROpportunity opp in adapter.Get())
{
if (Quotes.Current?.IsPrimary != true)
{
var selectExistingPrimary = new PXSelect<CRQuote, Where<CRQuote.quoteID,
Equal<Required<CRQuote.quoteID>>>>(this);
CRQuote primary = selectExistingPrimary.Select(opp.DefQuoteID);
if (primary != null && primary.QuoteID != Quotes.Current.QuoteID && primary.Status ==
PM.PMQuoteStatusAttribute.Closed)
{
throw new PXException(PM.Messages.QuoteIsClosed, opp.OpportunityID,
primary.QuoteNbr);
}
var quoteID = Quotes.Current.QuoteID;
var opportunityID = this.Opportunity.Current.OpportunityID;
this.Persist();
PXDatabase.Update<Standalone.CROpportunity>(
new PXDataFieldAssign<Standalone.CROpportunity.defQuoteID>(quoteID),
new PXDataFieldRestrict<Standalone.CROpportunity.opportunityID>(PXDbType.VarChar,
255, opportunityID, PXComp.EQ)
);
this.Cancel.Press();
CROpportunity rec = this.Opportunity.Search<CROpportunity.opportunityID>
(opportunityID);
yield return rec;
}
yield return opp;
}
``` My OverRide
public PXAction<CROpportunity> primaryQuote;
[PXUIField(DisplayName = Messages.MarkAsPrimary)]
[PXButton]
public virtual IEnumerable PrimaryQuote(PXAdapter adapter)
{
// this is currently selected record in quotes grid
var currQuoteNbr = Base.Quotes.Current.QuoteNbr;
bool isPrimary2;
foreach (CRQuote quote in Base.Quotes.Select())
{
var quoteNbr = quote.QuoteNbr;
if(quoteNbr.Trim() == currQuoteNbr.Trim())
{
isPrimary2 = true;
}
else
{
isPrimary2 = false;
}
PXTrace.WriteInformation(string.Format("Quote: {0} Value:
{1}",quoteNbr.ToString(),isPrimary2.ToString()));
var PMQuoteMaintGraph = PXGraph.CreateInstance<PMQuoteMaint>();
PMQuoteMaintGraph.Quote.Current = PMQuoteMaintGraph.Quote.Search<PMQuote.quoteNbr>
(quoteNbr.Trim()); // this is the current quote
foreach (CRActivity activity in PMQuoteMaintGraph.Activities.Select())
{
CRActivityExt itemExt = PXCache<CRActivity>.GetExtension<CRActivityExt>(activity);
itemExt.UsrPrimary = isPrimary2;
PMQuoteMaintGraph.Activities.Cache.Persist(PXDBOperation.Update);
PXDatabase.Update<CRActivity>(new PXDataFieldAssign<CRActivityExt.usrPrimary>
(isPrimary2));
}
}
return Base.primaryQuote.Press(adapter);
}
I have a customization to the Release Time Activities screen (EP507020) where I add a user field. This user field will contain the result of fetching the Appointment status from the Appointments screen (FS300200) based on the Appointment ID that I've also added to the Release Time Activities screen grid.
This was done so that the process grid could be filtered for appointment status that were a certain value. The Appointment Status User field I've added contains the same attributes that the Status field contains on the Appointments screen, with the Cache extension looking as follows:
#region UsrApptStatus
public abstract class usrApptStatus : IBqlField
{
}
[PXDBString(1)]
[FSAppointment.status.ListAtrribute]
[PXUIField(DisplayName = "Appt Status",Enabled = false)]
public virtual string UsrApptStatus { get; set; }
#endregion
This works fine when I fetch the status as follows in a Graph extension:
protected virtual void EPActivityApprove_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
var epactivityapprove = (EPActivityApprove)e.Row;
if (epactivityapprove != null)
{
FSxPMTimeActivity rowExt = epactivityapprove.GetExtension<FSxPMTimeActivity>();
if (rowExt != null)
{
var appointmentID = rowExt.AppointmentID;
var fsappt = (FSAppointment)PXSelect<FSAppointment,
Where<FSAppointment.appointmentID, Equal<Required<FSAppointment.appointmentID>>>>.Select(Base, appointmentID);
var epactivityapproveext = PXCache<EPActivityApprove>.GetExtension<EPActivityApproveExt>(epactivityapprove);
epactivityapproveext.UsrApptStatus = fsappt.Status;
}
}
}
The problem is that when I go to filter the Status column, no matter what I choose from the list of options, it clears all rows. I have no idea why this wouldn't work, but I'm sure I'm missing something.
Grid before filtering:
Filter:
Grid after filter:
It seems to me that changing the value in the RowUpdated event is interfering with the filter. If you wrote both extensions, it would help to have both custom fields in the same extension and use the PXFormula attribute to set the value of your status based on the AppointmentID field. This way you wouldn't have to rely on the event:
#region UsrApptStatus
public abstract class usrApptStatus : IBqlField
{
}
[PXDBString(1)]
[FSAppointment.status.ListAtrribute]
[PXFormula(typeof(Selector<appointmentID, FSAppointment.status>))]
[PXUIField(DisplayName = "Appt Status",Enabled = false)]
public virtual string UsrApptStatus { get; set; }
#endregion
am generating a pop on one new button click in stock Items screen, inside popup have two buttons, user select some data from fields in the popup and then click on ok, then inventoryId should be formed with some special characters and then it should display in InventoryID field. I can form the InventoryID but unable to display it in InventoryID field.
[PXButton]
[PXUIField(DisplayName = "Generate")]
public virtual void GenerateInv()
{
InventoryItemExt ext = Base.Item.Cache.GetExtension<InventoryItemExt>(Base.Item.Current);
Base.Item.Current.InventoryCD = ext.UsrInvId;
Base.Item.Cache.Insert(Base.Item.Current);
}
I had this issue before,
and the following code was provided by acumatica. you may try the same.
here in the below code, inventoryCD contains the value, i wanted to set.
InventoryItem item = PXCache<InventoryItem>.CreateCopy(Base.Item.Current);
OrderedDictionary keys = new OrderedDictionary(StringComparer.OrdinalIgnoreCase)
{
{
typeof(InventoryItem.inventoryCD).Name,
adapter.View.Cache.GetValue(adapter.View.Cache.Current,
typeof(InventoryItem.inventoryCD).Name)
}
};
OrderedDictionary vals = new OrderedDictionary(StringComparer.OrdinalIgnoreCase)
{
{
typeof(InventoryItem.inventoryCD).Name, inventoryCD
}
};
adapter.View.Cache.Update(keys, vals);
if (adapter.Searches != null && adapter.Searches.Length > 0)
{
adapter.Searches[0] = inventoryCD;
}
return adapter.Get();
Also make sure your function have the correct input and the return type
IEnumerable GenerateInv(PXAdapter adapter)
I've been having this problem on Acumatica extension for days now and can't seem to figure out the resolution. I've added an action on the Inventory Lookup Dialog of Sales Order screen (see screenshot below), the action is task to update the QtySelected to 1 and also to update my added Field which is the Brand to "testBrand". It is an extension of the SOSitesStatusSelected table, but whenever i clicked on the action, it only updates QtySelected and not my added Field Brand.
You may refer to my code below, thank you and I appreciate all the help.
//DAC
#region UsrBrand
[PXUIField(DisplayName = "Brand", Visible = true, Enabled = true)]
public virtual string UsrBrand{get;set;}
public abstract class usrBrand : IBqlField{}
#endregion
//BLC
public PXAction<PX.Objects.SO.SOOrder> updateAttributes;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Update Attributes")]
protected void UpdateAttributes()
{
this.Base.sitestatus.AllowInsert= true;
this.Base.sitestatus.AllowUpdate= true;
foreach (SOSiteStatusSelected line in this.Base.sitestatus.Select())
{
line.QtySelected = 1;
this.Base.sitestatus.Update(line);
SOSiteStatusSelectedExt rowExt = this.Base.sitestatus.Cache.GetExtension<SOSiteStatusSelectedExt>(line);
rowExt.UsrBrand = "testBrand";
this.Base.sitestatus.Cache.Update(rowExt);
}
}
In this case your extension SOSiteStatusSelectedExt is not a separate item. It's a part of the base record actually. So you don't need to update it separately.
line.QtySelected = 1;
SOSiteStatusSelectedExt rowExt = this.Base.sitestatus.Cache.GetExtension<SOSiteStatusSelectedExt>(line);
rowExt.UsrBrand = "testBrand";
this.Base.sitestatus.Update(line);