I run into this on occasion. I have list of parameters on this generic inquiry. All of them working except TaxInvoiceStatus:
TaxInvoiceStatus has a default value Pending :
public abstract class taxInvoiceStatus : PX.Data.IBqlField
{
}
protected int? _TaxInvoiceStatus;
[PXDBInt()]
[PXUIField(DisplayName = "TaxInvoice Status")]
[PXDefault(ExtStatus.Pending)]
[PXIntList(
new int[]
{
ExtStatus.Pending,
ExtStatus.Rejected,
ExtStatus.Confirmed,
ExtStatus.Initial,
ExtStatus.Corrected,
ExtStatus.Canceled,
ExtStatus.WaitingApprove,
ExtStatus.ApprovedByVendor
},
new string[]
{
"Pending",
"Rejected",
"Confirmed",
"Initial",
"Corrected",
"Canceled",
"Waiting Approve",
"Approved By Vendor"
})]
public virtual int? TaxInvoiceStatus
{
get
{
return this._TaxInvoiceStatus;
}
set
{
this._TaxInvoiceStatus = value;
}
}
So the problem is that I cant set a default value null for TaxInvoiceStatus on the generic inquery page. I tried #Null, #null, null in the parameters Default Value , but none of them was working. Those are conditions :
And in VIEW INQUERY :
As you can see Tax Invoice Status is Pending and it always filters it by pending status.
Also I am wondering if it's possible for user to clear that field so make it empty.
Generic Inquiry is very tricky when dealing with Default values.
If you cannot remove the PXDefault for the field, one thing you could do is:
Create a Custom DAC that inherits from YOURDAC involved.
On your Custom DAC, remove the PXDefault Attribute only for your Status field.
public class CUSTOMDAC: YOURDAC
{
.....
public abstract class taxInvoiceStatus : PX.Data.IBqlField
{
}
protected int? _TaxInvoiceStatus;
[PXDBInt()]
[PXUIField(DisplayName = "TaxInvoice Status")]
//[PXDefault(ExtStatus.Pending)]
[PXIntList(
new int[]
{
ExtStatus.Pending,
ExtStatus.Rejected,
ExtStatus.Confirmed,
ExtStatus.Initial,
ExtStatus.Corrected,
ExtStatus.Canceled,
ExtStatus.WaitingApprove,
ExtStatus.ApprovedByVendor
},
new string[]
{
"Pending",
"Rejected",
"Confirmed",
"Initial",
"Corrected",
"Canceled",
"Waiting Approve",
"Approved By Vendor"
})]
public virtual int? TaxInvoiceStatus
{
get
{
return this._TaxInvoiceStatus;
}
set
{
this._TaxInvoiceStatus = value;
}
}
........
}
Then use your new Custom DAC on the GI.
Related
Does anyone have a code snippet on how to go from RefNoteId => DAC when I dont know what dac type the note is attached to?
I have made it this far (row.RefNoteID is what I am starting from)
Note note = PXSelect<Note, Where<Note.noteID, Equal<Required<Note.noteID>>>>.Select(this, row.RefNoteID);
Type recordType = Type.GetType(note.EntityType);
PXCache recordCache = Caches[recordType];
How can I now do a PXSelect<recordType, Where<recodType.noteID, Equal<Required<recordType.noteID>>>>.Select(GRAPH) ? The recordType could be any DAC in the system that has a noteID.
Thanks
The below code works for me and it is based on the way Acumatica gets the record inside the PXRefNoteSelectorAttribute.PrimaryRow_RowPersisted.
The problem with this approach is that this will work for Header entities like SOOrder, INRegister, SOInvoice, SOShipment, and others. But for "detail" entities like SOLine, INTran, and others this approach will work only if that corresponding record has some Note related to Text/File. Acumatica is adding records corresponding to their NoteID into the Note table only if that detail records have some Note/Text. My best guess is that this is done in order to avoid over-spamming the Note table.
using PX.Data;
using PX.Objects.SO;
using System;
using System.Collections;
using System.Linq;
using System.Web.Compilation;
namespace SearchByNoteID
{
// Acuminator disable once PX1016 ExtensionDoesNotDeclareIsActiveMethod extension should be constantly active
public class SOOrderEntryExt : PXGraphExtension<SOOrderEntry>
{
public PXAction<SOOrder> searchByNoteID;
[PXUIField(DisplayName ="Search by Note ID")]
[PXButton(CommitChanges = true)]
public virtual IEnumerable SearchByNoteID(PXAdapter adapter)
{
var order = adapter.Get<SOOrder>().FirstOrDefault();
if(order!=null)
{
//
//...
//
Guid? noteID = GetNoteID();
object record = GetRecordByNoteID(noteID);
//
//... do whatever you want with the record
//
}
return adapter.Get();
}
protected object GetRecordByNoteID(Guid? noteID)
{
var type = GetEntityType(this.Base, noteID);
if(type==null) return null;
object entityRow = new EntityHelper(this.Base).GetEntityRow(type, noteID);
return entityRow;
}
protected Type GetEntityType(PXGraph graph, Guid? noteID)
{
if (noteID == null)
{
return null;
}
Note note = PXSelectBase<Note, PXSelect<Note, Where<Note.noteID, Equal<Required<Note.noteID>>>>.Config>.SelectWindowed(graph, 0, 1, new object[]
{
noteID
});
if (note == null || string.IsNullOrEmpty(note.EntityType))
{
return null;
}
return PXBuildManager.GetType(note.EntityType, false);
}
}
}
I have a request to add fields to a selector for Location on the Sales Order screen. In standard Acumatica style, this is not a typical selector, but something I've never seen before:
[LocationID(typeof(Where<Location.bAccountID, Equal<Current<SOOrder.customerID>>,
And<Location.isActive, Equal<True>,
And<MatchWithBranch<Location.cBranchID>>>>)
,DescriptionField = typeof(Location.descr)
,Visibility = PXUIVisibility.SelectorVisible)]
The fields I need to add are Address1, Address2, City, State, Zip. How would I add these fields to this cryptic selector called 'LocationID'?
I've tried this, but it doesn't work:
[PXRemoveBaseAttribute(typeof(LocationIDAttribute))]
[PXMergeAttributes(Method = MergeMethod.Append)]
[PXSelector(typeof(Search2<Location.locationID,
InnerJoin<Address,
On<Location.defAddressID, Equal<Address.addressID>>>,
Where<Location.bAccountID, Equal<Current<SOOrder.customerID>>,
And<Location.isActive, Equal<True>,
And<MatchWithBranch<Location.cBranchID>>>>>)
,typeof(Location.locationCD)
,typeof(Address.addressLine1)
,typeof(Address.addressLine2)
,typeof(Address.city)
,typeof(Address.state)
,typeof(Address.postalCode)
,SubstituteKey = typeof(Location.locationCD)
,DescriptionField = typeof(Location.descr))]
protected virtual void SOOrder_CustomerLocationID_CacheAttached(PXCache sender) { }
This one is a little tricky because the ability to change the column list is protected. We can change the columns by making our own location ID attribute that inherits the one we need to change and then replace the Dimension selector which at that time we can add the columns to be displayed. We also need to join in the address table to display the fields you are looking to add as they are not in the Location DAC.
Here are working examples:
A new attribute which we will use to replace the current attribute on SOOrder CustomerLocaitonID
public class LocationIDExtensionAttribute : LocationIDAttribute
{
public LocationIDExtensionAttribute(params Type[] fieldList)
: this(typeof(Where<boolTrue, Equal<boolTrue>>), fieldList)
{
}
public LocationIDExtensionAttribute(Type WhereType, params Type[] fieldList)
: base(WhereType)
{
AddColumns(WhereType, fieldList);
}
public LocationIDExtensionAttribute(Type WhereType, Type JoinType, params Type[] fieldList)
: base(WhereType, JoinType)
{
AddColumns(WhereType, JoinType, fieldList);
}
protected void AddColumns(Type WhereType, params Type[] fieldList)
{
var dimensionSelector = _Attributes[_SelAttrIndex];
if (dimensionSelector == null)
{
return;
}
_Attributes[_SelAttrIndex] = (PXEventSubscriberAttribute)new PXDimensionSelectorAttribute("LOCATION", BqlCommand.Compose(typeof(Search<,>), typeof(Location.locationID), WhereType), typeof(Location.locationCD), fieldList);
}
protected void AddColumns(Type WhereType, Type JoinType, System.Type[] fieldList)
{
var dimensionSelector = _Attributes[_SelAttrIndex];
if (dimensionSelector == null)
{
return;
}
_Attributes[_SelAttrIndex] = (PXEventSubscriberAttribute)new PXDimensionSelectorAttribute("LOCATION", BqlCommand.Compose(typeof(Search2<,,>), typeof(Location.locationID), JoinType, WhereType), typeof(Location.locationCD), fieldList);
}
}
Then we would use this attribute like this:
[LocationIDExtension(typeof(Where<Location.bAccountID, Equal<Current<SOOrder.customerID>>,
And<Location.isActive, Equal<True>,
And<MatchWithBranch<Location.cBranchID>>>>),
typeof(LeftJoin<Address, On<Location.defAddressID, Equal<Address.addressID>>>),
typeof(Location.locationCD),
typeof(Location.descr),
typeof(Address.addressLine1),
typeof(Address.addressLine2),
typeof(Address.city),
typeof(Address.state),
typeof(Address.postalCode),
DescriptionField = typeof(Location.descr),
Visibility = PXUIVisibility.SelectorVisible)]
And we end up with this:
I am trying to create a custom Parts selector to search all records if there is no vendor selected, if a vendor is selected I want to filter the selector's results to only include Parts with the vendor selected.
Using PXCustomSelectorAttribute:
SQL Error: Incorrect syntax near the keyword 'AND'
Incorrect syntax near the keyword 'ORDER'
[PXNonInstantiatedExtension]
public class SO_SOLine_ExistingColumn : PXCacheExtension<PX.Objects.SO.SOLine>
{
#region InventoryID
[PXMergeAttributes(Method = MergeMethod.Replace)] //was append
[PXUIField(DisplayName = "Part #")]
[PartSelector(typeof(SOLineExt.usrCusVendor))]
public int? InventoryID { get; set; }
#endregion
}
public class PartSelector : PXCustomSelectorAttribute
{
[Serializable]
[PXProjection(typeof(
Select2<atcVendorItem,
LeftJoin<InventoryItem,
On<InventoryItem.inventoryCD, Equal<atcVendorItem.inventoryCD>, And<InventoryItem.inventoryID, Equal<atcVendorItem.inventoryID>>>>>), Persistent = false)]
public class atcPartView : IBqlTable
{
// DAC W/Inventory Item Table mapped and joined with Vendor Items
}
//Selected table
private Type _MfgField;
////way to have multiple description fields
public PartSelector(Type MfgField) : base(typeof(atcPartView.inventoryID))
{
_MfgField = MfgField;
}
protected virtual IEnumerable GetRecords()
{
var cache = this._Graph.Caches[BqlCommand.GetItemType(_MfgField)];
var cbs = (BAccount)cache.Current;
// make mfgfield
if (cbs != null)
{
foreach (atcPartView p in PXSelect<atcPartView, Where<atcPartView.vendorID, Equal<Required<SOLineExt.usrMfg>>>>.Select(_Graph, cbs.BAccountID))
{
yield return p;
}
}
else
{
foreach (atcPartView p in PXSelect<atcPartView, Where<atcPartView.vendorID, IsNotNull>>.Select(_Graph))
{
yield return p;
}
}
}
}
I was able to find another exception while debugging in visual studio,
my issue was because I was trying to cast the field as BAccount when referencing the SOLine Extension. Changing the cast fixed my issue
I have a requirement to create a opportunity like screen and I do not know how to implement the auto generating the document number for newly created document
I am looking forward someone to help me on this issue.
The following steps I have used and I have attached the code for review. I am getting error while saving and not generating the number
I have create a numbering sequence for Memo In document
I have created a DAC for Sequence number setup
region MemoInOrderId
public abstract class memoInOrderId : PX.Data.IBqlField
{
}
protected string _MemoInOrderId;
[PXDBString(10, IsUnicode = true)]
[PXDefault("MEMOIN")]
[PXSelector(typeof(Numbering.numberingID),
DescriptionField = typeof(Numbering.descr))]
[PXUIField(DisplayName = "Memo In Order Nbr")]
public virtual string MemoInOrderId
{
get
{
return this._MemoInOrderId;
}
set
{
this._MemoInOrderId = value;
}
}
#endregion
I have added Auto Generation Sequence number to MemoIn DAC
`
#region OrderNbr
public abstract class orderNbr : PX.Data.IBqlField
{
}
[PXDBString(10, IsUnicode = true, IsKey = true, InputMask = ">CCCCCCCCCCCCCCC")]
[PXUIField(DisplayName = "Order Nbr", Visibility = PXUIVisibility.SelectorVisible)]
[AutoNumber(typeof(MemoSetUp.memoInOrderId), typeof(AccessInfo.businessDate))]
[PXSelector(typeof(MemoIN.orderNbr),
new Type[]
{
typeof(MemoIN.orderNbr),
typeof(MemoIN.orderDate),
typeof(MemoIN.vendorId)
})]
public virtual string OrderNbr { get; set; }
#endregion
In the configuration Screen I have selected numbering sequence used for memo in document
While saving the Memo In document I am getting the following error
I have noticed the Order number is not initialized to "NEW" and it is showing "SELECT"
I have gone through CASetup , CMSetup , ARSetup DAC code and not able to figure out the difference.
If we want to use a numbering sequence it is very straight forward in Acumatica. You should have a setup/preferences field somewhere that defines which numbering sequence you will use for your document number field.
Here is an example of a setup field using a selector to pick a numbering sequence:
// Setup field indicating which numbering sequence to use.
public abstract class myNumberingID : PX.Data.IBqlField
{
}
protected String _MyNumberingID;
[PXDBString(10, IsUnicode = true)]
[PXSelector(typeof(Numbering.numberingID), DescriptionField = typeof(Numbering.descr))]
[PXUIField(DisplayName = "My Numbering Sequence")]
public virtual String MyNumberingID
{
get
{
return this._MyNumberingID;
}
set
{
this._MyNumberingID = value;
}
}
Next, in your document number field you will use the AutoNumberAttribute to define the field as a consumer of a numbering sequence. Below is an example of a number field using the defined number sequence configured in the setup table above (Assumes "MyNumberingID" exists in DAC/Table "MySetup").
// Field using the numbering sequence...
public abstract class myNumberField : PX.Data.IBqlField
{
}
protected String _MyNumberField;
[PXDBString(15, IsUnicode = true, IsKey = true, InputMask = ">CCCCCCCCCCCCCCC")]
[PXUIField(DisplayName = "My Number", Visibility = PXUIVisibility.SelectorVisible)]
[AutoNumber(typeof (MySetup.myNumberingID), typeof (AccessInfo.businessDate))]
[PXDefault]
public virtual String MyNumberField
{
get
{
return this._MyNumberField;
}
set
{
this._MyNumberField = value;
}
}
Edit: Make sure in the graph building the documents to include a PXSetup view to the setup table.
Now when you insert and persist a new record on the DAC that contains your number field, the next numbering sequence value will be used (unless the numbering sequence is configured for manual numbering then the user must provide a value).
For a more complex configuration when there are multiple numbering sequences used based on specific conditions/field values, you can look at PX.Objects.IN.INRegister.RefNbr for an example. Look at INDocType.Numbering and how it changes the numbering sequence based on INRegister.docType (shown below). Another example would be sales order order types related to the sales order document.
public class NumberingAttribute : AutoNumberAttribute
{
public NumberingAttribute()
: base(typeof(INRegister.docType), typeof(INRegister.tranDate),
new string[] { Issue, Receipt, Transfer, Adjustment, Production, Change, Disassembly },
new Type[] { typeof(INSetup.issueNumberingID), typeof(INSetup.receiptNumberingID), typeof(INSetup.receiptNumberingID), typeof(INSetup.adjustmentNumberingID), typeof(INSetup.kitAssemblyNumberingID), typeof(INSetup.kitAssemblyNumberingID), typeof(INSetup.kitAssemblyNumberingID) }) { ; }
}
In Cash Sales (AR304000 screen) i want to set it's auto numbering sequence from invoice number sequence to payment number sequence.
i tried the following code but to no avail. saving new sales throws an error. see attached photo for the error.
here is my DAC code:
public class ARCashSaleExtension : PXCacheExtension<ARCashSale>
{
#region RefNumber
[PXDBString(15, IsKey = true, InputMask = ">CCCCCCCCCCCCCCC", IsUnicode = true, BqlField = typeof(**PX.Objects.AR.ARPayment.refNbr**))]
[PXDefault()]
[PXUIField(DisplayName = "Reference Nbr.", Visibility = PXUIVisibility.SelectorVisible)]
[ARPaymentType.RefNbr(typeof(Search2<ARCashSale.refNbr,
InnerJoinSingleTable<Customer, On<ARCashSale.customerID, Equal<Customer.bAccountID>>>,
Where<ARCashSale.docType, Equal<Current<ARCashSale.docType>>,
And2<Where<ARCashSale.origModule, NotEqual<BatchModule.moduleSO>, Or<ARCashSale.released, Equal<boolTrue>>>,
And<Match<Customer, Current<AccessInfo.userName>>>>>, OrderBy<Desc<ARCashSale.refNbr>>>), Filterable = true)]
[**ARPaymentType.Numbering()**]
[PXFieldDescription]
public String RefNbr
{
get;
set;
}
#endregion
}
I think you should use AutoNumberAttribute instead of ARPaymentType.Numbering attribute.
[AutoNumber(typeof(ARCashSale.docType), typeof(ARCashSale.docDate),
new string[] { CashSale, CashReturn },
new Type[] { typeof(ARSetup.paymentNumberingID), typeof(ARSetup.paymentNumberingID) })]
Besides, I can't see any reasons to use ARPaymentType.RefNbr attribute instead of ARCashSaleType.RefNbr attribute.
One more thing: from my point, it's better to use Cache_Attached on graph extension for rewriting attributes on one field instead of creating DAC extension.
Here is an example of Graph extension with CacheAttached:
public partial class ARCashSaleEntryExt : PXGraphExtension<ARCashSaleEntry>
{
[PXMergeAttributes(Method = MergeMethod.Merge)] // that attribute is here to keep all attributes of base field except the one that should be replaced.
[AutoNumber(typeof(ARCashSale.docType), typeof(ARCashSale.docDate),
new string[] { ARDocType.CashSale, ARDocType.CashReturn },
new Type[] { typeof(ARSetup.paymentNumberingID), typeof(ARSetup.paymentNumberingID) })]
public virtual void ARCashSale_RefNbr_CacheAttached(PXCache sender)
{
}
}
To learn more about cache_attached events see T200 training