Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/修复销售和采购

This commit is contained in:
jinling.yang
2024-01-09 09:32:30 +08:00
14 changed files with 219 additions and 25 deletions

View File

@@ -132,11 +132,11 @@ td.o_required_modifier {
//font-weight: bold; //font-weight: bold;
} }
//.text-truncate { .text-truncate {
// overflow: unset !important; overflow: unset !important;
// text-overflow: unset !important; text-overflow: unset !important;
// white-space: nowrap!important; //white-space: nowrap!important;
//} }
.o_list_renderer .o_list_table tbody > tr > td:not(.o_list_record_selector):not(.o_handle_cell):not(.o_list_button):not(.o_list_record_remove) { .o_list_renderer .o_list_table tbody > tr > td:not(.o_list_record_selector):not(.o_handle_cell):not(.o_list_button):not(.o_list_record_remove) {
white-space: nowrap !important; white-space: nowrap !important;
@@ -425,7 +425,13 @@ div:has(.o_required_modifier) > label::before {
.o_list_renderer .o_list_table thead .o_list_number_th { .o_list_renderer .o_list_table thead .o_list_number_th {
text-align:left; text-align:left;
} }
.o_list_renderer .o_list_table tbody > tr > td:not(.o_list_record_selector).o_list_number {
text-align: left;
}
.o_list_renderer .flex-row-reverse { .o_list_renderer .flex-row-reverse {
flex-direction: unset!important; flex-direction: unset!important;
}
.o_list_renderer .flex-row-reverse > .text-end {
text-align: left!important;
} }

View File

@@ -17,9 +17,32 @@ class MrpProduction(models.Model):
maintenance_count = fields.Integer(compute='_compute_maintenance_count', string="Number of maintenance requests") maintenance_count = fields.Integer(compute='_compute_maintenance_count', string="Number of maintenance requests")
request_ids = fields.One2many('maintenance.request', 'production_id') request_ids = fields.One2many('maintenance.request', 'production_id')
model_file = fields.Binary('模型文件', related='product_id.model_file') model_file = fields.Binary('模型文件', related='product_id.model_file')
schedule_state = fields.Selection([('未排', '未排'), ('已排', '已排')], schedule_state = fields.Selection([('未排', '未排'), ('已排', '已排'), ('已完成', '已完成')],
string='排程状态', default='未排') string='排程状态', default='未排')
# state = fields.Selection(selection_add=[
# ('pending_scheduling', '待排程'),
# ('pending_processing', '待加工'),
# ('completed', '已完工')
# ])
state = fields.Selection([
('draft', 'Draft'),
('confirmed', 'Confirmed'),
('progress', '待排程'),
('pending_processing', '待加工'),
('completed', '已完工'),
('to_close', 'To Close'),
('done', 'Done'),
('cancel', 'Cancelled')], string='State',
compute='_compute_state', copy=False, index=True, readonly=True,
store=True, tracking=True,
help=" * Draft: The MO is not confirmed yet.\n"
" * Confirmed: The MO is confirmed, the stock rules and the reordering of the components are trigerred.\n"
" * In Progress: The production has started (on the MO or on the WO).\n"
" * To Close: The production is done, the MO has to be closed.\n"
" * Done: The MO is closed, the stock moves are posted. \n"
" * Cancelled: The MO has been cancelled, can't be confirmed anymore.")
check_status = fields.Boolean(string='启用状态', default=False, readonly=True) check_status = fields.Boolean(string='启用状态', default=False, readonly=True)
active = fields.Boolean(string='已归档', default=True) active = fields.Boolean(string='已归档', default=True)
programming_no = fields.Char('编程单号') programming_no = fields.Char('编程单号')
@@ -27,6 +50,45 @@ class MrpProduction(models.Model):
programming_state = fields.Char('编程状态') programming_state = fields.Char('编程状态')
glb_file = fields.Binary("glb模型文件") glb_file = fields.Binary("glb模型文件")
@api.depends(
'move_raw_ids.state', 'move_raw_ids.quantity_done', 'move_finished_ids.state',
'workorder_ids.state', 'product_qty', 'qty_producing', 'schedule_state')
def _compute_state(self):
for production in self:
if not production.state or not production.product_uom_id:
production.state = 'draft'
elif production.state == 'cancel' or (production.move_finished_ids and all(
move.state == 'cancel' for move in production.move_finished_ids)):
production.state = 'cancel'
elif (
production.state == 'done'
or (production.move_raw_ids and all(
move.state in ('cancel', 'done') for move in production.move_raw_ids))
and all(move.state in ('cancel', 'done') for move in production.move_finished_ids)
):
production.state = 'done'
elif production.workorder_ids and all(
wo_state in ('done', 'cancel') for wo_state in production.workorder_ids.mapped('state')):
production.state = 'to_close'
elif not production.workorder_ids and float_compare(production.qty_producing, production.product_qty,
precision_rounding=production.product_uom_id.rounding) >= 0:
production.state = 'to_close'
elif any(wo_state in ('progress', 'done') for wo_state in production.workorder_ids.mapped('state')):
production.state = 'progress'
elif production.product_uom_id and not float_is_zero(production.qty_producing,
precision_rounding=production.product_uom_id.rounding):
production.state = 'progress'
elif any(not float_is_zero(move.quantity_done,
precision_rounding=move.product_uom.rounding or move.product_id.uom_id.rounding)
for move in production.move_raw_ids):
production.state = 'progress'
# 新添加的状态逻辑
if production.state == 'progress' and production.schedule_state == '已排':
production.state = 'pending_processing'
elif production.state == 'progress' and production.schedule_state == '已完成':
production.state = 'completed'
def action_check(self): def action_check(self):
""" """
审核启用 审核启用

View File

@@ -28,9 +28,9 @@
<xpath expr="//field[@name='production_real_duration']" position="after"> <xpath expr="//field[@name='production_real_duration']" position="after">
<field name="reservation_state" optional="hide" decoration-danger="reservation_state == 'confirmed'" decoration-success="reservation_state == 'assigned'"/> <field name="reservation_state" optional="hide" decoration-danger="reservation_state == 'confirmed'" decoration-success="reservation_state == 'assigned'"/>
</xpath> </xpath>
<xpath expr="//field[@name='state']" position="before"> <!-- <xpath expr="//field[@name='state']" position="before"> -->
<field name="schedule_state" optional="show"/> <!-- <field name="schedule_state" optional="show"/> -->
</xpath> <!-- </xpath> -->
<xpath expr="//field[@name='activity_ids']" position="replace"> <xpath expr="//field[@name='activity_ids']" position="replace">
<field name="activity_ids" string="下一个活动" widget="list_activity" optional="hide"/> <field name="activity_ids" string="下一个活动" widget="list_activity" optional="hide"/>
</xpath> </xpath>
@@ -58,6 +58,9 @@
<field name="model">mrp.production</field> <field name="model">mrp.production</field>
<field name="inherit_id" ref="mrp.mrp_production_form_view"/> <field name="inherit_id" ref="mrp.mrp_production_form_view"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//field[@name='state']" position="attributes">
<attribute name="statusbar_visible">draft,confirmed,progress,pending_processing,completed,done</attribute>
</xpath>
<xpath expr="//form//header//button[@name='action_confirm']" position="after"> <xpath expr="//form//header//button[@name='action_confirm']" position="after">
<field name="active" invisible="1"/> <field name="active" invisible="1"/>
<field name="check_status" invisible="1"/> <field name="check_status" invisible="1"/>

View File

@@ -2,3 +2,4 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details. # Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import models from . import models
from . import wizard

View File

@@ -17,8 +17,10 @@
'data': [ 'data': [
'security/ir.model.access.csv', 'security/ir.model.access.csv',
# 'security/rules.xml', # 'security/rules.xml',
'wizard/action_plan_some.xml',
'views/view.xml', 'views/view.xml',
'views/change_manufactuing.xml' 'views/change_manufactuing.xml',
], ],
'assets': { 'assets': {

View File

@@ -12,14 +12,30 @@ class sf_production_plan(models.Model):
_name = 'sf.production.plan' _name = 'sf.production.plan'
_description = 'sf_production_plan' _description = 'sf_production_plan'
_inherit = ['mail.thread'] _inherit = ['mail.thread']
_order = 'create_date desc' # _order = 'state desc, write_date desc'
state = fields.Selection([ state = fields.Selection([
('draft', '待排程'), ('draft', '待排程'),
('done', '已排程'), ('done', '已排程'),
('processing', '加工'), ('processing', '加工'),
('finished', '已完成') ('finished', '已完成')
], string='工单状态', tracking=True) ], string='工单状态', tracking=True)
state_order = fields.Integer(compute='_compute_state_order', store=True)
@api.depends('state')
def _compute_state_order(self):
order_mapping = {
'draft': 1,
'done': 2,
'processing': 3,
'finished': 4
}
for record in self:
record.state_order = order_mapping.get(record.state, 0)
_order = 'state_order asc, write_date desc'
name = fields.Char(string='工单编号') name = fields.Char(string='工单编号')
active = fields.Boolean(string='已归档', default=True) active = fields.Boolean(string='已归档', default=True)
# selected = fields.Boolean(default=False) # selected = fields.Boolean(default=False)
@@ -51,6 +67,11 @@ class sf_production_plan(models.Model):
sequence = fields.Integer(string='序号', copy=False, readonly=True, index=True) sequence = fields.Integer(string='序号', copy=False, readonly=True, index=True)
current_operation_name = fields.Char(string='当前工序名称', size=64, default='生产计划') current_operation_name = fields.Char(string='当前工序名称', size=64, default='生产计划')
@api.onchange('state')
def _onchange_state(self):
if self.state == 'finished':
self.production_id.schedule_state = '已完成'
# @api.model # @api.model
# def _search(self, args, offset=0, limit=None, order=None, count=False, access_rights_uid=None): # def _search(self, args, offset=0, limit=None, order=None, count=False, access_rights_uid=None):
# """ # """
@@ -252,6 +273,7 @@ class sf_production_plan(models.Model):
def cancel_production_schedule(self): def cancel_production_schedule(self):
self.date_planned_finished = False self.date_planned_finished = False
self.state = 'draft' self.state = 'draft'
self.production_line_id = False
aa = self.env['mrp.production'].sudo().search([('name', '=', self.name)]) aa = self.env['mrp.production'].sudo().search([('name', '=', self.name)])
aa.schedule_state = '未排' aa.schedule_state = '未排'
return self.date_planned_finished return self.date_planned_finished

View File

@@ -1,3 +1,5 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_sf_production_plan,sf.production.plan,model_sf_production_plan,base.group_user,1,0,0,0 access_sf_production_plan,sf.production.plan,model_sf_production_plan,base.group_user,1,0,0,0
access_sf_production_plan_for_dispatch,sf.production.plan for dispatch,model_sf_production_plan,sf_base.group_plan_dispatch,1,1,1,0 access_sf_production_plan_for_dispatch,sf.production.plan for dispatch,model_sf_production_plan,sf_base.group_plan_dispatch,1,1,1,0
access_sf_action_plan_all_wizard,sf.action.plan.all.wizard,model_sf_action_plan_all_wizard,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_sf_production_plan sf.production.plan model_sf_production_plan base.group_user 1 0 0 0
3 access_sf_production_plan_for_dispatch sf.production.plan for dispatch model_sf_production_plan sf_base.group_plan_dispatch 1 1 1 0
4 access_sf_action_plan_all_wizard sf.action.plan.all.wizard model_sf_action_plan_all_wizard base.group_user 1 1 1 1
5

View File

@@ -5,11 +5,13 @@
<field name="name">sf.production.plan.tree</field> <field name="name">sf.production.plan.tree</field>
<field name="model">sf.production.plan</field> <field name="model">sf.production.plan</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="订单计划" editable="bottom"> <!-- <tree string="订单计划" editable="bottom"> -->
<tree string="订单计划">
<header> <header>
<button name="do_production_schedule" type="object" string="批量排程"/> <!-- <button name="do_production_schedule" type="object" string="批量排程"/> -->
<button string="批量排程" name="%(sf_plan.action_plan_some)d" type="action" class="btn-primary"/>
</header> </header>
<field name="state" widget="badge" decoration-warning="state == 'draft'" decoration-success="state == 'done'"/> <field name="state" widget="badge" decoration-warning="state == 'draft'" decoration-success="state == 'done'" decoration-info="state == 'processing'" decoration-danger="state == 'finished'"/>
<field name="name"/> <field name="name"/>
<field name="origin"/> <field name="origin"/>
<field name="order_deadline"/> <field name="order_deadline"/>

View File

@@ -0,0 +1 @@
from . import action_plan_some

View File

@@ -0,0 +1,65 @@
# -*- coding: utf-8 -*-
import base64
import logging
import os
from datetime import datetime
from odoo import fields, models
# from odoo.exceptions import ValidationError
from odoo.exceptions import UserError
_logger = logging.getLogger(__name__)
class Action_Plan_All_Wizard(models.TransientModel):
_name = 'sf.action.plan.all.wizard'
_description = u'排程向导'
# 选择生产线
production_line_id = fields.Many2one('sf.production.line', string=u'生产线', required=True)
# 接收传递过来的计划ID
plan_ids = fields.Many2many('sf.production.plan', string=u'计划ID')
# 确认排程按钮
def action_plan_all(self):
# 使用传递过来的计划ID
temp_plan_ids = self.plan_ids
# 在这里添加您的逻辑来处理这些ID
for plan in temp_plan_ids:
# 处理每个计划
# 比如更新计划状态、分配资源等
# 示例plan.state = 'scheduled'
print('处理计划:', plan.id)
# 拿到计划对象
plan_obj = self.env['sf.production.plan'].browse(plan.id)
plan_obj.production_line_id = self.production_line_id.id
plan_obj.do_production_schedule()
# plan_obj.state = 'done'
print('处理计划:', plan.id, '完成')
# # 获取当前生产线
# production_line_id = self.production_line_id
# # 获取当前生产线的所有生产订单
# production_order_ids = self.env['mrp.production'].search([('production_line_id', '=', production_line_id.id)])
# # 获取当前生产线的所有生产订单的id
# production_order_id_list = []
# for production_order_id in production_order_ids:
# production_order_id_list.append(production_order_id.id)
# # 获取当前生产线的所有生产订单的排程状态
# production_order_plan_state_list = []
# for production_order_id in production_order_ids:
# production_order_plan_state_list.append(production_order_id.plan_state)
# # 如果当前生产线的所有生产订单的排程状态都是已排程,则报错
# if all(production_order_plan_state == '已排程' for production_order_plan_state in production_order_plan_state_list):
# raise UserError('当前生产线的所有生产订单都已排程,请勿重复排程!')
# # 如果当前生产线的所有生产订单的排程状态都是未排程,则报错
# if all(production_order_plan_state == '未排程' for production_order_plan_state in production_order_plan_state_list):
# raise UserError('当前生产线的所有生产订单都未排程,请先排程!')
# # 如果当前生产线的所有生产订单的排程状态都是已完成,则报错
# if all(production_order_plan_state == '已完成' for production_order_plan_state in production_order_plan_state_list):
# raise UserError('当前生产线的所有生产订单都已完成,请勿重复排程!')
# # 如果当前生产线的所有生产订单的排程状态都是已取消,则报错
# if all(production_order_plan_state == '已取消' for production_order_plan_state in production_order_plan_state_list):
# raise UserError('当前生产线的所有生产订单都已取消,请勿重复排程!')
# # 如果当前生产线的所有生产订单的排程状态都是已暂停,则报错
# if all(production_order_plan_state == '已暂停' for production_order_plan_state in production

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="action_plan_some_form" model="ir.ui.view">
<field name="name">选择生产线</field>
<field name="model">sf.action.plan.all.wizard</field>
<field name="arch" type="xml">
<form>
<group>
<field name="production_line_id"/>
</group>
<footer>
<button string="确认排程" name="action_plan_all" type="object" class="btn-primary"/>
<!-- <button string="取消" class="btn-secondary" special="cancel"/> -->
<button string="取消" class="btn-primary" special="cancel"/>
</footer>
</form>
</field>
</record>
<record id="action_plan_some" model="ir.actions.act_window">
<field name="name">请选择要排程的生产线</field>
<field name="type">ir.actions.act_window</field>
<!-- <field name="res_model">up.select.wizard</field>-->
<field name="res_model">sf.action.plan.all.wizard</field>
<field name="view_mode">form</field>
<field name="view_id" ref="action_plan_some_form"/>
<field name="target">new</field>
<field name="context">{'default_plan_ids': active_ids}</field>
</record>
</odoo>

View File

@@ -39704,7 +39704,7 @@ msgstr "付款中"
#: model_terms:ir.ui.view,arch_db:quality.quality_alert_view_search #: model_terms:ir.ui.view,arch_db:quality.quality_alert_view_search
#: model_terms:ir.ui.view,arch_db:quality_control.quality_check_view_search #: model_terms:ir.ui.view,arch_db:quality_control.quality_check_view_search
msgid "In Progress" msgid "In Progress"
msgstr "进行中" msgstr "待排程"
#. module: stock #. module: stock
#: model:ir.model.fields,field_description:stock.field_stock_warehouse__in_type_id #: model:ir.model.fields,field_description:stock.field_stock_warehouse__in_type_id
@@ -112590,7 +112590,7 @@ msgstr ""
#: model:ir.model,name:sf_manufacturing.model_mrp_production #: model:ir.model,name:sf_manufacturing.model_mrp_production
#: model:ir.ui.menu,name:sf_plan.mrp_custom_menu #: model:ir.ui.menu,name:sf_plan.mrp_custom_menu
msgid "制造订单" msgid "制造订单"
msgstr "生产订单" msgstr "制造订单"
#. module: sf_plan #. module: sf_plan
#: model:ir.actions.act_window,name:sf_plan.sf_production_plan_action #: model:ir.actions.act_window,name:sf_plan.sf_production_plan_action

View File

@@ -11,15 +11,16 @@ function setTableWidth() {
const tbody_tr = dom.find('tbody').children('tr') const tbody_tr = dom.find('tbody').children('tr')
dom.find('thead').children('tr').children().each(function () { dom.find('thead').children('tr').children().each(function () {
$('#widthTest').text($(this).text()) $('#widthTest').text($(this).text())
const width = $('#widthTest').width() const width = $('#widthTest').width() + 10
const i = $(this).index() const i = $(this).index()
console.log(111)
tbody_tr.each(function () { tbody_tr.each(function () {
if($(this).children().length > 2) { if($(this).children().length > 2) {
$(this).children().eq(i).css('min-width', width + 'px') $(this).children().eq(i).css('min-width', width + 'px')
} }
}) })
}) })
const resizeEvent = new Event('resize');
window.dispatchEvent(resizeEvent);
} }
$(function () { $(function () {

View File

@@ -11,11 +11,7 @@
} }
.o_form_view .o_field_widget .o_list_renderer { .o_form_view .o_field_widget .o_list_renderer {
width: calc(100% - 64px) !important; width: 100%!important;
margin:0 auto; margin:0 auto;
overflow: auto; overflow: auto;
} }
.o_list_renderer .o_list_table tbody > tr > td:not(.o_list_record_selector).o_list_number {
text-align: left;
}