3

Just hit a few cases where it would be great to have a contact with exact same status eg event, member, relationship, contribution, and of course custom fields on contact and those other entities etc so we can 'test' a fix on.

Might not need to clone 'everything' eg Activities, since I can see complexity bursting forth.

Anyone else looked at doing this? Any thoughts about (im)possibility of doing this?

3

You can do a shallow clone with cv (and a little stripping of the original ID).

cv api Contact.getsingle id=203 | sed -e 's#"id"#"foo"#g' | sed -e 's#"contact_id"#"bar"#g' | cv api Contact.create --in=json

For the rest, you'd really need to specify the outcomes. Should the spouse be a clone too, or the original? The event registrations are for a cloned event or the original? The employer and other relationships?

1980s movie hijinks will abound as you explore the philosophical implications of cloning, in a time before it was a hellish near-reality.


OK, it's sprint, here's some JS to clone a contact:

// Go find a contact
CRM.api3('Contact', 'get', {
  "sequential": 1,
  "id": 361
}).done(function(res_old) {
  // Grab contact out and remove their ID.
  var contact_params = res_old.values[0];
  // Remove existing ID so we create a new contact.
  delete contact_params.id;
  delete contact_params.contact_id;
  // Create our new contact.
  CRM.api3('Contact', 'create', contact_params);
});

And, to clone a contact and related contributions:

// Cloning a full contact + related contributions (+ ...)
CRM.api3('Contact', 'get', {
  "sequential": 1,
  "id": 361
}).done(function(res_old) {
  // Grab contact out and remove their ID.
  var contact_params = res_old.values[0];
  // Remove existing ID so we create a new contact.
  delete contact_params.id;
  delete contact_params.contact_id;
  // Create our new contact.
  CRM.api3('Contact', 'create', contact_params)
    .done(function (res_new) {
      // Now handle related entities, one by one.
      // Contributions only as an example below.
      CRM.api3('Contribution', 'get', {contact_id: res_old.id})
        .done(function(res_contrib) {
          for (var key in res_contrib.values) {
            var new_contrib = res_contrib.values[key];
            // Returned values need to be adjusted so we create a new contribution.
            // Remove link(s) with previous contribution.
            delete new_contrib.id;
            delete new_contrib.contribution_id;
            // Associate with the new contact.
            new_contrib.contact_id = res_new.id;
            // Contribution.create requires financial_type_id, not provided by
            // Contribution.get. That's a whole other topic. Random ID here.
            // You'd actually need to use api "return" to get all fields.
            new_contrib.financial_type_id = 1;
            CRM.api3('Contribution', 'create', new_contrib)
              .done(function (res_newcontrib) {
                // console.log(res_newcontrib, 'rnc');
              }); //
          }
        });
        // Repeat as above for other related entities you wish to clone.
    });
});

And so on to clone Contact with related Participant, Contribution & Relationship records ... Some thoughts on this:

  • Cloning a contact or other simple entity is straightforward here.
  • Cloning related entities got verbose fast!
  • It's kinda weird that you have to remove both contribution.contribution_id and contribution.id, both contact.id and contact.contact_id ...
  • It's also kinda weird that you can't pipe a contribution.get back into a contribution.create because contribution.get does not return the (required) financial_type_id field.
  • Sounds like to handle this last point, the current approach would require using return with the API to specify all the fields on an entity, including the required ones not returned by default.
  • in the scenario i was thinking around, the Contact and any Participant, Contribution, Relationship records would be cloned. I was not requiring or even considering cloning spouses or Events. – petednz - fuzion May 2 '17 at 20:43
1

Interesting idea Pete! Not looking at doing this. I would certainly limit to basic contact data and custom fields on contact level as a start. Perhaps relationships would make sense but hard to determine if they all need cloning (for example case relationships probably not)....

  • Yep, my sense is the interdependency of CiviCRM entities would mean you'd need to specify what should happen with each related civi-thing your contact is connected to. The API calls will be the easy part! – Chris Burgess May 2 '17 at 10:34
  • Paul B wants to know How to clone a contribution? - maybe there's demand for an entity clone tool. – Chris Burgess May 2 '17 at 10:43
  • Excellent. Clone me a Burgess when you have it up and running ;-) – petednz - fuzion May 2 '17 at 10:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.