Issue with Process Delegate after implementing a non-persistent DAC - acumatica

I am struggling with getting my Process Delegate to wire up correctly after implementing the advice pointed out in this ticket Implementing a DAC with no persisted fields. The processing page for the most part now behaves as we need. The records autoload based off of data pulled in via a ReST web service and we are not persisting any data to the ERP until the processing buttons are used. The issue I am having now is the SetProcessDeligate method is now not doing anything when I hit the process buttons. When I wire the older code into place that has one persistent field and requires a user to hit a load button the Process and Process All buttons work as expected.
I have created this screencast to walk through and give visual context to the issue. https://www.dropbox.com/s/j8vnp8p3556nj1e/issue%20with%20the%20PXProcessing%20page%20not%20wiring%20into%20the%20event%20handler%202019-01-03_12-57-50.mp4?dl=0
As always I am very grateful for any help. Thank you
Robert
//This is how my Graph is defined now.
public class CtpPaymentProcess : PXGraph<CtpPaymentProcess>
{
//public PXAction<CtpPayment> checkForC2PPayments;
public PXSetup<CtpSetup> setup;
public PXProcessing<CtpPayment> Payments;
public QueryPaymentsResponseViewModel paymentsFromCtpServer { get; internal set; }
public IEnumerable payments()
{
paymentsFromCtpServer = CtpAcumatica.CheckForAllNewPayments(100);
PXTrace.WriteInformation("Processing " + (paymentsFromCtpServer.Payments.Count) + " paymentsFromCtpServer");
if (paymentsFromCtpServer.Payments != null)
{
// Loop processing each payment returned from the gateway, storing the
// information into non persisted cache.
foreach (var payment in paymentsFromCtpServer.Payments)
{
if (!payment.IsMarkedRetrieved)
{
yield return BuildCtpPayment(payment);
}
}
}
}
private CtpPayment BuildCtpPayment(PaymentViewModel payment)
{
var customer = (Customer)PXSelect<Customer,
Where<Customer.bAccountID, Equal<Required<Customer.bAccountID>>>>
.Select(this, payment.CustomerId).FirstOrDefault();
//Todo: add assertion that will assert payment is made to only matching company payment.CompanyId
//Todo: find out if we need to handel Bank Account Types differently payment.BankAccountType
DateTime.TryParse(payment.Date, out var payDate);
return new CtpPayment
{
CustomerID = int.Parse(payment.CustomerId),
Customer = $"{customer.AcctCD}:{customer.AcctName}",
Amount = payment.Amount,
Description = $"Payment:{payment.Id}",
Id = payment.Id,
ApsTransactionID = payment.ApsTransactionId,
Currency = payment.Currency,
PaymentDate = payDate,
Invoices = InvoicesAsString(payment)
};
}
private static string InvoicesAsString(PaymentViewModel payment)
{
var Invoices = payment.Invoices.Select(x => x.InvoiceId);
StringBuilder stringBuilder = new StringBuilder();
foreach (string inv in Invoices)
{
stringBuilder.AppendFormat("{0} ", inv);
}
string result = stringBuilder.ToString();
if (result.Length > 100) result = result.Substring(0, 96) + "...";
return result;
}
private CtpAcumatica _ctpAcumatica;
public CtpAcumatica CtpAcumatica
{
get
{
if (_ctpAcumatica == null)
{
var graph = PXGraph.CreateInstance<PXGraph>();
_ctpAcumatica = new CtpAcumatica(setup.Current.CtpUrl,
setup.Current.CtpApiKey,
"NoLongerNeeded", //todo: refactor this out.
"NoLongerNeeded", //todo: refactor this out.
graph);
}
return _ctpAcumatica;
}
}
public CtpPaymentProcess()
{
Payments.SetProcessCaption("Process Payments");
Payments.SetProcessAllCaption("Process All Payments");
Payments.SetProcessDelegate<CtpPaymentProcess>(
delegate (CtpPaymentProcess graph, CtpPayment payment)
{
graph.Clear();
graph.ProcessPayment(payment, true);
}
);
//Alternate attempt proved un-successful
//Payments.SetProcessDelegate(PaymentGenerationDelegate);
}
/* implemented as a test. will remove from production code
private void PaymentGenerationDelegate(List<CtpPayment> list)
{
foreach (var payment in list)
{
ProcessPayment(payment, true);
}
}
*/
private void ProcessPayment(CtpPayment payment, bool massProcess)
{
PXTrace.WriteInformation($"Processing {payment}");
//for now we will only write to the trace window.
//Stopwatch stopWatch = new Stopwatch();
//stopWatch.Start();
//createPayment(payment);
//stopWatch.Stop();
//PXTrace.WriteInformation($"Payment {payment.ApsTransactionID} finished in {stopWatch.Elapsed.TotalSeconds} Seconds");
}
//todo: unfinished
private void createPayment(CtpPayment paymentData)
{
var paymentFromCtp = CtpAcumatica.GetPaymentRecord(long.Parse(paymentData.Id));
ARPaymentEntry arPaymentEntry = PXGraph.CreateInstance<ARPaymentEntry>();
ARPayment payment = new ARPayment
{
CustomerID = int.Parse(paymentFromCtp.CustomerId),
CuryOrigDocAmt = paymentData.Amount
};
arPaymentEntry.CurrentDocument.Insert(payment);
foreach (var invoice in paymentFromCtp.Invoices)
{
ARAdjust adj = new ARAdjust
{
AdjdRefNbr = invoice.InvoiceId,
CuryAdjgAmt = invoice.Amount
};
arPaymentEntry.Adjustments.Insert(adj);
}
arPaymentEntry.Persist();
PXTrace.WriteInformation(arPaymentEntry.ToString());
}
}
//This is the DAC definition.
[Serializable]
[PXPrimaryGraph(typeof(CtpPaymentProcess))]
//[PXNonInstantiatedExtension] this looked close
//to what we are looking for but experimenting
//with it did not yield desired results.
public class CtpPayment : IBqlTable
{
#region Selected
public abstract class selected : IBqlField{ }
[PXBool]
[PXUIField(DisplayName = "Selected")]
public virtual bool? Selected { get; set; }
#endregion
public abstract class id : IBqlField { }
//todo: find out what size we need 50 is just a guess.
//[PXString(50, IsKey = true)] //We are able to get this to work only if
//we have at least one persisting field.
//we can live with this but would prefer to
//have the whole class as non-persistent
[PXString(50,IsKey = true)] //having only non persisting attributes will result in a
//Incorrect syntax near the keyword 'FROM'. error.
[PXUIField(DisplayName = "Click To Pay Id")]
public virtual string Id { get; set; }
public abstract class customer : IBqlField { }
[PXString(100)]
[PXUIField(DisplayName = "Customer")]
public virtual string Customer { get; set; }
public abstract class description : IBqlField {}
[PXString(200)]
[PXUIField(DisplayName = "Payment Description")]
public virtual string Description { get; set; }
public abstract class amount : IBqlField { }
[PXDecimal(2)]
[PXUIField(DisplayName = "Payment Amount")]
public virtual decimal? Amount { get; set; }
public abstract class customerId : IBqlField { }
[PXInt]
[PXUIField(DisplayName = "Customer ID")]
//todo: decorate this with the needed attributes to display friendly key instead of int.
public virtual int? CustomerID { get; set; }
public abstract class apsTransactionID : IBqlField { }
[PXString]
[PXUIField(DisplayName = "Transaction ID")]
public virtual string ApsTransactionID { get; set; }
public abstract class currency : IBqlField { }
[PXString(10)]//todo: determine best size. 10 is a guess.
[PXUIField(DisplayName = "Currency")]
public virtual string Currency { get; set; }
public abstract class paymentDate : IBqlField { }
[PXDate]
[PXUIField(DisplayName = "Payment Date")]
public virtual DateTime? PaymentDate { get; set; }
public abstract class invoices : IBqlField { }
[PXString(100)]
[PXUIField(DisplayName = "Invoices")]
public virtual string Invoices { get; set; }
}

Thanks, HB_Acumatica for the direction on this.
Changing my code to use the following got to the end result I needed. I Hope this helps someone in the future.
//old implementation that would not render any result when the process buttons where clicked.
//public IEnumerable payments()
//{
// paymentsFromCtpServer = CtpAcumatica.CheckForAllNewPayments(100);
// PXTrace.WriteInformation("Processing " + (paymentsFromCtpServer.Payments.Count) + " paymentsFromCtpServer");
// if (paymentsFromCtpServer.Payments != null)
// {
// // Loop processing each payment returned from the gateway, storing the
// // information into non persisted cache.
// foreach (var payment in paymentsFromCtpServer.Payments)
// {
// if (!payment.IsMarkedRetrieved)
// {
// yield return BuildCtpPayment(payment);
// }
// }
// }
//}
public IEnumerable payments()
{
paymentsFromCtpServer = CtpAcumatica.CheckForAllNewPayments(100);
PXCache cache = Caches[typeof(CtpPayment)];
cache.AllowInsert = false;
cache.AllowUpdate = false;
if (cache.Current == null)
{
foreach (var payment in paymentsFromCtpServer.Payments)
{
if (!payment.IsMarkedRetrieved)
{
cache.SetStatus(BuildCtpPayment(payment), PXEntryStatus.Held);
}
}
}
return Payments.Cache.Cached;
}

Related

Acumatica - Revision

We have 2 DAC - Master and Child
Master DAC
#region MasterID
public abstract class masterID:PX.Data.BQL.BqlInt.Field<masterID> { }
protected int? _MasterID;
[PXDBIdentity()]
[PXUIField(Visibility = PXUIVisibility.Invisible)]
[PXReferentialIntegrityCheck]
public virtual int? MasterID
{
get {return this._MasterID;}
set {this._MasterID = value;}
}
#endregion
#region MasterCD
public abstract class masterRoutingCD:PX.Data.BQL.BqlString.Field<masterCD> { }
protected string _MasterRoutingCD;
[BomID(DisplayName = "Master #", IsKey = true, Required = true,
Visibility = PXUIVisibility.SelectorVisible)]
[PXDefault]
[Rev.Key(typeof(Setup.pMMasterNumberSequenceID),
typeof(Master.masterCD),
typeof(Master.revisionNo),
typeof(Master.masterCD),
typeof(Master.revisionNo)
)]
public virtual string MasterCD
{
get {return this._MasterCD;}
set {this._MasterCD = value;}
}
#endregion
#region RevisionNo
public abstract class revisionNo:PX.Data.IBqlField { }
protected string _RevisionNo;
[RevisionIDField(IsKey = true, Visibility = PXUIVisibility.SelectorVisible,
Required = true)]
[PXDefault(typeof(Master.defaultRevisionNo),
PersistingCheck = PXPersistingCheck.Nothing)]
[Rev.ID(typeof(Master.defaultRevisionNo),
typeof(Master.masterCD),
typeof(Master.revisionNo),
typeof(Master.revisionNo),
typeof(Master.description),
typeof(Master.fromDate),
typeof(Master.toDate))]
public virtual string RevisionNo
{
get {return this._RevisionNo;}
set {this._RevisionNo = value;}
}
#endregion
Child DAC
public abstract class childID:PX.Data.BQL.BqlInt.Field<childID> { }
protected int? _ChildID;
[PXDBIdentity()]
//[PXReferentialIntegrityCheck]
public virtual int? ChildID
{
get {return this._ChildID;}
set {this._ChildID = value;}
}
#endregion
#region MasterID
public abstract class masterID:PX.Data.BQL.BqlInt.Field<masterID> { }
protected int? _MasterID;
[PXDBInt()]
[PXDBDefault(typeof(Master.masterID))]
[PXParent(typeof(Select<Master, Where<Master.masterRoutingCD, Equal<Current<masterCD>>,
And<Master.revisionNo, Equal<Current<revisionNo>>>>>))]
public virtual int? MasterID
{
get {return _MasterID;}
set {_MasterID = value;}
}
#endregion MasterID
#region MasterCD
public abstract class masterCD:PX.Data.BQL.BqlString.Field<masterCD> { }
protected string _MasterCD;
[PXDBDefault(typeof(Master.masterCD))]
[PXDBString(IsKey = true, IsUnicode = true)]
public virtual string MasterCD
{
get {return this._MasterCD;}
set {this._MasterCD = value;}
}
#endregion
#region Revision
public abstract class revisionNo:PX.Data.BQL.BqlString.Field<revisionNo> {}
[PXDBString(15, IsKey = true, IsUnicode = true)]
[PXDBDefault(typeof(Master.revisionNo))]
public virtual string RevisionNo { get; set; }
#endregion Revision
public abstract class stepsID:PX.Data.BQL.BqlInt.Field<stepsID> { }
[OperationCDField(IsKey =true, DisplayName = "Steps ID",
Visibility = PXUIVisibility.SelectorVisible)]
[PXDefault(PersistingCheck = PXPersistingCheck.NullOrBlank)]
//[PXUIField(DisplayName = "Process Steps ID")]
public virtual string StepsID { get; set; }
Graph - MasterMaint
public class MasterMaint:PXRevisionableGraph<MasterMaint, Master,
Master.masterCD, Master.revisionNo>
{
public PXSelect<Child, Where<Child.masterCD, Equal<Current<Master.masterCD>>,
And<Child.revisionNo, Equal<Current<Master.revisionNo>>>>> ChildRecords;
#region Override
public override bool CanClipboardCopyPaste()
{
return false;
}
public override bool CanCreateNewRevision(MasterMaint fromGraph, MasterMaint toGraph,
string keyValue, string revisionValue, out string error)
{
// Always returns true as new revisions can be created at any time
error = string.Empty;
return true;
}
public override void CopyRevision(MasterMaint fromGraph, MasterMaint toGraph,
string keyValue, string revisionValue)
{
if(toGraph?.Documents?.Current == null || fromGraph?.Documents?.Current == null)
{
// api calls should create new revs on their own - this causes issues
// when calling from api so we need to turn the copy rev logic off
return;
}
toGraph.Documents.Cache.SetDefaultExt<EWPMMasterRouting.status>
(toGraph.Documents.Current);
if(SkipAutoCreateNewRevision())
{
return;
}
CopyChildRecords(fromGraph.Documents.Current.MasterRoutingCD,
fromGraph.Documents.Current.RevisionNo, toGraph.Documents.Current.MasterID,
keyValue, revisionValue, false);
}
internal virtual void CopyChildRecords(string sourceID, string sourceRevisionNo,
int? newMasterID, string newMasterCD, string newRevisionID, bool copyNotes)
{
foreach(Child fromRow in PXSelect<Child,
Where<Child.masterCD, Equal<Required<Child.masterCD>>,
And<Child.revisionNo, Equal<Required<Child.revisionNo>>>>>
.Select(this, sourceID, sourceRevisionNo))
{
var toRow = PXCache<Child>.CreateCopy(fromRow);
toRow.MasterID = newMasterRoutingID;
toRow.ChildID = null;
toRow.MasterCD = newMasterCD;
toRow.RevisionNo= newRevisionID;
toRow = ChildRecords.Insert(toRow);
}
}
#endregion
}
Issue - When the value is changed in the Revision the record is displayed with new revision number keeping the CD fields as for previous revision and all the child.
That is all correct, But when the record is saved, there is error "Another process has updated the Record, your changes will be lost"
Why there is a Error
In Acuamtica we have NoteID column unique across the system If you try to create a record with duplicating NoteID field value you'll get "Another process has updated the record" exception because it consider that you are updating the same record.
In you case when you copy revision you do not reset the NoteID value for the record so you actually try to insert another record with the same value.
You'll need to add the following line to CopyRevision method
toGraph.Documents.Cache.SetDefaultExt<EWPMMasterRouting.noteID>(toGraph.Documents.Current);

Calculate total Amount Paid on Prepare Payments

Good day
Page: AP503000
Build 19.104.0024
I am trying to calculate the Total Amount paid for all recorded in the APAdjust grid on the bottom of the Prepare Payments. This total I want to show on top in the Form area.
DAC
namespace PX.Objects.AP
{
public class PayBillsFilterExt : PXCacheExtension<PX.Objects.AP.PayBillsFilter>
{
#region UsrTotalAmountForPayment
[PXDecimal]
[PXUIField(DisplayName = "Total Amount For Payment")]
public virtual Decimal? UsrTotalAmountForPayment { get; set; }
public abstract class usrTotalAmountForPayment :
PX.Data.BQL.BqlDecimal.Field<usrTotalAmountForPayment> { }
#endregion
}
}
My first attempt I tried to add an unbound formula to my DAC for the below to work you will also need to add a new class decimal_0
namespace PX.Objects.AP
{
public class PayBillsFilterExt : PXCacheExtension<PX.Objects.AP.PayBillsFilter>
{
#region UsrTotalAmountForPayment
[PXDecimal]
[PXUIField(DisplayName = "Total Amount For Payment")]
// add this to the DAC
[PXUnboundFormula(typeof(Where<APAdjust.curyAdjdAmt,Greater<decimal_0>>)
,typeof(SumCalc<APAdjust.curyAdjdAmt>))]
public virtual Decimal? UsrTotalAmountForPayment { get; set; }
public abstract class usrTotalAmountForPayment :
PX.Data.BQL.BqlDecimal.Field<usrTotalAmountForPayment> { }
#endregion
//Class decimal_0
public class decimal_0 : Constant<decimal>
{
public decimal_0()
: base(0)
{ }
}
}
}
I have also tried adding an event to do the calculation:
namespace PX.Objects.AP
{
public class APPayBills_Extension : PXGraphExtension<APPayBills>
{
#region Event Handlers
protected void APAdjust_RowInserted(PXCache cache, PXRowInsertedEventArgs e)
{
var row = (APAdjust)e.Row;
PayBillsFilter filter = this.Base.Filter.Current;
PayBillsFilterExt FilExt = PXCache<PayBillsFilter>.GetExtension<PayBillsFilterExt>(filter);
if (filter != null)
{
FilExt.UsrTotalAmountForPayment += row.CuryAdjdAmt;
}
}
}
}
For accurate results I recommend you sum all the records at the same time.
You can use the DataView.Select method to iterate all records.
public void PayBillsFilter_UsrTotalAmountForPayment_FieldSelecting(PXCache sender, PXFieldSelectingEventArgs e)
{
decimal total = 0;
foreach (APAdjust adjustment in this.Base.APDocumentList.Select())
{
total += (adjustment.CuryAdjdAmt != null ? adjustment.CuryAdjdAmt.Value : 0M);
}
e.ReturnValue = total;
}

APRegisterExt not saving data on APInvoiceEntry

Build 18.203.0006
Page: AP301000
Good day, I have extended the APRegister Class by adding 2 new checkbox fields. I want to iterate through al the APTran transactions and look for suIDs that start with FBL and GAS. If I find them the new tick boxes should tick.
Currently, the fields(tick boxes) do not save to the database. I am not sure how to tell Acumatica the APRegisterExt has updated.
APInvoiceEntry_Extension:
namespace PX.Objects.AP
{
public class APRegisterExt : PXCacheExtension<PX.Objects.AP.APRegister>
{
#region UsrGroupAEmail
[PXDBBool]
[PXUIField(DisplayName="GroupA Email")]
public virtual bool? UsrGroupAEmail { get; set; }
public abstract class usrGroupAEmail : IBqlField { }
#endregion
#region UsrGroupBEmail
[PXDBBool]
[PXUIField(DisplayName="GroupB Email")]
public virtual bool? UsrGroupBEmail { get; set; }
public abstract class usrGroupBEmail : IBqlField { }
#endregion
}
}
APInvoiceEntry_Extension:
namespace PX.Objects.AP
{
public class APInvoiceEntry_Extension : PXGraphExtension<APInvoiceEntry>
{
#region Event Handlers
protected void APInvoice_RowSelected(PXCache cache, PXRowSelectedEventArgs e)
{
APInvoice invoice = e.Row as APInvoice;
if (invoice == null) return;
var apRX = invoice.GetExtension<APRegisterExt>();
PXResultset<APTran> Tlist = PXSelectJoin<APTran,
LeftJoin<POReceiptLine,
On<POReceiptLine.receiptNbr, Equal<APTran.receiptNbr>,
And<POReceiptLine.lineNbr, Equal<APTran.receiptLineNbr>>>>,
Where<
APTran.tranType, Equal<Current<APInvoice.docType>>,
And<APTran.refNbr, Equal<Current<APInvoice.refNbr>>>>,
OrderBy<
Asc<APTran.tranType,
Asc<APTran.refNbr,
Asc<APTran.lineNbr>>>>>.Select(Base);
apRX.UsrGroupBEmail = false;
apRX.UsrGroupAEmail = false;
foreach (APTran item in Tlist)
{
if (item.SubID.Value.ToString().StartsWith("FBL") || item.SubID.Value.ToString().StartsWith("GAS"))
{
apRX.UsrGroupBEmail = true;
cache.SetValue<APRegisterExt.usrGroupBEmail>(e.Row, true);
}
else
{
apRX.UsrGroupAEmail = true;
}
}
}
#endregion
}
}
Can someone please show me the correct way of saving the data to the new tick boxes so that cache updates.
Consider moving the logic to APRegister_RowPersisting.
Importantly, APTran.subID is an Int dataType.
Read instead the Sub table/DAC during a For Loop of
Base.Transactions.Select() to detect SubCD startsWith FBL or GAS.
foreach(APTran item in Base.Transaction.Select())
{
Sub sub = PXSelect<Sub,
Where<Sub.subID, Equal<Required<Sub.subID>>>>
.Select(graph, item.SubID);
if (item.SubCD.StartsWith("FBL") ||
item.SubCD.StartsWith("GAS"))
{
apRX.UsrGroupBEmail = true;
}
else
{
apRX.UsrGroupAEmail = true;
}
}
To be complete, you may also need to reset both flags during APTran_SubID_FieldUpdated regardless of the changed value:
protected void APTran_SubID_FieldUpdated(PXCache sender,
PXFieldUpdatedEventArgs e, PXFieldUpdated del)
{
del?.Invoke(sender,e);
var apRX = Base.Document.Current.GetExtension<APRegisterExt>();
apRX.UsrGroupBEmail = false;
apRX.UsrGroupAEmail = false;
}

Acumatica Processing Screen Updating ARTran Custom Field Needs To Also Update Custom Table field

We have a custom processing screen that is updating a custom field called UsrDateNotified in the ARTran table where the UsrDateNotified is prior to the RevisionDateReceived in a custom table ItemBaseDocument. We also need to update the UsrDateNotified field in table ItemBaseDocument which is linked to the InventoryID in ARTran. Our current code below validates for updating the ARTran table, but we are struggling with how to also update the related ItemBaseDocument for the selected ARTran records. What is the right approach for this scenario?
using System;
using System.Collections;
using System.Linq;
using PX.Data;
using PX.SM;
using PX.Objects.AR;
using PX.Objects.CR;
using PX.Objects.IN;
namespace DocCenter
{
public class UpdateLastNotified : PXGraph<UpdateLastNotified>
{
public PXFilter<UpdateLastNotifiedFilter> MasterView;
public PXCancel<UpdateLastNotifiedFilter> Cancel;
[PXFilterable]
public PXSelect<ARTran> DetailsView;
public UpdateLastNotified()
{
Cancel.SetCaption("Clear Filter");
this.DetailsView.Cache.AllowInsert = false;
this.DetailsView.Cache.AllowDelete = false;
this.DetailsView.Cache.AllowUpdate = true;
}
protected virtual IEnumerable detailsView()
{
UpdateLastNotifiedFilter filter = MasterView.Current as UpdateLastNotifiedFilter;
PXSelectBase<ARTran> cmd = new PXSelectJoinOrderBy<ARTran,
InnerJoin<InventoryItem, On<ARTran.inventoryID, Equal <InventoryItem.inventoryID>>,
InnerJoin<ItemBaseDocument, On<InventoryItemExt.usrDocumentNumber, Equal<ItemBaseDocument.baseDocumentCode>>,
InnerJoin<Contact, On<ARTranExt.usrContactID, Equal<Contact.contactID>>>>>,
OrderBy<Asc<ARTran.tranDate>>>(this);
cmd.WhereAnd<Where<ContactExt.usrNotificationPriority,
Equal<Current<UpdateLastNotifiedFilter.notificationPriority>>>>();
cmd.WhereAnd<Where<ARTranExt.usrDateNotified,
Less<ItemBaseDocument.revisionDateReceived>>>();
if (filter.BaseDocumentCode != null)
{
cmd.WhereAnd<Where<InventoryItemExt.usrDocumentNumber,
Equal<Current<UpdateLastNotifiedFilter.baseDocumentCode>>>>();
}
return cmd.Select();
}
public PXAction<UpdateLastNotifiedFilter> Process;
[PXProcessButton]
[PXButton(CommitChanges=true)]
[PXUIField(DisplayName = "Process")]
protected virtual IEnumerable process(PXAdapter adapter)
{
PXLongOperation.StartOperation(this, delegate()
{
foreach(ARTran tran in DetailsView.Select())
{
if (tran.Selected==true)
{
ARTranExt tranExt = tran.GetExtension<ARTranExt>();
ARInvoiceEntry tranEntry = new ARInvoiceEntry();
tranExt.UsrDateNotified = MasterView.Current.DateNotified;
tranEntry.Transactions.Update(tran);
tranEntry.Save.PressButton();
}
}
}
);
return adapter.Get();
}
[Serializable]
public class UpdateLastNotifiedFilter : IBqlTable
{
public static class NotificationPriority
{
public const string None = "N";
public const string Alert = "A";
public const string Express = "E";
public const string Shipment = "P";
public const string Subscription = "S";
}
#region NotificationPriority
public abstract class notificationPriority : PX.Data.IBqlField
{
}
[PXDBString(1, IsFixed = true)]
[PXDefault(NotificationPriority.None)]
[PXUIField(DisplayName = "Notification Type")]
[PXStringList(
new string[]
{
NotificationPriority.None,
NotificationPriority.Alert,
NotificationPriority.Express,
NotificationPriority.Shipment,
NotificationPriority.Subscription
},
new string[]
{
"None",
"Alert",
"Express",
"Shipment",
"Subscription"
})]
#endregion
#region BaseDocumentID
public abstract class baseDocumentCode : PX.Data.IBqlField
{
}
[PXString(50)]
[PXUIField(DisplayName="Document Number")]
[PXSelector(typeof(DocCenter.ItemBaseDocument.baseDocumentCode))]
public virtual String BaseDocumentCode
{
get;
set;
}
#endregion
#region DateNotified
public abstract class dateNotified : PX.Data.IBqlField
{
}
[PXDBDate()]
[PXDefault(typeof(AccessInfo.businessDate))]
[PXUIField(DisplayName = "Date Notified")]
public DateTime? DateNotified { get; set; }
#endregion
}
}
}
Your best bet would be to create a view that selects ItemBaseDocument.
PXSelect<ItemBaseDocument> ViewName;
In your for loop of your action button, you will want to create a new ItemBaseDocument object and set it equal to the corresponding ItemBaseDocument row entry. You can then update the date of this object, and when you execute your Save.PressButton() action, that should save the updates to that entry as well.
foreach(ARTran tran in DetailsView.Select())
{
if (tran.Selected==true)
{
ARTranExt tranExt = tran.GetExtension<ARTranExt>();
ARInvoiceEntry tranEntry = new ARInvoiceEntry();
tranExt.UsrDateNotified = MasterView.Current.DateNotified;
tranEntry.Transactions.Update(tran);
tranEntry.Save.PressButton();
//Target Added Code
ItemBaseDocument doc = PXSelect<ItemBaseDocument, Where<ItemBaseDocument.inventoryID,
Equal<Required<ARTran.inventoryID>>>>.Select(tran.InventoryID);
doc.UsrDateNotified = MasterView.Current.DateNotified;
}
}
Disclaimer: There may be a syntax error in the added code above. If there is, please let me know and I will fix it.

Acumatica Add Filter on Create Requisition Screen

May I ask for your guidance here, my problem is I added a Branch Filter on the Create Requisition(RQ504000) screen, I tried to override the RQRequestProcessing Class but it just don't work. I also tried adding a WhereAnd on the Records view upon field updated but it also does not work. Any suggestion is greatly appreciated thanks.
I propose you following solution:
public class RQRequestSelectionExt : PXCacheExtension<RQRequestSelection>
{
#region AllocatedAmount2
public abstract class usrBranchID : IBqlField
{
}
[PXDBInt]
[PXUIField(DisplayName = "Branch ID")]
[PXDefault(2)]
[Branch]
public int? UsrBranchID { get; set; }
#endregion
}
public class RQRequestProcessExt : PXGraphExtension<RQRequestProcess>
{
[PXFilterable(new System.Type[] { })]
public RQRequestProcess.RQRequestProcessing Records;
public IEnumerable records()
{
var currentFilter = Base.Filter.Current;
var filterExt = currentFilter.GetExtension<RQRequestSelectionExt>();
var newList = Base.Records.Select();
ArrayList result = new ArrayList();
foreach (PXResult<RQRequestLineOwned> listItme in newList)
{
var row = listItme.GetItem<RQRequestLineOwned>();
if (filterExt.UsrBranchID != null)
{
if (row.BranchID == filterExt.UsrBranchID)
{
result.Add(row);
}
}
else
{
result.Add(row);
}
}
return result;
}
}
Another one, you can try to play with WhereAnd, but I for myself wasn't very successful with it.

Resources