Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/sf物流方面缺陷与优化

This commit is contained in:
mgw
2024-06-27 17:31:21 +08:00
14 changed files with 120 additions and 56 deletions

View File

@@ -205,39 +205,17 @@ class StockRule(models.Model):
productions_values) productions_values)
# self.env['stock.move'].sudo().create(productions._get_moves_raw_values()) # self.env['stock.move'].sudo().create(productions._get_moves_raw_values())
self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \
(
p.move_dest_ids.procure_method != 'make_to_order' and not
p.move_raw_ids and not p.workorder_ids)).action_confirm()
''' '''
创建工单 创建工单
''' '''
# productions._create_workorder() # productions._create_workorder()
# #
grouped_product_ids = {k: list(g) for k, g in groupby(productions, key=lambda x: x.product_id.id)} self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
# 初始化一个字典来存储每个product_id对应的生产订单名称列表 productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \
product_id_to_production_names = {} (
# 对于每个product_id获取其所有生产订单的名称 p.move_dest_ids.procure_method != 'make_to_order' and not
for product_id, productions in grouped_product_ids.items(): p.move_raw_ids and not p.workorder_ids)).action_confirm()
# 为同一个product_id创建一个生产订单名称列表
product_id_to_production_names[product_id] = [production.name for production in productions]
for production_item in productions:
if production_item.product_id.id in product_id_to_production_names:
# # 同一个产品多个制造订单对应一个编程单和模型库
# # 只调用一次fetchCNC并将所有生产订单的名称作为字符串传递
if not production_item.programming_no:
production_programming = self.env['mrp.production'].search(
[('product_id.id', '=', production_item.product_id.id),
('origin', '=', production_item.origin)],
limit=1, order='id asc')
if not production_programming.programming_no:
production_item.fetchCNC(
', '.join(product_id_to_production_names[production_item.product_id.id]))
else:
production_item.write({'programming_no': production_programming.programming_no,
'programming_state': '编程中'})
for production in productions: for production in productions:
''' '''
创建制造订单时生成序列号 创建制造订单时生成序列号
@@ -283,6 +261,28 @@ class StockRule(models.Model):
'product_id': production.product_id.id, 'product_id': production.product_id.id,
'state': 'draft', 'state': 'draft',
}) })
grouped_product_ids = {k: list(g) for k, g in groupby(productions, key=lambda x: x.product_id.id)}
# 初始化一个字典来存储每个product_id对应的生产订单名称列表
product_id_to_production_names = {}
# 对于每个product_id获取其所有生产订单的名称
for product_id, productions in grouped_product_ids.items():
# 为同一个product_id创建一个生产订单名称列表
product_id_to_production_names[product_id] = [production.name for production in productions]
for production_item in productions:
if production_item.product_id.id in product_id_to_production_names:
# # 同一个产品多个制造订单对应一个编程单和模型库
# # 只调用一次fetchCNC并将所有生产订单的名称作为字符串传递
if not production_item.programming_no:
production_programming = self.env['mrp.production'].search(
[('product_id.id', '=', production_item.product_id.id),
('origin', '=', production_item.origin)],
limit=1, order='id asc')
if not production_programming.programming_no:
production_item.fetchCNC(
', '.join(product_id_to_production_names[production_item.product_id.id]))
else:
production_item.write({'programming_no': production_programming.programming_no,
'programming_state': '编程中'})
return True return True

View File

@@ -483,7 +483,10 @@
<field name="production_line_id" readonly="1"/> <field name="production_line_id" readonly="1"/>
<field name="task_delivery_time" readonly="1"/> <field name="task_delivery_time" readonly="1"/>
<field name="task_completion_time" readonly="1"/> <field name="task_completion_time" readonly="1"/>
<field name="status" readonly="1"/> <field name="status" readonly="1" widget="badge"
decoration-success="status == '已配送'"
decoration-warning="status == '待下发'"
decoration-danger="status == '待配送'"/>
</tree> </tree>
</field> </field>
</page> </page>
@@ -729,7 +732,7 @@
</search> </search>
</field> </field>
</record> </record>
<record id="sf_workpiece_delivery_act" model="ir.actions.act_window"> <record id="sf_workpiece_delivery_act" model="ir.actions.act_window">
<field name="name">工件配送</field> <field name="name">工件配送</field>
<field name="res_model">sf.workpiece.delivery</field> <field name="res_model">sf.workpiece.delivery</field>

View File

@@ -40,7 +40,7 @@ class Sf_Mrs_Connect(http.Controller):
download_state = request.env['sf.cnc.processing'].with_user( download_state = request.env['sf.cnc.processing'].with_user(
request.env.ref("base.user_admin")).download_file_tmp( request.env.ref("base.user_admin")).download_file_tmp(
ret['folder_name'], r) ret['folder_name'], r)
if download_state == 0: if download_state is False:
res['status'] = -2 res['status'] = -2
res['message'] = '编程单号为%s的CNC程序文件从FTP拉取失败' % (ret['programming_no']) res['message'] = '编程单号为%s的CNC程序文件从FTP拉取失败' % (ret['programming_no'])
return json.JSONEncoder().encode(res) return json.JSONEncoder().encode(res)

View File

@@ -171,6 +171,11 @@ class ProductTemplate(models.Model):
class RePurchaseOrder(models.Model): class RePurchaseOrder(models.Model):
_inherit = 'purchase.order' _inherit = 'purchase.order'
mrp_production_count = fields.Integer(
"Count of MO Source",
compute='_compute_mrp_production_count',
groups='mrp.group_mrp_user,sf_base.group_purchase,sf_base.group_purchase_director')
remark = fields.Text('备注') remark = fields.Text('备注')
user_id = fields.Many2one( user_id = fields.Many2one(
'res.users', string='买家', index=True, tracking=True, 'res.users', string='买家', index=True, tracking=True,

View File

@@ -54,7 +54,7 @@
<record model="ir.rule" id="sale_order_rule_my"> <record model="ir.rule" id="sale_order_rule_my">
<field name="name">销售经理查看自己的订单</field> <field name="name">销售经理查看自己的订单</field>
<field name="model_id" ref="model_sale_order"/> <field name="model_id" ref="model_sale_order"/>
<field name="domain_force">['|',('user_id','=',user.id),('create_uid', '=',user.id)]</field> <field name="domain_force">['|','|',('user_id','=',user.id),('user_id', '=', False),('create_uid', '=',user.id)]</field>
<field name="groups" eval="[(4, ref('sf_base.group_sale_salemanager'))]"/> <field name="groups" eval="[(4, ref('sf_base.group_sale_salemanager'))]"/>
<field name="perm_read" eval="1"/> <field name="perm_read" eval="1"/>
<field name="perm_write" eval="1"/> <field name="perm_write" eval="1"/>
@@ -74,7 +74,7 @@
<record model="ir.rule" id="inventory_purchase_order_rule_my"> <record model="ir.rule" id="inventory_purchase_order_rule_my">
<field name="name">采购岗查看自己的订单</field> <field name="name">采购岗查看自己的订单</field>
<field name="model_id" ref="purchase.model_purchase_order"/> <field name="model_id" ref="purchase.model_purchase_order"/>
<field name="domain_force">['|',('user_id','=',user.id),('create_uid', '=',user.id)]</field> <field name="domain_force">['|','|',('user_id','=',user.id),('user_id', '=', False),('create_uid', '=',user.id)]</field>
<field name="groups" eval="[(4, ref('sf_base.group_purchase'))]"/> <field name="groups" eval="[(4, ref('sf_base.group_purchase'))]"/>
<field name="perm_read" eval="1"/> <field name="perm_read" eval="1"/>
<field name="perm_write" eval="0"/> <field name="perm_write" eval="0"/>

View File

@@ -79,6 +79,13 @@
<xpath expr="//form/header/button[@name='button_done']" position="attributes"> <xpath expr="//form/header/button[@name='button_done']" position="attributes">
<attribute name="groups">sf_base.group_purchase,sf_base.group_purchase_director</attribute> <attribute name="groups">sf_base.group_purchase,sf_base.group_purchase_director</attribute>
</xpath> </xpath>
<xpath expr="//form/sheet/div[@name='button_box']/button[@name='action_view_mrp_productions']"
position="attributes">
<attribute name="groups">mrp.group_mrp_user,sf_base.group_purchase,sf_base.group_purchase_director
</attribute>
</xpath>
<xpath expr="//field[@name='order_line']" position="attributes"> <xpath expr="//field[@name='order_line']" position="attributes">
<attribute name="attrs">{'readonly': [('state', 'in', ['purchase'])]} <attribute name="attrs">{'readonly': [('state', 'in', ['purchase'])]}
</attribute> </attribute>

View File

@@ -944,13 +944,11 @@ class FunctionalToolDismantle(models.Model):
functional_tool_assembly = self.functional_tool_id.functional_tool_name_id functional_tool_assembly = self.functional_tool_id.functional_tool_name_id
if self.scrap_boolean: if self.scrap_boolean:
# 刀柄报废 入库到Scrap # 刀柄报废 入库到Scrap
lot.create_stock_quant(location, location_dest_scrap_ids[-1], functional_tool_assembly.id, code, lot.create_stock_quant(location, location_dest_scrap_ids[-1], False, code, False, False)
functional_tool_assembly, functional_tool_assembly.tool_groups_id)
lot.tool_material_status = '报废' lot.tool_material_status = '报废'
else: else:
# 刀柄不报废 入库到刀具房 # 刀柄不报废 入库到刀具房
lot.create_stock_quant(location, location_dest, functional_tool_assembly.id, code, lot.create_stock_quant(location, location_dest, False, code, False, False)
functional_tool_assembly, functional_tool_assembly.tool_groups_id)
lot.tool_material_status = '可用' lot.tool_material_status = '可用'
# ==============功能刀具[报废]拆解================ # ==============功能刀具[报废]拆解================

View File

@@ -3,6 +3,7 @@ import requests
import logging import logging
from odoo import models, api, fields from odoo import models, api, fields
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
from datetime import datetime, timedelta
from odoo.addons.sf_base.commons.common import Common from odoo.addons.sf_base.commons.common import Common
@@ -101,7 +102,7 @@ class SfMaintenanceEquipment(models.Model):
tool_install_time = {'Nomal': '正常', 'Warning': '报警'} tool_install_time = {'Nomal': '正常', 'Warning': '报警'}
equipment_tool_id.write({ equipment_tool_id.write({
'functional_tool_name_id': functional_tool_id.id, 'functional_tool_name_id': functional_tool_id.id,
'tool_install_time': time 'tool_install_time': time - timedelta(hours=8)
}) })
if functional_tool_id.current_location != '机内刀库': if functional_tool_id.current_location != '机内刀库':
# 对功能刀具进行移动到生产线 # 对功能刀具进行移动到生产线

View File

@@ -25,7 +25,8 @@ class ToolMaterial(models.Model):
have_been_used_num = fields.Integer('在用数量', compute='_compute_number', store=True) have_been_used_num = fields.Integer('在用数量', compute='_compute_number', store=True)
scrap_num = fields.Integer('报废数量', compute='_compute_number', store=True) scrap_num = fields.Integer('报废数量', compute='_compute_number', store=True)
barcode_ids = fields.One2many('stock.lot', 'tool_material_search_id', string='序列号', readonly=True) barcode_ids = fields.One2many('stock.lot', 'tool_material_search_id', string='序列号', readonly=True,
domain=[('tool_material_status', '!=', '未入库')])
@api.depends('product_id.stock_quant_ids.quantity') @api.depends('product_id.stock_quant_ids.quantity')
def _compute_number(self): def _compute_number(self):
@@ -46,8 +47,6 @@ class ToolMaterial(models.Model):
record.scrap_num = scrap_num record.scrap_num = scrap_num
record.number = usable_num + have_been_used_num + scrap_num record.number = usable_num + have_been_used_num + scrap_num
@api.model @api.model
def _read_group_cutting_tool_material_id(self, categories, domain, order): def _read_group_cutting_tool_material_id(self, categories, domain, order):
cutting_tool_material_id = categories._search([], order=order, access_rights_uid=SUPERUSER_ID) cutting_tool_material_id = categories._search([], order=order, access_rights_uid=SUPERUSER_ID)

View File

@@ -63,6 +63,7 @@
<field name="name"/> <field name="name"/>
<field name="rfid"/> <field name="rfid"/>
<field name="product_qty"/> <field name="product_qty"/>
<field name="create_date" string="入库日期"/>
<field name="tool_material_status"/> <field name="tool_material_status"/>
<!-- <button name="enroll_tool_material_stock" string="序列号注册" type="object" class="btn-primary"/>--> <!-- <button name="enroll_tool_material_stock" string="序列号注册" type="object" class="btn-primary"/>-->
</tree> </tree>

View File

@@ -557,8 +557,10 @@ class SfStockMoveLine(models.Model):
_name = 'stock.move.line' _name = 'stock.move.line'
_inherit = ['stock.move.line', 'printing.utils'] _inherit = ['stock.move.line', 'printing.utils']
stock_lot_name = fields.Char('序列号名称', related='lot_id.name')
current_location_id = fields.Many2one( current_location_id = fields.Many2one(
'sf.shelf.location', string='当前货位', compute='_compute_current_location_id', store=True) 'sf.shelf.location', string='当前货位', compute='_compute_current_location_id', store=True, readonly=False,
domain="[('product_id', '=', product_id),'|',('product_sn_id.name', '=', stock_lot_name),('product_sn_ids.lot_id.name','=',stock_lot_name)]")
# location_dest_id = fields.Many2one('stock.location', string='目标库位') # location_dest_id = fields.Many2one('stock.location', string='目标库位')
location_dest_id_product_type = fields.Many2many(related='location_dest_id.product_type') location_dest_id_product_type = fields.Many2many(related='location_dest_id.product_type')
location_dest_id_value = fields.Integer(compute='_compute_location_dest_id_value', store=True) location_dest_id_value = fields.Integer(compute='_compute_location_dest_id_value', store=True)
@@ -856,7 +858,9 @@ class SfStockMoveLine(models.Model):
def compute_destination_location_id(self): def compute_destination_location_id(self):
for record in self: for record in self:
obj = self.env['sf.shelf.location'].search([('name', '=', obj = self.env['sf.shelf.location'].search([('name', '=',
self.destination_location_id.name)]) record.destination_location_id.name)])
if obj and obj.product_id and obj.product_id != record.product_id:
raise ValidationError('目标货位【%s】已被【%s】产品占用!' % (obj.code, obj.product_id))
if record.lot_id: if record.lot_id:
if record.product_id.tracking == 'serial': if record.product_id.tracking == 'serial':
shelf_location_obj = self.env['sf.shelf.location'].search( shelf_location_obj = self.env['sf.shelf.location'].search(
@@ -869,7 +873,7 @@ class SfStockMoveLine(models.Model):
if obj: if obj:
obj.product_sn_id = record.lot_id.id obj.product_sn_id = record.lot_id.id
elif record.product_id.tracking == 'lot': elif record.product_id.tracking == 'lot':
self.put_shelf_location(record) record.put_shelf_location(record)
if not obj.product_id: if not obj.product_id:
obj.product_id = record.product_id.id obj.product_id = record.product_id.id
else: else:
@@ -980,15 +984,26 @@ class SfStockPicking(models.Model):
# 调用入库方法进行入库刀货位 # 调用入库方法进行入库刀货位
line.compute_destination_location_id() line.compute_destination_location_id()
else: else:
# 对除刀柄之外的刀具物料进行 目标货位必填校验 # 对除刀柄之外的刀具物料入库到刀具房进行 目标货位必填校验
if self.location_dest_id.name == '刀具房' and line.product_id.cutting_tool_material_id.name not in ( if self.location_dest_id.name == '刀具房' and line.product_id.cutting_tool_material_id.name not in (
'刀柄', False): '刀柄', False):
raise ValidationError('请选择【%s】产品的目标货位!' % line.product_id.name) raise ValidationError('请选择【%s】产品的目标货位!' % line.product_id.name)
if line.current_location_id:
# 对货位的批次产品进行出货
line.put_shelf_location(line)
if line.current_location_id: if line.current_location_id:
# 按序列号管理的产品
if line.current_location_id.product_sn_id: if line.current_location_id.product_sn_id:
line.current_location_id.product_sn_id = False line.current_location_id.product_sn_id = False
# line.current_location_id.location_status = '空闲' # line.current_location_id.location_status = '空闲'
line.current_location_id.product_num = 0 line.current_location_id.product_num = 0
line.current_location_id.product_id = False
else:
# 对除刀柄之外的刀具物料从刀具房出库进行 当前货位必填校验
if self.location_id.name == '刀具房' and line.product_id.cutting_tool_material_id.name not in (
'刀柄', False):
raise ValidationError('请选择【%s】产品的当前货位!' % line.product_id.name)
# 对入库作业的刀柄和托盘进行Rfid绑定校验 # 对入库作业的刀柄和托盘进行Rfid绑定校验
for move in self.move_ids: for move in self.move_ids:
@@ -1115,6 +1130,7 @@ class CustomStockMove(models.Model):
采购入库扫码绑定Rfid码 采购入库扫码绑定Rfid码
""" """
for record in self: for record in self:
logging.info('Rfid%s' % barcode)
if record: if record:
lot = self.env['stock.lot'].sudo().search([('rfid', '=', barcode)]) lot = self.env['stock.lot'].sudo().search([('rfid', '=', barcode)])
if lot: if lot:
@@ -1126,7 +1142,9 @@ class CustomStockMove(models.Model):
'该Rfid【%s】已经被序列号为【%s】的【%s】物料所占用!' % (barcode, lot.name, material)) '该Rfid【%s】已经被序列号为【%s】的【%s】物料所占用!' % (barcode, lot.name, material))
if '刀柄' in (record.product_id.cutting_tool_material_id.name or '') or '托盘' in ( if '刀柄' in (record.product_id.cutting_tool_material_id.name or '') or '托盘' in (
record.product_id.fixture_material_id.name or ''): record.product_id.fixture_material_id.name or ''):
logging.info('开始录入Rfid:%s' % record.move_line_nosuggest_ids)
for move_line_nosuggest_id in record.move_line_nosuggest_ids: for move_line_nosuggest_id in record.move_line_nosuggest_ids:
logging.info('录入的记录%s , Rfid:%s' % (move_line_nosuggest_id, move_line_nosuggest_id.rfid))
if move_line_nosuggest_id.rfid: if move_line_nosuggest_id.rfid:
if move_line_nosuggest_id.rfid == barcode: if move_line_nosuggest_id.rfid == barcode:
if record.product_id.cutting_tool_material_id.name: if record.product_id.cutting_tool_material_id.name:
@@ -1135,7 +1153,9 @@ class CustomStockMove(models.Model):
raise ValidationError('该托盘的Rfid已经录入请勿重复录入') raise ValidationError('该托盘的Rfid已经录入请勿重复录入')
else: else:
line_id = int(re.sub(r"\D", "", str(move_line_nosuggest_id.id))) line_id = int(re.sub(r"\D", "", str(move_line_nosuggest_id.id)))
self.env['stock.move.line'].sudo().search([('id', '=', line_id)]).write({'rfid': barcode}) res = self.env['stock.move.line'].sudo().search([('id', '=', line_id)]).write(
{'rfid': barcode})
logging.info('Rfid是否录入:%s' % res)
move_line_nosuggest_id.rfid = barcode move_line_nosuggest_id.rfid = barcode
break break
else: else:

View File

@@ -7,16 +7,18 @@
<field name="inherit_id" ref="stock.view_stock_move_line_detailed_operation_tree"/> <field name="inherit_id" ref="stock.view_stock_move_line_detailed_operation_tree"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//field[@name='location_id'][2]" position="after"> <xpath expr="//field[@name='location_id'][2]" position="after">
<field name="current_location_id" force_save="1"/> <field name="stock_lot_name" invisible="1"/>
<field name="current_location_id" force_save="1"
options="{'no_create': True,'no_create_edit':True}"/>
</xpath> </xpath>
<xpath expr="//field[@name='location_dest_id'][2]" position="after"> <xpath expr="//field[@name='location_dest_id'][2]" position="after">
<field name="current_product_id" invisible="1"/> <field name="current_product_id" invisible="1"/>
<field name="there_is_no_sn" invisible="1"/> <field name="there_is_no_sn" invisible="1"/>
<!-- <field name="destination_location_id" domain="[('location_id', '=', location_dest_id_value), --> <!-- <field name="destination_location_id" domain="[('location_id', '=', location_dest_id_value), -->
<!-- '|', --> <!-- '|', -->
<!-- ('location_status', '=', '空闲'), --> <!-- ('location_status', '=', '空闲'), -->
<!-- ('location_status', '=', '占用'), ('product_id', '=', current_product_id) --> <!-- ('location_status', '=', '占用'), ('product_id', '=', current_product_id) -->
<!-- ]"/> --> <!-- ]"/> -->
<field name="destination_location_id" domain="[('location_id', '=', location_dest_id_value), '|', <field name="destination_location_id" domain="[('location_id', '=', location_dest_id_value), '|',
('location_status', '=', '空闲'), ('product_id', '=', current_product_id), ('product_sn_id', ('location_status', '=', '空闲'), ('product_id', '=', current_product_id), ('product_sn_id',
'=', there_is_no_sn)]" options="{'no_create': True,'no_create_edit':True}"/> '=', there_is_no_sn)]" options="{'no_create': True,'no_create_edit':True}"/>
@@ -55,6 +57,7 @@
<field name="inherit_id" ref="stock.view_move_line_form"/> <field name="inherit_id" ref="stock.view_move_line_form"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//form//sheet//group//group//field[@name='location_id']" position="after"> <xpath expr="//form//sheet//group//group//field[@name='location_id']" position="after">
<field name="stock_lot_name" invisible="1"/>
<field name="current_location_id" options="{'no_create': False}" force_save="1"/> <field name="current_location_id" options="{'no_create': False}" force_save="1"/>
</xpath> </xpath>
<xpath expr="//form//sheet//group//group//field[@name='location_dest_id']" position="after"> <xpath expr="//form//sheet//group//group//field[@name='location_dest_id']" position="after">

View File

@@ -592,8 +592,23 @@ var GanttRow = Widget.extend({
}); });
pill.decorations = pillDecorations; pill.decorations = pillDecorations;
if (self.colorField) { // let isDelay = false
pill._color = self._getColor(pill[self.colorField]); // if(pill.state != 'processing' && pill.state != 'finished') { // 判断待加工
// isDelay = pill.order_deadline.isBefore(new Date())
// }
pill.exState = ''
if (self.colorField){
// console.log(self.colorField, self, pill, '颜色')
// pill._color = self._getColor(pill[self.colorField]);
// 设置pill背景颜色2 修改时间2024年6月25日17:09:43
let isDelay = false
if(pill.state != 'processing' && pill.state != 'finished') { // 判断待加工
isDelay = pill.order_deadline.isBefore(new Date())
}
if(isDelay) {
pill.disableDragdrop = true
}
pill._color = self._getColor2(isDelay ? 'delay' : pill.state);
} }
if (self.progressField) { if (self.progressField) {
@@ -613,6 +628,13 @@ var GanttRow = Widget.extend({
} }
return 0; return 0;
}, },
_getColor2 (state) {
return {
'finished': 'ccc',
'delay': 9,
'processing': 13 // 绿色
}[state]
},
/** /**
* Get context to evaluate decoration * Get context to evaluate decoration
* *
@@ -867,10 +889,11 @@ var GanttRow = Widget.extend({
if ($pill.hasClass('ui-draggable-dragging')) { if ($pill.hasClass('ui-draggable-dragging')) {
return; return;
} }
var self = this; var self = this;
var pill = _.findWhere(this.pills, { id: $pill.data('id') }); var pill = _.findWhere(this.pills, { id: $pill.data('id') });
if(pill.state == 'finished'){ // 已完成状态不能拖拽
return;
}
// DRAGGABLE // DRAGGABLE
if (this.options.canEdit && !pill.disableStartResize && !pill.disableStopResize && !this.isGroup) { if (this.options.canEdit && !pill.disableStartResize && !pill.disableStopResize && !this.isGroup) {

View File

@@ -754,3 +754,7 @@
left: -0.5 * $o-connector-creator-bullet-diameter; left: -0.5 * $o-connector-creator-bullet-diameter;
} }
} }
.o_gantt_view .o_gantt_row_nogroup .o_gantt_pill.o_gantt_color_ccc {
background-color: #ccc;
}