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.