create NetSuite ItemFulfillment containg items with lot/serial info - c#

I am using SuiteTalk web services (v. 2013_2) . I am trying to create an ItemFulfillment where the items in it were related to items that had a lot or serial number.
When I try to save this item fulfillment into NetSuite I get an error of :
Please commit inventorydetail on this line.
I was attempting to set the itemFulfillment.serialNumbers and itemFulfillment.binNumbers when I create the itemFulfillmentItem.
For example I set
nsIfItem.serialNumbers = "SNum(5)"
nsIfItem.binNumbers = "BNum(5)"
based on those properties being- A comma delimited list of serial or LOT numbers. If entering serial numbers there must be a number for each item.
Lot numbers must be entered in a format of LOT#(Quantity).
For example, to enter a quantity of 100 items as Lot number ABC1234, enter ABC1234(100).
Do I also need to set something else on the itemFulfillment or how do I get rid of that error.

I'm not sure if this question is still active, but I had the same issue and iI couldn't find much help on it. I solved this issue by creating the inventory assignment objects and adding to the transaction.
First, create the initialize ref for Item Fulfillment and assign the returned record to a variable:
InitializeRecord ir = new InitializeRecord();
ir.type = InitializeType.itemFulfillment;
InitializeRef iref = new InitializeRef();
iref.typeSpecified = true;
iref.type = InitializeRefType.salesOrder;
iref.internalId = 'Sales Order internalID';
ir.reference = iref;
ReadResponse getInitResp = _service.initialize(ir);
ItemFulfillment ifrec = (ItemFulfillment)getInitResp.record;
Get the list of items on the initialized transaction:
ItemFulfillmentItemList ifitemlist = ifrec.itemList;
Create a list to which to add each unique item being fulfilled:
List<ItemFulfillmentItem> ifitems = new List<ItemFulfillmentItem>();
Run the following code for each item in initialized transaction's item list:
If the current line item has already been added to the ifitems list, add the current Fulfillment line as an assignment to that item:
InventoryAssignment assignment = new InventoryAssignment
{
issueInventoryNumber = new RecordRef { internalId = 'internalID',
type = 'RecordType',
typeSpecified = true
}
};
List<InventoryAssignment> list = new List<InventoryAssignment>();
list.Add(assignment);
ifitemlist.item[b].inventoryDetail = new InventoryDetail
{
inventoryAssignmentList = new InventoryAssignmentList
{
inventoryAssignment = list.ToArray()
}
};
ifitemlist.item[b].quantity += 'quantity shipped';
If the line item has not yet been added, create new line item:
ItemFulfillmentItem ffItem = new ItemFulfillmentItem();
ffItem.item = ifitemlist.item[b].item;
ffItem.itemReceive = true;
ffItem.itemReceiveSpecified = true;
ffItem.itemIsFulfilled = true;
itemIsFulfilled = true;
ffItem.itemIsFulfilledSpecified = true;
ffItem.orderLineSpecified = true;
ffItem.orderLine = ifitemlist.item[b].orderLine;
//Check if serialized
if (Your fulfillment item contains serialized data)
{
ffItem.serialNumbers = 'Serial numbers';
InventoryAssignment assignment = new InventoryAssignment
{
issueInventoryNumber = new RecordRef {
internalId = 'Inventory internal ID',
type = RecordType,
typeSpecified = true
}
};
ffItem.inventoryDetail = new InventoryDetail
{
inventoryAssignmentList = new InventoryAssignmentList
{
inventoryAssignment = new InventoryAssignment[]
{
assignment
},
replaceAll = false
},
nullFieldList = new string[] { },
customForm = new RecordRef { }
};
}
ffItem.quantity = 'QUANTITY SHIPPED';
ffItem.quantitySpecified = true;
ifitems.Add(ffItem);
Finally, add your "ifitems" list to your Item Fulfillment and add this to NetSuite:
ItemFulfillmentItemList ifitemlistToFulfill = new ItemFulfillmentItemList();
ifitemlistToFulfill.replaceAll = false;
ifitemlistToFulfill.item = ifitems.ToArray();
ItemFulfillment newItemFulfill = new ItemFulfillment();
newItemFulfill.itemList = ifitemlistToFulfill;
_service.add(newItemFulfill);

Related

Passing multiple line items with GP webservice

Below is the code I'm working with to pass multiple line items to create sales order through GP Web service. I can pass single Line Item without any problem , but when I pass multiple Items it is only taking the last one. The array has around 5 Item ID and I'm passing fixed Quantity as 15, Need to make both dynamic. But for the testing purpose I'm trying like this. I know the problem with the creation/initialization of some web service objects. As novice to the entire set of things I couldn't find the exact problem.
C# Code
CompanyKey companyKey;
Context context;
SalesOrder salesOrder;
SalesDocumentTypeKey salesOrderType;
CustomerKey customerKey;
BatchKey batchKey;
// SalesOrderLine salesOrderLine;
ItemKey orderedItem;
Quantity orderedAmount;
Policy salesOrderCreatePolicy;
DynamicsGPClient wsDynamicsGP = new DynamicsGPClient();
wsDynamicsGP.ClientCredentials.Windows.ClientCredential.UserName = "Admin";
wsDynamicsGP.ClientCredentials.Windows.ClientCredential.Password = "pass";
wsDynamicsGP.ClientCredentials.Windows.ClientCredential.Domain = "Gp";
System.ServiceModel.WSHttpBinding binding;
binding = new System.ServiceModel.WSHttpBinding(System.ServiceModel.SecurityMode.None);
context = new Context();
companyKey = new CompanyKey();
companyKey.Id = (1);
context.OrganizationKey = (OrganizationKey)companyKey;
salesOrder = new SalesOrder();
salesOrderType = new SalesDocumentTypeKey();
salesOrderType.Type = SalesDocumentType.Order;
salesOrder.DocumentTypeKey = salesOrderType;
customerKey = new CustomerKey();
customerKey.Id = "121001";
salesOrder.CustomerKey = customerKey;
batchKey = new BatchKey();
batchKey.Id = "RMS";
salesOrder.BatchKey = batchKey;
// SalesOrderLine[] orders = new SalesOrderLine[6];
SalesOrderLine[] lines = { };
for (int i = 1; i < 5; i++)
{
SalesOrderLine salesOrderLine = new SalesOrderLine();
orderedItem = new ItemKey();
orderedItem.Id = Arr[i].ToString();
salesOrderLine.ItemKey = orderedItem;
orderedAmount = new Quantity();
orderedAmount.Value = 15;
salesOrderLine.Quantity = orderedAmount;
lines = new SalesOrderLine[] { salesOrderLine };
MessageBox.Show(lines.Count().ToString());
}
salesOrder.Lines = lines;
//salesOrder.Lines = orders;
salesOrderCreatePolicy = wsDynamicsGP.GetPolicyByOperation("CreateSalesOrder", context);
wsDynamicsGP.CreateSalesOrder(salesOrder, context, salesOrderCreatePolicy);
if (wsDynamicsGP.State != CommunicationState.Faulted)
{
wsDynamicsGP.Close();
}
MessageBox.Show("Success");
lines = new SalesOrderLine[] { salesOrderLine }; will recreate the lines array object each time meaning you loose any previously added objects. Effectively only the final object in the loop is actually added.
Try using a List<T> like so:
SalesOrderLine[] lines = { }; Becomes List<SalesOrderLine> lines = new List<SalesOrderLine>();
lines = new SalesOrderLine[] { salesOrderLine }; Becomes: lines.Add(salesOrderLine);
If its important you end up with an array as the input:
salesOrder.Lines = lines; Becomes: salesOrder.Lines = lines.ToArray();

NetSuite SuiteTalk: Search Filter with Custom Field Type

I am pulling my hair out on this one. I am attempting to filter a saved search with a custom field of type SearchColumnSelectCustomField (see XML of record below).
How do I convert this type properly, or what am I doing wrong here?
I'm not sure what I'm missing, but the error I always eventually hit is:
"Cannot implicitly convert type
'NetSuite.com.netsuite.na1.webservices.SearchColumnSelectCustomField'
to 'NetSuite.com.netsuite.na1.webservices.SearchCustomField'
"
TransactionSearchAdvanced transSearchAdv = new TransactionSearchAdvanced
{
savedSearchScriptId = "customsearch_mycustomsearch"
};
SearchColumnSelectCustomField cwoNumField = new SearchColumnSelectCustomField();
cwoNumField.internalId = "custbody_consolidatedworkorder";
transSearchAdv.criteria = new TransactionSearch
{
basic = new TransactionSearchBasic
{
//Error Here, on cwoNumField
customFieldList = new SearchCustomField[]{ cwoNumField }
}
};
XML of search results, without filter criteria added:
<tranSales:basic xmlns:platformCommon="urn:common_2014_1.platform.webservices.netsuite.com">
<platformCommon:appliedToTransaction>
<platformCore:searchValue internalId="442671"/>
<platformCore:customLabel>SO #</platformCore:customLabel>
</platformCommon:appliedToTransaction>
<platformCommon:item>
<platformCore:searchValue internalId="315838"/>
</platformCommon:item>
<platformCommon:quantity>
<platformCore:searchValue>11.0</platformCore:searchValue>
</platformCommon:quantity>
<platformCommon:status>
<platformCore:searchValue>pendingBuild</platformCore:searchValue>
</platformCommon:status>
<platformCommon:transactionNumber>
<platformCore:searchValue>204</platformCore:searchValue>
<platformCore:customLabel>WO #</platformCore:customLabel>
</platformCommon:transactionNumber>
<platformCommon:customFieldList>
<platformCore:customField xsi:type="platformCore:SearchColumnBooleanCustomField" scriptId="custbody_buildcomplete" internalId="501">
<platformCore:searchValue>false</platformCore:searchValue>
</platformCore:customField>
/*********** field in question here *************/
<platformCore:customField xsi:type="platformCore:SearchColumnSelectCustomField" scriptId="custbody_consolidatedworkorder" internalId="500">
<platformCore:searchValue typeId="85" internalId="24"/>
<platformCore:customLabel>CWO #</platformCore:customLabel>
</platformCore:customField>
</platformCommon:customFieldList>
</tranSales:basic>
I'm not sure WHY, but this is the answer. Can someone explain why a SearchColumnSelectCustomField field is searched via SearchMultiSelectCustomField ?
TransactionSearchAdvanced transSearchAdv = new TransactionSearchAdvanced
{
savedSearchScriptId = "customsearch_woconsolidationsublist"
};
SearchMultiSelectCustomField cwoNumField = new SearchMultiSelectCustomField();
cwoNumField.scriptId = "custbody_consolidatedworkorder";
cwoNumField.#operator = SearchMultiSelectFieldOperator.anyOf;
cwoNumField.operatorSpecified = true;
cwoNumField.searchValue = new ListOrRecordRef[] { new ListOrRecordRef {internalId = "36"} };
transSearchAdv.criteria = new TransactionSearch
{
basic = new customFieldList = new SearchCustomField[] { cwoNumField }
}
};

Add and remove Ektron content items from taxonomies? (C#)

I have content items stored in Ektron that are assigned to taxonomies. I'm trying to create a method that will allow me to programmatically change the taxonomies. So far I find the content item by ID, and I'm able to retrieve its taxonomies, but I'm not sure how to change them.
var ektronItem = contentManager.GetItem((long) item.tctmd_id);
if (ektronItem != null) // item exists in Ektron
{
var newTaxonomies = item.taxonomy_ids;
var taxonomyAPI = new Taxonomy();
var taxData = taxonomyAPI.ReadAllAssignedCategory(ektronItem.Id);
foreach (var tax in taxData)
{
taxonomyAPI.RemoveTaxonomyItem(???);
// here I'm trying to remove the content item from the taxonomy
}
}
taxonomyAPI.RemoveTaxonomyItem() takes a Ektron.Cms.TaxonomyRequest object, but I'm not sure how to create this. I'm also not sure if this is even the method I should be using.
In case anyone else wants to know how to do this, here's the solution I came up with:
var contentManager = new Ektron.Cms.Framework.Content.ContentManager();
var criteria = new Ektron.Cms.Content.ContentCriteria(ContentProperty.Id, EkEnumeration.OrderByDirection.Ascending);
criteria.AddFilter(ContentProperty.FolderId, CriteriaFilterOperator.EqualTo, toUpdate.folder_id);
criteria.OrderByDirection = Ektron.Cms.Common.EkEnumeration.OrderByDirection.Descending;
criteria.OrderByField = Ektron.Cms.Common.ContentProperty.GoLiveDate;
criteria.FolderRecursive = true;
criteria.PagingInfo = new Ektron.Cms.PagingInfo(50, 1);
var ektronItem = contentManager.GetItem((long) item.tctmd_id);
if (ektronItem != null) // item exists in Ektron
{
// update taxonomy in Ektron
var taxIds = item.taxonomy_ids;
var taxonomyAPI = new Taxonomy();
var taxData = taxonomyAPI.ReadAllAssignedCategory(ektronItem.Id);
var taxManager = new Ektron.Cms.Framework.Organization.TaxonomyItemManager();
var taxCriteria = new TaxonomyItemCriteria();
// create a taxonomy criteria of the item ID
taxCriteria.AddFilter(TaxonomyItemProperty.ItemId, CriteriaFilterOperator.EqualTo, item.tctmd_id);
// get all taxonomy items with item ID
var taxItems = taxManager.GetList(taxCriteria);
// determine taxonomyItemType
var type = taxItems.FirstOrDefault().ItemType;
foreach (var tax in taxData)
{
// delete from old taxonomies
taxManager.Delete(tax.Id, (long)item.tctmd_id, type);
}
foreach (var tax in taxIds)
{
// add to new taxonomies
var taxonomyItemData = new TaxonomyItemData()
{
TaxonomyId = tax,
ItemType = type,
ItemId = (long)item.tctmd_id
};
try
{
taxManager.Add(taxonomyItemData);
}
catch (Exception ex)
{
}
}
}

List items on eBay API with best offer enabled

So far I have been trying to list items on ebay and allow Best Offers items.
I have tried this:
if (_eBayListingUtility.AllowBestOffer)
{
item.BestOfferEnabled = true;
item.BestOfferEnabledSpecified = true;
item.BestOfferDetails = new BestOfferDetailsType
{
BestOfferEnabled = true,
BestOfferEnabledSpecified = true,
};
item.ListingDetails = new ListingDetailsType
{
MinimumBestOfferMessage = _eBayListingUtility.MinimumBestOfferMessage,
MinimumBestOfferPrice = new AmountType
{
currencyID = CurrencyUtility.GetDefaultCurrencyCodeType(_context.Site),
Value = (double)_eBayListingUtility.MinimumBestOffer
},
BestOfferAutoAcceptPrice = new AmountType
{
currencyID = CurrencyUtility.GetDefaultCurrencyCodeType(_context.Site),
Value = (double)_eBayListingUtility.MinimumBestOffer
}
};
}
But that does not change anything. FYI, AllowBestOffer is a boolean for an item to be listed, and an item is an ItemType ebay class item.
I have tried this on an auction or fixed price item based on the AddItem api call, but all my items (ex: http://cgi.sandbox.ebay.com/110141411066?hash=item19a4dce3e0#ht_849wt_1397) does not show the "Best offer" button. So how can I achieve what I need to do?

Adding properties of an Object together in a collection

I have an app that creates ContactList Objects and adds them to a Dictionary collection. My ContactList objects have a property called AggLabels which is a collection of AggregatedLabel objects containg Name and Count properties. What I am trying to do is change the "else" case of my code snippet so that before adding a new AggregatedLabel it will check whether the AggLabel.Name exists in the AggregatedLabel collection and if this is true it will not add the AggLabel.Name again. Instead it will add the value of AggLabel.Count (type int) to the existing AggregatedLabel object. So for an existing object, if the first Count value was 3 and the second value is 2 then the new Count value should be 5. In simple terms I want to have unique AggLabel Names and add together the Counts where the Names are the same. Hope that makes sense - would appreciate any help. Thanks!
Code snippet
Dictionary<int, ContactList> myContactDictionary = new Dictionary<int, ContactList>();
using (DB2DataReader dr = command.ExecuteReader())
{
while (dr.Read())
{
int id = Convert.ToInt32(dr["CONTACT_LIST_ID"]);
if (!myContactDictionary.ContainsKey(id))
{
ContactList contactList = new ContactList();
contactList.ContactListID = id;
contactList.ContactListName = dr["CONTACT_LIST_NAME"].ToString();
//contactList.AggLabels = new ObservableCollection<AggregatedLabel>() { new AggregatedLabel() { Name = dr["LABEL_NAME"].ToString(), Count = Convert.ToInt32(dr["LABEL_COUNT"])}};
contactList.AggLabels = new ObservableCollection<AggregatedLabel>()
{
new AggregatedLabel()
{
Name = dr["LABEL_NAME"].ToString(),
Count = Convert.ToInt32(dr["LABEL_COUNT"])
}
};
myContactDictionary.Add(id, contactList);
}
else
{
ContactList contactList = myContactDictionary[id];
contactList.AggLabels.Add(
new AggregatedLabel()
{
Name = dr["LABEL_NAME"].ToString(),
Count = Convert.ToInt32(dr["LABEL_COUNT"])
}
);
}
}
}
There are two possible solutions I can think of:
1) Use a dictionary instead of the collection of aggregated labels the same way you do it for the contact dictionary. When yout use the name as key and the count as value, you can use the ContainsKey-Method to check whether the label already exists.
contactList.AggLabels = new Dictionary<string, int>();
...
else
{
ContactList contactList = myContactDictionary[id];
if (contactList.AggLabels.ContainsKey(dr["LABEL_NAME"].ToString()))
{
contactList.AggLabels[dr["LABEL_NAME"].ToString()] += Convert.ToInt32(dr["LABEL_COUNT"]);
}
else
{
contactList.AggLabels.Add(dr["LABEL_NAME"].ToString(), Convert.ToInt32(dr["LABEL_COUNT"]));
}
}
2) I you need to use the AggreagteLabel object you can use a loop to search throug all labels.
else
{
bool flagAggLabelFound = false;
ContactList contactList = myContactDictionary[id];
foreach(AggregateLabel aggLabel in contactList.AggLabels)
{
if(aggLabel.Name == dr["LABEL_NAME"].ToString())
{
aggLabel.Count += Convert.ToInt32(dr["LABEL_COUNT"]);
flagAggLabelFound = true;
break;
}
}
if (!flagAggLabelFound)
{
contactList.AggLabels.Add(
new AggregatedLabel()
{
Name = dr["LABEL_NAME"].ToString(),
Count = Convert.ToInt32(dr["LABEL_COUNT"])
}
);
}
}
I hope this helps.
I would try this:
ContactList contactList = myContactDictionary[id];
AggregateLabel existing = contactList.AggLabels.FirstOrDefault(
l => l.Name == dr["LABEL_NAME"].ToString()
);
if (existing == null) { contactList.AggLabels.Add(
new AggregatedLabel() {
Name = dr["LABEL_NAME"].ToString(),
Count = Convert.ToInt32(dr["LABEL_COUNT"])
}
);
}
else { existing.Count += Convert.ToInt32(dr["LABEL_COUNT"]); }
#extract these Aggregated Labels and put them in a separate Observable collection:
1) If you a Dictionary for storing the labels in the contact list, this should work:
ObservableCollection<AggregateLabel> copyOfAggregateLabels = new ObservableCollection<AggregateLabel>();
foreach (KeyValuePair<string, int> aggLabel in aggregateLabels)
{
copyOfAggregateLabels.Add(
new AggregatedLabel() {
Name = aggLabel.Key,
Count = aggLabel.Value
}
);
}
2) If you use an ObservableCollection of AggregateLabels, you get an AggregateLable instead of a KeyValuePair in the loop. The rest works the same way.
First I thought of something like:
ObservableCollection<AggregateLabel> copyOfAggregateLabels = new ObservableCollection<AggregateLabel>(aggregateLables);
But this way you get a new ObservableCollection, but the labels stored in the new collection are still referring to the same objects as the ones in the collection you copy.

Categories

Resources