diff --git a/README.md b/README.md index 1969a59a1..5ec7e9eb1 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ The following Xero API functions are supported: * Bank Transfers * Branding Themes * Contacts +* Contact Groups * Credit Notes * Currencies * Invoices diff --git a/docs/Contact-Groups.md b/docs/Contact-Groups.md new file mode 100644 index 000000000..2abe2c8ec --- /dev/null +++ b/docs/Contact-Groups.md @@ -0,0 +1,249 @@ +The following examples explain the Contacts Groups section of the SDK. The API documentation on Contact Groups can be found [here](https://developer.xero.com/documentation/api/contactgroups). + +### Supported functions + +* Create New Contact Groups +* Retrieve Contact Groups (all, by ID, or with 'where' clause) +* Update Contact Group Name +* Delete Contact Group +* Add Contacts to Contact Group +* Remove Contacts from Contact Group (single/all) + +These functions are explained further below. + +### Entity Helper + +The entity helper that has been created for the contact groups functions exists in the following place: + +`client.core.contactGroups` + +This helper contains the following functions: + +* `newContactGroup(data[, options])` +* `getContactGroups([options])` +* `getContactGroup(id[, modifiedAfter])` + +The ContactGroup itself has the following functions: + +* `save([options])` +* `saveContacts(contacts)` +* `deleteContact(contactID)` +* `deleteAllContacts()` + +### Creating a new contact group + +This code assumes you've already created a client using the xero-node sdk. + +```javascript + +var sampleContactGroup = { + Name: 'New Contacts', + Status: 'ACTIVE' +}; + +var contactGroupObj = xeroClient.core.contactGroups.newContactGroup(sampleContactGroup); + +contactGroupObj.save() + .then(function(contactGroups) { + //Contact Group has been created + var myGroup = contactGroups.entities[0]; + }) + .catch(function(err) { + //Some error occurred + }); +``` + +Some points to note with the code snippet above: + +* The `.newContactGroup()` function doesn't actually make any API call to Xero. It only creates an object according to the contact schema that _can_ be saved using the `.save()` function at some point in future. +* The `.save()` function returns a promise that can be met using the `.then()` function, and rejections can be caught using the `.catch()` function. +* The promise that is returned by the `.save()` function contains a response object. This has a bunch of information about the state of the response, but also contains an `entities` array. This array is what actually contains the object that was just created. +* For single object saving, this `entities` array should only ever contain one element, but some objects support a multiple object save and in this case the `entities` array will contain all of the objects that were created. + +### Creating multiple contact groups + +This functionality allows developers to create multiple contact groups in one call to the SDK, rather than iterating. + +```javascript + +var data = [{ + Name: 'Johnnies Coffee', + Status: 'ACTIVE' +},{ + Name: 'Jimmies Cups', + Status: 'ACTIVE' +}]; + +var contactGroups = []; + +contactGroups.push(xeroClient.core.contactGroups.newContactGroup(data[0])); +contactGroups.push(xeroClient.core.contactGroups.newContactGroup(data[1])); + +xeroClient.core.contactGroups.saveContactGroups(contactGroups) + .then(function(response) { + //Contact Groups have been created + console.log(response.entities[0].Name); // 'Johnnies' + console.log(response.entities[1].Name); // 'Jimmies' + }) + .catch(function(err) { + //Some error occurred + }); +``` + +### Retrieving All Contact Groups + +This example shows how to retrieve all contact groups in a single call. + +```javascript + +xeroClient.core.contactGroups.getContactGroups() + .then(function(contactGroups) { + //We've got some groups + contactGroups.forEach(function(contactGroup){ + //do something useful + console.log(contactGroup.Name); + }); + }) +``` + +* When using the getContactGroups method, as no object is being saved there is no `entities` array. Instead you are provided an array of contactGroup objects that you can use directly in your application. + +### Retrieving ContactGroups by ID + +This example shows how to retrieve a contact group using the Xero supplied GUID. + +```javascript + +var myContactGroupID = '288762e4-67a9-442d-9956-9a14e9d8826e'; + +xeroClient.core.contactGroups.getContactGroup(myContactGroupID) + .then(function(contactGroup) { + //We've got the contact group so do something useful + console.log(contactGroup.Name); + }); +``` + +### Retrieving Contact Groups with filters + +This example shows how to retrieve a Contact Group using the 'where' filter. + +```javascript + +//filter contact groups that are type Customer +const filter = 'Name.Contains("Jim")'; + +xeroClient.core.contactGroups.getContactGroups({where: filter}) + .then(function(contactGroups) { + //We've got some groups + contactGroups.forEach(function(group){ + //do something useful + console.log(group.Name); //will contain 'Jim' + }); + }) +``` + +### Updating Contact Groups + +This example shows how to update a contact group that's been retrieved via the SDK. + +```javascript + +var someContactGroupID = '75520d2e-e19d-4f36-b19b-e3b9000b2daa'; + +xeroClient.core.contactGroups.getContactGroup(someContactGroupID) + .then(function(group) { + //We've got the group so now let's change the name + group.Name = 'My awesome new name'; + + return group.save(); + }) + .then(function(response) { + const thisGroup = response.entities[0]; + console.log(thisGroup.Name); //'My awesome new name' + }) +``` + +### Add a Contact to a Contact Group + +This example shows how to add an existing contact to a contact group that has been created. + +_Note:_ It's not possible to create a contact group with contacts at the same time. This must be done with two calls to the SDK. + +```javascript + +const contacts = [{ + ContactID: '75520d2e-e19d-4f36-b19b-e3b9000b2daa' +}]; +const someContactGroupID = '9d9vcd9-a0df-2bfe-39fd-0c0d0es9f0'; + +xeroClient.core.contactGroups.getContactGroup(someContactGroupID) + .then(function(group) { + // We've got the group so now let's save the new contacts + return group.saveContacts(contacts); + }) + .then(function(response) { + // This response contains a list of contacts that were just added + const groupContacts = response.entities[0]; + console.log(groupContacts[0].ContactID); // '75520d2e-e19d-4f36-b19b-e3b9000b2daa' + }) +``` + +### Delete a Contact from a Contact Group + +This example shows how to remove a contact from a contact group. + +```javascript + +const contactIDToRemove = '75520d2e-e19d-4f36-b19b-e3b9000b2daa'; +const someContactGroupID = '9d9vcd9-a0df-2bfe-39fd-0c0d0es9f0'; + +xeroClient.core.contactGroups.getContactGroup(someContactGroupID) + .then(function(group) { + // We've got the group so now let's delete a contact + return group.deleteContact(contactIDToRemove); + }) + .then(function(response) { + // if all was successful response will be an empty object + console.log(response) // will be {} + }) +``` + +### Delete all Contacts from a Contact Group + +This example shows how to remove all contacts from a specified contact group. + +```javascript + +const someContactGroupID = '9d9vcd9-a0df-2bfe-39fd-0c0d0es9f0'; + +xeroClient.core.contactGroups.getContactGroup(someContactGroupID) + .then(function(group) { + // We've got the group so now let's delete a contact + return group.deleteAllContacts(); + }) + .then(function(response) { + // if all was successful response will be an empty object + console.log(response) // will be {} + }) +``` + +### Delete a Contact Group + +This example shows how to remove a Contact Group completely + +```javascript + +const someContactGroupID = '9d9vcd9-a0df-2bfe-39fd-0c0d0es9f0'; + +xeroClient.core.contactGroups.getContactGroup(someContactGroupID) + .then(function(group) { + //We've got the group so now let's change the Status + group.Status = 'DELETED'; + + return group.save(); + }) + .then(function(response) { + const thisGroup = response.entities[0]; + console.log(thisGroup.Status); // 'DELETED' + }) +``` diff --git a/lib/entities/accounting/contactgroup.js b/lib/entities/accounting/contactgroup.js index 79bb82489..f85d91326 100644 --- a/lib/entities/accounting/contactgroup.js +++ b/lib/entities/accounting/contactgroup.js @@ -65,9 +65,9 @@ const ContactGroup = Entity.extend(ContactGroupSchema, { ); }, deleteContact: function(contactID) { - return this.deleteContacts(contactID); + return this.deleteAllContacts(contactID); }, - deleteContacts: function(contactID) { + deleteAllContacts: function(contactID) { let path = `ContactGroups/${this.ContactGroupID}/Contacts/`; if (contactID) { diff --git a/lib/entity_helpers/accounting/contactgroups.js b/lib/entity_helpers/accounting/contactgroups.js index b9bcf6417..675073d95 100644 --- a/lib/entity_helpers/accounting/contactgroups.js +++ b/lib/entity_helpers/accounting/contactgroups.js @@ -23,6 +23,9 @@ const ContactGroups = EntityHelper.extend({ _.first(contactGroups) ); }, + saveContactGroups: function(contactGroups, options) { + return this.saveEntities(contactGroups, this.setUpOptions(options)); + }, setUpOptions: function(options) { const self = this; const clonedOptions = _.clone(options || {}); diff --git a/test/core/contactgroups_tests.js b/test/core/contactgroups_tests.js index 4e47055fc..477388d3e 100644 --- a/test/core/contactgroups_tests.js +++ b/test/core/contactgroups_tests.js @@ -59,6 +59,24 @@ describe('Contact Groups', () => { }); }); + it('get with filter', done => { + const filter = 'Name.Contains("Updated")'; + common.currentApp.core.contactGroups + .getContactGroups({ + where: filter, + }) + .then(contactGroups => { + contactGroups.forEach(contactGroup => { + expect(contactGroup.Name.indexOf('Updated')).to.be.greaterThan(-1); + }); + done(); + }) + .catch(err => { + console.error(err); + done(wrapError(err)); + }); + }); + it('creates a contact group', done => { const contactGroup = common.currentApp.core.contactGroups.newContactGroup( sampleContactGroup @@ -77,6 +95,34 @@ describe('Contact Groups', () => { }); }); + it('create multiple contact groups', done => { + const contactGroups = []; + + for (let i = 0; i < 2; i += 1) { + contactGroups.push( + common.currentApp.core.contactGroups.newContactGroup({ + Name: `New Contacts ${Math.random()}`, + Status: 'ACTIVE', + }) + ); + } + + common.currentApp.core.contactGroups + .saveContactGroups(contactGroups) + .then(response => { + expect(response.entities).to.have.length.greaterThan(0); + response.entities.forEach(contactGroup => { + expect(contactGroup.ContactGroupID).to.not.equal(''); + expect(contactGroup.ContactGroupID).to.not.equal(undefined); + }); + done(); + }) + .catch(err => { + console.error(err); + done(wrapError(err)); + }); + }); + it('Updates a contact group', done => { const updatedName = `Updated ${Math.random()}`; common.currentApp.core.contactGroups @@ -152,7 +198,7 @@ describe('Contact Groups', () => { .getContactGroup(sampleContactGroup.ContactGroupID) .then(contactGroup => { expect(validateContactGroup(contactGroup)).to.equal(true); - return contactGroup.deleteContacts(); + return contactGroup.deleteAllContacts(); }) .then(() => { done(); diff --git a/test/core/contacts_tests.js b/test/core/contacts_tests.js index 4dd550fa7..cf24fde82 100644 --- a/test/core/contacts_tests.js +++ b/test/core/contacts_tests.js @@ -47,7 +47,7 @@ describe('contacts', () => { const modifiedAfter = new Date(); // take 30 seconds ago as we just created a contact - modifiedAfter.setTime(modifiedAfter.getTime()); + modifiedAfter.setTime(modifiedAfter.getTime() - 10000); currentApp.core.contacts .getContacts({ modifiedAfter: modifiedAfter }) @@ -116,7 +116,7 @@ describe('contacts', () => { done(wrapError(err)); }); }); - + it('get list of IDs', done => { currentApp.core.contacts .getContacts({ @@ -128,7 +128,7 @@ describe('contacts', () => { contacts.forEach(contact => { expect(contact.ContactID).to.be.oneOf(contactIDsList); }); - + done(); }) .catch(err => { @@ -136,7 +136,7 @@ describe('contacts', () => { done(wrapError(err)); }); }); - + it('get - invalid modified date', done => { currentApp.core.contacts .getContacts({ modifiedAfter: 'cats' })