548 lines
30 KiB
Python
548 lines
30 KiB
Python
# -*- coding: utf-8 -*-
|
|
import base64
|
|
import logging
|
|
from re import findall as regex_findall
|
|
from datetime import datetime, timedelta
|
|
from re import split as regex_split
|
|
import requests
|
|
from odoo import SUPERUSER_ID, _, api, fields, models
|
|
from odoo.tools import float_compare
|
|
from collections import defaultdict, namedtuple
|
|
from odoo.addons.stock.models.stock_rule import ProcurementException
|
|
from odoo.addons.sf_base.commons.common import Common
|
|
from odoo.exceptions import UserError
|
|
|
|
|
|
class StockRule(models.Model):
|
|
_inherit = 'stock.rule'
|
|
|
|
@api.model
|
|
def _run_pull(self, procurements):
|
|
moves_values_by_company = defaultdict(list)
|
|
mtso_products_by_locations = defaultdict(list)
|
|
|
|
# To handle the `mts_else_mto` procure method, we do a preliminary loop to
|
|
# isolate the products we would need to read the forecasted quantity,
|
|
# in order to to batch the read. We also make a sanitary check on the
|
|
# `location_src_id` field.
|
|
|
|
# list1 = []
|
|
# for item in procurements:
|
|
# num = int(item[0].product_qty)
|
|
# if num > 1:
|
|
# for no in range(1, num+1):
|
|
#
|
|
# Procurement = namedtuple('Procurement', ['product_id', 'product_qty',
|
|
# 'product_uom', 'location_id', 'name', 'origin',
|
|
# 'company_id',
|
|
# 'values'])
|
|
# s = Procurement(product_id=item[0].product_id,product_qty=1.0,product_uom=item[0].product_uom,
|
|
# location_id=item[0].location_id,
|
|
# name=item[0].name,
|
|
# origin=item[0].origin,
|
|
# company_id=item[0].company_id,
|
|
# values=item[0].values,
|
|
# )
|
|
# item1 = list(item)
|
|
# item1[0]=s
|
|
#
|
|
# list1.append(tuple(item1))
|
|
# else:
|
|
# list1.append(item)
|
|
|
|
for procurement, rule in procurements:
|
|
if not rule.location_src_id:
|
|
msg = _('No source location defined on stock rule: %s!') % (rule.name,)
|
|
raise ProcurementException([(procurement, msg)])
|
|
|
|
if rule.procure_method == 'mts_else_mto':
|
|
mtso_products_by_locations[rule.location_src_id].append(procurement.product_id.id)
|
|
|
|
# Get the forecasted quantity for the `mts_else_mto` procurement.
|
|
forecasted_qties_by_loc = {}
|
|
for location, product_ids in mtso_products_by_locations.items():
|
|
products = self.env['product.product'].browse(product_ids).with_context(location=location.id)
|
|
forecasted_qties_by_loc[location] = {product.id: product.free_qty for product in products}
|
|
|
|
# Prepare the move values, adapt the `procure_method` if needed.
|
|
procurements = sorted(procurements, key=lambda proc: float_compare(proc[0].product_qty, 0.0,
|
|
precision_rounding=proc[
|
|
0].product_uom.rounding) > 0)
|
|
list2 = []
|
|
for item in procurements:
|
|
num = int(item[0].product_qty)
|
|
|
|
product = self.env['product.product'].search(
|
|
[("id", '=', item[0].product_id.id)])
|
|
product_tmpl = self.env['product.template'].search(
|
|
["&", ("id", '=', product.product_tmpl_id.id), ('single_manufacturing', "!=", False)])
|
|
if product_tmpl:
|
|
if num > 1:
|
|
for no in range(1, num + 1):
|
|
Procurement = namedtuple('Procurement', ['product_id', 'product_qty',
|
|
'product_uom', 'location_id', 'name', 'origin',
|
|
'company_id',
|
|
'values'])
|
|
s = Procurement(product_id=item[0].product_id, product_qty=1.0, product_uom=item[0].product_uom,
|
|
location_id=item[0].location_id,
|
|
name=item[0].name,
|
|
origin=item[0].origin,
|
|
company_id=item[0].company_id,
|
|
values=item[0].values,
|
|
)
|
|
item1 = list(item)
|
|
item1[0] = s
|
|
|
|
list2.append(tuple(item1))
|
|
else:
|
|
list2.append(item)
|
|
else:
|
|
list2.append(item)
|
|
|
|
for procurement, rule in list2:
|
|
procure_method = rule.procure_method
|
|
if rule.procure_method == 'mts_else_mto':
|
|
qty_needed = procurement.product_uom._compute_quantity(procurement.product_qty,
|
|
procurement.product_id.uom_id)
|
|
if float_compare(qty_needed, 0, precision_rounding=procurement.product_id.uom_id.rounding) <= 0:
|
|
procure_method = 'make_to_order'
|
|
for move in procurement.values.get('group_id', self.env['procurement.group']).stock_move_ids:
|
|
if move.rule_id == rule and float_compare(move.product_uom_qty, 0,
|
|
precision_rounding=move.product_uom.rounding) > 0:
|
|
procure_method = move.procure_method
|
|
break
|
|
forecasted_qties_by_loc[rule.location_src_id][procurement.product_id.id] -= qty_needed
|
|
elif float_compare(qty_needed, forecasted_qties_by_loc[rule.location_src_id][procurement.product_id.id],
|
|
precision_rounding=procurement.product_id.uom_id.rounding) > 0:
|
|
procure_method = 'make_to_order'
|
|
else:
|
|
forecasted_qties_by_loc[rule.location_src_id][procurement.product_id.id] -= qty_needed
|
|
procure_method = 'make_to_stock'
|
|
|
|
move_values = rule._get_stock_move_values(*procurement)
|
|
move_values['procure_method'] = procure_method
|
|
moves_values_by_company[procurement.company_id.id].append(move_values)
|
|
|
|
for company_id, moves_values in moves_values_by_company.items():
|
|
# create the move as SUPERUSER because the current user may not have the rights to do it (mto product launched by a sale for example)
|
|
moves = self.env['stock.move'].with_user(SUPERUSER_ID).sudo().with_company(company_id).create(moves_values)
|
|
# Since action_confirm launch following procurement_group we should activate it.
|
|
moves._action_confirm()
|
|
|
|
return True
|
|
|
|
@api.model
|
|
def _run_manufacture(self, procurements):
|
|
productions_values_by_company = defaultdict(list)
|
|
errors = []
|
|
for procurement, rule in procurements:
|
|
if float_compare(procurement.product_qty, 0, precision_rounding=procurement.product_uom.rounding) <= 0:
|
|
# If procurement contains negative quantity, don't create a MO that would be for a negative value.
|
|
continue
|
|
bom = rule._get_matching_bom(procurement.product_id, procurement.company_id, procurement.values)
|
|
|
|
productions_values_by_company[procurement.company_id.id].append(rule._prepare_mo_vals(*procurement, bom))
|
|
|
|
if errors:
|
|
raise ProcurementException(errors)
|
|
|
|
for company_id, productions_values in productions_values_by_company.items():
|
|
# create the MO as SUPERUSER because the current user may not have the rights to do it (mto product launched by a sale for example)
|
|
'''创建制造订单'''
|
|
productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company(company_id).create(
|
|
productions_values)
|
|
|
|
self.env['stock.move'].sudo().create(productions._get_moves_raw_values())
|
|
self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
|
|
'''
|
|
创建工单
|
|
'''
|
|
productions._create_workorder()
|
|
|
|
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()
|
|
|
|
for production in productions:
|
|
'''
|
|
创建制造订单时生成序列号
|
|
'''
|
|
production.action_generate_serial()
|
|
origin_production = production.move_dest_ids and production.move_dest_ids[
|
|
0].raw_material_production_id or False
|
|
orderpoint = production.orderpoint_id
|
|
if orderpoint and orderpoint.create_uid.id == SUPERUSER_ID and orderpoint.trigger == 'manual':
|
|
production.message_post(
|
|
body=_('This production order has been created from Replenishment Report.'),
|
|
message_type='comment',
|
|
subtype_xmlid='mail.mt_note')
|
|
elif orderpoint:
|
|
production.message_post_with_view(
|
|
'mail.message_origin_link',
|
|
values={'self': production, 'origin': orderpoint},
|
|
subtype_id=self.env.ref('mail.mt_note').id)
|
|
elif origin_production:
|
|
production.message_post_with_view(
|
|
'mail.message_origin_link',
|
|
values={'self': production, 'origin': origin_production},
|
|
subtype_id=self.env.ref('mail.mt_note').id)
|
|
|
|
|
|
'''
|
|
创建生产计划
|
|
'''
|
|
# 工单耗时
|
|
workorder_duration = 0
|
|
for workorder in production.workorder_ids:
|
|
workorder_duration += workorder.duration_expected
|
|
|
|
sale_order = self.env['sale.order'].sudo().search([('name', '=', production.origin)])
|
|
if sale_order:
|
|
bb = sale_order.deadline_of_delivery
|
|
productions = self.env['sf.production.plan'].with_user(SUPERUSER_ID).sudo().with_company(company_id). \
|
|
create({
|
|
'name': production.name,
|
|
'order_deadline': sale_order.deadline_of_delivery,
|
|
'production_id': production.id,
|
|
'date_planned_start': production.date_planned_start,
|
|
'origin': production.origin,
|
|
'product_qty': production.product_qty,
|
|
'product_id': production.product_id.id,
|
|
'state': 'draft',
|
|
})
|
|
return True
|
|
|
|
|
|
class ProductionLot(models.Model):
|
|
_inherit = 'stock.lot'
|
|
|
|
@api.model
|
|
def generate_lot_names1(self, display_name, first_lot, count):
|
|
"""Generate `lot_names` from a string."""
|
|
if first_lot.__contains__(display_name):
|
|
first_lot = first_lot[(len(display_name) + 1):]
|
|
|
|
# We look if the first lot contains at least one digit.
|
|
caught_initial_number = regex_findall(r"\d+", first_lot)
|
|
if not caught_initial_number:
|
|
return self.generate_lot_names1(display_name, first_lot + "0", count)
|
|
# We base the series on the last number found in the base lot.
|
|
initial_number = caught_initial_number[-1]
|
|
padding = len(initial_number)
|
|
# We split the lot name to get the prefix and suffix.
|
|
splitted = regex_split(initial_number, first_lot)
|
|
# initial_number could appear several times, e.g. BAV023B00001S00001
|
|
prefix = initial_number.join(splitted[:-1])
|
|
suffix = splitted[-1]
|
|
initial_number = int(initial_number)
|
|
|
|
lot_names = []
|
|
for i in range(0, count):
|
|
lot_names.append('%s-%s%s%s' % (
|
|
display_name,
|
|
prefix,
|
|
str(initial_number + i).zfill(padding),
|
|
suffix
|
|
))
|
|
return lot_names
|
|
|
|
@api.model
|
|
def _get_next_serial(self, company, product):
|
|
"""Return the next serial number to be attributed to the product."""
|
|
if product.tracking == "serial":
|
|
last_serial = self.env['stock.lot'].search(
|
|
[('company_id', '=', company.id), ('product_id', '=', product.id)],
|
|
limit=1, order='id DESC')
|
|
if last_serial:
|
|
return self.env['stock.lot'].generate_lot_names1(product.name, last_serial.name, 2)[
|
|
1]
|
|
now = datetime.now().strftime("%Y-%m-%d")
|
|
# formatted_date = now.strftime("%Y-%m-%d")
|
|
if product.cutting_tool_model_id:
|
|
return "%s-%s-%03d" % (product.cutting_tool_model_id.code, now, 1)
|
|
return "%s-%03d" % (product.name, 1)
|
|
|
|
|
|
class StockPicking(models.Model):
|
|
_inherit = 'stock.picking'
|
|
|
|
workorder_in_id = fields.One2many('mrp.workorder', 'picking_in_id')
|
|
workorder_out_id = fields.One2many('mrp.workorder', 'picking_out_id')
|
|
|
|
# 设置外协出入单的名称
|
|
def _get_name_Res(self, rescode):
|
|
last_picking = self.sudo().search([('name', 'like', rescode)], order='create_date DESC', limit=1)
|
|
logging.info('编号:' + last_picking.name)
|
|
if not last_picking:
|
|
num = "%04d" % 1
|
|
else:
|
|
m = int(last_picking.name[-3:]) + 1
|
|
num = "%04d" % m
|
|
return '%s%s' % (rescode, num)
|
|
|
|
def button_validate(self):
|
|
# 出库单验证
|
|
if self.workorder_out_id:
|
|
workorder_in = self.workorder_out_id.filtered(lambda p: p.state == 'progress' and p.is_subcontract is True)
|
|
if workorder_in:
|
|
picking_in = self.sudo().search([('id', '=', workorder_in.picking_in_id.id)])
|
|
if picking_in:
|
|
picking_in.write({'state': 'assigned'})
|
|
else:
|
|
workorder_subcontract = self.workorder_out_id.filtered(
|
|
lambda p: p.state == 'pending' and p.is_subcontract is True)
|
|
if workorder_subcontract:
|
|
raise UserError(
|
|
_('该出库单里源单据内的单号为%s的工单还未开始,不能进行验证操作!' % workorder_subcontract[
|
|
0].name))
|
|
# 入库单验证
|
|
if self.workorder_in_id:
|
|
workorder_out = self.workorder_in_id.filtered(lambda p: p.state == 'progress' and p.is_subcontract is True)
|
|
if workorder_out:
|
|
picking_out = self.sudo().search([('id', '=', workorder_out.picking_out_id.id)])
|
|
if picking_out.state != 'done':
|
|
raise UserError(
|
|
_('该入库单对应的单号为%s的出库单还未完成,不能进行验证操作!' % picking_out.name))
|
|
|
|
res = super().button_validate()
|
|
# 采购单验证(夹具)
|
|
# for item in self.move_ids_without_package:
|
|
# if item.quantity_done > 0:
|
|
# if item.product_id.categ_type == '夹具':
|
|
# item._register_fixture()
|
|
# elif item.product_id.categ_type == '刀具':
|
|
# item._register_cutting_tool()
|
|
return res
|
|
|
|
# 创建 外协出库入单
|
|
def create_outcontract_picking(self, sorted_workorders_arr, item):
|
|
m = 0
|
|
for sorted_workorders in sorted_workorders_arr:
|
|
if m == 0:
|
|
outcontract_stock_move = self.env['stock.move'].search(
|
|
[('workorder_id', '=', sorted_workorders.id), ('production_id', '=', item.id)])
|
|
if not outcontract_stock_move:
|
|
location_id = self.env.ref(
|
|
'sf_manufacturing.stock_location_locations_virtual_outcontract').id,
|
|
location_dest_id = self.env['stock.location'].search(
|
|
[('barcode', '=', 'WH-PREPRODUCTION')]).id,
|
|
outcontract_picking_type_in = self.env.ref(
|
|
'sf_manufacturing.outcontract_picking_in').id,
|
|
outcontract_picking_type_out = self.env.ref(
|
|
'sf_manufacturing.outcontract_picking_out').id,
|
|
moves_in = self.env['stock.move'].sudo().create(
|
|
item._get_stock_move_values_Res(item, location_id, location_dest_id,
|
|
outcontract_picking_type_in))
|
|
moves_out = self.env['stock.move'].sudo().create(
|
|
item._get_stock_move_values_Res(item, location_dest_id, location_id,
|
|
outcontract_picking_type_out))
|
|
new_picking = True
|
|
picking_in = self.create(
|
|
moves_in._get_new_picking_values_Res(item, sorted_workorders, 'WH/OCIN/'))
|
|
picking_out = self.create(
|
|
moves_out._get_new_picking_values_Res(item, sorted_workorders, 'WH/OCOUT/'))
|
|
moves_in.write({'picking_id': picking_in.id, 'state': 'confirmed'})
|
|
moves_out.write({'picking_id': picking_out.id, 'state': 'confirmed'})
|
|
moves_in._assign_picking_post_process(new=new_picking)
|
|
moves_out._assign_picking_post_process(new=new_picking)
|
|
m += 1
|
|
sorted_workorders.write({'picking_in_id': picking_in.id, 'picking_out_id': picking_out.id})
|
|
|
|
|
|
class ReStockMove(models.Model):
|
|
_inherit = 'stock.move'
|
|
|
|
materiel_length = fields.Float(string='物料长度', digits=(16, 4))
|
|
materiel_width = fields.Float(string='物料宽度', digits=(16, 4))
|
|
materiel_height = fields.Float(string='物料高度', digits=(16, 4))
|
|
|
|
def _get_new_picking_values_Res(self, item, sorted_workorders, rescode):
|
|
logging.info('new_picking-rescode: %s' % rescode)
|
|
return {
|
|
'name': self.env['stock.picking']._get_name_Res(rescode),
|
|
'origin': item.name,
|
|
'company_id': self.mapped('company_id').id,
|
|
'user_id': False,
|
|
'move_type': self.mapped('group_id').move_type or 'direct',
|
|
'partner_id': sorted_workorders.supplier_id.id,
|
|
'picking_type_id': self.mapped('picking_type_id').id,
|
|
'location_id': self.mapped('location_id').id,
|
|
'location_dest_id': self.mapped('location_dest_id').id,
|
|
'state': 'confirmed',
|
|
}
|
|
|
|
# 将采购到的夹具注册到Cloud
|
|
def _register_fixture(self):
|
|
create_url = '/api/factory_fixture_material/create'
|
|
config = self.env['res.config.settings'].get_values()
|
|
headers = Common.get_headers(self, config['token'], config['sf_secret_key'])
|
|
strurl = config['sf_url'] + create_url
|
|
for item in self:
|
|
val = {
|
|
'token': config['token'],
|
|
'name': item.product_id.name,
|
|
'brand_code': self.env['sf.machine.brand'].search([('id', '=', item.product_id.brand_id.id)]).code,
|
|
'fixture_material_code': self.env['sf.fixture.material'].search(
|
|
[('id', '=', item.product_id.fixture_material_id.id)]).code,
|
|
'fixture_multi_mounting_type_code': self.env['sf.multi_mounting.type'].search(
|
|
[('id', '=', item.product_id.fixture_multi_mounting_type_id.id)]).code,
|
|
'fixture_materials_type_code': self.env['sf.materials.model'].search(
|
|
[('id', '=', item.product_id.materials_type_id.id)]).materials_no,
|
|
'fixture_clamping_way': item.product_id.fixture_clamping_way,
|
|
'fixture_port_type': item.product_id.fixture_port_type,
|
|
'fixture_length': item.product_id.tool_length,
|
|
'fixture_width': item.product_id.tool_width,
|
|
'fixture_height': item.product_id.tool_height,
|
|
'fixture_weight': item.product_id.tool_weight,
|
|
'fixture_amount': int(item.quantity_done),
|
|
'fixture_model_file': '' if not item.product_id.fixture_model_file else base64.b64encode(
|
|
item.product_id.fixture_model_file).decode(
|
|
'utf-8'),
|
|
'fixture_clamp_workpiece_length_max': item.product_id.fixture_clamp_workpiece_length_max,
|
|
'fixture_clamp_workpiece_width_max': item.product_id.fixture_clamp_workpiece_width_max,
|
|
'fixture_clamp_workpiece_height_max': item.product_id.fixture_clamp_workpiece_height_max,
|
|
'fixture_clamp_workpiece_diameter_max': item.product_id.fixture_clamp_workpiece_diameter_max,
|
|
'fixture_maximum_carrying_weight': item.product_id.fixture_maximum_carrying_weight,
|
|
'fixture_maximum_clamping_force': item.product_id.fixture_maximum_clamping_force,
|
|
'fixture_driving_way': '' if not item.product_id.fixture_driving_way else item.product_id.fixture_driving_way,
|
|
'fixture_apply_machine_tool_type_codes': self.env[
|
|
'product.template']._json_apply_machine_tool_type_item_code(item),
|
|
'fixture_through_hole_size': item.product_id.fixture_through_hole_size,
|
|
'fixture_screw_size': item.product_id.fixture_screw_size,
|
|
}
|
|
try:
|
|
if item.product_id.industry_code:
|
|
val['industry_code'] = item.product_id.industry_code
|
|
ret = requests.post(strurl, json={}, data=val, headers=headers)
|
|
ret = ret.json()
|
|
if ret['status'] == 200:
|
|
if not item.product_id.industry_code:
|
|
item.product_id.write({'register_state': '已注册', 'industry_code': ret['industry_code']})
|
|
else:
|
|
item.product_id.write({'register_state': '已注册'})
|
|
else:
|
|
item.product_id.write({'register_state': '注册失败'})
|
|
except Exception as e:
|
|
raise UserError("注册夹具到云端失败,请联系管理员!")
|
|
|
|
# 将采购到的刀具注册到Cloud
|
|
def _register_cutting_tool(self):
|
|
create_url = '/api/factory_cutting_tool_material/create'
|
|
config = self.env['res.config.settings'].get_values()
|
|
headers = Common.get_headers(self, config['token'], config['sf_secret_key'])
|
|
strurl = config['sf_url'] + create_url
|
|
for item in self:
|
|
val = {
|
|
'token': config['token'],
|
|
'name': item.product_id.name,
|
|
'brand_code': self.env['sf.machine.brand'].search([('id', '=', item.product_id.brand_id.id)]).code,
|
|
'cutting_tool_material_code': self.env['sf.cutting.tool.material'].search(
|
|
[('id', '=', item.product_id.cutting_tool_material_id.id)]).code,
|
|
'cutting_tool_type_code': self.env['sf.cutting.tool.type'].search(
|
|
[('id', '=', item.product_id.cutting_tool_type_id.id)]).code,
|
|
'material_model_code': self.env['sf.materials.model'].search(
|
|
[('id', '=', item.product_id.materials_type_id.id)]).materials_no,
|
|
'tool_length': item.product_id.tool_length,
|
|
'tool_width': item.product_id.tool_width,
|
|
'tool_height': item.product_id.tool_height,
|
|
'tool_thickness': item.product_id.tool_thickness,
|
|
'tool_weight': item.product_id.tool_weight,
|
|
'tool_hardness': item.product_id.tool_hardness,
|
|
'coating_material': item.product_id.coating_material,
|
|
'amount': int(item.quantity_done),
|
|
# 'model_file': '' if not item.product_id.fixture_model_file else base64.b64encode(
|
|
# item.product_id.fixture_model_file).decode(
|
|
# 'utf-8'),
|
|
'total_length': item.product_id.cutting_tool_total_length,
|
|
'shank_length': item.product_id.cutting_tool_shank_length,
|
|
'blade_length': item.product_id.cutting_tool_blade_length,
|
|
'neck_length': item.product_id.cutting_tool_neck_length,
|
|
'neck_diameter': item.product_id.cutting_tool_neck_diameter,
|
|
'shank_diameter': item.product_id.cutting_tool_shank_diameter,
|
|
'blade_tip_diameter': item.product_id.cutting_tool_blade_tip_diameter,
|
|
'blade_tip_taper': item.product_id.cutting_tool_blade_tip_taper,
|
|
'blade_helix_angle': item.product_id.cutting_tool_blade_helix_angle,
|
|
'blade_type': item.product_id.cutting_tool_blade_type,
|
|
'coarse_medium_fine': '' if item.product_id.cutting_tool_coarse_medium_fine is False else item.product_id.cutting_tool_coarse_medium_fine,
|
|
'run_out_accuracy_max': item.product_id.cutting_tool_run_out_accuracy_max,
|
|
'run_out_accuracy_min': item.product_id.cutting_tool_run_out_accuracy_min,
|
|
'head_diameter': item.product_id.cutting_tool_head_diameter,
|
|
'diameter': item.product_id.cutting_tool_diameter,
|
|
'blade_number': '' if item.product_id.cutting_tool_blade_number is False else item.product_id.cutting_tool_blade_number,
|
|
'front_angle': item.product_id.cutting_tool_front_angle,
|
|
'rear_angle': item.product_id.cutting_tool_rear_angle,
|
|
'main_included_angle': item.product_id.cutting_tool_main_included_angle,
|
|
'chuck_codes': self.env['product.template']._json_chuck_item_code(item),
|
|
'cutter_bar_codes': self.env['product.template']._json_cutter_bar_item_code(item),
|
|
'cutter_pad_codes': self.env['product.template']._json_cutter_pad_item_code(item),
|
|
'blade_codes': self.env['product.template']._json_blade_item_code(item),
|
|
'handle_codes': self.env['product.template']._json_handle_item_code(item),
|
|
'nut': item.product_id.cutting_tool_nut,
|
|
'top_angle': item.product_id.cutting_tool_top_angle,
|
|
'jump_accuracy': item.product_id.cutting_tool_jump_accuracy,
|
|
'working_hardness': item.product_id.cutting_tool_working_hardness,
|
|
'blade_diameter': item.product_id.cutting_tool_blade_diameter,
|
|
'wrench': item.product_id.cutting_tool_wrench,
|
|
'accuracy_level': item.product_id.cutting_tool_accuracy_level,
|
|
'clamping_way': item.product_id.cutting_tool_clamping_way,
|
|
'clamping_length': item.product_id.cutting_tool_clamping_length,
|
|
'clamping_tolerance': item.product_id.cutting_tool_clamping_tolerance,
|
|
'diameter_max': item.product_id.cutting_tool_diameter_max,
|
|
'clamping_diameter_min': item.product_id.cutting_tool_clamping_diameter_min,
|
|
'clamping_diameter_max': item.product_id.cutting_tool_clamping_diameter_max,
|
|
'detection_accuracy_max': item.product_id.cutting_tool_detection_accuracy_max,
|
|
'detection_accuracy_min': item.product_id.cutting_tool_detection_accuracy_min,
|
|
'is_rough_finish': item.product_id.cutting_tool_is_rough_finish,
|
|
'is_finish': item.product_id.cutting_tool_is_finish,
|
|
'is_drill_hole': item.product_id.cutting_tool_is_drill_hole,
|
|
'is_safety_lock': item.product_id.cutting_tool_is_safety_lock,
|
|
'is_high_speed_cutting': item.product_id.cutting_tool_is_high_speed_cutting,
|
|
'dynamic_balance_class': item.product_id.cutting_tool_dynamic_balance_class,
|
|
'change_time': item.product_id.cutting_tool_change_time,
|
|
'standard_speed': item.product_id.cutting_tool_standard_speed,
|
|
'speed_max': item.product_id.cutting_tool_speed_max,
|
|
'cooling_type': item.product_id.cutting_tool_cooling_type,
|
|
'body_accuracy': item.product_id.cutting_tool_body_accuracy,
|
|
'apply_lock_nut_model': item.product_id.apply_lock_nut_model,
|
|
'apply_lock_wrench_model': item.product_id.apply_lock_wrench_model,
|
|
'tool_taper': item.product_id.cutting_tool_taper,
|
|
'flange_length': item.product_id.cutting_tool_flange_length,
|
|
'flange_diameter': item.product_id.cutting_tool_flange_diameter,
|
|
'outer_diameter': item.product_id.cutting_tool_outer_diameter,
|
|
'inner_diameter': item.product_id.cutting_tool_inner_diameter,
|
|
'cooling_suit_type_ids': item.product_id.cooling_suit_type_ids,
|
|
'er_size_model': item.product_id.cutting_tool_er_size_model,
|
|
'image': '' if not item.product_id.image_1920 else base64.b64encode(item.product_id.image_1920).decode('utf-8'),
|
|
}
|
|
try:
|
|
if item.product_id.industry_code:
|
|
val['industry_code'] = item.product_id.industry_code
|
|
ret = requests.post(strurl, json={}, data=val, headers=headers)
|
|
ret = ret.json()
|
|
if ret['status'] == 200:
|
|
if not item.product_id.industry_code:
|
|
item.product_id.write({'register_state': '已注册', 'industry_code': ret['industry_code']})
|
|
else:
|
|
item.product_id.write({'register_state': '已注册'})
|
|
else:
|
|
item.product_id.write({'register_state': '注册失败'})
|
|
except Exception as e:
|
|
raise UserError("注册刀具到云端失败,请联系管理员!")
|
|
|
|
|
|
class ReStockQuant(models.Model):
|
|
_inherit = 'stock.quant'
|
|
|
|
def action_apply_inventory(self):
|
|
inventory_diff_quantity = self.inventory_diff_quantity
|
|
super(ReStockQuant, self).action_apply_inventory()
|
|
if inventory_diff_quantity >= 1:
|
|
stock = self.env['stock.move'].search([('product_id', '=', self.product_id.id), ('is_inventory', '=', True),
|
|
('reference', '=', '更新的产品数量'), ('state', '=', 'done')],
|
|
limit=1, order='id desc')
|
|
if self.product_id.categ_type == '夹具':
|
|
stock._register_fixture()
|
|
elif self.product_id.categ_type == '刀具':
|
|
stock._register_cutting_tool()
|
|
return True
|