Learn how to manipulate documents (creation, update, state change, deletion...) and launch queries through the REST API.
The steps below leverage the document types included in the addon Getting started with the Nuxeo Platform:
- The portfolio document type (
BCPortfolio
) holds the contracts of a customer. Its holds properties about the customer: the company name, industry and size, and the customer's juridical contact information. - The contract document type (
BCContract
) have several properties: an owner (an application user), some dates (signature, start, expiration dates), a type, an amount. It inherits customer information from its portfolio. - Some vocabularies are used to populate the portfolio and contract metadata (
companySize
,contractType
andindustry
) - Contracts have a specific lifecycle, so they can evolve though the states
draft
,approval
,running
,renegociation
andvoid
- Some business logic through automation chains and event handlers make contracts inherit properties from its portfolio, and evolve following its lifecycle
Creating a Document
Goal
Create a new contract in Nuxeo Platform.
Prerequisites
- Install the addon Getting started with the Nuxeo Platform. See Setting up Your Nuxeo Environment.
Procedure
Create a file called
createContract.js
with the following content:#!/usr/bin/env node const Nuxeo = require('nuxeo'); const nuxeo = new Nuxeo({ auth: { method: 'basic', username: 'Administrator', password: 'Administrator' } }); // Define the portfolio properties first const portfolioToCreate = { 'entity-type': 'document', 'type': 'BCPortfolio', 'name': 'awesome-tech', 'properties': { 'dc:title': 'Awesome Tech Ltd.', 'bccstm:companyIndustry': 'it', 'bccstm:companySize': 'medium', // Complex properties are sent as objects 'bccstm:juridicalContact': { 'firstName': 'John', 'lastName': 'McLane', 'tel': '555 123 456', 'email': '[email protected]' } } }; // Then define the contract properties const contractToCreate = { 'entity-type': 'document', 'type': 'BCContract', 'name': 'skynet-ai-maintenance', 'properties': { 'dc:title': 'Skynet AI Maintenance Contract', 'bccontract:contractOwner': 'afraser', 'bccontract:signatureDate': '2050-12-24', 'bccontract:startDate': '2050-12-25', 'bccontract:expirationDate': '2055-12-31', 'bccontract:type': 'maintenance', 'bcsalescommon:amount': '10000' } }; const whereToCreatePortfolio = '/default-domain/workspaces/North America'; const repository = nuxeo.repository(); // Then create the portfolio and contract repository .create(whereToCreatePortfolio, portfolioToCreate) .then(portfolio => { console.log('Portfolio has been created as follows:'); console.log(portfolio); return repository.create(portfolio.path, contractToCreate); }) .then(contract => { console.log('Contract has been created as follows:'); console.log(contract); }) .catch(error => { console.log('Apologies, an error occurred.'); console.log(error); if (error.response) { error.response.json().then(json => console.log(json)); } });
Save and run:
$ node createContract.js
Fetching a Document
Documents can be fetched using their ID or path.
Create a file called
fetchContract.js
with the following content.#!/usr/bin/env node const Nuxeo = require('nuxeo'); const nuxeo = new Nuxeo({ auth: { method: 'basic', username: 'Administrator', password: 'Administrator' } }); // Further calls will return all schemas when fetching a document // Note that it can easily be overridden on a per call basis if needed nuxeo.schemas('*'); nuxeo.repository() // These headers allow us to retrieve the associated contract owner in the same call .header('depth', 'max') .header('fetch.document', 'properties') // We'll also retrieve the document hierarchy .enricher('document', 'breadcrumb') .fetch('/default-domain/workspaces/North America/awesome-tech/skynet-ai-maintenance') .then(contract => { console.log('Contract has been retrieved:'); console.log(contract); console.log(`\nAnd here is the document's hierarchy to build a breadcrumb navigation:`); console.log(contract.contextParameters.breadcrumb); }) .catch(error => { console.log(error); });
Save and run:
$ node fetchContract.js
Notes
- We obtained detailed information about the contract owner because we added some headers to retrieve all the document's relations.
- The document hierarchy is provided in context parameters because we used a content enricher. That's only one out of many.
- The contract inherited the company name and other customer related properties from its portfolio (in the
bccustomer
schema) thanks to some business logic brought by the addon Getting started with the Nuxeo Platform.
Updating a Document
We will now update the contract to add some custom clauses.
Create a file called
updateContract.js
with the following content.#!/usr/bin/env node const Nuxeo = require('nuxeo'); const nuxeo = new Nuxeo({ auth: { method: 'basic', username: 'Administrator', password: 'Administrator' } }); // Further calls will return all schemas when fetching a document // Note that it can easily be overridden on a per call basis if needed nuxeo.schemas('*'); var contractToFetch = '/default-domain/workspaces/North America/awesome-tech/skynet-ai-maintenance'; // We're updating a complex and multi-valued property here // Multi-valued properties are expressed as arrays, complex properties as objects // So we're creating an object array here var propertiesToUpdate = { 'bccontract:customClauses': [{ 'label': 'Automatic Subscription Renewal', 'content': 'In case the user has not cancelled its subscription one month before the contract\'s expiration date, the contract will automatically be renewed for one more year.' }, { 'label': 'Payment Conditions', 'content': 'When an automatic subscription renewal is triggered, the user will need to pay the annual amount due. This amount will not be refunded if the contract is stopped before its new expiration date.' }] }; // And now we launch the actual update nuxeo.repository() .fetch(contractToFetch) .then(function(contract) { contract.set(propertiesToUpdate); return contract.save(); }) .then(function(contract) { console.log('Contract has been updated. Custom clauses are now as follows:'); console.log(contract.properties['bccontract:customClauses']); }) .catch(function(error) { console.log('Apologies, an error occurred while updating the contract.'); console.log(error); });
Save and run:
$ node updateContract.js
Trashing a Document
First we will trash the document, then in a second phase restore it from the trash.
Trashing the document
Create a file called
trashContract.js
with the following content.#!/usr/bin/env node const Nuxeo = require('nuxeo'); const nuxeo = new Nuxeo({ auth: { method: 'basic', username: 'Administrator', password: 'Administrator' } }); var contractToFetch = '/default-domain/workspaces/North America/awesome-tech/skynet-ai-maintenance'; nuxeo.repository() .fetch(contractToFetch) .then(function(contract) { return contract.followTransition('delete'); }) .then(function(contract) { console.log('Contract state has been changed. Contract is now as follows:'); console.log(contract); }) .catch(function(error) { console.log('Apologies, an error occurred while changing the contract state.'); console.log(error); });
Save and run:
$ node trashContract.js
Restore trashed document
Restore the contract from trash.
Create a file called
restoreContract.js
with the following content.#!/usr/bin/env node const Nuxeo = require('nuxeo'); const nuxeo = new Nuxeo({ auth: { method: 'basic', username: 'Administrator', password: 'Administrator' } }); var contractToFetch = '/default-domain/workspaces/North America/awesome-tech/skynet-ai-maintenance'; nuxeo.repository() // Find the trashed document .query({ query: "SELECT * FROM Document WHERE ecm:mixinType != 'HiddenInNavigation' AND ecm:isProxy = 0 AND ecm:isVersion = 0 AND ecm:isTrashed = 1 AND ecm:path STARTSWITH '/default-domain/workspaces/North America/awesome-tech/'" }) .then(function(contract) { return contract.entries[0]; }) // Restore it .then(function(contract) { return nuxeo.operation('Document.Untrash') .input(contract) .execute() }) .then(function() { console.log('Success! The contract has been untrashed.'); }) .catch(function(error) { console.log('Apologies, an error occurred while untrashing the document.'); console.log(error); });
Save and run:
$ node restoreContract.js
Searching for Documents
Find a contract that needs to be deleted: it expired before 2016 and has a limitation clause in its content.
Create a file called
query.js
which launches a query for all documents:- of the
BCContract
type - except archived versions and documents that are in the trash
- that contain the keyword "limitation"
- having expired before the end of 2015.
#!/usr/bin/env node const Nuxeo = require('nuxeo'); const nuxeo = new Nuxeo({ auth: { method: 'basic', username: 'Administrator', password: 'Administrator' } }); getContractsQuery = "SELECT * FROM BCContract " + " WHERE ecm:isVersion = 0 AND ecm:isTrashed = 0 AND ecm:fulltext = 'limitation' AND bccontract:expirationDate <= DATE '2015-12-31' "; nuxeo .repository() .query({ query: getContractsQuery }) .then(function(contracts) { console.log('The following contracts have been retrieved:'); console.log(contracts); }) .catch(function(error) { console.log('Apologies, an error occurred while launching the query.'); console.log(error); });
- of the
Save and run:
$ node query.js
Deleting a Document
The contract to delete has been identified as being the 2015 Annual Conference
belonging to the Bon Appétit Caterer
portfolio. Delete it.
Create a file called
deleteContract.js
with the following content.#!/usr/bin/env node const Nuxeo = require('nuxeo'); const nuxeo = new Nuxeo({ auth: { method: 'basic', username: 'Administrator', password: 'Administrator' } }); nuxeo.repository() .fetch('/default-domain/workspaces/North America/Caterer/2015 Annual Conference') .then(function(contract) { return nuxeo.operation('Document.Delete') .input(contract) .execute() }) .then(function(res) { console.log('Contract has been deleted permanently. Bye bye contract!') // res.status === 204 }) .catch(function(error) { console.log('Apologies, an error occurred while deleting the contract.'); console.log(error); });
Save and run:
$ node deleteContract.js
Note: This method does not include a "trash" behavior. The document is permanently erased. You should use the delete state and transitions to get documents to be moved to a trash before being permanently deleted.