Odoo の在庫モジュールを JSON-RPC で操作2

前回 の続きで、今回は Odoo の在庫モジュールを JSON-RPC で操作し在庫移動(顧客への出荷)を処理してみます。

ソースは http://github.com/fits/try_samples/tree/master/blog/20200112/

在庫管理

Odoo の画面では在庫移動(顧客への出荷等)を以下のように処理しているようでした。(ステータスは ドラフト -> 待機中 -> 準備完了 -> 完了 のように遷移)

  • (1) stock.picking を create - 作成
  • (2) action_confirm の実行 - 処理準備
  • (3) action_assign の実行 - 利用可能準備(引当)
  • (4) button_validate の実行
  • (5) stock.immediate.transfer の process を実施

ただ、画面処理を前提としたような (4) 以降の処理を API として呼び出すには違和感があります。

そこで、button_validate の処理等を参照して別の方法で処理できないか調べてみたところ、以下のようにしても実現できそうでした。

  • (4') (1) で作られた stock.move.line の qty_done を更新
  • (5') action_done の実行

よって、今回はこの両方を試してみます。

(c) 在庫移動1 - button_validate 実行

まずは、button_validate を呼び出す方を試してみます。 (認証などの処理は前回と同じです)

sample3.js
const axios = require('axios')

・・・

const pickingTypeId = parseInt(process.argv[2])
const locationId = parseInt(process.argv[3])
const locationDestId = parseInt(process.argv[4])
const productId = parseInt(process.argv[5])
const qty = parseInt(process.argv[6])

const main = async () => {
    const auth = ・・・

    const uid = auth.data.result

    // (1) 作成
    const sp1 = await axios.post(url, {
        jsonrpc: '2.0',
        method: 'call',
        id: 'c2',
        params: {
            service: 'object',
            method: 'execute',
            args: [db, uid, password, 'stock.picking', 'create', {
                picking_type_id: pickingTypeId, 
                location_id: locationId, 
                location_dest_id: locationDestId, 
                move_lines: [
                    [0, 0, {
                        name: 'move',
                        product_id: productId,
                        product_uom: 1, 
                        product_uom_qty: qty
                    }]
                ]
            }]
        }
    })

    console.log(sp1.data)

    if (sp1.data.error) {
        return
    }

    const pid = sp1.data.result

    console.log(`id: ${pid}`)

    // (2) 処理準備
    const sp2 = await axios.post(url, {
        jsonrpc: '2.0',
        method: 'call',
        id: 'c3',
        params: {
            service: 'object',
            method: 'execute',
            args: [db, uid, password, 'stock.picking', 'action_confirm', pid]
        }
    })

    console.log(sp2.data)

    if (sp2.data.error) {
        return
    }

    // (3) 利用可能準備(引当)
    const sp3 = await axios.post(url, {
        jsonrpc: '2.0',
        method: 'call',
        id: 'c4',
        params: {
            service: 'object',
            method: 'execute',
            args: [db, uid, password, 'stock.picking', 'action_assign', pid]
        }
    })

    console.log(sp3.data)

    if (sp3.data.error) {
        return
    }

    // (4) 検証(button_validate の実行)
    const sp4 = await axios.post(url, {
        jsonrpc: '2.0',
        method: 'call',
        id: 'c5',
        params: {
            service: 'object',
            method: 'execute',
            args: [db, uid, password, 'stock.picking', 'button_validate', pid]
        }
    })

    console.log(sp4.data)

    if (sp4.data.error) {
        return
    }

    const vld = sp4.data.result

    // (5) stock.immediate.transfer の process を実行
    const res = await axios.post(url, {
        jsonrpc: '2.0',
        method: 'call',
        id: 'c7',
        params: {
            service: 'object',
            method: 'execute',
            args: [db, uid, password, vld.res_model, 'process', vld.res_id]
        }
    })

    console.log(res.data)
}

main().catch(err => console.error(err))

上記を使って、ピッキングタイプ 2(Delivery Orders) で在庫ロケーション 8(WH/Stock) から顧客出荷用のロケーション 5(Partner Locations/Customers) へ商品 19(Large Desk) を 2個移動してみます。

実行
> node sample3.js 2 8 5 19 2

{ jsonrpc: '2.0', id: 'c2', result: 70 }
id: 70
{ jsonrpc: '2.0', id: 'c3', result: true }
{ jsonrpc: '2.0', id: 'c4', result: true }
{
  jsonrpc: '2.0',
  id: 'c5',
  result: {
    name: 'Immediate Transfer?',
    type: 'ir.actions.act_window',
    view_mode: 'form',
    res_model: 'stock.immediate.transfer',
    views: [ [Array] ],
    view_id: 477,
    target: 'new',
    res_id: 8,
    context: {}
  }
}
{ jsonrpc: '2.0', id: 'c7', result: false }

在庫数を確認してみると 100個あった在庫が 98個となっているため、とりあえずは成功しているようです。

在庫数の確認
> node sample1.js 19

・・・
[
  {
    id: 19,
    name: 'Large Desk',
    product_tmpl_id: [ 13, '[E-COM09] Large Desk' ],
    qty_available: 98,
    virtual_available: 98
  }
]

(d) 在庫移動2 - qty_done の更新

次に qty_done を更新する方法も試してみます。

sample4.js
const axios = require('axios')

・・・

const pickingTypeId = parseInt(process.argv[2])
const locationId = parseInt(process.argv[3])
const locationDestId = parseInt(process.argv[4])
const productId = parseInt(process.argv[5])
const qty = parseInt(process.argv[6])

const main = async () => {
    ・・・

    // (3) 利用可能準備(引当)
    const sp3 = await axios.post(url, {
        jsonrpc: '2.0',
        method: 'call',
        id: 'd4',
        params: {
            service: 'object',
            method: 'execute',
            args: [db, uid, password, 'stock.picking', 'action_assign', pid]
        }
    })

    console.log(sp3.data)

    if (sp3.data.error) {
        return
    }

    // move_line_ids の取得
    const pick = await axios.post(url, {
        jsonrpc: '2.0',
        method: 'call',
        id: 'd5',
        params: {
            service: 'object',
            method: 'execute_kw',
            args: [db, uid, password, 'stock.picking', 'read', [pid], {
                fields: ['move_line_ids']
            }]
        }
    })

    console.log(pick.data)

    const lineIds = pick.data.result[0].move_line_ids

    console.log(`move line ids: ${lineIds}`)

    // (4') stock.move.line の qty_done(処理済み在庫数)を更新
    const sml = await axios.post(url, {
        jsonrpc: '2.0',
        method: 'call',
        id: 'd6',
        params: {
            service: 'object',
            method: 'execute_kw',
            args: [
                db, 
                uid, 
                password, 
                'stock.move.line', 
                'write', 
                [ lineIds, { qty_done: qty }],
                {}
            ]
        }
    })

    console.log(sml.data)

    if (sml.data.error) {
        return
    }

    // (5') action_done の実行
    const sp4 = await axios.post(url, {
        jsonrpc: '2.0',
        method: 'call',
        id: 'd7',
        params: {
            service: 'object',
            method: 'execute',
            args: [db, uid, password, 'stock.picking', 'action_done', pid]
        }
    })

    console.log(sp4.data)
}

main().catch(err => console.error(err))

button_validate の時と同じようにピッキングタイプ 2(Delivery Orders) で在庫ロケーション 8(WH/Stock) から顧客出荷用のロケーション 5(Partner Locations/Customers) へ商品 19(Large Desk) を今度は 3個移動してみます。

実行
> node sample4.js 2 8 5 19 3

{ jsonrpc: '2.0', id: 'd2', result: 71 }
id: 71
{ jsonrpc: '2.0', id: 'd3', result: true }
{ jsonrpc: '2.0', id: 'd4', result: true }
{
  jsonrpc: '2.0',
  id: 'd5',
  result: [ { id: 71, move_line_ids: [Array] } ]
}
move line ids: 73
{ jsonrpc: '2.0', id: 'd6', result: true }
{ jsonrpc: '2.0', id: 'd7', result: true }

98個あった在庫が 95個となっているので、こちらも一応は成功しているようです。

在庫確認
> node sample1.js 19

・・・
[
  {
    id: 19,
    name: 'Large Desk',
    product_tmpl_id: [ 13, '[E-COM09] Large Desk' ],
    qty_available: 95,
    virtual_available: 95
  }
]