How to Add an optionset filter criteria in MS CRM Query Expression? - dynamics-crm-2011

I have an entity LeaveType with two attributes, 1. Type, 2. Available Days, where Type is an optionset and Available days is a text field. I want to fetch all such LeaveType records where the Type = 'Annual' selected in the optionset. I am not able to find how to add a filter the query expression for the option set value. Below is my in progress method:
public Entity Getleavetype(Guid LeaveDetailsId, IOrganizationService _orgService, CodeActivityContext Acontext)
{
QueryExpression GetLeavedetails = new QueryExpression();
GetLeavedetails.EntityName = "sgfdhr_leavetype";
GetLeavedetails.ColumnSet = new ColumnSet("new_type");
GetLeavedetails.ColumnSet = new ColumnSet("new_availabledays");
GetLeavedetails.Criteria.AddCondition("new_type", ConditionOperator.Equal, "Annual" ); //Is this correct????
GetLeavedetails.Criteria.AddCondition("new_employeeleavecalculation", ConditionOperator.Equal, LeaveDetailsId); //ignore this
//((OptionSetValue)LeaveDetailsId["new_leavetype"]).Value
EntityCollection LeaveDetails = _orgService.RetrieveMultiple(GetLeavedetails);
return LeaveDetails[0];
}

In your condition you need to set the integer value of the optionset, not the label.
Assuming that Annual value is for example 2, the code will be:
GetLeavedetails.Criteria.AddCondition("new_type", ConditionOperator.Equal, 2);

You should use RetrieveAttributeRequest to find an int value of OptionSet text.
In my code it looks like:
private static int findParkedOptionValue(IOrganizationService service)
{
RetrieveAttributeRequest attributeRequest = new RetrieveAttributeRequest
{
EntityLogicalName = Model.Invite.ENTITY_NAME,
LogicalName = Model.Invite.COLUMN_STATUS,
RetrieveAsIfPublished = false
};
// Execute the request
RetrieveAttributeResponse attributeResponse =
(RetrieveAttributeResponse)service.Execute(attributeRequest);
var attributeMetadata = (EnumAttributeMetadata)attributeResponse.AttributeMetadata;
// Get the current options list for the retrieved attribute.
var optionList = (from o in attributeMetadata.OptionSet.Options
select new { Value = o.Value, Text = o.Label.UserLocalizedLabel.Label }).ToList();
int value = (int)optionList.Where(o => o.Text == "Парковка")
.Select(o => o.Value)
.FirstOrDefault();
return value;
}
In https://community.dynamics.com/enterprise/b/crmmemories/archive/2017/04/20/retrieve-option-set-metadata-in-c you found a perfect example.

Related

How to pass or condition in Web Service Endpoints - Acumatica

I Have a requirement to pull the orders based on the Order Type conditions.I'm able to get the data by passing one order type,but i need to get the orders of two order types,couldn't find Or condition to Implement.
Here the code.
private static SalesOrder SOStokItem(DateTimeSearch whereCondition, StringSearch Condition, int rowCount)
{
SalesOrder item = new SalesOrder()
{
RowNumber = new LongSearch { Condition = LongCondition.IsLessThan, Value = rowCount },
ReturnBehavior = ReturnBehavior.OnlySpecified,
OrderType = new StringReturn(),
OrderNbr = new StringReturn(),
};
if (whereCondition != null)
item.LastModified = whereCondition;
if (Condition != null)
{
//item.OrderType = new StringSearch() { Condition = StringCondition.or, Value = "RC" };
//item.OrderType = new StringSearch() { Value = "RW" };
}
return item;
}
The SOAP API doesn't include or filter conditions on string fields.
You need to issue two SOAP requests to filter the sales orders with an or condition.

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 create purchase order via code?

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.

cannot get whole number attribute from entity with QueryExpression

Basicly, I was trying to get a whole number attribute from the entity to assign a value but when I check in debug, only "new_name" and "new_firmid" attributes shown.
Entity entity = new Entity("new_firm");
ConditionExpression condition = new ConditionExpression("new_name", ConditionOperator.Equal, "Firm");
QueryExpression query = new QueryExpression(entity.LogicalName);
query.ColumnSet = new ColumnSet("new_name","new_number");
query.Criteria = new FilterExpression();
query.Criteria.Conditions.Add(condition);
EntityCollection collection = service.RetrieveMultiple(query);
collection.Entities[0].Attributes["new_number"] = (int) collection.Entities[0].Attributes["new_number"] + 10;
service.Update(collection.Entities[0]);
You don't see the attribute new_number inside the entity attributes because the value is empty.
you need to check this condition before applying the new value, something like:
if (collection.Entities[0].Contains("new_number")) {
collection.Entities[0].Attributes["new_number"] = (int)collection.Entities[0].Attributes["new_number"] + 10;
} else {
collection.Entities[0].Attributes["new_number"] = 10; // assuming that empty equals 0
}

Return a set of objects from a class

I have a method that adds a new item to an EF table, then queries back the table to return a subset of the table. It needs to return to the caller a set of "rows", each of which is a set of columns. I'm not sure how to do this. I have some code, but I think it's wrong. I don't want to return ONE row, I want to return zero or more rows. I'm not sure what DataType to use... [qryCurrentTSApproval is an EF object, referring to a small view in SS. tblTimesheetEventlog is also an EF object, referring to the underlying table]
Ideas?
private qryCurrentTSApproval LogApprovalEvents(int TSID, int EventType)
{
using (CPASEntities ctx = new CPASEntities())
{
tblTimesheetEventLog el = new tblTimesheetEventLog();
el.TSID = TSID;
el.TSEventType = EventType;
el.TSEUserName = (string)Session["strShortUserName"];
el.TSEventDateTime = DateTime.Now;
ctx.tblTimesheetEventLogs.AddObject(el);
ctx.AcceptAllChanges();
var e = (from x in ctx.qryCurrentTSApprovals
where x.TSID == TSID
select x);
return (qryCurrentTSApproval)e;
}
}
Change your method return type to a collection of qryCurrentTSApproval
private List<qryCurrentTSApproval> LogApprovalEvents(int TSID, int EventType)
{
using (CPASEntities ctx = new CPASEntities())
{
// some other existing code here
var itemList = (from x in ctx.qryCurrentTSApprovals
where x.TSID == TSID
select x).ToList();
return itemList;
}
}

Resources