angular.module('odoo.factories', ['xml-rpc']) .factory('util', function () { return { asyncLoop : function (iterations, func, callback) { var index = 0; var done = false; var loop = { next: function () { if (done) { return; } if (index < iterations) { index++; func(loop); } else { done = true; callback(); } }, iteration: function() { return index - 1; }, break: function() { done = true; callback(); } }; loop.next(); return loop; } } }) .factory('odoo', function (xmlrpc, methodCallManager) { return { auth: function (config, success, error) { xmlrpc.callMethod(methodCallManager.call('authenticate', config), [config.database, config.username, config.password, {}]).then(function(response) { if (!response || response['faultCode']) { error(response); return; } success({ id: response, username: config.username, password: config.password }); }, function (xmlrpcError) { error(xmlrpcError); }); }, read: function (model, domain, config, success, error) { xmlrpc.callMethod(methodCallManager.call('execute_kw', config), [config.database, config.remote_id, config.password, model, 'search_read', [domain]]).then(function (response) { if (!response || response['faultCode']) { error(response); return; } success(response); }, function (xmlrpcError) { error(xmlrpcError); }); }, create: function (model, data, config, success, error) { xmlrpc.callMethod(methodCallManager.call('execute_kw', config), [config.database, config.remote_id, config.password, model, 'create', [data]]).then(function (response) { if (!response || response['faultCode']) { error(response); return; } success(response); }, function (xmlrpcError) { error(xmlrpcError); }); }, write: function (model, id, data, config, success, error) { xmlrpc.callMethod(methodCallManager.call('execute_kw', config), [config.database, config.remote_id, config.password, model, 'write', [[id], data]]).then(function (response) { if (!response || response['faultCode']) { error(response); return; } success(response); }, function (xmlrpcError) { error(xmlrpcError); }); }, unlink: function (model, id, config, success, error) { xmlrpc.callMethod(methodCallManager.call('execute_kw', config), [config.database, config.remote_id, config.password, model, 'unlink', [[id]]]).then(function (response) { if (!response || response['faultCode']) { error(response); return; } success(response); }, function (xmlrpcError) { error(xmlrpcError); }); } } }) .factory('methodCallManager', function(xmlrpc) { return { call: function(methodName, configuration) { var hostName = configuration.host + ':' + configuration.port; if(!hostName.startsWith('http://')) { hostName = 'http://' + hostName; } if(methodName == 'authenticate') { xmlrpc.config({ hostName: hostName, pathName: '/xmlrpc/2/common' }); } else { xmlrpc.config({ hostName: hostName, pathName: '/xmlrpc/2/object' }); } return methodName; } } }) .factory('sync', function (storage, odoo, util) { return { syncCustomers: function (success, error) { // Get current user saved on mobile storage.get('user', function (users) { if (users.length == 1) { var userConfig = users.item(0); // 1. Transfer all new data from mobile to server storage.getByConstraint('partner', 'remote_id = 0 AND customer = 1', function(newPartners) { util.asyncLoop(newPartners.length, function (loop) { var data = newPartners.item(loop.iteration()); // Avoid odoo server warning message delete data.id; delete data.remote_id; delete data.modified; delete data.modifiedDate; odoo.create('res.partner', data, userConfig, function (response) { loop.next(); }, function (odooCreateError) { loop.break(); }); // End loop }, function() { // 2. Transfer all modified data from mobile to server storage.getByConstraint('partner', 'remote_id != 0 AND customer = 1 AND modified = 1', function (modifiedPartners) { util.asyncLoop(modifiedPartners.length, function (loop) { var localData = modifiedPartners.item(loop.iteration()); odoo.read('res.partner', [['id', '=', localData.remote_id]], userConfig, function (response) { if (response.length == 1) { var remoteData = response[0]; var remoteModifiedDate = new Date(remoteData.__last_update); var localModifiedDate = new Date(localData.modifiedDate); if (localModifiedDate > remoteModifiedDate) { var id = localData.remote_id; // Avoid odoo server warning message delete localData.id; delete localData.remote_id; delete localData.modified; delete localData.modifiedDate; odoo.write('res.partner', id, localData, userConfig, function (response) { loop.next(); }, function (odooWriteError) { console.error(odooWriteError); loop.next(); }); } else { loop.next(); } } else { loop.next(); } }, function(odooReadError) { console.error(odooReadError); loop.next(); }); // End loop }, function () { // 3. Delete server data from mobile storage.getByConstraint('partner', 'remote_id != 0 AND customer = 1 AND modified = 2', function (deletedPartners) { util.asyncLoop(deletedPartners.length, function (loop) { var id = deletedPartners.item(loop.iteration()).remote_id; odoo.unlink('res.partner', id, userConfig, function (response) { loop.next(); }, function (odooUnlinkError) { console.error(odooUnlinkError); loop.next(); }); // End loop }, function () { // 4. Download updated data from server to mobile odoo.read('res.partner', [['customer', '=', true]], userConfig, function (updatedPartners) { storage.deleteAllCustomers(function () { util.asyncLoop(updatedPartners.length, function (loop) { var data = updatedPartners[loop.iteration()]; // Set id for save on local database data.remote_id = data.id; delete data.id; storage.saveCustomer(data, function (customerId) { loop.next(); } ,function (saveCustomerError) { console.error(saveCustomerError); loop.next(); }); }, function () { success(updatedPartners); }); }, function (deleteAllCustomersError) { error(deleteAllCustomersError); }); }, function (odooReadError) { error(odooReadError); }); }); }, function (getDeletedPartnersError) { error(getDeletedPartnersError); }); }); }, function (getModifiedPartnersError) { error(getModifiedPartnersError); }); }); }, function (partnerGetByConstraintError) { error(partnerGetByConstraintError); }); } }, function(userGetError) { error(userGetError); }); } } }) .factory('storage', function () { return { // Customer saveCustomer(customer, success, error) { var sql = ''; if (customer.id) { sql = `UPDATE partner SET remote_id = ${ customer.remote_id ? customer.remote_id : 0 }, modified = 1, modifiedDate = CURRENT_TIMESTAMP, name = ${ customer.name ? '"' + customer.name + '"' : null }, city = ${ customer.city ? '"' + customer.city + '"' : null }, mobile = ${ customer.mobile ? '"' + customer.mobile + '"' : null }, phone = ${ customer.phone ? '"' + customer.phone + '"' : null }, fax = ${ customer.fax ? '"' + customer.fax + '"' : null }, email = ${ customer.email ? '"' + customer.email + '"' : null }, street = ${ customer.street ? '"' + customer.street + '"' : null }, street2 = ${ customer.street2 ? '"' + customer.street2 + '"' : null }, image_medium = ${ customer.image_medium ? '"' + customer.image_medium + '"' : null }, image_small = ${ customer.image_small ? '"' + customer.image_small + '"' : null }, comment = ${ customer.comment ? '"' + customer.comment + '"' : null }, customer = ${ customer.customer ? customer.customer : 1 }, employee = ${ customer.employee ? customer.employee : 0 }, is_company = ${ customer.is_company ? customer.is_company : 0 }, debit = ${ customer.debit ? customer.debit : 0 }, debit_limit = ${ customer.debit_limit ? customer.debit_limit : 0 }, opportunity_count = ${ customer.opportunity_count ? customer.opportunity_count : 0 }, contracts_count = ${ customer.contracts_count ? customer.contracts_count : 0 }, journal_item_count = ${ customer.journal_item_count ? customer.journal_item_count : 0 }, meeting_count = ${ customer.meeting_count ? customer.meeting_count : 0 }, phonecall_count = ${ customer.phonecall_count ? customer.phonecall_count : 0 }, sale_order_count = ${ customer.sale_order_count ? customer.sale_order_count : 0 }, total_invoiced = ${ customer.total_invoiced ? customer.total_invoiced : 0 } WHERE id = ${ customer.id }`; } else { sql = `INSERT INTO partner(remote_id, name, city, mobile, phone, fax, email, street, street2, image_medium, image_small, comment, customer, employee, is_company, debit, debit_limit, opportunity_count, contracts_count, journal_item_count, meeting_count, phonecall_count, sale_order_count, total_invoiced) VALUES (${ customer.remote_id ? customer.remote_id : 0 }, ${ customer.name ? '"' + customer.name + '"' : null }, ${ customer.city ? '"' + customer.city + '"' : null }, ${ customer.mobile ? '"' + customer.mobile + '"' : null }, ${ customer.phone ? '"' + customer.phone + '"' : null }, ${ customer.fax ? '"' + customer.fax + '"' : null }, ${ customer.email ? '"' + customer.email + '"' : null }, ${ customer.street ? '"' + customer.street + '"' : null }, ${ customer.street2 ? '"' + customer.street2 + '"' : null }, ${ customer.image_medium ? '"' + customer.image_medium + '"' : null }, ${ customer.image_small ? '"' + customer.image_small + '"' : null }, ${ customer.comment ? '"' + customer.comment + '"' : null }, 1, 0, 0, ${ customer.debit ? customer.debit : 0 }, ${ customer.debit_limit ? customer.debit_limit : 0 }, ${ customer.opportunity_count ? customer.opportunity_count : 0 }, ${ customer.contracts_count ? customer.contracts_count : 0 }, ${ customer.journal_item_count ? customer.journal_item_count : 0 }, ${ customer.meeting_count ? customer.meeting_count : 0 }, ${ customer.phonecall_count ? customer.phonecall_count : 0 }, ${ customer.sale_order_count ? customer.sale_order_count : 0 }, ${ customer.total_invoiced ? customer.total_invoiced : 0 })`; } db.executeSql(sql, [], function(result) { success(sql.startsWith('INSERT') ? result.insertId : customer.id); }, function(err) { error(err); }); }, deleteCustomer(customer, success, error) { if (!customer.id) { error('Customer cannot delete without provide an id'); } var sql = ''; if (customer.remote_id) { sql = `UPDATE partner SET modified = 2 WHERE id = ${ customer.id }`; } else { sql = `DELETE FROM partner WHERE id = ${ customer.id }`; } console.log(sql); db.executeSql(sql, [], function(result) { success(result.rowsAffected); }, function(err) { error(err); }); }, deleteAllCustomers(success, error) { var sql = 'DELETE FROM partner WHERE customer = 1'; db.executeSql(sql, [], function(result) { success(result.rowsAffected); }, function(err) { error(err); }); }, // Users saveUser: function(data, success, error) { var sql = 'INSERT INTO user(remote_id, host, port, database, username, password) VALUES(?, ?, ?, ?, ?, ?)'; db.executeSql(sql, data, function (result) { success(result.insertId); }, function (err) { error(err); }); }, // Utils get: function(tableName, success, error) { var sql = 'SELECT * FROM ' + tableName; db.executeSql(sql, [], function(result) { success(result.rows); }, function(err) { error(err); }); }, getByConstraint: function(tableName, constraint, success, error) { var sql = 'SELECT * FROM ' + tableName + ' WHERE ' + constraint; db.executeSql(sql, [], function(result) { success(result.rows); }, function(err) { error(err); }); }, count: function(tableName, success, error) { var sql = 'SELECT COUNT(*) AS total FROM ' + tableName; db.executeSql(sql, [], function(result) { success(result.rows.item(0).total); }, function(err) { error(err); }); } } });