2

I'm making a button on PhoneCall ribbon that creates follow up call. I've tried to do this with javascript, with XrmServiceToolkit. Looks like I can't do it at all with SOAP end point and doing it with REST is some what tricky.

How do I copy to and from fields to a new activity?

Update Originally I tried using XrmServiceToolkit javascript library, but switched to C# for copying fields, following Peter's answer.

Still, no result. I do it this way:

EntityCollection toCollection = new EntityCollection();
foreach (var activityParty in ((EntityCollection)previousActivity["to"]).Entities)
{
    Entity newActivityParty = new Entity(ActivityParty.EntityLogicalName);
    newActivityParty["activityid"] = new EntityReference(context.PrimaryEntityName, context.PrimaryEntityId);
    newActivityParty["partyid"] = activityParty["partyid"];
    newActivityParty["participationtypemask"] = new OptionSetValue(2);//activityParty["participationtypemask"];
    //service.Create(newActivityParty);

    toCollection.Entities.Add(newActivityParty);
}
entity["to"] = toCollection;

What's the right way to do it?

chiwangc
  • 3,566
  • 16
  • 26
  • 32
skfd
  • 2,528
  • 1
  • 19
  • 29

3 Answers3

1

If you're finding it troublesome with JavaScript and you want a more front-end way of doing things, you could have a solution where you click your ribbon button which opens a new phone call form with the details you require pre-populated. You construct the URL with the parameters you require from your current form and this will set the values on your new form (your follow up phone call). Take a look at MSDN - Setting field values using paramaters.

You should be able to copy your to and from fields to the new form this way.

Note that this is an alternative. If you're wanting to completely automate the creation of the follow up phone call with JavaScript then I'd recommend using the REST endpoint and posting some code if you have difficulties.

David Spence
  • 7,999
  • 3
  • 39
  • 63
  • Passing parameters to a form will not do, because: >You cannot set the values for partylist or regarding lookups. So, I'll update question with REST code. – skfd May 11 '12 at 08:39
1

Edit: On thinking this over, the most logically correct approach is as follows:

  1. Create a self-referential lookup field/relationship in the PhoneCall entity (the target of which is PhoneCall), called something like new_OriginatingCall. This will provide you your trail of follow up phone calls.
  2. Create a Create, pre-operation/validation plug-in on the PhoneCall entity that checks for the existence of a value in the new_OriginatingCall field. If it exists, populate the to and from fields from the originating PhoneCall.
  3. In the javascript attached to your button, create a new PhoneCall with the new_OriginatingCall populated.

This way, no matter how a follow-up call is generated, the to and from fields are always populated correctly server-side.

Edit: See below for a sample of how to retrieve and set PartyLists via Linq.

// newPc is the Target entity of the plugin.
var pc = xsc.PhoneCallSet
    .Single(x => x.ActivityId == newPc.new_OriginatingCall.Id);
// pc is now a copy of the original phone call.

// Have to make new activity party lists because the activity parties attached to
// the original phone call activity have the activity id set to the original
// phone call.
// Trying to attach them unchanged to the new phone call (which would have a new 
// activity id) results in a FaultException.
var to = pc.To.Select(x => new ActivityParty { PartyId = x.PartyId });
var from = pc.From.Select(x => new ActivityParty { PartyId = x.PartyId });

// Prep the new phone call.
PhoneCall pcNew = new PhoneCall
{
    To = to,
    From = from,
    Subject = pc.Subject,
    ActualDurationMinutes = pc.ActualDurationMinutes,
    DirectionCode = pc.DirectionCode,
    PhoneNumber = pc.PhoneNumber
};

// Create the new phone call.
service.Create(pcNew);

If you can more easily assemble PartyLists in .NET than in javascript, I strongly recommend using one of the two best answers suggested in the great question Call C# Code from Ribbon JScript CRM Online 2011 (i.e. trigger your code via the creation of a "plugin" custom entity or include a field in the PhoneCall entity that is set via javascript, and on update, triggers a plugin that examines the state of that field and reacts accordingly).

I've used both approaches often, as it's often complicated to achieve similar results in the CRM with javascript.

Community
  • 1
  • 1
Peter Majeed
  • 5,304
  • 2
  • 32
  • 57
  • That's clever! I'll give it a try and report the result. – skfd May 13 '12 at 18:06
  • How do I copy this fields in C#? Tried obvious ways with no result :( – skfd May 27 '12 at 15:11
  • I tried to make late-bound version out of your sample, but ended up switching back to js. Target entity can not be modified with LINQ on pre-Create, as far as I know :( – skfd May 31 '12 at 11:16
  • @skfd: Two things: 1) Why use late-bound entities? If you need a hand getting started developing using early-bound classes, that would probably make things easier. 2) Linq is a query language, not (really) a way to set values for entities. So the values are queried via Linq, but the Target entity can be updated whether you use Linq to get your values or not. In any event, glad you got it working via javascript, which can always be a challenge (though presumably you'd want to get it working server side eventually). – Peter Majeed May 31 '12 at 13:20
  • By "modified with LINQ" I meant "modified as an early-bound class". I'd love to use early-bound, but TargetEntity comes as an `Entity`, not an early-bound class. I tried doing: `entity = (Entity)context.InputParameters["Target"]; entity["to"] = pc.To.Select(x => new ActivityParty { PartyId = x.PartyId });`, but it threw type mismatch -- one is IEnumerable, other is EntityCollection. I tried couple of things to fix it, but they did not work. – skfd May 31 '12 at 13:46
  • 1
    You can cast the `Target` `Entity` object as a CRM object by using something like this: `var entity = (Entity)context.InputParameters["Target"]; PhoneCall phoneCall = entity.ToEntity();`. You can then assign values to that new CRM object the same way you would to `Target`. – Peter Majeed May 31 '12 at 13:53
  • Wow, casting `Target` to `Entity` this way works like a charm! Thank you, Peter. – skfd Jul 05 '12 at 13:32
1

Ended up doing it with JavaScript, after all:

function main() {
    var newActivity = new XrmServiceToolkit.Soap.BusinessEntity('phonecall');

    newActivity.attributes['phonecall'] = {
        id : Xrm.Page.data.entity.getId(),
        logicalName : 'phonecall',
        type : 'EntityReference'
    }

    newActivity.attributes['to'] = {
        type: 'EntityCollection',
        value: lookupToEntityReferenceCollection('to')
    }

    var newId = XrmServiceToolkit.Soap.Create(newActivity);
}

function lookupToEntityReferenceCollection(lookupName) {
    var result = [],
        lookupValue = Xrm.Page.getAttribute(lookupName).getValue();

    if (lookupValue === null) {return result;}

    var arrayLength = lookupValue.length;

    for (var i = 0; i < arrayLength;i++) {
        result.push({
            id: lookupValue[i].id, 
            logicalName: lookupValue[i].typename,
            type: 'EntityReference'
        });
    }
    return result;
}
skfd
  • 2,528
  • 1
  • 19
  • 29