IN Kit Assembly screen, once i release Kit Assembly then i can never update INKitAssembly,
But I have to allow KitAssembly Extension table fields to update. how may i allow to update custom fields added in INRegister(InKitAssembly) extension table?
Is there a way to update InKitAssembly extension table fields on Release operation completion, DO you have any call back delegate after Release kitAssembly long operation completion?
Updating your extension values in the INReleaseProcess persist should work. Something like this:
public class INReleaseProcessExte : PXGraphExtension<INReleaseProcess>
{
[PXOverride]
public virtual void Persist(Action del)
{
foreach (INTran row in Base.intranselect.Cache.Updated)
{
if (row?.DocType != INDocType.Production || row.Released != true)
{
continue;
}
// update your extension here
var inTranExt = PXCache<INTran>.GetExtension<INTranMyExtension>(row);
inTranExt.MyField = "X";
Base.intranselect.Update(row);
}
del?.Invoke();
}
}
Related
I am trying to enable the custom field in Case when the Status is in Closed State. I am working on a customization for Acumatica version 20.114.0020 (2020 R1).
I have created a custom field usrIsNotBillable in CRCase DAC.
[PXDBBool]
[PXUIField(DisplayName="Confirmed Not Billable", Enabled = true)]
public virtual bool? UsrIsNotBillable { get; set; }
public abstract class usrIsNotBillable : PX.Data.BQL.BqlBool.Field<usrIsNotBillable> { }
It is totally working fine when the Case is in other states than Closed. But when the case is closed, every other property gets disabled. But I want this field to be set enabled. So, I override the Row Selected method for CRCaseMaint graph as below:
protected void CRCase_RowSelected(PXCache cache, PXRowSelectedEventArgs e, PXRowSelected InvokeBaseHandler)
{
InvokeBaseHandler?.Invoke(cache, e);
CRCase row = (CRCase) e.Row;
if (row == null) return;
Base.CaseCurrent.Cache.AllowUpdate = true;
Base.CaseCurrent.AllowUpdate = true;
PXUIFieldAttribute.SetEnabled<CRCaseExt.usrIsNotBillable>(cache, row, true);
}
If I use other DAC fields such as IsBillable like this:
PXUIFieldAttribute.SetEnabled<CRCase.isBillable>(cache, row, true);
It just works fine.
I checked other examples too and the implementation is similar to this. I am just not sure why it is not working in this case.
I have also checked if this screen has any existing workflows and it doesn't.
Any help would be appreciated.
Thanks.
Besides writing code to enable the field in RowSelected event, it is also important to add the field in Closed state in the Workflow.
However, if this is also not working deleting contents of CstDesigner of project does the job.
I have tried multiple ways, but getting Another process error in the default version of Acumatica 19.106.0020
On top of it i have a customized code on both customer and contact screen, my requirement to clear the value of the custom field that is created in contact table when customer is deleting from the screen AR303000 i need to set null value of the custom field for the deleted contact from the customer.
i have tried by setting value on Customer_RowDeleting event but continuously getting Another process error, below is the screenshot error
Below is the code that i was tried
protected virtual void Customer_RowDeleting(PXCache sender, PXRowDeletingEventArgs e, PXRowDeleting BaseEvent)
{
BaseEvent?.Invoke(sender, e);
Customer rows = e.Row as Customer;
if (rows == null)
return;
if (Base.BAccount.Cache.GetStatus(Base.BAccount.Current) == PXEntryStatus.Deleted)
{
foreach (Contact BACT in PXSelectReadonly<Contact,
Where<Contact.bAccountID, Equal<Required<Contact.bAccountID>>,
And<Contact.contactType, NotEqual<ContactTypesAttribute.bAccountProperty>>>>.Select(Base, rows.BAccountID))
{
ContactMaint congraph = PXGraph.CreateInstance<ContactMaint>();
Contact CTData = PXSelectReadonly<Contact,
Where<Contact.contactID, Equal<Required<Contact.contactID>>>>.Select(Base, BACT.ContactID);
if (CTData != null)
{
congraph.Contact.Current = CTData;
if (congraph.Contact.Current != null)
{
congraph.Contact.SetValueExt<ContactExt.usrKWBAccountId>(congraph.Contact.Current, null);
congraph.Contact.Update(congraph.Contact.Current);
congraph.Save.Press();
}
}
}
}
}
Thanks in advance.
Hi Chris, please find the attached image here
I don't recommend to create graphs during RowDeleting event. If you have Acuminator installed, you will see a warning about creating graphs in event handlers.
Instead, call your custom code during the Persist method. Persist method is called during Delete operation. After the Base persist is finished, your custom code can perform it's work. Try something like this
public class CustomerMaint_Extension : PXGraphExtension<CustomerMaint>
{
public delegate void PersistDelegate();
[PXOverride]
public void Persist(PersistDelegate baseMethod)
{
Customer currentCustomer = Base.CurrentCustomer.Current; //get the customer record before it's deleted, i.e. Customer.bAccountID
baseMethod(); //let the base delete process happen first
if (Base.CurrentCustomer.Cache.GetStatus(currentCustomer) == PXEntryStatus.Deleted)
{
using (PXTransactionScope ts = new PXTransactionScope())
{
//here is where you add your code to delete other records
ts.Complete(); //be sure to complete the transaction scope
}
}
}
}
Also you might want to unpublish other customization packages, and see if the error continues without those packages. That is one way to determine the source of the error...by process of elimination.
I'm upgrading a customization project from version 5.3.2936 to version 6.10.0755. I've run into an attribute: [PXNotPersistable] which, apparently, no longer exists. I don't know what this attribute does or if there is a replacement. It's used to decorate a PXSselectJoin BQL statement. Any help would be appreciated.
The PXNotPersistable attribute was completely removed from the Acumatica Framework mostly because it was not used anywhere inside Acumatica ERP solution.
Below is the implementation of PXNotPersistableAttribute:
public sealed class PXNotPersistableAttribute : PXCacheExtensionAttribute
{
protected override void AddHandlers(PXCache cache)
{
cache.RowPersisting += (sender, args) => args.Cancel = true;
}
}
As you might notice, the attribute was quite basic and didn't do much: only prevented modified records of the main data view DAC from beings saved to a database.
Say, you have a custom data view declared as follows for ver. 5.3:
[PXNotPersistable]
public PXSelectJoin<MyDacA,
LeftJoin<MyDacB, On<MyDacB.someField, Equal<MyDacA.someField>>>> DataView;
For ver. 6.1, PXNotPersistableAttribute can be simply replaced with the MyDacA_RowPersisting handler (since MyDacA is the main DAC for our data view and only changes made to this DAC will be saved to a database):
public void MyDacA_RowPersisting(PXCache sender, PXRowPersistingEventArgs e)
{
e.Cancel = true;
}
As title, i don't know how can customize this page (processing page). I have extension with override Initialize as below
Base.INDocumentList.SetProcessDelegate(delegate(List<INRegister> list){ ReleaseDocExt(list); });
But ReleaseDocExt not run when i process item.
I was able to create an extension and override the release process. If I include this extension, system will show "Hello, World!" when trying to release any IN document from the batch processing screen:
namespace PX.Objects.IN
{
public class INDocumentRelease_Extension:PXGraphExtension<INDocumentRelease>
{
public override void Initialize()
{
Base.INDocumentList.SetProcessDelegate(delegate(List<INRegister> list){ ReleaseDocExt(list); });
}
public static void ReleaseDocExt(List<INRegister> list)
{
throw new PXException("Hello, World!!");
}
}
}
This code is not getting invoked when releasing a document from one of the inventory screens, like the Receipts (IN.30.10.00) screen. The reason is because these screens directly invoke a static method in the INDocumentRelease class, and don't create a graph to do it:
public PXAction<INRegister> release;
[PXUIField(DisplayName = Messages.Release, MapEnableRights = PXCacheRights.Update, MapViewRights = PXCacheRights.Update)]
[PXProcessButton]
public virtual IEnumerable Release(PXAdapter adapter)
{
PXCache cache = receipt.Cache;
List<INRegister> list = new List<INRegister>();
foreach (INRegister indoc in adapter.Get<INRegister>())
{
if (indoc.Hold == false && indoc.Released == false)
{
cache.Update(indoc);
list.Add(indoc);
}
}
if (list.Count == 0)
{
throw new PXException(Messages.Document_Status_Invalid);
}
Save.Press();
PXLongOperation.StartOperation(this, delegate() { INDocumentRelease.ReleaseDoc(list, false); });
return list;
}
There's therefore no opportunity for system to include your extension in this process.
If you absolutely need to customize this process, you'll also need to override the Release actions in the individual screens. This code could also be modified by Acumatica to avoid the use of static functions, and instead instantiate a INDocumentRelease instance that can be customized.
Finally, I would like to warn you about customizing the transaction release processes - make sure you know what you're doing!
In a cross platform Xamarin app built with the MvvmCross framework I'm using a ToggleButton Widget in an Android .axml layout. I've bound the Checked property to a View Model property using a converter using the following binding syntax:
Checked MarketBuySellViewModel.Direction, Converter=DirectionBool, ConverterParameter='Sell'
Everything works well. On the iOS side, it appears you can use UIButton as a ToggleButton by using the Selected property. This implies that the following binding should achieve what I want on iOS:
set.Bind (SellButton).For(b => b.Selected).To (vm => vm.MarketBuySellViewModel.Direction).WithConversion("DirectionBool", "Sell");
I don't get any binding errors in the application output but the binding itself doesn't seem to work. Clicking the button doesn't set the Direction property and setting the direction to a different value does not set the Selected property on the UIButton.
Do I need to create a Custom Binding or am I simply setting up the binding incorrectly?
I also tried using a UISegmentedControl to achieve the same effect. Is binding to this control supported at all in MvvmCross? I don't see any reference to it in the source code. Does this mean I need to create custom bindings for it too?
For the UIButton, I don't believe there's any included Selected binding built into MvvmCross. Because of this - and because Selected doesn't have a simple paired event SelectedChanged, then I believe Selected binding should work one-way (from ViewModel to View) but not two-way.
There is a binding for the On of a UISwitch control and that's the control I've seen used most in these situations.
If you wanted to add a custom 2-way binding for Selected then I guess you'd have to do this using the ValueChanged event (but would need to check that is correct).
To do so, you'd just build a target binding something like:
public class MvxUIButtonSelectedTargetBinding : MvxPropertyInfoTargetBinding<UIButton>
{
public MvxUIButtonSelectedTargetBinding(object target, PropertyInfo targetPropertyInfo)
: base(target, targetPropertyInfo)
{
var view = View;
view.ValueChanged += HandleValueChanged;
}
private void HandleValueChanged(object sender, System.EventArgs e)
{
var view = View;
if (view == null)
return;
FireValueChanged(view.Selected);
}
public override MvxBindingMode DefaultMode
{
get { return MvxBindingMode.TwoWay; }
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (isDisposing)
{
var view = View;
if (view != null)
{
view.ValueChanged -= HandleValueChanged;
}
}
}
}
and this could be registered in Setup in protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry) using something like:
registry.RegisterPropertyInfoBindingFactory(typeof(MvxUIButtonSelectedTargetBinding), typeof(UIButton),
"Selected");
Similarly, I don't believe anyone has added a two way UISegmentedControl binding yet - but would happily see one added.
Building a two way UISegmentedControl binding would be quite straight-forward - you'd just have to bind to the pair SelectedSegment and ValueChanged - with code similar to above.
Alternatively, you could switch to using a custom MySegmentedControl which had a nicer Value`ValueChanged` pair which would automatically work without a custom binding - e.g.:
public class MySegmentedControl : UISegmentedControl
{
// add more constructors if required
public int Value
{
get { return base.SelectedSegment; }
set { base.SelectedSegment = value; }
}
}
If any or all of these custom bindings are needed, then the Mvx project is happy to get these bindings added as issues or pull requests along with test/demo UIs in the https://github.com/slodge/MvvmCross-Tutorials/blob/master/ApiExamples/ApiExamples.Touch/Views/FirstView.cs project
Could be helpful to someone else, so i'm sharing my experience. I needed a two way binding for UISegmentedControl.SelectedSegment property to a ViewModel. The one way biding (ViewModel => View) works by default. I couldn't able to properly utilize the solution proposed by Stuart - to subclass the UISegmentedControl. I tried to ensure that the linker does not rip off the new custom control code, but this didn't help me a bit. So a perfectly viable solution is the one with MvxPropertyInfoTargetBinding. Here is the code working ok for me:
public class MvxUISegmentedControlSelectedSegmentTargetBinding : MvxPropertyInfoTargetBinding<UISegmentedControl>
{
public MvxUISegmentedControlSelectedSegmentTargetBinding(object target, PropertyInfo targetPropertyInfo)
: base(target, targetPropertyInfo)
{
this.View.ValueChanged += HandleValueChanged;
}
private void HandleValueChanged(object sender, System.EventArgs e)
{
var view = this.View;
if (view == null)
{
return;
}
FireValueChanged(view.SelectedSegment);
}
public override MvxBindingMode DefaultMode
{
get { return MvxBindingMode.TwoWay; }
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (isDisposing)
{
var view = this.View;
if (view != null)
{
view.ValueChanged -= HandleValueChanged;
}
}
}
}
public class Setup : MvxTouchSetup
{
...
protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry)
{
registry.RegisterPropertyInfoBindingFactory(typeof(MvxUISegmentedControlSelectedSegmentTargetBinding), typeof(UISegmentedControl), "SelectedSegment");
}
}