Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to associate Activity Parties #16

Open
shaunjc opened this issue Nov 5, 2019 · 6 comments
Open

Ability to associate Activity Parties #16

shaunjc opened this issue Nov 5, 2019 · 6 comments
Labels
enhancement New feature or request

Comments

@shaunjc
Copy link

shaunjc commented Nov 5, 2019

Native support for Activity parties does not appear to be a core part of the toolkit functionality. The serialization helper seems to strip these fields as they do not show in the returned metadata with the current implementation.

As an example, attempting to create a campaignresponse with a matching customer does not work like the standard way to update and associate records.

$contact_ref = new \AlexaCRM\Xrm\EntityReference( 'contact', $contactid );

// $campaignresponse['customer'] is stripped out during $serializer->serializeEntity( $campaignresponse ); A 400 Bad Request error would be thrown otherwise.
$campaignresponse['customer'] = $contact_ref;

// A different 400 Bad Request error is thrown for attempting to associate using this action.
$client()->Associate(
    'campaignresponse',
    $campaignresponse->Id,
    new \AlexaCRM\Xrm\Relationship( 'contact_campaigncesponses' ),
    [ $contact_ref ]
);

// Same for the reverse association - a similar error will be thrown.
$client()->Associate(
    'contact',
    $contactId,
    new \AlexaCRM\Xrm\Relationship( 'contact_campaigncesponses' ),
    [ new \AlexaCRM\Xrm\EntityReference( 'campaignresponse', $campaignresponse->Id )]
);

// It is possible to set this by serializing the data, adjusting the payload and using the OData Client.
$serializer = new \AlexaCRM\WebAPI\SerializationHelper( $client->getClient() );
// Creating the ActivityParty as an Entity helps with serialization.
$activityparty = new \AlexaCRM\Xrm\Entity( 'activityparty' );
$activityparty['partyid'] = $contact_ref;
$activityparty['participationtypemask'] = 11;
// Activity Party and campaign response are serialized and attached to each other.
$translatedData = $serializer->serializeEntity( $campaignresponse );
$translatedData['campaignresponse_activity_parties'] = array( $serializer->serializeEntity( $activityparty ) );
// Using the OData\Client gets around serialized data being lost.
$client->getClient()->update( $client->getClient()->getMetadata()->getEntitySetName( 'campaignresponse' ), $translatedData );

A new class for Activity Party entity types which encode themselves appropriately and possibly match the correct parts of the metadata, would help simplify the process of linking data.

// Potential new class
class ActivityParty implements \ArrayAccess {
    public $Entities = [];
    public function __construct( $entityReference, $type ) {
    }
}
// Possible example usage
$activityparty = new ActivityParty( $contact_ref, ActivityParty::TYPE_CUSTOMER );
$campaignresponse['campaignresponse_activity_parties'] = $activityparty;
@wizardist
Copy link
Collaborator

wizardist commented Nov 5, 2019

Hi @shaunjc

Could you provide error messages received from Web API please? Thanks

@shaunjc
Copy link
Author

shaunjc commented Nov 5, 2019

Hi @wizardist,

Each of these throw a 400 Bad Request when attempting to POST the following data.

$translatedData['[email protected]'] = "/contacts({$contactid})";

An undeclared property 'customer' which only has property annotations in the payload but no property value was found in the payload. In OData, only declared navigation properties and declared named streams can be represented as properties without values.

$translatedData['customer'] = array( $customer_ref );

An error occurred while validating input parameters: Microsoft.OData.ODataException: Does not support untyped value in non-open type.

$client()->Associate(
    'campaignresponse',
    $campaignresponse->Id,
    new \AlexaCRM\Xrm\Relationship( 'contact_campaigncesponses' ),
    [ $contact_ref ]
);

The URI segment '$ref' is invalid after the segment 'customers'.

$client()->Associate(
    'contact',
    $contactId,
    new \AlexaCRM\Xrm\Relationship( 'contact_campaigncesponses' ),
    [ new \AlexaCRM\Xrm\EntityReference( 'campaignresponse', $campaignresponse->Id )]
);

The URI segment '$ref' is invalid after the segment 'contact_campaignresponses'.

@wizardist
Copy link
Collaborator

Hi @shaunjc

One thing I want to point out is that relationship schema names are case-sensitive and sensitive to spelling mistakes. And CDS / Dynamics 365 have a contact_CampaignResponses relationship. And only contact entity has this relationship. Its partner in campaignresponse is regardingobjectid_contact_campaignresponse.

customer and customers are party lists, and they are not exposed to Web API. I'm afraid you will have to create activityparty records with the corresponding participationtypemask, in this case it's 11 (Customer).

@shaunjc
Copy link
Author

shaunjc commented Nov 5, 2019

Hi @wizardist,

That does seem odd as the only items that I've seen that are in PascalCase are the entity properties. All other data I get from the API (and in turn submit back to it), such as each of the attribute keys and entity names, are all in lowercase.

The case sensitivity here probably explains why the Contact relation didn't work, and while I did find the regardingobjectid_contact_campaignresponse, I didn't expect that to be the relationship name.

Regardless, the last paragraph in that first code block was what I implemented to get the data saving in the first place.

// It is possible to set this by serializing the data, adjusting the payload and using the OData Client.
$serializer = new \AlexaCRM\WebAPI\SerializationHelper( $client->getClient() );
// Creating the ActivityParty as an Entity helps with serialization.
$activityparty = new \AlexaCRM\Xrm\Entity( 'activityparty' );
$activityparty['partyid'] = $contact_ref;
$activityparty['participationtypemask'] = 11;
// Activity Party and campaign response are serialized and attached to each other.
$translatedData = $serializer->serializeEntity( $campaignresponse );
$translatedData['campaignresponse_activity_parties'] = array( $serializer->serializeEntity( $activityparty ) );
// Using the OData\Client gets around serialized data being lost.
$client->getClient()->update( $client->getClient()->getMetadata()->getEntitySetName( 'campaignresponse' ), $translatedData );

As you can see I did use the participationtypemask of 11, and it works so long as I update the serialized data and access the OData client.

I still think that finding some way to expose / leverage Party Lists through the Web API would be a beneficial feature to have, however I understand if you would prefer to close this feature request.

@wizardist
Copy link
Collaborator

@shaunjc What you're trying to do here is a deep insert, and the toolkit indeed does not support that yet. But it is a valid feature request. 👍

As for exposing party lists, we would require to look up organization metadata instead of OData metadata, which is a different beast. But it is doable in theory ;)

@wizardist wizardist added the enhancement New feature or request label Nov 5, 2019
@shaunjc
Copy link
Author

shaunjc commented Nov 6, 2019

On the topic of deep retrievals, the easiest way I found to access and manage associations was to access the ODataClient.

$_accounts = $client->getClient()->getRecord(
    $client->getClient()->getMetadata()->getEntitySetName( 'list' ),
    $list->listid,
    [
        'Expand' => 'listaccount_association',
        'Select' => [ 'listaccount_association' ]
    ]
);
foreach ( $_accounts->listaccount_association as $_account ) {
    $account = $serializer->deserializeEntity(
        $_account,
        new AlexaCRM\Xrm\EntityReference( 'account', $_account->accountid )
    );
   // Do stuff here.
}

Adding a new optional parameter to Client::Retrieve to update $options before they are sent to ODataClient::getRecord may be a suitable solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants