C# NetSuite WebServices: Get value from custom field in saved search (ItemSearchAdvanced) - c#

I'm using C# MVC to connect to NetSuite using their WebServices API. I have some current code that calls a saved search of inventory items. Here is the current code that is working perfectly:
ItemSearchAdvanced searchItems = new ItemSearchAdvanced();
searchItems.savedSearchId = "128";
SearchResult result = netSuiteSvc.search(searchItems);
int totalRecords = 0;
int processedRecords = 0;
UpdateNetsuitePriceListModel returnObj = new UpdateNetsuitePriceListModel();
returnObj.NewPriceList = new List<NetSuitePriceListRecord>();
if (result.status.isSuccess)
{
SearchRow[] searchRows = result.searchRowList;
if (searchRows != null && searchRows.Length >= 1)
{
for (int i = 0; i < searchRows.Length - 1; i++)
{
ItemSearchRow itemRow = (ItemSearchRow)searchRows[i];
if (itemRow.basic.itemId != null && itemRow.basic.mpn != null && itemRow.basic.basePrice != null && itemRow.basic.salesDescription != null)
{
returnObj.NewPriceList.Add(new NetSuitePriceListRecord()
{
ItemId = itemRow.basic.itemId[0].searchValue,
ManufacturerPartNumber = itemRow.basic.mpn[0].searchValue,
ContractPrice = Convert.ToDecimal(itemRow.basic.basePrice[0].searchValue),
Cost = CalculateProductCostForIngram(Convert.ToDecimal(itemRow.basic.basePrice[0].searchValue)),
Description = itemRow.basic.salesDescription[0].searchValue
});
processedRecords++;
}
totalRecords++;
}
}
else
{
throw new Exception("NetSuite Part List Blank");
}
}
else
{
throw new Exception("NetSuite Part List Search Failure");
}
Now I have need to pull the itemId from a custom added field rather than the default itemId field.
Obviously since this is a custom field it isn't a property of ItemSearchRowBasic. It looks like instead of the property I can choose "customFieldList" which is an array of "SearchColumnCustomField". If I choose an index for the array I can see that SearchColumnCustomField contains:
customLabel
internalId
scriptId
I imagine I should be able to get the internalId of the SearchColumnCustomField and somehow use that to get the search value for that custom column but I've had some trouble finding any examples that fit so far.
This custom field is a free form text field added to all inventory items.

Try setting scriptId with the ID of the field ("custitem_xyz"). That should work.
Before 2013 one would use internalId, but since then it changed to scriptId.

You would need to loop over the CustomRecord items in the customFieldList. I then usually check for a specific type so I can cast to the correct object, but with some reflection you could probably avoid that.
foreach (Record r in mySearchResponse.recordList){
foreach (CustomFieldRef cr in ((CustomRecord)r).customFieldList){
if (cr.GetType().Name == "SelectCustomFieldRef"){
if (((SelectCustomFieldRef)cr).scriptId == "my_custom_field"){
internalID = ((CustomRecord)r).internalId;
}
}
}
}

Related

if else if for multiple possible values for a variable C#

I have a if-else if construct where in I am setting a particular value of a variable based on the XName Element local name as follows:
public struct UserObject
{
public string rawValue;
}
var xmlElements= record.Descendants("abc")
.Select(x => x.Elements().ToArray());
foreach (XElement[] elements in xmlElements)
{
foreach (XElement element in elements)
{
UserObject userObject = new UserObject();
if (element.Name.LocalName == "b036") //"b036" is a XML element tag name
userObject.rawValue = (element.Value.Trim()); //note rawvalue is of string type
else if (element.Name.LocalName == "b037")
userObject.rawValue = (element.Value.Trim());
else if (element.Name.LocalName == "b040")
userObject.rawValue = (element.Value.Trim());
}
For the name of the userObject(rawvalue) to load I want to follow this hierarchical order :-
b036, PersonName (e.g., John Smith) if not available use b037
b037, PersonName (e.g., Smith, John) if not available use b040
b040, KeyNames, a.k.a Last Name (e.g., Smith)
If none of b036, b037 or b040 are found, I do not want to set the "rawvalue" for that record
How can I construct my if-else statements or should I use switch case statements to achieve the same?
Since you want to find the value for the highest of certain elements, do a max search. By rolling your own, you avoid having to scan or test twice.
First, create a variable to represent the precedence of the interesting names:
var hierarchy = new[] { "b040", "b037", "b036" };
Now setup some variables to remember the maximum candidate found so far:
XElement candidate = null;
int candidatePos = -1;
Finally, go through all the XMLElement values and remember the maximum found:
foreach (var element in xmlElements.SelectMany(elements => elements)) {
var pos = Array.IndexOf(hierarchy, element.Name.LocalName);
if (pos >= 0) {
if (candidate == null || pos > candidatePos) {
candidate = element;
candidatePos = pos;
}
}
}
If you found a maximum, you can work with it:
if (candidate != null) { //"b036" is a XML element tag name
UserObject userObject = new UserObject();
userObject.rawValue = (candidate.Value.Trim()); //note rawvalue is of string type
// work with userObject
}

Amazon DynamoDB store list of custom objects

I'm using Amazon DynamoDB for the first time (and it is awesome). I am working with my the object persistence model so I'm using my own objects to send back and forth. This is working great on my primitive properties (strings, etc.). However I also have a property that is a list of other custom objects that I would like to store and I can't get that to commit to the DB. It's a list of custom objects; each object has a few primitive properties and another list of custom objects (and these have only primitives on them). I found this:
http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ArbitraryDataMappingHLAPI.html
and have tried to copy it but can't get it to work. I also found this on storing maps:
http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DataModel.html#DataModel.DataTypes
but that doesn't really seem to work directly with objects unless I'm missing something. Anyway here is the converter I came up with:
public class AwsCommentConverter : IPropertyConverter
{
public object FromEntry(DynamoDBEntry entry)
{
PrimitiveList primList = entry as PrimitiveList;
if (primList == null)
{ throw new ArgumentOutOfRangeException(); }
List<CommentVM> comments = new List<CommentVM>();
foreach (string s in primList.AsListOfString())
{
string[] vals = s.Split(new string[] { "$~$" }, StringSplitOptions.None);
if (vals.Length < 3) throw new ArgumentOutOfRangeException();
List<StatusUpdate> updates = new List<StatusUpdate>();
for (int i = 2; i < vals.Length; i++)
{
string[] udVals = vals[i].Split(new string[] { "###" }, StringSplitOptions.None);
if (udVals.Length != 4) throw new ArgumentOutOfRangeException();
StatusUpdate ud = new StatusUpdate()
{
StatusType = (StatusUpdate.StatusUpdateType)Enum.Parse(typeof(StatusUpdate.StatusUpdateType), udVals[0]),
StatusDate = DateTime.FromFileTime(long.Parse(udVals[1])),
UserName = udVals[2],
NewValue = udVals[3]
};
updates.Add(ud);
}
comments.Add(new CommentVM(vals[0], vals[1], updates));
}
return comments;
}
public DynamoDBEntry ToEntry(object value)
{
List<CommentVM> comments = value as List<CommentVM>;
List<Primitive> storageVals = new List<Primitive>();
if (comments == null) throw new ArgumentOutOfRangeException();
foreach (CommentVM cm in comments)
{
string dta = cm.ID + "$~$" + cm.CommentText + "$~$";
foreach (StatusUpdate ud in cm.StatusLog)
{ dta += ud.StatusType.ToString() + "###" + ud.StatusDate.ToFileTime().ToString() + "###" + ud.UserName + "###" + ud.NewValue + "$~$"; }
if (dta.EndsWith("$~$"))
{ dta = dta.Substring(0, dta.Length - 3); }
storageVals.Add(new Primitive() { Value = dta });
}
return new PrimitiveList() { Entries = storageVals };
}
}
Here is the property declaration:
[DynamoDBProperty(typeof(AwsCommentConverter))]
public List<CommentVM> Comments
I set a break point in the converter and it never seems to get hit which leads me to believe I've messed up setting it up, but I'm not sure how... Can anyone tell me how to get this stored and retrieved?
Ok I think I figured it out. The property is read only and apparently that means it is skipped? It's a list and it doesn't have a setter because the list is constructed on object creation and the list object itself should not really be replaced, although the contents of the list are modified frequently (hence the need to store them in the db).
I added a setter and now it works with the object persistence model and my custom converter...

Trouble with adding values to a multivalue cookie

So I'm trying to make a multivalued cookie that keeps track how many times an specific category is visited on the site.
So I was thinking to make a multivalued cookies where a category is added as key and the value is the amount of times visited.
But for some reason it only creates the cookie but doesn't add a key, value pair.
Here is the code:
String categorie = GetCategorie();
if (Request.Cookies["UserInteresse"] == null)
{
UserInteresse = new HttpCookie("UserInteresse");
Response.Cookies["UserInteresse"]["Favoriet"] = "Geen";
}
else
{
UserInteresse = Request.Cookies["UserInteresse"];
}
if (Request.Cookies["UserInteresse"][categorie] == null)
{
Response.Cookies["UserInteresse"][categorie] = "0";
}
else
{
Response.Cookies["UserInteresse"][categorie]=
Convert.ToInt32(Request.Cookies["UserInteresse"][categorie]) + 1.ToString();
}
Response.Cookies.Add(UserInteresse);
So this code checks first if the cookie exists, if not it will create one with a value to keep track which category is visited the most.
And then it will check if a category as visited before, if not it will add it to the list, if it was visited before its number should be incremented with one.
Everthing is written in ASP.NET (c#)
The code does compile, but when I check the cookie or print out the valuelist I get nothing
I found the answer myself after a long search. I found other ways to add values a cookies, I rewrote my code and now it works beautifull.
Here is the new code
categorie = GetCategorie();
if (Request.Cookies["UserInteresse"] == null)
{
UserInteresse = new HttpCookie("UserInteresse");
Response.Cookies.Add(UserInteresse);
Response.Cookies["UserInteresse"]["Favoriet"] = "Geen";
}
else
{
UserInteresse = Request.Cookies["UserInteresse"];
}
if (Request.Cookies["UserInteresse"][categorie]==null)
{
UserInteresse.Values.Add(categorie,"0");
}
else
{
int nieuwaantal = Convert.ToInt32(Request.Cookies["UserInteresse"][categorie]) + 1;
UserInteresse.Values.Remove(categorie);
UserInteresse.Values.Add(categorie, nieuwaantal.ToString());
if (Convert.ToInt32(Request.Cookies["UserInteresse"][categorie]) >= 7 &&
(Request.Cookies["UserInteresse"]["Favoriet"].Equals("Geen")||Convert.ToInt32(Request.Cookies["UserInteresse"][categorie]) >
Convert.ToInt32(Request.Cookies["UserInteresse"][Request.Cookies["UserInteresse"]["Favoriet"]])))
{
UserInteresse.Values.Remove("Favoriet");
UserInteresse.Values.Add("Favoriet", categorie);
}
}
Response.Cookies.Add(UserInteresse);
}

Use a numeric value in a linq dynamic query string

I am trying to make a dynamic linq query that will check for values based on a string.
First of all, here's the query:
objQry = from o in m_Db.OBJECTS.Where(whereConditions)
select o;
if(!objQry.Any())
{
return null;
}
The whereConditions variable is a string I build and pass as parameter to find out the values I need. Here's examples of valid string:
OBJ_NAME == \"Sword\" and OBJ_OWNER == \"Stan\"
This will return any item whose name is "Sword" and owner is "Stan;
OBJ_COLOR == \"Blue\" OR OBJ_COLOR == \"Red\"
This will return any item which color is either blue or red.
Up to there, I'm fine, but now I have a problem: I need to check a decimal field. So I've tried this string:
OBJ_NUMBER == 1
But the query returns null even if there are objects which OBJ_NUMBER value is 1. It's a decimal. How can I indicate the query that they need to check for a decimal value?
**** EDIT ****
I have tried to "modify" the value passed so that it looks like this:
"CARD_NUMBER == Convert.ToDecimal(1)"
And now I have a different kind of error telling me this:
LINQ to Entities does not recognize the method 'System.Decimal ToDecimal(Int32)' method, and this method cannot be translated into a store expression.
Any clues anyone? I'm still looking for a way to do this. Thanks!
EDIT 2
You can get an example of how my code is shaped by looking at this question.
Let's come back at this problem. I want to check decimal values. Let's say that OBJ_NUMBER is a decimal field.
Using Dynamic Linq, I tried to read the decimal field. Say that I want to get each object which number is 1.27. The whereConditions field would then be shaped like this:
OBJ_NUMBER == 1.27
But then I would get an Invalid real literal '1.27' error. I don't know why.
So I have tried Gert Arnold's solution and done this instead:
decimal bDecimal = decimal.Parce(valueToParse);
param = new ObjectParameter("cardNumber", typeof(decimal)) { Value = bDecimal };
valuesToUse.Add("CARD_NUMBER == #cardNumber");
listParams.Add(param);
But I ended up having 2 problems:
The first problem is that my whereConditions string is shaped this way:
CARD_NUMBER == #cardNumber
But I get the following error:
No property or field 'cardNumber' exists in type 'CARD'
Leading me to believe that it cannot make the link between the object parameter and the string used to do the query.
As you can see, I have a list of Params. This is because I cannot know for sure how many parameters the user will chose. So each time the user enters a new search field, I have to create a new ObjectParameter and store it in a list. Here's how I try to do the thing after:
ObjectParameter[] arrayParameters = listParams.ToArray();
// Convert the list to an array
And then, when I try to make the query:
cardQry = from c in mDb.CARD.Where(whereConditions, arrayParameters)
select c;
But to no avail.
RESULTS
Based on the answered question below, I have developped something "awful", yet functional.
First of all, I ignore every decimal fields because I could never reach them with dynamic linq. Instead, I do this:
var valuesToParse = keyValuePair.Value.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries);
// Here I parse the value and, if that's the case, the symbol.
decimal baseValue = decimal.Parse(valuesToParse[0]);
if (valuesToParse.Count() > 1)
{
string baseMethod = valuesToParse[1];
if (baseMethod == ">" || baseMethod == ">=")
{
if (baseMethod == ">=")
{
baseValue--;
}
// The list is actually like this: Dictionary<string, object> list = new Dictionary<string, object>();
list.Add("low", baseValue);
// I kind of activate a tag telling me that the user is looking for a higher value.
cardHigher = true;
}
else
{
if (baseMethod == "<=")
{
baseValue++;
}
list.Add("low", baseValue);
cardLower = true;
}
}
else
{
//lowParam = new ObjectParameter("dec", typeof(decimal)) { Value = baseValue };
list.Add("low", baseValue);
}
cardNumberActivated = true;
At the end, when I get the list of objects, I do this:
if (list.Count > 0)
{
(example)
if (cardNumberActivated)
{
if (cardHigher)
{
q = mDb.CARD.Where("CARD_NUMBER >= #0", list["low"]).ToList();
}
else if (cardLower)
{
q = mDb.CARD.Where("CARD_NUMBER <= #0", list["low"]).ToList();
}
else
{
q = mDb.CARD.Where("CARD_NUMBER == #0", list["low"]).ToList();
}
}
}
// Here we get the orinalData with the basic filters.
listToReturn.AddRange(cardQry);
if (q != null)
{
//listToReturn.AddRange(q);
for (int i = 0; i < listToReturn.Count; i++)
{
var priceList1 = listToReturn[i];
if (!q.Any(_item => _item.CARD_NUMBER == priceList1.CARD_NUMBER))
{
listToReturn.RemoveAt(i);
i--;
}
}
}
And it works. This is not an elegant way to make it work, but I can validate the fields the way I wanted, and for this, I am thankful at last.
You should not build a query string with inline predicate values. Use parameters in stead. Then will also be able to specify the type:
var whereConditions= "it.CARD_NUMBER = #cardNumber";
var param = new ObjectParameter("cardNumber", typeof(decimal)) { Value = 1 };
objQry = from o in m_Db.OBJECTS.Where(whereConditions, param);
Edit
I don't know what doesn't work in your code. Here's just a random piece of working code derived from one of my own projects:
var param1 = new ObjectParameter("dec", typeof(decimal)) { Value = 90000m };
var param2 = new ObjectParameter("int", typeof(int)) { Value = 90000 };
var q = ValueHolders.Where("it.DecimalValue >= #dec OR it.IntegerValue > #int",
param1, param2).ToList();
Note that param1, param2 could also be an array of ObjectParameter.

Get index with value in Checked List Box

I am actually finding that chkContactType.Items is empty when I step through the code. I even added a Watch to chkContactType.Items.Count and it is never anything but 0. I am severly confused now as it obviously isn't as my Insert method works fine which uses these same boxes and inserts the Value Member for each item....
I have some checked list box controls that I need to set the CheckState based on the item value as that is what is stored in the DB for an exsiting record. Unfortunately, I only see a way to set this by index which is not stored. The index is local to the control so, for example, control ContactType has 15 items in it. Index is 0-14. Item Value is 39,40,41,42,43,44,45,46,47,48,49,50,2077,2078,2079 respectively. How can I either get the index value with the Value Member value OR set the checkstate of each returned item with the Value Member value?
Thanks
private void PaintDetails(Guid cNoteID)
{
var cNoteDetailDT = CurrentCaseNote.GetCNoteDetail(cNoteID);
LoadCaseNoteDetailData(cNoteDetailDT.Rows[0]);
// Load Contact Type Data for this CaseNote
// contactTypeDT returns ItemID of chk items
// that were checked for this Guid
using (var contactTypeDT = CurrentCaseNote.GetCNoteContactType(cNoteID))
{
if (contactTypeDT.Rows.Count > 0)
foreach (DataRow row in contactTypeDT.Rows)
{
LoadContactTypeData(row);
}
}
}
private void LoadContactTypeData(DataRow row)
{
// This does not work
var theItem = row["ItemID"].ToString();
// itemIndex always ends up set to -1
var itemIndex = chkContactType.Items.IndexOf(theItem);
chkContactType.SetItemChecked((int) itemIndex, true);
// This works I just need to supply the correct index
chkContactType.SetItemChecked(0,true);
}
EDIT in response to comment
This is how I populate the Checked ListBox. I know there is a "magic number" there. I am working on it. It relates to the CategoryID in the DB of ContactType.
// Contact Type Check List Box
chkContactType.DataSource = CurrentCaseNote.GetMaintItems(1);
chkContactType.DisplayMember = "ItemDescription";
chkContactType.ValueMember = "ItemID";
and then CurrentCaseNote BLL(kinda)-->
public static DataTable GetMaintItems(int iCat)
{
IQueryable<tblCaseNotesMaintItem> tItems = CaseNoteDAL.GetCNTable();
return (tItems.Where(item => item.CategoryID == iCat & item.IsActive).OrderBy(
item => item.OrderID).Select(item => new {item.ItemID, item.ItemDescription})).CopyLinqToDataTable();
}
and finally the DAL -->
public static Table<tblCaseNotesMaintItem> GetCNTable()
{
return dcCaseNotes.GetTable<tblCaseNotesMaintItem>();
}
EDIT 2
This is what my code NOW looks like but still no go. It is like ItemCount is never populated....
// Load Contact Type Data for this CaseNote
using (var contactTypeDT = CurrentCaseNote.GetCNoteContactType(cNoteID))
{
if (contactTypeDT.Rows.Count > 0)
foreach (DataRow row in contactTypeDT.Rows)
{
LoadContactTypeData(row);
}
}
}
private void LoadContactTypeData(DataRow row)
{
// This does not work
var theItem = row["ItemID"];
for (int i = 0; i < chkContactType.ItemCount; i++)
{
if(theItem == chkContactType.GetItemValue(i))
chkContactType.SetItemChecked(i,true);
}
}
This seems to work:
int index = checkedListBox1.Items.IndexOf("42");
checkedListBox1.SetItemChecked(index, true);
For j As Integer = 0 To chklst_distributorlist.Items.Count - 1
If chklst_distributorlist.GetItemText(chklst_distributorlist.Items.Item(j)) = ds1.Tables(0).Rows(0)("suppliername").ToString Then
chklst_distributorlist.SetSelected(j, True)
chklst_distributorlist.SetItemCheckState(j, CheckState.Checked)
End If
Next
I also faced the same issue.
The index of checkedListBox1.Items.IndexOf("value"); is always -1.
I managed to get the index using following code.
for (int i = 0; i < checkedListBox1.Items.Count; i++)
{
if (((System.Data.DataRowView)(checkedListBox1.Items[i])).Row.ItemArray[0].ToString() == "Value")
checkedListBox1.SetItemCheckState(i, CheckState.Checked);
}

Categories

Resources