From ce532a6b630c54c0ee473ecd5b8a7d07d255749d Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Tue, 30 May 2023 14:50:18 +0800 Subject: [PATCH 1/9] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AE=A1=E6=89=B9?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF=E9=85=8D=E7=BD=AE=E5=AF=B9=E8=B1=A1=EF=BC=8C?= =?UTF-8?q?=E5=BD=93=E4=BC=81=E4=B8=9A=E5=BE=AE=E4=BF=A1=E6=A8=A1=E6=9D=BF?= =?UTF-8?q?=E6=9C=89=E6=9B=B4=E6=96=B0=E6=97=B6=EF=BC=8C=E4=BB=8E=E6=AD=A4?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E5=AF=B9=E8=B1=A1=E8=AF=BB=E5=8F=96=E6=A8=A1?= =?UTF-8?q?=E6=9D=BFid=E5=88=97=E8=A1=A8=EF=BC=8C=E5=8D=B3=E5=8F=AF?= =?UTF-8?q?=E6=9B=B4=E6=96=B0odoo=E4=B8=AD=E7=9A=84=E5=AE=A1=E6=89=B9?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_wxwork_approval/models/wxwork_settings.py | 10 +++++ .../security/ir.model.access.csv | 1 + .../views/wxwork_settings_view.xml | 40 +++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/sf_wxwork_approval/models/wxwork_settings.py b/sf_wxwork_approval/models/wxwork_settings.py index 4e048263..862bc97d 100644 --- a/sf_wxwork_approval/models/wxwork_settings.py +++ b/sf_wxwork_approval/models/wxwork_settings.py @@ -10,3 +10,13 @@ class WxSettings(models.Model): wx_work_app = fields.Char(string='企业微信应用名称') wx_work_corp_id = fields.Char(string='企业微信CorpID') wx_work_secret = fields.Char(string='企业微信Secret') + wx_work_templates = fields.One2many('wxwork.template.settings', 'wxwork_id', string='审批模板') + + +class WxTemplateSettings(models.Model): + _name = 'wxwork.template.settings' + _description = '企业微信模板设置' + + sp_name = fields.Char(string='审批模板名称') + template_id = fields.Char(string='审批模板ID') + wxwork_id = fields.Many2one('wxwork.settings', string='企业微信') diff --git a/sf_wxwork_approval/security/ir.model.access.csv b/sf_wxwork_approval/security/ir.model.access.csv index e3840580..6315b0d5 100644 --- a/sf_wxwork_approval/security/ir.model.access.csv +++ b/sf_wxwork_approval/security/ir.model.access.csv @@ -6,6 +6,7 @@ access_wxwork_approval_template_controls,wxwork.approval.template.controls,model access_wxwork_approval_approver_line,wxwork.approval.approver_line,model_wxwork_approval_approver_line,base.group_user,1,1,1,1 access_wxwork_settings,wxwork.settings,model_wxwork_settings,base.group_user,1,1,1,1 access_wxwork_approval_template_summary,wxwork.approval.template.summary,model_wxwork_approval_template_summary,base.group_user,1,1,1,1 +access_wxwork_template_settings,wxwork.template.settings,model_wxwork_template_settings,base.group_user,1,1,1,1 diff --git a/sf_wxwork_approval/views/wxwork_settings_view.xml b/sf_wxwork_approval/views/wxwork_settings_view.xml index 904fd019..3442a6c8 100644 --- a/sf_wxwork_approval/views/wxwork_settings_view.xml +++ b/sf_wxwork_approval/views/wxwork_settings_view.xml @@ -9,6 +9,7 @@ + @@ -21,6 +22,32 @@ + + + + + + + + 企业微信模板设置 + wxwork.template.settings + + + + + + + + + + 企业微信模板设置 + wxwork.template.settings + +
+ + + +
@@ -37,7 +64,20 @@
+ + 企业微信模板设置 + wxwork.template.settings + tree,form + +

+ 请设置企业微信模板参数!!! +

+
+
+ + From 48e0809bd735c05857a8cb6b08884fbd7de1b8ca Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Wed, 31 May 2023 18:13:12 +0800 Subject: [PATCH 2/9] =?UTF-8?q?=E5=90=8C=E6=AD=A5=E4=BC=81=E4=B8=9A?= =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E5=AE=A1=E6=89=B9=E6=A8=A1=E6=9D=BF~?= =?UTF-8?q?=E9=99=A4=E2=80=9D=E6=8E=A7=E4=BB=B6=E9=85=8D=E7=BD=AE=E2=80=9C?= =?UTF-8?q?=E5=A4=96=E5=9F=BA=E6=9C=AC=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_wxwork_approval/models/__init__.py | 1 + sf_wxwork_approval/models/wx_work_api.py | 177 ++++++++++-------- .../wxwork_approval_template_controls.py | 168 +++++++++-------- sf_wxwork_approval/models/wxwork_settings.py | 129 ++++++++++++- .../security/ir.model.access.csv | 4 + .../views/wxwork_approval_template_view.xml | 94 ++++++++-- 6 files changed, 392 insertions(+), 181 deletions(-) diff --git a/sf_wxwork_approval/models/__init__.py b/sf_wxwork_approval/models/__init__.py index 96798de7..9c7125e6 100644 --- a/sf_wxwork_approval/models/__init__.py +++ b/sf_wxwork_approval/models/__init__.py @@ -5,5 +5,6 @@ from . import wxwork_approval_template_controls from . import wxwork_settings from . import wxwork_approval_template_summary from . import we_approval_record +from . import wx_work_api # from . import res_config_setting diff --git a/sf_wxwork_approval/models/wx_work_api.py b/sf_wxwork_approval/models/wx_work_api.py index eb1b4130..c07c2a3f 100644 --- a/sf_wxwork_approval/models/wx_work_api.py +++ b/sf_wxwork_approval/models/wx_work_api.py @@ -19,6 +19,17 @@ class WxWorkAPI: else: raise Exception(f"获取AccessToken失败: {result}") + def get_template_detail(self, template_data): + url = f"https://qyapi.weixin.qq.com/cgi-bin/oa/gettemplatedetail?access_token={self.access_token}" + headers = {'Content-Type': 'application/json'} + response = requests.post(url, json=template_data, headers=headers) + result = response.json() + if result['errcode'] == 0: + # print(result) + return result + else: + raise Exception(f"获取模板详情请求失败: {result}") + def create_approval_request(self, approval_data): url = f"https://qyapi.weixin.qq.com/cgi-bin/oa/applyevent?access_token={self.access_token}" headers = {'Content-Type': 'application/json'} @@ -60,89 +71,89 @@ class WxWorkAPI: return result['media_id'] -template_id_dict = {"test": "ZvmJBAt7U2iUju9JLePxfkfuN22meQMVTAHymA"} -creator_userid = "MaGuangWei" -corid = 'wweaf7f1caab27a136' -secret = 'L6z-kjrUBOWfhBiLOmX_fNSY3jydDkLUNNWnemafn00' -wx = WxWorkAPI(corid, secret) -media_id = wx.upload_temp_file() -print(media_id) -# access = wx.get_access_token() -approval_datas = { - "creator_userid": creator_userid, - "template_id": template_id_dict['test'], - "use_template_approver": 0, - # "choose_department": 2, - "approver": [ - { - "attr": 2, - "userid": ["MaGuangWei", "YangJinLing"] - }, - { - "attr": 1, - "userid": ["MaGuangWei"] - } - ], - "notifyer": ["MaGuangWei", "PengYuBo"], - # "notifyer": ["MaGuangWei"], - "notify_type": 1, - "apply_data": { - "contents": [ - # 申请事项 - { - "control": "Text", - "id": "Text-1640339319582", - "value": { - "text": "测试测试测试测试测试" - } - }, - # 申请内容 - { - "control": "Textarea", - "id": "Textarea-1640339335659", - "value": { - "text": "odoo>>>企业微信审批" - } - }, - # 附件 - { - "control": "File", - "id": "File-1640339381728", - "value": { - "files": [ - { - "file_id": media_id - } - ] - } - - }, - - ] - }, - "summary_list": [ - { - "summary_info": [{ - "text": "测试附件上传", - "lang": "zh_CN" - }] - }, - # { - # "summary_info": [{ - # "text": "摘要第2行", - # "lang": "zh_CN" - # }] - # }, - # { - # "summary_info": [{ - # "text": "摘要第3行", - # "lang": "zh_CN" - # }] - # } - ] -} -wx.create_approval_request(approval_datas) -print('创建成功') +# template_id_dict = {"test": "ZvmJBAt7U2iUju9JLePxfkfuN22meQMVTAHymA"} +# creator_userid = "MaGuangWei" +# corid = 'wweaf7f1caab27a136' +# secret = 'L6z-kjrUBOWfhBiLOmX_fNSY3jydDkLUNNWnemafn00' +# wx = WxWorkAPI(corid, secret) +# media_id = wx.upload_temp_file() +# print(media_id) +# # access = wx.get_access_token() +# approval_datas = { +# "creator_userid": creator_userid, +# "template_id": template_id_dict['test'], +# "use_template_approver": 0, +# # "choose_department": 2, +# "approver": [ +# { +# "attr": 2, +# "userid": ["MaGuangWei", "YangJinLing"] +# }, +# { +# "attr": 1, +# "userid": ["MaGuangWei"] +# } +# ], +# "notifyer": ["MaGuangWei", "PengYuBo"], +# # "notifyer": ["MaGuangWei"], +# "notify_type": 1, +# "apply_data": { +# "contents": [ +# # 申请事项 +# { +# "control": "Text", +# "id": "Text-1640339319582", +# "value": { +# "text": "测试测试测试测试测试" +# } +# }, +# # 申请内容 +# { +# "control": "Textarea", +# "id": "Textarea-1640339335659", +# "value": { +# "text": "odoo>>>企业微信审批" +# } +# }, +# # 附件 +# { +# "control": "File", +# "id": "File-1640339381728", +# "value": { +# "files": [ +# { +# "file_id": media_id +# } +# ] +# } +# +# }, +# +# ] +# }, +# "summary_list": [ +# { +# "summary_info": [{ +# "text": "测试附件上传", +# "lang": "zh_CN" +# }] +# }, +# # { +# # "summary_info": [{ +# # "text": "摘要第2行", +# # "lang": "zh_CN" +# # }] +# # }, +# # { +# # "summary_info": [{ +# # "text": "摘要第3行", +# # "lang": "zh_CN" +# # }] +# # } +# ] +# } +# wx.create_approval_request(approval_datas) +# print('创建成功') aa = {"errcode": 0, "errmsg": "ok", "template_names": [{"text": "对接开发测试", "lang": "zh_CN"}], "template_content": { "controls": [{"property": {"control": "Text", "id": "Text-1640339319582", diff --git a/sf_wxwork_approval/models/wxwork_approval_template_controls.py b/sf_wxwork_approval/models/wxwork_approval_template_controls.py index cc5e4273..d903ab3f 100644 --- a/sf_wxwork_approval/models/wxwork_approval_template_controls.py +++ b/sf_wxwork_approval/models/wxwork_approval_template_controls.py @@ -6,97 +6,103 @@ from odoo.exceptions import UserError _logger = logging.getLogger(__name__) +# 控件模型 class WxWorkApprovalTemplate(models.Model): _name = 'wxwork.approval.template.controls' _description = "企业微信审批模板控件" + + template_id = fields.Many2one('wxwork.approval.template', string='模板') + property_id = fields.One2many('property.model', 'control_id', string='控件属性') + config_id = fields.One2many('config.model', 'control_id', string='控件配置') + + +# 控件属性模型 +class PropertyModel(models.Model): + _name = 'property.model' _rec_name = "title" - SELECTION_RELATION = { - '申请事项': {'id': 'Text-1640339319582', 'control': 'Text', 'value': '{"text": "文本填写的内容"}'}, - '申请内容': {'id': 'Textarea-1640339335659', 'control': 'Textarea', 'value': '{"text": "文本填写的内容"}'}, - '多行文本': {'id': 'Textarea-1684823453770', 'control': 'Textarea', 'value': '{"text": "文本填写的内容"}'}, - '金额': {'id': 'Money-1684823460232', 'control': 'Money', 'value': '{"new_money": "0"}'}, - '部门': {'id': 'Contact-1684823477216', 'control': 'Contact', - 'value': '{"departments":[{"openapi_id":"2","name":"销售部"},{"openapi_id":"3","name":"生产部"}]}'}, - '成员': {'id': 'Contact-1684823465317', 'control': 'Contact', - 'value': '{"members":[{"userid":"WuJunJie","name":"Jackie"},{"userid":"WangXiaoMing","name":"Tom"}]}'}, - '明细': {'id': 'Table-1684823492261', 'control': 'Table', - 'value': '{"children":[{"list":[' - '{"control":"Text","id":"Text-15111111111","title":' - '[{"text":"明细内文本控件","lang":"zh_CN"}],"value":{"text":"明细文本1"}},' - '{"control":"Money","id":"Text-15111111112","title":[{"text":"明细内金额控件","lang":"zh_CN"}],' - '"value":{"new_money":"700"}}]},' - '{"list":[{"control":"Text","id":"Text-15111111111",' - '"title":[{"text":"明细内文本控件","lang":"zh_CN"}],"value":{"text":"明细文本2"}},' - '{"control":"Money","id":"Text-15111111112","title":[{"text":"明细内金额控件","lang":"zh_CN"}],' - '"value":{"new_money":"900"}}]}]}'}, - '关联申请单': {'id': 'RelatedApproval-1684823485883', 'control': 'RelatedApproval', - 'value': '{"related_approval":[{"sp_no":"202011180001"}]}'}, - '附件': {'id': 'File-1640339381728', 'control': 'File', - 'value': '{"files":[{"file_id":"1G6nrLmr5EC3MMb_-zK1dDdzmd0p7cNliYu9V5w7o8K1aaa"}]}'}, - '数字': {'id': 'File-1640339381728', 'control': 'Number', 'value': '{"new_number": "700"}'}, - '日期/日期+时间': {'id': 'File-1640339381728', 'control': 'Date', - 'value': '{"date": {"type": "day","s_timestamp": "1569859200"}}'}, - '单选/多选': {'id': 'File-1640339381728', 'control': 'Selector', - 'value': '{"selector": ' - '{"type": "multi","options": [{"key": "option-15111111111"},{"key": "option-15222222222"}]}}' - }, - '说明文字': {'id': 'File-1640339381728', 'control': 'Tips'}, - '位置': {'id': 'File-1640339381728', 'control': 'Location', - 'value': '{"location":{"latitude":"30.547239","longitude":"104.063291",' - '"title":"腾讯科技(成都)有限公司(腾讯成都大厦)",' - '"address":"四川省成都市武侯区天府三街198号腾讯成都大厦A座","time":1605690460}}'}, - '公式': {'id': 'File-1640339381728', 'control': 'Formula', 'value': '{"formula":{"value":"5.0"}}'}, - '时长': {'id': 'File-1640339381728', 'control': 'DateRange', - 'value': '{"date_range":{"new_begin":1570550400,"new_end":1570593600,"new_duration":86400}}'}, - '请假组件': {'id': 'File-1640339381728', 'control': 'Vacation', - 'value': '{"vacation":{"selector":{"type":"single","options":[{"key":"3",' - '"value":[{"text":"病假","lang":"zh_CN"}]}],"exp_type":0},' - '"attendance":{"date_range":{"type":"hour","new_begin":1568077200,' - '"new_end":1568368800,"new_duration":291600},"type":1}}}'}, - '出差/外出/加班组件': {'id': 'File-1640339381728', 'control': 'Attendance', - 'value': '{"attendance":{"date_range":{"type":"halfday","new_begin":1570550400,' - '"new_end":1570593600,"new_duration":86400},"type":4}}'}, - - } - - title = fields.Selection( - selection=[(key, key) for key in SELECTION_RELATION.keys()], - string='控件名称', - ) - template_id = fields.Many2one('wxwork.approval.template', string='模板名称') - control_id = fields.Char(string='控件ID') - control = fields.Char(string='控件类型') - value = fields.Char(string='内容') - - placeholder = fields.Char(string='占位符') - require = fields.Boolean(string='必填', compute='_compute_require') - un_print = fields.Boolean(string='不打印') + CONTROL_TYPE_SELECTION = [ + ('Text', '文本'), + ('Textarea', '多行文本'), + ('Number', '数字'), + ('Money', '金额'), + ('Date', '日期/日期+时间'), + ('Selector', '单选/多选'), + ('Contact', '成员/部门'), + ('Tips', '说明文字'), + ('File', '附件'), + ('Table', '明细'), + ('Attendance', '假勤控件'), + ('Vacation', '请假控件'), + ('Location', '位置'), + ('RelatedApproval', '关联审批单'), + ('Formula', '公式'), + ('DateRange', '时长') + ] + control_type = fields.Selection(CONTROL_TYPE_SELECTION, string='控件类型') + control_id = fields.Many2one('wxwork.approval.template.controls', string='控件') + unique_control_id = fields.Char(string='控件ID') + title = fields.Char(string='控件名称', translate=True) + placeholder = fields.Char(string='控件说明', translate=True) + require = fields.Boolean(string='是否必填') + un_print = fields.Boolean(string='是否参与打印') un_replace = fields.Boolean(string='不替换') - display = fields.Boolean(string='显示', compute='_compute_display') + display = fields.Boolean(string='显示') + child_control_id = fields.Many2one('config.model', string='明细子控件') - @api.onchange('title') - def _onchange_title(self): - if self.title: - related_values = WxWorkApprovalTemplate.SELECTION_RELATION[self.title] - self.control_id = related_values['id'] - self.control = related_values['control'] - # 特殊处理:对于"说明文字",将"value"设置为空字符串 - if self.control == 'Tips': - self.value = '' - else: - self.value = related_values['value'] +# 控件配置模型 +class ConfigModel(models.Model): + _name = 'config.model' + _rec_name = "title" - @api.depends('title') - def _compute_require(self): - for record in self: - record.require = record.title in ['申请事项', '申请内容'] + control_id = fields.Many2one('wxwork.approval.template.controls', string='控件') + # 在此添加其他字段以存储不同控件类型的附加类型和属性 + date_type = fields.Selection([('day', '日期'), ('hour', '日期+时间')], string='日期类型') - @api.depends('title') - def _compute_display(self): - for record in self: - record.display = record.title in ['申请事项', '申请内容'] + selector_type = fields.Selection([('single', '单选'), ('multi', '多选')], string='选择器类型') + options = fields.One2many('config.option', 'config_id', string='选项') + + contact_type = fields.Selection( + [('single', '单选'), ('multi', '多选')], + string='联系人类型') + contact_mode = fields.Selection( + [('user', '成员'), ('department', '部门')], + string='联系人模式') + + # table_children = fields.One2many('config.child', 'config_id', string='明细子控件') + table_children = fields.One2many('property.model', 'child_control_id', string='明细子控件') + + attendance_type = fields.Selection([('1', '请假'), ('3', '出差'), ('4', '外出'), ('5', '加班')], string='假勤组件类型') + attendance_date_range_type = fields.Selection([('hour', '分钟'), ('halfday', '上午/下午')], string='假勤时间刻度') + + vacation_list = fields.One2many('config.option', 'config_id', string='假期类型列表') + + +class ConfigOption(models.Model): + _name = 'config.option' + + key = fields.Char(string='选项Key') + text = fields.Char(string='选项Text') + lang = fields.Char(string='语言') + config_id = fields.Many2one('config.model', string='配置') + + +class ConfigChild(models.Model): + _name = 'config.child' + + control = fields.Char(string='控件类型') + control_id = fields.Char(string='控件ID') + # 其他属性... + + +class VacationType(models.Model): + _name = 'vacation.type' + + config_id = fields.Many2one('config.model', string='配置') + vacation_id = fields.Integer(string='假期ID') + name = fields.Char(string='假期名称') + lang = fields.Char(string='语言') class ApproverLine(models.Model): diff --git a/sf_wxwork_approval/models/wxwork_settings.py b/sf_wxwork_approval/models/wxwork_settings.py index 862bc97d..8b62e334 100644 --- a/sf_wxwork_approval/models/wxwork_settings.py +++ b/sf_wxwork_approval/models/wxwork_settings.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- +import json from odoo import api, fields, models +from odoo.addons.sf_wxwork_approval.models import wx_work_api class WxSettings(models.Model): @@ -10,7 +12,130 @@ class WxSettings(models.Model): wx_work_app = fields.Char(string='企业微信应用名称') wx_work_corp_id = fields.Char(string='企业微信CorpID') wx_work_secret = fields.Char(string='企业微信Secret') - wx_work_templates = fields.One2many('wxwork.template.settings', 'wxwork_id', string='审批模板') + wx_work_template_ids = fields.Many2many('wxwork.template.settings', string='审批模板') + + def update_template(self): + template_dict = {} + template_list = [] + print(self.wx_work_template_ids) + for template in self.wx_work_template_ids: + # template_dict[template.sp_name] = template.template_id + template_list.append(template.template_id) + # template_dict = {} + # print(template_list) + wx = wx_work_api.WxWorkAPI(self.wx_work_corp_id, self.wx_work_secret) + # print(wx) + # 获取模型中的所有记录 + all_records = self.env['wxwork.approval.template'].search([]) + all_records1 = self.env['wxwork.approval.template.controls'].search([]) + + # 删除所有记录 + all_records.unlink() + all_records1.unlink() + for template in template_list: + print('====================') + temp_dict = {'template_id': template} + # print(json.dumps(temp_dict)) + # aa = json.dumps(temp_dict) + template_detail = wx.get_template_detail(temp_dict) + # print('template_detail%s' % template_detail) + # + # # 准备用于创建记录的字段值 + # values = { + # 'process_code': template, + # 'name': template_detail['template_names'][0]['text'], + # # 如果需要设置content_ids,请按照正确格式添加关联数据 + # } + # # 使用create方法创建记录 + # new_record = self.env['wxwork.approval.template'].create(values) + + # 解析template_detail中的内容数据 + content_data_list = [] + # print('jjjjjjjj', template_detail['template_content']) + # print('jjjjjjjjjj', template_detail['template_content']['controls']) + for control_data in template_detail['template_content']['controls']: + print('control_data', control_data) + property_data = control_data['property'] + config_values = {} + + # print(property_data) + # 准备用于创建记录的字段值 + property_values = { + 'control_type': property_data.get('control', ''), + 'unique_control_id': property_data.get('id', ''), + 'title': property_data['title'][0]['text'] if 'title' in property_data else '', + 'placeholder': property_data['placeholder'][0]['text'] if 'placeholder' in property_data else '', + 'require': property_data.get('require', None), + 'un_print': property_data.get('un_print', None), + 'un_replace': property_data.get('un_replace', None), + 'display': property_data.get('display', None), + # 'un_replace': template_detail['template_names'][0]['text'], + # 如果需要设置content_ids,请按照正确格式添加关联数据 + } + # print('property_values', property_values) + # config_data = None + + if 'config' in control_data: + + config_data = control_data['config'] + # print('config_data===', config_data) + if '"date":' in config_data: + # config_values = { + # 'date_type': config_data.get('type', ''), + # } + config_values['date_type'] = config_data.get('type', '') + if '"selector":' in config_data: + # config_values = { + # 'selector_type': config_data.get('type', ''), + # # 'options': config_data['title'][0]['text'] if 'title' in property_data else '', + # } + config_values['selector_type'] = config_data.get('type', '') + if '"contact":' in config_data: + # config_values = { + # 'contact_type': config_data.get('type', ''), + # 'contact_mode': config_data.get('mode', ''), + # + # } + config_values['contact_type'] = config_data.get('type', '') + config_values['contact_mode'] = config_data.get('mode', '') + if '"table":' in config_data: + pass + # config_values = { + # 'table_children': config_data.get('un_print', None), + # } + if '"attendance":' in config_data: + pass + # config_values = { + # 'attendance_type': config_data.get('un_replace', None), + # 'attendance_date_range_type': config_data.get('display', None), + # # 如果需要设置content_ids,请按照正确格式添加关联数据 + # } + if '"vacation_list":' in config_data: + pass + # config_values = { + # 'vacation_list': config_data['template_names'][0]['text'], + # # 如果需要设置content_ids,请按照正确格式添加关联数据 + # } + + content_data_list.append((0, 0, { + 'property_id': [(0, 0, property_values)], + 'config_id': [(0, 0, config_values)], + })) + else: + content_data_list.append((0, 0, { + 'property_id': [(0, 0, property_values)], + # 'config_id': [(0, 0, config_values)], + })) + + # 准备用于创建记录的字段值,包括content_ids数据 + values = { + 'process_code': template, + 'name': template_detail['template_names'][0]['text'], + 'content_ids': content_data_list, + } + + # 使用create方法创建记录 + new_record = self.env['wxwork.approval.template'].create(values) class WxTemplateSettings(models.Model): @@ -19,4 +144,4 @@ class WxTemplateSettings(models.Model): sp_name = fields.Char(string='审批模板名称') template_id = fields.Char(string='审批模板ID') - wxwork_id = fields.Many2one('wxwork.settings', string='企业微信') + # wxwork_id = fields.Many2one('wxwork.settings', string='企业微信') diff --git a/sf_wxwork_approval/security/ir.model.access.csv b/sf_wxwork_approval/security/ir.model.access.csv index 6315b0d5..6374ff3a 100644 --- a/sf_wxwork_approval/security/ir.model.access.csv +++ b/sf_wxwork_approval/security/ir.model.access.csv @@ -7,6 +7,10 @@ access_wxwork_approval_approver_line,wxwork.approval.approver_line,model_wxwork_ access_wxwork_settings,wxwork.settings,model_wxwork_settings,base.group_user,1,1,1,1 access_wxwork_approval_template_summary,wxwork.approval.template.summary,model_wxwork_approval_template_summary,base.group_user,1,1,1,1 access_wxwork_template_settings,wxwork.template.settings,model_wxwork_template_settings,base.group_user,1,1,1,1 +access_property_model,property.model,model_property_model,base.group_user,1,1,1,1 +access_config_model,config.model,model_config_model,base.group_user,1,1,1,1 +access_config_option,config.option,model_config_option,base.group_user,1,1,1,1 +access_vacation_type,vacation.type,model_vacation_type,base.group_user,1,1,1,1 diff --git a/sf_wxwork_approval/views/wxwork_approval_template_view.xml b/sf_wxwork_approval/views/wxwork_approval_template_view.xml index 175ab1dc..ce1304bb 100644 --- a/sf_wxwork_approval/views/wxwork_approval_template_view.xml +++ b/sf_wxwork_approval/views/wxwork_approval_template_view.xml @@ -10,8 +10,8 @@ - + @@ -23,8 +23,8 @@
- + @@ -33,7 +33,7 @@ - + - - -
- - - -
- - - -
- - - -
- -
- - -
- - - - diff --git a/mrp_workorder_hr/static/src/components/popup.js b/mrp_workorder_hr/static/src/components/popup.js deleted file mode 100644 index 44b92f61..00000000 --- a/mrp_workorder_hr/static/src/components/popup.js +++ /dev/null @@ -1,25 +0,0 @@ -/** @odoo-module **/ - -const { Component } = owl; - -export class SelectionPopup extends Component { - - get title() { - return this.props.popupData.title; - } - - get list() { - return this.props.popupData.list; - } - - cancel() { - this.props.onClosePopup('SelectionPopup', true); - } - - async selectItem(id) { - await this.props.onSelectEmployee(id); - this.props.onClosePopup('SelectionPopup'); - } -} - -SelectionPopup.template = 'mrp_workorder_hr.SelectionPopup'; diff --git a/mrp_workorder_hr/static/src/components/popup.xml b/mrp_workorder_hr/static/src/components/popup.xml deleted file mode 100644 index 7bac9a0e..00000000 --- a/mrp_workorder_hr/static/src/components/popup.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - diff --git a/mrp_workorder_hr/static/src/components/tablet.js b/mrp_workorder_hr/static/src/components/tablet.js deleted file mode 100644 index a129c0b8..00000000 --- a/mrp_workorder_hr/static/src/components/tablet.js +++ /dev/null @@ -1,156 +0,0 @@ -/** @odoo-module **/ - -import { useBus, useService } from "@web/core/utils/hooks"; -import Tablet from '@mrp_workorder/components/tablet'; -import { SelectionPopup } from '@mrp_workorder_hr/components/popup'; -import { WorkingEmployeePopup } from '@mrp_workorder_hr/components/working_employee_popup'; -import { patch } from 'web.utils'; -import { PinPopup } from '@mrp_workorder_hr/components/pin_popup'; - -const { onMounted } = owl; - -patch(Tablet.prototype, 'mrp_workorder_hr', { - setup() { - this._super(); - this.notification = useService("notification"); - this.popup.SelectionPopup = { - isShown: false, - data: {}, - }; - this.popup.PinPopup = { - isShown: false, - data: {}, - }; - this.popup.WorkingEmployeePopup = { - isShown: false, - data: {}, - }; - this.state.tabletEmployeeIds = []; - this.employee = this.props.action.context.employee_id; - this.actionRedirect = false; - useBus(this.workorderBus, "popupEmployeeManagement", this.popupEmployeeManagement); - onMounted(() => this.checkEmployeeLogged()); - }, - - checkEmployeeLogged() { - if (this.data.employee_list.length && !this.data.employee && !this.employee) { - this.popupAddEmployee(); - } - }, - // Popup Menu Actions - - popupEmployeeManagement() { - this.showPopup({ workorderId: this.workorderId }, 'WorkingEmployeePopup'); - }, - - popupAddEmployee() { - const list = this.data.employee_list.filter(e => ! this.data.employee_ids.includes(e.id)).map((employee) => { - return { - id: employee.id, - item: employee, - label: employee.name, - isSelected: false, - }; - }); - const title = this.env._t('Change Worker'); - this.showPopup({ title, list }, 'SelectionPopup'); - }, - - popupEmployeePin(employeeId) { - const employee = this.data.employee_list.find(e => e.id === employeeId); - this.showPopup({ employee }, 'PinPopup'); - }, - - // Buisness method - - async lockEmployee(employeeId, pin) { - const pinValid = await this._checkPin(employeeId, pin); - if (! pinValid) { - this.actionRedirect = this.lockEmployee; - return; - } - this.render(); - }, - - async startEmployee(employeeId, pin) { - const pinValid = await this._checkPin(employeeId, pin); - if (! pinValid) { - this.actionRedirect = this.startEmployee; - return; - } - this.state.tabletEmployeeIds.push(employeeId); - await this.orm.call( - 'mrp.workorder', - 'start_employee', - [this.workorderId, employeeId], - ); - await this.getState(); - this.render(); - }, - - async stopEmployee(employeeId, pin) { - const pinValid = await this._checkPin(employeeId, pin, false); - if (! pinValid) { - this.actionRedirect = this.stopEmployee; - return; - } - const index = this.state.tabletEmployeeIds.indexOf(employeeId); - this.state.tabletEmployeeIds.slice(index, 1); - await this.orm.call( - 'mrp.workorder', - 'stop_employee', - [this.workorderId, employeeId], - ); - await this.getState(); - this.render(); - }, - - redirectToAction(employeeId, pin) { - this.actionRedirect(employeeId, pin); - this.actionRedirect = false; - }, - - get isBlocked() { - let isBlocked = this._super(); - if (this.data.employee_list.length !== 0 && ! this.data.employee_id) { - isBlocked = true; - } - return isBlocked; - }, - - // Private - - async _checkPin(employeeId, pin, sessionSave = true) { - const pinValid = await this.orm.call('hr.employee', 'login', [employeeId, pin, sessionSave]); - if (!pinValid) { - this.popupEmployeePin(employeeId); - return; - } - return true; - }, - - _onBarcodeScanned(barcode) { - const employee = this.data.employee_list.find(e => e.barcode === barcode); - if (employee) { - this.startEmployee(employee.id); - } else { - return this._super(barcode); - } - }, - - async _onWillStart() { - const superMethod = this._super; - const employeeId = this.props.action.context.employee_id; - if (employeeId) { - await this.startEmployee(employeeId); - } - await superMethod(); - if (employeeId) { - await this.getState(); - } - }, -}); - -Tablet.components.SelectionPopup = SelectionPopup; -Tablet.components.PinPopup = PinPopup; -Tablet.components.WorkingEmployeePopup = WorkingEmployeePopup; diff --git a/mrp_workorder_hr/static/src/components/tablet.xml b/mrp_workorder_hr/static/src/components/tablet.xml deleted file mode 100644 index 67d6a18a..00000000 --- a/mrp_workorder_hr/static/src/components/tablet.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - -
- -
-
- -
-
- -
-
-
-
diff --git a/mrp_workorder_hr/static/src/components/working_employee_popup.js b/mrp_workorder_hr/static/src/components/working_employee_popup.js deleted file mode 100644 index 4f8dbeb2..00000000 --- a/mrp_workorder_hr/static/src/components/working_employee_popup.js +++ /dev/null @@ -1,80 +0,0 @@ -/** @odoo-module **/ - -import { MrpTimer } from "@mrp/widgets/timer"; -import { useService } from "@web/core/utils/hooks"; -import time from 'web.time'; - -const { Component, onWillStart } = owl; - -export class WorkingEmployeePopup extends Component { - setup() { - super.setup(); - this.orm = useService('orm'); - this.workorderId = this.props.popupData.workorderId; - - onWillStart(() => this._getState()) - } - - addEmployee() { - this.props.onAddEmployee(); - this.close(); - } - - lockEmployee(employeeId) { - this.startEmployee(employeeId); - this.props.onLockEmployee(employeeId); - this.close(); - } - - async stopEmployee(employeeId) { - this.props.onStopEmployee(employeeId); - this.lines.map(l => { - if (l.employee_id === employeeId) { - l.ongoing = false; - } - }); - this.render(); - } - - startEmployee(employeeId) { - this.props.onStartEmployee(employeeId); - this.lines.map(l => { - if (l.employee_id === employeeId) { - l.ongoing = true; - } - }); - this.render(); - } - - close() { - this.props.onClosePopup('WorkingEmployeePopup', true); - } - - async _getState() { - const productivityLines = await this.orm.call('mrp.workcenter.productivity', 'read_group', [ - [ - ['workorder_id', '=', this.workorderId], - ['employee_id', '!=', false], - ], - ['duration', 'date_start:array_agg', 'date_end:array_agg'], - ['employee_id'] - ]); - this.lines = productivityLines.map((pl) => { - let duration = pl.duration * 60; - const ongoingTimerIndex = pl.date_end.indexOf(null); - if ( ongoingTimerIndex != -1 ){ - const additionalDuration = moment(new Date()).diff(moment(time.auto_str_to_date(pl.date_start[ongoingTimerIndex])), 'seconds'); - duration += additionalDuration; - } - return { - 'employee_id': pl.employee_id[0], - 'employee_name': pl.employee_id[1], - 'duration': duration, - 'ongoing': pl.date_end.some(d => !d), - } - }) - } -} - -WorkingEmployeePopup.components = { MrpTimer }; -WorkingEmployeePopup.template = 'mrp_workorder_hr.WorkingEmployeePopup'; diff --git a/mrp_workorder_hr/static/src/components/working_employee_popup.scss b/mrp_workorder_hr/static/src/components/working_employee_popup.scss deleted file mode 100644 index db4914d1..00000000 --- a/mrp_workorder_hr/static/src/components/working_employee_popup.scss +++ /dev/null @@ -1,13 +0,0 @@ -.o_popup_employee_selection { - display: flex; - flex-direction: row; - justify-content: space-between; - line-height: 50px; - color: black; - div { - flex-basis: 25%; - } - .o_popup_employee_name { - flex-basis: 50%; - } -} diff --git a/mrp_workorder_hr/static/src/components/working_employee_popup.xml b/mrp_workorder_hr/static/src/components/working_employee_popup.xml deleted file mode 100644 index c7674160..00000000 --- a/mrp_workorder_hr/static/src/components/working_employee_popup.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - -
- -
-
-
diff --git a/mrp_workorder_hr/static/src/views/kanban/mrp_workorder_kanban_controller.js b/mrp_workorder_hr/static/src/views/kanban/mrp_workorder_kanban_controller.js deleted file mode 100644 index b67367d8..00000000 --- a/mrp_workorder_hr/static/src/views/kanban/mrp_workorder_kanban_controller.js +++ /dev/null @@ -1,152 +0,0 @@ -/** @odoo-module */ - -import { SelectionPopup } from '@mrp_workorder_hr/components/popup'; -import { PinPopup } from '@mrp_workorder_hr/components/pin_popup'; -import { useBus, useService } from "@web/core/utils/hooks"; -import { patch } from "@web/core/utils/patch"; -import {MrpWorkorderKanbanController} from '@mrp_workorder/views/kanban/mrp_workorder_kanban_controller'; - -const {onWillStart, useState, onMounted} = owl; - -MrpWorkorderKanbanController.components.SelectionPopup = SelectionPopup; -MrpWorkorderKanbanController.components.PinPopup = PinPopup; - -patch(MrpWorkorderKanbanController.prototype, 'mrp_workorder_hr', { - setup() { - this._super(); - this.popup = useState({ - PinPopup: { - isShown: false, - data: {}, - }, - SelectionPopup: { - isShown: false, - data: {}, - } - }); - this.notification = useService('notification'); - this.barcode = useService("barcode"); - useBus(this.barcode.bus, 'barcode_scanned', (event) => this._onBarcodeScanned(event.detail.barcode)); - this.workcenterId = this.props.context.default_workcenter_id; - this.workcenter = false; - this.employee = useState({ - name: false || this.props.context.employee_name, - id: 0 || this.props.context.employee_id, - }); - onWillStart(async () => { - await this.onWillStart(); - }); - onMounted(() => { - this.onMount(); - }); - }, - - async onWillStart() { - if (!this.workcenterId) { - return; - } - const workcenter = await this.orm.read( - "mrp.workcenter", [this.workcenterId], ['allow_employee', 'employee_ids'] - ); - this.workcenter = workcenter[0]; - if (!this.workcenter.allow_employee) { - return; - } - const fieldsToRead = ['id', 'name', 'barcode']; - const employees_domain = []; - if (this.workcenter.employee_ids.length) { - employees_domain.push(['id', 'in', this.workcenter.employee_ids]); - } - this.employees = await this.orm.searchRead( - "hr.employee", employees_domain, fieldsToRead, - ); - }, - - onMount() { - if (this.employeeId) { - this.selectEmployee(this.employeeId); - } - }, - - // destroy: function () { - // core.bus.off('barcode_scanned', this, this._onBarcodeScanned); - // this._super(); - // }, - - openEmployeeSelection() { - const employeeList = this.employees.map(employee => Object.create({ - id: employee.id, - item: employee, - label: employee.name, - isSelected: employee === this.employee.id, - })); - this.popup.SelectionPopup = { - data: { title: this.env._t('Select Employee'), list: employeeList }, - isShown: true, - }; - }, - - async selectEmployee(employeeId, pin) { - const employee = this.employees.find(e => e.id === employeeId); - const employee_function = this.employee.name && this.employee.id === employeeId ? 'logout' : 'login'; - const pinValid = await this.orm.call( - "hr.employee", employee_function, [employeeId, pin], - ); - if (!pinValid && this.popup.PinPopup.isShown) { - this.notification.add(this.env._t('Wrong password !'), {type: 'danger'}); - return; - } - if (!pinValid) { - this._askPin(employee); - return; - } - - if (employee_function === 'login') { - this.notification.add(this.env._t('Logged in!'), {type: 'success'}); - this.employee = { - name: employee.name, - id: employee.id, - }; - if (this.context.openRecord) { - this.openRecord(...this.context.openRecord); - - } - } else { - this.employee = { - name: false, - id: 0, - }; - } - }, - - closePopup(popupName) { - this.popup[popupName].isShown = false; - }, - - _askPin(employee) { - this.popup.PinPopup = { - data: {employee: employee}, - isShown: true, - }; - }, - - _onBarcodeScanned(barcode) { - const employee = this.employees.find(e => e.barcode === barcode); - if (employee) { - this.selectEmployee(employee.id); - } else { - this.notification.add(this.env._t('This employee is not allowed on this workcenter'), {type: 'danger'}); - } - }, - - async openRecord(record, mode) { - if (this.employees && !this.employee.name) { - this.context.openRecord = [record, mode]; - this.openEmployeeSelection(); - return; - } - delete this.context.openRecord; - Object.assign(this.context, {employee_id: this.employee.id}); - this._super(...arguments); - }, -}); diff --git a/mrp_workorder_hr/static/src/views/list/mrp_workorder_list_controller.js b/mrp_workorder_hr/static/src/views/list/mrp_workorder_list_controller.js deleted file mode 100644 index fa43f183..00000000 --- a/mrp_workorder_hr/static/src/views/list/mrp_workorder_list_controller.js +++ /dev/null @@ -1,152 +0,0 @@ -/** @odoo-module */ - -import { SelectionPopup } from "@mrp_workorder_hr/components/popup"; -import { PinPopup } from "@mrp_workorder_hr/components/pin_popup"; -import core from "web.core"; -import { useService } from "@web/core/utils/hooks"; -import { patch } from "@web/core/utils/patch"; -import {MrpWorkorderListController} from "@mrp_workorder/views/list/mrp_workorder_list_controller"; - -const {onWillStart, useState, onMounted} = owl; - -MrpWorkorderListController.components.SelectionPopup = SelectionPopup; -MrpWorkorderListController.components.PinPopup = PinPopup; - -patch(MrpWorkorderListController.prototype, "mrp_workorder_hr", { - setup() { - this._super(); - this.popup = useState({ - PinPopup: { - isShown: false, - data: {}, - }, - SelectionPopup: { - isShown: false, - data: {}, - } - }); - this.notification = useService("notification"); - this.orm = useService("orm"); - this.workcenterId = this.props.context.default_workcenter_id; - this.workcenter = false; - this.employee = useState({ - name: false || this.props.context.employee_name, - id: 0 || this.props.context.employee_id, - }); - onWillStart(async () => { - await this.onWillStart(); - }); - onMounted(() => { - this.onMount(); - }); - }, - - async onWillStart() { - if (!this.workcenterId) { - return; - } - const workcenter = await this.orm.read( - "mrp.workcenter", [this.workcenterId], ["allow_employee", "employee_ids"] - ); - this.workcenter = workcenter[0]; - if (!this.workcenter.allow_employee) { - return; - } - const fieldsToRead = ["id", "name", "barcode"]; - const employees_domain = []; - if (this.workcenter.employee_ids.length) { - employees_domain.push(["id", "in", this.workcenter.employee_ids]); - } - this.employees = await this.orm.searchRead( - "hr.employee", employees_domain, fieldsToRead, - ); - }, - - onMount() { - if (this.employeeId) { - this.selectEmployee(this.employeeId); - } - core.bus.on("barcode_scanned", this, this._onBarcodeScanned); - }, - - // destroy: function () { - // core.bus.off("barcode_scanned", this, this._onBarcodeScanned); - // this._super(); - // }, - - openEmployeeSelection() { - const employeeList = this.employees.map(employee => Object.create({ - id: employee.id, - item: employee, - label: employee.name, - isSelected: employee === this.employee.id, - })); - this.popup.SelectionPopup = { - data: { title: this.env._t("Select Employee"), list: employeeList }, - isShown: true, - }; - }, - - async selectEmployee(employeeId, pin) { - const employee = this.employees.find(e => e.id === employeeId); - const employee_function = this.employee.name && this.employee.id === employeeId ? "logout" : "login"; - const pinValid = await this.orm.call( - "hr.employee", employee_function, [employeeId, pin], - ); - if (!pinValid && this.popup.PinPopup.isShown) { - this.notification.add(this.env._t("Wrong password !"), {type: "danger"}); - return; - } - if (!pinValid) { - this._askPin(employee); - return; - } - - if (employee_function === "login") { - this.notification.add(this.env._t("Logged in!"), {type: "success"}); - this.employee = { - name: employee.name, - id: employee.id, - }; - if (this.context.openRecord) { - this.openRecord(...this.context.openRecord); - } - } else { - this.employee = { - name: false, - id: 0, - }; - } - }, - - closePopup(popupName) { - this.popup[popupName].isShown = false; - }, - - _askPin(employee) { - this.popup.PinPopup = { - data: {employee: employee}, - isShown: true, - }; - }, - - _onBarcodeScanned: function (barcode) { - const employee = this.employees.find(e => e.barcode === barcode); - if (employee) { - this.selectEmployee(employee.id); - } else { - this.notification.add(this.env._t("This employee is not allowed on this workcenter"), {type: "danger"}); - } - }, - - async openRecord(record, mode) { - if (this.employees && !this.employee.name) { - this.context.openRecord = [record, mode]; - this.openEmployeeSelection(); - return; - } - delete this.context.openRecord; - Object.assign(this.context, {employee_id: this.employee.id}); - this._super(...arguments); - }, -}); diff --git a/mrp_workorder_hr/static/src/views/xml/mrp_workorder_buttons.xml b/mrp_workorder_hr/static/src/views/xml/mrp_workorder_buttons.xml deleted file mode 100644 index ab77ce2e..00000000 --- a/mrp_workorder_hr/static/src/views/xml/mrp_workorder_buttons.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - -
- -
-
- -
-
-
-
diff --git a/mrp_workorder_hr/static/tests/tours/tour_test_workorder.js b/mrp_workorder_hr/static/tests/tours/tour_test_workorder.js deleted file mode 100644 index 086c703a..00000000 --- a/mrp_workorder_hr/static/tests/tours/tour_test_workorder.js +++ /dev/null @@ -1,94 +0,0 @@ -/** @odoo-module **/ - -import tour from 'web_tour.tour'; -import helper from 'mrp_workorder.tourHelper'; - -tour.register('test_production_with_employee', {test: true}, [ - {trigger: 'div.popup'}, - {trigger: 'h3:contains("Change Worker")'}, - {trigger: 'div.selection-item:contains("Arthur")'}, - {trigger: 'div.popup-numpad'}, - {trigger: '.popup-numpad button:contains("1")'}, - {trigger: 'span.highlight:contains("•")'}, - {trigger: '.popup-numpad button:contains("2")'}, - {trigger: 'span.highlight:contains("••")'}, - {trigger: '.popup-numpad button:contains("3")'}, - {trigger: 'span.highlight:contains("•••")'}, - {trigger: '.popup-numpad button:contains("4")'}, - {trigger: 'span.highlight:contains("••••")'}, - {trigger: 'button.confirm'}, - { - trigger: 'span[title="Arthur Fu"]', - run: function () { - helper.assertCheckLength(3); - helper.assertValidatedCheckLength(0); - helper.assertQtyToProduce(2, 2); - helper.assertCurrentCheck('Instruction 1'); - } - }, - {trigger: 'div[name=employee_name]'}, - {trigger: 'button.btn-link:contains("New")'}, - {trigger: 'h3:contains("Change Worker")'}, - {trigger: 'div.selection-item:contains("Thomas")'}, - {trigger: 'div.popup-numpad'}, - {trigger: '.popup-numpad button:contains("5")'}, - {trigger: 'span.highlight:contains("•")'}, - {trigger: '.popup-numpad button:contains("6")'}, - {trigger: 'span.highlight:contains("••")'}, - {trigger: '.popup-numpad button:contains("7")'}, - {trigger: 'span.highlight:contains("•••")'}, - {trigger: '.popup-numpad button:contains("8")'}, - {trigger: 'span.highlight:contains("••••")'}, - {trigger: 'button.confirm'}, - { - trigger: 'span[title="Thomas Nific"]', - run: function () { - helper.assertCheckLength(3); - helper.assertValidatedCheckLength(0); - helper.assertQtyToProduce(2, 2); - helper.assertCurrentCheck('Instruction 1'); - } - }, - {trigger: 'div[name=employee_name]'}, - {trigger: 'button.btn_employee:contains("Thomas")'}, - {trigger: 'button[name="action_next"]'}, - {trigger: 'div[name=qty_producing]:contains("2")'}, //field become readonly - { - trigger: '.o_tablet_step_ok', - run: function () { - helper.assertCheckLength(3); - helper.assertValidatedCheckLength(1); - helper.assertQtyToProduce(2, 2); - helper.assertCurrentCheck('Instruction 2'); - } - }, - {trigger: 'button[name="action_next"]'}, - { - trigger: 'p:contains("third")', - run: function () { - helper.assertCheckLength(3); - helper.assertValidatedCheckLength(2); - helper.assertQtyToProduce(2, 2); - helper.assertCurrentCheck('Instruction 3'); - } - }, - {trigger: 'button[name=openMenuPopup]'}, - {trigger: '.o_tablet_popups'}, - {trigger: '.btn:contains("Update Instruction")'}, - {trigger: '.modal-title:contains("Update Instruction")'}, - // { - // trigger: "div[name=note] p", - // position: 'bottom', - // run: 'text my new instruction', - // }, { - { - trigger: "input#comment", - position: 'bottom', - run: 'text my reason', - }, - {trigger: '.btn-primary[name="process"]'}, - {trigger: '.o_tablet_client_action'}, - {trigger: '.btn-primary[name="action_next"]'}, - {trigger: '.btn[name=do_finish]'}, - {trigger: '.o_searchview_input'}, -]); diff --git a/mrp_workorder_hr/tests/__init__.py b/mrp_workorder_hr/tests/__init__.py deleted file mode 100644 index 02da47bf..00000000 --- a/mrp_workorder_hr/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import test_tablet_client_action diff --git a/mrp_workorder_hr/tests/test_tablet_client_action.py b/mrp_workorder_hr/tests/test_tablet_client_action.py deleted file mode 100644 index ef89d6aa..00000000 --- a/mrp_workorder_hr/tests/test_tablet_client_action.py +++ /dev/null @@ -1,83 +0,0 @@ -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from odoo.tests import Form, HttpCase, tagged -from odoo import Command - -from odoo.addons.mrp.tests.common import TestMrpCommon - - -@tagged('post_install', '-at_install') -class TestTabletWorkorderHr(TestMrpCommon, HttpCase): - def _get_client_action_url(self, workorder_id): - action = self.env["ir.actions.actions"]._for_xml_id("mrp_workorder.tablet_client_action") - return '/web?debug=assets#action=%s&active_id=%s' % (action['id'], workorder_id) - - def test_production_with_employee(self): - self.env['mrp.workcenter'].search([]).write({ - 'allow_employee': True, - 'employee_ids': [ - Command.create({ - 'name': 'Arthur Fu', - 'pin': '1234', - }), - Command.create({ - 'name': 'Thomas Nific', - 'pin': '5678', - }) - ] - }) - self.env['stock.lot'].create([{ - 'product_id': self.product_6.id, - 'name': 'sn1', - 'company_id': self.env.company.id, - }]) - picking_type = self.env.ref('stock.warehouse0').manu_type_id - self.bom_3.operation_ids[0].quality_point_ids = [ - Command.create({ - 'product_ids': self.product_6.ids, - 'picking_type_ids': picking_type.ids, - 'operation_id': self.bom_3.operation_ids[0], - 'test_type_id': self.env.ref('quality.test_type_instructions').id, - 'note': "this is the first note", - 'title': "Instruction 1", - }), - Command.create({ - 'product_ids': self.product_6.ids, - 'picking_type_ids': picking_type.ids, - 'operation_id': self.bom_3.operation_ids[0], - 'test_type_id': self.env.ref('quality.test_type_instructions').id, - 'note': "this is the second note", - 'title': "Instruction 2", - }), - Command.create({ - 'product_ids': self.product_6.ids, - 'picking_type_ids': picking_type.ids, - 'operation_id': self.bom_3.operation_ids[0], - 'test_type_id': self.env.ref('quality.test_type_instructions').id, - 'note': "this is the third note", - 'title': "Instruction 3", - }), - ] - - mrp_order_form = Form(self.env['mrp.production']) - mrp_order_form.product_id = self.product_6 - production = mrp_order_form.save() - production.action_confirm() - production.action_assign() - production.button_plan() - production.qty_producing = 2 - self.assertEqual(len(production.workorder_ids.check_ids), 3) - wo = production.workorder_ids[0] - wo.button_start() - url = self._get_client_action_url(wo.id) - - self.start_tour(url, 'test_production_with_employee', login='admin', timeout=20) - employee1 = self.env['hr.employee'].search([ - ('name', '=', 'Arthur Fu'), - ]) - employee2 = self.env['hr.employee'].search([ - ('name', '=', 'Thomas Nific'), - ]) - self.assertEqual(len(wo.time_ids), 2) - self.assertTrue(wo.time_ids[0].employee_id, employee1) - self.assertTrue(wo.time_ids[1].employee_id, employee2) diff --git a/mrp_workorder_hr/views/hr_employee_views.xml b/mrp_workorder_hr/views/hr_employee_views.xml deleted file mode 100644 index c7b3e283..00000000 --- a/mrp_workorder_hr/views/hr_employee_views.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - hr.employee.view.form.inherit.mrp.workorder.hr - hr.employee - - - - - - - - - diff --git a/mrp_workorder_hr/views/mrp_operation_views.xml b/mrp_workorder_hr/views/mrp_operation_views.xml deleted file mode 100644 index bf32d9d6..00000000 --- a/mrp_workorder_hr/views/mrp_operation_views.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - mrp.routing.workcenter.form.view - mrp.routing.workcenter - - - - - - - - diff --git a/mrp_workorder_hr/views/mrp_workcenter_views.xml b/mrp_workorder_hr/views/mrp_workcenter_views.xml deleted file mode 100644 index da7bbed0..00000000 --- a/mrp_workorder_hr/views/mrp_workcenter_views.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - mrp.workcenter.tree.view.inherit - mrp.workcenter - - - - - - - - - mrp.workcenter.form.view.inherit - mrp.workcenter - - - - - -
- Allowed Employees - -
-
-
- - -
-
-
diff --git a/mrp_workorder_hr/views/mrp_workorder_views.xml b/mrp_workorder_hr/views/mrp_workorder_views.xml deleted file mode 100644 index 427bd254..00000000 --- a/mrp_workorder_hr/views/mrp_workorder_views.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - - mrp.workorder.view.tablet.form.inherit.workorder.hr - mrp.workorder - - - - - - - - - - {'invisible': ['|', '|', '|', ('allow_employee', '=', True), ('is_user_working', '=', True), ('working_state', '=', 'blocked'), ('state', '=', ('done', 'cancel'))]} - - - {'invisible': ['|', '|', ('allow_employee', '=', True), ('is_user_working', '=', False), ('working_state', '=', 'blocked')]} - - - - - - mrp.workorder.view.form.inherit.workorder.hr - mrp.workorder - - - - - - - - - - {'column_invisible': [('parent.allow_employee', '!=', False)]} - - - - - - {'column_invisible': [('parent.allow_employee', '!=', False)]} - - - - - - - - - - mrp.workorder.view.kanban.inherit.mrp.workorder.hr - mrp.workorder - - - - - - - record.last_working_user_id.raw_value & ! allow_employee - - - - - diff --git a/mrp_workorder_hr/wizard/__init__.py b/mrp_workorder_hr/wizard/__init__.py deleted file mode 100644 index af231a21..00000000 --- a/mrp_workorder_hr/wizard/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import propose_change diff --git a/mrp_workorder_hr/wizard/propose_change.py b/mrp_workorder_hr/wizard/propose_change.py deleted file mode 100644 index adb68917..00000000 --- a/mrp_workorder_hr/wizard/propose_change.py +++ /dev/null @@ -1,13 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from odoo import models - - -class ProposeChange(models.TransientModel): - _inherit = 'propose.change' - - def _workorder_name(self): - if self.workorder_id.employee_id: - return self.workorder_id.employee_id.name - return super()._workorder_name() diff --git a/sf_mrs_connect/models/sync_common.py b/sf_mrs_connect/models/sync_common.py index dc428061..edd7e394 100644 --- a/sf_mrs_connect/models/sync_common.py +++ b/sf_mrs_connect/models/sync_common.py @@ -1028,7 +1028,6 @@ class MachineToolCategory(models.Model): token = sf_sync_config['token'] sf_secret_key = sf_sync_config['sf_secret_key'] headers = Common.get_headers(self, token, sf_secret_key) - strUrl = sf_sync_config['sf_url'] + self.url r = requests.post(strUrl, json={}, data=None, headers=headers) r = r.json() diff --git a/sf_mrs_connect/views/res_config_settings_views.xml b/sf_mrs_connect/views/res_config_settings_views.xml index 7bc7f2ad..e8d81453 100644 --- a/sf_mrs_connect/views/res_config_settings_views.xml +++ b/sf_mrs_connect/views/res_config_settings_views.xml @@ -26,7 +26,7 @@
-
From bf3c7e2b4dd90364c5ce55edc09dc7f3b62695b5 Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Thu, 8 Jun 2023 14:58:40 +0800 Subject: [PATCH 9/9] =?UTF-8?q?sf=E5=88=80=E5=85=B7=E5=9F=BA=E7=A1=80?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E5=B7=B2=E5=88=9D=E6=AD=A5=E5=BB=BA=E7=AB=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_base/__manifest__.py | 4 +- sf_base/models/__init__.py | 1 + sf_base/models/tool_base.py | 267 ++++++++++ sf_base/security/ir.model.access.csv | 14 + sf_base/views/tool_base_menu.xml | 244 ++++++++++ sf_base/views/tool_base_views.xml | 695 +++++++++++++++++++++++++++ 6 files changed, 1224 insertions(+), 1 deletion(-) create mode 100644 sf_base/models/tool_base.py create mode 100644 sf_base/views/tool_base_menu.xml create mode 100644 sf_base/views/tool_base_views.xml diff --git a/sf_base/__manifest__.py b/sf_base/__manifest__.py index 2daf3ec0..045692f4 100644 --- a/sf_base/__manifest__.py +++ b/sf_base/__manifest__.py @@ -16,7 +16,9 @@ 'security/ir.model.access.csv', 'views/base_view.xml', 'views/common_view.xml', - "views/menu_view.xml" + "views/menu_view.xml", + "views/tool_base_views.xml", + "views/tool_base_menu.xml", ], 'demo': [ diff --git a/sf_base/models/__init__.py b/sf_base/models/__init__.py index 4714c995..f6e247d2 100644 --- a/sf_base/models/__init__.py +++ b/sf_base/models/__init__.py @@ -1,4 +1,5 @@ from . import base from . import common +from . import tool_base diff --git a/sf_base/models/tool_base.py b/sf_base/models/tool_base.py new file mode 100644 index 00000000..c1a90a92 --- /dev/null +++ b/sf_base/models/tool_base.py @@ -0,0 +1,267 @@ +# -*- coding: utf-8 -*- +import logging + +from odoo import fields, models, api +from odoo.exceptions import UserError +# from odoo.addons import mrs_base, mrs_common +from datetime import datetime + + +# 功能刀具 +class FunctionalCuttingTool(models.Model): + _name = 'mrs.functional.cutting.tool' + _description = '功能刀具' + + code = fields.Char('编码') + name = fields.Char('名称') + # 增加功能刀具类型、整体式刀具型号、刀片型号、刀杆型号、刀盘型号、刀柄型号、夹头型号、直径(mm)、刀具等级、加工精度(mm)、装刀长、刃数、整体刃长(mm)、有效刃长(mm)、最大寿命值、是否标准刀、适用范围 + functional_model_number = fields.Many2one('mrs.functional.cutting.tool.model', string='功能刀具类型', required=True) + integral_model_number = fields.Many2one('mrs.integral.cutting.tool', string='整体式刀具型号') + blade_model_number = fields.Many2one('mrs.blade', string='刀片型号') + cutterbar_model_number = fields.Many2one('mrs.cutter.bar', string='刀杆型号') + cutterpad_model_number = fields.Many2one('mrs.cutter.pad', string='刀盘型号') + handle_model_number = fields.Many2one('mrs.handle', string='刀柄型号', required=True) + chuck_model_number = fields.Many2one('mrs.chuck', string='夹头型号', required=True) + diameter = fields.Float('直径(mm)') + tool_grade = fields.Selection([('1', 'P1'), ('2', 'P2'), ('3', 'P3'), ('4', 'P4'), ('5', 'P5'), ('6', 'P6')], + string='刀具等级') + machining_accuracy = fields.Float('加工精度(mm)') + tool_length = fields.Float('装刀长') + blade_number = fields.Integer('刃数') + integral_blade_length = fields.Float('整体刃长(mm)') + effective_blade_length = fields.Float('有效刃长(mm)') + max_life = fields.Float('最大寿命值') + is_standard = fields.Boolean('是否标准刀') + applicable_range = fields.Char('适用范围') + image = fields.Binary('图片') + + +# 功能刀具类型 +class FunctionalCuttingToolModel(models.Model): + _name = 'mrs.functional.cutting.tool.model' + _description = '功能刀具类型' + + name = fields.Char('名称', required=True) + code = fields.Char('编码', required=True) + remark = fields.Text('备注') + + +# 整体式刀具 +class IntegralCuttingTool(models.Model): + _name = 'mrs.integral.cutting.tool' + _description = '整体式刀具' + + code = fields.Char('编码') + name = fields.Char('型号名称', required=True) + # 整体式刀具类型字段,关联整体式刀具类型对象 + integral_model_number = fields.Many2one('mrs.integral.cutting.tool.model', '整体式刀具类型', required=True) + # 增加品牌、总长度(mm)、柄部长度(mm)、刃部长度(mm)、直径(mm)、刃数、前角(°)、后角(°)、主偏角(°)、材料型号、配对螺母(mm)、适用夹头型号、适用范围、图片、创建人、创建时间等字段 + brand = fields.Many2one('mrs.machine.brand', '品牌', required=True) + total_length = fields.Float('总长度(mm)', required=True) + shank_length = fields.Float('柄部长度(mm)', required=True) + blade_length = fields.Float('刃部长度(mm)', required=True) + diameter = fields.Float('直径(mm)', required=True) + blade_number = fields.Integer('刃数', required=True) + front_angle = fields.Float('前角(°)', required=True) + rear_angle = fields.Float('后角(°)', required=True) + main_included_angle = fields.Float('主偏角(°)', required=True) + material_model = fields.Many2one('mrs.production.materials', '材料型号', required=True) + nut = fields.Float('配对螺母(mm)', required=True) + # 适用夹头型号可以多选 + chuck_model = fields.Many2many('mrs.chuck', string='适用夹头型号', required=True) + scope = fields.Char('适用范围', required=True) + image = fields.Binary('图片') + + +# 整体式刀具类型 +class IntegralCuttingToolModel(models.Model): + _name = 'mrs.integral.cutting.tool.model' + _description = '整体式刀具类型' + + code = fields.Char('编码') + name = fields.Char('名称', required=True) + remark = fields.Text('备注') + + +# 刀片 +class Blade(models.Model): + _name = 'mrs.blade' + _description = '刀片' + + code = fields.Char('编码') + name = fields.Char('型号名称', required=True) + # 刀片类型字段,关联刀片类型对象 + blade_model_number = fields.Many2one('mrs.blade.model', '刀片类型', required=True) + # 编码、型号名称、刀片类型、品牌、长度L(mm)、宽度D(mm)、高度T(mm)、顶角(°)、前角(°)、后角(°)、主偏角(°)、R角(°)、材料型号、加工硬度、配对螺母(mm)、适用刀杆/刀盘型号、刀尖半径(mm)、图片、创建人、创建时间字段 + brand = fields.Many2one('mrs.machine.brand', '品牌', required=True) + length = fields.Float('长度L(mm)', required=True) + width = fields.Float('宽度D(mm)', required=True) + height = fields.Float('高度T(mm)', required=True) + top_angle = fields.Float('顶角(°)', required=True) + front_angle = fields.Float('前角(°)', required=True) + rear_angle = fields.Float('后角(°)', required=True) + main_included_angle = fields.Float('主偏角(°)', required=True) + r_angle = fields.Float('R角(°)', required=True) + material_model = fields.Many2one('mrs.production.materials', '材料型号', required=True) + hardness = fields.Char('加工硬度', required=True) + nut = fields.Float('配对螺母(mm)', required=True) + # 适用刀杆型号可以多选 + cutter_bar = fields.Many2many('mrs.cutter.bar', string='适用刀杆型号') + # 适用刀盘型号可以多选 + cutter_pad = fields.Many2many('mrs.cutter.pad', string='适用刀盘型号') + radius = fields.Float('刀尖半径(mm)', required=True) + image = fields.Binary('图片') + + +# 刀片类型 +class BladeModel(models.Model): + _name = 'mrs.blade.model' + _description = '刀片类型' + + code = fields.Char('编码') + name = fields.Char('名称', required=True) + # 刀片类型字段,关联刀片对象 + blade_ids = fields.One2many('mrs.blade', 'blade_model_number', '刀片类型') + remark = fields.Text('备注') + + +# 刀杆 +class CutterBar(models.Model): + _name = 'mrs.cutter.bar' + _description = '刀杆' + + code = fields.Char('编码') + name = fields.Char('型号名称', required=True) + # 刀杆类型字段,关联刀杆类型对象 + cutter_bar_model_number = fields.Many2one('mrs.cutter.bar.model', '刀杆类型', required=True) + # 品牌、C柄径(mm)、L总长(mm)、材料型号、刃数、D刃径(mm)、适用刀片型号、配对扳手(mm)、配备螺丝(mm)、刀尖圆角半径、精度等级、硬度(°)、适用范围、图片、创建人、创建时间 + brand = fields.Many2one('mrs.machine.brand', '品牌', required=True) + c_diameter = fields.Float('C柄径(mm)', required=True) + total_length = fields.Float('L总长(mm)', required=True) + material_model = fields.Many2one('mrs.production.materials', '材料型号', required=True) + blade_number = fields.Integer('刃数', required=True) + d_diameter = fields.Float('D刃径(mm)', required=True) + blade = fields.Many2many('mrs.blade', string='适用刀片型号') + wrench = fields.Float('配对扳手(mm)', required=True) + screw = fields.Float('配备螺丝(mm)', required=True) + radius = fields.Float('刀尖圆角半径', required=True) + accuracy = fields.Char('精度等级', required=True) + hardness = fields.Char('硬度(°)', required=True) + scope = fields.Char('适用范围', required=True) + image = fields.Binary('图片') + + +# 刀杆类型 +class CutterBarModel(models.Model): + _name = 'mrs.cutter.bar.model' + _description = '刀杆类型' + + code = fields.Char('编码') + name = fields.Char('名称', required=True) + remark = fields.Text('备注') + + +# 刀盘 +class CutterPad(models.Model): + _name = 'mrs.cutter.pad' + _description = '刀盘' + + code = fields.Char('编码') + name = fields.Char('型号名称', required=True) + # 刀盘类型字段,关联刀盘类型对象 + cutter_pad_model_number = fields.Many2one('mrs.cutter.pad.model', '刀盘类型', required=True) + # 增加品牌、C柄径(mm)、L总长(mm)、材料型号、刃数、D刃径(mm)、适用刀片型号、配对扳手(mm)、配备螺丝(mm)、刀尖圆角半径、精度等级、硬度(°)、适用范围、图片、创建人、创建时间 + brand = fields.Many2one('mrs.machine.brand', '品牌', required=True) + c_diameter = fields.Float('C柄径(mm)', required=True) + total_length = fields.Float('L总长(mm)', required=True) + material_model = fields.Many2one('mrs.production.materials', '材料型号', required=True) + blade_number = fields.Integer('刃数', required=True) + d_diameter = fields.Float('D刃径(mm)', required=True) + blade = fields.Many2many('mrs.blade', string='适用刀片型号') + wrench = fields.Float('配对扳手(mm)', required=True) + screw = fields.Float('配备螺丝(mm)', required=True) + radius = fields.Float('刀尖圆角半径', required=True) + accuracy = fields.Char('精度等级', required=True) + hardness = fields.Char('硬度(°)', required=True) + scope = fields.Char('适用范围', required=True) + image = fields.Binary('图片') + + +# 刀盘类型 +class CutterPadModel(models.Model): + _name = 'mrs.cutter.pad.model' + _description = '刀盘类型' + + code = fields.Char('编码') + name = fields.Char('名称', required=True) + remark = fields.Text('备注') + + +# 刀柄 +class Handle(models.Model): + _name = 'mrs.handle' + _description = '刀柄' + + code = fields.Char('编码') + name = fields.Char('型号名称', required=True) + # 刀柄类型字段,关联刀柄类型对象 + handle_model_number = fields.Many2one('mrs.handle.model', '刀柄类型', required=True) + # 增加、刀柄类型、品牌、L(mm)、L1(mm)、D1(mm)、重量(kg)、材料型号、本体精度(mm)、配对螺母(mm)、适用夹头型号、夹持范围(mm)、检测精度、检测硬度、标准转速、图片、创建人、创建时间 + brand = fields.Many2one('mrs.machine.brand', '品牌', required=True) + length = fields.Float('L(mm)', required=True) + length1 = fields.Float('L1(mm)', required=True) + diameter1 = fields.Float('D1(mm)', required=True) + weight = fields.Float('重量(kg)', required=True) + material_model = fields.Many2one('mrs.production.materials', '材料型号', required=True) + body_accuracy = fields.Float('本体精度(mm)', required=True) + nut = fields.Float('配对螺母(mm)', required=True) + chuck_model = fields.Many2many('mrs.chuck.model', string='适用夹头型号', required=True) + clamping_range = fields.Float('夹持范围(mm)', required=True) + detection_accuracy = fields.Float('检测精度', required=True) + detection_hardness = fields.Char('检测硬度', required=True) + standard_speed = fields.Float('标准转速', required=True) + image = fields.Binary('图片') + + +# 刀柄类型 +class HandleModel(models.Model): + _name = 'mrs.handle.model' + _description = '刀柄类型' + + code = fields.Char('编码') + name = fields.Char('名称', required=True) + remark = fields.Text('备注') + + +# 夹头对象(夹头型号对象) +class Chuck(models.Model): + _name = 'mrs.chuck' + _description = '夹头' + + code = fields.Char('编码') + name = fields.Char('型号名称', required=True) + # 夹头类型字段,关联夹头类型对象 + chuck_model_number = fields.Many2one('mrs.chuck.model', '夹头类型', required=True) + # 增加品牌、精度(mm)、外径(mm)、内径(mm)、高度(mm)、材料型号、配对螺母(mm)、适用刀柄型号、夹持范围(mm)、特性、图片、创建人、创建时间 + brand = fields.Many2one('mrs.machine.brand', '品牌', required=True) + accuracy = fields.Float('精度(mm)', required=True) + diameter = fields.Float('外径(mm)', required=True) + inner_diameter = fields.Float('内径(mm)', required=True) + height = fields.Float('高度(mm)', required=True) + material_model = fields.Many2one('mrs.production.materials', '材料型号', required=True) + nut = fields.Float('配对螺母(mm)', required=True) + handle_model = fields.Many2many('mrs.handle.model', string='适用刀柄型号', required=True) + clamping_range = fields.Float('夹持范围(mm)', required=True) + feature = fields.Char('特性', required=True) + image = fields.Binary('图片') + + +# 夹头类型 +class ChuckModel(models.Model): + _name = 'mrs.chuck.model' + _description = '夹头类型' + + code = fields.Char('编码') + name = fields.Char('名称', required=True) + remark = fields.Text('备注') + diff --git a/sf_base/security/ir.model.access.csv b/sf_base/security/ir.model.access.csv index 7c13d58d..b68c6271 100644 --- a/sf_base/security/ir.model.access.csv +++ b/sf_base/security/ir.model.access.csv @@ -16,6 +16,20 @@ access_sf_supplier_sort,sf_supplier_sort,model_sf_supplier_sort,base.group_user, access_sf_production_process_parameter,sf_production_process_parameter,model_sf_production_process_parameter,base.group_user,1,1,1,1 access_sf_production_process_category,sf_production_process_category,model_sf_production_process_category,base.group_user,1,1,1,1 +access_mrs_functional_cutting_tool,mrs.functional.cutting.tool,model_mrs_functional_cutting_tool,base.group_user,1,1,1,1 +access_mrs_functional_cutting_tool_model,mrs.functional.cutting.tool.model,model_mrs_functional_cutting_tool_model,base.group_user,1,1,1,1 +access_mrs_integral_cutting_tool,mrs.integral.cutting.tool,model_mrs_integral_cutting_tool,base.group_user,1,1,1,1 +access_mrs_integral_cutting_tool_model,mrs.integral.cutting.tool.model,model_mrs_integral_cutting_tool_model,base.group_user,1,1,1,1 +access_mrs_blade,mrs.blade,model_mrs_blade,base.group_user,1,1,1,1 +access_mrs_blade_model,mrs.blade.model,model_mrs_blade_model,base.group_user,1,1,1,1 +access_mrs_cutter_bar,mrs.cutter.bar,model_mrs_cutter_bar,base.group_user,1,1,1,1 +access_mrs_cutter_bar_model,mrs.cutter.bar.model,model_mrs_cutter_bar_model,base.group_user,1,1,1,1 +access_mrs_cutter_pad,mrs.cutter.pad,model_mrs_cutter_pad,base.group_user,1,1,1,1 +access_mrs_cutter_pad_model,mrs.cutter.pad.model,model_mrs_cutter_pad_model,base.group_user,1,1,1,1 +access_mrs_handle,mrs.handle,model_mrs_handle,base.group_user,1,1,1,1 +access_mrs_handle_model,mrs.handle.model,model_mrs_handle_model,base.group_user,1,1,1,1 +access_mrs_chuck,mrs.chuck,model_mrs_chuck,base.group_user,1,1,1,1 +access_mrs_chuck_model,mrs.chuck.model,model_mrs_chuck_model,base.group_user,1,1,1,1 diff --git a/sf_base/views/tool_base_menu.xml b/sf_base/views/tool_base_menu.xml new file mode 100644 index 00000000..6f44729a --- /dev/null +++ b/sf_base/views/tool_base_menu.xml @@ -0,0 +1,244 @@ + + + + + + 整体式刀具型号 + ir.actions.act_window + mrs.integral.cutting.tool + + tree,form + + + + 功能刀具型号 + ir.actions.act_window + mrs.functional.cutting.tool + tree,form + + + + 刀片型号 + ir.actions.act_window + mrs.blade + tree,form + + + + 刀杆型号 + ir.actions.act_window + mrs.cutter.bar + tree,form + + + + 刀盘型号 + ir.actions.act_window + mrs.cutter.pad + tree,form + + + + 刀柄型号 + ir.actions.act_window + mrs.handle + tree,form + + + + 夹头型号 + ir.actions.act_window + mrs.chuck + tree,form + + + + 功能刀具类型 + ir.actions.act_window + mrs.functional.cutting.tool.model + tree,form + + + + 整体式刀具类型 + ir.actions.act_window + mrs.integral.cutting.tool.model + tree,form + + + + 刀片类型 + ir.actions.act_window + mrs.blade.model + tree,form + + + + 刀杆类型 + ir.actions.act_window + mrs.cutter.bar.model + tree,form + + + + 刀盘类型 + ir.actions.act_window + mrs.cutter.pad.model + tree,form + + + + 刀柄类型 + ir.actions.act_window + mrs.handle.model + tree,form + + + + 夹头类型 + ir.actions.act_window + mrs.chuck.model + tree,form + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sf_base/views/tool_base_views.xml b/sf_base/views/tool_base_views.xml new file mode 100644 index 00000000..ea091428 --- /dev/null +++ b/sf_base/views/tool_base_views.xml @@ -0,0 +1,695 @@ + + + + + + mrs.functional.cutting.tool.tree + mrs.functional.cutting.tool + + + + + + + + + + + + + mrs.functional.cutting.tool.form + mrs.functional.cutting.tool + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + mrs.integral.cutting.tool.tree + mrs.integral.cutting.tool + + + + + + + + + + + + + + + mrs.integral.cutting.tool.form + mrs.integral.cutting.tool + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + mrs.blade.tree + mrs.blade + + + + + + + + + + + + + mrs.blade.form + mrs.blade + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + mrs.cutter.bar.tree + mrs.cutter.bar + + + + + + + + + + + + + mrs.cutter.bar.form + mrs.cutter.bar + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + mrs.cutter.pad.tree + mrs.cutter.pad + + + + + + + + + + + + + mrs.cutter.pad.form + mrs.cutter.pad + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + mrs.cutter.handle.tree + mrs.handle + + + + + + + + + + + + + mrs.cutter.handle.form + mrs.handle + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + mrs.cutter.chuck.tree + mrs.chuck + + + + + + + + + + + + + mrs.cutter.chuck.form + mrs.chuck + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + mrs.cutter.function.tree + mrs.functional.cutting.tool.model + + + + + + + + + + + + mrs.cutter.function.form + mrs.functional.cutting.tool.model + +
+ + + + + + + + + + + +
+
+
+ + + mrs.integral.cutting.tool.model.tree + mrs.integral.cutting.tool.model + + + + + + + + + + + + mrs.integral.cutting.tool.model.form + mrs.integral.cutting.tool.model + +
+ + + + + + + + + + + +
+
+
+ + + mrs.blade.model.tree + mrs.blade.model + + + + + + + + + + + + mrs.blade.model.form + mrs.blade.model + +
+ + + + + + + + + + + + +
+
+
+ + + mrs.cutter.bar.model.tree + mrs.cutter.bar.model + + + + + + + + + + + + mrs.cutter.bar.model.form + mrs.cutter.bar.model + +
+ + + + + + + + + + + +
+
+
+ + + mrs.cutter.pad.model.tree + mrs.cutter.pad.model + + + + + + + + + + + + mrs.cutter.pad.model.form + mrs.cutter.pad.model + +
+ + + + + + + + + + + +
+
+
+ + + + mrs.handle.model.tree + mrs.handle.model + + + + + + + + + + + + mrs.handle.model.form + mrs.handle.model + +
+ + + + + + + + + + + +
+
+
+ + + mrs.chuck.model.tree + mrs.chuck.model + + + + + + + + + + + + mrs.chuck.model.form + mrs.chuck.model + +
+ + + + + + + + + + + +
+
+
+ + +
+