How to add a custom field into the ARInvoice Customer selector? - customization

There is a custom field, that I declared for the Customer DAC:
public class CustomerExt : PXCacheExtension<Customer>
{
#region UsrDemoField
[PXDBString(255)]
[PXUIField(DisplayName = "Demo Field")]
public virtual string UsrDemoField { get; set; }
public abstract class usrDemoField : IBqlField { }
#endregion
}
Attempts to modify the ARInvoice Customer selector with the Customize Selector Columns popup didn't seem to work. How can I add my custom field into the ARInvoice customer selector?

Be aware, since Acumatica ERP build #17.201.0043, it's possible to customize the list of columns defined for AR Invoices' Customer lookup via the Customize Selector Columns dialog (available in the Data Class section of the Customization Manager). For step-by-step instructions please check the screenshot below:
To modify AR Invoices' Customer lookup on Acumatica ERP ver. 6.1 and earlier, please follow the steps below:
The definition of PXCustomizeSelectorColumns generated by the Customize Selector Columns popup brilliantly works with the majority of selectors inside Acumatica ERP. Basically, PXCustomizeSelectorColumns simply replaces originally defined columns for a selector with the custom set of columns during an initialization of PXCache:
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method, AllowMultiple = false)]
public class PXCustomizeSelectorColumns: PXEventSubscriberAttribute
{
private readonly Type[] _columns;
public PXCustomizeSelectorColumns(params Type[] columns)
{
_columns = columns;
}
public override void CacheAttached(PXCache cache)
{
cache.SetAltered(this.FieldName, true);
foreach (PXEventSubscriberAttribute attr in cache.GetAttributes(null, this.FieldName))
{
PXSelectorAttribute sel = attr as PXSelectorAttribute;
if (sel == null)
continue;
sel.SetFieldList(_columns);
sel.Headers = null;
}
}
}
So what can cause the PXCustomizeSelectorColumns attribute to fail and not replace selector's originally defined columns? Any time the SetColumns method is executed on an instance of PXDimensionSelectorAttribute or PXSelectorAttribute after PXCache was initialized, there is no chance for PXCustomizeSelectorColumns to do its job.
[PXDBInt()]
[PXUIField(DisplayName = "Customer", Visibility = PXUIVisibility.Visible)]
[Serializable]
public class CustomerAttribute : AcctSubAttribute
{
...
public virtual void FieldSelecting(PXCache sender, PXFieldSelectingEventArgs e)
{
if (this.AttributeLevel == PXAttributeLevel.Item || e.IsAltered)
{
PopulateFields(sender);
}
PXFieldSelecting handler = GetAttribute<PXDimensionSelectorAttribute>().FieldSelecting;
handler(sender, e);
}
protected virtual void PopulateFields(PXCache sender)
{
if (_FieldList == null)
{
_FieldList = new string[this._fields.Length];
_HeaderList = new string[this._fields.Length];
for (int i = 0; i < this._fields.Length; i++)
{
Type cacheType = BqlCommand.GetItemType(_fields[i]);
PXCache cache = sender.Graph.Caches[cacheType];
if (cacheType.IsAssignableFrom(typeof(BAccountR)) ||
_fields[i].Name == typeof(BAccountR.acctCD).Name ||
_fields[i].Name == typeof(BAccountR.acctName).Name)
{
_FieldList[i] = _fields[i].Name;
}
else
{
_FieldList[i] = cacheType.Name + "__" + _fields[i].Name;
}
_HeaderList[i] = PXUIFieldAttribute.GetDisplayName(cache, _fields[i].Name);
}
}
var attr = GetAttribute<PXDimensionSelectorAttribute>().GetAttribute<PXSelectorAttribute>();
attr.SetColumns(_FieldList, _HeaderList);
}
...
}
With that said, to add a custom field into the ARInvoice Customer selector, one should replace all attributes declared for the ARInvoice.CustomerID field and redefine columns for the Customer selector within the CustomerActive attribute:
[PXDefault()]
[CustomerActive(typeof(Search<BAccountR.bAccountID>),
new Type[]
{
typeof(BAccountR.acctCD),
typeof(BAccountR.acctName),
typeof(CustomerExt.usrDemoField),
typeof(Address.addressLine1),
typeof(Address.addressLine2),
typeof(Address.postalCode),
typeof(CustomerAttribute.Contact.phone1),
typeof(Address.city),
typeof(Address.countryID),
typeof(CustomerAttribute.Location.taxRegistrationID),
typeof(Customer.curyID),
typeof(CustomerAttribute.Contact.salutation),
typeof(Customer.customerClassID),
typeof(Customer.status)
},
Visibility = PXUIVisibility.SelectorVisible, DescriptionField = typeof(Customer.acctName), Filterable = true, TabOrder = 2)]
After publishing the customization, custom Demo Field should finally appear in the ARInvoice Customer selector:
To enable searching against a custom field inside the ARInvoice Customer selector, open Invoices and Memos screen in the Layout Editor and type UsrDemoField as the GridProperties.FastFilterFields property of the Customer selector:

Related

insert whole list of data into sql database table in xamarin.android

i'm trying to create an application where data in a list must be inserted into a database table at once. I made some research and found out that this is possible using user-defined table types where in c# a datatable is used and passed to a stored procedure that is executed. now my problem is that there are no data tables in Xamarin.Android. so I thought to use a list instead. my idea was to create a list in the application and pass it to the webservice method, and in my webservice method I receive the list and convert it to a datatable then pass it as a parameter to the stored procedure. I wrote the following codes:
in my webservice:
[WebMethod]
public bool insrt_dt(List<Class1> lst)
{
SqlParameter param;
SqlConnection conn = new SqlConnection(new DBConnection().ConnectionString);
DataTable dt = list_to_dt(lst);
SqlCommand cmd = new SqlCommand("Insert_Customers", conn);
cmd.CommandType = CommandType.StoredProcedure;
if (conn.State == System.Data.ConnectionState.Closed)
{
conn.Open();
}
param = new SqlParameter("#tblcustomers", dt);
param.Direction = ParameterDirection.Input;
param.DbType = DbType.String;
cmd.Parameters.Add(param);
cmd.CommandTimeout = 300;
int a=cmd.ExecuteNonQuery();
if (a > 0)
{
return true;
}
else return false;
}
}
Class1:
public class Class1
{
public int id { get; set; }
public string name { get; set; }
public string country { get; set; }
}
in my Xamarin.Android app
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.activity_main);
Button btn = FindViewById<Button>(Resource.Id.button1);
btn.Click += delegate
{
wr.WebService1 ws = new wr.WebService1();
wr.Class1 class1 = new wr.Class1();
List<wr.Class1> lst = new List<wr.Class1>(){
new wr.Class1() { id = 1, name = "hgf", country = "khg" },
new wr.Class1() { id = 2, name = "hgf", country = "khg"} };
ws.insrt_dt(lst);
ws.insrt_dtCompleted += Ws_insrt_dtCompleted;
};
}
private void Ws_insrt_dtCompleted(object sender, wr.insrt_dtCompletedEventArgs e)
{
bool l = e.Result;
if (l == true)
Toast.MakeText(this, "khh", ToastLength.Long).Show();
else
Toast.MakeText(this, "ijo'pioo", ToastLength.Long).Show();
}
}
but I keep getting this error:
Argument 1: cannot convert from 'System.Collections.Generic.List<app_dt.wr.Class1>' to 'app_dt.wr.Class1[]
so I used these lines instead
new wr.Class1() { id = 1, name = "hgf", country = "khg" },
new wr.Class1() { id = 2, name = "hgf", country = "khg"} };
wr.Class1[] class1s = lst.ToArray();
ws.insrt_dt(class1s);
now I don't get an error, but it doesn't work, I mean why does it say that the webservice method input must be an array and I've created it as a list. any suggestions for this?
As i know, Xamarin do not support System.Data.SqlClient. If you want to use the database for the Xamarin android project, you could use the SQLite.NET.
Install the package from the NuGet.
NuGet: sqlite-net-pcl https://www.nuget.org/packages/sqlite-net-pcl/
For the code sample about how to use the database in Xamarin, you could check the link below. https://learn.microsoft.com/en-us/xamarin/get-started/quickstarts/database?pivots=windows
For Xamarin.Android, you could check the sample code in the link below. https://learn.microsoft.com/en-us/xamarin/android/data-cloud/data-access/using-sqlite-orm

Acumatica refer custom field to another custom field on different screen

I have created 2 custom fields(UsrFFA and UsrFreeFreightDay) as below in the Customers Screen.Customers Screen
Then I created similar fields on the Sales Order Screen as below
Sales Order
I want these fields on Sales Order screen to populate values for respective Customer ID.
I went through the training material T200 and found this code
protected void SOOrder_CustomerID_FieldUpdated(PXCache sender,PXFieldUpdatedEventArgs e)
{
SOOrder order = e.Row as SOOrder;
BAccount customer =
PXSelectorAttribute.Select<SOOrder.customerID>(sender, order)
as BAccount;
if (customer != null)
{
Contact defContact = PXSelect<Contact,
Where<Contact.bAccountID, Equal<Required<Contact.bAccountID>>,
And<Contact.contactID, Equal<Required<Contact.contactID>>>>>
.Select(Base, customer.BAccountID, customer.DefContactID);
if (defContact != null)
{
ContactExt contactExt = PXCache<Contact>
.GetExtension<ContactExt>(defContact);
sender.SetValue<SOOrderExt.usrCRVerified>(order,
contactExt.UsrCreditRecordVerified);
}
}
}
I am not able to understand this code and how should I use it in my customization.
You should subscribe to FieldUpdated handler for the SOOrder.CustomerID field and populate your custom fields on the Sales Order screen in the same way as shown in Example 5.2: Inserting a Default Detail Data Record of the T200 training class:
protected virtual void ShipmentLine_ProductID_FieldUpdated(PXCache sender, PXFieldUpdatedEventArgs e)
{
// Obtain the new data record that contains the updated
// values of all data fields
ShipmentLine line = (ShipmentLine)e.Row;
line.Description = string.Empty;
if (line.ProductID != null)
{
Product product = PXSelectorAttribute.Select<ShipmentLine.productID>(sender, line) as Product;
if (product != null)
{
// Copy the product name to the description of the shipment line
line.Description = product.ProductName;
}
}
}
You might also check Step 3.1: Adding the FieldUpdated Event Handler (CustomerMaint) and Step 5.2: Customizing Business Logic for the Sales Orders form (SOOrderEntry) from the T300 training class for additional samples.
The code snippet below should accomplish desired results on the Sales Orders screen. If you still have issues understanding the code below, I highly recommend you to go through the T300 training class for very detailed hands-on exercises with step-by-step instructions.
public class SOOrderEntryExt : PXGraphExtension<SOOrderEntry>
{
public void SOOrder_CustomerID_FieldUpdated(PXCache sender, PXFieldUpdatedEventArgs e)
{
var order = e.Row as SOOrder;
if (order.CustomerID != null)
{
var customer = PXSelectorAttribute.Select<SOOrder.customerID>(sender, order) as BAccountR;
if (customer != null)
{
var customerExt = customer.GetExtension<BAccountExt>();
var orderExt = order.GetExtension<SOOrderExt>();
orderExt.UsrFFA = customerExt.UsrFFA;
orderExt.UsrFreeFreightDay = customerExt.UsrFreeFreightDay;
}
}
}
}
Customize the attributes on the SOOrder field in the following way:
For UsrFFA field
[PXDBString(100)]
[PXUIField(DisplayName="FFA", Visible = true, Enabled = false)]
[PXFormula(typeof(Selector<SOOrder.customerID, BAccountExt.usrFFA>))]
For UsrFreeFreightDay field
[PXDBString(100)]
[PXUIField(DisplayName="Free Freight Day", Visible = true, Enabled = false)]
[PXFormula(typeof(Selector<SOOrder.customerID, BAccountExt.usrFreeFreightDay>))]

Display items in bucket with Sitecore Data Provider

Hej Guys
I have a rather large problem, I've been tasked with creating a Custom Data Provider for extracting Stock Keeping Units(SKUs) from a SOLR database into sitecore, without actually populating the database with items.
I've created a data provider, which succesfully pulls data from the SOLR database a "creates" the items in sitecore, by using the following code:
public class SkuDataProvider : DataProvider, ISkuDataProvider
{
private readonly string _targetDatabaseName = "master";
private readonly string _idTablePrefix = "Skus";
private readonly ID _skuTemplateId = new ID("{F806B403-BDAF-4C60-959D-E706A82FC1DC}");
private readonly ID _skuRootTemplateId = new ID("{9767BC47-0A95-40E9-A2DE-3766FF241411}");
private readonly IEnumerable<SkuItemInfo> _skus;
public SkuDataProvider(/*IProductPageService productPageService*/)
{
_skus = new MockDataForSkuDataProvider().GetSimpleSkuCollection();
}
public override ItemDefinition GetItemDefinition(ID itemId, CallContext context)
{
Assert.ArgumentNotNull(itemId, "itemID");
// Retrieve the sku id from Sitecore's IDTable
var skuId = GetSkuIdFromIdTable(itemId);
if (!string.IsNullOrEmpty(skuId))
{
// Retrieve the sku data from the skus collection
var sku = _skus.FirstOrDefault(o => o.SkuId == skuId);
if (sku != null)
{
// Ensure the sku item name is valid for the Sitecore content tree
var itemName = ItemUtil.ProposeValidItemName($"{sku.SkuId}_{sku.Name}");
// Return a Sitecore item definition for the sku using the sku template
return new ItemDefinition(itemId, itemName, ID.Parse(_skuTemplateId), ID.Null);
}
}
return null;
}
private string GetSkuIdFromIdTable(ID itemId)
{
var idTableEntries = IDTable.GetKeys(_idTablePrefix, itemId);
if (idTableEntries.Any())
return idTableEntries[0].Key.ToString();
return null;
}
public override IDList GetChildIDs(ItemDefinition parentItem, CallContext context)
{
if (CanProcessParent(parentItem.ID))
{
var itemIdList = new IDList();
foreach (var sku in _skus)
{
var skuId = sku.SkuId;
// Retrieve the Sitecore item ID mapped to his sku
IDTableEntry mappedId = IDTable.GetID(_idTablePrefix, skuId) ??
IDTable.GetNewID(_idTablePrefix, skuId, parentItem.ID);
itemIdList.Add(mappedId.ID);
}
context.DataManager.Database.Caches.DataCache.Clear();
return itemIdList;
}
return base.GetChildIDs(parentItem, context);
}
private bool CanProcessParent(ID id)
{
var item = Factory.GetDatabase(_targetDatabaseName).Items[id];
bool canProcess = item.Paths.IsContentItem && item.TemplateID == _skuRootTemplateId && item.ID == new ID("{F37753A0-BC79-4FF7-B975-A8F142AACD76}");
return canProcess;
}
public override ID GetParentID(ItemDefinition itemDefinition, CallContext context)
{
var idTableEntries = IDTable.GetKeys(_idTablePrefix, itemDefinition.ID);
if (idTableEntries.Any())
{
return idTableEntries.First().ParentID;
}
return base.GetParentID(itemDefinition, context);
}
public override FieldList GetItemFields(ItemDefinition itemDefinition, VersionUri version, CallContext context)
{
var fields = new FieldList();
var idTableEntries = IDTable.GetKeys(_idTablePrefix, itemDefinition.ID);
if (idTableEntries.Any())
{
if (context.DataManager.DataSource.ItemExists(itemDefinition.ID))
{
ReflectionUtil.CallMethod(typeof(ItemCache), CacheManager.GetItemCache(context.DataManager.Database), "RemoveItem", true, true, new object[] { itemDefinition.ID });
}
var template = TemplateManager.GetTemplate(_skuTemplateId, Factory.GetDatabase(_targetDatabaseName));
if (template != null)
{
var skuId = GetSkuIdFromIdTable(itemDefinition.ID);
if (!string.IsNullOrEmpty(skuId))
{
var sku = _skus.FirstOrDefault(o => o.SkuId == skuId);
if (sku != null)
{
foreach (var field in GetDataFields(template))
{
fields.Add(field.ID, GetFieldValue(field, sku));
}
}
}
}
}
return fields;
}
protected virtual IEnumerable<TemplateField> GetDataFields(Template template)
{
return template.GetFields().Where(ItemUtil.IsDataField);
}
private string GetFieldValue(TemplateField field, SkuItemInfo sku)
{
string fieldValue = string.Empty;
switch (field.Name)
{
case "Name":
fieldValue = sku.Name;
break;
case "SkuId":
fieldValue = sku.SkuId;
break;
default:
break;
}
return fieldValue;
}
}
}
The problem emerges when accessing the Sitecore backend, where all items appears below the bucket item in a hierarchly-way.
I've checked that the Root item is set a bucket and that the template used is bucketable.
Furthermore when inserting manually in the backend, the item is correctly inserted in the bucket.
Do anyone got an idea for me, on how to fix this issue?
Best Regards
Nicolai
You need to set the Is Bucketable flag on the standard values of the template item rather than the template item itself.
Also, the way that items get "bucketed" is via events when the item is being created or saved. Sitecore then creates the bucket folders to store the items in. In your case as you have virtual items, you will need to handle their path via the data provider.
If you just want them hidden in the same way that they are in a standard bucket, then I would suggest creating a bucket folder under your SKU Root folder and using that item as the parent for all SKU virtual items. That way the bucket folder will be hidden by sitecore and you will get the same view as a standard bucket.
This is the template to use:

MVCxGridView Bind List<> with collection to column names

i have some task: I have a List that I pass in View from Controller, But this model in itself is a collection. How should I bind a column in the method of constructing?
c#:
public static void GridColumns(List<ParameterCollection> model, MVCxGridViewColumnCollection columns)
{
columns.Add(??????????);
}
View:
#model List<TFlex.DOCs.Model.Parameters.ParameterCollection>
#using TFlexDOCsWeb;
#Html.DevExpress().GridView(settings =>
{
settings.Name = "GridView";
//settings.ClientSideEvents.Init = "OnInit";
settings.KeyFieldName = "SystemFields.Id";
settings.SettingsBehavior.ConfirmDelete = true;
settings.CallbackRouteValues = new { Controller = "Catalogues", Action = "_GridViewPartial" };
settings.CommandColumn.Visible = true;
settings.CommandColumn.Caption = "*";
settings.CommandColumn.Width = System.Web.UI.WebControls.Unit.Percentage(5);
settings.SettingsPager.Visible = true;
settings.SettingsBehavior.AllowSelectByRowClick = false;
TFlexDOCsWeb.DevEx.GridViewBuilding.<bold>GridColumns</bold>(Model, settings.Columns);
var headerFilterMode = true ? HeaderFilterMode.CheckedList : HeaderFilterMode.List;
foreach (GridViewDataColumn column in settings.Columns)
column.Settings.HeaderFilterMode = headerFilterMode;
settings.Settings.ShowFilterRow = true;
settings.Settings.ShowFilterRowMenu = true;
}).Bind(Model).GetHtml()<bold>
</bold>
model ParameterCollection consist from , where parameter.Value = is value, and parameter.ParameterInfo = Caption of this parameter(name of field). I Dont know how to bind column names for each ParameterCollection Parameter.parameterInfo.name
You just bind it to the name of the property on the object(s) that your list holds in the column settings where you make your gridviewsettings.
See below simplified example.
MODEL
namespace Some.Name.Space
{
public class RecipientListViewModel : List<RecipientViewModel> // HOwever you define your list
{
}
public class RecipientViewModel
{
public string Id {get; set;}
public string FullName { get; set; }
}
}
VIEW
#Html.DevExpress().GridView(settings =>
{
//General settings
settings.Name = "GridViewName";
settings.KeyFieldName = "Id"; // actual parameter name of keyfield on your object that is in your list
//other settings etc
settings.Columns.Add(column =>
{
column.Name = "FullName"; // actual parameter name on your object that is in your list that you want on the column
column.FieldName = "FullName"; // actual parameter name on your object that is in your list that you want on the column
column.Caption = LanguageHelper.GetText("UserConfig_Recipients_RecipientNameHeader");
//column.Width = System.Web.UI.WebControls.Unit.Pixel(200);
});
//other columns etc
}).Bind(YourModel).GetHtml()
CONTROLLER
public ActionResult Overview()
{
RecipientListViewModel model = PopulateInformationView(); // Populates the list with data
return View("YOURVIEWNAME", model);
}

using a viewmodel to assign values from a soap web service to a dropdownlist

I need some advice on getting values from a soap web service to display in a dropdownlist using a viewmodel, I currently receive the data for the various dropdownlists from a service class found in a service class library project (n-tier application).
The code for the dropdownlist service follows a similar format to the code below:
public IEnumerable<SelectListItem> getValuesAsSelectItems(string selected)
{
var items = new List<SelectListItem>();
items.Add(new SelectListItem { Text = "Please Select", Value = string.Empty, Selected = (selected == string.Empty) });
foreach (var value in this.getValues())
{
items.Add(new SelectListItem { Text = value.Value, Value = value.Value, Selected = (selected == value.Value) });
}
return new SelectList(items, "Value", "Text");
}
I need a way of passing the values from this service to the viewmodel I have then created 7 controllers for each of the dropdownlist which will all link to partial views that I can reuse throughout the application, dropdownlists include titles, countries, states and others.
An approach you could take is to extract the drop down list values into a viewmodel of their own. So:
Step 1: Create a view model (ItemsViewModel) that encapsulates the drop down list items:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Models
{
public class DropDownListItem
{
public string Text { get; set; }
public string Value { get; set; }
}
public class ItemsViewModel
{
private readonly List<DropDownListItem> _items;
// The selected item:
public string SelectedItem { get; set; }
// The items:
public IEnumerable<SelectListItem> Items
{
get
{
var allItems = _items.Select(i => new SelectListItem
{
Value = i.Value,
Text = i.Text
});
return DefaultItem.Concat(allItems);
}
}
// Default item (i.e. the "select" text) if none selected
public IEnumerable<SelectListItem> DefaultItem
{
get
{
return Enumerable.Repeat(new SelectListItem
{
Value = "-1",
Text = "Select an item"
}, count: 1);
}
}
public ItemsViewModel()
{
}
// Constructor taking in items from service and selected item string:
public ItemsViewModel(List<DropDownListItem> items, string selected)
{
_items = items;
SelectedItem = selected;
}
}
}
Step 2: Create a partial view in the Views folder that binds to the ItemsViewModel:
#model Models.ItemsViewModel
#Html.DropDownListFor(m => m.SelectedItem, Model.Items)
Step 3: In the appropriate controller (e.g. HomeController), place the child action that pulls the data from the service, the view model and the partial view together:
[ChildActionOnly]
public ActionResult DropDownList(string type, string selected)
{
// If you need to call different services based on the type (e.g. Country), then pass through "type" and base the call on that
var items = new ItemsViewModel(
(from g in _service.getTitles() select new DropDownListItem { Text = g.Text, Value = g.Value }).ToList(),
selected);
return PartialView("DropDownPartial", items);
}
Step 4: Drop this line of code into the view where you need the drop down list:
#Html.Action("DropDownList", "Home", new { selected = "2", type = "country" })
Note that selected and type are to be determined whichever way you see fit and are optional.
Hopefully this gives you some inspiration.