Connect to Odoo REST API Using xml_rpc in Flutter

XML-RPC is a remote procedure call protocol that uses XML to encode the parameters and return values. It is a popular protocol for exchanging data between servers and clients and is used by many programming languages.

Flutter includes a library for making XML-RPC calls, which makes it easy to connect to Odoo servers from your Flutter app.

class OdooClient {
  String? url;
  String? db;
  String? username;
  String? pass;
  int? uid;

  OdooClient(this.url, this.db, this.username, this.pass, this.uid);

  OdooClient.withUser(User user) {
    uid = user.id;
    url = user.url;
    db = user.database;
    username = user.username;
    pass = user.password;
  }

  Future<OdooResponse> fetchData(String table, List<dynamic> args, Map<String, Object> params) async {

    //default params
    if(!params.containsKey("offset")){
      params["offset"] = 0;
    }
    if(!params.containsKey("limit")){
      params["limit"] = 100;
    }

    OdooResponse response = OdooResponse.empty();
    await searchRead(table, [args], params).then((items) async {
      for (var i = 0; i < items.length; i++) {
        response.jsonData!.add(items[i]);
      }
      response.success = ResponseStatus.success;
    }).onError((error, stackTrace) {
      response.success = ResponseStatus.failed;
      response.message = error.toString();
    });
    return response;
  }


  /*Base*/

  String? get formattedBaseURL {
    String fUrl = url!;
    if (!fUrl.endsWith('/')) {
      fUrl = fUrl + '/';
    }
    return fUrl;
  }

  Uri get commonURL {
    return Uri.parse(formattedBaseURL! + 'xmlrpc/2/common');
  }

  Uri get objectURL {
    return Uri.parse(formattedBaseURL! + 'xmlrpc/2/object');
  }

  Future<List<dynamic>> search(String model, List<dynamic> args) async {
    return await xml_rpc.call(objectURL, 'execute_kw', [db, uid, pass, model, 'search', args]);
  }

  Future<List<dynamic>> searchRead(String model, List<dynamic> args, Map<String, Object> params) async {
    return await xml_rpc.call(objectURL, 'execute_kw', [db, uid, pass, model, 'search_read', args, params]);
  }

  Future<dynamic> create(String model, List<dynamic> params) async {
    return await xml_rpc.call(objectURL, 'execute_kw', [db, uid, pass, model, 'create', params]);
  }

  Future<dynamic> write(String model, List<dynamic> params) async {
    return await xml_rpc.call(objectURL, 'execute_kw', [db, uid, pass, model, 'write', params]);
  }

  Future<dynamic> action(String model, String action, List<dynamic> params) async {
    return await xml_rpc.call(objectURL, 'execute_kw', [db, uid, pass, model, action, params]);
  }

  Future<dynamic> authenticate() async {
    return await xml_rpc.call(commonURL, 'authenticate', [db, username, pass, '']);
  }

  Future<dynamic> getFields(String model) async {
    //Map<String, List<dynamic>> params = {'attributes': ['string', 'help', 'type']};
    Map<String, List<dynamic>> params = {
      'attributes': ['string']
    };
    return await xml_rpc.call(objectURL, 'execute_kw', [db, uid, pass, model, 'fields_get', [], params]);
  }
}
class OdooResponse {
  ResponseStatus? success;
  String? message;
  List<dynamic>? jsonData;

  OdooResponse(this.success, this.message, this.jsonData);

  OdooResponse.empty() {
    success = ResponseStatus.failed;
    message = "";
    jsonData = [];
  }

  bool get isSuccess => success == ResponseStatus.success;
}