use crate as odoo_api;
use crate::jsonrpc::{OdooId, OdooIds, OdooOrmMethod};
use odoo_api_macros::odoo_orm;
use serde::ser::SerializeTuple;
use serde::{de, Deserialize, Deserializer, Serialize};
use serde_json::{Map, Value};
use serde_tuple::{Deserialize_tuple, Serialize_tuple};
use std::collections::HashMap;
use std::fmt;
#[odoo_orm(
method = "create",
args = ["values"],
kwargs = [],
)]
#[derive(Debug)]
pub struct Create {
pub database: String,
pub uid: OdooId,
pub password: String,
pub model: String,
pub values: CreateVals,
}
#[derive(Debug, Serialize)]
#[serde(untagged)]
pub enum CreateVals {
One(Map<String, Value>),
Multi(Vec<Value>),
}
impl From<Map<String, Value>> for CreateVals {
fn from(value: Map<String, Value>) -> Self {
Self::One(value)
}
}
impl From<Vec<Value>> for CreateVals {
fn from(value: Vec<Value>) -> Self {
Self::Multi(value)
}
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct CreateResponse {
pub ids: CreateResponseItem,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum CreateResponseItem {
One(OdooId),
Multi(Vec<OdooId>),
}
#[odoo_orm(
method = "read",
args = ["ids"],
kwargs = ["fields"],
)]
#[derive(Debug)]
pub struct Read {
pub database: String,
pub uid: OdooId,
pub password: String,
pub model: String,
pub ids: OdooIds,
pub fields: Vec<String>,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct ReadResponse {
pub data: Vec<Map<String, Value>>,
}
#[odoo_orm(
method = "write",
args = ["ids", "values"],
kwargs = [],
)]
#[derive(Debug)]
pub struct Write {
pub database: String,
pub uid: OdooId,
pub password: String,
pub model: String,
pub ids: OdooIds,
pub values: Map<String, Value>,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct WriteResponse {
pub ok: bool,
}
#[odoo_orm(
method = "unlink",
args = ["ids"],
kwargs = [],
)]
#[derive(Debug)]
pub struct Unlink {
pub database: String,
pub uid: OdooId,
pub password: String,
pub model: String,
pub ids: OdooIds,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct UnlinkResponse {
pub ok: bool,
}
#[odoo_orm(
method = "read_group",
args = ["domain", "fields", "groupby"],
kwargs = ["offset", "limit", "orderby", "lazy"],
)]
#[derive(Debug)]
pub struct ReadGroup {
pub database: String,
pub uid: OdooId,
pub password: String,
pub model: String,
pub domain: Vec<Value>,
pub fields: Vec<String>,
pub groupby: Vec<String>,
pub offset: Option<u32>,
pub limit: Option<u32>,
pub orderby: Option<String>,
pub lazy: bool,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct ReadGroupResponse {
pub result: Vec<Map<String, Value>>,
}
#[odoo_orm(
method = "search_read",
args = [],
kwargs = ["domain", "fields", "offset", "limit", "order"],
)]
#[derive(Debug)]
pub struct SearchRead {
pub database: String,
pub uid: OdooId,
pub password: String,
pub model: String,
pub domain: Vec<Value>,
pub fields: Vec<String>,
pub offset: Option<u32>,
pub limit: Option<u32>,
pub order: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct SearchReadResponse {
pub data: Vec<Map<String, Value>>,
}
#[odoo_orm(
method = "search",
args = ["domain"],
kwargs = ["offset", "limit", "order"],
)]
#[derive(Debug)]
pub struct Search {
pub database: String,
pub uid: OdooId,
pub password: String,
pub model: String,
pub domain: Vec<Value>,
pub offset: Option<u32>,
pub limit: Option<u32>,
pub order: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct SearchResponse {
pub records: Vec<OdooId>,
}
#[odoo_orm(
method = "search_count",
args = ["domain"],
kwargs = ["limit"],
)]
#[derive(Debug)]
pub struct SearchCount {
pub database: String,
pub uid: OdooId,
pub password: String,
pub model: String,
pub domain: Vec<Value>,
pub limit: Option<u32>,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct SearchCountResponse {
pub count: u32,
}
#[odoo_orm(
method = "copy",
args = ["id"],
kwargs = ["default"],
)]
#[derive(Debug)]
pub struct Copy {
pub database: String,
pub uid: OdooId,
pub password: String,
pub model: String,
pub id: OdooId,
pub default: Option<Map<String, Value>>,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct CopyResponse {
pub id: OdooId,
}
#[odoo_orm(
method = "exists",
args = ["ids"],
kwargs = [],
)]
#[derive(Debug)]
pub struct Exists {
pub database: String,
pub uid: OdooId,
pub password: String,
pub model: String,
pub ids: OdooIds,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct ExistsResponse {
pub existing_records: OdooIds,
}
#[derive(Debug, Serialize)]
pub enum AccessOperation {
#[serde(rename = "create")]
Create,
#[serde(rename = "read")]
Read,
#[serde(rename = "write")]
Write,
#[serde(rename = "unlink")]
Unlink,
}
#[odoo_orm(
method = "check_access_rights",
args = ["operation"],
kwargs = ["raise_exception"],
)]
#[derive(Debug)]
pub struct CheckAccessRights {
pub database: String,
pub uid: OdooId,
pub password: String,
pub model: String,
pub operation: AccessOperation,
pub raise_exception: bool,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct CheckAccessRightsResponse {
pub ok: bool,
}
#[odoo_orm(
method = "check_access_rule",
name = "check_access_rules",
args = ["ids", "operation"],
kwargs = [],
)]
#[derive(Debug)]
pub struct CheckAccessRules {
pub database: String,
pub uid: OdooId,
pub password: String,
pub model: String,
pub ids: OdooIds,
pub operation: AccessOperation,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct CheckAccessRulesResponse {}
#[odoo_orm(
method = "check_field_access_rights",
args = ["operation", "fields"],
kwargs = [],
)]
#[derive(Debug)]
pub struct CheckFieldAccessRights {
pub database: String,
pub uid: OdooId,
pub password: String,
pub model: String,
pub operation: AccessOperation,
pub fields: Vec<String>,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct CheckFieldAccessRightsResponse {
pub result: Option<Vec<String>>,
}
#[odoo_orm(
method = "get_metadata",
args = ["ids"],
kwargs = [],
)]
#[derive(Debug)]
pub struct GetMetadata {
pub database: String,
pub uid: OdooId,
pub password: String,
pub model: String,
pub ids: OdooIds,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct GetMetadataResponse {
pub metadata: Vec<Map<String, Value>>,
}
fn get_external_id_deserialize<'de, D>(de: D) -> Result<HashMap<OdooId, String>, D::Error>
where
D: Deserializer<'de>,
{
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = HashMap<OdooId, String>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a map of \"id\": \"external_id\"")
}
fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
where
M: de::MapAccess<'de>,
{
let mut map = HashMap::new();
while let Some((key, value)) = access.next_entry::<String, String>()? {
let key = key.parse().map_err(|_e| {
de::Error::invalid_value(
de::Unexpected::Str(&key),
&"A String representing an i32",
)
})?;
map.insert(key, value);
}
Ok(map)
}
}
de.deserialize_map(Visitor)
}
#[odoo_orm(
method = "get_external_id",
args = ["ids"],
kwargs = [],
)]
#[derive(Debug)]
pub struct GetExternalId {
pub database: String,
pub uid: OdooId,
pub password: String,
pub model: String,
pub ids: OdooIds,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct GetExternalIdResponse {
#[serde(deserialize_with = "get_external_id_deserialize")]
pub external_ids: HashMap<OdooId, String>,
}
#[odoo_orm(
method = "get_xml_id",
args = ["ids"],
kwargs = [],
)]
#[derive(Debug)]
pub struct GetXmlId {
pub database: String,
pub uid: OdooId,
pub password: String,
pub model: String,
pub ids: OdooIds,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct GetXmlIdResponse {
#[serde(deserialize_with = "get_external_id_deserialize")]
pub external_ids: HashMap<OdooId, String>,
}
#[odoo_orm(
method = "name_get",
args = ["ids"],
kwargs = [],
)]
#[derive(Debug)]
pub struct NameGet {
pub database: String,
pub uid: OdooId,
pub password: String,
pub model: String,
pub ids: OdooIds,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct NameGetResponse {
pub display_names: Vec<NameGetResponseItem>,
}
#[derive(Debug, Serialize_tuple, Deserialize_tuple)]
pub struct NameGetResponseItem {
pub id: OdooId,
pub name: String,
}
#[odoo_orm(
method = "name_create",
args = ["name"],
kwargs = [],
)]
#[derive(Debug)]
pub struct NameCreate {
pub database: String,
pub uid: OdooId,
pub password: String,
pub model: String,
pub name: String,
}
#[derive(Debug, Serialize_tuple, Deserialize_tuple)]
pub struct NameCreateResponse {
pub id: OdooId,
pub name: String,
}
#[odoo_orm(
method = "name_search",
args = ["name"],
kwargs = ["args", "operator", "limit"],
)]
#[derive(Debug)]
pub struct NameSearch {
pub database: String,
pub uid: OdooId,
pub password: String,
pub model: String,
pub name: String,
pub args: Option<Vec<Value>>,
pub operator: Option<String>,
pub limit: Option<u32>,
}
#[derive(Debug, Serialize_tuple, Deserialize_tuple)]
#[serde(transparent)]
pub struct NameSearchResponse {
pub records: Vec<NameSearchResponseItem>,
}
#[derive(Debug, Serialize_tuple, Deserialize_tuple)]
pub struct NameSearchResponseItem {
pub id: OdooId,
pub name: String,
}
#[cfg(test)]
mod test {
use super::*;
use crate::client::error::Result;
use crate::jsonrpc::{JsonRpcParams, JsonRpcResponse};
use crate::{jmap, jvec, svec};
use serde_json::{from_value, json, to_value};
#[test]
fn create_one() -> Result<()> {
let expected = json!({
"jsonrpc": "2.0",
"method": "call",
"id": 1000,
"params": {
"service": "object",
"method": "execute_kw",
"args": [
"some-database",
2,
"password",
"res.partner",
"create",
[
{"name": "Hello, world!"}
],
{}
]
}
});
let actual = to_value(
Create {
database: "some-database".into(),
uid: 2,
password: "password".into(),
model: "res.partner".into(),
values: jmap! {"name": "Hello, world!"}.into(),
}
.build(1000),
)?;
assert_eq!(actual, expected);
Ok(())
}
#[test]
fn create_one_response() -> Result<()> {
let payload = json!({
"jsonrpc": "2.0",
"id": 1000,
"result": 47
});
let response: JsonRpcResponse<CreateResponse> = from_value(payload)?;
match response {
JsonRpcResponse::Error(e) => Err(e.error.into()),
JsonRpcResponse::Success(_) => Ok(()),
}
}
#[test]
fn create_multi() -> Result<()> {
let expected = json!({
"jsonrpc": "2.0",
"method": "call",
"id": 1000,
"params": {
"service": "object",
"method": "execute_kw",
"args": [
"some-database",
2,
"password",
"res.partner",
"create",
[
[
{"name": "Hello, world!"},
{"name": "Marco, polo!"}
]
],
{}
]
}
});
let actual = to_value(
Create {
database: "some-database".into(),
uid: 2,
password: "password".into(),
model: "res.partner".into(),
values: jvec![
{"name": "Hello, world!"},
{"name": "Marco, polo!"}
]
.into(),
}
.build(1000),
)?;
assert_eq!(actual, expected);
Ok(())
}
#[test]
fn create_multi_response() -> Result<()> {
let payload = json!({
"jsonrpc": "2.0",
"id": 1000,
"result": [
50,
51
]
});
let response: JsonRpcResponse<CreateResponse> = from_value(payload)?;
match response {
JsonRpcResponse::Error(e) => Err(e.error.into()),
JsonRpcResponse::Success(_) => Ok(()),
}
}
#[test]
fn read() -> Result<()> {
let expected = json!({
"jsonrpc": "2.0",
"method": "call",
"id": 1000,
"params": {
"service": "object",
"method": "execute_kw",
"args": [
"some-database",
2,
"password",
"res.partner",
"read",
[
[1, 2, 3]
],
{
"fields": ["id", "login"]
}
]
}
});
let actual = to_value(
Read {
database: "some-database".into(),
uid: 2,
password: "password".into(),
model: "res.partner".into(),
ids: vec![1, 2, 3].into(),
fields: svec!["id", "login"],
}
.build(1000),
)?;
assert_eq!(actual, expected);
Ok(())
}
#[test]
fn read_response() -> Result<()> {
let payload = json!({
"jsonrpc": "2.0",
"id": 1000,
"result": [
{
"id": 1,
"name": "My Company (San Francisco)"
},
{
"id": 2,
"name": "OdooBot"
},
{
"id": 3,
"name": "Administrator"
}
]
});
let response: JsonRpcResponse<ReadResponse> = from_value(payload)?;
match response {
JsonRpcResponse::Error(e) => Err(e.error.into()),
JsonRpcResponse::Success(_) => Ok(()),
}
}
#[test]
fn write() -> Result<()> {
let expected = json!({
"jsonrpc": "2.0",
"method": "call",
"id": 1000,
"params": {
"service": "object",
"method": "execute_kw",
"args": [
"some-database",
2,
"password",
"res.partner",
"write",
[
[2],
{
"name": "The Admin Account"
}
],
{}
]
}
});
let actual = to_value(
Write {
database: "some-database".into(),
uid: 2,
password: "password".into(),
model: "res.partner".into(),
ids: 2.into(),
values: jmap! {"name": "The Admin Account"},
}
.build(1000),
)?;
assert_eq!(actual, expected);
Ok(())
}
#[test]
fn write_response() -> Result<()> {
let payload = json!({
"jsonrpc": "2.0",
"id": 1000,
"result": true
});
let response: JsonRpcResponse<WriteResponse> = from_value(payload)?;
match response {
JsonRpcResponse::Error(e) => Err(e.error.into()),
JsonRpcResponse::Success(_) => Ok(()),
}
}
#[test]
fn unlink() -> Result<()> {
let expected = json!({
"jsonrpc": "2.0",
"method": "call",
"id": 1000,
"params": {
"service": "object",
"method": "execute_kw",
"args": [
"some-database",
2,
"password",
"res.partner",
"unlink",
[
[3],
],
{}
]
}
});
let actual = to_value(
Unlink {
database: "some-database".into(),
uid: 2,
password: "password".into(),
model: "res.partner".into(),
ids: 3.into(), }
.build(1000),
)?;
assert_eq!(actual, expected);
Ok(())
}
#[test]
fn unlink_response() -> Result<()> {
let payload = json!({
"jsonrpc": "2.0",
"id": 1000,
"result": true
});
let response: JsonRpcResponse<UnlinkResponse> = from_value(payload)?;
match response {
JsonRpcResponse::Error(e) => Err(e.error.into()),
JsonRpcResponse::Success(_) => Ok(()),
}
}
#[test]
fn read_group() -> Result<()> {
let expected = json!({
"jsonrpc": "2.0",
"method": "call",
"id": 1000,
"params": {
"service": "object",
"method": "execute_kw",
"args": [
"some-database",
2,
"password",
"res.partner",
"read_group",
[
[
["id", ">", 0]
],
[
"id",
"name",
"company_type"
],
[
"create_date:month",
"company_id"
]
],
{
"offset": 0,
"limit": 100,
"orderby": "create_date desc",
"lazy": false
}
]
}
});
let actual = to_value(
ReadGroup {
database: "some-database".into(),
uid: 2,
password: "password".into(),
model: "res.partner".into(),
domain: jvec![["id", ">", 0]],
fields: svec!["id", "name", "company_type"],
groupby: svec!["create_date:month", "company_id"],
offset: Some(0),
limit: Some(100),
orderby: Some("create_date desc".into()),
lazy: false,
}
.build(1000),
)?;
assert_eq!(actual, expected);
Ok(())
}
#[test]
fn read_group_response() -> Result<()> {
let payload = json!({
"jsonrpc": "2.0",
"id": 1000,
"result": [
{
"__count": 5,
"create_date:month": "January 2023",
"company_id": false,
"__domain": [
"&",
"&",
"&",
[
"create_date",
">=",
"2023-01-01 00:00:00"
],
[
"create_date",
"<",
"2023-02-01 00:00:00"
],
[
"company_id",
"=",
false
],
[
"id",
">",
0
]
]
},
{
"__count": 1,
"create_date:month": "December 2022",
"company_id": [
1,
"Test!"
],
"__domain": [
"&",
"&",
"&",
[
"create_date",
">=",
"2022-12-01 00:00:00"
],
[
"create_date",
"<",
"2023-01-01 00:00:00"
],
[
"company_id",
"=",
1
],
[
"id",
">",
0
]
]
},
]
});
let response: JsonRpcResponse<ReadGroupResponse> = from_value(payload)?;
match response {
JsonRpcResponse::Error(e) => Err(e.error.into()),
JsonRpcResponse::Success(_) => Ok(()),
}
}
#[test]
fn search_read() -> Result<()> {
let expected = json!({
"jsonrpc": "2.0",
"method": "call",
"id": 1000,
"params": {
"service": "object",
"method": "execute_kw",
"args": [
"some-database",
2,
"password",
"res.partner",
"search_read",
[],
{
"domain": [
["company_type", "=", "company"]
],
"fields": [
"id",
"name",
"company_type"
],
"offset": 0,
"limit": 100,
"order": "create_date desc"
}
]
}
});
let actual = to_value(
SearchRead {
database: "some-database".into(),
uid: 2,
password: "password".into(),
model: "res.partner".into(),
domain: jvec![["company_type", "=", "company"]],
fields: svec!["id", "name", "company_type"],
offset: Some(0),
limit: Some(100),
order: Some("create_date desc".into()),
}
.build(1000),
)?;
assert_eq!(actual, expected);
Ok(())
}
#[test]
fn search_read_response() -> Result<()> {
let payload = json!({
"jsonrpc": "2.0",
"id": 1000,
"result": [
{
"id": 48,
"name": "Partner #1",
"company_type": "person"
},
{
"id": 49,
"name": "Partner #2",
"company_type": "person"
},
]
});
let response: JsonRpcResponse<SearchReadResponse> = from_value(payload)?;
match response {
JsonRpcResponse::Error(e) => Err(e.error.into()),
JsonRpcResponse::Success(_) => Ok(()),
}
}
#[test]
fn search() -> Result<()> {
let expected = json!({
"jsonrpc": "2.0",
"method": "call",
"id": 1000,
"params": {
"service": "object",
"method": "execute_kw",
"args": [
"some-database",
2,
"password",
"res.partner",
"search",
[
[
["company_type", "=", "company"]
]
],
{
"offset": 0,
"limit": 100,
"order": "create_date desc"
}
]
}
});
let actual = to_value(
Search {
database: "some-database".into(),
uid: 2,
password: "password".into(),
model: "res.partner".into(),
domain: jvec![["company_type", "=", "company"]],
offset: Some(0),
limit: Some(100),
order: Some("create_date desc".into()),
}
.build(1000),
)?;
assert_eq!(actual, expected);
Ok(())
}
#[test]
fn search_response() -> Result<()> {
let payload = json!({
"jsonrpc": "2.0",
"id": 1000,
"result": [
48,
49,
47,
45,
44,
]
});
let response: JsonRpcResponse<SearchResponse> = from_value(payload)?;
match response {
JsonRpcResponse::Error(e) => Err(e.error.into()),
JsonRpcResponse::Success(_) => Ok(()),
}
}
#[test]
fn search_count() -> Result<()> {
let expected = json!({
"jsonrpc": "2.0",
"method": "call",
"id": 1000,
"params": {
"service": "object",
"method": "execute_kw",
"args": [
"some-database",
2,
"password",
"res.partner",
"search_count",
[
[
["company_type", "=", "company"]
]
],
{
"limit": null
}
]
}
});
let actual = to_value(
SearchCount {
database: "some-database".into(),
uid: 2,
password: "password".into(),
model: "res.partner".into(),
domain: jvec![["company_type", "=", "company"]],
limit: None,
}
.build(1000),
)?;
assert_eq!(actual, expected);
Ok(())
}
#[test]
fn search_count_response() -> Result<()> {
let payload = json!({
"jsonrpc": "2.0",
"id": 1000,
"result": 46
});
let response: JsonRpcResponse<SearchCountResponse> = from_value(payload)?;
match response {
JsonRpcResponse::Error(e) => Err(e.error.into()),
JsonRpcResponse::Success(_) => Ok(()),
}
}
#[test]
fn copy() -> Result<()> {
let expected = json!({
"jsonrpc": "2.0",
"method": "call",
"id": 1000,
"params": {
"service": "object",
"method": "execute_kw",
"args": [
"some-database",
2,
"password",
"res.partner",
"copy",
[
2
],
{
"default": null
}
]
}
});
let actual = to_value(
Copy {
database: "some-database".into(),
uid: 2,
password: "password".into(),
model: "res.partner".into(),
id: 2,
default: None,
}
.build(1000),
)?;
assert_eq!(actual, expected);
Ok(())
}
#[test]
fn copy_response() -> Result<()> {
let payload = json!({
"jsonrpc": "2.0",
"id": 1000,
"result": 54
});
let response: JsonRpcResponse<CopyResponse> = from_value(payload)?;
match response {
JsonRpcResponse::Error(e) => Err(e.error.into()),
JsonRpcResponse::Success(_) => Ok(()),
}
}
#[test]
fn exists() -> Result<()> {
let expected = json!({
"jsonrpc": "2.0",
"method": "call",
"id": 1000,
"params": {
"service": "object",
"method": "execute_kw",
"args": [
"some-database",
2,
"password",
"res.partner",
"exists",
[
[1, 2, -1, 999999999]
],
{
}
]
}
});
let actual = to_value(
Exists {
database: "some-database".into(),
uid: 2,
password: "password".into(),
model: "res.partner".into(),
ids: vec![1, 2, -1, 999999999].into(),
}
.build(1000),
)?;
assert_eq!(actual, expected);
Ok(())
}
#[test]
fn exists_response() -> Result<()> {
let payload = json!({
"jsonrpc": "2.0",
"id": 1000,
"result": [
1,
2
]
});
let response: JsonRpcResponse<ExistsResponse> = from_value(payload)?;
match response {
JsonRpcResponse::Error(e) => Err(e.error.into()),
JsonRpcResponse::Success(_) => Ok(()),
}
}
#[test]
fn check_access_rights() -> Result<()> {
let expected = json!({
"jsonrpc": "2.0",
"method": "call",
"id": 1000,
"params": {
"service": "object",
"method": "execute_kw",
"args": [
"some-database",
2,
"password",
"stock.quant",
"check_access_rights",
[
"unlink"
],
{
"raise_exception": false
}
]
}
});
let actual = to_value(
CheckAccessRights {
database: "some-database".into(),
uid: 2,
password: "password".into(),
model: "stock.quant".into(),
operation: AccessOperation::Unlink,
raise_exception: false,
}
.build(1000),
)?;
assert_eq!(actual, expected);
Ok(())
}
#[test]
fn check_access_rights_response() -> Result<()> {
let payload = json!({
"jsonrpc": "2.0",
"id": 1000,
"result": false
});
let response: JsonRpcResponse<CheckAccessRightsResponse> = from_value(payload)?;
match response {
JsonRpcResponse::Error(e) => Err(e.error.into()),
JsonRpcResponse::Success(_) => Ok(()),
}
}
#[test]
fn check_access_rules() -> Result<()> {
let expected = json!({
"jsonrpc": "2.0",
"method": "call",
"id": 1000,
"params": {
"service": "object",
"method": "execute_kw",
"args": [
"some-database",
2,
"password",
"res.partner",
"check_access_rule",
[
[1, 2],
"unlink"
],
{
}
]
}
});
let actual = to_value(
CheckAccessRules {
database: "some-database".into(),
uid: 2,
password: "password".into(),
model: "res.partner".into(),
ids: vec![1, 2].into(),
operation: AccessOperation::Unlink,
}
.build(1000),
)?;
assert_eq!(actual, expected);
Ok(())
}
#[test]
fn check_access_rules_response() -> Result<()> {
let payload = json!({
"jsonrpc": "2.0",
"id": 1000,
"result": [
"id",
"email",
"this_is_a_fake_field"
]
});
let response: JsonRpcResponse<CheckAccessRulesResponse> = {
match from_value(payload) {
Ok(d) => d,
Err(_) => {
return Ok(());
}
}
};
match response {
JsonRpcResponse::Error(e) => Err(e.error.into()),
JsonRpcResponse::Success(_) => Ok(()),
}
}
#[test]
fn check_field_access_rights() -> Result<()> {
let expected = json!({
"jsonrpc": "2.0",
"method": "call",
"id": 1000,
"params": {
"service": "object",
"method": "execute_kw",
"args": [
"some-database",
2,
"password",
"res.partner",
"check_field_access_rights",
[
"unlink",
[
"id",
"email",
"this_is_a_fake_field"
]
],
{
}
]
}
});
let actual = to_value(
CheckFieldAccessRights {
database: "some-database".into(),
uid: 2,
password: "password".into(),
model: "res.partner".into(),
operation: AccessOperation::Unlink,
fields: svec!["id", "email", "this_is_a_fake_field"],
}
.build(1000),
)?;
assert_eq!(actual, expected);
Ok(())
}
#[test]
fn check_field_access_rights_response() -> Result<()> {
let payload = json!({
"jsonrpc": "2.0",
"id": 1000,
"result": [
"id",
"email",
"this_is_a_fake_field"
]
});
let response: JsonRpcResponse<CheckFieldAccessRightsResponse> = from_value(payload)?;
match response {
JsonRpcResponse::Error(e) => Err(e.error.into()),
JsonRpcResponse::Success(_) => Ok(()),
}
}
#[test]
fn get_metadata() -> Result<()> {
let expected = json!({
"jsonrpc": "2.0",
"method": "call",
"id": 1000,
"params": {
"service": "object",
"method": "execute_kw",
"args": [
"some-database",
2,
"password",
"res.partner",
"get_metadata",
[
[1, 2]
],
{
}
]
}
});
let actual = to_value(
GetMetadata {
database: "some-database".into(),
uid: 2,
password: "password".into(),
model: "res.partner".into(),
ids: vec![1, 2].into(),
}
.build(1000),
)?;
assert_eq!(actual, expected);
Ok(())
}
#[test]
fn get_metadata_response() -> Result<()> {
let payload = json!({
"jsonrpc": "2.0",
"id": 1000,
"result": [
{
"id": 1,
"create_uid": false,
"create_date": "2022-09-15 20:00:41",
"write_uid": [
2,
"Administrator"
],
"write_date": "2023-01-16 01:17:19",
"xmlid": "base.main_partner",
"noupdate": true
},
{
"id": 2,
"create_uid": [
1,
"OdooBot"
],
"create_date": "2022-09-15 20:00:43",
"write_uid": [
1,
"OdooBot"
],
"write_date": "2023-02-20 22:32:37",
"xmlid": "base.partner_root",
"noupdate": true
}
]
});
let response: JsonRpcResponse<GetMetadataResponse> = from_value(payload)?;
match response {
JsonRpcResponse::Error(e) => Err(e.error.into()),
JsonRpcResponse::Success(_) => Ok(()),
}
}
#[test]
fn get_external_id() -> Result<()> {
let expected = json!({
"jsonrpc": "2.0",
"method": "call",
"id": 1000,
"params": {
"service": "object",
"method": "execute_kw",
"args": [
"some-database",
2,
"password",
"res.partner",
"get_external_id",
[
[1, 2]
],
{
}
]
}
});
let actual = to_value(
GetExternalId {
database: "some-database".into(),
uid: 2,
password: "password".into(),
model: "res.partner".into(),
ids: vec![1, 2].into(),
}
.build(1000),
)?;
assert_eq!(actual, expected);
Ok(())
}
#[test]
fn get_external_id_response() -> Result<()> {
let payload = json!({
"jsonrpc": "2.0",
"id": 1000,
"result": {
"1": "base.main_partner",
"2": "base.partner_root"
}
});
let response: JsonRpcResponse<GetExternalIdResponse> = from_value(payload)?;
match response {
JsonRpcResponse::Error(e) => Err(e.error.into()),
JsonRpcResponse::Success(_) => Ok(()),
}
}
#[test]
fn get_xml_id() -> Result<()> {
let expected = json!({
"jsonrpc": "2.0",
"method": "call",
"id": 1000,
"params": {
"service": "object",
"method": "execute_kw",
"args": [
"some-database",
2,
"password",
"res.partner",
"get_xml_id",
[
[1, 2]
],
{
}
]
}
});
let actual = to_value(
GetXmlId {
database: "some-database".into(),
uid: 2,
password: "password".into(),
model: "res.partner".into(),
ids: vec![1, 2].into(),
}
.build(1000),
)?;
assert_eq!(actual, expected);
Ok(())
}
#[test]
fn get_xml_id_response() -> Result<()> {
let payload = json!({
"jsonrpc": "2.0",
"id": 1000,
"result": {
"1": "base.main_partner",
"2": "base.partner_root"
}
});
let response: JsonRpcResponse<GetXmlIdResponse> = from_value(payload)?;
match response {
JsonRpcResponse::Error(e) => Err(e.error.into()),
JsonRpcResponse::Success(_) => Ok(()),
}
}
#[test]
fn name_get() -> Result<()> {
let expected = json!({
"jsonrpc": "2.0",
"method": "call",
"id": 1000,
"params": {
"service": "object",
"method": "execute_kw",
"args": [
"some-database",
2,
"password",
"res.partner",
"name_get",
[
[1, 2, 3]
],
{
}
]
}
});
let actual = to_value(
NameGet {
database: "some-database".into(),
uid: 2,
password: "password".into(),
model: "res.partner".into(),
ids: vec![1, 2, 3].into(),
}
.build(1000),
)?;
assert_eq!(actual, expected);
Ok(())
}
#[test]
fn name_get_response() -> Result<()> {
let payload = json!({
"jsonrpc": "2.0",
"id": 1000,
"result": [
[
1,
"Test!"
],
[
2,
"OdooBot"
],
[
3,
"YourCompany, Administrator"
]
]
});
let response: JsonRpcResponse<NameGetResponse> = from_value(payload)?;
match response {
JsonRpcResponse::Error(e) => Err(e.error.into()),
JsonRpcResponse::Success(_) => Ok(()),
}
}
#[test]
fn name_create() -> Result<()> {
let expected = json!({
"jsonrpc": "2.0",
"method": "call",
"id": 1000,
"params": {
"service": "object",
"method": "execute_kw",
"args": [
"some-database",
2,
"password",
"res.partner",
"name_create",
[
"I am a test!"
],
{
}
]
}
});
let actual = to_value(
NameCreate {
database: "some-database".into(),
uid: 2,
password: "password".into(),
model: "res.partner".into(),
name: "I am a test!".into(),
}
.build(1000),
)?;
assert_eq!(actual, expected);
Ok(())
}
#[test]
fn name_create_response() -> Result<()> {
let payload = json!({
"jsonrpc": "2.0",
"id": 1000,
"result": [
56,
"I am a test!"
]
});
let response: JsonRpcResponse<NameCreateResponse> = from_value(payload)?;
match response {
JsonRpcResponse::Error(e) => Err(e.error.into()),
JsonRpcResponse::Success(_) => Ok(()),
}
}
#[test]
fn name_search() -> Result<()> {
let expected = json!({
"jsonrpc": "2.0",
"method": "call",
"id": 1000,
"params": {
"service": "object",
"method": "execute_kw",
"args": [
"some-database",
2,
"password",
"res.partner",
"name_search",
[
"I am a test!"
],
{
"args": null,
"operator": null,
"limit": null,
}
]
}
});
let actual = to_value(
NameSearch {
database: "some-database".into(),
uid: 2,
password: "password".into(),
model: "res.partner".into(),
name: "I am a test!".into(),
args: None,
operator: None,
limit: None,
}
.build(1000),
)?;
assert_eq!(actual, expected);
Ok(())
}
#[test]
fn name_search_response() -> Result<()> {
let payload = json!({
"jsonrpc": "2.0",
"id": 1000,
"result": [
[
56,
"I am a test!"
],
[
57,
"I am a test!"
]
]
});
let response: JsonRpcResponse<NameSearchResponse> = from_value(payload)?;
match response {
JsonRpcResponse::Error(e) => Err(e.error.into()),
JsonRpcResponse::Success(_) => Ok(()),
}
}
}