ionic 访问odoo11之具体业务类api接口

在前面测试通过odoo登录的功能,这次的问题重点是如何访问后台具体的业务类的接口呢?这次就以我们在odoo中安装的lunch模块为例,目标是获取lunch.alert的数据,如下图

具体过程接上次文章,继续完善OdooJsonRpc类的代码,首先是基础代码,这个是需要提供具体的model名称和具体方法,也是是一个很基础的方法,后台的odoo网站会利用类似C#反射的机制调用目标类的方法。

    /**
     * Calls the method of that particular model
     * @param model Model name
     * @param method Method name of particular model
     * @param args Array of fields
     * @param kwargs Object
     */
    public call(model: string, method: string, args: any, kwargs?: any)
    {
        kwargs = kwargs || {};
        let params =
        {
            model: model,
            method: method,
            args: args,
            kwargs: kwargs == false ? {} : kwargs,
            context: this.getContext()
        };
        return this.sendRequest("/web/dataset/call_kw", params);
    }

调用以上基础call方法的几个基本封装函数有如下几个,基本实现了对数据的CRUD功能,当然基本上是针对一条数据的操作

    /**
     * Reads that perticular fields of that particular ID
     * @param model Model Name
     * @param id Id of that record which you want to read
     * @param mArgs Array of fields which you want to read of the particular id
     */

    public read(model: string, id: number, mArgs: any): Promise<any>
    {
        let args =
        [
            id, [mArgs]
        ]
        return this.call(model, 'read', args)
    }

    /**
     * Provide the name that you want to search
     * @param model Model name
     * @param name Name that you want to search
     */
    public nameSearch(model: string, name: string): Promise<any>
    {
        let kwargs =
        {
            name: name,
            args: [],
            operator: "ilike",
            limit: 0
        }
        return this.call(model, 'name_search', [], kwargs)
    }

    /**
     * Provide the IDs and you will get the names of that paticular IDs
     * @param model Model name
     * @param mArgs Array of IDs that you want to pass
     */
    public nameGet(model: string, mArgs: any): Promise<any>
    {
        let args = [mArgs]
        return this.call(model, 'name_get', args)
    }

    /**
     * Create a new record
     * @param model Model name
     * @param mArgs Object of fields and value
     */
    public createRecord(model: string, mArgs: any)
    {
        let args = [mArgs];
        return this.call(model, "create", args, null)
    }

    /**
     * Delete the record of particular ID
     * @param model Model Name
     * @param id Id of record that you want to delete
     */
    public deleteRecord(model: string, id: number)
    {
        let mArgs = [id]
        return this.call(model, "unlink", mArgs, null)
    }

    /**
     * Updates the record of particular ID
     * @param model Model Name
     * @param id Id of record that you want to update the.
     * @param mArgs The Object of fields and value that you want to update
     *              (e.g)
     *              let args = {
     *                 "name": "Mtfa"
     *              }
     */
    public updateRecord(model: string, id: number, mArgs: any)
    {
        let args =
        [
            [id], mArgs
        ]
        return this.call(model, "write", args, null)
    }

针对单条数据的读取,这里还有另外一种方法,类似上面的read函数

    /**
     * Loads all data of the paricular ID
     * @param model Model name
     * @param id Id of that particular data which you want to load
     */
    public load(model: string, id: number): Promise<any>
    {
        let params =
        {
            model: model,
            id: id,
            fields: [],
            context: this.getContext()
        }
        return this.sendRequest("/web/dataset/load", params)
    }

还有对odoo多条件查询的情况,尤其还有分页的问题,这里也有这样一个很实用的分页查询的方法,这个在日后app的开发中会经常用到

    /**
     * Fires query in particular model with fields and conditions
     * @param model Model name
     * @param domain Conditions that you want to fire on your query
     *              (e.g) let domain = [
     *                         ["id","=",11]
     *                    ]
     * @param fields Fields names which you want to bring from server
     *              (e.g) let fields = [
     *                         ["id","name","email"]
     *                    ]
     * @param limit limit of the record
     * @param offset
     * @param sort sorting order of data (e.g) let sort = "ascending"
     */
    public searchRead(model: string, domain: any, fields: any, limit: number, offset: any, sort: string)
    {
        let params =
        {
            model: model,
            fields: fields,
            domain: domain,
            offset: offset,
            limit: limit,
            sort: sort,
            context: this.getContext()
        };
        return this.sendRequest("/web/dataset/search_read", params);
    }

到此,访问odoo具体业务类的OdooJsonRpc类封装完毕,完整的代码在这里。接下来怎么获取我们的lunch.alert数据呢??

首先定义我们访问odoo业务类的成员变量,这里我们的model类是lunch.alert,需要获取的字段是message和id,其他参数我们暂使用默认的值

    private lunchAlert = "lunch.alert";
    private fields = ["message", "id"];
    private domain = []
    private sort = ""
    private limit = 0
    private offset = 0
    private items: Array<{ id: number, message: string }> = []

第二步是,与odoo后台网站交互获取数据的过程

    private TestMyOdooModel()
    {
            this.odooRpc.searchRead(this.lunchAlert,this.domain, this.fields, this.limit, this.offset,this.sort)
            .then((lunchAlerts: any) =>
            {
                let json = JSON.parse(lunchAlerts._body);
                if (!json.error)
                {
                    let query = json["result"].records
                    for (let i in query)
                    {
                        this.items.push
                        ({
                            id: query[i].id,
                            message: query[i].message
                        })
                    }
                    this.utils.presentAlert("Lunch Message", this.items[0].message,[{text: "Ok"}])
                }
                else
                {
                    this.utils.presentAlert("LunchAlert", "Parse lunch alert error",[{text: "Ok"}])
                }
            })
    }

如果正确获取数据,我们会弹出第一条数据对应的message.

编译打包成*.apk,在手机上测试,确实成功了,如下图所示。

由于这些都是测试阶段的代码,将来可能会改变,现阶段把这些代码全部放在这里。

测试部分的Page页面odooLogin.ts

import { Component } from '@angular/core';
import {
          AlertController,
          IonicPage,
          Loading,
          LoadingController,
          NavController,
          NavParams
        } from 'ionic-angular';
import { OdooJsonRpc } from '../../../../providers/baseService/Odoojsonrpc';
import { Utils } from "../../../../providers/baseService/Utils";

@IonicPage()
@Component
({
    selector: 'page-odooLogin',
    templateUrl: 'odooLogin.html',
})

export class OdooLoginPage
{
    private listForProtocol: Array<{ protocol: string}> = []
    public perfectUrl: boolean = false
    public odooUrl
    public selectedProtocol
    private dbList: Array<{ dbName: string}> = []
    private selectedDatabase
    private email
    private password

    constructor(public navCtrl: NavController,
                private alert: AlertController, public navParams: NavParams,
                private odooRpc: OdooJsonRpc, private loadingCtrl: LoadingController,
                private utils: Utils)
    {
        this.listForProtocol.push({ protocol: "http" })
        this.listForProtocol.push({protocol: "https"})
    }

    public checkUrl()
    {
        this.utils.presentLoading("Please Wait")
        this.odooRpc.init
        ({
            odoo_server: this.selectedProtocol + "://" + this.odooUrl
            //http_auth: 'username:password' // optional
        })

        this.odooRpc.getDbList().then((dbList: any) =>
        {
            console.log(dbList)
            this.perfectUrl = true
            this.utils.dismissLoading()
            this.fillData(dbList)
        }).
        catch((err: any) =>
        {
          console.log(err)
          this.utils.presentAlert("Error", "You Entered a wrong Odoo URL",
          [{
            text: "Ok"
          }])
          this.utils.dismissLoading()
        });
    }

    public fillData(res: any)
    {
        let body = JSON.parse(res._body)
        let json = body['result'];
        this.dbList.length = 0;
        for (var key in json)
        {
            this.dbList.push({ dbName: json[key] });
        }
    }

    private login()
    {
          this.utils.presentLoading("Please wait", 0, true)
          this.odooRpc.login(this.selectedDatabase, this.email, this.password)
          .then((res: any) =>
          {
              let logiData: any = JSON.parse(res._body)["result"];
              logiData.password = this.password
              localStorage.setItem("token", JSON.stringify(logiData));
              //this.utils.dismissLoading()
              this.utils.presentAlert("Congratulation", "You login success",[{text: "Ok"}])
              this.TestMyOdooModel()
          }).
          catch((err) =>
          {
              this.utils.presentAlert("Error", "Username or password must be incorrect",
              [{
                text: "Ok"
              }])
          });
    }


    private lunchAlert = "lunch.alert";
    private fields = ["message", "id"];
    private domain = []
    private sort = ""
    private limit = 0
    private offset = 0
    private items: Array<{ id: number, message: string }> = []

    private TestMyOdooModel()
    {
            this.odooRpc.searchRead(this.lunchAlert,this.domain, this.fields, this.limit, this.offset,this.sort)
            .then((lunchAlerts: any) =>
            {
                let json = JSON.parse(lunchAlerts._body);
                if (!json.error)
                {
                    let query = json["result"].records
                    for (let i in query)
                    {
                        this.items.push
                        ({
                            id: query[i].id,
                            message: query[i].message
                        })
                    }
                    this.utils.presentAlert("Lunch Message", this.items[0].message,[{text: "Ok"}])
                }
                else
                {
                    this.utils.presentAlert("LunchAlert", "Parse lunch alert error",[{text: "Ok"}])
                }
            })
    }
}
View Code

页面布局部分odooLogin.html

<ion-content class="background">
  <ion-card>
    <ion-card-content>

      <div class="spacer" style="height: 10px;"></div>
      <ion-item>
        <ion-label style="color: #fff">Select Protocol</ion-label>
        <ion-select [(ngModel)]="selectedProtocol" style="color: #fff" name="dbNames">
          <ion-option *ngFor="let item of listForProtocol" value="{{item.protocol}}">{{item.protocol}}</ion-option>
        </ion-select>
      </ion-item>
      <div class="spacer" style="height: 10px;"></div>
      <ion-item>
        <ion-input [(ngModel)]="odooUrl" type="url" name="odooUrl" placeholder="Odoo Url"></ion-input>
      </ion-item>
      <div class="spacer" style="height: 10px;"></div>
      <button ion-button block round outline color="light" (click)="checkUrl()" text-center>
        Check Url
        <ion-icon name="md-arrow-round-forward"></ion-icon>
      </button>
      <div [hidden]="!perfectUrl">
        <form (ngSubmit)="login()" #registerForm="ngForm">
          <div class="spacer" style="height: 10px;"></div>
          <ion-item>
            <ion-input type="email" [(ngModel)]="email" name="email" placeholder="Email" required></ion-input>
          </ion-item>
          <div class="spacer" style="height: 5px;"></div>
          <ion-item>
            <ion-input type="password" [(ngModel)]="password" name="pass" placeholder="Password" required></ion-input>
          </ion-item>
          <div class="spacer" style="height: 10px;"></div>
          <div class="spacer" style="height: 10px;"></div>
          <ion-item>
            <ion-label style="color: #fff">Select Database</ion-label>
            <ion-select [(ngModel)]="selectedDatabase" name="selectDatabase" style="color: #fff" required>
              <ion-option *ngFor="let item of dbList" value="{{item.dbName}}">{{item.dbName}}</ion-option>
            </ion-select>
          </ion-item>
          <button ion-button block round outline color="light" [disabled]="!registerForm.form.valid" (click)="signin()">Login</button>
        </form>
      </div>
    </ion-card-content>
  </ion-card>
</ion-content
View Code

CSS效果部分odooLogin.scss

page-odooLogin {
    .background {
        height: 100%;
         100%;
        background-size: cover !important;
        background-position: center center !important;
        background-image: url('../assets/imgs/mountain.jpg')
    }

    ion-card.card {
        margin-top: 30%;
        box-shadow: none;
        background: rgba(0, 0, 0, 0.5);
        border-radius: 5px;
    }
    a, p,
    ion-card-header.card-header {
        color: #fff!important;
    }

    .list > .item-block:first-child {
        border: medium none;
    }

    .item {
        margin-bottom: 10px;
        background: rgba(255, 255, 255, 0.5);
        border: medium none;

        .text-input, {
            color: #fff;
        }


        input::-moz-placeholder{
            color: #fff!important;
        }
        input:-moz-placeholder {
            color: #fff!important;
        }
        *:-moz-placeholder{
            color: #fff!important;
        }
        *:-ms-input-placeholder{
            color: #fff!important;
        }
        *::-webkit-input-placeholder{
            color: #fff!important;
        }
    }
}
View Code

OdooJsonRpc部分Odoojsonrpc.ts

import { Injectable } from '@angular/core';
import 'rxjs/add/operator/toPromise';
import 'rxjs/Rx';

import { Headers, Http } from '@angular/http';
import { Utils } from './Utils';

@Injectable()
export class OdooJsonRpc
{
    private jsonRpcID: number = 0;
    private headers: Headers;
    private odoo_server: string;
    private http_auth: string;
    private list = "/web/database/list";
    private get_list = "/web/database/get_list";
    private jsonrpc = "/jsonrpc";

    constructor(private http: Http, private utils: Utils)
    {
        this.http = http;
    }

    /**
     * Builds a request for odoo server
     * @param url Odoo Server URL
     * @param params Object
     */
    private buildRequest(url: String, params: any)
    {
        this.jsonRpcID += 1;
        return JSON.stringify
        ({
            jsonrpc: "2.0",
            method: "call",
            id: this.jsonRpcID,
            params: params,
        });
    }

    /**
     * Returns the error message
     * @param response Error response from server
     */
    public handleOdooErrors(response: any)
    {
        let err: string = response.error.data.message
        let msg = err.split("
")
        let errMsg = msg[0]

        this.utils.presentAlert("Error", errMsg, [{
            text: "Ok",
            role: "cancel"
        }])
    }

    /**
     * Handles HTTP errors
     */
    public handleHttpErrors(error: any)
    {
        return Promise.reject(error.message || error);
    }

    /**
     * Sends a JSON request to the odoo server
     * @param url Url of odoo
     * @param params Object
     */
    public sendRequest(url: string, params: Object): Promise<any>
    {
        let options = this.buildRequest(url, params);
        this.headers = new Headers({
            'Content-Type': 'application/json; charset=utf-8',
        });

        let result = this.http.post(this.odoo_server + url, options, { headers: this.headers })
            .toPromise()
        return result;
    }

    public init(configs: any)
    {
        this.odoo_server = configs.odoo_server;
        this.http_auth = configs.http_auth || null;
    }

    public setOdooServer(odoo_server: string)
    {
        this.odoo_server = odoo_server;
    }


    public setHttpAuth(http_auth: string)
    {
        this.http_auth = http_auth;
    }

    /**
     * Gets the server info
     */
    public getServerInfo()
    {
        return this.sendRequest("/web/webclient/version_info", {});
    }


    /**
     * Gets the session info
     */
    public getSessionInfo()
    {
        return this.sendRequest("/web/session/get_session_info", {});
    }


    /**
     * Gets the Odoo Server Version Number
     */
    public getServerVersionNumber(): Promise<number>
    {
        return this.getServerInfo().then((res: any): Promise<number> =>
        {
            return new Promise<number>((resolve) =>
            {
                resolve(JSON.parse(res._body)["result"]["server_version_info"][0]);
            });
        });
    }

    /**
     * Get the database list
     */
    public getDbList(): Promise<string>
    {
        let dbParams =
        {
            context: {}
        }
        return this.getServerVersionNumber().then((data: number) =>
        {
            if (data <= 8)
            {
                return this.sendRequest(this.get_list, dbParams);
            }
            else if (data == 9)
            {
                return this.sendRequest(this.jsonrpc, dbParams);
            }
            else
            {
                return this.sendRequest(this.list, dbParams);
            }
        })
    }

    /**
     * Returns all modules that are installed in your database
     */
    public modules(): Promise<string>
    {
        let params =
        {
            context: {}
        }
        return this.sendRequest("/web/session/modules", params)
    }


    /**
     * Login to the database
     * @param db Database name of odoo
     * @param login Username
     * @param password password
     */
    public login(db: string, login: string, password: string)
    {
        let params =
        {
            db: db,
            login: login,
            password: password,
            base_location: this.odoo_server,
            context: {}
        };
        return this.sendRequest("/web/session/authenticate", params)
    }

    /**
     * Check whether the session is live or not
     */
    public check(): Promise<string>
    {
        let params =
        {
            context: this.getContext()
        }
        return this.sendRequest("/web/session/check", params)
    }


    /**
     * Destroy the session
     */
    public destroy()
    {
        let params =
        {
            context: {}
        }
        return this.sendRequest("/web/session/destroy", params)
    }


    /**
     * Fires query in particular model with fields and conditions
     * @param model Model name
     * @param domain Conditions that you want to fire on your query
     *              (e.g) let domain = [
     *                         ["id","=",11]
     *                    ]
     * @param fields Fields names which you want to bring from server
     *              (e.g) let fields = [
     *                         ["id","name","email"]
     *                    ]
     * @param limit limit of the record
     * @param offset
     * @param sort sorting order of data (e.g) let sort = "ascending"
     */
    public searchRead(model: string, domain: any, fields: any, limit: number, offset: any, sort: string)
    {
        let params =
        {
            model: model,
            fields: fields,
            domain: domain,
            offset: offset,
            limit: limit,
            sort: sort,
            context: this.getContext()
        };
        return this.sendRequest("/web/dataset/search_read", params);
    }


    /**
     * Calls the method of that particular model
     * @param model Model name
     * @param method Method name of particular model
     * @param args Array of fields
     * @param kwargs Object
     */
    public call(model: string, method: string, args: any, kwargs?: any)
    {

        kwargs = kwargs || {};
        let params =
        {
            model: model,
            method: method,
            args: args,
            kwargs: kwargs == false ? {} : kwargs,
            context: this.getContext()
        };
        return this.sendRequest("/web/dataset/call_kw", params);
    }


    /**
     * Reads that perticular fields of that particular ID
     * @param model Model Name
     * @param id Id of that record which you want to read
     * @param mArgs Array of fields which you want to read of the particular id
     */

    public read(model: string, id: number, mArgs: any): Promise<any>
    {
        let args =
        [
            id, [mArgs]
        ]
        return this.call(model, 'read', args)
    }


    /**
     * Loads all data of the paricular ID
     * @param model Model name
     * @param id Id of that particular data which you want to load
     */
    public load(model: string, id: number): Promise<any>
    {
        let params =
        {
            model: model,
            id: id,
            fields: [],
            context: this.getContext()
        }
        return this.sendRequest("/web/dataset/load", params)
    }


    /**
     * Provide the name that you want to search
     * @param model Model name
     * @param name Name that you want to search
     */
    public nameSearch(model: string, name: string): Promise<any>
    {
        let kwargs =
        {
            name: name,
            args: [],
            operator: "ilike",
            limit: 0
        }
        return this.call(model, 'name_search', [], kwargs)
    }


    /**
     * Provide the IDs and you will get the names of that paticular IDs
     * @param model Model name
     * @param mArgs Array of IDs that you want to pass
     */
    public nameGet(model: string, mArgs: any): Promise<any>
    {
        let args = [mArgs]
        return this.call(model, 'name_get', args)
    }

    /**
     * Create a new record
     * @param model Model name
     * @param mArgs Object of fields and value
     */
    public createRecord(model: string, mArgs: any)
    {
        let args = [mArgs];
        return this.call(model, "create", args, null)
    }



    /**
     * Delete the record of particular ID
     * @param model Model Name
     * @param id Id of record that you want to delete
     */
    public deleteRecord(model: string, id: number)
    {
        let mArgs = [id]
        return this.call(model, "unlink", mArgs, null)
    }


    /**
     * Updates the record of particular ID
     * @param model Model Name
     * @param id Id of record that you want to update the.
     * @param mArgs The Object of fields and value that you want to update
     *              (e.g)
     *              let args = {
     *                 "name": "Mtfa"
     *              }
     */
    public updateRecord(model: string, id: number, mArgs: any)
    {
        let args =
        [
            [id], mArgs
        ]
        return this.call(model, "write", args, null)
    }

    /**
     * Get the User Context from the response of odoo server
     */
    private getContext()
    {
        let response = localStorage.getItem("token");
        let jsonData = JSON.parse(response);
        let context = jsonData["user_context"];
        return context;
    }
}
View Code

通用类Utils.ts

import { Injectable } from "@angular/core";
import
{
    AlertController, Loading,
    LoadingController, Toast, ToastController,
    ActionSheetController
} from "ionic-angular";

@Injectable()
export class Utils
{
    private loading: Loading

    constructor(private alrtCtrl: AlertController,
        private loadingCtrl: LoadingController,
        private toastCtrl: ToastController,
        private actionSheetCtrl: ActionSheetController)
    {

    }

    public presentAlert(title: string,
        message: string,
        buttons: [{}],
        subtitle?: string,
        enableBackdropDismiss?: boolean,
        inputs?: [{}]): void
    {

        let alrt = this.alrtCtrl.create
        ({
            title: title,
            subTitle: subtitle,
            message: message,
            buttons: buttons,
            enableBackdropDismiss: enableBackdropDismiss,
            inputs: inputs
        })

        alrt.present()
    }

    public presentToast(message: string, duration?: number,
        dissmissOnPageChange?: boolean,
        position?: string,
        showCloseButton?: boolean,
        closeButtonText?: string): void
    {
        let toast = this.toastCtrl.create
        ({
            message: message,
            position: position,
            dismissOnPageChange: dissmissOnPageChange,
            duration: duration,
            showCloseButton: showCloseButton,
            closeButtonText: closeButtonText
        })
        toast.present()
    }

    public presentLoading(content: string, duration?: number,
        dissmissOnPageChange?: boolean,
        enableBackDropDismiss?: boolean,
        showBackDrop?: boolean,
        spinner?: string): void
    {
        this.loading = this.loadingCtrl.create
        ({
            content: content,
            dismissOnPageChange: dissmissOnPageChange,
            duration: duration,
            enableBackdropDismiss: enableBackDropDismiss,
            showBackdrop: showBackDrop,
            spinner: spinner
        })
        this.loading.present()
    }

    public dismissLoading(): void
    {
        this.loading.dismiss()
    }

    public presentActionSheet(buttons: [{}], title: string, subtitle?: string,
        enableBackdropDismiss?: boolean): void
    {
        let actionCtrl = this.actionSheetCtrl.create
        ({
            buttons: buttons,
            subTitle: subtitle,
            title: title,
            enableBackdropDismiss: enableBackdropDismiss
        })
        actionCtrl.present()
    }
}
View Code
原文地址:https://www.cnblogs.com/crazyguo/p/8558054.html