diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index b342fca..0000000 --- a/.jshintrc +++ /dev/null @@ -1,19 +0,0 @@ -{ - "curly": false, - "eqeqeq": false, - "indent": false, - "newcap": false, - "plusplus": false, - "quotmark": false, - "unused": false, - "strict": false, - "trailing": false, - "maxstatements": false, - "maxlen": false, - - "eqnull": true, - "smarttabs": true, - - "browser": true, - "node": true -} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e804489 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 César Gutiérrez Olivares + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 10b5efe..88df26f 100644 --- a/README.md +++ b/README.md @@ -1,172 +1,164 @@ -# Odoo +# react-native-odoo-promise-based -React Native library for Odoo +⚠️ This repository is no longer being maintained. Feel free to use it for reference and forking. + +React Native library for Odoo using the Fetch API and JSON-RPC. + +This library is a modified version from the original repository and was created to allow authentication using Odoo session ids for in-app session persistence. Also server response handling was reimplemented using Promises instead of callback functions for convenience. + +**This package is still a work in progress** and hasn't been subjected to proper unit testing after the original repository was forked. ## Installation ```bash -$ npm install react-native-odoo +$ npm install react-native-odoo-promise-based +``` +or +```bash +$ yarn add react-native-odoo-promise-based ``` ## Usage +Please refer to the Odoo [API documentation](https://www.odoo.com/documentation/11.0/webservices/odoo.html) if you need help structuring your database queries. I'll try to make a more thorough explanation in the future about how it works. + +**Creating Odoo connection instance** +Before executing any kind of query operations, a connection instance must be established either with a username/password or with a previously retrieved session id. ```js -import Odoo from 'odoo' +import Odoo from 'react-native-odoo-promise-based' +/* Create new Odoo connection instance */ const odoo = new Odoo({ - host: 'localhost', - port: 8069, - database: 'demo', - username: 'admin', - password: 'admin' -}); - -// Connect to Odoo -odoo.connect(function (err) { - if (err) { return console.log(err); } -}); - -// Get a partner -// https://www.odoo.com/documentation/8.0/api_integration.html#read-records -// https://www.odoo.com/documentation/8.0/reference/orm.html#openerp.models.Model.read -var params = { + host: 'YOUR_SERVER_ADDRESS', + port: 8069, /* Defaults to 80 if not specified */ + database: 'YOUR_DATABASE_NAME', + username: 'YOUR_USERNAME', /* Optional if using a stored session_id */ + password: 'YOUR_PASSWORD', /* Optional if using a stored session_id */ + sid: 'YOUR_SESSION_ID', /* Optional if using username/password */ + protocol: 'https' /* Defaults to http if not specified */ +}) + +``` + +**Connect** +Returns a promise which resolves into an object containing the current users' data, including a session id which can be stored for future connections and session persistence. +```js +odoo.connect() +.then(response => { /* ... */ }) +.catch(e => { /* ... */ }) +``` + +**Get (Odoo Read)** +Receives an Odoo database `model` string and a `params` object containing the `ids` you want to read and the `fields` you want to retrieve from each result. + +Returns a promise which resolves to an array of results matching the array of ids provided in the parameters. +```js +/* Get partner from server example */ +const params = { ids: [1,2,3,4,5], fields: [ 'name' ], -}; //params -odoo.get('res.partner', params, function (err, partners) { - if (err) { return console.log(err); } - - console.log(partners); -// [ -// { id: 1, name: 'Demo Company' }, -// { id: 3, name: 'Administrator' }, -// { id: 4, name: 'Public user' }, -// { id: 5, name: 'Demo User' } -// ] -}); //get - - -// Search & Get products in one RPC call -// https://www.odoo.com/documentation/8.0/api_integration.html#search-and-read -// https://www.odoo.com/documentation/8.0/reference/orm.html#openerp.models.Model.search -// https://www.odoo.com/documentation/8.0/reference/orm.html#openerp.models.Model.read -var params = { +} + +odoo.get('res.partner', params, context) +.then(response => { /* ... */ }) +.catch(e => { /* ... */ }) +``` + +**Search & Read items** +Just like the Get method, this one also receives a `model` string and a `params` object. With this method the parameters may include a `domain` array for filtering purposes (with filter statements similar to SQL's `WHERE`), `limit` and `offset` values for pagination and an `order` property which can be set to specific fields. The array of `ids` becomes optional. + +Returns a promised which resolves to an array of results matching the parameters provided. +```js +const params = { ids: [1,2,3,4,5], domain: [ [ 'list_price', '>', '50' ], [ 'list_price', '<', '65' ] ], fields: [ 'name', 'list_price', 'items' ], - order: 'list_price', - limit: 5, - offset: 0, -}; //params -odoo.search_read('product.product', params, function (err, products) { - if (err) { return console.log(err); } - - console.log(products); -// [ -// { list_price: 60, id: 52, name: 'Router R430' }, -// { list_price: 62, id: 39, name: 'Headset standard' } -// ] - -}); //search_read - - -// Browse products by ID -// Not a direct implementation of Odoo RPC 'browse' but rather a workaround based on 'search_read' -// https://www.odoo.com/documentation/8.0/reference/orm.html#openerp.models.Model.browse -var params = { - fields: [ 'name', 'list_price'], - limit: 5, - offset: 0, -}; //params -odoo.browse_by_id('product.product', params, function (err, products) { - if (err) { return console.log(err); } - - console.log(products); -// [ -// { list_price: 4.49, id: 1180, name: 'Fruit Cup' }, -// { list_price: 0, id: 1139, name: 'Orange Crush' }, -// { list_price: 1.59, id: 1062, name: 'Blueberry muffin' }, -// { list_price: 1.35, id: 1381, name: 'Otis Harvest Bran' } -// ] -}); //browse_by_id - - -// Generic RPC call -// Note that, unlike the other methods, the context is not automatically included -var endpoint = '/web/dataset/call_kw'; -var model = 'sale.order'; -var method = 'action_view_delivery'; - -var args = [ - [sale_order_id], - { - tz: odoo.context.tz, - uid: odoo.context.uid, - }, -];//args - -var params = { - model: model, - method: method, - args: args, - kwargs: {}, -};//params - -// View Delivery Order -odoo.rpc_call(endpoint, params, function(err, result) { - if(err) { - console.log(err); - return; - }//if - - var delivery_order = result; - - console.log(delivery_order); -});//odoo.rpc_call + order: 'list_price DESC', + limit: 5, + offset: 0, +} + +odoo.search_read('product.product', params, context) +.then(response => { /* ... */ }) +.catch(e => { /* ... */ }) +``` +**Read Group** +Just like the Search & read, but get the list of records in list view grouped by the given ``groupby`` fields. +If ``lazy`` true, the results are only grouped by the first groupby and the remaining groupbys are put in the __context key. +If ``lazy`` false, all the groupbys are done in one call. +Returns a promised which resolves to an array of results matching the parameters provided. +Array containing: all the values of fields grouped by the fields in ``groupby`` argument, +``__domain``: array of list specifying the search criteria, ``__context``: array with argument like ``groupby`` +```js +const params = { + domain: [ ["project_id", "=", 7] ], + fields: [ "color", "stage_id" , "sequence"], + groupby: [ + "stage_id" + ], + order: 'sequence', + lazy: true +} + +odoo.read_group('project.task', params, context) +.then(response => { /* ... */ }) +.catch(e => { /* ... */ }) +``` +**Create** +Receives a `model` string and a `params` object with properties corresponding to the fields you want to write in the row. + +```js +odoo.create('delivery.order.line', { + sale_order_id: 123 + delivered: 'false', +}, context) +.then(response => { /* ... */ }) +.catch(e => { /* ... */ }) ``` -## Methods -* odoo.connect(callback) -* odoo.get(model, id, callback) -* odoo.search(model, params, callback) -* odoo.search_read(model, params, callback) -* odoo.browse_by_id(model, params, callback) -* odoo.create(model, params, callback) -* odoo.update(model, id, params, callback) -* odoo.delete(model, id, callback) -* odoo.rpc_call(endpoint, params, callback); +**Update** +Receives a `model` string, an array of `ids` related to the rows you want to update in the database and a `params` object with properties corresponding to the fields that are going to be updated. -##Node version -Works better with NodeJS v11.16 and further +If you need to update several rows in the database you can take advantage of the Promises API to generate and populate an array of promises by iterating through each operation and then resolving all of them using `Promise.all()` +```js +odoo.update('delivery.order.line', [ids], { + delivered: 'true', + delivery_note: 'Delivered on time!' +}, context) +.then(response => { /* ... */ }) +.catch(e => { /* ... */ }) +``` -## Reference +**Delete** +Receives an Odoo database `model` string and an `ids` array corresponding to the rows you want to delete in the database. -* [Odoo Technical Documentation](https://www.odoo.com/documentation/8.0) -* [Odoo Web Service API](https://www.odoo.com/documentation/8.0/api_integration.html) +```js +odoo.delete('delivery.order.line', [ids], context) +.then(response => { /* ... */ }) +.catch(e => { /* ... */ }) +``` -## License +**Custom RPC Call** +If you wish to execute a custom RPC call not represented in this library's methods, you can also run a custom call by passing an `endpoint` string and a `params` object. This requires understanding how the Odoo Web API works more thoroughly so you can properly structure the functions parameters. + +```js +odoo.rpc_call('/web/dataset/call_kw', params) +.then(response => { /* ... */ }) +.catch(e => { /* ... */ }) +``` -The MIT License (MIT) +## References -Copyright (c) 2015 Marco Godínez, 4yopping and all the related trademarks +* [Odoo ORM API Reference](https://www.odoo.com/documentation/11.0/reference/orm.html) -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +* [Odoo Web Service External API](https://www.odoo.com/documentation/11.0/webservices/odoo.html) + +## License +This project is licensed under the MIT License - see the [LICENSE.md](https://github.com/cesar-gutierrez/react-native-odoo/LICENSE.md) file for details -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +## Acknowledgements -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. +This project was built upon previous versions. It is a fork of [kevin3274](https://github.com/kevin3274/react-native-odoo)'s original React Native library which in turn is based of [saidimu](https://github.com/saidimu/odoo)'s Node.js library. diff --git a/examples/basic.js b/examples/basic.js deleted file mode 100644 index a2f11bd..0000000 --- a/examples/basic.js +++ /dev/null @@ -1,21 +0,0 @@ -var Odoo = require('../lib/index'); - -var odoo = new Odoo({ - host: 'localhost', - port: 4569, - database: '4yopping', - username: 'admin', - password: '4yopping' -}); - -// Connect to Odoo -odoo.connect(function (err) { - if (err) { return console.log(err); } - - // Get a partner - odoo.get('res.partner', 4, function (err, partner) { - if (err) { return console.log(err); } - - console.log('Partner', partner); - }); -}); diff --git a/gulpfile.js b/gulpfile.js deleted file mode 100644 index 8df8944..0000000 --- a/gulpfile.js +++ /dev/null @@ -1,11 +0,0 @@ -var gulp = require('gulp'), - mocha = require('gulp-mocha'); - -gulp.task('test', function () { - return gulp.src(['./test/**/*.js'], { read: false }) - .pipe(mocha({ reporter: 'spec' })); -}); - -gulp.task('default', function () { - gulp.watch(['./lib/**/*', './test/**/*'], ['test']); -}); diff --git a/lib/index.js b/lib/index.js index 8e7a74c..1f7259e 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,26 +1,27 @@ -'use strict'; +'use strict' var Odoo = function (config) { - config = config || {}; + config = config || {} - this.host = config.host; - this.port = config.port || 80; - this.database = config.database; - this.username = config.username; - this.password = config.password; -}; + this.host = config.host + this.port = config.port || 80 + this.database = config.database + this.username = config.username || null + this.password = config.password || null + this.sid = config.sid || null + this.protocol = config.protocol || 'http' +} // Connect - -Odoo.prototype.connect = function(cb){ +Odoo.prototype.connect = function () { var params = { db: this.database, login: this.username, password: this.password - }; + } - var json = JSON.stringify({ params: params }); - var url = 'http://' + this.host + ':' + this.port + '/web/session/authenticate'; + var json = JSON.stringify({ params: params }) + var url = `${this.protocol}://${this.host}:${this.port}/web/session/authenticate` var options = { method: 'POST', @@ -29,176 +30,185 @@ Odoo.prototype.connect = function(cb){ 'Accept': 'application/json', 'Content-Length': json.length }, - body: json - }; - fetch(url, options) - .then(res=>{ - this.sid = res.headers.map['set-cookie'][0].split(';')[0]; - console.log('sid:', this.sid); - return res.json() + body: json, + credentials: 'omit' + } + + var context = this + + return fetch(url, options) + .then(function (response) { + context.sid = response.headers.map['set-cookie'].split(';')[0].split('=')[1]; + context.cookie = response.headers.map['set-cookie']; + return response.json() }) - .then(data=>{ - if (data.error){ - cb(data.error, null); - }else{ - this.uid = data.result.uid; - this.session_id = data.result.session_id; - this.context = data.result.user_context; - this.username = data.result.username; - cb(null, data.result); + .then(function (responseJson) { + if (responseJson.error) return { success: false, error: responseJson.error } + else { + context.uid = responseJson.result.uid + context.session_id = responseJson.result.session_id + context.context = responseJson.result.user_context + context.username = responseJson.result.username + return { success: true, data: responseJson.result } } - }, err=>{ - cb(err, null); - }); - -}; + }) + .catch(function (error) { + return { success: false, error: error } + }) +} // Search records -Odoo.prototype.search = function (model, params, callback) { - // assert(params.ids, "Must provide a list of IDs."); - //assert(params.domain, "Must provide a search domain."); - - this._request('/web/dataset/call_kw', { +Odoo.prototype.search = function (model, params, context) { + return this._request('/web/dataset/call_kw', { kwargs: { - context: this.context + context: {...this.context, ...context} }, model: model, method: 'search', args: [ params.domain, ], - }, callback); -}; + }) +} // Search & Read records -// https://www.odoo.com/documentation/8.0/api_integration.html#search-and-read -// https://www.odoo.com/documentation/8.0/reference/orm.html#openerp.models.Model.search -// https://www.odoo.com/documentation/8.0/reference/orm.html#openerp.models.Model.read -Odoo.prototype.search_read = function (model, params, callback) { - //assert(params.domain, "'domain' parameter required. Must provide a search domain."); - //assert(params.limit, "'limit' parameter required. Must specify max. number of results to return."); - - this._request('/web/dataset/call_kw', { +Odoo.prototype.search_read = function (model, params, context) { + + return this._request('/web/dataset/call_kw', { model: model, method: 'search_read', args: [], kwargs: { - context: this.context, + context: {...this.context, ...context}, domain: params.domain, offset: params.offset, limit: params.limit, order: params.order, fields: params.fields, }, - }, callback); -}; + }) +} -// Get record -// https://www.odoo.com/documentation/8.0/api_integration.html#read-records -// https://www.odoo.com/documentation/8.0/reference/orm.html#openerp.models.Model.read -Odoo.prototype.get = function (model, params, callback) { - //assert(params.ids, "Must provide a list of IDs."); - - this._request('/web/dataset/call_kw', { +// Read records +Odoo.prototype.get = function (model, params, context) { + return this._request('/web/dataset/call_kw', { model: model, method: 'read', args: [ params.ids, ], kwargs: { + context: {...this.context, ...context}, fields: params.fields, }, - }, callback); -}; //get + }) +} +// Read Group +Odoo.prototype.read_group = function(model, params, context) { + return this._request("/web/dataset/call_kw", { + model: model, + method: "read_group", + args: [], + kwargs: { + context: { ...this.context, ...context }, + domain: params.domain, + fields: params.fields, + groupby: params.groupby, + lazy: params.lazy, + orderby: params.order + }, + }) +} // Browse records by ID // Not a direct implementation of Odoo RPC 'browse' but rather a workaround based on 'search_read' -// https://www.odoo.com/documentation/8.0/reference/orm.html#openerp.models.Model.browse -Odoo.prototype.browse_by_id = function(model, params, callback) { - params.domain = [['id', '>', '0' ]]; // assumes all records IDs are > 0 - this.search_read(model, params, callback); -}; //browse +Odoo.prototype.browse_by_id = function (model, params) { + params.domain = [['id', '>', '0']] + this.search_read(model, params) + .then(function (response) { + return response + }) +} -// Create record -Odoo.prototype.create = function (model, params, callback) { - this._request('/web/dataset/call_kw', { +// Create records +Odoo.prototype.create = function (model, params, context) { + return this._request('/web/dataset/call_kw', { kwargs: { - context: this.context + context: {...this.context, ...context} }, model: model, method: 'create', args: [params] - }, callback); -}; + }) +} -// Update record -Odoo.prototype.update = function (model, id, params, callback) { - if (id) { - this._request('/web/dataset/call_kw', { +// Update records +Odoo.prototype.update = function (model, ids, params, context) { + if (ids) { + return this._request('/web/dataset/call_kw', { kwargs: { - context: this.context + context: {...this.context, ...context} }, model: model, method: 'write', - args: [[id], params] - }, callback); + args: [ids, params] + }) } -}; - -// Delete record -Odoo.prototype.delete = function (model, id, callback) { - this._request('/web/dataset/call_kw', { - kwargs: { - context: this.context - }, - model: model, - method: 'unlink', - args: [[id]] - }, callback); -}; +} +// Delete records +Odoo.prototype.delete = function (model, ids, context) { + if (ids) { + return this._request('/web/dataset/call_kw', { + kwargs: { + context: {...this.context, ...context} + }, + model: model, + method: 'unlink', + args: [ids] + }) + } +} // Generic RPC wrapper -// DOES NOT AUTO-INCLUDE context -Odoo.prototype.rpc_call = function (endpoint, params, callback) { - //assert(params.model); - // assert(params.method); - // assert(params.args); - // assert(params.kwargs); - // assert(params.kwargs.context); - - this._request(endpoint, params, callback); -}; //generic - +Odoo.prototype.rpc_call = function (endpoint, params) { + return this._request(endpoint, params) +} // Private functions -Odoo.prototype._request = function (path, params, cb) { - params = params || {}; +Odoo.prototype._request = function (path, params) { + params = params || {} - var url = 'http://' + this.host + ':' + this.port + (path || '/') + ''; + var url = `${this.protocol}://${this.host}:${this.port}${path || '/'}` var options = { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', - 'Cookie': this.sid + ';' + 'Cookie': this.cookie }, - body: JSON.stringify({jsonrpc: '2.0', id: new Date().getUTCMilliseconds(), method: 'call', params: params}) - }; - - fetch(url, options) - .then(res=>res.json()) - .then(data=>{ - if (data.error){ - cb(data.error, null); - }else{ - cb(null, data.result); - } - }, err=>{ - cb(err, null); - }); -}; + credentials: 'omit', + body: JSON.stringify({ + jsonrpc: '2.0', + id: new Date().getUTCMilliseconds(), + method: 'call', + params: params + }) + } + + return fetch(url, options) + .then(function (response) { + return response.json() + }) + .then(function (responseJson) { + if (responseJson.error) return { success: false, error: responseJson.error } + else return { success: true, data: responseJson.result } + }) + .catch(function (error) { + return { success: false, error: error } + }) +} -module.exports = Odoo; +module.exports = Odoo diff --git a/package.json b/package.json index 7e065d6..a90c038 100644 --- a/package.json +++ b/package.json @@ -1,47 +1,33 @@ { - "name": "react-native-odoo", - "version": "0.1.0", - "description": "React Native library for Odoo using JSON-RPC", - "main": "./lib/index.js", - "directories": { - "test": "test" - }, - "scripts": { - "test": "mocha test" - }, - "engines": { - "node": ">=0.11.16" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/kevin3274/react-native-odoo.git" - }, + "name": "react-native-odoo-promise-based", + "version": "0.6.8", + "description": "React Native library for Odoo using Fetch API and JSON-RPC", "keywords": [ "odoo", "openerp", - "jsonrpc" + "jsonrpc", "react-native" ], - "author": { - "name": "Kevin Wang", - "email": "kevin_327@163.com" - }, + "homepage": "https://github.com/cesar-gutierrez/react-native-odoo-promise-based", "bugs": { - "url": "https://github.com/kevin327/react-native-odoo/issues" + "url": "https://github.com/cesar-gutierrez/react-native-odoo-promise-based/issues" + }, + "license": "MIT", + "main": "./lib/index.js", + "directories": { + "test": "test" }, - "homepage": "https://github.com/kevin3274/react-native-odoo", - "dependencies": { + "repository": { + "type": "git", + "url": "git+https://github.com/cesar-gutierrez/react-native-odoo-promise-based.git" }, - "devDependencies": { - "gulp": "^3.8.11", - "gulp-mocha": "^2.0.0", - "sinon": "^1.12.2" + "scripts": { + "test": "mocha test" }, + "author": "César Gutiérrez Olivares ", "maintainers": [ - { - "name": "kevin3274", - "email": "kevin_327@163.com" - } - ], - "readme": "ERROR: No README data found!" + "César Gutiérrez Olivares ", + "Nichita Gruia ", + "Aidos Kakimzhanov " + ] } diff --git a/test/test.js b/test/test.js deleted file mode 100644 index 4c9c415..0000000 --- a/test/test.js +++ /dev/null @@ -1,171 +0,0 @@ -var assert = require('assert'), - sinon = require('sinon'), - Odoo = require('../lib/index'); - -var config = { - host: 'odoo4yopping.vagrantshare.com', - port: 80, - database: '4yopping', - username: 'admin', - password: '4yopping' -}; - -var odoo = new Odoo(config); - -describe('Odoo', function () { - this.timeout(3000); - - it('Odoo should be a function', function () { - assert.equal(typeof Odoo, 'function'); - }); - - it('odoo should be an instance of Odoo', function () { - assert(odoo instanceof Odoo); - }); - - it('odoo should have this properties', function () { - assert.notEqual(odoo.host, undefined); - assert.equal(odoo.host, config.host); - assert.notEqual(odoo.port, undefined); - assert.equal(odoo.port, config.port); - assert.notEqual(odoo.database, undefined); - assert.equal(odoo.database, config.database); - assert.notEqual(odoo.username, undefined); - assert.equal(odoo.username, config.username); - assert.notEqual(odoo.password, undefined); - assert.equal(odoo.password, config.password); - }); - - it('odoo should have this public functions', function () { - assert.equal(typeof odoo.connect, 'function'); - assert.equal(typeof odoo.create, 'function'); - assert.equal(typeof odoo.get, 'function'); - assert.equal(typeof odoo.update, 'function'); - assert.equal(typeof odoo.delete, 'function'); - assert.equal(typeof odoo.search, 'function'); - }); - - it('odoo should have this private functions', function () { - assert.equal(typeof odoo._request, 'function'); - }); - - describe('Creating client', function () { - - it('client should not be able to connect to odoo server', function (done) { - var client = new Odoo({ - host: config.host, - database: 'DatabaseNotFound', - username: config.username, - password: config.password - }), - callback = sinon.spy(); - - client.connect(callback); - - setTimeout(function () { - assert(callback.called); - assert.equal(typeof callback.args[0][0], 'object'); - assert.equal(callback.args[0][1], null); - - done(); - }, 2000); - }); - - it('client should be able to connect to odoo server', function (done) { - var callback = sinon.spy(); - - odoo.connect(callback); - - setTimeout(function () { - assert(callback.calledWith(null)); - assert.equal(typeof callback.args[0][1], 'object'); - assert(odoo.uid); - assert(odoo.sid); - assert(odoo.session_id); - assert(odoo.context); - - done(); - }, 2000); - }); - - }); - - describe('Records', function () { - - var created; - - it('client should create a record', function (done) { - var callback = sinon.spy(); - odoo.create('hr.employee', { - name: 'John Doe', - work_email: 'john@doe.com' - }, callback); - - setTimeout(function () { - assert(callback.calledWith(null)); - assert.equal(typeof callback.args[0][1], 'number'); - - created = callback.args[0][1]; - - done(); - }, 2000); - - }); - - it('client should get a record', function (done) { - var callback = sinon.spy(); - odoo.get('hr.employee', created, callback); - - setTimeout(function () { - assert(callback.calledWith(null)); - assert.equal(typeof callback.args[0][1], 'object'); - assert.equal(callback.args[0][1].display_name, 'John Doe'); - assert.equal(callback.args[0][1].work_email, 'john@doe.com'); - - done(); - }, 2000); - - }); - - it('client should update a record', function (done) { - var callback = sinon.spy(); - odoo.update('hr.employee', created, { - name: 'Jane Doe', - work_email: 'jane@doe.com' - }, callback); - - setTimeout(function () { - assert(callback.calledWith(null)); - assert(callback.args[0][1]); - - done(); - }, 2000); - }); - - it('client should delete a record', function (done) { - var callback = sinon.spy(); - odoo.delete('hr.employee', created, callback); - - setTimeout(function () { - assert(callback.calledWith(null)); - assert(callback.args[0][1]); - - done(); - }, 2000); - }); - - it('client should search records', function (done) { - var callback = sinon.spy(); - odoo.search('hr.employee', [['login', '=', 'admin']], callback); - - setTimeout(function () { - assert(callback.calledWith(null)); - assert.equal(typeof callback.args[0][1], 'array'); - - done(); - }, 2000); - }); - - }); - -});