新增企业微信模块

This commit is contained in:
jinling.yang
2023-05-30 11:26:03 +08:00
parent c913973936
commit 9ae2ff1a2b
21 changed files with 1098 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
from . import model
from . import wxwork_config
from . import wxwork_approval_template
from . import wxwork_approval_template_controls
from . import wxwork_settings
from . import wxwork_approval_template_summary
from . import we_approval_record
# from . import res_config_setting

View File

@@ -0,0 +1,52 @@
# -*- coding: utf-8 -*-
import re
import logging
import time
import requests
from datetime import datetime
import base64
import hashlib
from odoo import fields, models, api
import json
import requests
from odoo.http import request
from odoo.exceptions import ValidationError
from odoo.exceptions import UserError
_logger = logging.getLogger(__name__)
# 审批管理
class WxWorkApproval(models.Model):
_name = 'wxwork.approval.record'
_description = '审批记录'
approval_type = fields.Many2one('wxwork.approval.template', string='审批模板名称')
approval_num = fields.Char(string='审批单据编号')
initiator = fields.Many2one('hr.employee', string='发起人')
# approver = fields.Many2one('hr.employee', string='审批人')
approval_state = fields.Selection([
('draft', '提交审批'),
('pending', '审批中'),
('approved', '已批准'),
('rejected', '已拒绝')
], string='审批状态', default='草稿')
approval_time = fields.Datetime(string='审批发起时间')
note = fields.Text(string='备注')
#
# # 根据具体业务需要添加其他字段
# leave_type = fields.Selection([
# ('annual_leave', 'Annual Leave'),
# ('sick_leave', 'Sick Leave'),
# ('personal_leave', 'Personal Leave')
# ], string='请假类型')
# leave_days = fields.Float(string='Leave Days')
# overtime_hours = fields.Float(string='Overtime Hours')

View File

@@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
# Part of SmartGo. See LICENSE file for full copyright and licensing details.
import logging
from odoo import api, fields, models, _
_logger = logging.getLogger(__name__)
class WxWorkConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
wxwork_corp_id = fields.Char(string='企业微信CorpID')
wxwork_secret = fields.Char(string='企业微信Secret')
@api.model
def get_values(self):
"""
重载获取参数的方法,参数都存在系统参数中
:return:
"""
values = super(WxWorkConfigSettings, self).get_values()
config = self.env['ir.config_parameter'].sudo()
wxwork_corp_id = config.get_param('wxwork_corp_id', default='')
wxwork_secret = config.get_param('wxwork_secret', default='')
values.update(
wxwork_corp_id=wxwork_corp_id,
wxwork_secret=wxwork_secret,
)
return values
def set_values(self):
super(WxWorkConfigSettings, self).set_values()
ir_config = self.env['ir.config_parameter'].sudo()
ir_config.set_param("wxwork_corp_id", self.wxwork_corp_id or "")
ir_config.set_param("wxwork_secret", self.wxwork_secret or "")

View File

@@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
from odoo import api, fields, models
class WeApprovalRecord(models.Model):
_name = 'we.approval.record'
_description = '审批记录'
sp_no = fields.Char('审批单号')
employee_id = fields.Many2one('hr.employee', '审批人', index=True)
state = fields.Selection([('1', '审批中'), ('2', '已同意'), ('3', '已驳回'), ('4', '已转审')], string='审批状态')
approval_time = fields.Datetime('审批时间')
approval_options = fields.Char('审批意见')
def create_approve_record(self, sp_no, userid, sp_state, approval_time, approval_options):
"""
创建审批记录
:param sp_no:
:param userid:
:param sp_state:
:param approval_time:
:param approval_options:
:return:
"""
employee_obj = self.env['hr.employee'].search([('we_employee_id', '=', userid)])
approval_order = self.env['we.approval.record'].search(
[('employee_id', '=', employee_obj.id), ('sp_no', '=', sp_no)])
vals = {
'sp_no': sp_no,
'employee_id': employee_obj.id,
'state': sp_state,
'approval_time': approval_time,
'approval_options': approval_options
}
if not approval_order:
approval_order = super(WeApprovalRecord, self).create(vals)
else:
approval_order.write(vals)
return approval_order

View File

@@ -0,0 +1,208 @@
# wxwork_api.py
import requests
class WxWorkAPI:
def __init__(self, corp_id, secret):
self.corp_id = corp_id
self.secret = secret
self.access_token = self.get_access_token()
# self.type = type
def get_access_token(self):
url = f"https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={self.corp_id}&corpsecret={self.secret}"
response = requests.get(url)
result = response.json()
if 'access_token' in result:
return result['access_token']
else:
raise Exception(f"获取AccessToken失败: {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'}
response = requests.post(url, json=approval_data, headers=headers)
result = response.json()
if result['errcode'] == 0:
print(result)
return result['sp_no']
else:
raise Exception(f"发起审批请求失败: {result}")
def get_approval_result(self, event_id):
url = f"https://qyapi.weixin.qq.com/cgi-bin/oa/getapprovalinfo?access_token={self.access_token}"
headers = {'Content-Type': 'application/json'}
data = {"apply_eventid": event_id}
response = requests.post(url, json=data, headers=headers)
result = response.json()
if result['errcode'] == 0:
return result
else:
raise Exception(f"获取审批结果失败: {result}")
def upload_temp_file(self):
"""
上传临时素材
:return:
"""
url = f"https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token={self.access_token}&type=file"
headers = {'Content-Type': 'application/json'}
file_path = '长沙研究院2023年月度考勤.xlsx'
media_type = 'file'
with open(file_path, 'rb') as f:
file_content = f.read()
files = {'media': (file_path, file_content)}
# response = requests.post(url=url.format(access_token=access_token, type=media_type), files=files)
response = requests.post(url=url, files=files)
result = response.json()
print('upload_result%s' % result)
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('创建成功')
aa = {"errcode": 0, "errmsg": "ok", "template_names": [{"text": "对接开发测试", "lang": "zh_CN"}], "template_content": {
"controls": [{"property": {"control": "Text", "id": "Text-1640339319582",
"title": [{"text": "申请事项", "lang": "zh_CN"}],
"placeholder": [{"text": "请输入申请事项", "lang": "zh_CN"}], "require": 1, "un_print": 0,
"un_replace": 0, "display": 1}},
{
"property": {"control": "Textarea", "id": "Textarea-1640339335659",
"title": [{"text": "申请内容", "lang": "zh_CN"}],
"placeholder": [{"text": "请输入申请详情描述", "lang": "zh_CN"}], "require": 1, "un_print": 0,
"un_replace": 0, "display": 1}},
{
"property": {"control": "Textarea", "id": "Textarea-1684823453770",
"title": [{"text": "多行文本", "lang": "zh_CN"}],
"placeholder": [{"text": "", "lang": "zh_CN"}], "require": 0, "un_print": 0}},
{
"property": {"control": "Money", "id": "Money-1684823460232",
"title": [{"text": "金额", "lang": "zh_CN"}],
"placeholder": [{"text": "", "lang": "zh_CN"}], "require": 0, "un_print": 0}},
{
"property": {"control": "Contact", "id": "Contact-1684823477216",
"title": [{"text": "部门", "lang": "zh_CN"}],
"placeholder": [{"text": "", "lang": "zh_CN"}], "require": 0, "un_print": 0},
"config": {"contact": {"type": "multi", "mode": "department"}}},
{
"property": {"control": "Contact", "id": "Contact-1684823465317",
"title": [{"text": "成员", "lang": "zh_CN"}],
"placeholder": [{"text": "", "lang": "zh_CN"}], "require": 0, "un_print": 0},
"config": {"contact": {"type": "multi", "mode": "user"}}},
{
"property": {"control": "Table", "id": "Table-1684823492261",
"title": [{"text": "明细", "lang": "zh_CN"}],
"placeholder": [{"text": "", "lang": "zh_CN"}], "require": 0, "un_print": 0},
"config": {"table": {"children": [{"property": {"control": "Selector",
"id": "Selector-1684823501307",
"title": [{"text": "单选", "lang": "zh_CN"}],
"placeholder": [{"text": "", "lang": "zh_CN"}],
"require": 0, "un_print": 0}, "config": {
"selector": {"type": "single", "exp_type": 0, "options": [
{"key": "option-1684823501307", "value": [{"text": "选项1", "lang": "zh_CN"}]},
{"key": "option-1684823501308", "value": [{"text": "选项2", "lang": "zh_CN"}]}],
"op_relations": [],
"external_option": {"use_external_option": False, "external_url": ""}}}}, {
"property": {"control": "Selector",
"id": "Selector-1684823504236",
"title": [{"text": "多选", "lang": "zh_CN"}],
"placeholder": [{"text": "", "lang": "zh_CN"}],
"require": 0, "un_print": 0}, "config": {
"selector": {"type": "multi", "exp_type": 0, "options": [
{"key": "option-1684823504236", "value": [{"text": "选项1", "lang": "zh_CN"}]},
{"key": "option-1684823504237", "value": [{"text": "选项2", "lang": "zh_CN"}]}],
"op_relations": [],
"external_option": {"use_external_option": False, "external_url": ""}}}}],
"stat_field": [], "sum_field": [], "print_format": 0}}},
{
"property": {"control": "RelatedApproval", "id": "RelatedApproval-1684823485883",
"title": [{"text": "关联申请单", "lang": "zh_CN"}],
"placeholder": [{"text": "", "lang": "zh_CN"}], "require": 0, "un_print": 0}},
{
"property": {"control": "File", "id": "File-1640339381728",
"title": [{"text": "附件", "lang": "zh_CN"}],
"placeholder": [{"text": "", "lang": "zh_CN"}], "require": 0, "un_print": 0,
"un_replace": 0, "display": 1}, "config": {"file": {"is_only_photo": 0}}}]}}

View File

@@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
import logging
from odoo import api, fields, models
from odoo.exceptions import UserError
_logger = logging.getLogger(__name__)
class WxWorkApprovalTemplate(models.Model):
_name = 'wxwork.approval.template'
_description = "企业微信审批模板"
process_code = fields.Char(string='模板id')
name = fields.Char(string='模板名称')
# content_ids = fields.Many2many('wxwork.approval.template.controls', string='模板内容')
content_ids = fields.One2many('wxwork.approval.template.controls', 'template_id', string='模板内容')
company_id = fields.Many2one('res.company', '公司', default=lambda self: self.env.user.company_id.id)
creator_userid = fields.Many2one('res.users', '创建者', default=lambda self: self.env.user.id)
use_template_approver = fields.Selection([
('0', '自选审批人'),
('1', '预设审批人')
], string='审批人模式', default='0')
choose_department = fields.Char(string='提单部门')
approver = fields.One2many('wxwork.approval.approver_line', 'main_id', string='审批流程')
notifyer = fields.Many2many('res.users', string='抄送人userid列表')
notify_type = fields.Selection([
('1', '提单时抄送'),
('2', '单据通过后抄送'),
('3', '提单和单据通过后抄送'),
])
summary_info_ids = fields.One2many('wxwork.approval.template.summary', 'template_id', string='模板摘要')
related_records_count = fields.Integer(string="关联记录数", compute="_compute_related_records_count")
@api.depends("summary_info_ids")
def _compute_related_records_count(self):
for record in self:
record.related_records_count = len(record.summary_info_ids)

View File

@@ -0,0 +1,112 @@
# -*- coding: utf-8 -*-
import logging
from odoo import api, fields, models
from odoo.exceptions import UserError
_logger = logging.getLogger(__name__)
class WxWorkApprovalTemplate(models.Model):
_name = 'wxwork.approval.template.controls'
_description = "企业微信审批模板控件"
_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='不打印')
un_replace = fields.Boolean(string='不替换')
display = fields.Boolean(string='显示', compute='_compute_display')
@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']
@api.depends('title')
def _compute_require(self):
for record in self:
record.require = record.title in ['申请事项', '申请内容']
@api.depends('title')
def _compute_display(self):
for record in self:
record.display = record.title in ['申请事项', '申请内容']
class ApproverLine(models.Model):
_name = 'wxwork.approval.approver_line'
main_id = fields.Many2one('wxwork.approval.template', string='主模型')
userid = fields.Many2many('res.users', string='审批人userid列表')
attr = fields.Selection([('1', '或签'), ('2', '会签')], string='节点审批方式')
class ResUserAddShow(models.Model):
_inherit = 'res.users'
_rec_name = 'name'

View File

@@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
import logging
from odoo import api, fields, models
from odoo.exceptions import UserError, ValidationError
_logger = logging.getLogger(__name__)
class WxWorkApprovalTemplateSummary(models.Model):
_name = 'wxwork.approval.template.summary'
_description = "企业微信审批模板摘要"
# _rec_name = "title"
template_id = fields.Many2one('wxwork.approval.template', string='模板名称')
text = fields.Char(string='摘要行显示文字', size=20)
lang = fields.Selection([
('zh_CN', '中文'),
('en', '英文')
], string='控件类型', default='中文')
# @api.constrains('template_id')
# def _check_max_records(self):
# for record in self:
# # 统计与当前template_id相关联的记录数
# related_records_count = self.search_count([
# ('template_id', '=', record.template_id.id)
# ])
#
# # 如果记录数大于3则引发异常
# if related_records_count > 3:
# raise ValidationError("最多只能有三条记录")

View File

@@ -0,0 +1,24 @@
# models/wxwork_config.py
from odoo import fields, models
class WxWorkConfigSettings(models.TransientModel):
_name = 'wxwork.config.settings'
_inherit = 'res.config.settings'
wxwork_corp_id = fields.Char(string='企业微信CorpID')
wxwork_secret = fields.Char(string='企业微信Secret')
def set_values(self):
super(WxWorkConfigSettings, self).set_values()
self.env['ir.config_parameter'].set_param('wxwork.corp_id', self.wxwork_corp_id)
self.env['ir.config_parameter'].set_param('wxwork.secret', self.wxwork_secret)
def get_values(self):
res = super(WxWorkConfigSettings, self).get_values()
res.update(
wxwork_corp_id=self.env['ir.config_parameter'].get_param('wxwork.corp_id'),
wxwork_secret=self.env['ir.config_parameter'].get_param('wxwork.secret'),
)
return res

View File

@@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
from odoo import api, fields, models
class WxSettings(models.Model):
_name = 'wxwork.settings'
_description = '企业微信设置'
wx_work_app = fields.Char(string='企业微信应用名称')
wx_work_corp_id = fields.Char(string='企业微信CorpID')
wx_work_secret = fields.Char(string='企业微信Secret')