Giter Site home page Giter Site logo

odoo-rpc-dart's Introduction

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 odoo_rpc as a dependency in your pubspec.yaml file. For example:

dependencies:
  odoo_rpc: ^0.4.5

Examples

Basic RPC-call

import 'dart:io';
import 'package:odoo_rpc/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:odoo_rpc/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:odoo_rpc/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 odoo/odoo#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.

odoo-rpc-dart's People

Contributors

lem8r avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

odoo-rpc-dart's Issues

Update code function : callRPC

You should update this String by the param which is funcName

It looks like there might be an issue with how you're sending the request to the Odoo server. In your callRPC function, you're setting the method name as a string 'funcName' instead of the actual value of the funcName variable.

  Future<dynamic> callRPC(path, funcName, params) async {
 final uri = Uri.parse(baseURL + path);
    var body = json.encode({
      'jsonrpc': '2.0',
      'method': 'funcName',  // // Update this line by   'method': funcName,
      'params': params,
      'id': sha1.convert(utf8.encode(DateTime.now().toString())).toString()
    });

Path: line 183

link

# Error:

I/flutter (21348):   File "C:\Program Files\Odoo 16.0\server\odoo\http.py", line 1588, in _serve_db
I/flutter (21348):     return service_model.retrying(self._serve_ir_http, self.env)
I/flutter (21348):   File "C:\Program Files\Odoo 16.0\server\odoo\service\model.py", line 133, in retrying
I/flutter (21348):     result = func()
I/flutter (21348):   File "C:\Program Files\Odoo 16.0\server\odoo\http.py", line 1615, in _serve_ir_http
I/flutter (21348):     response = self.dispatcher.dispatch(rule.endpoint, args)
I/flutter (21348):   File "C:\Program Files\Odoo 16.0\server\odoo\http.py", line 1819, in dispatch
I/flutter (21348):     result = self.request.registry['ir.http']._dispatch(endpoint)
I/flutter (21348):   File "C:\Program Files\Odoo 16.0\server\odoo\addons\website\models\ir_http.py", line 237, in _dispatch
I/flutter (21348):     response = super()._dispatch(endpoint)
I/flutter (21348):   File "C:\Program Files\Odoo 16.0\server\odoo\addons\base\models\ir_http.py", line 154, in _dispatch
I/flutter (21348):     result = endpoint(**request.params)
I/flutter (21348):   File "C:\Program Files\Odoo 16.0\server\odoo\http.py",
I/flutter (21348): 505-builtins.TypeError

Thank you for your effort

Update http dependency to the latest version (1.1.0)

I am seeing this version conflict in my project:

Because odoo_rpc 0.5.1 depends on http ^0.13.0 and no versions of odoo_rpc match >0.5.1 <0.6.0, odoo_rpc ^0.5.1 requires http ^0.13.0.
So, because faster_empleo depends on both http ^1.1.0 and odoo_rpc ^0.5.1, version solving failed.
Process

If somebody is having this issue, you can temporarily force the http version by adding this in pubspec.yaml:

dependency_overrides:
  http: 1.0.0

update data in an existing module

Hi,
How can we update data in a module .I want to change the name of driver assigned to car in the fleet module.
Secondly, Can we stream into the Discuss module from apps ?
Can u show an example for both problems.

type 'List<dynamic>' is not a subtype of type 'List<int>' in type cast

Hello.

I'm getting this exception when authenticating with the server. I just upgraded to Flutter 2 in stable and I am tracking and fixing some issues here and there. This code used to work just fine, but now I get this exception. What can be causing this...?

I am using odoo_rpc 0.4.0

Thanks

 [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: type 'List<dynamic>' is not a subtype of type 'List<int>' in type cast
 #0      OdooSession.fromSessionInfo (package:odoo_rpc/src/odoo_session.dart:58:49)
 #1      OdooClient.authenticate (package:odoo_rpc/src/odoo_client.dart:253:32)
 <asynchronous suspension>
 #2      APIService.initialize (package:nbp_odoo_client/app/services/API_service.dart:32:13)
 <asynchronous suspension>
 #3      _LoginPageState.loginAction (package:nbp_odoo_client/app/pages/login_page.dart:169:30)
 <asynchronous suspension>

code: 200 , message: Odoo server error

the method search_read worked fine
but when i try to use method create
it result in:
{"jsonrpc": "2.0", "id": null, "error": {"code": 200, "message": "Odoo Server Error"}}

[Feature] Get list of available databases

Hello,

I was wondering if there was a way to get the list of available databases on a server using the current version of the package or if it's something that might be useful to implement as a new feature.

Thanks!

Extract a flutter application using Odoo_rpc package

After i extract an application using this package , i can't sign in in the application that doesn't using debug mood , it's only work in debug mood .
When i use it in a debug mood , i get this error :
ClientException with SocketException : Failed host lookup :' my Url' ( OS Error: No address associated with hostname , error =7),

Please give me some clues to the solution

pulling images like contact avatar

when i tried to pull a contact avatar to the contacts page it is giving out a blank pic
Screenshot_1708964449

like this and when i tried to access the link for example
http://localhost:8069/web/image?model=res.partner&field=image_128&id=23&unique=20240223035456
in browser it shows

Screenshot 2024-02-26 215231

like this maybe because i have not logged in
so i logged in to odoo in browser

and then when i open the link

i got this
Screenshot 2024-02-26 215428

yeah i will share the code

`import 'package:flutter/material.dart';
import 'package:odoo_rpc/odoo_rpc.dart';

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {
@OverRide
Widget build(BuildContext context) {
return MaterialApp(
title: 'Odoo Contacts App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: LoginPage(),
);
}
}

class LoginPage extends StatefulWidget {
@OverRide
_LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State {
final TextEditingController emailController = TextEditingController();
final TextEditingController passwordController = TextEditingController();
final OdooClient odoo = OdooClient('http://172.18.109.2:8069');

Future _login() async {
try {
await odoo.authenticate(
'test', emailController.text, passwordController.text);
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => HomePage(odoo: odoo)),
);
} catch (e) {
print('Login failed: $e');
// Handle login failure, show an error message, etc.
}
}

@OverRide
void dispose() {
emailController.dispose();
passwordController.dispose();
odoo.close();
super.dispose();
}

@OverRide
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Login Page'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField(
controller: emailController,
decoration: InputDecoration(labelText: 'Email'),
),
TextField(
controller: passwordController,
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
),
SizedBox(height: 16.0),
ElevatedButton(
onPressed: _login,
child: Text('Login'),
),
],
),
),
);
}
}

class HomePage extends StatelessWidget {
final OdooClient odoo;

HomePage({required this.odoo});

Future fetchContacts() {
return odoo.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) {
print(record);
var unique = record['__last_update'] as String;
unique = unique.replaceAll(RegExp(r'[^0-9]'), '');
print(odoo.baseURL);
final avatarUrl =
'${odoo.baseURL}/web/image?model=res.partner&field=image_128&id=${record["id"]}&unique=$unique';
print(avatarUrl);
return ListTile(
leading: CircleAvatar(
backgroundImage: NetworkImage(avatarUrl),
backgroundColor: Colors.black,
),
title: Text(record['name']),
subtitle: Text(record['email'] is String ? record['email'] : ''),
);
}

@OverRide
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Contacts'),
// actions: [
// IconButton(
// onPressed: () {
// // Log out and navigate back to the login page
// odoo.logout();
// Navigator.pop(context);
// },
// icon: Icon(Icons.logout),
// ),
// ],
),
body: Center(
child: FutureBuilder(
future: fetchContacts(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text('Unable to fetch data');
} else 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 {
return Text('No data available');
}
},
),
),
);
}
}
`

orpc.authenticate raise a null pointer exception

flutter: ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
flutter: │ #0 main (package:odoo_rpc_flutter_demo/main.dart:54:12)
flutter: │ #1
flutter: ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
flutter: │ 💡 Logging with credentials
flutter: └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: type 'Null' is not a subtype of type 'int' in type cast
#0 OdooSession.fromSessionInfo (package:odoo_rpc/src/odoo_session.dart:65:37)
#1 OdooClient.authenticate (package:odoo_rpc/src/odoo_client.dart:261:32)

#2 main (package:odoo_rpc_flutter_demo/main.dart:55:5)

keep session and saty logged in

in my flutter app i use multiple pages, is there a way to use the same instance (opened when user logged in) or should I authenticate everytime i switch pages

CallKW result is not a valid json result

Hi, I have an issue after calling a 'callKw' method the result as String is not a JSONformat instead it appears like that:

'[{id: 1, partner_id: [26, SIGMA soft], create_date: 2019-11-16 14:44:21, name: WH/IN/00001}, {id: 2, partner_id: [26, SIGMA soft], create_date: 2019-11-16 15:20:24, name: WH/IN/00002}, {id: 4, partner_id: [26, SIGMA soft], create_date: 2020-03-08 07:47:28, name: WH/IN/00003}, {id: 5, partner_id: [26, SIGMA soft], create_date: 2020-03-08 09:22:47, name: WH/IN/00004}, {id: 19, partner_id: [26, SIGMA soft], create_date: 2020-06-12 22:11:40, name: WH/IN/00005}]'

Any suggestions to set it as a valid JSON format.
Thank you

error OdooException: {code: 200, message: Odoo Server Error, data: {name: builtins.ValueError, debug: Traceback (most recent call last):

when i try this code :
var res = await client.callKw({
'model': 'hr.attendance',
'method': 'write',
'args': [
17,
{
'check_out': a,
},
],
'kwargs': {},
});
I have this error:
error OdooException: {code: 200, message: Odoo Server Error, data: {name: builtins.ValueError, debug: Traceback (most recent call last):
I/flutter ( 5416): File "/home/odoo/src/odoo/saas-16.4/odoo/http.py", line 1710, in _serve_db
I/flutter ( 5416): return service_model.retrying(self._serve_ir_http, self.env)
I/flutter ( 5416): File "/home/odoo/src/odoo/saas-16.4/odoo/service/model.py", line 133, in retrying
I/flutter ( 5416): result = func()
I/flutter ( 5416): File "/home/odoo/src/odoo/saas-16.4/odoo/http.py", line 1737, in _serve_ir_http
I/flutter ( 5416): response = self.dispatcher.dispatch(rule.endpoint, args)
I/flutter ( 5416): File "/home/odoo/src/odoo/saas-16.4/odoo/http.py", line 1938, in dispatch
result = self.request.registry['ir.http']._dispatch(endpoint)
I/flutter ( 5416): File "/home/odoo/src/odoo/saas-16.4/addons/website/models/ir_http.py", line 233, in _dispatch
I/flutter ( 5416): response = super()._dispatch(endpoint)
I/flutter ( 5416): File "/home/odoo/src/odoo/saas-16.4/odoo/addons/base/models/ir_http.py", line 191, in _dispatch
I/flutter ( 5416): result = endpoint(**request.params)
I/flutter ( 5416): File "/home/odoo/src/odoo/saas-16.4/odoo/http.py", line 717, in route_wrappe

how to resolve it

Keep sessions when Apps closed

How to handle sessions when apps being closed and then apps re opening,

Because when apps is closed then opening again, it says Session Expired

Thanks

Incomplete text in exceptions

Hello,

Whenever I get an exception, the full stacktrace is incomplete. For example:

OdooException: {code: 200, message: Odoo Server Error, data: {name: psycopg2.DataError, debug: Traceback (most recent call last):
   File "/opt/odoo/odoo/http.py", line 624, in _handle_exception
     return super(JsonRequest, self)._handle_exception(exception)
   File "/opt/odoo/odoo/http.py", line 310, in _handle_exception
     raise pycompat.reraise(type(exception), exception, sys.exc_info()[2])
   File "/opt/odoo/odoo/tools/pycompat.py", line 14, in reraise
     raise value
   File "/opt/odoo/odoo/http.py", line 669, in dispatch
     result = self._call_function(**self.params)
   File "/opt/odoo/odoo/http.py", line 350, in _call_function
     return checked_call(self.db, *args, **kwargs)
   File "/opt/odoo/odoo/service/model.py", line 94, in wrapper
     return f(dbname, *args, **kwargs)
   File "/opt/odoo/odoo/http.py", line 339, in checked_call
     result = self.endpoint(*a, **kw)
   File "/opt/odoo/odoo/http.py", line 915, in __call__
     return self.method(*args, **kw)
   File "/opt/odoo/odoo/http.py", line 515, in

I'm not sure if this is due to something in odoo-rpc-dart or somewhere else. Any ideas how may I fix this?

Thanks

Session Expired Exception

This issue reports the "Odoo Session Expired Exception" encountered during an Odoo operation.

Response

{
  "jsonrpc": "2.0",
  "id": "14678723494e63fbecfdcfa059293a9f258b4c44",
  "error": {
    "code": 100,
    "message": "Odoo Session Expired",
    "data": {
      "name": "odoo.http.SessionExpiredException",
      "debug": "... Traceback details ..."
    },
    "message": "Session expired",
    "arguments": ["Session expired"],
    "context": {}
  }
}

how i call it

 try{
       await client.authenticate(ODOO_DB, ODOO_UserName, ODOO_Password);

      await client.callKw({
        'model': 'request.request',
        'method': 'create',
        'args': [
          {
            ....
          },
        ],
        'kwargs': {}
      });
}

Cookie for Auth

Hi. Great job.

I have found 2 issues:

  1. On odoo_client.dart / _updateSessionIdFromCookies , data from response.headers['set-cookie'] comes with an error from Odoo response after authentication (I have tested with Community Ed. Versions 12 and 14).

Content of set-cookie:
__cfduid=d7aa416b09272df9c8ooooooo84f5d031615155878; expires=Tue, 06-Apr-21 22:24:38 GMT; path=/; domain=.mhfly.com; HttpOnly; SameSite=Lax,session_id=16ec9824767d8ca27ooooooo2fa61803fb35857b; Expires=Sat, 05-Jun-2021 22:24:38 GMT; Max-Age=7776000; HttpOnly; Path=/

Note that separator between SameSite=Lax AND session_id =... is a comma, not a semicolon. This Odoo bug cause bad parsing in _updateSessionIdFromCookies

  1. For a good callRPC you must send __cfduid + session_id in Cookie, something like:
    __cfduid=d0c6c49b60848cc2d509ooooooo1261615152080; session_id=5af3e0bb806a96b7oooooooo5398bc4be1a25

Even sending whole original set-cookie obtained from authentication also works (just changing comma separator by semicolon).

Best regards.

Typo in pub.dev page

Hello, there is a typo in the examples in the pub.dev page.
The import line says 'packages' but it should be 'package' (singular)

Current:
import 'packages:odoo_rpc/odoo_rpc.dart'

Correct:
import 'package:odoo_rpc/odoo_rpc.dart'

New Odoo Change data type in Saas DB

New Update in Odoo Saas db field serverVersion return a String.
Is required change file odoo_session.dart

final int serverVersion => final String severVersion
serverVersion: versionInfo[0] as int => serverVersion: versionInfo[0] as String
serverVersion: newSessionId == '' ? 0 : serverVersion => serverVersion: newSessionId == '' ? '' : serverVersion,

I tested and work OK.

Cannot access avatar from the url

From the example, we can get the URL of the avatar, but always get default image, as we did not login, so cannot get the real image of user. How to resolve it?

Odoo 9.0

Does this plugin support Odoo 9.0 version?

type 'Null' is not a subtype of type 'int' in type cast

environment:
sdk: '>=2.16.0'
dependencies:
odoo_rpc: ^0.4.5

code:
main() async { final client = OdooClient('http://127.0.0.1:8069'); try { await client.authenticate('odoo17uat', 'admin', 'admin'); print(client); // 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(); }

err:
Unhandled exception:
type 'Null' is not a subtype of type 'int' in type cast
#0 OdooSession.fromSessionInfo (package:odoo_rpc/src/odoo_session.dart:65:37)
#1 OdooClient.authenticate (package:odoo_rpc/src/odoo_client.dart:262:32)

I traced the code, it successfully login, but this sentense throw err:
_sessionId = OdooSession.fromSessionInfo(result['result']);

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.