Odoo RPC Client Library for Dart

Odoo RPC Client Library

Odoo RPC Client Library for Dart.

Features

  • Initialize client with previously stored Odoo Session.
  • Authenticate via database name, login and password.
  • Issue JSON-RPC requests to JSON controllers.
  • Execute public methods via CallKw.
  • Get Odoo Session updates via stream.
  • Terminate session (logout).
  • Catch exceptions when session expires.

Usage

To use this plugin, add flutter_odoo_rpc as a dependency in your pubspec.yaml file. For example:

dependencies:
  flutter_odoo_rpc: ^0.4.5

Examples

Basic RPC-call

import 'dart:io';
import 'package:flutter_odoo_rpc/flutter_odoo_rpc.dart'

main() async {
  final client = OdooClient('https://my-db.odoo.com');
  try {
    await client.authenticate('my-db', 'admin', 'admin');
    final res = await client.callRPC('/web/session/modules', 'call', {});
    print('Installed modules: \n' + res.toString());
  } on OdooException catch (e) {
    print(e);
    client.close();
    exit(-1);
  }
  client.close();
}

RPC-Calls with tracking session changes. Odoo server will issue new session_id on each call.

import 'dart:io';
import 'package:flutter_odoo_rpc/flutter_odoo_rpc.dart'


sessionChanged(OdooSession sessionId) async {
  print('We got new session ID: ' + sessionId.id);
  store_session_somehow(sessionId);
}


main() async {
  var prev_session = restore_session_somehow();
  var client = OdooClient("https://my-db.odoo.com", prev_session);

  // Subscribe to session changes to store most recent one
  var subscription = client.sessionStream.listen(sessionChanged);

  try {
    final session = await client.authenticate('my-db', 'admin', 'admin');
    var res = await client.callRPC('/web/session/modules', 'call', {});
    print('Installed modules: \n' + res.toString());

    // logout
    await client.destroySession();
  } on OdooException catch (e) {
    print(e);
    subscription.cancel();
    client.close();
    exit(-1);
  }

  try {
    await client.checkSession();
  } on OdooSessionExpiredException {
    print('Session expired');
  }

  subscription.cancel();
  client.close();
}

Flutter example using FutureBuilder.

import 'package:flutter/material.dart';
import 'package:flutter_odoo_rpc/flutter_odoo_rpc.dart';

final orpc = OdooClient('https://my-odoo-instance.com');
void main() async {
  await orpc.authenticate('odoo-db', 'admin', 'admin');
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  Future<dynamic> fetchContacts() {
    return orpc.callKw({
      'model': 'res.partner',
      'method': 'search_read',
      'args': [],
      'kwargs': {
        'context': {'bin_size': true},
        'domain': [],
        'fields': ['id', 'name', 'email', '__last_update', 'image_128'],
        'limit': 80,
      },
    });
  }

  Widget buildListItem(Map<String, dynamic> record) {
    var unique = record['__last_update'] as String;
    unique = unique.replaceAll(RegExp(r'[^0-9]'), '');
    final avatarUrl =
        '${orpc.baseURL}/web/image?model=res.partner&field=image_128&id=${record["id"]}&unique=$unique';
    return ListTile(
      leading: CircleAvatar(backgroundImage: NetworkImage(avatarUrl)),
      title: Text(record['name']),
      subtitle: Text(record['email'] is String ? record['email'] : ''),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Contacts'),
      ),
      body: Center(
        child: FutureBuilder(
            future: fetchContacts(),
            builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
              if (snapshot.hasData) {
                return ListView.builder(
                    itemCount: snapshot.data.length,
                    itemBuilder: (context, index) {
                      final record =
                          snapshot.data[index] as Map<String, dynamic>;
                      return buildListItem(record);
                    });
              } else {
                if (snapshot.hasError) return Text('Unable to fetch data');
                return CircularProgressIndicator();
              }
            }),
      ),
    );
  }
}

For more complex usage consider odoo_repository as abstraction layer between your flutter app and Odoo backend.

Web platform notice

This package intentionally uses http package instead of dart:io so web platform could be supported. However RPC calls via web client (dart js) that is hosted on separate domain will not work due to CORS requests currently are not correctly handled by Odoo. See https://github.com/odoo/odoo/pull/37853 for the details.

Issues

Please file any issues, bugs or feature requests as an issue on our GitHub page.

Want to contribute

If you would like to contribute to the plugin (e.g. by improving the documentation, solving a bug or adding a cool new feature), please send us your pull request.

Author

Odoo RPC Client Library is developed by ERP Ukraine.

Use this package as a library

Depend on it

Run this command:

With Dart:

 $ dart pub add flutter_odoo_rpc

With Flutter:

 $ flutter pub add flutter_odoo_rpc

This will add a line like this to your package's pubspec.yaml (and run an implicit dart pub get):

dependencies:
  flutter_odoo_rpc: ^0.6.0

Alternatively, your editor might support dart pub get or flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:flutter_odoo_rpc/flutter_odoo_rpc.dart'; 

example/lib/main.dart

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter_odoo_rpc/flutter_odoo_rpc.dart';

void sessionChanged(OdooSession sessionId) async {
  debugPrint('We got new session ID: ${sessionId.id}');
  // write to persistent storage
}

void loginStateChanged(OdooLoginEvent event) async {
  if (event == OdooLoginEvent.loggedIn) {
    debugPrint('Logged in');
  }
  if (event == OdooLoginEvent.loggedOut) {
    debugPrint('Logged out');
  }
}

void inRequestChanged(bool event) async {
  if (event) debugPrint('Request is executing'); // draw progress indicator
  if (!event) debugPrint('Request is finished'); // hide progress indicator
}

void main() async {
  // Restore session ID from storage and pass it to client constructor.
  const baseUrl = 'https://demo.odoo.com';
  final client = OdooClient(baseUrl);
  // Subscribe to session changes to store most recent one
  var subscription = client.sessionStream.listen(sessionChanged);
  var loginSubscription = client.loginStream.listen(loginStateChanged);
  var inRequestSubscription = client.inRequestStream.listen(inRequestChanged);

  try {
    // Authenticate to server with db name and credentials
    final session = await client.authenticate('odoo', 'admin', 'admin');
    debugPrint(session.toString());
    debugPrint('Authenticated');

    // Compute image avatar field name depending on server version
    final imageField =
        session.serverVersionInt >= 13 ? 'image_128' : 'image_small';

    // Read our user's fields
    final uid = session.userId;
    var res = await client.callKw({
      'model': 'res.users',
      'method': 'search_read',
      'args': [],
      'kwargs': {
        'context': {'bin_size': true},
        'domain': [
          ['id', '=', uid]
        ],
        'fields': ['id', 'name', '__last_update', imageField],
      },
    });
    debugPrint('\nUser info: \n$res');
    // compute avatar url if we got reply
    if (res.length == 1) {
      var unique = res[0]['__last_update'] as String;
      unique = unique.replaceAll(RegExp(r'[^0-9]'), '');
      final userAvatar =
          '$baseUrl/web/image?model=res.user&field=$imageField&id=$uid&unique=$unique';
      debugPrint('User Avatar URL: $userAvatar');
    }

    // Create partner
    var partnerId = await client.callKw({
      'model': 'res.partner',
      'method': 'create',
      'args': [
        {
          'name': 'Stealthy Wood',
        },
      ],
      'kwargs': {},
    });
    // Update partner by id
    res = await client.callKw({
      'model': 'res.partner',
      'method': 'write',
      'args': [
        partnerId,
        {
          'is_company': true,
        },
      ],
      'kwargs': {},
    });

    // Get list of installed modules
    res = await client.callRPC('/web/session/modules', 'call', {});
    debugPrint('\nInstalled modules: \n$res');

    // Check if loggeed in
    debugPrint('\nChecking session while logged in');
    res = await client.checkSession();
    debugPrint('ok');

    // Log out
    debugPrint('\nDestroying session');
    await client.destroySession();
    debugPrint('ok');
  } on OdooException catch (e) {
    // Cleanup on odoo exception
    debugPrint(e.message);
    await subscription.cancel();
    await loginSubscription.cancel();
    await inRequestSubscription.cancel();
    client.close();
    exit(-1);
  }

  debugPrint('\nChecking session while logged out');
  try {
    var res = await client.checkSession();
    debugPrint(res);
  } on OdooSessionExpiredException {
    debugPrint('Odoo Exception:Session expired');
  }
  await client.inRequestStream.isEmpty;
  await subscription.cancel();
  await loginSubscription.cancel();
  await inRequestSubscription.cancel();
  client.close();
} 

Download details:

Author: 

Source: https://pub.dev/packages/flutter_odoo_rpc

#flutter #android #ios 

Odoo RPC Client Library for Dart
3.20 GEEK