Hi everyone,
I’m creating a module allowing to manage Vehicles. It allows to create a Mission, choose the vehicles category to use for that mission, and for each choosen category, to create a MissionOrder (the MissionOrder makes the link between the Mission, the Driver doing the mission, and the vehicle to use).
In the form allowing to create a new MissionOrder, I’m trying to filter the field truck (which is the vehicle to use for the mission), so that the user can choose only between available vehicles in the right category. The field is a Many2One field with a domain, but no matter how I write the domain, I always end up with a javascript error from Sao.
The error is :
TypeError: Cannot use 'in' operator to search for 'truck_category' in null
My models are defined this way :
class VehicleCategory(ModelSQL, ModelView):
'VehicleCategory'
__name__ = 'transport.vehicle_category'
_rec_name = 'code'
# Relations with other models
vehicles = fields.One2Many('transport.vehicle', 'category', 'Vehicles')
parent = fields.Many2One('transport.vehicle_category', 'Parent Category', ondelete='RESTRICT', required=False, select=True)
subcategories = fields.One2Many('transport.vehicle_category', 'parent', 'Subcategories')
# Model properties
code = fields.Char('Code', required=True)
label = fields.Char('Label', required=True)
# Add a unicity constraint on the field "code"
@classmethod
def __setup__(cls):
super().__setup__()
t = cls.__table__()
cls._sql_constraints += [
('code_uniq', Unique(t, t.code), 'The Code must be unique.'),
]
class Vehicle(ModelSQL, ModelView):
'Vehicle'
__name__ = 'transport.vehicle'
_rec_name = 'license_number'
# Relations with other models
category = fields.Many2One('transport.vehicle_category', 'Category', ondelete='RESTRICT', required=True)
# Model properties
license_number = fields.Char('License Number', required=True)
label = fields.Char('Label', required=True)
# Add a unicity constraint on the field "license_number"
@classmethod
def __setup__(cls):
super().__setup__()
t = cls.__table__()
cls._sql_constraints += [
('license_number_uniq', Unique(t, t.license_number), 'The license number must be unique.'),
]
class Driver(ModelSQL, ModelView):
'Driver'
__name__ = 'transport.driver'
_rec_name = 'code'
# Relations with other models
employee = fields.Many2One('company.employee', 'Employee', ondelete='RESTRICT', required=True)
# Model properties
code = fields.Char('Code', required=True)
license_number = fields.Char('License Number', required=True)
# Add a unicity constraint on the field "code"
@classmethod
def __setup__(cls):
super().__setup__()
t = cls.__table__()
cls._sql_constraints += [
('code_uniq', Unique(t, t.code), 'The Code must be unique.'),
]
class Mission(ModelSQL, ModelView):
'Mission'
__name__ = 'transport.mission'
_rec_name = 'description'
# Model properties
identifier = fields.Char('Identifier', required=True)
date = fields.Date('Date', required=True)
start_time = fields.Time('Start Time', required=True)
end_time = fields.Time('End Time', required=True)
vehicle_categories = fields.One2Many('transport.mission_vehicle_category', 'mission', 'Vehicle Categories')
class MissionVehicleCategory(ModelSQL, ModelView):
'MissionVehicleCategory'
__name__ = 'transport.mission_vehicle_category'
_rec_name = 'rec_name'
# Relations with other models
mission = fields.Many2One('transport.mission', 'Mission', ondelete='CASCADE', required=True)
truck_category = fields.Many2One('transport.vehicle_category', 'Truck Type', ondelete='RESTRICT', required=True,
domain=['AND',
('code','not in', ['REM','SR']),
['OR',
('parent', '=', None),
('parent.code','not in', ['REM','SR'])
]
]
)
trailer_category = fields.Many2One('transport.vehicle_category', 'Trailer Type', ondelete='RESTRICT', required=False,
domain=['OR',
('code', 'in', ['REM','SR']),
('parent.code', 'in', ['REM','SR'])
]
)
mission_orders = fields.One2Many('transport.mission_order', 'mission_vehicle_category', 'Mission orders')
# Model properties
number = fields.Integer('Number', required=True)
# Override get_rec_name to display a proper name for the MissionVehicleCategory
def get_rec_name(self, name):
name = self.truck_category.rec_name
if self.trailer_category:
name += " - " + self.trailer_category.rec_name
name += ' (x%d)' % (self.number)
return name
class MissionOrder(ModelSQL, ModelView):
'MissionOrder'
__name__ = 'transport.mission_order'
_rec_name = 'label'
# Relations with other models
mission_vehicle_category = fields.Many2One('transport.mission_vehicle_category', 'Mission Vehicle Category',
ondelete='SET NULL', required=False)
driver = fields.Many2One('transport.driver', 'Driver', ondelete='RESTRICT', required=True,
domain=[('id', 'not in', Eval('unavailable_drivers'))], depends=['unavailable_drivers']
)
unavailable_drivers = fields.Function(
fields.Many2Many('transport.mission_order-transport.driver', 'mission_order', 'driver', 'Unavailable drivers'),
'getter_unavailable_drivers'
)
truck = fields.Many2One('transport.vehicle', 'Truck', ondelete='RESTRICT', required=False,
domain=['AND',
('category.code', 'not in', ['REM','SR']),
('category.parent.code', 'not in', ['REM','SR']),
('category.code','=', Eval('mission_vehicle_category', {}).get('truck_category', 0)),
('id', 'not in', Eval('unavailable_vehicles'))
], depends=['unavailable_vehicles', 'mission_vehicle_category']
)
trailer = fields.Many2One('transport.vehicle', 'Trailer', ondelete='RESTRICT', required=False,
domain=['OR',
('category.code', 'in', ['REM','SR']),
('category.parent.code', 'in', ['REM','SR']),
('id', 'not in', Eval('unavailable_vehicles'))
], depends=['unavailable_vehicles']
)
unavailable_vehicles = fields.Function(
fields.Many2Many('transport.mission_order-transport.vehicle', 'mission_order', 'vehicle', 'Unavailable vehicles'),
'getter_unavailable_vehicles'
)
# Model properties
label = fields.Char('Label', required=True)
comment = fields.Text('Comment', required=False)
client = fields.Many2One('party.party', 'Client', ondelete='RESTRICT', required=False)
def getter_unavailable_drivers(self, name):
f = open("/modules/transport/transport.log", "w+")
f.write("getter_unavailable_drivers : \n")
if not self.start_date or not self.end_date:
return None
missionOrder = Pool().get('transport.mission_order')
missionOrderTable = missionOrder.__table__()
cursor = Transaction().connection.cursor()
where = (
(missionOrderTable.start_date.__ge__(self.start_date) & missionOrderTable.start_date.__le__(self.end_date))
| (missionOrderTable.end_date.__ge__(self.start_date) & missionOrderTable.end_date.__le__(self.end_date))
) & missionOrderTable.id.__ne__(self.id)
cursor.execute(*missionOrderTable.select(
missionOrderTable.driver,
where=where
))
result = [driver[0] for driver in cursor.fetchall()]
for driver in cursor.fetchall():
f.write("Driver ID : %s\n" % driver)
f.close()
return result
def getter_unavailable_vehicles(self, name):
f = open("/modules/transport/transport.log", "w+")
f.write("getter_unavailable_vehicles : \n")
if not self.start_date or not self.end_date:
return None
missionOrder = Pool().get('transport.mission_order')
missionOrderTable = missionOrder.__table__()
cursor = Transaction().connection.cursor()
where = (
(missionOrderTable.start_date.__ge__(self.start_date) & missionOrderTable.start_date.__le__(self.end_date))
| (missionOrderTable.end_date.__ge__(self.start_date) & missionOrderTable.end_date.__le__(self.end_date))
) & missionOrderTable.id.__ne__(self.id)
cursor.execute(*missionOrderTable.select(
missionOrderTable.truck, missionOrderTable.trailer,
where=where
))
result = []
for truck, trailer in cursor.fetchall():
result.append(truck)
result.append(trailer)
f.write("Truck ID : %s\n" % truck)
f.write("Trailer ID : %s\n" % trailer)
f.close()
return result
class MissionOrderDriverRelation(ModelSQL):
'MissionOrder - Driver relation'
__name__ = 'transport.mission_order-transport.driver'
mission_order = fields.Many2One('transport.mission_order', 'Mission Order', required=True, ondelete='CASCADE')
driver = fields.Many2One('transport.driver', 'Driver', required=True, ondelete='CASCADE')
class MissionOrderVehicleRelation(ModelSQL):
'MissionOrder - Vehicle relation'
__name__ = 'transport.mission_order-transport.vehicle'
mission_order = fields.Many2One('transport.mission_order', 'Mission Order', required=True, ondelete='CASCADE')
vehicle = fields.Many2One('transport.vehicle', 'Vehicle', required=True, ondelete='CASCADE')
I have created the form views for all the models. I can create a new mission, and add a MissionVehicleCategory to it. After it is saved, I’m trying to add a MissionOrder to the MissionVehicleCategory. A new window appear with the MissionOrder form, but I got this javascript error from Sao that I mentionned earlier.
The problematic field is truck, in the model MissionOrder :
truck = fields.Many2One('transport.vehicle', 'Truck', ondelete='RESTRICT', required=False,
domain=['AND',
('category.code', 'not in', ['REM','SR']),
('category.parent.code', 'not in', ['REM','SR']),
('category.code','=', Eval('mission_vehicle_category', {}).get('truck_category', 0)),
('id', 'not in', Eval('unavailable_vehicles'))
], depends=['unavailable_vehicles', 'mission_vehicle_category']
)
More specifically, the third clause of the domain does not work. If I comment this line :
('category.code','=', Eval('mission_vehicle_category', {}).get('truck_category', 0)),
I don’t have the error (but the vehicles are not filtered properly when the user choose a vehicle for the field “truck”.
I have also tried to replace this clause with :
('category.code','=', Eval('mission_vehicle_category.truck_category', 0)),
But I get another javascript error :
TypeError: Cannot use 'in' operator to search for 'truck_category' in 11
When debugging, I can see that mission_vehicle_category is null when doing the Eval.
What am I doing wrong ?
Thanks in advance for any help.