I’m trying to automate linking the NetSuite purchase order to a NetSuite sale order and the following is the code I tried to accomplish this task. But I'm getting error (see at the bottom). Can you please check and let me know what I’m missing here?
Purchase Order Creation code:
var createPurchaseOrder = new PurchaseOrder();
createPurchaseOrder.entity = new RecordRef()
{
internalId = “653”
//type = RecordType.purchaseOrder,
//typeSpecified = true
};
RecordRef soRecordRef = new RecordRef();
soRecordRef.internalId = “XXXXXXXX”;
soRecordRef.type = RecordType.salesOrder;
soRecordRef.typeSpecified = true;
createPurchaseOrder.createdFrom = soRecordRef;
RecordRef depRecordRef = new RecordRef();
depRecordRef.internalId = “3”;
depRecordRef.name = “eBay : eBay FNC”;
depRecordRef.type = RecordType.department;
depRecordRef.typeSpecified = true;
createPurchaseOrder.department = depRecordRef;
PurchaseOrderItem[] Items = new PurchaseOrderItem[1];
Items[0] = new PurchaseOrderItem();
RecordRef item = new RecordRef();
item.type = RecordType.nonInventoryPurchaseItem;
item.typeSpecified = true;
item.internalId = “XXXXX”;
Items[0].item = item;
Items[0].rate = “5”;
Items[0].quantity = 1;
Items[0].quantitySpecified = true;
PurchaseOrderItemList purchaseOrderItemList = new PurchaseOrderItemList();
purchaseOrderItemList.item = Items;
createPurchaseOrder.itemList = purchaseOrderItemList;
WriteResponse response = Service.add(createPurchaseOrder);
Code I'm using to Update Purchase Order Number in Sales Order:
var updateSalesOrder = new SalesOrder();
updateSalesOrder.internalId = “XXXXXXXX”;
SalesOrderItem[] soItems = new SalesOrderItem[1];
var soItem = new SalesOrderItem();
RecordRef roItem = new RecordRef();
roItem.type = RecordType.inventoryItem;
roItem.typeSpecified = true;
roItem.internalId = “XXXXX”;
soItem.item = roItem;
RecordRef prLevel = new RecordRef();
prLevel.type = RecordType.priceLevel;
prLevel.internalId = “-1”;
prLevel.typeSpecified = true;
soItem.price = prLevel;
soItem.rate = “15”;
soItem.quantity = 1;
soItem.quantitySpecified = true;
RecordRef poItem = new RecordRef();
poItem.type = RecordType.purchaseOrder;
poItem.typeSpecified = true;
poItem.internalId = purchaseOrder.internalId;
soItem.createdPo = poItem;
soItems[0] = soItem;
SalesOrderItemList salesOrderItemList = new SalesOrderItemList();
salesOrderItemList.item = soItems;
updateSalesOrder.itemList = salesOrderItemList;
response = Service.update(updateSalesOrder);
if (response.status.isSuccess != true) throw new Exception(response.status.statusDetail[0].message);
But I get the follwoing Error:
You do not have permissions to set a value for element createPOSpecified due to one of the following reasons: 1) The field is read-only; 2) An associated feature is disabled; 3) The field is available either when a record is created or updated, but not in both cases.
Note: createPOSpecified is not displayed in the sales order screen in NetSuite. When I try to update a field in the sales order which exist in the form, then I am able to update it successfully but the field I am trying to update (createPOSpecified ) is not available in this sales form. In this case how can I update this ? Also is this the better way of linking the purchase order with sales order?
Thanks,
Hemant.
Updated 25-May-2020 (Responding to Anand Rajaram)
We are using the ADMINISTRATOR role for creating purchase order and linking that to sales order. A user with this role has been provided by our client and we don’t have permission to see fields that are displayed in the screen and have been restricted for EDIT. But we are able to edit most of the field displayed in the screen.
createPOSpecified is not a custom field. It’s a property in the SALESORDETITEM class. It will not be displayed in any sales order form.
If this is the proper code for creating purchase order and linking that to sales order, then I have few queries:
3.1 When we create purchase order through NetSuite by clicking the dropship link in the sales order item grid, we are able to see Mark Shipped button.
But when we create purchase order through code, it is displaying the Receive button and there was no changes in the purchase order status.
3.2 **createdFrom** field is displaying as below when we create purchase order through netsuite.
This field is not displaying when we are creating purchase order through code. We have provided information for createdFrom property, but not sure why it is not displaying
We assume this is the field that helps to link with sales order. We have provided this information while creating item fulfillment and vendor bill and these are properly linked with sales order, but we are not sure why purchase order is not getting linked with sales order.
Finally on the below comments which you have provided
Which is basically having a custom transaction body field on Sales Order form, and once PO is created, update the newly created PO in Sales Order field.
We don’t have any custom transaction body field in our sales order form for providing purchase order. But once purchase order is created through NetSuite, purchase order number will be displayed in the sales order item grid.
So all this boils down to: what is that we have missed in the code and what is that we have to fix to display the "Mark Shipped" button, “Created From" label and linking Purchase Order to Sales Order.
Thanks,
Hemant.
I don't have an answer, but hopefully I can contribute. First of all, I think you're approaching this from the wrong direction. Rather than creating the PO and then trying to link it to the SO, I think you'll have to initialize the PO via the native dropship process and then save the PO. For example, creating a drop ship PO is pretty easy in SuiteScript 2.0. Here's how it's done:
var purchaseOrder = record.create ({
type: record.Type.PURCHASE_ORDER,
isDynamic: true,
defaultValues: {
recordmode: 'dynamic',
soid: '11111',
dropship: true,
custid: '22222',
entity: '33333'
}
})
This new PO is populated with all valid items from the SO and when it's saved all the linking is done automatically (createdFrom is automatically set on the PO; createdPo is automatically set on the SO item). I tried to recreate this in SuiteTalk using two different methods, both of which failed. Here they are:
The first approach tries to emulate the SuiteScript method using the initialize() method. This is how you create an SO from an Estimate, or an IF from an SO, so it seems promising:
var initrec = new InitializeRecord
{
type = InitializeType.purchaseOrder,
reference = new InitializeRef
{
internalId = "11111",
type = InitializeRefType.salesOrder,
typeSpecified = true
}
};
var res = NSBase.Client.Service.initialize(initrec);
// "You can not initialize purchaseOrder by referencing salesOrder."
The error is self-explanatory. It's not possible to create a PO from an SO using initialize(). This is very disheartening.
The second approach essentially tries to programmatically click the "drop ship" link on the line item. It fails with a similar error to the one you encountered before:
var objSO = new SalesOrder();
objSO.internalId = "11111";
objSO.itemList = new SalesOrderItemList
{
item = new SalesOrderItem[]
{
new SalesOrderItem { line = 10, lineSpecified = true, createPo = SalesOrderItemCreatePo._dropShipment, createPoSpecified = true }
},
replaceAll = false
};
var result = Service.update(objSO);
// "You do not have permissions to set a value for element item.createpo due to one of the following reasons: 1) The field is read-only; 2) An associated feature is disabled; 3) The field is available either when a record is created or updated, but not in both cases."
Unfortunately, this is the best I can do. The initialization approach definitely seems like the most likely solution to the problem, and the fact that it fails makes me wonder if it is even possible to create a drop ship/special order PO using SuiteTalk.
As an addendum to Will C.'s outstanding answer, there are three undocumented fields that you can use in suitescript to associate a purchase order line with a sales order line.
These fields are:
createdfrom -- this should be set to the internalid of the salesorder
orderdoc -- this should be set to the internalid of the salesorder
orderline -- this should be set to the 1-indexed line id of the sales order item that you want to link to the purchase order
id -- this should be set to the concatenation of orderdoc and orderline separated by an _ (underscore).
these four fields allow you to associate any arbitrary purchase order line with a sales order line even if those lines were not pulled into the purchase order from the call to record.create.
So following could be your issues:
Permission Issue: What role are you trying to create and link the two transactions? Does that role have appropriate permissions to achieve the same? Also are there any restrictions added in the custom field "createPOSpecified"?
Custom Field Setting: You mentioned that the field "createPOSpecified" is not available in Sales Order form. Review the custom field definition and see if the field is applied to "Sales". If not, then the field will not be available in all Sales transaction forms, and you wouldn't be able to update it in the script. Also in the custom field settings, verify if the field is set to "Read Only". If it is then change it to either normal or disabled (if you don't want users to manually edit it).
And to your final question, yes, this is an appropriate way to custom link a Sales Order and a Purchase Order transaction in NetSuite. Which is basically having a custom transaction body field on Sales Order form, and once PO is created, update the newly created PO in Sales Order field.
With the suggestion and from #Will Charbonneau, we have tested the following script using SuiteScript 1.0 and it helped us to link the purchase order to a sales order.
var po = nlapiCreateRecord('purchaseorder', {recordmode:"dynamic", soid:soInternalId,poentity:vendorEntity,vendor:vendorEntity,entity:custEntity});
var id = nlapiSubmitRecord(po, true)
nlapiLogExecution("DEBUG", "DropShip PO Created", "PO=" + id);
Thanks,
Hemant.
Related
I am trying to set default price list for a product bundle that i am trying to create using Microsoft.CrmSdk.CoreAssemblies. I have written the working code that successfully creates the product bundle with all the configurations that I specify in the code but default price list is never set. Following is the code snippet:
Entity ProductBundleEntity = new Entity("product");
ProductBundleEntity.Attributes["name"] = Name;
ProductBundleEntity.Attributes["productstructure"] = new OptionSetValue(3);
ProductBundleEntity.Attributes["productnumber"] = Guid.NewGuid().ToString();
///// setting defult price list here
ProductBundleEntity.Attributes["pricelevelid"] = new EntityReference("pricelevel", PriceListID);
ProductBundleEntity.Attributes["defaultuomscheduleid"] = new EntityReference("uomschedule", UOMScheduleID);
ProductBundleEntity.Attributes["defaultuomid"] = new EntityReference("uom", UOMID);
Please suggest if i am missing anything.
Did you receive any error?
When is your plugin running, create/update?
Is it synchronous? –
is it pre operation or post?
If post you might have to use service.update(Entity object) Better try with pre operation so that same object/ can be used.
Although I don't know the definition of the PriceListId variable, normally you need to assign an id as below, I think the PriceListId variable does not contain a value;
ProductBundleEntity.Attributes["pricelevelid"] = new EntityReference("pricelevel", ((Microsoft.Xrm.Sdk.EntityReference)(originalEntity.Attributes["pricelevelid"])).Id);
I am coding in C#, using the SuiteTalk Web Services to create Item Fulfillment records from existing sales orders.
I am not sure how to configure the inventory detail, when serial numbers are specified on items.
I successfully generate the item fulfillment and can update NetSuite when items are not serialized. When items are serialized, I get the following error:
"Please configure the inventory detail in line 1 of the item list."
I run through each line item and check whether it is fulfilled, after which I add it to my new item fulfillment list as follows:
List<ItemFulfillmentItem> ifitems = new List<ItemFulfillmentItem>();
ItemFulfillmentItem ffItem = new ItemFulfillmentItem();
ffItem.item = ifitemlist.item[b].item;
ffItem.orderLineSpecified = true;
ffItem.orderLine = ifitemlist.item[b].orderLine;
ffItem.quantity = msg.despatchItems[i].qtyDespatched;
ffItem.quantitySpecified = true;
ifitems.Add(ffItem);
ItemFulfillmentItemList ifitemlistToFulfill = new ItemFulfillmentItemList();
ifitemlistToFulfill.item = ifitems.ToArray();
newItemFulfill.itemList = ifitemlistToFulfill;
WriteResponse writeRes = _service.add(newItemFulfill);
Any help would be appreciated.
You need to add and inventory detail subrecord for each line item
Then you will have to set the serialnumber* and **qty
You cannot add a comma-separated list as you must specify the qty
I am not familiar with the C# api, only the JS and Java api which all have the same workflow (inventory detail subrecord)
On the item fulfillment item, there is a text field called serialNumbers. Add them by way of a comma separated list.
Trying to access AX 2012 QueryService through c# application and would like to get CustomerID and Customername fields only. Problem is, CustomerID is in CustTable and CustomerName is in DirPartyTable.
Any help to article or code samples would be appreciated.
Reference to QueryDataSourceMetadata to put join in these tables and get data.
What are the options and when to use Relations and JoinMode?
I searched in MSDN and it just lists the property names and methods and not much help in the form of code samples.
According to my knowledge, you put in the two tables you want to query into your QueryDataSourceMetadata. The resulting dataset should contain both tables.
(Example code for creating a QueryDataSourceMetadataObject is here:
http://msdn.microsoft.com/EN-US/library/gg844682.aspx)
The property you need, for the tables to be joined, is ReturnFlatDataSet.
(this may help: http://msdn.microsoft.com/EN-US/library/gg841671.aspx)
Hope i could help you or point you in the right direction!
Its too late to answer and I think you already might have found some solutions. Anyway here is the link to my response on AX community:
https://community.dynamics.com/ax/f/33/p/212065/573674#573674
I found 2 ways to add the relations from c#. I have commented the first approach based on AOT table relation. In the code below QueryServiceReference is the service reference name in VS. You can remove it in all the lines if you have only QueryService reference but no MetaDataService reference. Here is the code :
query.DataSources = new QueryServiceReference.QueryDataSourceMetadata[1];
// Set the properties on Customers data source.
customerDataSource = new QueryServiceReference.QueryDataSourceMetadata();
customerDataSource.Name = "Customers";
customerDataSource.Enabled = true;
customerDataSource.FetchMode = QueryServiceReference.FetchMode.OneToOne;
customerDataSource.Table = "CustTable";
//customerDataSource.DynamicFieldList = false;
query.DataSources[0] = customerDataSource;
QueryServiceReference.QueryDataSourceMetadata dirPartyTableDataSource = new QueryServiceReference.QueryDataSourceMetadata();
dirPartyTableDataSource.Name = "DirPartyTable";
dirPartyTableDataSource.Table = "DirPartyTable";
dirPartyTableDataSource.Enabled = true;
dirPartyTableDataSource.DynamicFieldList = true;
customerDataSource.DataSources = new QueryServiceReference.QueryDataSourceMetadata[1] { dirPartyTableDataSource };
QueryServiceReference.QueryRelationMetadata relation = new QueryServiceReference.QueryRelationMetadata();
//this is also one way of setting the relation
//relation.JoinRelation = "DirPartyTable_FK"; //table relation defined in AOT
//relation.JoinDataSource = customerDataSource.Name; //parent datasource name
relation.Table = "CustTable";//Parent table
relation.Field = "Party";
relation.RelatedTable = "DirPartyTable"; // child table
relation.RelatedField = "RecId";
relation.JoinDataSource = customerDataSource.Name;
dirPartyTableDataSource.Relations = new QueryServiceReference.QueryRelationMetadata[1] { relation };
ASP.NET C# MVC 4 Code First application - in Visual Studio 2012 Express, SQL Server 2012 Express.
I have a places object. I would like to output the name of all places in a list - with a check box next to each.
I would then like logged in users to select the places they like - and have that saved. Then later they can login and see a them all again, with the appropriate check boxes selected.
What is the best approach? I'm new to MVC and not sure of best practice here.
thanks
Update
The below CheckboxListFor helper worked great, though it wasn't obvious how to process the user selection (it just returns a list of IDs).
I created the below to take that list of IDs - convert it to a list of objects, and add it to the SelecteCities list in the view model. This will select all the checkboxes that the user selected before the page was posted:
public ActionResult Examples(PostedCities postedCities)
{
// ViewModel
CitiesViewModel cvm = new CitiesViewModel();
// Create list of cities
List<City> cities = new List<City>{
new City { Id = 1, Name = "London"},
new City { Id = 2, Name = "Saigon"},
new City { Id = 3, Name = "New York"}
};
// Assign list of cities to ViewModel
cvm.AvailableCities = cities;
// If posted cities present, user posted something (else probably first call)
if (postedCities.CityIDs != null)
{
// temporary city object
City cty = new City();
// List of selected cities
List<City> selCities = new List<City>();
// Go through each postedCity ID
foreach (string s in postedCities.CityIDs)
{
// Get ID of postedCity
int IdSel = Convert.ToInt32(s);
// Lookup city Id in cities
cty = cities.Single(c => c.Id == IdSel);
// Add selected city to cty object
selCities.Add(cty);
}
// Fill cvm.SelectedCities with selCities
cvm.SelectedCities = selCities;
}
return View(cvm);
}
This works - is it a good approach or have I overcomplicated it? Or done something badly?
You can save yourself the work and use the existing MvcCheckBoxList library.
Install it with nuget using the command:
PM> Install-Package MvcCheckBoxList
Here is their home page: MvcCheckBoxList
And here is the documentation: MvcCheckBoxList/Documentation
Other solutions will require some ugly coding.
Update
As Klas Mellbourn suggested (I'm sorry for taking it for granted) a view model with a list will be the best practice for such sceneria. The documentation link I provided contains such examples for you to understand more easily.
I would say that MVC best practices would be to have a viewmodel mirroring the fields you wish to display. It would contain a List with items, each item containing a placename string and a bool for the checkbox.
In the controller method that displays the page you build the view model based on the places objects that you have populated from the database using Entity Framework.
The users presumably save the state using some command, a submit button perhaps. This calls a second controller method that reads the viewmodel and persists the content using Entity Framework.
I've been having a problem for some time, and I've exhausted all means of figuring this out for myself.
I have 2 lists in a MS Sharepoint 2010 environment that are holding personal physician data for a medical group...nothing special just mainly text fields and a few lookup choice fields.
I am trying to write a program that will migrate the data over from List A to List B. I am using LINQ to Sharepoint to accomplish this. Everything compiles just fine, but when it runs and hits the SubmitChanges() method, I get a runtime error that states:
"All new entities within an object graph must be added/attached before changes are submitted."
this issue must be outside of my realm of C# knowledge because I simply cannot find the solution for it. The problem is DEFINITELY stemming from the fact that some of the columns are of type "Lookup", because when I create a new "Physician" entity in my LINQ query, if I comment out the fields that deal with the lookup columns, everything runs perfectly.
With the lookup columns included, if I debug and hit breakpoints before the SubmitChanges() method, I can look at the new "Physician" entities created from the old list and the fields, including data from the lookup columns, looks good, the data is in there the way I want it to be, it just flakes out whenever it tries to actually update the new list with the new entities.
I have tried several methods of working around this error, all to no avail. In particular, I have tried created a brand new EntityList list and calling the Attach() method after each new "Physician" Entity is created, but to no avail, it just sends me around in a bunch of circles, chasing other errors such as "ID cannot be null", "Cannot insert entities that have been deleted" etc.,
I am no farther now than when I first got this error and any help that anyone can offer would certainly be appreciated.
Here is my code:
using (ProviderDataContext ctx = new ProviderDataContext("http://dev"))
{
SPSite sitecollection = new SPSite("http://dev");
SPWeb web = sitecollection.OpenWeb();
SPList theOldList = web.Lists.TryGetList("OldList_Physicians");
//Create new Physician entities.
foreach(SPListItem l in theOldList.Items)
{
PhysiciansItem p = new PhysiciansItem()
{
FirstName = (String)l["First Name"],
Title = (String)l["Last Name"],
MiddleInitial = (String)l["Middle Init"],
ProviderNumber = Convert.ToInt32(l["Provider No"]),
Gender = ConvertGender(l),
UndergraduateSchool =(String)l["UG_School"],
MedicalSchool = (String)l["Med_School"],
Residency = (String)l["Residency"],
Fellowship = (String)l["Fellowship"],
Internship = (String)l["Internship"],
PhysicianType = ConvertToPhysiciantype(l),
Specialty = ConvertSpecialties(l),
InsurancesAccepted = ConvertInsurance(l),
};
ctx.Physicians.InsertOnSubmit(p);
}
ctx.SubmitChanges(); //this is where it flakes out
}
}
//Theses are conversion functions that I wrote to convert the data from the old list to the new lookup columns.
private Gender ConvertGender(SPListItem l)
{
Gender g = new Gender();
if ((String)l["Sex"] == "M")
{
g = Gender.M;
}
else g = Gender.F;
return g;
}
//Process and convert the 'Physician Type', namely the distinction between MD (Medical Doctor) and
//DO (Doctor of Osteopathic Medicine). State Regualtions require this information to be attached
//to a physician's profile.
private ProviderTypesItem ConvertToPhysiciantype(SPListItem l)
{
ProviderTypesItem p = new ProviderTypesItem();
p.Title = (String)l["Provider_Title:Title"];
p.Intials = (String)l["Provider_Title"];
return p;
}
//Process and convert current Specialty and SubSpecialty data into the single multi-choice lookup column
private EntitySet<Item> ConvertSpecialties(SPListItem l)
{
EntitySet<Item> theEntityList = new EntitySet<Item>();
Item i = new Item();
i.Title = (String)l["Provider Specialty"];
theEntityList.Add(i);
if ((String)l["Provider SubSpecialty"] != null)
{
Item theSubSpecialty = new Item();
theSubSpecialty.Title = (String)l["Provider SubSpecialty"];
theEntityList.Add(theSubSpecialty);
}
return theEntityList;
}
//Process and add insurance accepted.
//Note this is a conversion from 3 boolean columns in the SP Environment to a multi-select enabled checkbox
//list.
private EntitySet<Item> ConvertInsurance(SPListItem l)
{
EntitySet<Item> theEntityList = new EntitySet<Item>();
if ((bool)l["TennCare"] == true)
{
Item TenncareItem = new Item();
TenncareItem.Title = "TennCare";
theEntityList.Add(TenncareItem);
}
if ((bool)l["Medicare"] == true)
{
Item MedicareItem = new Item();
MedicareItem.Title = "Medicare";
theEntityList.Add(MedicareItem);
}
if ((bool)l["Commercial"] == true)
{
Item CommercialItem = new Item();
CommercialItem.Title = "Commercial";
theEntityList.Add(CommercialItem);
}
return theEntityList;
}
}
So this may not be the answer you're looking for, but it's what's worked for me in the past. I've found that updating lookup fields using Linq to Sharepoint to be quite frustrating. It frequently doesn't work, or doesn't work efficiently (forcing me to query an item by ID just to set the lookup value).
You can set up the entity so that it has an int property for the lookup id (for each lookup field) and a string property for the lookup value. If, when you generate the entities using SPMetal, you don't generate the list that is being looked up then it will do this on it's own. What I like to do is (using your entity as an example)
Generate the entity for just that one list (Physicians) in some temporary folder
Pull out the properties for lookup id & value (there will also be private backing fields that need to come along for the ride too) for each of the lookups (or the ones that I'm interested in)
Create a partial class file for Physicians in my actual project file, so that regenerating the entire SPMetal file normally (without restricting to just that list) doesn't overwrite changes
Paste the lookup id & value properties in this partial Physicians class.
Now you will have 3 properties for each lookup field. For example, for PhysicianType there will be:
PhysicianType, which is the one that is currently there. This is great when querying data, as you can perform joins and such very easily.
PhysicianTypeId which can be occasionally useful for queries if you only need ID as it makes it a bit simpler, but mostly I use it whenever setting the value. To set a lookup field you only need to set the ID. This is easy, and has a good track record of actually working (correctly) in my experiences.
PhysicianTypeValue which could be useful when performing queries if you just need the lookup value, as a string (meaning it will be the raw value, rather than something which is already parsed if it's a multivalued field, or a user field, etc. Sometimes I'd rather parse it myself, or maybe just see what the underlying value is when doing development. Even if you don't use it and use the first property, I often bring it along for the ride since I'm already doing most of the work to bring the PhysicianTypeId field over.
It seems a bit hacky, and contrary to the general design of linq-to-SharePoint. I agree, but it also has the advantage of actually working, and not actually being all that hard (once you get the rhythm of it down and learn what exactly needs to be copied over to move the properties from one file to another).