/**
* Odoo, Open Source Management Solution
* Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http:www.gnu.org/licenses/>
*
* Created on 30/12/14 3:31 PM
*/
package com.odoo.core.orm;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.SyncResult;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.util.Log;
import com.odoo.App;
import com.odoo.base.addons.ir.IrModel;
import com.odoo.core.auth.OdooAccountManager;
import com.odoo.core.orm.annotation.Odoo;
import com.odoo.core.orm.fields.OColumn;
import com.odoo.core.orm.fields.types.OBoolean;
import com.odoo.core.orm.fields.types.ODateTime;
import com.odoo.core.orm.fields.types.OInteger;
import com.odoo.core.orm.fields.types.OSelection;
import com.odoo.core.orm.provider.BaseModelProvider;
import com.odoo.core.service.ISyncServiceListener;
import com.odoo.core.service.OSyncAdapter;
import com.odoo.core.support.OUser;
import com.odoo.core.support.OdooFields;
import com.odoo.core.utils.OCursorUtils;
import com.odoo.core.utils.ODateUtils;
import com.odoo.core.utils.OListUtils;
import com.odoo.core.utils.OPreferenceManager;
import com.odoo.core.utils.OStorageUtils;
import com.odoo.core.utils.StringUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import odoo.ODomain;
import odoo.OdooVersion;
public class OModel implements ISyncServiceListener {
public static final String TAG = OModel.class.getSimpleName();
public String BASE_AUTHORITY = "com.odoo.crm.core.provider.content";
public static final String KEY_UPDATE_IDS = "key_update_ids";
public static final String KEY_INSERT_IDS = "key_insert_ids";
public static final int INVALID_ROW_ID = -1;
public static OSQLite sqLite = null;
private Context mContext;
private OUser mUser;
private String model_name = null;
private List<OColumn> mColumns = new ArrayList<>();
private List<OColumn> mRelationColumns = new ArrayList<>();
private List<OColumn> mFunctionalColumns = new ArrayList<>();
private HashMap<String, Field> mDeclaredFields = new HashMap<>();
private OdooVersion mOdooVersion = null;
private String default_name_column = "name";
public static OModelRegistry modelRegistry = new OModelRegistry();
private boolean hasMailChatter = false;
// Relation record command
public enum Command {
Add(0), Update(1), Delete(2), Replace(6);
int type;
Command(int type) {
this.type = type;
}
public int getValue() {
return type;
}
}
// Base Columns
OColumn id = new OColumn("ID", OInteger.class).setDefaultValue(0);
@Odoo.api.v8
@Odoo.api.v9alpha
public OColumn create_date = new OColumn("Created On", ODateTime.class);
@Odoo.api.v8
@Odoo.api.v9alpha
public OColumn write_date = new OColumn("Last Updated On", ODateTime.class);
// Local Base columns
OColumn _id = new OColumn("_ID", OInteger.class).setAutoIncrement().setLocalColumn();
OColumn _write_date = new OColumn("Local Write Date", ODateTime.class).setLocalColumn();
OColumn _is_dirty = new OColumn("Dirty record", OBoolean.class).setDefaultValue(false).setLocalColumn();
OColumn _is_active = new OColumn("Active Record", OBoolean.class).setDefaultValue(true).setLocalColumn();
public OModel(Context context, String model_name, OUser user) {
mContext = context;
mUser = (user == null) ? OUser.current(context) : user;
this.model_name = model_name;
if (mUser != null) {
mOdooVersion = new OdooVersion();
mOdooVersion.setVersion_number(mUser.getVersion_number());
mOdooVersion.setServer_serie(mUser.getVersion_serie());
if (sqLite == null) {
sqLite = new OSQLite(mContext, mUser);
}
}
}
public SQLiteDatabase getReadableDatabase() {
return sqLite.getReadableDatabase();
}
public SQLiteDatabase getWritableDatabase() {
return sqLite.getWritableDatabase();
}
public String getDatabaseName() {
return sqLite.getDatabaseName();
}
public void close() {
// Any operation when closing database
}
public void setDefaultNameColumn(String nameColumn) {
default_name_column = nameColumn;
}
public String getDefaultNameColumn() {
return default_name_column;
}
public OModel setModelName(String model_name) {
this.model_name = model_name;
return this;
}
public boolean hasMailChatter() {
return hasMailChatter;
}
public void setHasMailChatter(boolean hasMailChatter) {
this.hasMailChatter = hasMailChatter;
}
public OUser getUser() {
return mUser;
}
public OdooVersion getOdooVersion() {
return mOdooVersion;
}
public List<OColumn> getColumns() {
if (mColumns.size() == 0) {
prepareFields();
}
return mColumns;
}
public List<OColumn> getColumns(Boolean local) {
if (local != null) {
List<OColumn> cols = new ArrayList<>();
for (OColumn column : getColumns())
if (local == column.isLocal())
cols.add(column);
return cols;
} else {
return mColumns;
}
}
public List<OColumn> getRelationColumns() {
if (mColumns.size() <= 0)
prepareFields();
return mRelationColumns;
}
public OColumn getColumn(String column_name) {
if (mDeclaredFields.size() <= 0)
prepareFields();
Field filed = mDeclaredFields.get(column_name);
return getColumn(filed);
}
private OColumn getColumn(Field field) {
OColumn column = null;
if (field != null) {
try {
field.setAccessible(true);
column = (OColumn) field.get(this);
if (column.getName() == null)
column.setName(field.getName());
Boolean validField = compatibleField(field);
if (validField) {
// Functional Method
Method method = checkForFunctionalColumn(field);
if (method != null) {
column.setIsFunctionalColumn(true);
column.setFunctionalMethod(method);
column.setFunctionalStore(checkForFunctionalStore(field));
column.setFunctionalStoreDepends(getFunctionalDepends(field));
if (!column.canFunctionalStore()) {
column.setLocalColumn();
}
}
// Onchange method for column
Method onChangeMethod = checkForOnChangeMethod(field);
if (onChangeMethod != null) {
column.setOnChangeMethod(onChangeMethod);
column.setOnChangeBGProcess(checkForOnChangeBGProcess(field));
}
// domain filter on column
column.setHasDomainFilterColumn(isDomainFilterColumn(field));
return column;
}
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, e.getMessage());
}
}
return null;
}
private boolean isDomainFilterColumn(Field field) {
Annotation annotation = field.getAnnotation(Odoo.hasDomainFilter.class);
if (annotation != null) {
Odoo.hasDomainFilter domainFilter = (Odoo.hasDomainFilter) annotation;
return domainFilter.checkDomainRuntime();
}
return false;
}
private Boolean checkForOnChangeBGProcess(Field field) {
Annotation annotation = field.getAnnotation(Odoo.onChange.class);
if (annotation != null) {
Odoo.onChange onChange = (Odoo.onChange) annotation;
return onChange.bg_process();
}
return false;
}
private Method checkForOnChangeMethod(Field field) {
Annotation annotation = field.getAnnotation(Odoo.onChange.class);
if (annotation != null) {
Odoo.onChange onChange = (Odoo.onChange) annotation;
String method_name = onChange.method();
try {
return getClass().getMethod(method_name, ODataRow.class);
} catch (NoSuchMethodException e) {
Log.e(TAG, "No Such Method: " + e.getMessage());
}
}
return null;
}
/**
* Check for functional store.
*
* @param field the field
* @return the boolean
*/
public Boolean checkForFunctionalStore(Field field) {
Annotation annotation = field.getAnnotation(Odoo.Functional.class);
if (annotation != null) {
Odoo.Functional functional = (Odoo.Functional) annotation;
return functional.store();
}
return false;
}
/**
* Gets the functional depends.
*
* @param field the field
* @return the functional depends
*/
public String[] getFunctionalDepends(Field field) {
Annotation annotation = field.getAnnotation(Odoo.Functional.class);
if (annotation != null) {
Odoo.Functional functional = (Odoo.Functional) annotation;
return functional.depends();
}
return null;
}
private Method checkForFunctionalColumn(Field field) {
Annotation annotation = field.getAnnotation(Odoo.Functional.class);
if (annotation != null) {
Odoo.Functional functional = (Odoo.Functional) annotation;
String method_name = functional.method();
try {
if (functional.store())
return getClass().getMethod(method_name, OValues.class);
else
return getClass().getMethod(method_name, ODataRow.class);
} catch (NoSuchMethodException e) {
Log.e(TAG, "No Such Method: " + e.getMessage());
}
}
return null;
}
private boolean compatibleField(Field field) {
if (mOdooVersion != null) {
Annotation[] annotations = field.getDeclaredAnnotations();
if (annotations.length > 0) {
int version = 0;
for (Annotation annotation : annotations) {
// Check for odoo api annotation
Class<? extends Annotation> type = annotation.annotationType();
if (type.getDeclaringClass().isAssignableFrom(Odoo.api.class)) {
switch (mOdooVersion.getVersion_number()) {
case 9:
if (type.isAssignableFrom(Odoo.api.v9alpha.class)) {
version++;
}
break;
case 8:
if (type.isAssignableFrom(Odoo.api.v8.class)) {
version++;
}
break;
case 7:
if (type.isAssignableFrom(Odoo.api.v7.class)) {
version++;
}
break;
}
}
// Check for functional annotation
if (type.isAssignableFrom(Odoo.Functional.class)
|| type.isAssignableFrom(Odoo.onChange.class)
|| type.isAssignableFrom(Odoo.hasDomainFilter.class)) {
version++;
}
}
return (version > 0) ? true : false;
}
return true;
}
return false;
}
private void prepareFields() {
mColumns.clear();
mRelationColumns.clear();
List<Field> fields = new ArrayList<>();
fields.addAll(Arrays.asList(getClass().getSuperclass().getDeclaredFields()));
fields.addAll(Arrays.asList(getClass().getDeclaredFields()));
mDeclaredFields.clear();
for (Field field : fields) {
if (field.getType().isAssignableFrom(OColumn.class)) {
String name = field.getName();
try {
OColumn column = getColumn(field);
if (column != null) {
name = column.getName();
if (column.getRelationType() != null) {
mRelationColumns.add(column);
}
if (column.isFunctionalColumn()) {
if (column.canFunctionalStore()) {
mColumns.add(column);
}
mFunctionalColumns.add(column);
} else {
mColumns.add(column);
}
}
} catch (Exception e) {
e.printStackTrace();
}
mDeclaredFields.put(name, field);
}
}
}
public List<OColumn> getFunctionalColumns() {
if (mColumns.size() <= 0)
prepareFields();
return mFunctionalColumns;
}
public String getModelName() {
return model_name;
}
public List<OColumn> getManyToManyColumns(OModel relation_model) {
List<OColumn> cols = new ArrayList<OColumn>();
_write_date.setName("_write_date");
cols.add(_write_date);
_is_dirty.setName("_is_dirty");
cols.add(_is_dirty);
_is_active.setName("_is_active");
cols.add(_is_active);
OColumn base_id = new OColumn("Base Id", OInteger.class);
base_id.setName(getTableName() + "_id");
cols.add(base_id);
OColumn relation_id = new OColumn("Relation Id", OInteger.class);
relation_id.setName(relation_model.getTableName() + "_id");
cols.add(relation_id);
return cols;
}
public OModel createInstance(Class<?> type) {
try {
Constructor<?> constructor = type.getConstructor(Context.class, OUser.class);
return (OModel) constructor.newInstance(mContext, mUser);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public String getTableName() {
return getModelName().replaceAll("\\.", "_");
}
public String toString() {
return getModelName();
}
public static OModel get(Context context, String model_name, String username) {
OModel model = modelRegistry.getModel(model_name, username);
OUser user = OdooAccountManager.getDetails(context, username);
if (model == null) {
try {
OPreferenceManager pfManager = new OPreferenceManager(context);
Class<?> model_class = Class.forName(pfManager.getString(model_name, null));
if (model_class != null) {
model = new OModel(context, model_name, user).createInstance(model_class);
if (model != null) {
modelRegistry.register(model);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
return model;
}
public String authority() {
return BASE_AUTHORITY;
}
public Uri buildURI(String authority) {
BASE_AUTHORITY = authority;
String path = getModelName().toLowerCase(Locale.getDefault());
return BaseModelProvider.buildURI(BASE_AUTHORITY, path, mUser.getAndroidName());
}
public Uri uri() {
String path = getModelName().toLowerCase(Locale.getDefault());
return BaseModelProvider.buildURI(BASE_AUTHORITY, path, mUser.getAndroidName());
}
public ODomain defaultDomain() {
return new ODomain();
}
private String[] updateProjection(String[] projection) {
HashSet<String> names = new HashSet<>();
String[] allProjection = projection;
if (allProjection == null) {
allProjection = projection();
} else {
for (String col : projection) {
OColumn column = getColumn(col);
if (column.isFunctionalColumn() && column.canFunctionalStore()) {
names.add(column.getName());
}
}
}
names.addAll(Arrays.asList(allProjection));
names.addAll(Arrays.asList(new String[]{OColumn.ROW_ID, "id", "_write_date", "_is_dirty", "_is_active"}));
return names.toArray(new String[names.size()]);
}
public String[] projection(Boolean onlyServerColumns) {
List<String> names = new ArrayList<>();
for (OColumn column : getColumns(false)) {
if (column.getRelationType() == null || column.canFunctionalStore()) {
names.add(column.getName());
} else if (column.getRelationType() == OColumn.RelationType.ManyToOne) {
names.add(column.getName());
}
}
return names.toArray(new String[names.size()]);
}
public String[] projection() {
List<String> names = new ArrayList<>();
for (OColumn column : getColumns()) {
if (column.getRelationType() == null || column.canFunctionalStore()) {
names.add(column.getName());
} else if (column.getRelationType() == OColumn.RelationType.ManyToOne) {
names.add(column.getName());
}
}
return names.toArray(new String[names.size()]);
}
// Sync default methods
public boolean checkForCreateDate() {
return true;
}
public boolean checkForWriteDate() {
return true;
}
public boolean allowUpdateRecordOnServer() {
return true;
}
public boolean allowCreateRecordOnServer() {
return true;
}
public boolean allowDeleteRecordOnServer() {
return true;
}
public boolean allowDeleteRecordInLocal() {
return true;
}
// Database Operations
public String getLabel(String column, String key) {
OColumn col = getColumn(column);
if (col.getType().isAssignableFrom(OSelection.class)) {
return col.getSelectionMap().get(key);
}
return "false";
}
public ODataRow browse(int row_id) {
return browse(null, row_id);
}
public ODataRow browse(String[] projection, int row_id) {
List<ODataRow> rows = select(projection, OColumn.ROW_ID + " = ?", new String[]{row_id + ""});
if (rows.size() > 0) {
return rows.get(0);
}
return null;
}
public ODataRow browse(String[] projection, String selection, String[] args) {
List<ODataRow> rows = select(updateProjection(projection), selection, args);
if (rows.size() > 0) {
return rows.get(0);
}
return null;
}
public List<Integer> getServerIds() {
List<Integer> ids = new ArrayList<>();
for (ODataRow row : select(new String[]{"id"})) {
if (row.getInt("id") != 0) {
ids.add(row.getInt("id"));
}
}
return ids;
}
public boolean isEmptyTable() {
return (count(null, null) <= 0);
}
public String getLastSyncDateTime() {
IrModel model = new IrModel(mContext, mUser);
List<ODataRow> records = model.select(null, "model = ?", new String[]{getModelName()});
if (records.size() > 0) {
String date = records.get(0).getString("last_synced");
Date write_date = ODateUtils.createDateObject(date, ODateUtils.DEFAULT_FORMAT, true);
Calendar cal = Calendar.getInstance();
cal.setTime(write_date);
/*
Fixed for Postgres SQL
It stores milliseconds so comparing date wrong.
*/
cal.set(Calendar.SECOND, cal.get(Calendar.SECOND) + 2);
write_date = cal.getTime();
return ODateUtils.getDate(write_date, ODateUtils.DEFAULT_FORMAT);
}
return null;
}
public List<ODataRow> select() {
return select(null, null, null, null);
}
public List<ODataRow> select(String[] projection) {
return select(projection, null, null, null);
}
public List<ODataRow> select(String[] projection, String where, String[] args) {
return select(projection, where, args, null);
}
public List<ODataRow> select(String[] projection, String where, String[] args, String sortOrder) {
Cursor cr = mContext.getContentResolver().query(uri(),
updateProjection(projection), where, args, sortOrder);
List<ODataRow> rows = new ArrayList<>();
try {
if (cr != null && cr.moveToFirst()) {
do {
ODataRow row = OCursorUtils.toDatarow(cr);
for (OColumn column : getRelationColumns(projection)) {
if (!row.getString(column.getName()).equals("false")
|| column.getRelationType() == OColumn.RelationType.OneToMany
|| column.getRelationType() == OColumn.RelationType.ManyToMany) {
switch (column.getRelationType()) {
case ManyToMany:
OM2MRecord m2mRecords = new OM2MRecord(this, column, row.getInt(OColumn.ROW_ID));
row.put(column.getName(), m2mRecords);
break;
case ManyToOne:
OM2ORecord m2ORecord = new OM2ORecord(this, column, row.getInt(column.getName()));
row.put(column.getName(), m2ORecord);
break;
case OneToMany:
OO2MRecord o2MRecord = new OO2MRecord(this, column, row.getInt(OColumn.ROW_ID));
row.put(column.getName(), o2MRecord);
break;
}
}
}
for (OColumn column : getFunctionalColumns(projection)) {
List<String> depends = column.getFunctionalStoreDepends();
if (depends != null && depends.size() > 0) {
ODataRow values = new ODataRow();
for (String depend : depends) {
if (row.contains(depend)) {
values.put(depend, row.get(depend));
}
}
if (values.size() == depends.size()) {
Object value = getFunctionalMethodValue(column, values);
row.put(column.getName(), value);
}
}
}
rows.add(row);
} while (cr.moveToNext());
}
} finally {
cr.close();
}
return rows;
}
public Object getFunctionalMethodValue(OColumn column, Object record) {
if (column.isFunctionalColumn()) {
Method method = column.getFunctionalMethod();
OModel model = this;
try {
return method.invoke(model, new Object[]{record});
} catch (Exception e) {
e.printStackTrace();
}
}
return false;
}
public Object getOnChangeMethodValue(OColumn column, Object record) {
Method method = column.getOnChangeMethod();
OModel model = this;
try {
return method.invoke(model, new Object[]{record});
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
private List<OColumn> getFunctionalColumns(String[] projection) {
List<OColumn> cols = new ArrayList<>();
if (projection != null) {
for (String key : projection) {
OColumn column = getColumn(key);
if (column.isFunctionalColumn() && !column.canFunctionalStore()) {
cols.add(column);
}
}
} else {
for (OColumn column : getFunctionalColumns()) {
if (!column.canFunctionalStore())
cols.add(column);
}
}
return cols;
}
private List<OColumn> getRelationColumns(String[] projection) {
List<OColumn> cols = new ArrayList<>();
if (projection != null) {
for (String key : projection) {
OColumn column = getColumn(key);
if (column.getRelationType() != null) {
cols.add(column);
}
}
} else {
cols.addAll(getRelationColumns());
}
return cols;
}
public int insertOrUpdate(int serverId, OValues values) {
if (hasServerRecord(serverId)) {
int row_id = selectRowId(serverId);
update(row_id, values);
return row_id;
} else {
return insert(values);
}
}
public int insertOrUpdate(String selection, String[] args, OValues values) {
int count = update(selection, args, values);
if (count <= 0) {
return insert(values);
} else {
return selectRowId(selection, args);
}
}
public int selectRowId(String selection, String[] args) {
int row_id = INVALID_ROW_ID;
SQLiteDatabase db = getReadableDatabase();
Cursor cr = db.query(getTableName(), new String[]{OColumn.ROW_ID}, selection, args, null, null, null);
try {
if (cr.moveToFirst()) {
row_id = cr.getInt(0);
}
} finally {
cr.close();
}
return row_id;
}
public int selectServerId(int row_id) {
return browse(row_id).getInt("id");
}
public int selectRowId(int server_id) {
List<ODataRow> rows = select(new String[]{OColumn.ROW_ID}, "id = ?", new String[]{server_id + ""});
if (rows.size() > 0) {
return rows.get(0).getInt(OColumn.ROW_ID);
}
return INVALID_ROW_ID;
}
public int insert(OValues values) {
Uri uri = mContext.getContentResolver().insert(uri(), values.toContentValues());
if (uri != null) {
return Integer.parseInt(uri.getLastPathSegment());
}
return INVALID_ROW_ID;
}
public boolean hasServerRecord(int server_id) {
int count = count("id = ? ", new String[]{server_id + ""});
return (count > 0);
}
public boolean isServerRecordDirty(int server_id) {
int count = count("id = ? and _is_dirty = ?", new String[]{server_id + "", "true"});
return (count > 0);
}
public boolean hasRecord(int row_id) {
int count = count(OColumn.ROW_ID + " = ? ", new String[]{row_id + ""});
return (count > 0);
}
public int deleteRecords(List<Integer> serverIds, boolean permanently) {
String selection = "id IN (" + StringUtils.repeat("?, ", serverIds.size() - 1) + " ?)";
String[] args = OListUtils.toStringList(serverIds).toArray(new String[serverIds.size()]);
if (permanently) {
return delete(selection, args, true);
} else {
OValues values = new OValues();
values.put("_is_active", "false");
return update(selection, args, values);
}
}
public int delete(String selection, String[] args) {
return delete(selection, args, false);
}
public int delete(String selection, String[] args, boolean permanently) {
int count = 0;
if (permanently) {
count = mContext.getContentResolver().delete(uri(), selection, args);
} else {
List<ODataRow> records = select(new String[]{"_is_active"}, selection, args);
for (ODataRow row : records) {
if (row.getBoolean("_is_active")) {
OValues values = new OValues();
values.put("_is_active", "false");
update(row.getInt(OColumn.ROW_ID), values);
}
count++;
}
}
return count;
}
public boolean delete(int row_id) {
return delete(row_id, false);
}
public boolean delete(int row_id, boolean permanently) {
int count = 0;
if (permanently)
count = mContext.getContentResolver().delete(uri().withAppendedPath(uri(), row_id + ""), null, null);
else {
OValues values = new OValues();
values.put("_is_active", "false");
update(row_id, values);
count++;
}
return (count > 0) ? true : false;
}
public int update(String selection, String[] args, OValues values) {
return mContext.getContentResolver().update(uri(), values.toContentValues(), selection, args);
}
public boolean update(int row_id, OValues values) {
int count = mContext.getContentResolver().update(uri().withAppendedPath(uri(), row_id + ""),
values.toContentValues(), null, null);
return (count > 0) ? true : false;
}
public List<ODataRow> query(String query) {
return query(query, null);
}
public List<ODataRow> query(String query, String[] args) {
List<ODataRow> rows = new ArrayList<>();
SQLiteDatabase db = getReadableDatabase();
Cursor cr = db.rawQuery(query, args);
try {
if (cr.moveToFirst()) {
do {
rows.add(OCursorUtils.toDatarow(cr));
} while (cr.moveToNext());
}
} finally {
cr.close();
}
return rows;
}
public int count(String selection, String[] args) {
int count = 0;
SQLiteDatabase db = getReadableDatabase();
Cursor cr = db.query(getTableName(), new String[]{"count(*)"}, selection, args, null, null, null);
try {
cr.moveToFirst();
count = cr.getInt(0);
} finally {
cr.close();
}
return count;
}
public void storeManyToManyRecord(String column_name, int row_id, List<Integer> relationIds,
Command command)
throws InvalidObjectException {
OColumn column = getColumn(column_name);
if (column != null) {
OModel rel_model = createInstance(column.getType());
String table = getTableName() + "_" + rel_model.getTableName() + "_rel";
String base_column = getTableName() + "_id";
String rel_column = rel_model.getTableName() + "_id";
SQLiteDatabase db = getWritableDatabase();
try {
switch (command) {
case Add:
if (relationIds.size() > 0) {
for (int id : relationIds) {
ContentValues values = new ContentValues();
values.put(base_column, row_id);
values.put(rel_column, id);
values.put("_write_date", ODateUtils.getDate());
db.insert(table, null, values);
}
}
break;
case Update:
break;
case Delete:
// Deleting records to relation model
if (relationIds.size() > 0) {
for (int id : relationIds) {
db.delete(table, base_column + " = ? AND " + rel_column
+ " = ?", new String[]{row_id + "", id + ""});
}
}
break;
case Replace:
// Removing old entries
db.delete(table, base_column + " = ?", new String[]{row_id + ""});
// Creating new entries
storeManyToManyRecord(column_name, row_id, relationIds, Command.Add);
break;
}
} finally {
db.close();
rel_model.close();
}
} else {
throw new InvalidObjectException("Column [" + column_name + "] not found in " + getModelName() + " model.");
}
}
public List<ODataRow> selectManyToManyRecords(String[] projection, String column_name, int row_id) {
OColumn column = getColumn(column_name);
OModel rel_model = createInstance(column.getType());
String table = getTableName() + "_" + rel_model.getTableName() + "_rel";
String base_column = getTableName() + "_id";
String rel_column = rel_model.getTableName() + "_id";
// Getting relation table ids
List<String> ids = new ArrayList<>();
SQLiteDatabase db = getReadableDatabase();
Cursor cr = null;
try {
cr = db.query(table, new String[]{rel_column}, base_column + "=?",
new String[]{row_id + ""}, null, null, null);
if (cr.moveToFirst()) {
do {
ids.add(cr.getInt(0) + "");
} while (cr.moveToNext());
}
} finally {
if (cr != null) {
cr.close();
}
}
List<ODataRow> data = rel_model.select(projection, OColumn.ROW_ID + " IN (" + StringUtils.repeat(" ?, ", ids.size() - 1) + " ?)",
ids.toArray(new String[ids.size()]));
rel_model.close();
return data;
}
public ServerDataHelper getServerDataHelper() {
return new ServerDataHelper(mContext, this, getUser());
}
public String getName(int row_id) {
ODataRow row = browse(row_id);
if (row != null) {
return row.getString("name");
}
return "false";
}
public void quickSyncRecords(ODomain domain) {
OSyncAdapter syncAdapter = new OSyncAdapter(mContext, getClass(), null, true);
syncAdapter.setModel(this);
syncAdapter.setDomain(domain);
syncAdapter.checkForWriteCreateDate(false);
syncAdapter.onPerformSync(getUser().getAccount(), null, authority(), null, new SyncResult());
}
public ODataRow quickCreateRecord(ODataRow record) {
OSyncAdapter syncAdapter = new OSyncAdapter(mContext, getClass(), null, true);
syncAdapter.setModel(this);
ODomain domain = new ODomain();
domain.add("id", "=", record.getInt("id"));
syncAdapter.setDomain(domain);
syncAdapter.checkForWriteCreateDate(false);
syncAdapter.onPerformSync(getUser().getAccount(), null, authority(), null, new SyncResult());
return browse(null, "id = ?", new String[]{record.getString("id")});
}
public ODataRow countGroupBy(String column, String group_by, String having, String[] args) {
String sql = "select count(*) as total, " + column;
sql += " from " + getTableName() + " group by " + group_by + " having " + having;
List<ODataRow> data = query(sql, args);
if (data.size() > 0) {
return data.get(0);
} else {
ODataRow row = new ODataRow();
row.put("total", 0);
return row;
}
}
public boolean isInstalledOnServer(String module_name) {
try {
App app = (App) mContext.getApplicationContext();
IrModel model = new IrModel(mContext, getUser());
List<ODataRow> modules = model.select(null, "name = ?", new String[]{module_name.trim()});
if (modules.size() > 0) {
if (modules.get(0).getString("state").equals("installed")) {
return true;
}
}
if (app.inNetwork()) {
odoo.Odoo odoo = app.getOdoo(getUser());
OdooFields fields = new OdooFields(new String[]{"state", "name"});
ODomain domain = new ODomain();
domain.add("name", "=", module_name);
JSONArray result = odoo.search_read("ir.module.module", fields.get(), domain.get())
.getJSONArray("records");
if (result.length() > 0) {
JSONObject record = result.getJSONObject(0);
if (record.getString("state").equals("installed")) {
OValues values = new OValues();
values.put("id", record.getInt("id"));
values.put("name", record.getString("name"));
values.put("state", record.getString("state"));
model.insertOrUpdate(record.getInt("id"), values);
return true;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
public String getDatabaseLocalPath() {
return sqLite.databaseLocalPath();
}
public void exportDB() {
FileChannel source;
FileChannel destination;
String currentDBPath = getDatabaseLocalPath();
String backupDBPath = OStorageUtils.getDirectoryPath("file")
+ "/" + getDatabaseName();
File currentDB = new File(currentDBPath);
File backupDB = new File(backupDBPath);
try {
source = new FileInputStream(currentDB).getChannel();
destination = new FileOutputStream(backupDB).getChannel();
destination.transferFrom(source, 0, source.size());
source.close();
destination.close();
String subject = "Database Export: " + getDatabaseName();
Uri uri = Uri.fromFile(backupDB);
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_STREAM, uri);
intent.putExtra(Intent.EXTRA_SUBJECT, subject);
intent.setType("message/rfc822");
mContext.startActivity(intent);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onSyncStarted() {
// Will be over ride by extending model
}
@Override
public void onSyncFinished() {
// Will be over ride by extending model
}
}