Compare commits
33 Commits
feature/修改
...
feature/67
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4615f1576f | ||
|
|
c8f1676de9 | ||
|
|
f165bec662 | ||
|
|
133eac4a5c | ||
|
|
9922402b3b | ||
|
|
0a79a4e336 | ||
|
|
00922e3674 | ||
|
|
2a330a4bd8 | ||
|
|
33647fa3e0 | ||
|
|
a2a652eea4 | ||
|
|
05c5c0ef81 | ||
|
|
35e80266d7 | ||
|
|
13d33488dc | ||
|
|
2c2fa87719 | ||
|
|
e7b312fb22 | ||
|
|
55cc4906ef | ||
|
|
d21e0c7fd9 | ||
|
|
61034c3424 | ||
|
|
10e995ec7f | ||
|
|
5c7e6e969f | ||
|
|
fb3bb8f1c0 | ||
|
|
9123aeaee8 | ||
|
|
e3af0bea3c | ||
|
|
2febc369bb | ||
|
|
6ee1c5f9a9 | ||
|
|
fa03b562a2 | ||
|
|
5f55c954d1 | ||
|
|
e0ca13b5b7 | ||
|
|
ceb7a02209 | ||
|
|
1c1d1a74ad | ||
|
|
7d46d00fd7 | ||
|
|
5a22402e7a | ||
|
|
e145e8a3a4 |
@@ -31,12 +31,20 @@ class PurchaseOrder(models.Model):
|
||||
|
||||
def button_cancel(self):
|
||||
"""
|
||||
将取消的采购订单关联的库存移动撤销
|
||||
1. 先将采购订单行与目标库存移动断开链接,避免采购单取消后,调拨单被调整为mts的问题
|
||||
2. 取消采购订单
|
||||
3. 将采购订单行与目标库存移动重新建立链接
|
||||
"""
|
||||
move_ids = self.order_line.move_dest_ids.filtered(lambda move: move.state != 'done' and not move.scrapped)
|
||||
created_purchase_request_line_ids = {}
|
||||
if self.order_line.move_dest_ids.created_purchase_request_line_id:
|
||||
move_ids = self.order_line.move_dest_ids.filtered(lambda move: move.state != 'done' and not move.scrapped)
|
||||
created_purchase_request_line_ids = {move.id: move.created_purchase_request_line_id for move in move_ids}
|
||||
self.order_line.write({'move_dest_ids': [(5, 0, 0)]})
|
||||
res =super(PurchaseOrder, self).button_cancel()
|
||||
if move_ids.mapped('created_purchase_request_line_id'):
|
||||
move_ids.write({'state': 'waiting', 'is_done': False})
|
||||
for move_id, created_purchase_request_line_id in created_purchase_request_line_ids.items():
|
||||
self.env['stock.move'].browse(move_id).created_purchase_request_line_id = created_purchase_request_line_id
|
||||
# if move_ids.mapped('created_purchase_request_line_id'):
|
||||
# move_ids.write({'state': 'waiting', 'is_done': False})
|
||||
return res
|
||||
|
||||
def write(self, vals):
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from . import controllers
|
||||
from . import models
|
||||
from . import wizard
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
from . import controllers
|
||||
@@ -1,37 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import logging
|
||||
import json
|
||||
from odoo import http, fields, models
|
||||
from odoo.http import request
|
||||
from odoo.addons.sf_base.controllers.controllers import MultiInheritController
|
||||
|
||||
|
||||
class SfPlanMrsConnect(http.Controller, MultiInheritController):
|
||||
|
||||
@http.route('/api/demand_plan/update_processing_time', type='json', auth='sf_token', methods=['GET', 'POST'],
|
||||
csrf=False,
|
||||
cors="*")
|
||||
def update_processing_time(self, **kw):
|
||||
"""
|
||||
根据模型id修改程序工时
|
||||
:param kw:
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
res = {'status': 1, 'message': '成功'}
|
||||
datas = request.httprequest.data
|
||||
ret = json.loads(datas)
|
||||
ret = json.loads(ret['result'])
|
||||
logging.info('根据模型id修改程序工时:%s' % ret)
|
||||
demand_plan = request.env['sf.production.demand.plan'].sudo().search(
|
||||
[('model_id', '=', ret['model_id'])])
|
||||
if demand_plan:
|
||||
demand_plan.write(
|
||||
{'processing_time': ret['total_estimated_time']})
|
||||
else:
|
||||
res = {'status': 0, 'message': '未查到该需求计划'}
|
||||
except Exception as e:
|
||||
logging.info('update_demand_paln error:%s' % e)
|
||||
res['status'] = -1
|
||||
res['message'] = '系统解析错误!'
|
||||
return json.JSONEncoder().encode(res)
|
||||
@@ -259,7 +259,9 @@ class SfProductionDemandPlan(models.Model):
|
||||
manufacturing_orders = record.sale_order_id.mrp_production_ids.filtered(
|
||||
lambda mo: mo.product_id == record.product_id)
|
||||
finished_orders = manufacturing_orders.filtered(lambda mo: mo.state == 'done')
|
||||
if len(finished_orders) >= record.product_uom_qty:
|
||||
sum_product_qty = sum(finished_orders.mapped('product_qty'))
|
||||
if finished_orders and float_compare(sum_product_qty, record.product_uom_qty,
|
||||
precision_rounding=record.product_id.uom_id.rounding) >= 0:
|
||||
end_dates = [
|
||||
workorder.date_finished for mo in finished_orders
|
||||
for workorder in mo.workorder_ids if workorder.date_finished
|
||||
@@ -361,7 +363,8 @@ class SfProductionDemandPlan(models.Model):
|
||||
)
|
||||
for order in purchase_orders
|
||||
)
|
||||
if total_purchase_quantity < record.product_uom_qty:
|
||||
if float_compare(total_purchase_quantity, record.product_uom_qty,
|
||||
precision_rounding=record.product_id.uom_id.rounding) == -1:
|
||||
pr_ids = self.env['purchase.request'].sudo().search(
|
||||
[('line_ids.product_id', 'in', raw_materials.ids), ('state', '!=', 'done')])
|
||||
outsourcing_purchase_request.extend(pr_ids.ids)
|
||||
@@ -378,7 +381,9 @@ class SfProductionDemandPlan(models.Model):
|
||||
)
|
||||
for order in purchase_orders
|
||||
)
|
||||
if total_purchase_quantity < record.product_uom_qty:
|
||||
|
||||
if float_compare(total_purchase_quantity, record.product_uom_qty,
|
||||
precision_rounding=record.product_id.uom_id.rounding) == -1:
|
||||
pr_ids = self.env['purchase.request'].sudo().search(
|
||||
[('origin', 'like', record.sale_order_id.name), ('state', '!=', 'done')])
|
||||
outsourcing_purchase_request.extend(pr_ids.ids)
|
||||
@@ -400,7 +405,9 @@ class SfProductionDemandPlan(models.Model):
|
||||
)
|
||||
for order in product_purchase_orders
|
||||
)
|
||||
if total_outsourcing_purchase_quantity / total_product_qty < record.product_uom_qty:
|
||||
quantity = total_outsourcing_purchase_quantity / total_product_qty
|
||||
if float_compare(quantity, record.product_uom_qty,
|
||||
precision_rounding=record.product_id.uom_id.rounding) == -1:
|
||||
purchase_request = self.env['purchase.request'].sudo().search(
|
||||
[('line_ids.product_id', 'in', bom_product_ids.ids),
|
||||
('line_ids.purchase_state', 'not in', ('purchase', 'done')), ('state', '!=', 'done')])
|
||||
|
||||
@@ -377,7 +377,11 @@ class Sf_Dashboard_Connect(http.Controller):
|
||||
line_list_obj = request.env['sf.production.line'].sudo().search([('name', 'ilike', 'CNC')])
|
||||
line_list = list(map(lambda x: x.name, line_list_obj))
|
||||
# print('line_list: %s' % line_list)
|
||||
res['LineList'] = line_list
|
||||
res['LineList'] = ['业绩总览']
|
||||
res['LineList'] += line_list
|
||||
res['LineList'].append('人工线下加工中心')
|
||||
# 增加“业绩总览”与“人工线下加工中心”
|
||||
|
||||
|
||||
except Exception as e:
|
||||
res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
|
||||
@@ -401,37 +405,55 @@ class Sf_Dashboard_Connect(http.Controller):
|
||||
|
||||
try:
|
||||
plan_obj = request.env['sf.production.plan'].sudo()
|
||||
production_obj = request.env['mrp.production'].sudo()
|
||||
# production_obj = request.env['mrp.production'].sudo()
|
||||
work_order_obj = request.env['mrp.workorder'].sudo()
|
||||
line_list = ast.literal_eval(kw['line_list'])
|
||||
|
||||
line_list_obj = request.env['sf.production.line'].sudo().search([('name', 'ilike', 'CNC')])
|
||||
cnc_line_list = list(map(lambda x: x.name, line_list_obj))
|
||||
# print('line_list: %s' % line_list)
|
||||
for line in line_list:
|
||||
|
||||
if line == '业绩总览':
|
||||
work_order_domain = [('routing_type', 'in', ['人工线下加工', 'CNC加工'])]
|
||||
plan_domain = []
|
||||
elif line == '人工线下加工中心':
|
||||
work_order_domain = [('routing_type', '=', '人工线下加工')]
|
||||
plan_domain = [('production_type', '=', '人工线下加工')]
|
||||
else:
|
||||
work_order_domain = [
|
||||
('production_line_id.name', '=', line),
|
||||
('routing_type', '=', 'CNC加工')
|
||||
]
|
||||
plan_domain = [('production_line_id.name', '=', line)]
|
||||
# # 工单计划量
|
||||
# plan_data_total_counts = production_obj.search_count(
|
||||
# [('production_line_id.name', '=', line), ('state', 'not in', ['cancel']),
|
||||
# ('active', '=', True)])
|
||||
|
||||
# 工单计划量切换为CNC工单
|
||||
plan_data_total_counts = work_order_obj.search_count(
|
||||
[('production_line_id.name', '=', line), ('id', '!=', 8061),
|
||||
('state', 'in', ['ready', 'progress', 'done']), ('routing_type', '=', 'CNC加工')])
|
||||
plan_data_total = work_order_obj.search(work_order_domain + [
|
||||
('id', '!=', 8061),
|
||||
('state', 'in', ['ready', 'progress', 'done'])
|
||||
])
|
||||
|
||||
plan_data_total_counts = sum(plan_data_total.mapped('qty_production'))
|
||||
|
||||
# # 工单完成量
|
||||
# plan_data_finish_counts = plan_obj.search_count(
|
||||
# [('production_line_id.name', '=', line), ('state', 'in', ['finished'])])
|
||||
|
||||
# 工单完成量切换为CNC工单
|
||||
plan_data_finish_counts = work_order_obj.search_count(
|
||||
[('production_line_id.name', '=', line),
|
||||
('state', 'in', ['done']), ('routing_type', '=', 'CNC加工')])
|
||||
plan_data_finish = work_order_obj.search(work_order_domain + [
|
||||
('state', 'in', ['done'])
|
||||
])
|
||||
|
||||
plan_data_finish_counts = sum(plan_data_finish.mapped('qty_produced'))
|
||||
|
||||
# 超期完成量
|
||||
# 搜索所有已经完成的工单
|
||||
plan_data_overtime = work_order_obj.search([
|
||||
('production_line_id.name', '=', line),
|
||||
('state', 'in', ['done']),
|
||||
('routing_type', '=', 'CNC加工')
|
||||
plan_data_overtime = work_order_obj.search(work_order_domain + [
|
||||
('state', 'in', ['done'])
|
||||
])
|
||||
|
||||
# 使用 filtered 进行字段比较
|
||||
@@ -440,36 +462,38 @@ class Sf_Dashboard_Connect(http.Controller):
|
||||
)
|
||||
|
||||
# 获取数量
|
||||
plan_data_overtime_counts = len(plan_data_overtime_counts)
|
||||
# plan_data_overtime_counts = len(plan_data_overtime_counts)
|
||||
plan_data_overtime_counts = sum(plan_data_overtime_counts.mapped('qty_produced'))
|
||||
|
||||
# 查找符合条件的生产计划记录
|
||||
plan_data = plan_obj.search([
|
||||
('production_line_id.name', '=', line),
|
||||
])
|
||||
# plan_data = plan_obj.search(plan_domain)
|
||||
|
||||
# 过滤出那些检测结果状态为 '返工' 或 '报废' 的记录
|
||||
# faulty_plans = plan_data.filtered(lambda p: any(
|
||||
# result.test_results in ['返工', '报废'] for result in p.production_id.detection_result_ids
|
||||
# ))
|
||||
|
||||
faulty_plans = request.env['quality.check'].sudo().search([
|
||||
('operation_id.name', '=', 'CNC加工'),
|
||||
('quality_state', 'in', ['fail'])
|
||||
faulty_plans = work_order_obj.search(work_order_domain + [
|
||||
('state', 'in', ['scrap', 'rework'])
|
||||
])
|
||||
|
||||
# 查找制造订单取消与归档的数量
|
||||
cancel_order_count = production_obj.search_count(
|
||||
[('production_line_id.name', '=', line), ('state', 'in', ['cancel']),
|
||||
('active', '=', False)])
|
||||
# cancel_order_count = production_obj.search_count(
|
||||
# [('production_line_id.name', '=', line), ('state', 'in', ['cancel']),
|
||||
# ('active', '=', False)])
|
||||
|
||||
# 计算符合条件的记录数量
|
||||
# plan_data_fault_counts = len(faulty_plans) + cancel_order_count
|
||||
plan_data_fault_counts = len(faulty_plans)
|
||||
# plan_data_fault_counts = len(faulty_plans)
|
||||
plan_data_fault_counts = sum(faulty_plans.mapped('qty_produced'))
|
||||
|
||||
# 工单返工数量
|
||||
|
||||
plan_data_rework_counts = plan_obj.search_count(
|
||||
[('production_line_id.name', '=', line), ('production_id.state', 'in', ['rework'])])
|
||||
plan_data_rework = work_order_obj.search(work_order_domain + [
|
||||
('state', 'in', ['rework'])
|
||||
])
|
||||
|
||||
plan_data_rework_counts = sum(plan_data_rework.mapped('qty_produced'))
|
||||
|
||||
# 工单完成率
|
||||
finishe_rate = round(
|
||||
@@ -479,8 +503,9 @@ class Sf_Dashboard_Connect(http.Controller):
|
||||
plan_data_progress_deviation = plan_data_total_counts - plan_data_finish_counts - plan_data_fault_counts
|
||||
|
||||
# 完成记录
|
||||
plan_data_finish_orders = plan_obj.search(
|
||||
[('production_line_id.name', '=', line), ('state', 'in', ['finished'])])
|
||||
plan_data_finish_orders = plan_obj.search(plan_domain + [
|
||||
('state', 'in', ['finished'])
|
||||
])
|
||||
|
||||
# # 检测量
|
||||
# detection_nums = 0
|
||||
@@ -534,25 +559,25 @@ class Sf_Dashboard_Connect(http.Controller):
|
||||
delay_rate = round((delay_num / plan_data_finish_counts if plan_data_finish_counts > 0 else 0), 3)
|
||||
on_time_rate = 1 - delay_rate
|
||||
|
||||
if plan_data:
|
||||
data = {
|
||||
'plan_data_total_counts': plan_data_total_counts,
|
||||
'plan_data_finish_counts': plan_data_finish_counts,
|
||||
'plan_data_plan_counts': plan_data_total_counts,
|
||||
'plan_data_fault_counts': plan_data_fault_counts,
|
||||
'nopass_orders_counts': detection_data - len(pass_nums),
|
||||
'finishe_rate': finishe_rate,
|
||||
'plan_data_progress_deviation': plan_data_progress_deviation,
|
||||
'plan_data_rework_counts': plan_data_rework_counts,
|
||||
'on_time_rate': on_time_rate,
|
||||
# 'detection_data': detection_data,
|
||||
'detection_data': plan_data_finish_counts,
|
||||
'pass_rate': (plan_data_finish_counts - plan_data_fault_counts) / plan_data_finish_counts,
|
||||
'plan_data_overtime_counts': plan_data_overtime_counts,
|
||||
'overtime_rate': plan_data_overtime_counts / plan_data_finish_counts
|
||||
if plan_data_finish_counts > 0 else 0,
|
||||
}
|
||||
res['data'][line] = data
|
||||
# if plan_data:
|
||||
data = {
|
||||
'plan_data_total_counts': plan_data_total_counts,
|
||||
'plan_data_finish_counts': plan_data_finish_counts,
|
||||
'plan_data_plan_counts': plan_data_total_counts,
|
||||
'plan_data_fault_counts': plan_data_fault_counts,
|
||||
'nopass_orders_counts': detection_data - len(pass_nums),
|
||||
'finishe_rate': finishe_rate,
|
||||
'plan_data_progress_deviation': plan_data_progress_deviation,
|
||||
'plan_data_rework_counts': plan_data_rework_counts,
|
||||
'on_time_rate': on_time_rate,
|
||||
# 'detection_data': detection_data,
|
||||
'detection_data': plan_data_finish_counts,
|
||||
'pass_rate': (plan_data_finish_counts - plan_data_fault_counts) / plan_data_finish_counts,
|
||||
'plan_data_overtime_counts': plan_data_overtime_counts,
|
||||
'overtime_rate': plan_data_overtime_counts / plan_data_finish_counts
|
||||
if plan_data_finish_counts > 0 else 0,
|
||||
}
|
||||
res['data'][line] = data
|
||||
|
||||
return json.dumps(res) # 注意使用 json.dumps 而不是直接用 json.JSONEncoder().encode()
|
||||
|
||||
@@ -576,8 +601,11 @@ class Sf_Dashboard_Connect(http.Controller):
|
||||
line_list = ast.literal_eval(kw['line_list'])
|
||||
begin_time_str = kw['begin_time'].strip('"')
|
||||
end_time_str = kw['end_time'].strip('"')
|
||||
begin_time = datetime.strptime(begin_time_str, '%Y-%m-%d %H:%M:%S')
|
||||
end_time = datetime.strptime(end_time_str, '%Y-%m-%d %H:%M:%S')
|
||||
# 将时间减去8小时(UTC+8转UTC)
|
||||
begin_time = (datetime.strptime(begin_time_str, '%Y-%m-%d %H:%M:%S') - timedelta(hours=8))
|
||||
end_time = (datetime.strptime(end_time_str, '%Y-%m-%d %H:%M:%S') - timedelta(hours=8))
|
||||
# begin_time = datetime.strptime(begin_time_str, '%Y-%m-%d %H:%M:%S')
|
||||
# end_time = datetime.strptime(end_time_str, '%Y-%m-%d %H:%M:%S')
|
||||
# print('line_list: %s' % line_list)
|
||||
print('kw', kw)
|
||||
time_unit = kw.get('time_unit', 'day').strip('"') # 默认单位为天
|
||||
@@ -608,16 +636,43 @@ class Sf_Dashboard_Connect(http.Controller):
|
||||
date_list.append(current_date)
|
||||
current_date += timedelta(days=1)
|
||||
return date_list
|
||||
|
||||
|
||||
for line in line_list:
|
||||
date_field_name = 'date_finished' # 替换为你模型中的实际字段名
|
||||
order_counts = []
|
||||
if time_unit == 'hour':
|
||||
|
||||
if time_unit == 'hour':
|
||||
# 计划量,目前只能从mail.message中筛选出
|
||||
plan_order_messages = request.env['mail.message'].sudo().search([
|
||||
('model', '=', 'mrp.workorder'),
|
||||
('create_date', '>=', begin_time.strftime('%Y-%m-%d %H:%M:%S')),
|
||||
('create_date', '<=', end_time.strftime('%Y-%m-%d %H:%M:%S')),
|
||||
('tracking_value_ids.field_desc', '=', '状态'),
|
||||
('tracking_value_ids.new_value_char', '=', '就绪')
|
||||
])
|
||||
|
||||
for line in line_list:
|
||||
date_field_name = 'date_finished' # 替换为你模型中的实际字段名
|
||||
order_counts = []
|
||||
|
||||
if line == '业绩总览':
|
||||
work_order_domain = [('routing_type', 'in', ['人工线下加工', 'CNC加工'])]
|
||||
elif line == '人工线下加工中心':
|
||||
work_order_domain = [('routing_type', '=', '人工线下加工')]
|
||||
else:
|
||||
work_order_domain = [
|
||||
('production_line_id.name', '=', line),
|
||||
('routing_type', '=', 'CNC加工')
|
||||
]
|
||||
time_intervals = get_time_intervals(begin_time, end_time, time_unit)
|
||||
print('============================= %s' % time_intervals)
|
||||
|
||||
time_count_dict = {}
|
||||
plan_count_dict = {}
|
||||
|
||||
orders = request.env['mrp.workorder'].sudo().search(work_order_domain + [
|
||||
('state', 'in', ['done']),
|
||||
(date_field_name, '>=', begin_time.strftime('%Y-%m-%d %H:%M:%S')),
|
||||
(date_field_name, '<=', end_time.strftime('%Y-%m-%d %H:%M:%S'))
|
||||
])
|
||||
|
||||
for time_interval in time_intervals:
|
||||
start_time, end_time = time_interval
|
||||
@@ -629,66 +684,106 @@ class Sf_Dashboard_Connect(http.Controller):
|
||||
# (date_field_name, '<=', end_time.strftime('%Y-%m-%d %H:%M:%S')) # 包括结束时间
|
||||
# ])
|
||||
|
||||
orders = request.env['mrp.workorder'].sudo().search([
|
||||
('routing_type', '=', 'CNC加工'), # 将第一个条件合并进来
|
||||
('production_line_id.name', '=', line),
|
||||
('state', 'in', ['done']),
|
||||
(date_field_name, '>=', start_time.strftime('%Y-%m-%d %H:%M:%S')),
|
||||
(date_field_name, '<=', end_time.strftime('%Y-%m-%d %H:%M:%S'))
|
||||
])
|
||||
interval_orders = orders.filtered(
|
||||
lambda o: o[date_field_name] >= start_time
|
||||
and o[date_field_name] <= end_time
|
||||
)
|
||||
|
||||
# 使用小时和分钟作为键,确保每个小时的数据有独立的键
|
||||
key = start_time.strftime('%H:%M:%S') # 只取小时:分钟:秒作为键
|
||||
time_count_dict[key] = len(orders)
|
||||
key = (start_time + timedelta(hours=8)).strftime('%H:%M:%S') # 只取小时:分钟:秒作为键
|
||||
# time_count_dict[key] = len(orders)
|
||||
time_count_dict[key] = sum(interval_orders.mapped('qty_produced'))
|
||||
|
||||
for time_interval in time_intervals:
|
||||
start_time, end_time = time_interval
|
||||
|
||||
# orders = plan_obj.search([
|
||||
# ('production_line_id.name', '=', line),
|
||||
# ('state', 'in', ['done']),
|
||||
# (date_field_name, '>=', start_time.strftime('%Y-%m-%d %H:%M:%S')),
|
||||
# (date_field_name, '<=', end_time.strftime('%Y-%m-%d %H:%M:%S')) # 包括结束时间
|
||||
# ])
|
||||
|
||||
interval_plan_orders = plan_order_messages.filtered(
|
||||
lambda o: o.create_date >= start_time
|
||||
and o.create_date <= end_time
|
||||
)
|
||||
|
||||
interval_order_ids = set(interval_plan_orders.mapped('res_id'))
|
||||
|
||||
interval_orders = request.env['mrp.workorder'].sudo().browse(interval_order_ids)
|
||||
if line == '业绩总览':
|
||||
interval_orders = interval_orders.filtered(lambda o: o.routing_type in ['人工线下加工', 'CNC加工'])
|
||||
elif line == '人工线下加工中心':
|
||||
interval_orders = interval_orders.filtered(lambda o: o.routing_type == '人工线下加工')
|
||||
else:
|
||||
interval_orders = interval_orders.filtered(lambda o: o.routing_type == 'CNC加工' and o.production_line_id.name == line)
|
||||
|
||||
# 使用小时和分钟作为键,确保每个小时的数据有独立的键
|
||||
key = (start_time + timedelta(hours=8)).strftime('%H:%M:%S') # 只取小时:分钟:秒作为键
|
||||
# time_count_dict[key] = len(orders)
|
||||
plan_count_dict[key] = sum(interval_orders.mapped('qty_production'))
|
||||
|
||||
# order_counts.append()
|
||||
res['data'][line] = {
|
||||
'finish_order_nums': time_count_dict,
|
||||
'plan_order_nums': 28
|
||||
'plan_order_nums': plan_count_dict
|
||||
}
|
||||
return json.dumps(res)
|
||||
else:
|
||||
|
||||
date_list = get_date_list(begin_time, end_time)
|
||||
for line in line_list:
|
||||
date_field_name = 'date_finished' # 替换为你模型中的实际字段名
|
||||
order_counts = []
|
||||
|
||||
for date in date_list:
|
||||
next_day = date + timedelta(days=1)
|
||||
orders = request.env['mrp.workorder'].sudo().search(
|
||||
[('production_id.production_line_id.name', '=', line), ('state', 'in', ['done']),
|
||||
('routing_type', '=', 'CNC加工'),
|
||||
(date_field_name, '>=', date.strftime('%Y-%m-%d 00:00:00')),
|
||||
(date_field_name, '<', next_day.strftime('%Y-%m-%d 00:00:00'))
|
||||
])
|
||||
if line == '业绩总览':
|
||||
work_order_domain = [('routing_type', 'in', ['人工线下加工', 'CNC加工'])]
|
||||
elif line == '人工线下加工中心':
|
||||
work_order_domain = [('routing_type', '=', '人工线下加工')]
|
||||
else:
|
||||
work_order_domain = [
|
||||
('production_line_id.name', '=', line),
|
||||
('routing_type', '=', 'CNC加工')
|
||||
]
|
||||
|
||||
rework_orders = request.env['mrp.workorder'].sudo().search(
|
||||
[('production_id.production_line_id.name', '=', line), ('state', 'in', ['rework']),
|
||||
('routing_type', '=', 'CNC加工'),
|
||||
(date_field_name, '>=', date.strftime('%Y-%m-%d 00:00:00')),
|
||||
(date_field_name, '<', next_day.strftime('%Y-%m-%d 00:00:00'))
|
||||
])
|
||||
not_passed_orders = request.env['mrp.workorder'].sudo().search(
|
||||
[('production_id.production_line_id.name', '=', line), ('state', 'in', ['scrap', 'cancel']),
|
||||
('routing_type', '=', 'CNC加工'),
|
||||
(date_field_name, '>=', date.strftime('%Y-%m-%d 00:00:00')),
|
||||
(date_field_name, '<', next_day.strftime('%Y-%m-%d 00:00:00'))
|
||||
])
|
||||
order_counts.append({
|
||||
'date': date.strftime('%Y-%m-%d'),
|
||||
'order_count': len(orders),
|
||||
'rework_orders': len(rework_orders),
|
||||
'not_passed_orders': len(not_passed_orders)
|
||||
})
|
||||
# 外面包一层,没什么是包一层不能解决的,包一层就能区分了,类似于包一层div
|
||||
# 外面包一层的好处是,可以把多个数据结构打包在一起,方便前端处理
|
||||
date_list = get_date_list(begin_time, end_time)
|
||||
|
||||
# date_list_dict = {line: order_counts}
|
||||
for date in date_list:
|
||||
next_day = date + timedelta(days=1)
|
||||
orders = request.env['mrp.workorder'].sudo().search(work_order_domain + [
|
||||
('state', 'in', ['done']),
|
||||
(date_field_name, '>=', date.strftime('%Y-%m-%d 00:00:00')),
|
||||
(date_field_name, '<', next_day.strftime('%Y-%m-%d 00:00:00'))
|
||||
])
|
||||
|
||||
res['data'][line] = order_counts
|
||||
rework_orders = request.env['mrp.workorder'].sudo().search(work_order_domain + [
|
||||
('state', 'in', ['rework']),
|
||||
(date_field_name, '>=', date.strftime('%Y-%m-%d 00:00:00')),
|
||||
(date_field_name, '<', next_day.strftime('%Y-%m-%d 00:00:00'))
|
||||
])
|
||||
not_passed_orders = request.env['mrp.workorder'].sudo().search(work_order_domain + [
|
||||
('state', 'in', ['scrap', 'cancel']),
|
||||
(date_field_name, '>=', date.strftime('%Y-%m-%d 00:00:00')),
|
||||
(date_field_name, '<', next_day.strftime('%Y-%m-%d 00:00:00'))
|
||||
])
|
||||
order_counts.append({
|
||||
'date': date.strftime('%Y-%m-%d'),
|
||||
'order_count': sum(orders.mapped('qty_produced')),
|
||||
'rework_orders': sum(rework_orders.mapped('qty_produced')),
|
||||
'not_passed_orders': sum(not_passed_orders.mapped('qty_produced'))
|
||||
})
|
||||
# 外面包一层,没什么是包一层不能解决的,包一层就能区分了,类似于包一层div
|
||||
# 外面包一层的好处是,可以把多个数据结构打包在一起,方便前端处理
|
||||
|
||||
# date_list_dict = {line: order_counts}
|
||||
|
||||
res['data'][line] = order_counts
|
||||
return json.dumps(res)
|
||||
|
||||
# 实时产量
|
||||
@http.route('/api/RealTimeProduct', type='http', auth='public', methods=['GET', 'POST'], csrf=False, cors="*")
|
||||
def RealTimeProduct(self, **kw):
|
||||
"""
|
||||
获取实时产量
|
||||
获取实时产量(作废)
|
||||
:param kw:
|
||||
:return:
|
||||
"""
|
||||
@@ -711,6 +806,21 @@ class Sf_Dashboard_Connect(http.Controller):
|
||||
|
||||
# 当班计划量
|
||||
for line in line_list:
|
||||
|
||||
if line == '业绩总览':
|
||||
work_order_domain = [('routing_type', 'in', ['人工线下加工', 'CNC加工'])]
|
||||
plan_domain = []
|
||||
elif line == '人工线下加工中心':
|
||||
work_order_domain = [('routing_type', '=', '人工线下加工')]
|
||||
plan_domain = [('production_type', '=', '人工线下加工')]
|
||||
else:
|
||||
work_order_domain = [
|
||||
('production_line_id.name', '=', line),
|
||||
('routing_type', '=', 'CNC加工')
|
||||
]
|
||||
plan_domain = [('production_line_id.name', '=', line)]
|
||||
|
||||
|
||||
plan_order_nums = plan_obj.search_count(
|
||||
[('production_line_id.name', '=', line), ('state', 'not in', ['draft']),
|
||||
('date_planned_start', '>=', begin_time),
|
||||
@@ -752,42 +862,72 @@ class Sf_Dashboard_Connect(http.Controller):
|
||||
:param kw:
|
||||
:return:
|
||||
"""
|
||||
|
||||
# res = {'status': 1, 'message': '成功', 'not_done_data': [], 'done_data': []}
|
||||
res = {'status': 1, 'message': '成功', 'data': {}}
|
||||
# 解决产品名称取到英文的问题
|
||||
request.update_context(lang='zh_CN')
|
||||
plan_obj = request.env['sf.production.plan'].sudo()
|
||||
work_order_obj = request.env['mrp.workorder'].sudo()
|
||||
# 获取mrp.workorder的state字段的selection内容
|
||||
state_dict = dict(request.env['mrp.workorder'].sudo()._fields['state'].selection)
|
||||
line_list = ast.literal_eval(kw['line_list'])
|
||||
begin_time_str = kw['begin_time'].strip('"')
|
||||
end_time_str = kw['end_time'].strip('"')
|
||||
begin_time = datetime.strptime(begin_time_str, '%Y-%m-%d %H:%M:%S')
|
||||
end_time = datetime.strptime(end_time_str, '%Y-%m-%d %H:%M:%S')
|
||||
# print('line_list: %s' % line_list)
|
||||
not_done_data = []
|
||||
done_data = []
|
||||
final_data = {}
|
||||
|
||||
# 获取当前时间,并计算24小时前的时间
|
||||
current_time = datetime.now()
|
||||
time_48_hours_ago = current_time - timedelta(hours=48)
|
||||
|
||||
# # 计划量,目前只能从mail.message中筛选出
|
||||
# plan_order_messages = request.env['mail.message'].sudo().search([
|
||||
# ('model', '=', 'mrp.workorder'),
|
||||
# ('create_date', '>=', time_48_hours_ago.strftime('%Y-%m-%d %H:%M:%S')),
|
||||
# ('tracking_value_ids.field_desc', '=', '状态'),
|
||||
# ('tracking_value_ids.new_value_char', 'in', ['就绪', '生产中'])
|
||||
# ])
|
||||
|
||||
for line in line_list:
|
||||
not_done_data = []
|
||||
done_data = []
|
||||
not_done_index = 1
|
||||
done_index = 1
|
||||
|
||||
if line == '业绩总览':
|
||||
work_order_domain = [('routing_type', 'in', ['人工线下加工', 'CNC加工'])]
|
||||
elif line == '人工线下加工中心':
|
||||
work_order_domain = [('routing_type', '=', '人工线下加工')]
|
||||
else:
|
||||
work_order_domain = [
|
||||
('production_line_id.name', '=', line),
|
||||
('routing_type', '=', 'CNC加工')
|
||||
]
|
||||
# 未完成订单
|
||||
# not_done_orders = plan_obj.search(
|
||||
# [('production_line_id.name', '=', line), ('state', 'not in', ['finished']),
|
||||
# ('production_id.state', 'not in', ['cancel', 'done']), ('active', '=', True)
|
||||
# ])
|
||||
not_done_orders = request.env['mrp.workorder'].sudo().search(
|
||||
[('production_line_id.name', '=', line), ('state', 'in', ['ready', 'progress']),
|
||||
('routing_type', '=', 'CNC加工')
|
||||
])
|
||||
not_done_orders = work_order_obj.search(work_order_domain + [
|
||||
('state', 'in', ['ready', 'progress']),
|
||||
('date_planned_start', '>=', time_48_hours_ago),
|
||||
('date_planned_start', '<=', current_time)
|
||||
], order='id asc'
|
||||
)
|
||||
|
||||
# 完成订单
|
||||
# 获取当前时间,并计算24小时前的时间
|
||||
current_time = datetime.now()
|
||||
time_24_hours_ago = current_time - timedelta(hours=24)
|
||||
# current_time = datetime.now()
|
||||
# time_24_hours_ago = current_time - timedelta(hours=24)
|
||||
|
||||
finish_orders = plan_obj.search([
|
||||
('production_line_id.name', '=', line), ('state', 'in', ['finished']),
|
||||
('production_id.state', 'not in', ['cancel']), ('active', '=', True),
|
||||
('actual_end_time', '>=', time_24_hours_ago)
|
||||
])
|
||||
# print(finish_orders)
|
||||
finish_orders = work_order_obj.search(work_order_domain + [
|
||||
('state', 'in', ['done']),
|
||||
('production_id.state', 'not in', ['cancel']),
|
||||
('date_finished', '>=', time_48_hours_ago)
|
||||
], order='id asc')
|
||||
# logging.info('完成订单: %s' % finish_orders)
|
||||
|
||||
# 获取所有未完成订单的ID列表
|
||||
order_ids = [order.id for order in not_done_orders]
|
||||
@@ -795,14 +935,14 @@ class Sf_Dashboard_Connect(http.Controller):
|
||||
finish_order_ids = [order.id for order in finish_orders]
|
||||
|
||||
# 对ID进行排序
|
||||
sorted_order_ids = sorted(order_ids)
|
||||
# sorted_order_ids = sorted(order_ids)
|
||||
|
||||
finish_sorted_order_ids = sorted(finish_order_ids)
|
||||
# finish_sorted_order_ids = sorted(finish_order_ids)
|
||||
|
||||
# 创建ID与序号的对应关系
|
||||
id_to_sequence = {order_id: index + 1 for index, order_id in enumerate(sorted_order_ids)}
|
||||
# id_to_sequence = {order_id: index + 1 for index, order_id in enumerate(sorted_order_ids)}
|
||||
|
||||
finish_id_to_sequence = {order_id: index + 1 for index, order_id in enumerate(finish_sorted_order_ids)}
|
||||
# finish_id_to_sequence = {order_id: index + 1 for index, order_id in enumerate(finish_sorted_order_ids)}
|
||||
|
||||
# # 输出结果或进一步处理
|
||||
# for order_id, sequence in id_to_sequence.items():
|
||||
@@ -823,30 +963,21 @@ class Sf_Dashboard_Connect(http.Controller):
|
||||
material_match = re.search(material_pattern, blank_name)
|
||||
material = material_match.group(1) if material_match else 'No match found'
|
||||
|
||||
state_dict = {
|
||||
'draft': '待排程',
|
||||
'done': '已排程',
|
||||
'processing': '生产中',
|
||||
'finished': '已完成',
|
||||
'ready': '待加工',
|
||||
'progress': '生产中',
|
||||
}
|
||||
|
||||
line_dict = {
|
||||
'sequence': id_to_sequence[order.id],
|
||||
'sequence': not_done_index,
|
||||
'workorder_name': order.production_id.name,
|
||||
'blank_name': blank_name,
|
||||
'material': material,
|
||||
'dimensions': dimensions,
|
||||
'order_qty': 1,
|
||||
'order_qty': order.qty_production,
|
||||
'state': state_dict[order.state],
|
||||
|
||||
}
|
||||
not_done_data.append(line_dict)
|
||||
not_done_index += 1
|
||||
|
||||
for finish_order in finish_orders:
|
||||
if not finish_order.actual_end_time:
|
||||
continue
|
||||
blank_name = ''
|
||||
try:
|
||||
blank_name = finish_order.production_id.move_raw_ids[0].product_id.name
|
||||
@@ -861,17 +992,18 @@ class Sf_Dashboard_Connect(http.Controller):
|
||||
material = material_match.group(1) if material_match else 'No match found'
|
||||
|
||||
line_dict = {
|
||||
'sequence': finish_id_to_sequence[finish_order.id],
|
||||
'workorder_name': finish_order.name,
|
||||
'sequence': done_index,
|
||||
'workorder_name': finish_order.production_id.name,
|
||||
'blank_name': blank_name,
|
||||
'material': material,
|
||||
'dimensions': dimensions,
|
||||
'order_qty': finish_order.product_qty,
|
||||
'finish_time': finish_order.actual_end_time.strftime(
|
||||
'%Y-%m-%d %H:%M:%S') if finish_order.actual_end_time else ' '
|
||||
'order_qty': finish_order.qty_produced,
|
||||
'finish_time': finish_order.date_finished.strftime(
|
||||
'%Y-%m-%d %H:%M:%S') if finish_order.date_finished else ' '
|
||||
|
||||
}
|
||||
done_data.append(line_dict)
|
||||
done_index += 1
|
||||
|
||||
# 开始包一层
|
||||
res['data'][line] = {'not_done_data': not_done_data, 'done_data': done_data}
|
||||
|
||||
@@ -23,7 +23,6 @@ class sf_technology_design(models.Model):
|
||||
# def _compute_group_uniq_id(self):
|
||||
# for record in self:
|
||||
|
||||
|
||||
def json_technology_design_str(self, k, route, i, process_parameter):
|
||||
workorders_values_str = [0, '', {
|
||||
'route_id': route.id if route.routing_type in ['表面工艺'] else route.route_workcenter_id.id,
|
||||
@@ -36,11 +35,19 @@ class sf_technology_design(models.Model):
|
||||
return workorders_values_str
|
||||
|
||||
def write(self, vals):
|
||||
return super(sf_technology_design, self).write(vals)
|
||||
res = super(sf_technology_design, self).write(vals)
|
||||
if 'group_uniq_id' in vals or 'process_parameters_id' in vals or 'active' in vals:
|
||||
if self.production_id:
|
||||
process_parameters_id = self.production_id.technology_design_ids.mapped('process_parameters_id')
|
||||
if process_parameters_id.ids:
|
||||
self.production_id.product_id.model_process_parameters_ids = process_parameters_id.ids
|
||||
else:
|
||||
self.production_id.product_id.model_process_parameters_ids = None
|
||||
return res
|
||||
|
||||
def unlink_technology_design(self):
|
||||
self.active = False
|
||||
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for vals in vals_list:
|
||||
@@ -48,10 +55,12 @@ class sf_technology_design(models.Model):
|
||||
raise ValidationError(_("工序不能为空"))
|
||||
result = super(sf_technology_design, self).create(vals_list)
|
||||
for res in result:
|
||||
record = self.search([('production_id', '=', res.production_id.id), ('active', 'in', [True, False])], order='group_uniq_id desc', limit=1)
|
||||
res.group_uniq_id=record.group_uniq_id + 1
|
||||
record = self.search([('production_id', '=', res.production_id.id), ('active', 'in', [True, False])],
|
||||
order='group_uniq_id desc', limit=1)
|
||||
res.group_uniq_id = record.group_uniq_id + 1
|
||||
return result
|
||||
def get_duplicates_with_inactive(self,technology_designs):
|
||||
|
||||
def get_duplicates_with_inactive(self, technology_designs):
|
||||
# 统计每个 'sequence' 出现的次数
|
||||
sequence_count = Counter(technology_design.sequence for technology_design in technology_designs)
|
||||
|
||||
@@ -62,6 +71,7 @@ class sf_technology_design(models.Model):
|
||||
]
|
||||
|
||||
return result
|
||||
|
||||
# def rearrange_numbering(self,self_technology_designs):
|
||||
# inactive_designs = self.get_duplicates_with_inactive(self_technology_designs)
|
||||
# if inactive_designs:
|
||||
@@ -75,7 +85,7 @@ class sf_technology_design(models.Model):
|
||||
|
||||
def get_technology_design(self):
|
||||
return {
|
||||
'sequence':self.sequence,
|
||||
'sequence': self.sequence,
|
||||
'route_id': self.route_id.id,
|
||||
'process_parameters_id': self.process_parameters_id.id,
|
||||
'panel': self.panel,
|
||||
@@ -83,17 +93,19 @@ class sf_technology_design(models.Model):
|
||||
'time_cycle_manual': self.time_cycle_manual,
|
||||
'is_auto': self.is_auto,
|
||||
'active': self.active,
|
||||
'group_uniq_id':self.group_uniq_id,
|
||||
'group_uniq_id': self.group_uniq_id,
|
||||
}
|
||||
def sync_technology_designs(self,production_technology_designs, self_technology_designs):
|
||||
|
||||
def sync_technology_designs(self, production_technology_designs, self_technology_designs):
|
||||
production_id = production_technology_designs[0].production_id.id
|
||||
self_technology_design_dict = {item.group_uniq_id:item for item in self_technology_designs}
|
||||
production_technology_designs_dict = {item.group_uniq_id:item for item in production_technology_designs}
|
||||
self_technology_design_dict = {item.group_uniq_id: item for item in self_technology_designs}
|
||||
production_technology_designs_dict = {item.group_uniq_id: item for item in production_technology_designs}
|
||||
for technology_design in production_technology_designs:
|
||||
if not self_technology_design_dict.get(technology_design.group_uniq_id):
|
||||
technology_design.write({'production_id': False})
|
||||
else:
|
||||
technology_design.write(self_technology_design_dict.get(technology_design.group_uniq_id).get_technology_design())
|
||||
technology_design.write(
|
||||
self_technology_design_dict.get(technology_design.group_uniq_id).get_technology_design())
|
||||
for technology_design in self_technology_designs:
|
||||
if not production_technology_designs_dict.get(technology_design.group_uniq_id):
|
||||
technology_design = technology_design.get_technology_design()
|
||||
@@ -101,9 +113,8 @@ class sf_technology_design(models.Model):
|
||||
technology_design.pop('group_uniq_id')
|
||||
self.env['sf.technology.design'].create(technology_design)
|
||||
|
||||
|
||||
|
||||
def unified_procedure_multiple_work_orders(self,self_technology_designs,production_item):
|
||||
def unified_procedure_multiple_work_orders(self, self_technology_designs, production_item):
|
||||
technology_designs = self.env['sf.technology.design'].sudo().search(
|
||||
[('production_id', '=', production_item.id), ('active', 'in', [True, False])])
|
||||
self.sync_technology_designs(self_technology_designs=self_technology_designs,production_technology_designs=technology_designs)
|
||||
self.sync_technology_designs(self_technology_designs=self_technology_designs,
|
||||
production_technology_designs=technology_designs)
|
||||
|
||||
@@ -42,6 +42,12 @@ class Sf_Mrs_Connect(http.Controller, MultiInheritController):
|
||||
res = {'status': -2, 'message': '查询到待工艺确认的制造订单'}
|
||||
return json.JSONEncoder().encode(res)
|
||||
if productions:
|
||||
# 修改需求计划中的程序工时
|
||||
demand_plan = request.env['sf.production.demand.plan'].with_user(
|
||||
request.env.ref("base.user_admin")).search([('model_id', '=', ret['folder_name'])])
|
||||
if demand_plan and ret['total_estimated_time']:
|
||||
demand_plan.write(
|
||||
{'processing_time': ret['total_estimated_time']})
|
||||
|
||||
# 拉取所有加工面的程序文件
|
||||
for r in ret['processing_panel'].split(','):
|
||||
|
||||
Reference in New Issue
Block a user