Warehouse-location fusion, WIP.
This commit is contained in:
@@ -24,7 +24,6 @@
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from warehouse import *
|
||||
from location import *
|
||||
from packing import *
|
||||
from move import *
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
'partner', 'product'
|
||||
],
|
||||
'xml': [
|
||||
'warehouse.xml',
|
||||
'location.xml',
|
||||
'move.xml',
|
||||
'packing.xml',
|
||||
|
||||
+23
-13
@@ -2,9 +2,12 @@
|
||||
from trytond.osv import fields, OSV
|
||||
|
||||
STATES = {
|
||||
'readonly': "active == False",
|
||||
'readonly': "not active",
|
||||
}
|
||||
STATES_WH = {
|
||||
'readonly': "(not active) or type != 'warehouse'",
|
||||
'required': "type == 'warehouse' and active",
|
||||
}
|
||||
|
||||
class Location(OSV):
|
||||
"Stock Location"
|
||||
_name = 'stock.location'
|
||||
@@ -13,13 +16,26 @@ class Location(OSV):
|
||||
name = fields.Char("Name", size=64, required=True, states=STATES,)
|
||||
code = fields.Char("Code", size=32, states=STATES, select=True,)
|
||||
active = fields.Boolean('Active', select=True)
|
||||
usage = fields.Selection([('supplier', 'Supplier'),
|
||||
address = fields.Many2One("partner.address", "Address", states=STATES_WH,)
|
||||
type = fields.Selection([('supplier', 'Supplier'),
|
||||
('customer', 'Customer'),
|
||||
('inventory', 'Inventory'),
|
||||
('procurement', 'Procurement'),
|
||||
('warehouse', 'Warehouse'),
|
||||
('storage', 'Storage'),
|
||||
('production', 'Production')],
|
||||
'Location type', states=STATES,)
|
||||
warehouse = fields.Many2One("stock.warehouse", "Warehouse", select="1")
|
||||
parent = fields.Many2One("stock.location", "Parent", select="1")
|
||||
childs = fields.One2Many("stock.location", "parent", "Childs",)
|
||||
input_location = fields.Many2One(
|
||||
"stock.location", "Input", states=STATES_WH,
|
||||
domain="[('type','=','storage')]",)
|
||||
output_location = fields.Many2One(
|
||||
"stock.location", "Output", states=STATES_WH,
|
||||
domain="[('type','=','storage')]",)
|
||||
storage_location = fields.Many2One(
|
||||
"stock.location", "Storage", states=STATES_WH,
|
||||
domain="[('type','=','storage')]")
|
||||
|
||||
# TODO: champ calcule vers product (retournant les product dispo)
|
||||
# + context qui passe la location courante et permet de calculer
|
||||
@@ -28,6 +44,9 @@ class Location(OSV):
|
||||
def default_active(self, cursor, user, context=None):
|
||||
return True
|
||||
|
||||
def default_type(self, cursor, user, context=None):
|
||||
return 'storage'
|
||||
|
||||
def name_search(self, cursor, user, name, args=None, operator='ilike',
|
||||
context=None, limit=80):
|
||||
if not args:
|
||||
@@ -107,12 +126,3 @@ class Location(OSV):
|
||||
|
||||
Location()
|
||||
|
||||
|
||||
class Warehouse(OSV):
|
||||
_name = "stock.warehouse"
|
||||
_inherit = "stock.warehouse"
|
||||
input_location = fields.Many2One("stock.location", "Input location", required=True,)
|
||||
output_location = fields.Many2One("stock.location", "Output location", required=True,)
|
||||
store_location = fields.Many2One("stock.location", "Default store location", required=True,)
|
||||
|
||||
Warehouse()
|
||||
|
||||
+74
-14
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0"?>
|
||||
<tryton>
|
||||
<data>
|
||||
<menuitem name="Inventory Management" sequence="3" id="menu_stock"/>
|
||||
<record model="ir.ui.view" id="location_view_form">
|
||||
<field name="model">stock.location</field>
|
||||
<field name="type">form</field>
|
||||
@@ -11,17 +12,21 @@
|
||||
<field name="name"/>
|
||||
<label name="code"/>
|
||||
<field name="code"/>
|
||||
<label name="usage"/>
|
||||
<field name="usage"/>
|
||||
<label name="parent"/>
|
||||
<field name="parent"/>
|
||||
<label name="active"/>
|
||||
<field name="active"/>
|
||||
<label name="type"/>
|
||||
<field name="type"/>
|
||||
<newline/>
|
||||
<label name="input_zone"/>
|
||||
<field name="input_zone"/>
|
||||
<label name="output_zone"/>
|
||||
<field name="output_zone"/>
|
||||
<label name="warehouse"/>
|
||||
<field name="warehouse"/>
|
||||
<label name="address"/>
|
||||
<field name="address"/>
|
||||
<label name="input_location"/>
|
||||
<field name="input_location"/>
|
||||
<label name="output_location"/>
|
||||
<field name="output_location"/>
|
||||
<label name="storage_location"/>
|
||||
<field name="storage_location"/>
|
||||
</form>
|
||||
]]>
|
||||
</field>
|
||||
@@ -29,23 +34,40 @@
|
||||
<record model="ir.ui.view" id="location_view_tree">
|
||||
<field name="model">stock.location</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="field_childs">childs</field>
|
||||
<field name="arch" type="xml">
|
||||
<![CDATA[
|
||||
<tree string="locations">
|
||||
<field name="name" select="1"/>
|
||||
<field name="code" select="2"/>
|
||||
<field name="usage" select="1"/>
|
||||
<field name="input_zone" select="2"/>
|
||||
<field name="output_zone" select="2"/>
|
||||
<field name="warehouse" select="2"/>
|
||||
<field name="type" select="1"/>
|
||||
<field name="input_location" select="2"/>
|
||||
<field name="output_location" select="2"/>
|
||||
<field name="storage_location" select="2"/>
|
||||
<field name="parent" select="2"/>
|
||||
<field name="active" select="2"/>
|
||||
</tree>
|
||||
]]>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window" id="act_location_form">
|
||||
|
||||
<record model="ir.action.act_window" id="act_location_tree">
|
||||
<field name="name">Locations</field>
|
||||
<field name="res_model">stock.location</field>
|
||||
<field name="view_type">tree</field>
|
||||
<field name="domain">[('parent', '=', False)]</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_location_tree_view">
|
||||
<field name="sequence" eval="10"/>
|
||||
<field name="view" ref="location_view_tree"/>
|
||||
<field name="act_window" ref="act_location_tree"/>
|
||||
</record>
|
||||
<menuitem parent="menu_stock" sequence="1"
|
||||
action="act_location_tree" id="menu_location_tree"/>
|
||||
|
||||
<record model="ir.action.act_window" id="act_location_form">
|
||||
<field name="name">Edit Locations</field>
|
||||
<field name="res_model">stock.location</field>
|
||||
<field name="view_type">form</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_location_form_view1">
|
||||
@@ -58,10 +80,17 @@
|
||||
<field name="view" ref="location_view_form"/>
|
||||
<field name="act_window" ref="act_location_form"/>
|
||||
</record>
|
||||
<menuitem parent="menu_stock" sequence="2"
|
||||
<menuitem parent="menu_location_tree" sequence="1"
|
||||
action="act_location_form" id="menu_location_form"/>
|
||||
|
||||
|
||||
<!-- Model Access -->
|
||||
<record model="res.group" id="group_stock_admin">
|
||||
<field name="name">Stock administration</field>
|
||||
</record>
|
||||
<record model="res.user" id="res.user_admin">
|
||||
<field name="groups" eval="[('add', ref('group_stock_admin'))]"/>
|
||||
</record>
|
||||
<record model="ir.model.access" id="access_location">
|
||||
<field name="model" search="[('model', '=', 'stock.location')]"/>
|
||||
<field name="perm_read" eval="True"/>
|
||||
@@ -78,5 +107,36 @@
|
||||
<field name="perm_unlink" eval="True"/>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- Default locations -->
|
||||
|
||||
<record model="stock.location" id="location_input">
|
||||
<field name="name">Input Zone</field>
|
||||
<field name="code">IN</field>
|
||||
<field name="type">storage</field>
|
||||
</record>
|
||||
<record model="stock.location" id="location_output">
|
||||
<field name="name">Output Zone</field>
|
||||
<field name="code">OUT</field>
|
||||
<field name="type">storage</field>
|
||||
</record>
|
||||
<record model="stock.location" id="location_storage">
|
||||
<field name="name">Storage Zone</field>
|
||||
<field name="code">STO</field>
|
||||
<field name="type">storage</field>
|
||||
</record>
|
||||
<record model="stock.location" id="location_warehouse">
|
||||
<field name="name">Warehouse</field>
|
||||
<field name="code">WH</field>
|
||||
<field name="type">warehouse</field>
|
||||
<field name="input_location" ref="location_input"/>
|
||||
<field name="output_location" ref="location_output"/>
|
||||
<field name="storage_location" ref="location_storage"/>
|
||||
</record>
|
||||
<!-- <record model="stock.location" id="location_storage"> -->
|
||||
<!-- <field name="parent" ref="location_warehouse"/> -->
|
||||
<!-- </record> -->
|
||||
|
||||
|
||||
</data>
|
||||
</tryton>
|
||||
|
||||
@@ -20,12 +20,12 @@ class Move(OSV):
|
||||
quantity = fields.Float(
|
||||
"Quantity", digits=(12, 6), required=True,
|
||||
states=STATES,)
|
||||
from_location =fields.Many2One(
|
||||
from_location = fields.Many2One(
|
||||
"stock.location", "From Location", select=True, required=True,
|
||||
states=STATES,)
|
||||
states=STATES, domain="[('type', '!=', 'warehouse')]",)
|
||||
to_location = fields.Many2One(
|
||||
"stock.location", "To Location", select=True, required=True,
|
||||
states=STATES,)
|
||||
states=STATES,domain="[('type', '!=', 'warehouse')]",)
|
||||
incoming_packing_in = fields.Many2One(
|
||||
"stock.packing.in", "Supplier Packing", states=STATES, select=True)
|
||||
inventory_packing_in = fields.Many2One(
|
||||
@@ -95,59 +95,47 @@ class Move(OSV):
|
||||
return True
|
||||
|
||||
def default_to_location(self, cursor, user, context=None):
|
||||
if context and context.get('wh_incoming'):
|
||||
warehouse = self.pool.get('stock.warehouse').browse(
|
||||
cursor, user, context['wh_incoming'], context=context)
|
||||
return warehouse.input_location.id
|
||||
if context and context.get('wh_inv_out'):
|
||||
warehouse = self.pool.get('stock.warehouse').browse(
|
||||
cursor, user, context['wh_inv_out'], context=context)
|
||||
return warehouse.output_location.id
|
||||
if context and context.get('wh_inv_in'):
|
||||
warehouse = self.pool.get('stock.warehouse').browse(
|
||||
cursor, user, context['wh_inv_in'], context=context)
|
||||
return warehouse.store_location.id
|
||||
return False
|
||||
if context and context.get('warehouse') and context.get('type'):
|
||||
wh_location = self.pool.get('stock.location').browse(
|
||||
cursor, user, context['warehouse'], context=context)
|
||||
field = {'inventory_in': 'storage_location',
|
||||
'inventory_out': 'output_location',
|
||||
'incoming': 'input_location',}.get(context['type'])
|
||||
return field and wh_location[field].id or False
|
||||
|
||||
def default_from_location(self, cursor, user, context=None):
|
||||
if context and context.get('wh_inv_in'):
|
||||
warehouse = self.pool.get('stock.warehouse').browse(
|
||||
cursor, user, context['wh_inv_in'], context=context)
|
||||
return warehouse.input_location.id
|
||||
if context and context.get('wh_outgoing'):
|
||||
warehouse = self.pool.get('stock.warehouse').browse(
|
||||
cursor, user, context['wh_outgoing'], context=context)
|
||||
return warehouse.output_location.id
|
||||
if context and context.get('wh_inv_out'):
|
||||
warehouse = self.pool.get('stock.warehouse').browse(
|
||||
cursor, user, context['wh_inv_out'], context=context)
|
||||
return warehouse.store_location.id
|
||||
return False
|
||||
if context and context.get('warehouse') and context.get('type'):
|
||||
wh_location = self.pool.get('stock.location').browse(
|
||||
cursor, user, context['warehouse'], context=context)
|
||||
field = {'inventory_in': 'input_location',
|
||||
'inventory_out': 'storage_location',
|
||||
'outgoing': 'output_location',}.get(context['type'])
|
||||
return field and wh_location[field].id or False
|
||||
|
||||
def default_state(self, cursor, user, context=None):
|
||||
if not context: return 'draft'
|
||||
if 'pack_incoming_state' in context:
|
||||
if context['pack_incoming_state'] == 'waiting':
|
||||
return 'waiting'
|
||||
if context['pack_incoming_state'] in ('received', 'done'):
|
||||
return 'done'
|
||||
if 'pack_inv_in_state' in context:
|
||||
if context['pack_inv_in_state'] == 'received':
|
||||
return 'waiting'
|
||||
if context['pack_inv_in_state'] == 'done':
|
||||
return 'done'
|
||||
if 'pack_outgoing_state' in context:
|
||||
if context['pack_outgoing_state'] in \
|
||||
('waiting', 'assigned', 'ready'):
|
||||
return 'waiting'
|
||||
if context['pack_outgoing_state'] in 'done':
|
||||
return 'done'
|
||||
if 'pack_inv_out_state' in context:
|
||||
if context['pack_inv_out_state'] == 'assigned':
|
||||
return 'waiting'
|
||||
if context['pack_inv_out_state'] == 'ready':
|
||||
return 'done'
|
||||
|
||||
#TODO
|
||||
# if not context: return 'draft'
|
||||
# if 'pack_incoming_state' in context:
|
||||
# if context['pack_incoming_state'] == 'waiting':
|
||||
# return 'waiting'
|
||||
# if context['pack_incoming_state'] in ('received', 'done'):
|
||||
# return 'done'
|
||||
# if 'pack_inv_in_state' in context:
|
||||
# if context['pack_inv_in_state'] == 'received':
|
||||
# return 'waiting'
|
||||
# if context['pack_inv_in_state'] == 'done':
|
||||
# return 'done'
|
||||
# if 'pack_outgoing_state' in context:
|
||||
# if context['pack_outgoing_state'] in \
|
||||
# ('waiting', 'assigned', 'ready'):
|
||||
# return 'waiting'
|
||||
# if context['pack_outgoing_state'] in 'done':
|
||||
# return 'done'
|
||||
# if 'pack_inv_out_state' in context:
|
||||
# if context['pack_inv_out_state'] == 'assigned':
|
||||
# return 'waiting'
|
||||
# if context['pack_inv_out_state'] == 'ready':
|
||||
# return 'done'
|
||||
return 'draft'
|
||||
|
||||
def on_change_product(self, cursor, user, ids, value, context=None):
|
||||
@@ -217,7 +205,7 @@ class CreatePacking(Wizard):
|
||||
|
||||
move_obj = self.pool.get('stock.move')
|
||||
packing_obj = self.pool.get('stock.packing.in')
|
||||
warehouse_obj = self.pool.get('stock.warehouse')
|
||||
location_obj = self.pool.get('stock.location')
|
||||
|
||||
moves = move_obj.browse(cursor, user, data['ids'], context=context)
|
||||
# Collect moves by incoming location
|
||||
@@ -237,25 +225,26 @@ class CreatePacking(Wizard):
|
||||
moves_by_location[location].append(move.id)
|
||||
|
||||
# Fetch warehouse for these locations
|
||||
warehouse_ids = warehouse_obj.search(
|
||||
wh_location_ids = location_obj.search(
|
||||
cursor, user,
|
||||
[('input_location', 'in',
|
||||
[l for l in moves_by_location])])
|
||||
warehouses = warehouse_obj.browse(
|
||||
[l for l in moves_by_location]),
|
||||
('usage','=','warehouse')])
|
||||
wh_locations = location_obj.browse(
|
||||
cursor, user, warehouse_ids, context=context)
|
||||
loc2wh = dict([( wh.input_location.id, wh.id) for wh in warehouses])
|
||||
loc2wh = dict([( whl.input_location.id, whl.id) for whl in wh_locations])
|
||||
|
||||
packing_ids = []
|
||||
for location, move_ids in moves_by_location.iteritems():
|
||||
wh = loc2wh.get(location)
|
||||
if not wh:
|
||||
whl = loc2wh.get(location)
|
||||
if not whl:
|
||||
raise ExceptWizard(
|
||||
'UserError',
|
||||
'Moves must have a final destination '\
|
||||
'who is an input location of a wharehouse.')
|
||||
pid = packing_obj.create(
|
||||
cursor, user,
|
||||
{'incoming_moves': [('set',move_ids)], 'warehouse': wh},
|
||||
{'incoming_moves': [('set',move_ids)], 'warehouse': whl},
|
||||
context=context)
|
||||
|
||||
packing_ids.append(pid)
|
||||
|
||||
+8
-7
@@ -17,21 +17,21 @@ class PackingIn(OSV):
|
||||
effective_date =fields.DateTime('Effective Date', readonly=True)
|
||||
planned_date = fields.DateTime('Planned Date', readonly=True)
|
||||
warehouse = fields.Many2One(
|
||||
'stock.warehouse',"Warehouse", required=True, states=STATES,)
|
||||
'stock.location',"Warehouse", required=True, states=STATES,
|
||||
domain="[('type', '=', 'warehouse')]",)
|
||||
incoming_moves = fields.One2Many(
|
||||
'stock.move', 'incoming_packing_in', 'Incoming Moves',
|
||||
states={'readonly':"state in ('received','done')",},
|
||||
context="{'wh_incoming': warehouse, 'pack_incoming_state': state}")
|
||||
context="{'warehouse': warehouse, 'packing_state': state, 'type':'incoming'}")
|
||||
inventory_moves = fields.One2Many(
|
||||
'stock.move', 'inventory_packing_in', 'Inventory Moves',
|
||||
states={'readonly':"state in ('draft','waiting')",},
|
||||
context="{'wh_inv_in': warehouse, 'pack_inv_in_state': state}")
|
||||
context="{'warehouse': warehouse, 'packing_state': state, 'type':'inventory_in'}")
|
||||
code = fields.Char("Code", size=None, select=1, readonly=True,)
|
||||
state = fields.Selection(
|
||||
[('draft','Draft'),('done','Done'),('cancel','Cancel'),
|
||||
('waiting','Waiting'),('received','Received')], 'State', readonly=True)
|
||||
|
||||
|
||||
def __init__(self):
|
||||
super(PackingIn, self).__init__()
|
||||
self._rpc_allowed += [
|
||||
@@ -142,15 +142,16 @@ class PackingOut(OSV):
|
||||
effective_date =fields.DateTime('Effective Date', readonly=True)
|
||||
planned_date = fields.DateTime('Planned Date', readonly=True)
|
||||
warehouse = fields.Many2One(
|
||||
'stock.warehouse',"Warehouse", required=True, states=STATES,)
|
||||
'stock.location',"Warehouse", required=True, states=STATES,
|
||||
domain="[('type', '=', 'warehouse')]",)
|
||||
outgoing_moves = fields.One2Many(
|
||||
'stock.move', 'outgoing_packing_out', 'Outgoing Moves',
|
||||
states=STATES,
|
||||
context="{'wh_outgoing': warehouse, 'pack_outgoing_state': state}")
|
||||
context="{'warehouse': warehouse, 'packing_state': state, 'type':'outgoing',}")
|
||||
inventory_moves = fields.One2Many(
|
||||
'stock.move', 'inventory_packing_out', 'Inventory Moves',
|
||||
states={'readonly':"state not in ('assigned')",},
|
||||
context="{'wh_inv_out': warehouse, 'pack_inv_out_state': state}")
|
||||
context="{'warehouse': warehouse, 'packing_state': state, 'type':'inventory_out',}")
|
||||
code = fields.Char("Code", size=None, select=1, readonly=True,)
|
||||
state = fields.Selection(
|
||||
[('draft','Draft'),('done','Done'),('cancel','Cancel'),
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
"Wharehouse"
|
||||
from trytond.osv import fields, OSV
|
||||
|
||||
STATES = {
|
||||
'readonly': "active == False",
|
||||
}
|
||||
|
||||
|
||||
class Warehouse(OSV):
|
||||
"Warehouse"
|
||||
_name = 'stock.warehouse'
|
||||
_order = 'name'
|
||||
_description = __doc__
|
||||
name = fields.Char("Name", size=64, required=True, select=True)
|
||||
address = fields.Many2One("partner.address", "Address")
|
||||
locations = fields.One2Many(
|
||||
"stock.location", "warehouse", "Storage locations",)
|
||||
active = fields.Boolean('Active', select=True)
|
||||
|
||||
def default_active(self, cursor, user, context=None):
|
||||
return True
|
||||
|
||||
Warehouse()
|
||||
@@ -1,84 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<tryton>
|
||||
<data>
|
||||
<menuitem name="Inventory Management" sequence="3" id="menu_stock"/>
|
||||
<record model="ir.ui.view" id="warehouse_view_form">
|
||||
<field name="model">stock.warehouse</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<![CDATA[
|
||||
<form string="Warehouse">
|
||||
<label name="name"/>
|
||||
<field name="name"/>
|
||||
<label name="address"/>
|
||||
<field name="address"/>
|
||||
<label name="input_location"/>
|
||||
<field name="input_location"/>
|
||||
<label name="output_location"/>
|
||||
<field name="output_location"/>
|
||||
<label name="store_location"/>
|
||||
<field name="store_location"/>
|
||||
<separator name="locations" colspan="4"/>
|
||||
<field name="locations" colspan="4"/>
|
||||
</form>
|
||||
]]>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="warehouse_view_tree">
|
||||
<field name="model">stock.warehouse</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<![CDATA[
|
||||
<tree string="Warehouses">
|
||||
<field name="name"/>
|
||||
<field name="address"/>
|
||||
</tree>
|
||||
]]>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window" id="act_warehouse_form">
|
||||
<field name="name">Warehouses</field>
|
||||
<field name="res_model">stock.warehouse</field>
|
||||
<field name="view_type">form</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_warehouse_form_view1">
|
||||
<field name="sequence" eval="1"/>
|
||||
<field name="view" ref="warehouse_view_tree"/>
|
||||
<field name="act_window" ref="act_warehouse_form"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_warehouse_form_view2">
|
||||
<field name="sequence" eval="2"/>
|
||||
<field name="view" ref="warehouse_view_form"/>
|
||||
<field name="act_window" ref="act_warehouse_form"/>
|
||||
</record>
|
||||
<menuitem parent="menu_stock" sequence="1"
|
||||
action="act_warehouse_form" id="menu_warehouse_form"/>
|
||||
|
||||
|
||||
|
||||
<record model="res.group" id="group_stock_admin">
|
||||
<field name="name">Stock administration</field>
|
||||
</record>
|
||||
<record model="res.user" id="res.user_admin">
|
||||
<field name="groups" eval="[('add', ref('group_stock_admin'))]"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.model.access" id="access_warehouse">
|
||||
<field name="model" search="[('model', '=', 'stock.warehouse')]"/>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="False"/>
|
||||
<field name="perm_create" eval="False"/>
|
||||
<field name="perm_unlink" eval="False"/>
|
||||
</record>
|
||||
<record model="ir.model.access" id="access_stock_admin">
|
||||
<field name="model" search="[('model', '=', 'stock.warehouse')]"/>
|
||||
<field name="group" ref="group_stock_admin"/>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="True"/>
|
||||
<field name="perm_create" eval="True"/>
|
||||
<field name="perm_unlink" eval="True"/>
|
||||
</record>
|
||||
|
||||
|
||||
</data>
|
||||
</tryton>
|
||||
Reference in New Issue
Block a user