Notes Window Not Updating on Bill - acumatica

I am updating the Notes on a Bill via some custom code in a graph extension. My problem is that the window that pops open when you click on the Notes icon in the upper-right corner of the screen does not reflect the changes that I made to the notes in code. If I use the < > buttons to scroll to another Bill and then back to the one that I updated, it shows the changes. So, I'm not sure how to get the notes to refresh.
This is on the AP301000 screen. I have tried Base.Document.View.RequestRefresh(), Base.Document.View.Clear() and calling the Base.Actions.PressSave() after my code changes the note for the Bill.
TIA!
Here's Code:
protected void APTran_RowInserted(PXCache cache, PXRowInsertedEventArgs e)
{
var row = (APTran)e.Row;
if (row == null)
return;
//*********************** copy notes and file attachments from PO lines and header to the Bill **********************************
if ((row.PONbr != null) && (row.POLineNbr != null))
{
POOrderEntry poEntry = (POOrderEntry)PXGraph.CreateInstance(typeof(POOrderEntry));
poEntry.Clear();
POOrder poHeader = poEntry.Document.Search<POOrder.orderNbr>(row.PONbr);
poEntry.Document.Current = poHeader;
POLine poLine = poEntry.Transactions.Search<POLine.lineNbr>(row.POLineNbr);
if (poLine != null)
{
PXNoteAttribute.CopyNoteAndFiles(poEntry.Caches[typeof(POLine)], poLine, cache, row); //// - use this for Notes and Files.
// making of copy of what the note is on the APInvoice at this point because the PXNoteAttribute.CopyNoteAndFiles() below
// will replace what is in the notes with what is in the PO instead of appending.
string oldNote = PXNoteAttribute.GetNote(Base.Caches[typeof(APInvoice)], Base.CurrentDocument.Current);
PXNoteAttribute.CopyNoteAndFiles(poEntry.Caches[typeof(POOrder)], poHeader, Base.Caches[typeof(APInvoice)], Base.CurrentDocument.Current);
PXNoteAttribute.SetNote(Base.Caches[typeof(APInvoice)], Base.CurrentDocument.Current, oldNote);
Base.Actions.PressSave();
string poNote = PXNoteAttribute.GetNote(poEntry.Caches[typeof(POOrder)], poHeader);
if (!string.IsNullOrEmpty(poNote))
{
//string oldNote = PXNoteAttribute.GetNote(Base.Caches[typeof(APInvoice)], Base.CurrentDocument.Current);
if ((oldNote == null) || !oldNote.Contains(poNote))
{
string newNote = "";
if (string.IsNullOrEmpty(oldNote))
newNote = poNote;
else
newNote = oldNote + Environment.NewLine + poNote;
//These 2 lines will not update the note without the PressSave();
//Guid noteGuid = (Guid)PXNoteAttribute.GetNoteID(Base.Caches[typeof(APInvoice)], Base.CurrentDocument.Current, null);
//PXNoteAttribute.UpdateNoteRecord(Base.Caches[typeof(APInvoice)], noteGuid, newNote);
PXNoteAttribute.SetNote(Base.Caches[typeof(APInvoice)], Base.Document.Current, newNote); // Sets the note but, screen does not refresh.
//Base.Caches[typeof(APInvoice)].Update(Base.Document.Current); //Does not refresh Notes on screen.
//PXNoteAttribute.GetNoteID<APInvoice.noteID>(Base.Caches[typeof(APInvoice)], Base.Document.Current); // Does not update the screen.
//Base.Caches[typeof(Note)].IsDirty = true; /// No Effect.
//Base.Caches[typeof(Note)].Clear(); //this has no effect on refreshing the notes that are seen on the screen.
//Base.Caches[typeof(NoteDoc)].Clear();
//Base.Actions.PressSave(); // blanks out the header if the Bill has never been saved. Does not refresh note on screen.
//Base.Document.View.Clear();
//Base.Document.View.RequestRefresh(); // this wipes out the new note if adding a second PO.
}
}
}
}
}

Here's the fix for this that I deployed. I'm thinking that there is a better way to do this but, seems to be working ok for now. I added this:
[PXOverride]
public void Persist(Action persist)
{
persist();
APInvoice invoice = (APInvoice)Base.CurrentDocument.SelectSingle();
if (invoice.Status == "H")
throw new PXRedirectRequiredException(Base, "Reloading Notes...");
}
So, I overrode the Persist() in order to refresh the page but, I only do that if the Bill is still on Hold. This refreshes the Notes that are shown on the screen.

Related

Modify filtered data grid when a row is selected

I have a processing page which may contain multiple rows with a common id value. When a row is selected, I would like to deselect and disable all other rows with the same id value. Likewise if that row is deselected I want to re-enable all the other rows with the same id. I know I need to use a rowupdated event but I don't know how to attach to the cache for the grid. Any help is appreciated.
public void EDIOrder_RowUpdated(PXCache sender, PXRowUpdatedEventArgs e)
{
EDIOrder row = (EDIOrder)e.Row;
if (row != null)
{
// attach to cache and update other rows with same id
}
}
I had a similar situation, where PayoutDetail records belonging to the same Payout needed to stay in synch. I chose Field_Updated for the event handling to select or deselect like-records:
protected virtual void RCPayoutDetail_Selected_FieldUpdated(
PX.Data.PXCache cache, PX.Data.PXFieldUpdatedEventArgs e)
{
RCPayoutDetail row = (RCPayoutDetail)e.Row;
if (row != null)
{
// keep all Payouts in synch
foreach (RCPayoutDetail rec in this.Records.Select())
{
if (rec.RCPayoutID == row.RCPayoutID &&
row.RCPayoutDetailID != rec.RCPayoutDetailID)
{
cache.SetValue<RCPayoutDetail.selected>(rec, row.Selected);
}
}
this.Records.View.RequestRefresh();
}
}
In your case for enable/disable, try adding:
PXUIFieldAttribute.SetEnabled<RCPayoutDetail.selected>(
cache, rec, !(bool)row.Selected);
// optional, see RowSelected comments and changes suggested below
cache.SetStatus(rec, row.Selected == true ?
PXEntryStatus.Notchanged : PXEntryStatus.Modified);
In a processing page, if you are disabling the entire row, but only enabling the Selected field during RowSelected, then add the following "if" line to RowSelected for interplay with row's Status:
protected virtual void RCPayoutDetail_RowSelected(PX.Data.PXCache cache, PX.Data.PXRowSelectedEventArgs e)
{
RCPayoutDetail row = (RCPayoutDetail)e.Row;
if (row != null)
{
//Set Row Enabled = false
PXUIFieldAttribute.SetEnabled(cache, e.Row, false);
// optional if line, otherwise always enable Selected
if(cache.GetStatus(row) == PXEntryStatus.Updated || row.Selected == null)
PXUIFieldAttribute.SetEnabled<RCPayoutDetail.selected>(
cache, row, true);
}
}

Acumatica - FieldDefaulting update ImageUrl from DAC extension

I am trying to update the Inventory Item ImageUrl if it is found to be null with some conditions. I have added a Usr field called UsrStyleImg to the Item Class screen. This field is for a basic image of an item and it is stored in the database. The functionality I want is if the Inventory Item does not have an image in the ImageUrl then it will default to the UsrStyleImg that is connected with the ItemClassID. ItemClassID is also found on the Stock Item Screen. Here is the code I have in the InventoryItemMaint graph:
protected void InventoryItem_ImageUrl_FieldDefaulting(PXCache cache, PXFieldDefaultingEventArgs e)
{
var row = (InventoryItem)e.Row;
if (row == null) return;
var item = (INItemClass)PXSelect<INItemClass, Where<INItemClass.itemClassID, Equal<Current<InventoryItem.itemClassID>>>>.Select(Base, row.ItemClassID);
var image = PXSelect<InventoryItem, Where<InventoryItem.imageUrl, Equal<Current<InventoryItem.imageUrl>>>>.Select(Base, row.ImageUrl);
if (image != null)
return;
else {
e.NewValue = item.GetExtension<INItemClassExt>().UsrStyleImg;
}
}
The code compiles fine but when I test with an Item that has an Item Class attached to it with an image in the INItemClass table called UsrStyleImg it does not populate to the imageUrl found in the Inventory Item table or the Stock Item screen. I have also tried this with FieldSelecting and using the e.ReturnValue with still the same results.
If I need more clarification please let me know.
Try using a RowSelecting Event
protected virtual void InventoryItem_RowSelecting(PXCache sender, PXRowSelectingEventArgs e)
{
InventoryItem row = e.Row as InventoryItem;
//Extra checks to prevent infinite loops
if (row != null && !string.IsNullOrWhiteSpace(row.InventoryCD) && Base.Item.Cache.GetStatus(row) == PXEntryStatus.Notchanged)
{
if (!string.IsNullOrWhiteSpace(row.ItemClassID))
{
//You must always use a PXConnectionScope if Selecting during RowSelecting
using (new PXConnectionScope())
{
//If you're going to pass in a value in .Select, use Required instead of Current.
INItemClass itemClass = PXSelectReadonly<INItemClass, Where<INItemClass.itemClassID, Equal<Required<INItemClass.itemClassID>>>>.Select(Base, row.ItemClassID);
if (itemClass != null && string.IsNullOrWhiteSpace(row.ImageUrl))
{
INItemClassExt itemClassExt = itemClass.GetExtension<INItemClassExt>();
//To prevent unneeded update if it's blank
if (!string.IsNullOrWhiteSpace(itemClassExt.UsrStyleImg))
{
row.ImageUrl = itemClassExt .UsrStyleImg;
//Force set the status in the Cache, otherwise it infinite loops
Base.Item.Cache.SetStatus(row, PXEntryStatus.Updated);
Base.Item.Update(row);
}
}
}
}
}
}

Error: Reference Nbr. cannot be found in the system.."}

I customized the ARPaymentEntry in which it creates a Journal Voucher Entry with created Credit Memo, it retrieves the Credit Memo applies the open invoice that is also applied in the current payment. when I create the instance to call the Credit Memo and add the Invoice in ARAdjust table, an error occurs when trying to insert it, giving a Reference Nbr cannot be found in the system, although when I'm trying to manually applying it I could see the open invoice.
public void ReleaseCreditMemo(string refNbr)
{
try
{
ARPaymentEntry docGraph = PXGraph.CreateInstance<ARPaymentEntry>();
List<ARRegister> list = new List<ARRegister>();
ARPayment payment;
ARRegister invoice = PXSelect<ARRegister, Where<ARRegister.docType, Equal<Required<ARRegister.docType>>, And<ARRegister.refNbr, Equal<Required<ARRegister.refNbr>>>>>.Select(docGraph, ARInvoiceType.CreditMemo, refNbr);
docGraph.Document.Current = PXSelect<ARPayment, Where<ARPayment.docType, Equal<Required<ARPayment.docType>>, And<ARPayment.refNbr, Equal<Required<ARPayment.refNbr>>>>>.Select(docGraph, ARInvoiceType.CreditMemo, refNbr);
payment = docGraph.Document.Current;
list.Add(payment);
foreach (ISARWhTax item in ARWhLine.Select())
{
decimal? _CuryAdjgAmt = payment.CuryOrigDocAmt > invoice.CuryDocBal ? invoice.CuryDocBal : payment.CuryOrigDocAmt;
decimal? _CuryAdjgDiscAmt = payment.CuryOrigDocAmt > invoice.CuryDocBal ? 0m : invoice.CuryDiscBal;
ARAdjust adj = new ARAdjust();
adj.AdjdBranchID = item.AdjdBranchID;
adj.AdjdDocType = ARInvoiceType.Invoice;
adj.AdjdRefNbr = item.AdjdRefNbr;
adj.AdjdCustomerID = item.CustomerID;
adj.AdjdDocDate = invoice.DocDate;
adj.CuryAdjgAmt = _CuryAdjgAmt;
adj.CuryAdjdDiscAmt = _CuryAdjgDiscAmt;
if (docGraph.Document.Current.CuryUnappliedBal == 0m && docGraph.Document.Current.CuryOrigDocAmt > 0m)
{
throw new PXLoadInvoiceException();
}
//This line code below OCCURS THE ERROR
docGraph.Adjustments.Insert(adj);
}
docGraph.Save.Press();
PXLongOperation.StartOperation(docGraph, delegate() { ARDocumentRelease.ReleaseDoc(list, false); });
}
catch (Exception ex)
{
throw new PXException(ex.Message);
}
}
I would look at the selector of the field causing the error ("Reference Nbr.") as having a selector on a field will validate the entered value to the selector's select statement (unless validatevalue=false for the selector). Maybe the selector will give you some pointers as to what is missing or causing the validation to fail.
I figured it out it that after the code below executes it does not immediately updates the View. So what I did is to execute my code at ARPayment_RowSelected event with a conditional statement if the document is released.
PXLongOperation.StartOperation(this.Base, delegate() { ARDocumentRelease.ReleaseDoc(list, false); });

Entity Framework 5: Context updated, but not View

I use Unit of Work and Repository patterns in my software.
There is a dataGridView on form and it gets data from next way:
acceptedBonusesGrid.DataSource = _unitOfWork.DocumentRepository.GetDocumentsInfo();
GetDocumentsInfo is in DocumentRepository. GetDocumentsInfoes - is complex view with joins:
public IQueryable<GetDocumentsInfo> GetDocumentsInfo()
{
return _context.GetDocumentsInfoes;
}
When user double-clicks on record, it's form for editing this record appears. I send unit of work to form:
CorrectionAcceptedForm corrForm = new CorrectionAcceptedForm(_unitOfWork, docNum);
Form opens and link to unit of work is in use:
public CorrectionAcceptedForm(UnitOfWork unitOfWork, int docNum)
{
InitializeComponent();
_unitOfWork = unitOfWork;
_documentData = _unitOfWork.DocumentRepository.GetById(docNum);
AssignValues();
}
User makes changes in the record and saves changes:
private void SaveBill(int billId)
{
if (ValidateChildren())
{
SaveSupplierAddress();
Bill billData = _documentData.Bills.FirstOrDefault(bill => bill.BillId == billId);
if (billData != null)
{
billData.Description = descriptionTextbox.Text;
billData.Price = Convert.ToDecimal(priceTextbox.Text.Replace('.', ','));
_unitOfWork.Save();
}
}
}
When this correction form closes, then datagrid on main form reloads:
acceptedBonusesGrid.DataSource = null;
acceptedBonusesGrid.Columns.Clear();
acceptedBonusesGrid.DataSource = _unitOfWork.DocumentRepository.GetDocumentsInfo();
But after reload - all rows in datagrid are old, that was before making changes.
What is the problem?
After 3 months I have discovered problem.
GetDocumentsInfo() has to be like this:
public IQueryable<GetDocumentsInfo> GetDocumentsInfo()
{
_context.GetDocumentsInfoes.MergeOption = MergeOption.OverwriteChanges;
return _context.GetDocumentsInfoes;
}
Now my DataGrid updates when I make changes in child form.

Why is UILabel not updating?

I have created a view that shows lost connection messages to users which pops over the current view. I want to update the view periodically based on connection status changes.
I can properly get the view and change the text of a label (verified with WriteLines), but nothing changes on the actual display. I even tried removing the view and readding it and calling SetNeedsDisplay, but nothing seems to help.
I have a global variable called OverView:
public static UIView OverView;
I create the label subview, add it to the overview and pop the overview in front of the current view:
UILabel labelTitle = new UILabel();
labelTitle.Text = title;
UIView labelTitleView = (UIView) labelTitle;
labelTitleView.Tag = 5000;
OverView.AddSubview(labelTitleView);
curView.InsertSubviewAbove(OverView, curView);
curView.BringSubviewToFront(OverView);
And then at a later time, I try to modify it like this from another function:
if ((OverView != null) && (OverView.Subviews != null))
{
for (int i = 0; i < OverView.Subviews.Length; i++)
{
WriteToConsole("Type: " + OverView.Subviews[i].GetType());
if (OverView.Subviews[i] is UILabel)
{
WriteToConsole("Found Label with Tag: " + ((UILabel)(OverView.Subviews[i])).Tag + " Text: " + ((UILabel)(OverView.Subviews[i])).Text);
if (((UILabel)(OverView.Subviews[i])).Tag == 5000)
{
WriteToConsole("Setting subview Title to: " + lostConnectionTitle);
lock (overViewLocker)
{
appReference.InvokeOnMainThread(delegate
{
UILabel tempLabel = ((UILabel)(OverView.Subviews[i]));
tempLabel.Text = lostConnectionTitle;
OverView.Subviews[i].RemoveFromSuperview();
OverView.AddSubview(tempLabel);
OverView.BringSubviewToFront(tempLabel);
OverView.SetNeedsLayout();
OverView.SetNeedsDisplay();
WriteToConsole("SetNeedsDisplay");
});
}
}
}
}
}
Have you tried to use delegate methods on your label, and change their value when events occur ?
For example, if your event is clicking on a button, you should have something like that:
yourLabel.Text = "Init";
buttonExample.TouchUpInside += (sender, e) => {
yourLabel.Text = "I touched my button";
};
When your View loads, you'll see "Init" and your button and once you click on it, the label text changed.
Xamarin has some explanation about events and delegate methods here.
I hope that helped.

Resources