How can I update ContentItem from a background task in Orchard? - orchardcms

The ContentItem I'm updating has a bool variable and I only know ContentItem Id. How can I update this variable from controller? I'm planning to send ajax request to the controller and then update.
I have a checkbox and I want to change bool variable when the user clicks it.
I tried to update it with ContentManager.Query() but I failed. This is the part where I'm planning to send the request.
$("li").click(function () {
if ($(this).hasClass('checked')) {
$(this).removeClass('checked');
//Make State False $(this).attr("id")
} else {
$(this).addClass('checked');
//Make State True $(this).attr("id")
}
});

In your controller, assuming you have injected a IContentManager instance named _contentManager, you should be able to do something like this (I'm assuming what you called a "bool variable" is a Boolean field named "State" under some part):
public ActionResult SetState(int contentItemId, bool state) {
var contentItem = _contentManager.GetLatest(id);
if (contentItem == null) return HttpNotFound();
var field = contentItem
.Parts
.SelectMany(p => p.Fields)
.FirstOrDefault(f => f.Name == "State") as BooleanField;
if (field != null) {
field.Value = state;
}
return RedirectToAction("SomeAction");
}

Related

Acumatica - Need Help in Updating Activities in Project Quotes Screen PM304500 through custom action

I have a custom action on screen CR304000 - OpportunityMaint in the Quotes tab of the grid view that marks a field called IsPrimary in the CRQuote DAC as true for the current record in the Quotes view. These project Quotes are associated with the current opportunity as well as with a related PMQoute in the PMQuoteMaint BLC. The PMQuoteMaint BLC has a view called Activties that has all the CRActivities associated with the PMQuote. I created a custom field in the CRActivity called IsPrimary and added it to the Activities view in the PMQuoteMaint BLC grid.
My goal was to override the Action in the OpportunityMaint to update the IsPrimary field in CRActivity to true or false depending on what the Action in OpportunityMaint is toggling. However, my IsPrimary field in PMQuoteMaint is not toggling. My code attempts to get Current Quote OpportunityMain and then create a PMQuoteMaint graph and set the Current record. Then iterate though Activies view and set the IsPrimary field accordingly. Like I said, not having success because I'm not sure that my code is successfully retrieving the correct Activities.
There might be a better way to access CRActivity associated with a PMQuote, but I'm not sure. Any help would be appreciated. Here is code:
public virtual IEnumerable PrimaryQuote(PXAdapter adapter)
{
foreach (CROpportunity opp in adapter.Get())
{
if (Quotes.Current?.IsPrimary != true)
{
var selectExistingPrimary = new PXSelect<CRQuote, Where<CRQuote.quoteID,
Equal<Required<CRQuote.quoteID>>>>(this);
CRQuote primary = selectExistingPrimary.Select(opp.DefQuoteID);
if (primary != null && primary.QuoteID != Quotes.Current.QuoteID && primary.Status ==
PM.PMQuoteStatusAttribute.Closed)
{
throw new PXException(PM.Messages.QuoteIsClosed, opp.OpportunityID,
primary.QuoteNbr);
}
var quoteID = Quotes.Current.QuoteID;
var opportunityID = this.Opportunity.Current.OpportunityID;
this.Persist();
PXDatabase.Update<Standalone.CROpportunity>(
new PXDataFieldAssign<Standalone.CROpportunity.defQuoteID>(quoteID),
new PXDataFieldRestrict<Standalone.CROpportunity.opportunityID>(PXDbType.VarChar,
255, opportunityID, PXComp.EQ)
);
this.Cancel.Press();
CROpportunity rec = this.Opportunity.Search<CROpportunity.opportunityID>
(opportunityID);
yield return rec;
}
yield return opp;
}
``` My OverRide
public PXAction<CROpportunity> primaryQuote;
[PXUIField(DisplayName = Messages.MarkAsPrimary)]
[PXButton]
public virtual IEnumerable PrimaryQuote(PXAdapter adapter)
{
// this is currently selected record in quotes grid
var currQuoteNbr = Base.Quotes.Current.QuoteNbr;
bool isPrimary2;
foreach (CRQuote quote in Base.Quotes.Select())
{
var quoteNbr = quote.QuoteNbr;
if(quoteNbr.Trim() == currQuoteNbr.Trim())
{
isPrimary2 = true;
}
else
{
isPrimary2 = false;
}
PXTrace.WriteInformation(string.Format("Quote: {0} Value:
{1}",quoteNbr.ToString(),isPrimary2.ToString()));
var PMQuoteMaintGraph = PXGraph.CreateInstance<PMQuoteMaint>();
PMQuoteMaintGraph.Quote.Current = PMQuoteMaintGraph.Quote.Search<PMQuote.quoteNbr>
(quoteNbr.Trim()); // this is the current quote
foreach (CRActivity activity in PMQuoteMaintGraph.Activities.Select())
{
CRActivityExt itemExt = PXCache<CRActivity>.GetExtension<CRActivityExt>(activity);
itemExt.UsrPrimary = isPrimary2;
PMQuoteMaintGraph.Activities.Cache.Persist(PXDBOperation.Update);
PXDatabase.Update<CRActivity>(new PXDataFieldAssign<CRActivityExt.usrPrimary>
(isPrimary2));
}
}
return Base.primaryQuote.Press(adapter);
}

Update Project's attribute value from Different Page

I need help to update the value of Project's attribute from different page.
I have fetched the attribute value in 'Appointments' page using following code.
protected void FSAppointment_RowSelected(PXCache cache, PXRowSelectedEventArgs e, PXRowSelected InvokeBaseHandler)
{
if (InvokeBaseHandler != null)
InvokeBaseHandler(cache, e);
var row = (FSAppointment)e.Row;
AppointmentEntry graph = (AppointmentEntry)cache.Graph;
if (graph.ServiceOrderRelated.Current != null)
{
int? projectID = graph.ServiceOrderRelated.Current.ProjectID;
ProjectEntry projectGraph = PXGraph.CreateInstance<ProjectEntry>();
projectGraph.Project.Current = projectGraph.Project.Search<PMProject.contractID>(projectID);
foreach (CSAnswers att in projectGraph.Answers.Select())
{
if (att.AttributeID == "ESTHOURS")
{
cache.SetValueExt<FieldService.ServiceDispatch.FSAppointmentExt.usrProjectEstimatedRemainingHours>(row, att.Value);
return;
}
}
}
}
And, now I want user to be able to update that particular attribute's value from 'Appointments' page.
For that, I had written following code by overriding the Persist method of 'Appointments' page.
public delegate void PersistDelegate();
[PXOverride]
public void Persist(PersistDelegate baseMethod)
{
if (Base.ServiceOrderRelated.Current != null)
{
using (PXTransactionScope scope = new PXTransactionScope())
{
int? projectID = Base.ServiceOrderRelated.Current.ProjectID;
ProjectEntry projectGraph = PXGraph.CreateInstance<ProjectEntry>();
var project = projectGraph.Project.Search<PMProject.contractID>(projectID);
var answers = projectGraph.Answers.Select();
foreach (CSAnswers att in answers)
{
if (att.AttributeID == "ESTHOURS")
{
att.Value = "20";
}
}
projectGraph.Actions.PressSave();
}
}
baseMethod();
}
But still it is not updating the value.
The thing to realize is that the attribute system is different that the usual DAC->SQL system. CSAnswers is a unnormalized table of values for all the attributes. They are linked to a DAC document by RefNoteID. See select * from CSAnswers where AttributeID = 'ESTHOURS' In the code above you are altering every project's 'esthours'. You're also missing a statement where you tell the graph to update the cache with your altered object. Something like projectGraph.Answers.Update(att);

How to reference a custom helper in controller method as I did in the view

I made a grid helper in App_Code called ControlHelper and it works just fine. I renders a form and a table with inputs and has buttons to submit all the information back to a method of my choosing.
I can tell that the controller code to handle the submits off this grid is going to be the same every time, so I added a method called Submit() onto my helper to reuse that code.
I can successfully call the helper method to render the grid from my view with
#ControlHelper.Grid(Html, Model, "About", "Home")
But when I try to call ControlHelper.Submit() from my controller code it says my helper is undefined.
The name 'ControlHelper' does not exist in the current context
Here's the relevant part of the code of the helper:
#using System.Web.Mvc;
#using System.Web.Mvc.Html;
#using male.services.biz
#functions
{
public static HelperResult Grid<TModel, T>(HtmlHelper<TModel> html,
EFCollection<T> collection,
string action,
string controller,
FormMethod method = FormMethod.Post,
string formName = null) where T : EFObject<T>
{
formName = formName ?? "frm" + typeof(T).Name + "s";
return RenderGrid(html, typeof(T), collection, action, controller, method, formName);
}
public static void Submit<T>(EFCollection<T> collection, string save, string add, string delete) where T : EFObject<T>
{
if (add == null)
collection.Remove(collection.Last());
if (delete != null)
{
var itemToDelete = collection[int.Parse(delete)];
collection.Remove(itemToDelete);
itemToDelete.Delete();
}
if (add != null || delete != null || save != null)
collection.Save();
}
}
My controller code currently is:
[HttpPost]
public ActionResult About(EFCollection<Member> members, string save, string add, string delete)
{
if (add == null)
members.Remove(members.Last());
if (delete != null)
{
var memberToDelete = members[int.Parse(delete)];
members.Remove(memberToDelete);
memberToDelete.Delete();
}
if (add != null || delete != null || save != null)
members.Save();
return View(members);
}
but see if I can get this to work it will reduce to just:
[HttpPost]
public ActionResult About(EFCollection<Member> members, string save, string add, string delete)
{
ControlHelper.Submit(members, save, add, delete);
return View(members);
}
The answer is, I don't do this like this any more. I use shared edit / display views for certain types and classes to achieve what I want.

AttributeRouting: Multiple routes based on user roles

thank you for your reply,
i added BeginExecuteCore in base controller like this
`public class BaseController : Controller
{
protected override IAsyncResult BeginExecuteCore(AsyncCallback callback, object state)
{
//string email = string.Empty;
dbEntities dbcontext = new dbEntities();
var userRoleName = (from n in dbcontext.VAgentClientEmails where n.Email == User.Identity.Name select n.Role).FirstOrDefault();
if (userRoleName == "SuperAdmin")
RouteData.Values["role"] = userRoleName;
else
RouteData.Values["role"] = "";
return base.BeginExecuteCore(callback, state);
}`
and i have given in home controller like this
[Route("~/{role}/SavedSearch/Index")]
public ActionResult Index()
{
...
}
its working for admin/savedsearch/index
and also if i give fjsdfk/savedsearch/index its working
in the above case it should not work..
and in else case i dont want role
do i need to do any changes?

Orchard CMS: How to get specific Content Item in Controller without ID

I just wondering how can I get an specific ContentItem in my controller.
I want to get the specific content Item and then display it's shape on my custom View..
PS: I also dont know how to get the ID of the content item should i use the ContentManager.Get(ID)
[HttpGet]
public ActionResult Index(string jobType, string location) {
var vm = new SearchForJobViewModel();
var items = new List<CustomPart>();
// Load the WhatsAround content items
IEnumerable<ContentItem> whatsAroundContentItems = ContentManager.Query().ForType("Custom").List();
foreach (ContentItem contentItem in whatsAroundContentItems)
{
ContentItemRecord contentItemRecord = contentItem.Record;
if (contentItem == null)
continue;
//CustomPart item = new CustomPart(contentItemRecord.Data);
//items.Add(item);
}
//Im also planning to pass the ContentItem in the view and then render it there
//return View("../JobSearchResults", items.Single(i => i.Name == "MyContentItem");
return View("../JobSearchResults", vm);
}
ADDITIONAL
[Themed]
[HttpGet]
public ActionResult Index(string jobType, string location) {
var vm = new SearchForJobViewModel();
vm.SelectedJobType = jobType;
vm.SelectedLocation = location;
//query all the content items
IEnumerable<ContentItem> items = ContentManager.Query().List();
foreach (ContentItem contentItem in items) {
ContentItemRecord contentItemRecord = contentItem.Record;
if (contentItem == null)
continue;
if (contentItemRecord.ContentType.Name == "CustomPage") {
// I just painfully search the contents just to get the ID of the specific content item that I want to display
// I dont know what table where I can see the ID on the content items
if (contentItemRecord.Id == 40) {
ContentItem ci = contentItem;
var test = ci.As<CustomPart>().Scripts; //custom part that I made
// the body part (raw html from the wysiwg editor)
// this I wil render it in my view
vm.Body = ci.As<BodyPart>().Text;
}
}
}
return View("../JobSearchResults", vm);
}
JobSearchResults.cshtml
#Html.Raw(Model.Body)
It's actually looks wierd but I'm trying something like utilizing Orchard CMS without using Orchard core (contentpart, drivers,handlers, etc)
Your can refer this.
http://skywalkersoftwaredevelopment.net/blog/getting-the-current-content-item-in-orchard
Or using the driver
protected override DriverResult Display(YourModulePart part, string displayType, dynamic shapeHelper){
var title = part.As<TitlePart>();
//here you can access the title part.
}

Resources