How to create purchase order via code? - acumatica

I had wrote some code for creating po via code, but it faild with error message: "CS Error: Cannot generate the next number for the sequence."
How can I fix this? Anything I missed? Thx for helping!
protected void createPO() {
POOrder order = new POOrder();
POOrderEntry graph = PXGraph.CreateInstance < POOrderEntry > ();
order.OrderType = "Normal";
order.OrderDesc = "some text";
order.EmployeeID = 215;
order.Hold = false;
var branch = (Branch)PXSelect<Branch, Where<Branch.branchCD, Equal<Required<Branch.branchCD>>>>.Select(Base, "WEST");
graph.FieldDefaulting.AddHandler<POOrder.branchID>((s, e) =>
{
e.NewValue = branch.BranchID;
e.Cancel = true;
});
order.VendorID = 79;
order = graph.CurrentDocument.Insert(order);
graph.CurrentDocument.Update(order);
graph.Actions.PressSave();
throw new PXRedirectRequiredException(graph, null);
}

Try to simply it first to see if something like this works...
protected void createPO()
{
var graph = PXGraph.CreateInstance<POOrderEntry>();
var order = graph.Document.Insert(new POOrder());
order.OrderType = POOrderType.RegularOrder; // This is the default so not necessary
order.OrderDesc = "some text";
order.EmployeeID = 215;
order.Hold = false;
order.VendorID = 79;
graph.Document.Update(order);
graph.Actions.PressSave();
throw new PXRedirectRequiredException(graph, null);
}
Using the Document view in place of the CurrentDocument view which is based on the current record of Document. Document is the primary view and the primary view should be used.
Also for the purchase order type the attribute related to the list values should be used for the stored value of the database (vs what you had was the displayed list value). For example order.OrderType = POOrderType.RegularOrder. Also this is the default value for a PO so it is not necessary to set this value unless you want a different constant found in the POOrderType class.

Related

How to get Opportunity Relations in Sales Order

In Opportunity screen, the definition of the data view for Relations is simply :
public CRRelationsList<CROpportunity.noteID> Relations;
When a Sales Order is raised from the Opportunity. I'd like to display the Relations defined from the source Opporunity in another tab. And I'm just struggling how to write the the data view and pass the Opportunity noteid.
public CRRelationsList<???>Relations;
Thanks !
The generic type in dataviews often resolve to the current record.
In CRRelationsList class the generic type is named TNoteField:
public class CRRelationsList<TNoteField> : PXSelect<CRRelation>
where TNoteField : IBqlField
ssuming the dataview is declared as CRRelationsList<CROpportunity.noteID>.
The generic type value will be resolved like this Caches[typeof(CROpportunity)].Current.NoteID.
protected virtual void CRRelation_RefNoteID_FieldDefaulting(PXCache sender, PXFieldDefaultingEventArgs e)
{
// Get a cache object of type CROpportunity
var refCache = sender.Graph.Caches[BqlCommand.GetItemType(typeof(TNoteField))];
// Get the NoteID field value of the current CROpportunity object
e.NewValue = refCache.GetValue(refCache.Current, typeof(TNoteField).Name);
}
So to set DAC.Field of CRelationsList<DAC.field> you would do:
// In a graph extension (PXGraphExtension)
Base.Caches[typeof(DAC)].Current.Fied = ???;
// Or in graph (PXGraph)
Caches[typeof(DAC)].Current.Fied = ???;
If current DAC object is null you need to insert a record in a dataview or directly in the cache object.
I'm not sure re-using CRRelationsList list is the best approach if you want to simply display records because it does much more than that. It should be possible to extract the select request out of it and directly substitute the TNoteField value:
private static PXSelectDelegate GetHandler()
{
return () =>
{
var command = new Select2<CRRelation,
LeftJoin<BAccount, On<BAccount.bAccountID, Equal<CRRelation.entityID>>,
LeftJoin<Contact,
On<Contact.contactID, Equal<Switch<Case<Where<BAccount.type, Equal<BAccountType.employeeType>>, BAccount.defContactID>, CRRelation.contactID>>>,
LeftJoin<Users, On<Users.pKID, Equal<Contact.userID>>>>>,
Where<CRRelation.refNoteID, Equal<Current<TNoteField>>>>();
var startRow = PXView.StartRow;
int totalRows = 0;
var list = new PXView(PXView.CurrentGraph, false, command).
Select(null, null, PXView.Searches, PXView.SortColumns, PXView.Descendings, PXView.Filters,
ref startRow, PXView.MaximumRows, ref totalRows);
PXView.StartRow = 0;
foreach (PXResult<CRRelation, BAccount, Contact, Users> row in list)
{
var relation = (CRRelation)row[typeof(CRRelation)];
var account = (BAccount)row[typeof(BAccount)];
relation.Name = account.AcctName;
relation.EntityCD = account.AcctCD;
var contact = (Contact)row[typeof(Contact)];
if (contact.ContactID == null && relation.ContactID != null &&
account.Type != BAccountType.EmployeeType)
{
var directContact = (Contact)PXSelect<Contact>.
Search<Contact.contactID>(PXView.CurrentGraph, relation.ContactID);
if (directContact != null) contact = directContact;
}
relation.Email = contact.EMail;
var user = (Users)row[typeof(Users)];
if (account.Type != BAccountType.EmployeeType)
relation.ContactName = contact.DisplayName;
else
{
if (string.IsNullOrEmpty(relation.Name))
relation.Name = user.FullName;
if (string.IsNullOrEmpty(relation.Email))
relation.Email = user.Email;
}
}
return list;
};
}

How to get TreeProvider.SelectNodes to return all data in preview mode like CMSRepeater does

if I provide the data query as properties of the CMSRepeater, the repeater shows all items (published or not) in preview mode and only published items on the live site.
However, if I try to pass a datasource to the repeater, I can't get it to do the same thing.
Is there some property or method I'm missing?
Works
<cms:CMSRepeater ID="rep2" runat="server" EnableViewState="true"
Path="./%" OrderBy="NodeOrder ASC"
MaxRelativeLevel="1"
ClassNames="MyClassName"
SelectedColumns="Col1, col2, etc">
</cms:CMSRepeater>
Does Not Work
private DataSet LoadRepeaterItemsWithoutCache()
{
var columns = #"col1,col2";
var path ="./%";
TreeProvider tree = new TreeProvider();
return tree.SelectNodes("MyClassName")
.OnCurrentSite()
.Path(path)
.OrderBy("NodeOrder")
.NestingLevel(1)
//.Published(true/false)
//.CheckPermissions(true/false)
.CombineWithDefaultCulture(false)
.Columns(columns);
}
var tnds = LoadRepeaterItemsWithoutCache();
rep2.DataBindByDefault = false;
rep2.HideControlForZeroRows = true;
if (!DataHelper.DataSourceIsEmpty(tnds))
{
rep2.DataSource = tnds;
rep2.DataBind();
}
Looks like you need to modify your query a bit. Your function is expecting a DataSet as a return value and you're returning an ObjectQuery. If you want or need to return a DataSet then add .Result to the end of your .SelectNodes() method.
.Columns(columns).Result;
The other option is to return an ObjectQuery and simply assign that to the repeater and let the natural lifecycle process things.
public override void OnContentLoaded()
{
//rep2.DataBindByDefault = false;
rep2.HideControlForZeroRows = true;
TreeProvider tree = new TreeProvider();
rep2.DataSource = tree.SelectNodes("MyClassName")
.OnCurrentSite()
.Path(path)
.OrderBy("NodeOrder")
.NestingLevel(1)
//.Published(true/false)
//.CheckPermissions(true/false)
.CombineWithDefaultCulture(false)
.Columns(columns);
}
I think you can try this way:
private DataSet LoadRepeaterItemsWithoutCache()
{
var columns = #"col1,col2";
var path ="./%";
TreeProvider tree = new TreeProvider();
var datasource = tree.SelectNodes("MyClassName")
.OnCurrentSite()
.Path(path)
.OrderBy("NodeOrder")
.NestingLevel(1)
//.Published(true/false)
//.CheckPermissions(true/false)
.CombineWithDefaultCulture(false)
.Columns(columns);
//If is in LiveSite mode, then return only published
if (PortalContext.ViewMode == ViewModeEnum.LiveSite)
datasource = datasource.Published();
return datasource;
}
Before return the datasource, check if the site is in LiveSite mode. If true return only the Published nodes, otherwise return Published and Unpublished nodes.
I've not tested it, but hope it works.

Netsuite Transaction search performance

I am using Netsuite API (version v2016_2) to search data. With below code, it seems that Netsuite taking much time to give response for the query. I am searching GL transaction of periticular period that has 149 MainLine record and 3941 LineItem (Journal Entries) record and Netsuite takes almost 22 minutes to give this data in response. Below is code snippet that I am using to search transaction.
public void GetTransactionData()
{
DataTable dtData = new DataTable();
string errorMsg = "";
LoginToService(ref errorMsg);
TransactionSearch objTransSearch = new TransactionSearch();
TransactionSearchBasic objTransSearchBasic = new TransactionSearchBasic();
SearchEnumMultiSelectField semsf = new SearchEnumMultiSelectField();
semsf.#operator = SearchEnumMultiSelectFieldOperator.anyOf;
semsf.operatorSpecified = true;
semsf.searchValue = new string[] { "Journal" };
objTransSearchBasic.type = semsf;
objTransSearchBasic.postingPeriod = new RecordRef() { internalId = "43" };
objTransSearch.basic = objTransSearchBasic;
//Set Search Preferences
SearchPreferences _searchPreferences = new SearchPreferences();
Preferences _prefs = new Preferences();
_serviceInstance.preferences = _prefs;
_serviceInstance.searchPreferences = _searchPreferences;
_searchPreferences.pageSize = 1000;
_searchPreferences.pageSizeSpecified = true;
_searchPreferences.bodyFieldsOnly = false;
//Set Search Preferences
try
{
SearchResult result = _serviceInstance.search(objTransSearch);
/*
Above line taking almost 22 minutes for below record count
result.recordList.Length = 149
Total JournalEntryLine = 3941
*/
List<JournalEntry> lstJEntry = new List<JournalEntry>();
List<JournalEntryLine> lstLineItems = new List<JournalEntryLine>();
if (result.status.isSuccess)
{
for (int i = 0; i <= result.recordList.Length - 1; i += 1)
{
JournalEntry JEntry = (JournalEntry)result.recordList[i];
lstJEntry.Add((JournalEntry)result.recordList[i]);
if (JEntry.lineList != null)
{
foreach (JournalEntryLine line in JEntry.lineList.line)
{
lstLineItems.Add(line);
}
}
}
}
try
{
_serviceInstance.logout();
}
catch (Exception ex)
{
}
}
catch (Exception ex)
{
throw ex;
}
}
I am unable to know that If I am missing something in my code or this is something about the data. Please suggest me some sort of solution for this.
Thanks.
You should set _searchPreferences.bodyFieldsOnly = true. It will improve the performance with searching because it doesn't return the related or sublist data
I think you are doing this search from the outside of the Netsuite to get journal entries data or lines. Instead of doing a direct search outside, do maintain RESTLET in NETSUITE and call that RESTLET. In the RESTLET DO that search you wanted and return results. Within the NETSUITE, search performance gives fast results.

Error: Reference Nbr. cannot be found in the system.."}

I customized the ARPaymentEntry in which it creates a Journal Voucher Entry with created Credit Memo, it retrieves the Credit Memo applies the open invoice that is also applied in the current payment. when I create the instance to call the Credit Memo and add the Invoice in ARAdjust table, an error occurs when trying to insert it, giving a Reference Nbr cannot be found in the system, although when I'm trying to manually applying it I could see the open invoice.
public void ReleaseCreditMemo(string refNbr)
{
try
{
ARPaymentEntry docGraph = PXGraph.CreateInstance<ARPaymentEntry>();
List<ARRegister> list = new List<ARRegister>();
ARPayment payment;
ARRegister invoice = PXSelect<ARRegister, Where<ARRegister.docType, Equal<Required<ARRegister.docType>>, And<ARRegister.refNbr, Equal<Required<ARRegister.refNbr>>>>>.Select(docGraph, ARInvoiceType.CreditMemo, refNbr);
docGraph.Document.Current = PXSelect<ARPayment, Where<ARPayment.docType, Equal<Required<ARPayment.docType>>, And<ARPayment.refNbr, Equal<Required<ARPayment.refNbr>>>>>.Select(docGraph, ARInvoiceType.CreditMemo, refNbr);
payment = docGraph.Document.Current;
list.Add(payment);
foreach (ISARWhTax item in ARWhLine.Select())
{
decimal? _CuryAdjgAmt = payment.CuryOrigDocAmt > invoice.CuryDocBal ? invoice.CuryDocBal : payment.CuryOrigDocAmt;
decimal? _CuryAdjgDiscAmt = payment.CuryOrigDocAmt > invoice.CuryDocBal ? 0m : invoice.CuryDiscBal;
ARAdjust adj = new ARAdjust();
adj.AdjdBranchID = item.AdjdBranchID;
adj.AdjdDocType = ARInvoiceType.Invoice;
adj.AdjdRefNbr = item.AdjdRefNbr;
adj.AdjdCustomerID = item.CustomerID;
adj.AdjdDocDate = invoice.DocDate;
adj.CuryAdjgAmt = _CuryAdjgAmt;
adj.CuryAdjdDiscAmt = _CuryAdjgDiscAmt;
if (docGraph.Document.Current.CuryUnappliedBal == 0m && docGraph.Document.Current.CuryOrigDocAmt > 0m)
{
throw new PXLoadInvoiceException();
}
//This line code below OCCURS THE ERROR
docGraph.Adjustments.Insert(adj);
}
docGraph.Save.Press();
PXLongOperation.StartOperation(docGraph, delegate() { ARDocumentRelease.ReleaseDoc(list, false); });
}
catch (Exception ex)
{
throw new PXException(ex.Message);
}
}
I would look at the selector of the field causing the error ("Reference Nbr.") as having a selector on a field will validate the entered value to the selector's select statement (unless validatevalue=false for the selector). Maybe the selector will give you some pointers as to what is missing or causing the validation to fail.
I figured it out it that after the code below executes it does not immediately updates the View. So what I did is to execute my code at ARPayment_RowSelected event with a conditional statement if the document is released.
PXLongOperation.StartOperation(this.Base, delegate() { ARDocumentRelease.ReleaseDoc(list, false); });

Creating a new entity with a field of type optionset

I have an html form which does a post to an aspx page which uses the SOAP web services to connect to CRM. The code behind the page creates an entity in the CRM. I am using the IOrganizationService in my code behind.
The code looks like
IOrganizationService service = (IOrganizationService)serviceProxy;
Entity lead = new Entity("lead");
string fieldValue = string.Empty;
foreach (string key in Request.Form.AllKeys)
{
if (key.Equals(SubmitKey, StringComparison.InvariantCultureIgnoreCase) == false &&
key.Equals(CRMHostKey, StringComparison.InvariantCultureIgnoreCase) == false &&
key.Equals(redirectErrorURLKey, StringComparison.InvariantCultureIgnoreCase) == false &&
key.Equals(redirectSuccessURLKey, StringComparison.InvariantCultureIgnoreCase) == false)
{
if (!string.IsNullOrEmpty(Request.Form[key]))
{
fieldValue = Request.Form[key].Trim();
}
else
{
fieldValue = string.Empty;
}
if (key.Equals("new_contacttypechoices", StringComparison.InvariantCultureIgnoreCase))
{
lead[key] = new KeyValuePair<string, int>("Email", 100000000);
//OptionMetadata objOM = GetOptionMetadata("lead", "new_contacttypechoices", fieldValue, service);
//lead[key] = objOM;
//lead[key] = 100000000; //Incorrect attribute value type System.Int32
//lead[key] = fieldValue; //Incorrect attribute value type System.String
}
else
{
lead[key] = fieldValue;
}
}
newLeadID = service.Create(lead);
}
Screenshot of the field
I get an error when I try
lead[key] = fieldValue
I get an error when I try
lead[key] = 100000000
I get an error when I try
lead[key] = new KeyValuePair<string, int>("Email", 100000000);
I get an error when I get the OptionMetaData and set that to the entity. Any ideas on how to create an entity using an optionset?
Thanks
Depends on the error you are getting, but if lead is of type Microsoft.Xrm.Sdk.Entity, it could be that you need to either replace an existing value or add a new one.
if (lead.Attributes.Contains(key))
{
lead[key] = new OptionSetValue(100000000);
}
else
{
lead.Attributes.Add(key, new OptionSetValue(100000000));
}
Rereading I notice you have put (presumably) the errors in comments. In that case, I suggest the issue is that you need to assign a value of type OptionSetValue

Resources