Accept Merge Request #1287: (feature/tax_sync -> develop)

Merge Request: bom物料清单,sf与cloud数据同步

Created By: @廖丹龙
Reviewed By: @马广威
Approved By: @马广威 
Accepted By: @廖丹龙
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1287
This commit is contained in:
廖丹龙
2024-09-09 18:00:55 +08:00
committed by Coding
19 changed files with 396 additions and 17 deletions

View File

@@ -80,10 +80,10 @@
<field name="name">sf.cutter.function.tree</field>
<field name="model">sf.functional.cutting.tool.model</field>
<field name="arch" type="xml">
<tree string="功能刀具类型" create="0" delete="0" edit="1">
<field name="name" string="名称"/>
<field name="code"/>
<field name="remark"/>
<tree string="功能刀具类型" create="0" delete="0" edit="1" editable="bottom">
<field name="name" string="名称" readonly="1"/>
<field name="code" readonly="1"/>
<field name="remark" readonly="1"/>
</tree>
</field>
</record>

View File

@@ -37,7 +37,7 @@
<field name="date_planned_start" string="计划开始日期" optional="show"/>
</xpath>
<xpath expr="//field[@name='date_planned_start']" position="before">
<field name="reserved_duration" string="计划预留时间" optional="show"/>
<field name="reserved_duration" string="计划预留时间" optional="hide"/>
</xpath>
<xpath expr="//field[@name='date_planned_finished']" position="replace">
<field name="date_planned_finished" string="计划结束日期" optional="hide"/>

View File

@@ -1,8 +1,11 @@
# -*- coding: utf-8 -*-
# Part of SmartGo. See LICENSE file for full copyright and licensing details.
import logging
import requests
from odoo import api, fields, models
from odoo.exceptions import ValidationError
from odoo.exceptions import ValidationError, UserError
_logger = logging.getLogger(__name__)
@@ -86,7 +89,7 @@ class ResConfigSettings(models.TransientModel):
_logger.info("同步刀具物料每齿走刀量完成")
except Exception as e:
_logger.info("捕获错误信息:%s" % e)
_logger.info("sf_all_sync error: %s" % e)
raise ValidationError("数据错误导致同步失败,请联系管理员")
@api.model
@@ -144,3 +147,68 @@ class ResConfigSettings(models.TransientModel):
ir_config.set_param("ftp_user", self.ftp_user or "")
ir_config.set_param("ftp_password", self.ftp_password or "")
ir_config.set_param("enable_tool_presetter", self.enable_tool_presetter or False)
def sync_sale_price(self):
self.get_page_all_records(self.sale_order_price_process)
def sale_order_price_process(self, datas):
if not datas:
return
try:
convert_sale_data = map(lambda data:
{'name': data.name, 'order_lines': {
str(i): str(value.price_unit) for i, value in enumerate(data.order_line)
}
},
datas)
config = self.env['res.config.settings'].get_values()
url = config['bfm_url_new'] + '/api/sync/order/price'
json_data = {
'params': {
'data': list(convert_sale_data),
},
}
response = requests.post(url, json=json_data, data=None)
response = response.json()
if not response.get('error'):
result = response.get('result')
for need_change_sale_data in result:
res_order_lines_map = need_change_sale_data.get('order_lines')
if not res_order_lines_map:
continue
need_change_sale_order = self.env['sale.order'].sudo().search([('name', '=', need_change_sale_data.get('name'))])
for index,need_change_sale_order_line in enumerate(need_change_sale_order.order_line):
if not res_order_lines_map.get(str(index)):
continue
order_line = self.env['sale.order.line'].browse(need_change_sale_order_line.id)
new_price = res_order_lines_map.get(str(index))
if order_line:
# 修改单价
order_line.write({'remark': new_price})
else:
logging.error('同步销售订单价格失败 {}'.format(response.text))
raise UserError('同步销售订单价格失败')
except Exception as e:
raise UserError(e)
def get_page_all_records(self, func, page_size=100):
# 获取模型对象
model = self.env['sale.order'].sudo()
# 初始化分页参数
page_number = 1
while True:
# 计算偏移量
offset = (page_number - 1) * page_size
# 获取当前页的数据
records = model.search([], limit=page_size, offset=offset)
# 如果没有更多记录,退出循环
if not records:
break
# 将当前页的数据添加到结果列表
func(records)
# 增加页码
page_number += 1

View File

@@ -2,6 +2,8 @@
import logging
import json
import base64
import traceback
import requests
from odoo import models
from odoo.exceptions import ValidationError
@@ -73,7 +75,8 @@ class MrStaticResourceDataSync(models.Model):
self.env['sf.feed.per.tooth'].sync_feed_per_tooth_yesterday()
_logger.info("同步刀具物料每齿走刀量完成")
except Exception as e:
logging.info("捕获错误信息:%s" % e)
traceback_error = traceback.format_exc()
logging.error("同步静态资源库失败:%s" % traceback_error)
raise ValidationError("数据错误导致同步失败,请联系管理员")
@@ -2759,8 +2762,9 @@ class CuttingToolBasicParameters(models.Model):
if result['status'] == 1:
if 'basic_parameters_integral_tool' in result['cutting_tool_basic_parameters_yesterday_list']:
if result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_integral_tool']:
basic_parameters_integral_tool_list = json.loads(
result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_integral_tool'])
cutting_tool_basic_parameters_yesterday_list= result['cutting_tool_basic_parameters_yesterday_list']
basic_parameters_integral_tool_list = cutting_tool_basic_parameters_yesterday_list['basic_parameters_integral_tool']
if basic_parameters_integral_tool_list:
for integral_tool_item in basic_parameters_integral_tool_list:
integral_tool = self.search(

View File

@@ -129,6 +129,21 @@
</div>
</div>
</div>
<div>
<h2>销售订单价格同步</h2>
<div class="row mt16 o_settings_container">
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<div class="col-12 col-lg-6 o_setting_box">
<button type="object" class="oe_highlight" name="sync_sale_price" confirm="确认同步"
string="同步销售订单价格"
/>
</div>
</div>
</div>
</div>
</div>
</xpath>
</field>
</record>

View File

@@ -10,7 +10,7 @@
""",
'category': 'sf',
'website': 'https://www.sf.jikimo.com',
'depends': ['sf_manufacturing'],
'depends': ['sf_manufacturing', 'sf_base'],
'data': [
'security/group_security.xml',
'security/ir.model.access.csv',
@@ -24,6 +24,11 @@
'views/menu_view.xml',
'views/stock.xml',
'data/tool_data.xml',
'wizard/jikimo_bom_wizard.xml',
'views/tool_inventory.xml',
'views/jikimo_bom.xml',
'views/tool_views.xml',
],
'demo': [
],

View File

@@ -8,4 +8,6 @@ from . import fixture_material_search
from . import fixture_enroll
from . import temporary_data_processing_methods
from . import stock
from . import jikimo_bom
from . import tool_inventory
from . import functional_cutting_tool_model

View File

@@ -0,0 +1,6 @@
from odoo import models, fields
class SyncFunctionalCuttingToolModel(models.Model):
_inherit = 'sf.functional.cutting.tool.model'
cutting_tool_type_ids = fields.Many2many('sf.cutting.tool.type', string='整体式刀具物料')

View File

@@ -50,7 +50,7 @@ class ToolDatasync(models.Model):
# self.env['sf.real.time.distribution.of.functional.tools'].sudo().sync_enroll_functional_tool_real_time_distribution_all()
# logging.info("功能刀具安全库存每日同步成功")
except Exception as e:
logging.info("捕获错误信息:%s" % e)
logging.info("刀具物料、刀具信息同步失败:%s" % e)
raise ValidationError("数据错误导致同步失败,请联系管理员")
@@ -312,7 +312,7 @@ class FunctionalToolWarning(models.Model):
else:
logging.info('没有注册功能刀具预警信息')
except Exception as e:
logging.info("捕获错误信息:%s" % e)
logging.info("功能刀具预警同步失败:%s" % e)
class StockMoveLine(models.Model):
@@ -373,7 +373,7 @@ class StockMoveLine(models.Model):
else:
logging.info('没有注册功能刀具出入库记录信息')
except Exception as e:
logging.info("捕获错误信息:%s" % e)
logging.info("出入库记录信息同步失败:%s" % e)
class RealTimeDistributionFunctionalTools(models.Model):
@@ -446,4 +446,4 @@ class RealTimeDistributionFunctionalTools(models.Model):
else:
logging.info('没有注册功能刀具出入库记录信息')
except Exception as e:
logging.info("捕获错误信息:%s" % e)
logging.info("实时功能刀具同步失败:%s" % e)

View File

@@ -0,0 +1,96 @@
# -*- coding: utf-8 -*-
from xml import etree
from odoo import models, fields, api, Command
from odoo.http import request
class jikimo_bom(models.Model):
_name = 'jikimo.bom'
_description = '功能刀具物料清单'
tool_inventory_id = fields.Many2one('sf.tool.inventory', '功能刀具清单')
tool_name = fields.Char(related="tool_inventory_id.name", string='功能刀具名称')
functional_cutting_tool_model_id = fields.Many2one(related='tool_inventory_id.functional_cutting_tool_model_id',
string='功能刀具类型')
tool_groups_id = fields.Many2one(related='tool_inventory_id.tool_groups_id', string='刀具组')
tool_length = fields.Float(related='tool_inventory_id.tool_length', string='刀具总长(mm)')
diameter = fields.Float(related='tool_inventory_id.diameter', string='直径(mm)')
angle = fields.Float(related='tool_inventory_id.angle', string='R角(mm)')
extension = fields.Float(related='tool_inventory_id.extension', string='伸出长度(mm)')
product_ids = fields.Many2many('product.product', string='产品')
knife_handle_model = fields.Selection(related='tool_inventory_id.knife_handle_model', string='使用刀柄型号')
options = fields.Char('产品清单')
def name_get(self):
result = []
for bom in self:
result.append((bom.id, '功能刀具物料清单'))
return result
def bom_product_domains(self, assembly_options):
self.options = assembly_options
cutting_tool_materials = self.env['sf.cutting.tool.material'].search(
[('name', 'in', assembly_options.split('+'))])
domains = []
for index, option in enumerate(cutting_tool_materials):
domain = ['&',('cutting_tool_material_id', '=', option.id),
("cutting_tool_type_id", "in",
self.tool_inventory_id.functional_cutting_tool_model_id.cutting_tool_type_ids.ids)]
if option.name == '刀柄':
domain = ['&']+domain+[ ("cutting_tool_taper_shank_model", "=", self.tool_inventory_id.knife_handle_model)]
if option.name == '整体式刀具':
domain=['&']+domain+[
'|',
# 刀具直径
('cutting_tool_blade_diameter', '=', self.tool_inventory_id.diameter),
# r角
('cutting_tool_blade_tip_working_size', '=', self.tool_inventory_id.angle)]
if option.name == '刀杆':
domain = ['&'] + domain + [
("cutting_tool_cutter_arbor_diameter", "=", self.tool_inventory_id.diameter)]
if option.name == '刀片':
domain = ['&'] + domain + [
("cutting_tool_blade_tip_circular_arc_radius", "=", self.tool_inventory_id.angle)]
if option.name == '刀盘':
domain = ['&'] + domain + [
("cutting_tool_cutter_head_diameter", "=", self.tool_inventory_id.diameter)]
domains=domains+domain
if index != 0:
domains = ['|'] + domains
# wqwqwe = self.env['product.product'].search(ddd)
# product = self.env['product.product'].search(domain)
# if product:
# products = products + product
return domains
def generate_bill_materials(self, assembly_options):
domains=self.bom_product_domains(assembly_options)
products = self.env['product.product'].search(domains)
if products:
self.product_ids = [Command.set(products.ids)]
# if option.name == '刀盘':
# hilt = self.env['product.product'].search(
# [('cutting_tool_blade_diameter', '=', self.tool_inventory_id.diameter),
# ('cutting_tool_material_id', '=', option.id)])
# self.product_ids = [Command.set(hilt.ids)]k
class jikimo_bom_line(models.Model):
_name = 'jikimo.bom.line'
_description = 'jikimo.bom.line'
name = fields.Char()
class ProductProduct(models.Model):
_inherit = 'product.product'
def search(self, args, offset=0, limit=None, order=None, count=False):
# 你可以在这里修改 `args` 以调整搜索条件
# 例如,添加额外的搜索条件
if self.env.context.get('jikimo_bom_product'):
bom_id = self.env['jikimo.bom'].browse(request.session.get('jikimo_bom_product').get('bom_id'))
domains = bom_id.bom_product_domains(bom_id.options)
args=args+domains
return super(ProductProduct, self).search(args, offset=offset, limit=limit, order=order, count=count)

View File

@@ -0,0 +1,34 @@
from odoo import models, fields
from odoo.http import request
class ToolInventory(models.Model):
_inherit = 'sf.tool.inventory'
_description = '功能刀具清单'
knife_handle_model = fields.Selection([('BT30', 'BT30'), ('BT40', 'BT40'), ('BT50', 'BT50'), ('GSK30', 'GSK30'), ('GSK40', 'GSK40'), ('GSK50', 'GSK50')], string='使用刀柄型号')
jikimo_bom_ids = fields.One2many('jikimo.bom','tool_inventory_id', 'bom单')
def bom_mainfest(self):
jikimo_bom_ids = self.mapped('jikimo_bom_ids')
if not jikimo_bom_ids:
self._bom_mainfest()
return self.bom_mainfest()
request.session['jikimo_bom_product'] = {'bom_id': int(self.jikimo_bom_ids)}
# context = dict(self.env.context)
# context.update({'jikimo_bom_product': self.jikimo_bom_ids.options})
# if self.functional_cutting_tool_model_id.cutting_tool_type_ids:
# context.update({'jikimo_bom_product_cutting_tool_type': self.functional_cutting_tool_model_id.cutting_tool_type_ids.ids})
return {
'type': 'ir.actions.act_window',
'name': '刀具组装清单',
'res_model': 'jikimo.bom',
'view_mode': 'form',
'view_id': self.env.ref('sf_tool_management.view_jikimo_bom_form').id,
'res_id': int(self.jikimo_bom_ids),
'target': 'current', # Use 'new' to open in a new window/tab
# {'jikimo_bom_product': self.jikimo_bom_ids.options}
}
# 创建bom单
def _bom_mainfest(self):
self.env['jikimo.bom'].create({'tool_inventory_id':self.id})

View File

@@ -38,3 +38,6 @@ access_sf_fixture_material_search_group_plan_dispatch,sf.fixture.material.search
access_sf_functional_tool_dismantle,sf.functional.tool.dismantle,model_sf_functional_tool_dismantle,base.group_user,1,1,1,0
access_sf_functional_tool_dismantle_group_sf_tool_user,sf.functional.tool.dismantle_group_sf_tool_user,model_sf_functional_tool_dismantle,sf_base.group_sf_tool_user,1,1,1,0
access_sf_functional_tool_dismantle_group_plan_dispatch,sf.functional.tool.dismantle_group_plan_dispatch,model_sf_functional_tool_dismantle,sf_base.group_plan_dispatch,1,0,0,0
access_jikimo_bom,jikimo.bom,model_jikimo_bom,base.group_user,1,1,1,1
access_jikimo_bom_wizard,jikimo.bom.wizard,model_jikimo_bom_wizard,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
38
39
40
41
42
43

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record model="ir.actions.act_window" id="view_jikimo_bom_form_act">
<field name="name">bom物料清单</field>
<field name="res_model">jikimo.bom</field>
<field name="view_mode">tree,form</field>
</record>
<record id="view_jikimo_bom_form" model="ir.ui.view">
<field name="name">jikimo.bom.form</field>
<field name="model">jikimo.bom</field>
<field name="arch" type="xml">
<form>
<header>
<button type="action" name="%(action_jikimo_bom_wizard)d"
class="btn btn-info" string="组装方式.." context="{'default_bom_id':id}"
/>
</header>
<sheet>
<group>
<field name="tool_name"/>
<field name="functional_cutting_tool_model_id"/>
<field name="tool_groups_id"/>
<field name="diameter"/>
</group>
<group>
<field name="angle"/>
<field name="tool_length"/>
<field name="extension"/>
<field name="knife_handle_model"/>
</group>
<notebook colspan="4">
<page string="物料清单">
<field name="product_ids" context="{'jikimo_bom_product': True}">
<tree>
<field name="name"/>
<field name="categ_id"/>
<field name="cutting_tool_model_id"/>
<field name="specification_id"/>
<field name="brand_id"/>
<field name="qty_available"/>
</tree>
</field>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
</odoo>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_tool_inventory_inherit_tree" model="ir.ui.view">
<field name="name">sf.tool.inventory.inherit.tree</field>
<field name="model">sf.tool.inventory</field>
<field name="inherit_id" ref="sf_base.view_tool_inventory_tree"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='type']" position="before">
<field name="knife_handle_model" />
<button name="bom_mainfest" string="bom清单" type="object" class="btn-link"
icon="fa-refresh" />
</xpath>
</field>
</record>
</odoo>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<!-- ================================================功能刀具类型================================================ -->
<record id="view_cutter_function_inherit_tree" model="ir.ui.view">
<field name="name">sf.cutter.function.inherit.tree</field>
<field name="model">sf.functional.cutting.tool.model</field>
<field name="inherit_id" ref="sf_base.view_cutter_function_tree"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='name']" position="after">
<field name="cutting_tool_type_ids" widget="many2many_tags"/>
</xpath>
</field>
</record>
<!-- 功能刀具类型搜索 -->
</odoo>

View File

@@ -1 +1,2 @@
from . import wizard
from . import jikimo_bom_wizard

View File

@@ -0,0 +1,28 @@
import logging
from datetime import timedelta, datetime, date
from odoo import fields, models, api
from odoo.exceptions import ValidationError, UserError
class JikimoBomWizard(models.TransientModel):
_name = 'jikimo.bom.wizard'
_description = '组装方式选择'
bom_id = fields.Many2one('jikimo.bom', '刀具组装清单')
assembly_options = fields.Selection([
('刀柄+整体式刀具', '刀柄+整体式刀具'),
('刀柄+刀杆+刀片', '刀柄+刀杆+刀片'),
('刀柄+刀盘+刀片', '刀柄+刀盘+刀片')
], string='组装方式', required=True)
# assembly_options_ids = fields.Many2many('sf.cutting.tool.material', string="组装方式")
is_ok = fields.Boolean('确认上述信息正确无误。')
def submit(self):
if not self.bom_id:
raise UserError('缺少bom信息')
if self.bom_id.tool_inventory_id.functional_cutting_tool_model_id.name == '飞刀' and self.assembly_options == '刀柄+整体式刀具':
raise UserError('飞刀只可选 刀柄+刀杆+刀片 或 刀柄+刀盘+刀片')
if self.bom_id.tool_inventory_id.functional_cutting_tool_model_id.name in['中心钻','合金钻','合金刀','整体刀','倒角刀','丝锥'] and self.assembly_options != '刀柄+整体式刀具':
raise UserError('此功能刀具只可选 刀柄+整体式刀具')
self.bom_id.generate_bill_materials(self.assembly_options)

View File

@@ -0,0 +1,33 @@
<openerp>
<data>
<record id="action_jikimo_bom_wizard" model="ir.actions.act_window">
<field name="name">组装方式..</field>
<field name="res_model">jikimo.bom.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<record model="ir.ui.view" id="jikimo_bom_wizard_form_view">
<field name="name">jikimo.bom.wizard.form.view</field>
<field name="model">jikimo.bom.wizard</field>
<field name="arch" type="xml">
<form string="组装方式..">
<group>
<field name="assembly_options"/>
<!-- <field name="factory_no" required="1"/>-->
</group>
<div>
<field name="is_ok"/>
确认上述信息正确无误.
</div>
<footer>
<button string="确认组装方式" name="submit" type="object" class="oe_highlight"
attrs="{'invisible':[('is_ok','=',False)]}"/>
<button string="取消" class="btn btn-secondary" special="cancel"/>
</footer>
</form>
</field>
</record>
</data>
</openerp>

View File

@@ -139,5 +139,5 @@ class MrsShelfLocationDataSync(models.Model):
location_id.product_sn_id = False
except Exception as e:
logging.info("捕获错误信息:%s" % e)
logging.info("库区信息同步失败:%s" % e)
raise ValidationError("数据错误导致同步失败,请联系管理员")