diff --git a/jikimo_frontend/static/src/fields/Many2OneRadioField/many2one_radio_field.js b/jikimo_frontend/static/src/fields/Many2OneRadioField/many2one_radio_field.js index 836ee6d8..8c2be97f 100644 --- a/jikimo_frontend/static/src/fields/Many2OneRadioField/many2one_radio_field.js +++ b/jikimo_frontend/static/src/fields/Many2OneRadioField/many2one_radio_field.js @@ -11,24 +11,22 @@ export class Many2OneRadioField extends RadioField { // 你自己的代码 } - onImageClick(event) { // 放大图片逻辑 // 获取图片元素 const img = event.target; - const close = img.nextSibling - + const close = img.nextSibling; // 实现放大图片逻辑 // 比如使用 CSS 放大 img.parentElement.classList.add('zoomed'); - close.classList.add('img_close') + close.classList.add('img_close'); } onCloseClick(event) { const close = event.target; - const img = close.previousSibling - img.parentElement.classList.remove('zoomed') - close.classList.remove('img_close') + const img = close.previousSibling; + img.parentElement.classList.remove('zoomed'); + close.classList.remove('img_close'); } get items() { @@ -47,10 +45,9 @@ export class Many2OneRadioField extends RadioField { return []; } } - } -Many2OneRadioField.template = "jikimo_frontend.Many2OneRadioField" +Many2OneRadioField.template = "jikimo_frontend.Many2OneRadioField"; // MyCustomWidget.supportedTypes = ['many2many']; registry.category("fields").add("many2one_radio", Many2OneRadioField); diff --git a/jikimo_frontend/static/src/fields/custom_many2many_checkboxes/custom_many2many_checkboxes.js b/jikimo_frontend/static/src/fields/custom_many2many_checkboxes/custom_many2many_checkboxes.js index 5845dbae..a3053b72 100644 --- a/jikimo_frontend/static/src/fields/custom_many2many_checkboxes/custom_many2many_checkboxes.js +++ b/jikimo_frontend/static/src/fields/custom_many2many_checkboxes/custom_many2many_checkboxes.js @@ -15,23 +15,24 @@ export class MyCustomWidget extends Many2ManyCheckboxesField { // 放大图片逻辑 // 获取图片元素 const img = event.target; - const close = img.nextSibling + const close = img.nextSibling; // 实现放大图片逻辑 // 比如使用 CSS 放大 img.parentElement.classList.add('zoomed'); - close.classList.add('img_close') + close.classList.add('img_close'); } onCloseClick(event) { const close = event.target; - const img = close.previousSibling - img.parentElement.classList.remove('zoomed') - close.classList.remove('img_close') + const img = close.previousSibling; + img.parentElement.classList.remove('zoomed'); + close.classList.remove('img_close'); } } -MyCustomWidget.template = "jikimo_frontend.MyCustomWidget" +MyCustomWidget.template = "jikimo_frontend.MyCustomWidget"; // MyCustomWidget.supportedTypes = ['many2many']; registry.category("fields").add("custom_many2many_checkboxes", MyCustomWidget); + diff --git a/jikimo_frontend/static/src/js/custom_form_status_indicator.js b/jikimo_frontend/static/src/js/custom_form_status_indicator.js index a5f68479..c1ba8248 100644 --- a/jikimo_frontend/static/src/js/custom_form_status_indicator.js +++ b/jikimo_frontend/static/src/js/custom_form_status_indicator.js @@ -3,7 +3,7 @@ import {patch} from '@web/core/utils/patch'; // import { Dialog } from "@web/core/dialog/dialog"; import {_t} from "@web/core/l10n/translation"; -import {FormStatusIndicator} from "@web/views/form/form_status_indicator/form_status_indicator" +import {FormStatusIndicator} from "@web/views/form/form_status_indicator/form_status_indicator"; var Dialog = require('web.Dialog'); // var {patch} = require("web.utils") 这句话也行 diff --git a/jikimo_frontend/static/src/list/custom_width.js b/jikimo_frontend/static/src/list/custom_width.js index 31fd23ca..f7c1c55d 100644 --- a/jikimo_frontend/static/src/list/custom_width.js +++ b/jikimo_frontend/static/src/list/custom_width.js @@ -1,7 +1,7 @@ /** @odoo-module */ import {patch} from '@web/core/utils/patch'; -import {ListRenderer} from "@web/views/list/list_renderer" +import {ListRenderer} from "@web/views/list/list_renderer"; // var {patch} = require("web.utils") 这句话也行 @@ -17,7 +17,7 @@ patch(ListRenderer.prototype, 'jikimo_frontend.ListRenderer', { const table = this.tableRef.el; const headers = [...table.querySelectorAll("thead th:not(.o_list_actions_header)")]; - const column_num = headers.length + const column_num = headers.length; if (!this.columnWidths || !this.columnWidths.length) { // no column widths to restore @@ -66,8 +66,8 @@ patch(ListRenderer.prototype, 'jikimo_frontend.ListRenderer', { // } // 判断 this.state.columns 是否存在且长度大于零 - if (this.state.columns && this.state.columns.length > 0 && - this.state.columns[0].name === "sequence") { + if (this.state.columns && this.state.columns.length > 0 + && this.state.columns[0].name === "sequence") { widths[1] = { type: "relative", value: 0.1 }; } diff --git a/jikimo_frontend/static/src/views/list_nums/list_nbCols.js b/jikimo_frontend/static/src/views/list_nums/list_nbCols.js index b0bacb02..1403544f 100644 --- a/jikimo_frontend/static/src/views/list_nums/list_nbCols.js +++ b/jikimo_frontend/static/src/views/list_nums/list_nbCols.js @@ -8,4 +8,4 @@ patch(ListRenderer.prototype, '/jikimo_frontend/static/src/views/list_nums/list_ const nbCols = this._super(...arguments); return nbCols + 1; } -}); \ No newline at end of file +}); diff --git a/sf_bf_connect/__manifest__.py b/sf_bf_connect/__manifest__.py index 46ca09f8..ce938272 100644 --- a/sf_bf_connect/__manifest__.py +++ b/sf_bf_connect/__manifest__.py @@ -10,10 +10,10 @@ """, 'category': 'sf', 'website': 'https://www.sf.cs.jikimo.com', - 'depends': ['sf_base'], + 'depends': ['sf_base', 'delivery'], 'data': [ 'views/res_partner_view.xml', - # 'views/view.xml', + 'views/view.xml', 'report/bill_report.xml', ], 'demo': [ diff --git a/sf_bf_connect/models/jd_eclp.py b/sf_bf_connect/models/jd_eclp.py index dfcb20f8..4ccb0db6 100644 --- a/sf_bf_connect/models/jd_eclp.py +++ b/sf_bf_connect/models/jd_eclp.py @@ -3,9 +3,9 @@ import logging from datetime import datetime import requests import cpca -from odoo.exceptions import UserError -from odoo.exceptions import ValidationError -from odoo import api, fields, models, SUPERUSER_ID, _ +# from odoo.exceptions import UserError +# from odoo.exceptions import ValidationError +from odoo import api, fields, models _logger = logging.getLogger(__name__) @@ -40,9 +40,22 @@ class JdEclp(models.Model): # bill = fields.Many2one('ir.attachment', string='物流面单', compute='query_bill_pdf') # bill_show = fields.Binary(string='物流面单展示', readonly=True, related='self.bill.datas') bill_show = fields.Binary(string='物流面单展示', readonly=True) + check_out = fields.Char(string='查询是否为出库单', compute='_check_is_out') + + @api.depends('name') + def _check_is_out(self): + """ + 判断是否为出库单 + """ + if self.name: + is_check_out = self.name.split('/') + self.check_out = is_check_out[1] @api.depends('carrier_tracking_ref') def query_bill_pdf(self): + """ + 查询物流面单,并赋值给bill + """ self.bill = self.env['ir.attachment'].sudo().search([('name', '=', self.carrier_tracking_ref)]) @api.depends('origin') @@ -77,12 +90,12 @@ class JdEclp(models.Model): self.receiverTownName = self.receiverTownName except Exception as e: print(f"Error address is none: {e}") - pass def create_order(self): # sale_order_id = self.env['sale.order'].search([('name', '=', self.origin)]) # if self.carrier_id == '京东物流': + config = self.env['res.config.settings'].get_values() createTime = str(datetime.now()) json1 = { 'params': { @@ -106,7 +119,7 @@ class JdEclp(models.Model): }, } _logger.info('准备调接口1') - url1 = 'https://bfm.cs.jikimo.com/api/create/jd/order' + url1 = config['bfm_url'] + '/api/create/jd/order' requests.post(url1, json=json1, data=None) _logger.info('调用成功1') _logger.info('准备调接口2') @@ -115,7 +128,7 @@ class JdEclp(models.Model): 'orderNo': self.origin, }, } - url2 = 'https://bfm.cs.jikimo.com/api/get/jd/no' + url2 = config['bfm_url'] + '/api/get/jd/no' response = requests.post(url2, json=json2, data=None) # _logger.info('调用成功2', response.json()['result']['wbNo']) self.carrier_tracking_ref = response.json()['result']['wbNo'] @@ -124,12 +137,16 @@ class JdEclp(models.Model): # raise UserError("选择京东物流才能下单呦") def get_bill(self): + """ + 获取物流面单 + """ + config = self.env['res.config.settings'].get_values() json1 = { 'params': { 'no': self.origin, }, } - url1 = 'https://bfm.cs.jikimo.com/api/create/jd/bill' + url1 = config['bfm_url'] + '/api/create/jd/bill' response = requests.post(url1, json=json1, data=None) # _logger.info('调用成功2', response.json()) @@ -152,5 +169,3 @@ class JdEclp(models.Model): # 'model_name': 'stock.picking', }) _logger.info(attachment) - # _logger.info(attachment.datas) - # _logger.info(attachment.datas_fname) diff --git a/sf_bf_connect/models/process_status.py b/sf_bf_connect/models/process_status.py index 3a579920..d79b3369 100644 --- a/sf_bf_connect/models/process_status.py +++ b/sf_bf_connect/models/process_status.py @@ -3,7 +3,6 @@ import logging import requests from odoo import fields, models - _logger = logging.getLogger(__name__) @@ -203,17 +202,17 @@ class FinishStatusChange(models.Model): [('id', 'child_of', self.picking_type_id.warehouse_id.view_location_id.id), ('usage', '!=', 'supplier')]) if self.env['stock.move'].search([ - ('state', 'in', ['confirmed', 'partially_available', 'waiting', 'assigned']), - ('product_qty', '>', 0), - ('location_id', 'in', wh_location_ids), - ('move_orig_ids', '=', False), - ('picking_id', 'not in', self.ids), - ('product_id', 'in', lines.product_id.ids)], limit=1): + ('state', 'in', ['confirmed', 'partially_available', 'waiting', 'assigned']), + ('product_qty', '>', 0), + ('location_id', 'in', wh_location_ids), + ('move_orig_ids', '=', False), + ('picking_id', 'not in', self.ids), + ('product_id', 'in', lines.product_id.ids)], limit=1): action = self.action_view_reception_report() action['context'] = {'default_picking_ids': self.ids} return action - out_start_time = str(datetime.now()) + # out_start_time = str(datetime.now()) json2 = { 'params': { 'model_name': 'jikimo.process.order', diff --git a/sf_bf_connect/views/view.xml b/sf_bf_connect/views/view.xml index ec6dc394..c4f0e446 100644 --- a/sf_bf_connect/views/view.xml +++ b/sf_bf_connect/views/view.xml @@ -1,5 +1,31 @@ + + + 增加一个check_out字段 + stock.picking + + + + + + + + + + 物流 + stock.picking + + + + +

@@ -264,126 +274,96 @@ - + - 功能刀具实时分布 + 功能刀具安全库存 sf.real.time.distribution.of.functional.tools - - - - - - - - - - + + + + + - - - - - - + + + + - 功能刀具实时分布 + 功能刀具安全库存 sf.real.time.distribution.of.functional.tools

- +

- - - - - - - - - - + + + + + - + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + +
@@ -392,28 +372,31 @@
- 功能刀具实时分布 + 功能刀具安全库存 sf.real.time.distribution.of.functional.tools - - - - - - - - - + + + + + + + + + + + + - + - 功能刀具实时分布 + 功能刀具安全库存 ir.actions.act_window sf.real.time.distribution.of.functional.tools tree,form,search diff --git a/sf_tool_management/wizard/wizard.py b/sf_tool_management/wizard/wizard.py index d667ba33..2c81cb31 100644 --- a/sf_tool_management/wizard/wizard.py +++ b/sf_tool_management/wizard/wizard.py @@ -57,12 +57,10 @@ class ToolChangeRequirementInformation(models.TransientModel): 确认换刀申请(按键) :return: """ - print('已运行') record = self.env['sf.machine.table.tool.changing.apply'].search( [('maintenance_equipment_id', '=', self.maintenance_equipment_id.id), ('cutter_spacing_code_id', '=', self.cutter_spacing_code_id.id) ]) - print('运行record_1') # 功能刀具组装创建新任务(new_assembly_task) sf_functional_tool_assembly = self.env['sf.functional.tool.assembly'].sudo().create({ @@ -86,13 +84,11 @@ class ToolChangeRequirementInformation(models.TransientModel): 'reason_for_applying': self.reason_for_applying, 'sf_machine_table_tool_changing_apply_id': record.id }) - print('sf_functional_tool_assembly:', sf_functional_tool_assembly) # 修改机床换刀申请状态 record.write({ 'status': '1', - 'sf_functional_tool_assembly_id': sf_functional_tool_assembly + 'sf_functional_tool_assembly_id': sf_functional_tool_assembly.id }) - print('运行成功') # 关闭弹出窗口 return {'type': 'ir.actions.act_window_close'} @@ -186,7 +182,9 @@ class FunctionalToolAssemblyOrder(models.TransientModel): # 功能刀具组装信息 # 整体式刀具型号 integral_code_id = fields.Many2one('stock.lot', string='整体式刀具序列号', - domain=[('product_id.cutting_tool_material_id.name', '=', '整体式刀具')]) + domain=[('product_id.cutting_tool_material_id.name', '=', '整体式刀具'), + ('quant_ids.location_id.name', 'in', ['刀具房']), + ('quant_ids.quantity', '>', 0)]) cutting_tool_integral_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='整体式刀具型号', readonly=True) integral_name = fields.Char('整体式刀具名称', readonly=True) @@ -194,14 +192,18 @@ class FunctionalToolAssemblyOrder(models.TransientModel): # 刀片型号 blade_code_id = fields.Many2one('stock.lot', '刀片序列号', - domain=[('product_id.cutting_tool_material_id.name', '=', '刀片')]) + domain=[('product_id.cutting_tool_material_id.name', '=', '刀片'), + ('quant_ids.location_id.name', 'in', ['刀具房']), + ('quant_ids.quantity', '>', 0)]) cutting_tool_blade_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀片型号', readonly=True) blade_name = fields.Char('刀片名称', readonly=True) sf_tool_brand_id_2 = fields.Many2one('sf.machine.brand', '刀片品牌', readonly=True) # 刀杆型号 bar_code_id = fields.Many2one('stock.lot', '刀杆序列号', - domain=[('product_id.cutting_tool_material_id.name', '=', '刀杆')]) + domain=[('product_id.cutting_tool_material_id.name', '=', '刀杆'), + ('quant_ids.location_id.name', 'in', ['刀具房']), + ('quant_ids.quantity', '>', 0)]) cutting_tool_cutterbar_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀杆型号', readonly=True) bar_name = fields.Char('刀杆名称', readonly=True) @@ -209,7 +211,9 @@ class FunctionalToolAssemblyOrder(models.TransientModel): # 刀盘型号 pad_code_id = fields.Many2one('stock.lot', '刀盘序列号', - domain=[('product_id.cutting_tool_material_id.name', '=', '刀盘')]) + domain=[('product_id.cutting_tool_material_id.name', '=', '刀盘'), + ('quant_ids.location_id.name', 'in', ['刀具房']), + ('quant_ids.quantity', '>', 0)]) cutting_tool_cutterpad_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀盘型号', readonly=True) pad_name = fields.Char('刀盘名称', readonly=True) @@ -217,7 +221,9 @@ class FunctionalToolAssemblyOrder(models.TransientModel): # 刀柄型号 handle_code_id = fields.Many2one('stock.lot', '刀柄序列号', required=True, - domain=[('product_id.cutting_tool_material_id.name', '=', '刀柄')]) + domain=[('product_id.cutting_tool_material_id.name', '=', '刀柄'), + ('quant_ids.location_id.name', 'in', ['刀具房']), + ('quant_ids.quantity', '>', 0)]) cutting_tool_cutterhandle_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀柄型号', readonly=True) handle_name = fields.Char('刀柄名称', readonly=True) @@ -225,7 +231,9 @@ class FunctionalToolAssemblyOrder(models.TransientModel): # 夹头型号 chuck_code_id = fields.Many2one('stock.lot', '夹头序列号', required=True, - domain=[('product_id.cutting_tool_material_id.name', '=', '夹头')]) + domain=[('product_id.cutting_tool_material_id.name', '=', '夹头'), + ('quant_ids.location_id.name', 'in', ['刀具房']), + ('quant_ids.quantity', '>', 0)]) cutting_tool_cutterhead_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='夹头型号', readonly=True) chuck_name = fields.Char('夹头名称', readonly=True, compute='_compute_auto_fill') @@ -339,6 +347,7 @@ class FunctionalToolAssemblyOrder(models.TransientModel): 功能刀具组装 :return: """ + # 获取组装单对象 functional_tool_assembly = self.env['sf.functional.tool.assembly'].search([ ('assembly_order_code', '=', self.assembly_order_code), ('machine_tool_name_id', '=', self.machine_tool_name_id.id), @@ -348,29 +357,45 @@ class FunctionalToolAssemblyOrder(models.TransientModel): # 对物料做必填判断 self.materials_must_be_judged() + product_id = self.env['product.product'].search([('name', '=', '功能刀具')]) # 创建组装入库单 # 创建功能刀具批次/序列号记录 - stock_lot = self.create_assemble_warehouse_receipt(functional_tool_assembly) + stock_lot = product_id.create_assemble_warehouse_receipt(self.id, functional_tool_assembly) # 创建刀具组装入库单 self.create_stocking_picking(stock_lot) - # 封装功能刀具数据 - desc_1 = self.get_desc_1(stock_lot) + # 刀具物料出库 + if self.integral_code_id: + product_id.tool_material_stock_moves(self.integral_code_id) + if self.blade_code_id: + product_id.tool_material_stock_moves(self.blade_code_id) + if self.bar_code_id: + product_id.tool_material_stock_moves(self.bar_code_id) + if self.pad_code_id: + product_id.tool_material_stock_moves(self.pad_code_id) + if self.handle_code_id: + product_id.tool_material_stock_moves(self.handle_code_id) + if self.chuck_code_id: + product_id.tool_material_stock_moves(self.chuck_code_id) - # 创建功能刀具列表记录 + # ============================创建功能刀具列表、安全库存记录=============================== # 封装功能刀具数据 desc_2 = self.get_desc_2(stock_lot, functional_tool_assembly) - # 创建功能刀具列表、功能刀具预警、功能刀具实时分布、功能刀具出入库记录 + # 创建功能刀具列表记录 record_1 = self.env['sf.functional.cutting.tool.entity'].create(desc_2) - # self.env['sf.real.time.distribution.of.functional.tools'].create({ - # 'functional_cutting_tool_id': record_1.id - # }) - # self.env['sf.inbound.and.outbound.records.of.functional.tools'].create({ - # 'functional_cutting_tool_id': record_1.id - # }) + # 创建安全库存信息 + self.env['sf.real.time.distribution.of.functional.tools'].create_or_edit_safety_stock({ + 'name': self.after_assembly_functional_tool_name, + 'sf_cutting_tool_type_id': self.after_assembly_functional_tool_type_id.id, + 'diameter': self.after_assembly_functional_tool_diameter, + 'knife_tip_r_angle': self.after_assembly_knife_tip_r_angle, + 'coarse_middle_thin': self.after_assembly_coarse_middle_thin, + }, record_1) + # =====================修改功能刀具组装单、机床换刀申请、CAM工单程序用刀计划的状态============== + # 封装功能刀具数据 + desc_1 = self.get_desc_1(stock_lot) # 修改功能刀具组装单信息 functional_tool_assembly.write(desc_1) - if functional_tool_assembly.sf_machine_table_tool_changing_apply_id: # 修改机床换刀申请的状态 self.env['sf.machine.table.tool.changing.apply'].sudo().search([ @@ -414,71 +439,6 @@ class FunctionalToolAssemblyOrder(models.TransientModel): # 将刀具组装入库单的状态更改为就绪 picking_id.action_confirm() - def create_assemble_warehouse_receipt(self, functional_tool_assembly): - """ - 创建功能刀具批次/序列号记录 - """ - product_id = self.env['product.product'].search([('name', '=', '功能刀具')]) - - stock_lot = self.env['stock.lot'].create({ - 'name': self.get_stock_lot_name(), - 'product_id': product_id.id, - 'company_id': self.env.company.id - }) - # 创建功能刀具该批次/序列号 库存移动和移动历史 - self.create_stock_quant(product_id, stock_lot, functional_tool_assembly) - - return stock_lot - - def create_stock_quant(self, product_id, stock_lot, functional_tool_assembly): - """ - 创建功能刀具该批次/序列号 库存移动和移动历史 - """ - # 获取位置对象 - stock_location_id = self.env['stock.location'].search([('name', '=', '组装后')]) - location_inventory_id = self.env['stock.location'].search([('name', '=', 'Inventory adjustment')]) - - # 创建库存移动 - stock_move_id = self.env['stock.move'].create({ - 'name': '功能刀具组装出库', - 'product_id': product_id.id, - 'location_id': location_inventory_id.id, - 'location_dest_id': stock_location_id.id, - 'product_uom_qty': 1.00, - 'state': 'done' - }) - - # 创建移动历史 - stock_move_line_id = self.env['stock.move.line'].create({ - 'product_id': product_id.id, - 'functional_tool_name_id': functional_tool_assembly.id, - 'lot_id': stock_lot.id, - 'move_id': stock_move_id.id, - 'install_tool_time': fields.Datetime.now(), - 'qty_done': 1.0, - 'state': 'done' - }) - return stock_move_id, stock_move_line_id - - def get_stock_lot_name(self): - """ - 生成功能刀具序列号 - """ - code = 'JKM-T-' + str(self.functional_tool_type_id.code) + '-' + str(self.functional_tool_diameter) + '-' - new_time = fields.Date.today() - code += str(new_time) + '-' - stock_lot_id = self.env['stock.lot'].sudo().search( - [('name', 'like', new_time), ('product_id.name', '=', '功能刀具')], - limit=1, - order="id desc" - ) - if not stock_lot_id: - num = "%03d" % 1 - else: - m = int(stock_lot_id.name[-3:]) + 1 - num = "%03d" % m - return code + str(num) - def get_desc_1(self, stock_lot): return { 'barcode_id': stock_lot.id, @@ -543,3 +503,90 @@ class FunctionalToolAssemblyOrder(models.TransientModel): 'cut_number': self.cut_number, 'current_location_id': stock_lot.quant_ids.location_id.ids[-1], } + + +class ProductProduct(models.Model): + _inherit = 'product.product' + + def create_assemble_warehouse_receipt(self, tool_assembly_order_id, functional_tool_assembly): + """ + 创建功能刀具批次/序列号记录 + """ + product_id = self.env['product.product'].search([('name', '=', '功能刀具')]) + + stock_lot = self.env['stock.lot'].create({ + 'name': self.get_stock_lot_name(tool_assembly_order_id), + 'product_id': product_id.id, + 'company_id': self.env.company.id + }) + # 获取位置对象 + location_inventory_id = self.env['stock.location'].search([('name', '=', 'Production')]) + stock_location_id = self.env['stock.location'].search([('name', '=', '组装后')]) + # 创建功能刀具该批次/序列号 库存移动和移动历史 + stock_lot.create_stock_quant(location_inventory_id, stock_location_id, functional_tool_assembly.id) + + return stock_lot + + def get_stock_lot_name(self, tool_assembly_order_id): + """ + 生成功能刀具序列号 + """ + tool_assembly_order = self.env['sf.functional.tool.assembly.order'].search( + [('id', '=', tool_assembly_order_id)]) + code = 'JKM-T-' + str(tool_assembly_order.after_assembly_functional_tool_type_id.code) + '-' + str( + tool_assembly_order.after_assembly_functional_tool_diameter) + '-' + new_time = fields.Date.today() + code += str(new_time) + '-' + stock_lot_id = self.env['stock.lot'].sudo().search( + [('name', 'like', new_time), ('product_id.name', '=', '功能刀具')], + limit=1, + order="id desc" + ) + if not stock_lot_id: + num = "%03d" % 1 + else: + m = int(stock_lot_id.name[-3:]) + 1 + num = "%03d" % m + return code + str(num) + + def tool_material_stock_moves(self, tool_material): + """ + 对刀具物料进行库存移动到 刀具组装位置 + """ + # 获取位置对象 + location_inventory_id = tool_material.quant_ids.location_id[-1] + print(location_inventory_id) + stock_location_id = self.env['stock.location'].search([('name', '=', '刀具组装位置')]) + # 创建功能刀具该批次/序列号 库存移动和移动历史 + tool_material.create_stock_quant(location_inventory_id, stock_location_id, None) + + +class StockLot(models.Model): + _inherit = 'stock.lot' + + def create_stock_quant(self, location_inventory_id, stock_location_id, functional_tool_assembly_id): + """ + 对功能刀具组装过程的功能刀具和刀具物料进行库存移动,以及创建移动历史 + """ + + # 创建库存移动记录 + stock_move_id = self.env['stock.move'].create({ + 'name': '功能刀具组装', + 'product_id': self.product_id.id, + 'location_id': location_inventory_id.id, + 'location_dest_id': stock_location_id.id, + 'product_uom_qty': 1.00, + 'state': 'done' + }) + + # 创建移动历史记录 + stock_move_line_id = self.env['stock.move.line'].create({ + 'product_id': self.product_id.id, + 'functional_tool_name_id': functional_tool_assembly_id, + 'lot_id': self.id, + 'move_id': stock_move_id.id, + 'install_tool_time': fields.Datetime.now(), + 'qty_done': 1.0, + 'state': 'done' + }) + return stock_move_id, stock_move_line_id diff --git a/sf_warehouse/__manifest__.py b/sf_warehouse/__manifest__.py index c3cdf682..0f241b90 100644 --- a/sf_warehouse/__manifest__.py +++ b/sf_warehouse/__manifest__.py @@ -13,8 +13,9 @@ 'depends': ['stock', 'web', ], 'data': [ # 'security/group_security.xml', - # 'security/ir.model.access.csv', + 'security/ir.model.access.csv', 'views/view.xml', + 'views/shelf_location.xml', ], 'demo': [ ], diff --git a/sf_warehouse/models/model.py b/sf_warehouse/models/model.py index cfa097ce..6ff3e65a 100644 --- a/sf_warehouse/models/model.py +++ b/sf_warehouse/models/model.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- -import logging -from odoo import SUPERUSER_ID, _, api, fields, models +from odoo import api, fields, models from odoo.osv import expression @@ -12,10 +11,13 @@ class SfLocation(models.Model): barcode = fields.Char('Barcode', copy=False, size=15) # 仓库类别(selection:库区、库位、货位) + # location_type = fields.Selection([ + # ('库区', '库区'), + # ('货架', '货架'), + # ('货位', '货位') + # ], string='存储类型') location_type = fields.Selection([ - ('库区', '库区'), - ('货架', '货架'), - ('货位', '货位') + ('库区', '库区') ], string='存储类型') # 库区类型(selection:拣货区、存货区、收货区、退货区、次品区) area_type = fields.Selection([ @@ -25,6 +27,10 @@ class SfLocation(models.Model): ('退货区', '退货区'), ('次品区', '次品区') ], string='库区类型') + # 当前位置 + current_location_id = fields.Many2one('sf.shelf.location', string='当前位置') + # 目的位置 + destination_location_id = fields.Many2one('sf.shelf.location', string='目的位置') # 存储类型(selection:库区、货架) # storage_type = fields.Selection([ # ('库区', '库区'), @@ -207,6 +213,108 @@ class SfLocation(models.Model): # + str(j + 1) +class ShelfLocation(models.Model): + _name = 'sf.shelf.location' + _description = '货架货位' + + name = fields.Char('名称', required=True, size=20) + barcode = fields.Char('编码', copy=False, size=15) + + # 仓库类别(selection:库区、库位、货位) + location_type = fields.Selection([ + ('货架', '货架'), + ('货位', '货位') + ], string='存储类型') + # 绑定库区 + location_id = fields.Many2one('stock.location', string='所属库区', domain=[('location_type', '=', '库区')]) + # 产品类别 (关联:product.category) + product_type = fields.Many2many('product.category', string='产品类别') + # 货架独有字段:通道、方向、货架高度(m)、货架层数、层数容量 + channel = fields.Char(string='通道') + direction = fields.Selection([ + ('R', 'R'), + ('L', 'L') + ], string='方向') + shelf_height = fields.Float(string='货架高度(m)') + shelf_layer = fields.Integer(string='货架层数') + layer_capacity = fields.Integer(string='层数容量') + + # 货位独有字段:货位状态、产品(关联产品对象)、产品序列号(关联产品序列号对象) + location_status = fields.Selection([ + ('空闲', '空闲'), + ('占用', '占用'), + ('禁用', '禁用') + ], string='货位状态', default='空闲') + # product_id = fields.Many2one('product.template', string='产品') + product_id = fields.Many2one('product.product', string='产品', compute='_compute_product_id', readonly=True) + product_sn_id = fields.Many2one('stock.lot', string='产品序列号') + + hide_shelf = fields.Boolean(compute='_compute_hide_what', string='隐藏货架') + hide_location = fields.Boolean(compute='_compute_hide_what', string='隐藏货位') + + @api.depends('product_sn_id') + def _compute_product_id(self): + """ + 根据产品序列号,获取产品 + """ + for record in self: + if record.product_sn_id: + record.product_id = record.product_sn_id.product_id + record.location_status = '占用' + else: + record.product_id = False + # record.location_status = '空闲' + + @api.depends('location_type') + def _compute_hide_what(self): + """ + 根据仓库类别,隐藏不需要的字段 + :return: + """ + for record in self: + record.hide_shelf = False + record.hide_location = False + if record.location_type and record.location_type == '货架': + record.hide_shelf = True + elif record.location_type and record.location_type == '货位': + record.hide_location = True + else: + pass + + # 生成货位 + def create_location(self): + """ + 当仓库类型为货架时,自动生成其下面的货位,数量为货架层数*层数容量 + """ + if self.location_type == '货架': + for i in range(self.shelf_layer): + for j in range(self.layer_capacity): + self.create({ + 'name': self.name + '-' + str(i + 1) + '层' + '-' + str(j + 1) + '位置', + 'location_id': self.id, + 'location_type': '货位', + 'barcode': self.generate_barcode(i, j), + 'location_status': '空闲' + }) + + def generate_barcode(self, i, j): + """ + 生成货位条码 + """ + # 这里是你生成barcode的代码 + # area_type_barcode = self.location_id.barcode + area_type_barcode = self.barcode + i_str = str(i + 1).zfill(3) # 确保是两位数,如果不足两位,左侧补0 + j_str = str(j + 1).zfill(3) # 确保是两位数,如果不足两位,左侧补0 + return area_type_barcode + self.channel + self.direction + '-' + self.barcode + '-' + i_str + '-' + j_str + + # def generate_barcode(self, i, j): + # # 这里是你生成barcode的代码 + # area_type_barcode = self.location_id.barcode + # return area_type_barcode + self.channel + self.direction + '-' + self.barcode + '-' + str(i + 1) + '-' + # + str(j + 1) + + class SfProcurementGroup(models.Model): _inherit = 'procurement.group' diff --git a/sf_warehouse/security/ir.model.access.csv b/sf_warehouse/security/ir.model.access.csv index 94ce7d2b..46c1988e 100644 --- a/sf_warehouse/security/ir.model.access.csv +++ b/sf_warehouse/security/ir.model.access.csv @@ -1,4 +1,4 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_stock_location,stock.location,model_stock_location,base.group_user,1,1,1,1 +access_sf_shelf_location,sf.shelf.location,model_sf_shelf_location,base.group_user,1,1,1,1 diff --git a/sf_warehouse/static/src/colorGuide.js b/sf_warehouse/static/src/colorGuide.js index c6cc0f94..dd5a4b02 100644 --- a/sf_warehouse/static/src/colorGuide.js +++ b/sf_warehouse/static/src/colorGuide.js @@ -1,12 +1,11 @@ odoo.define('sf_warehouse.custom_kanban', function (require) { - "use strict" + "use strict"; var KanbanRenderer = require('web.KanbanRenderer'); KanbanRenderer.include({ _render: function () { var self = this; return this._super.apply(this, arguments).then(function () { - var colorGuide = $('
\ \ \ @@ -16,5 +15,4 @@ odoo.define('sf_warehouse.custom_kanban', function (require) { }); }, }); - -}); \ No newline at end of file +}); diff --git a/sf_warehouse/static/src/js/cust_char.js b/sf_warehouse/static/src/js/cust_char.js index 3757bfb8..d67f2d7a 100644 --- a/sf_warehouse/static/src/js/cust_char.js +++ b/sf_warehouse/static/src/js/cust_char.js @@ -1,9 +1,7 @@ /** @odoo-module **/ -import { registry } from "@web/core/registry"; -import { CharField } from '@web/views/fields/char/char_field'; - - +import {registry} from "@web/core/registry"; +import {CharField} from '@web/views/fields/char/char_field'; // 继承CharField组件实现自定义组件:当光标聚焦于输入框时,选中输入框内容 class CustomChar extends CharField { @@ -20,7 +18,7 @@ class CustomChar extends CharField { // 当光标聚焦于输入框时,选中输入框内容 this.input.el.addEventListener('focus', function () { this.select(); - }) + }); } @@ -72,13 +70,10 @@ class CustomChar extends CharField { // } // } - // this.$input.on('focus', function () { - // $(this).select(); - // }); - - + // this.$input.on('focus', function () { + // $(this).select(); + // }); // 当光标聚焦于输入框时,选中输入框内容 - } -registry.category("fields").add("custom_char", CustomChar); \ No newline at end of file +registry.category("fields").add("custom_char", CustomChar); diff --git a/sf_warehouse/static/src/js/custom_kanban_controller.js b/sf_warehouse/static/src/js/custom_kanban_controller.js index 7b9d01fb..62c83505 100644 --- a/sf_warehouse/static/src/js/custom_kanban_controller.js +++ b/sf_warehouse/static/src/js/custom_kanban_controller.js @@ -1,8 +1,8 @@ /** @odoo-module */ -import { KanbanController } from "@web/views/kanban/kanban_controller"; -import { kanbanView } from "@web/views/kanban/kanban_view"; -import { registry } from "@web/core/registry"; +import {KanbanController} from "@web/views/kanban/kanban_controller"; +import {kanbanView} from "@web/views/kanban/kanban_view"; +import {registry} from "@web/core/registry"; // the controller usually contains the Layout and the renderer. class CustomKanbanController extends KanbanController { @@ -18,4 +18,4 @@ export const customKanbanView = { }; // Register it to the views registry -registry.category("views").add("custom_kanban", customKanbanView); \ No newline at end of file +registry.category("views").add("custom_kanban", customKanbanView); diff --git a/sf_warehouse/static/src/js/custom_many2one.js b/sf_warehouse/static/src/js/custom_many2one.js index c6a86af5..2e0e70bf 100644 --- a/sf_warehouse/static/src/js/custom_many2one.js +++ b/sf_warehouse/static/src/js/custom_many2one.js @@ -1,8 +1,7 @@ /** @odoo-module **/ -import { registry } from "@web/core/registry"; -import { Many2OneField } from '@web/views/fields/many2one/many2one_field'; - +import {registry} from "@web/core/registry"; +import {Many2OneField} from '@web/views/fields/many2one/many2one_field'; // 继承FieldMany2One组件实现自定义组件:当光标聚焦于输入框时,选中输入框内容 @@ -17,14 +16,14 @@ class CustomMany2One extends Many2OneField { // console.log('CustomMany2One.setup11111111111111'); super.setup(); } + onMounted() { // console.log('CustomMany2One.onMounted1'); // 当光标聚焦于输入框时,选中输入框内容 this.input.el.addEventListener('focus', function () { this.select(); - }) + }); } - } registry.category("fields").add("custom_many2one", CustomMany2One); diff --git a/sf_warehouse/views/shelf_location.xml b/sf_warehouse/views/shelf_location.xml new file mode 100644 index 00000000..a7ef00d9 --- /dev/null +++ b/sf_warehouse/views/shelf_location.xml @@ -0,0 +1,201 @@ + + + + + Shelf Location tree + sf.shelf.location + + + + + + + + + + + Shelf Location form + sf.shelf.location + + +
+
+ + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 货架货位 + ir.actions.act_window + sf.shelf.location + tree,form + + + + + + + + + + + + + + + + + + + + + + +
+
diff --git a/sf_warehouse/views/view.xml b/sf_warehouse/views/view.xml index 56ddc19a..93e55dfb 100644 --- a/sf_warehouse/views/view.xml +++ b/sf_warehouse/views/view.xml @@ -32,6 +32,8 @@ + + diff --git a/web_widget_model_viewer/static/src/js/3d_viewer.js b/web_widget_model_viewer/static/src/js/3d_viewer.js index 3c66b142..15374070 100644 --- a/web_widget_model_viewer/static/src/js/3d_viewer.js +++ b/web_widget_model_viewer/static/src/js/3d_viewer.js @@ -26,15 +26,15 @@ export class StepViewer extends Component { model: this.props.record.resModel, id: JSON.stringify(this.props.record.data['id']), field: this.props.name - } - url = url_props['base_url'].replace('http://', 'https://') + '/web/content/' + url_props['model'] + '/' + url_props['id'] + '/' + url_props['field'] + '?download=true' + }; + url = url_props['base_url'].replace('http://', 'https://') + '/web/content/' + url_props['model'] + '/' + url_props['id'] + '/' + url_props['field'] + '?download=true'; // url = 'http://localhost:8069'+'/web/content/'+url_props['model']+'/'+url_props['id']+'/'+url_props['field']+'?download=true' // console.log('url111111', url) - return url + return url; } else { url = "data:model/gltf-binary;base64," + this.props.value; // console.log('url2', url) - return url + return url; // localStorage.setItem('url',url) // let new_url = localStorage.getItem(('url')) // var oViewer = document.getElementsByTagName('model-viewer')[0]; diff --git a/yizuo_login_background_and_styles/controllers/main.py b/yizuo_login_background_and_styles/controllers/main.py index 6412ba67..d1271133 100644 --- a/yizuo_login_background_and_styles/controllers/main.py +++ b/yizuo_login_background_and_styles/controllers/main.py @@ -23,7 +23,6 @@ try: import httpagentparser except ImportError: pass -from time import gmtime, strftime from odoo.addons.web.controllers import home from odoo.http import request from odoo.exceptions import Warning diff --git a/yizuo_login_background_and_styles/models/login_image.py b/yizuo_login_background_and_styles/models/login_image.py index 5b3b19fe..c8a36e0d 100644 --- a/yizuo_login_background_and_styles/models/login_image.py +++ b/yizuo_login_background_and_styles/models/login_image.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from odoo import models, fields, api, _ +from odoo import models, fields class LoginImage(models.Model): diff --git a/yizuo_login_background_and_styles/models/res_config_settings.py b/yizuo_login_background_and_styles/models/res_config_settings.py index 66394f9e..cefc659f 100644 --- a/yizuo_login_background_and_styles/models/res_config_settings.py +++ b/yizuo_login_background_and_styles/models/res_config_settings.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from odoo import api, fields, models, modules +from odoo import api, fields, models class ResConfigSettings(models.TransientModel): diff --git a/zpl_print/controllers/report.py b/zpl_print/controllers/report.py index ade1c26f..7d9041de 100644 --- a/zpl_print/controllers/report.py +++ b/zpl_print/controllers/report.py @@ -8,11 +8,9 @@ import werkzeug.exceptions import werkzeug.utils import werkzeug.wrappers import werkzeug.wsgi -from werkzeug.urls import url_parse from odoo import http -from odoo.http import content_disposition, request -from odoo.tools.safe_eval import safe_eval, time +from odoo.http import request from odoo.addons.web.controllers.report import ReportController from ..models.common import Common diff --git a/zpl_print/models/common.py b/zpl_print/models/common.py index c10d5a74..d45f74e0 100644 --- a/zpl_print/models/common.py +++ b/zpl_print/models/common.py @@ -18,4 +18,4 @@ class Common(models.Model): tsclibrary.printlabelW("0", "1"); tsclibrary.closeport(); except Exception as e: - raise UserWarning("错误警告") + raise UserWarning("错误警告:%s" % e)