[REF] stock_landed_costs: create from vendor bill

Add a many2one on the landed cost to the vendor bill. Allow to create a
landed cost from a vendor bill if the product is a service. It will use
the price_subtotal of the account move line. Add a is_landed_costs_line
to separate products of landed costs on the account move line. It's a
checkbox. Ticking the checkbox will change the account of the account
move if the company is in anglo saxon accounting.

Tweak the accounts used by the landed costs so that everything is well
balanced (see the added tests). Auto reconcile AML when possible.

task-59011
This commit is contained in:
Simon Lejeune
2019-08-07 14:11:21 +00:00
parent 24bca8fd4a
commit 90c055cd35
9 changed files with 435 additions and 35 deletions
@@ -8,6 +8,44 @@ from odoo.fields import Datetime
from odoo.tests.common import Form, SavepointCase
def _create_accounting_data(env):
"""Create the accounts and journals used in stock valuation.
:param env: environment used to create the records
:return: an input account, an output account, a valuation account, an expense account, a stock journal
"""
stock_input_account = env['account.account'].create({
'name': 'Stock Input',
'code': 'StockIn',
'user_type_id': env.ref('account.data_account_type_current_assets').id,
'reconcile': True,
})
stock_output_account = env['account.account'].create({
'name': 'Stock Output',
'code': 'StockOut',
'user_type_id': env.ref('account.data_account_type_current_assets').id,
'reconcile': True,
})
stock_valuation_account = env['account.account'].create({
'name': 'Stock Valuation',
'code': 'Stock Valuation',
'user_type_id': env.ref('account.data_account_type_current_assets').id,
'reconcile': True,
})
expense_account = env['account.account'].create({
'name': 'Expense Account',
'code': 'Expense Account',
'user_type_id': env.ref('account.data_account_type_expenses').id,
'reconcile': True,
})
stock_journal = env['account.journal'].create({
'name': 'Stock Journal',
'code': 'STJTEST',
'type': 'general',
})
return stock_input_account, stock_output_account, stock_valuation_account, expense_account, stock_journal
class TestStockValuation(SavepointCase):
@classmethod
def setUpClass(cls):
@@ -37,34 +75,9 @@ class TestStockValuation(SavepointCase):
'groups_id': [(6, 0, [cls.env.ref('stock.group_stock_user').id])]
})
cls.stock_input_account, cls.stock_output_account, cls.stock_valuation_account, cls.expense_account, cls.stock_journal = _create_accounting_data(cls.env)
cls.product1.categ_id.property_valuation = 'real_time'
cls.product2.categ_id.property_valuation = 'real_time'
Account = cls.env['account.account']
cls.stock_input_account = Account.create({
'name': 'Stock Input',
'code': 'StockIn',
'user_type_id': cls.env.ref('account.data_account_type_current_assets').id,
})
cls.stock_output_account = Account.create({
'name': 'Stock Output',
'code': 'StockOut',
'user_type_id': cls.env.ref('account.data_account_type_current_assets').id,
})
cls.stock_valuation_account = Account.create({
'name': 'Stock Valuation',
'code': 'Stock Valuation',
'user_type_id': cls.env.ref('account.data_account_type_current_assets').id,
})
cls.expense_account = Account.create({
'name': 'Expense Account',
'code': 'Expense Account',
'user_type_id': cls.env.ref('account.data_account_type_expenses').id,
})
cls.stock_journal = cls.env['account.journal'].create({
'name': 'Stock Journal',
'code': 'STJTEST',
'type': 'general',
})
cls.product1.write({
'property_account_expense_id': cls.expense_account.id,
})
@@ -3,6 +3,7 @@
""" Implementation of "INVENTORY VALUATION TESTS (With valuation layers)" spreadsheet. """
from odoo.addons.stock_account.tests.test_stockvaluation import _create_accounting_data
from odoo.tests import Form, tagged
from odoo.tests.common import SavepointCase, TransactionCase
@@ -709,8 +710,22 @@ class TestStockValuationChangeCostMethod(TestStockValuationCommon):
self.assertEqual(self.product1.quantity_svl, 19)
@tagged('post_install', '-at_install')
class TestStockValuationChangeValuation(TestStockValuationCommon):
@classmethod
def setUpClass(cls):
super(TestStockValuationChangeValuation, cls).setUpClass()
cls.stock_input_account, cls.stock_output_account, cls.stock_valuation_account, cls.expense_account, cls.stock_journal = _create_accounting_data(cls.env)
cls.product1.categ_id.property_valuation = 'real_time'
cls.product1.write({
'property_account_expense_id': cls.expense_account.id,
})
cls.product1.categ_id.write({
'property_stock_account_input_categ_id': cls.stock_input_account.id,
'property_stock_account_output_categ_id': cls.stock_output_account.id,
'property_stock_valuation_account_id': cls.stock_valuation_account.id,
'property_stock_journal': cls.stock_journal.id,
})
def test_standard_manual_to_auto_1(self):
self.product1.product_tmpl_id.categ_id.property_cost_method = 'standard'
self.product1.product_tmpl_id.categ_id.property_valuation = 'manual_periodic'
@@ -743,9 +758,16 @@ class TestStockValuationChangeValuation(TestStockValuationCommon):
self.assertEqual(len(self.product1.stock_valuation_layer_ids.mapped('account_move_id')), 0)
self.assertEqual(len(self.product1.stock_valuation_layer_ids), 1)
cat2 = self.env['product.category'].create({'name': 'fifo'})
cat2 = self.env['product.category'].create({'name': 'standard auto'})
cat2.property_cost_method = 'standard'
cat2.property_valuation = 'real_time'
cat2.write({
'property_stock_account_input_categ_id': self.stock_input_account.id,
'property_stock_account_output_categ_id': self.stock_output_account.id,
'property_stock_valuation_account_id': self.stock_valuation_account.id,
'property_stock_journal': self.stock_journal.id,
})
self.product1.categ_id = cat2
self.assertEqual(self.product1.value_svl, 100)
@@ -19,6 +19,7 @@ This module allows you to easily add extra costs on pickings and decide the spli
'security/ir.model.access.csv',
'security/stock_landed_cost_security.xml',
'data/stock_landed_cost_data.xml',
'views/account_move_views.xml',
'views/product_views.xml',
'views/stock_landed_cost_views.xml',
'views/stock_valuation_layer_views.xml',
@@ -5,5 +5,6 @@ from . import product
from . import res_company
from . import res_config_settings
from . import stock_landed_cost
from . import account_move
from . import stock_valuation_layer
@@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models
class AccountMove(models.Model):
_inherit = 'account.move'
landed_costs_ids = fields.One2many('stock.landed.cost', 'vendor_bill_id', string='Landed Costs')
landed_costs_visible = fields.Boolean(compute='_compute_landed_costs_visible')
@api.depends('line_ids', 'line_ids.is_landed_costs_line')
def _compute_landed_costs_visible(self):
for account_move in self:
if account_move.landed_costs_ids:
account_move.landed_costs_visible = False
else:
account_move.landed_costs_visible = any(line.is_landed_costs_line for line in account_move.line_ids)
def button_create_landed_costs(self):
"""Create a `stock.landed.cost` record associated to the account move of `self`, each
`stock.landed.costs` lines mirroring the current `account.move.line` of self.
"""
self.ensure_one()
landed_costs_lines = self.line_ids.filtered(lambda line: line.is_landed_costs_line)
landed_costs = self.env['stock.landed.cost'].create({
'vendor_bill_id': self.id,
'cost_lines': [(0, 0, {
'product_id': l.product_id.id,
'name': l.product_id.name,
'account_id': l.product_id.product_tmpl_id.get_product_accounts()['stock_input'].id,
'price_unit': l.price_subtotal,
'split_method': 'equal',
}) for l in landed_costs_lines],
})
action = self.env.ref('stock_landed_costs.action_stock_landed_cost').read()[0]
return dict(action, view_mode='form', res_id=landed_costs.id, views=[(False, 'form')])
def action_view_landed_costs(self):
self.ensure_one()
action = self.env.ref('stock_landed_costs.action_stock_landed_cost').read()[0]
domain = [('id', 'in', self.landed_costs_ids.ids)]
context = dict(self.env.context, default_vendor_bill_id=self.id)
views = [(self.env.ref('stock_landed_costs.view_stock_landed_cost_tree2').id, 'tree'), (False, 'form'), (False, 'kanban')]
return dict(action, domain=domain, context=context, views=views)
class AccountMoveLine(models.Model):
_inherit = 'account.move.line'
product_type = fields.Selection(related='product_id.type', readonly=True)
is_landed_costs_line = fields.Boolean()
@api.onchange('is_landed_costs_line')
def _onchange_is_landed_costs_line(self):
"""Mark an invoice line as a landed cost line and adapt `self.account_id`. The default
value can be set according to `self.product_id.landed_cost_ok`."""
if self.product_id:
accounts = self.product_id.product_tmpl_id._get_product_accounts()
if self.product_type != 'service':
self.account_id = accounts['expense']
self.is_landed_costs_line = False
elif self.is_landed_costs_line and self.move_id.company_id.anglo_saxon_accounting:
self.account_id = accounts['stock_input']
else:
self.account_id = accounts['expense']
@api.onchange('product_id')
def _onchange_is_landed_costs_line_product(self):
if self.product_id.landed_cost_ok:
self.is_landed_costs_line = True
else:
self.is_landed_costs_line = False
@@ -118,6 +118,7 @@ class LandedCost(models.Model):
'date': cost.date,
'ref': cost.name,
'line_ids': [],
'type': 'entry',
}
for line in cost.valuation_adjustment_lines.filtered(lambda line: line.move_id):
remaining_qty = sum(line.move_id.stock_valuation_layer_ids.mapped('remaining_qty'))
@@ -155,6 +156,13 @@ class LandedCost(models.Model):
move = move.create(move_vals)
cost.write({'state': 'done', 'account_move_id': move.id})
move.post()
if cost.vendor_bill_id and cost.vendor_bill_id.state == 'posted' and cost.company_id.anglo_saxon_accounting:
all_amls = cost.vendor_bill_id.line_ids | cost.account_move_id.line_ids
for product in cost.cost_lines.product_id:
accounts = product.product_tmpl_id.get_product_accounts()
input_account = accounts['stock_input']
all_amls.filtered(lambda aml: aml.account_id == input_account).reconcile()
return True
def _check_sum(self):
@@ -285,7 +293,8 @@ class LandedCostLine(models.Model):
self.name = self.product_id.name or ''
self.split_method = 'equal'
self.price_unit = self.product_id.standard_price or 0.0
self.account_id = self.product_id.property_account_expense_id.id or self.product_id.categ_id.property_account_expense_categ_id.id
accounts_data = self.product_id.product_tmpl_id.get_product_accounts()
self.account_id = accounts_data['stock_input']
class AdjustmentLines(models.Model):
@@ -341,7 +350,7 @@ class AdjustmentLines(models.Model):
if self.move_id._is_dropshipped():
debit_account_id = accounts.get('expense') and accounts['expense'].id or False
already_out_account_id = accounts['stock_output'].id
credit_account_id = self.cost_line_id.account_id.id or cost_product.property_account_expense_id.id or cost_product.categ_id.property_account_expense_categ_id.id
credit_account_id = self.cost_line_id.account_id.id or cost_product.categ_id.property_stock_account_input_categ_id.id
if not credit_account_id:
raise UserError(_('Please configure Stock Expense Account for product: %s.') % (cost_product.name))
@@ -394,12 +403,12 @@ class AdjustmentLines(models.Model):
AccountMoveLine.append([0, 0, debit_line])
AccountMoveLine.append([0, 0, credit_line])
# TDE FIXME: oh dear
if self.env.company.anglo_saxon_accounting:
expense_account_id = self.product_id.product_tmpl_id.get_product_accounts()['expense'].id
debit_line = dict(base_line,
name=(self.name + ": " + str(qty_out) + _(' already out')),
quantity=0,
account_id=credit_account_id)
account_id=expense_account_id)
credit_line = dict(base_line,
name=(self.name + ": " + str(qty_out) + _(' already out')),
quantity=0,
@@ -5,6 +5,7 @@
from odoo.tests import Form, tagged
from odoo.addons.stock_account.tests.test_stockvaluationlayer import TestStockValuationCommon
from odoo.addons.stock_account.tests.test_stockvaluation import _create_accounting_data
class TestStockValuationLC(TestStockValuationCommon):
@@ -16,11 +17,55 @@ class TestStockValuationLC(TestStockValuationCommon):
'type': 'service',
'categ_id': cls.env.ref('product.product_category_all').id,
})
cls.stock_input_account, cls.stock_output_account, cls.stock_valuation_account, cls.expense_account, cls.stock_journal = _create_accounting_data(cls.env)
cls.product1.write({
'property_account_expense_id': cls.expense_account.id,
})
cls.productlc1.write({
'property_account_expense_id': cls.expense_account.id,
})
cls.product1.categ_id.write({
'property_stock_account_input_categ_id': cls.stock_input_account.id,
'property_stock_account_output_categ_id': cls.stock_output_account.id,
'property_stock_valuation_account_id': cls.stock_valuation_account.id,
'property_stock_journal': cls.stock_journal.id,
})
cls.payable_account = cls.env['account.account'].create({
'name': 'payable',
'code': 'payable',
'user_type_id': cls.env.ref('account.data_account_type_payable').id,
'reconcile': True,
})
def _get_stock_input_move_lines(self):
return self.env['account.move.line'].search([
('account_id', '=', self.stock_input_account.id),
], order='date, id')
def _get_stock_output_move_lines(self):
return self.env['account.move.line'].search([
('account_id', '=', self.stock_output_account.id),
], order='date, id')
def _get_stock_valuation_move_lines(self):
return self.env['account.move.line'].search([
('account_id', '=', self.stock_valuation_account.id),
], order='date, id')
def _get_payable_move_lines(self):
return self.env['account.move.line'].search([
('account_id', '=', self.payable_account.id),
], order='id')
def _get_expense_move_lines(self):
return self.env['account.move.line'].search([
('account_id', '=', self.expense_account.id),
], order='id')
def _make_lc(self, move, amount):
picking = move.picking_id
lc = Form(self.env['stock.landed.cost'])
lc.account_journal_id = self.env['account.journal'].search([('name', 'ilike', '%misc%')], limit=1)
lc.account_journal_id = self.stock_journal
lc.picking_ids.add(move.picking_id)
with lc.cost_lines.new() as cost_line:
cost_line.product_id = self.productlc1
@@ -31,7 +76,6 @@ class TestStockValuationLC(TestStockValuationCommon):
return lc
@tagged('post_install', '-at_install')
class TestStockValuationLCFIFO(TestStockValuationLC):
def setUp(self):
super(TestStockValuationLCFIFO, self).setUp()
@@ -96,7 +140,6 @@ class TestStockValuationLCFIFO(TestStockValuationLC):
self.assertEqual(in_svl.value, 225)
@tagged('post_install', '-at_install')
class TestStockValuationLCAVCO(TestStockValuationLC):
def setUp(self):
super(TestStockValuationLCAVCO, self).setUp()
@@ -137,3 +180,189 @@ class TestStockValuationLCAVCO(TestStockValuationLC):
self.assertEqual(self.product1.value_svl, 375)
self.assertEqual(self.product1.quantity_svl, 19)
class TestStockValuationLCFIFOVB(TestStockValuationLC):
@classmethod
def setUpClass(cls):
super(TestStockValuationLCFIFOVB, cls).setUpClass()
cls.vendor1 = cls.env['res.partner'].search([], limit=1)
cls.vendor1.property_account_payable_id = cls.payable_account
cls.vendor2 = cls.env['res.partner'].search([], limit=2)[-1]
cls.vendor2.property_account_payable_id = cls.payable_account
cls.product1.product_tmpl_id.categ_id.property_cost_method = 'fifo'
cls.product1.product_tmpl_id.categ_id.property_valuation = 'real_time'
def test_vendor_bill_flow_anglo_saxon_1(self):
"""In anglo saxon accounting, receive 10@10 and invoice. Then invoice 1@50 as a landed costs
and create a linked landed costs record.
"""
self.env.company.anglo_saxon_accounting = True
# Create an RFQ for self.product1, 10@10
rfq = Form(self.env['purchase.order'])
rfq.partner_id = self.vendor1
with rfq.order_line.new() as po_line:
po_line.product_id = self.product1
po_line.price_unit = 10
po_line.product_qty = 10
po_line.taxes_id.clear()
rfq = rfq.save()
rfq.button_confirm()
# Process the receipt
receipt = rfq.picking_ids
wiz = receipt.button_validate()
wiz = self.env['stock.immediate.transfer'].browse(wiz['res_id']).process()
self.assertEqual(rfq.order_line.qty_received, 10)
input_aml = self._get_stock_input_move_lines()[-1]
self.assertEqual(input_aml.debit, 0)
self.assertEqual(input_aml.credit, 100)
valuation_aml = self._get_stock_valuation_move_lines()[-1]
self.assertEqual(valuation_aml.debit, 100)
self.assertEqual(valuation_aml.credit, 0)
# Create a vebdor bill for the RFQ
action = rfq.action_view_invoice()
vb = Form(self.env['account.move'].with_context(action['context']))
vb = vb.save()
vb.post()
input_aml = self._get_stock_input_move_lines()[-1]
self.assertEqual(input_aml.debit, 100)
self.assertEqual(input_aml.credit, 0)
payable_aml = self._get_payable_move_lines()[-1]
self.assertEqual(payable_aml.debit, 0)
self.assertEqual(payable_aml.credit, 100)
# Create a vendor bill for a landed cost product, post it and validate a landed cost
# linked to this vendor bill. LC; 1@50
lcvb = Form(self.env['account.move'].with_context(default_type='in_invoice'))
lcvb.partner_id = self.vendor2
with lcvb.invoice_line_ids.new() as inv_line:
inv_line.product_id = self.productlc1
inv_line.price_unit = 50
inv_line.is_landed_costs_line = True
with lcvb.invoice_line_ids.edit(0) as inv_line:
inv_line.tax_ids.clear()
lcvb = lcvb.save()
lcvb.post()
input_aml = self._get_stock_input_move_lines()[-1]
self.assertEqual(input_aml.debit, 50)
self.assertEqual(input_aml.credit, 0)
payable_aml = self._get_payable_move_lines()[-1]
self.assertEqual(payable_aml.debit, 0)
self.assertEqual(payable_aml.credit, 50)
action = lcvb.button_create_landed_costs()
lc = Form(self.env[action['res_model']].browse(action['res_id']))
lc.picking_ids.add(receipt)
lc = lc.save()
lc.button_validate()
self.assertEqual(lc.cost_lines.price_unit, 50)
self.assertEqual(lc.cost_lines.product_id, self.productlc1)
input_aml = self._get_stock_input_move_lines()[-1]
self.assertEqual(input_aml.debit, 0)
self.assertEqual(input_aml.credit, 50)
valuation_aml = self._get_stock_valuation_move_lines()[-1]
self.assertEqual(valuation_aml.debit, 50)
self.assertEqual(valuation_aml.credit, 0)
# Check reconciliation of input aml of lc
lc_input_aml = lc.account_move_id.line_ids.filtered(lambda aml: aml.account_id == self.stock_input_account)
self.assertTrue(len(lc_input_aml.full_reconcile_id), 1)
self.assertEqual(self.product1.quantity_svl, 10)
self.assertEqual(self.product1.value_svl, 150)
def test_vendor_bill_flow_continental_1(self):
"""In continental accounting, receive 10@10 and invoice. Then invoice 1@50 as a landed costs
and create a linked landed costs record.
"""
self.env.company.anglo_saxon_accounting = False
# Create an RFQ for self.product1, 10@10
rfq = Form(self.env['purchase.order'])
rfq.partner_id = self.vendor1
with rfq.order_line.new() as po_line:
po_line.product_id = self.product1
po_line.price_unit = 10
po_line.product_qty = 10
po_line.taxes_id.clear()
rfq = rfq.save()
rfq.button_confirm()
# Process the receipt
receipt = rfq.picking_ids
wiz = receipt.button_validate()
wiz = self.env['stock.immediate.transfer'].browse(wiz['res_id']).process()
self.assertEqual(rfq.order_line.qty_received, 10)
input_aml = self._get_stock_input_move_lines()[-1]
self.assertEqual(input_aml.debit, 0)
self.assertEqual(input_aml.credit, 100)
valuation_aml = self._get_stock_valuation_move_lines()[-1]
self.assertEqual(valuation_aml.debit, 100)
self.assertEqual(valuation_aml.credit, 0)
# Create a vebdor bill for the RFQ
action = rfq.action_view_invoice()
vb = Form(self.env['account.move'].with_context(action['context']))
vb = vb.save()
vb.post()
expense_aml = self._get_expense_move_lines()[-1]
self.assertEqual(expense_aml.debit, 100)
self.assertEqual(expense_aml.credit, 0)
payable_aml = self._get_payable_move_lines()[-1]
self.assertEqual(payable_aml.debit, 0)
self.assertEqual(payable_aml.credit, 100)
# Create a vendor bill for a landed cost product, post it and validate a landed cost
# linked to this vendor bill. LC; 1@50
lcvb = Form(self.env['account.move'].with_context(default_type='in_invoice'))
lcvb.partner_id = self.vendor2
with lcvb.invoice_line_ids.new() as inv_line:
inv_line.product_id = self.productlc1
inv_line.price_unit = 50
inv_line.is_landed_costs_line = True
with lcvb.invoice_line_ids.edit(0) as inv_line:
inv_line.tax_ids.clear()
lcvb = lcvb.save()
lcvb.post()
expense_aml = self._get_expense_move_lines()[-1]
self.assertEqual(expense_aml.debit, 50)
self.assertEqual(expense_aml.credit, 0)
payable_aml = self._get_payable_move_lines()[-1]
self.assertEqual(payable_aml.debit, 0)
self.assertEqual(payable_aml.credit, 50)
action = lcvb.button_create_landed_costs()
lc = Form(self.env[action['res_model']].browse(action['res_id']))
lc.picking_ids.add(receipt)
lc = lc.save()
lc.button_validate()
self.assertEqual(lc.cost_lines.price_unit, 50)
self.assertEqual(lc.cost_lines.product_id, self.productlc1)
input_aml = self._get_stock_input_move_lines()[-1]
self.assertEqual(input_aml.debit, 0)
self.assertEqual(input_aml.credit, 50)
valuation_aml = self._get_stock_valuation_move_lines()[-1]
self.assertEqual(valuation_aml.debit, 50)
self.assertEqual(valuation_aml.credit, 0)
self.assertEqual(self.product1.quantity_svl, 10)
self.assertEqual(self.product1.value_svl, 150)
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="account_view_move_form_inherited" model="ir.ui.view">
<field name="name">account.view.move.form.inherited</field>
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_move_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='button_box']" position="inside">
<field name="landed_costs_ids" invisible="1"/>
<button string="Landed Costs" type="object"
name="action_view_landed_costs"
class="oe_stat_button" icon="fa-plus-square" groups="stock.group_stock_manager"
attrs="{'invisible': [('landed_costs_ids', '=', [])]}" />
</xpath>
<field name="state" position="before">
<field name="landed_costs_visible" invisible="1"/>
<button name="button_create_landed_costs" class="oe_highlight" string="Create Landed Costs" type="object" groups="account.group_account_invoice" attrs="{'invisible': [('landed_costs_visible', '!=', True)]}"/>
</field>
<xpath expr="//field[@name='invoice_line_ids']/tree/field[@name='name']" position="after">
<field name="product_type" invisible="1"/>
<field name="is_landed_costs_line" string="Landed Costs" attrs="{'readonly': [('product_type', '!=', 'service')], 'column_invisible': [('parent.type', '!=', 'in_invoice')]}" optional="show"/>
</xpath>
<xpath expr="//field[@name='line_ids']/tree/field[@name='name']" position="after">
<field name="product_type" invisible="1"/>
<field name="is_landed_costs_line" invisible="1"/>
</xpath>
</field>
</record>
</odoo>
@@ -34,6 +34,7 @@
<label for="account_journal_id" string="Journal"/>
<field name="account_journal_id" nolabel="1"/>
<field name="account_move_id" attrs="{'invisible': [('account_move_id', '=', False)]}"/>
<field name="vendor_bill_id"/>
</group>
</group>
<notebook>
@@ -119,6 +120,22 @@
</field>
</record>
<record id='view_stock_landed_cost_tree2' model='ir.ui.view'>
<field name="name">stock.landed.cost.tree</field>
<field name="model">stock.landed.cost</field>
<field name="priority">1000</field>
<field name="arch" type="xml">
<tree string="Landed Costs">
<field name="name"/>
<field name="date"/>
<field name="currency_id" invisible="1"/>
<field name="amount_total" widget="monetary"/>
<field name="state"/>
<field name="company_id" groups="base.group_multi_company"/>
</tree>
</field>
</record>
<record id='stock_landed_cost_view_kanban' model='ir.ui.view'>
<field name="name">stock.landed.cost.kanban</field>
<field name="model">stock.landed.cost</field>