diff --git a/web_widgets/__init__.py b/web_widgets/__init__.py
deleted file mode 100644
index e89927ca6..000000000
--- a/web_widgets/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from . import models
-from . import controllers
\ No newline at end of file
diff --git a/web_widgets/__manifest__.py b/web_widgets/__manifest__.py
deleted file mode 100644
index cc07e503c..000000000
--- a/web_widgets/__manifest__.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# -*- coding: utf-8 -*-
-
-{
- "name": "iErp Web Widgets",
- "author": "RStudio",
- "category": "iErp Suites/Widget",
- "summary": "iErp Widgets",
- "website": "https://eis-solution.coding.net/public/odoo/oec/git",
- "version": "17.0.0.1",
- "description": """
-
-""",
- "depends": [
- "web",
- "attachment_indexation",
- ],
- "external_dependencies": {
- "python": [
- # "pyzbar",
- ],
- },
- "data": [],
- "assets": {
- # "web.assets_common": [
- # "web_widgets/static/fonts/fonts.scss",
- # ],
- "web.assets_backend": [
- "web_widgets/static/fonts/fonts.scss",
- "web_widgets/static/src/views/**/*.js",
- "web_widgets/static/src/views/**/*.xml",
- "web_widgets/static/src/views/**/*.scss",
- "web_widgets/static/src/webclient/**/*",
- ],
- "web.assets_frontend": [
- # "web_widgets/static/lib/officetohtml/**/*",
- ],
- },
- "sequence": 500,
- "installable": True,
- "auto_install": True,
- "application": False,
- "license": "AGPL-3",
-}
diff --git a/web_widgets/controllers/__init__.py b/web_widgets/controllers/__init__.py
deleted file mode 100644
index abae753cb..000000000
--- a/web_widgets/controllers/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from . import binary
diff --git a/web_widgets/controllers/binary.py b/web_widgets/controllers/binary.py
deleted file mode 100644
index 6bc6c565e..000000000
--- a/web_widgets/controllers/binary.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import os
-import logging
-
-from odoo import SUPERUSER_ID, _, http
-from odoo.exceptions import AccessError, MissingError, ValidationError
-from odoo.fields import Command
-from odoo.http import request
-
-from odoo.addons.web.controllers.binary import Binary
-from odoo.exceptions import AccessError, UserError
-from odoo.tools import file_open, file_path, replace_exceptions
-
-
-_logger = logging.getLogger(__name__)
-
-
-class WebWidgetBinary(Binary):
-
- @http.route(
- ["///."],
- type="http",
- # auth="public",
- auth="user",
- )
- def get_office_url(
- self,
- xmlid=None,
- model="ir.attachment",
- id=None,
- field="raw",
- filetype=None,
- filename=None,
- filename_field="name",
- mimetype=None,
- unique=False,
- download=False,
- access_token=None,
- nocache=False,
- ):
- print(model, field, id, filename, filename_field, filetype)
-
- with replace_exceptions(UserError, by=request.not_found()):
- record = request.env["ir.binary"]._find_record(
- xmlid, model, id and int(id), access_token
- )
- stream = request.env["ir.binary"]._get_stream_from(
- record, field, filename, filename_field, mimetype
- )
- send_file_kwargs = {"as_attachment": False}
- if unique:
- send_file_kwargs["immutable"] = True
- send_file_kwargs["max_age"] = http.STATIC_CACHE_LONG
- if nocache:
- send_file_kwargs["max_age"] = None
-
- res = stream.get_response(**send_file_kwargs)
- res.headers["Content-Security-Policy"] = "default-src 'none'"
- return "https://wecom.rstudio.xyz/web_widgets/static/files/office/sale_order_outsourcing/finalized_office_file_4.docx"
- return res
diff --git a/web_widgets/i18n/zh_CN.po b/web_widgets/i18n/zh_CN.po
deleted file mode 100644
index 048d69e1f..000000000
--- a/web_widgets/i18n/zh_CN.po
+++ /dev/null
@@ -1,93 +0,0 @@
-# Translation of Odoo Server.
-# This file contains the translation of the following modules:
-# * web_widgets
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: Odoo Server 17.0\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2024-03-10 04:17+0000\n"
-"PO-Revision-Date: 2024-03-10 12:19+0800\n"
-"Last-Translator: \n"
-"Language-Team: \n"
-"Language: zh_CN\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Poedit 3.4.2\n"
-
-#. module: web_widgets
-#. odoo-javascript
-#: code:addons/web_widgets/static/src/webclient/actions/api_error_dialog/api_error_dialog.js:0
-#, python-format
-msgid "API Error"
-msgstr "API错误"
-
-#. module: web_widgets
-#. odoo-javascript
-#: code:addons/web_widgets/static/src/webclient/actions/api_error_dialog/api_error_dialog.xml:0
-#, python-format
-msgid "Error Details:"
-msgstr "错误详细信息:"
-
-#. module: web_widgets
-#. odoo-javascript
-#: code:addons/web_widgets/static/src/webclient/actions/api_error_dialog/api_error_dialog.xml:0
-#, python-format
-msgid "Error code:"
-msgstr "错误代码:"
-
-#. module: web_widgets
-#. odoo-javascript
-#: code:addons/web_widgets/static/src/webclient/actions/api_error_dialog/api_error_dialog.xml:0
-#, python-format
-msgid "Error description:"
-msgstr "错误描述:"
-
-#. module: web_widgets
-#. odoo-javascript
-#: code:addons/web_widgets/static/src/webclient/actions/api_error_dialog/api_error_dialog.xml:0
-#, python-format
-msgid "Error troubleshooting method:"
-msgstr "错误排除方法:"
-
-#. module: web_widgets
-#. odoo-python
-#: code:addons/web_widgets/models/ir_module.py:0
-#, python-format
-msgid "Failed to upload file %s, reason:%s"
-msgstr "无法上载文件%s,原因:%s"
-
-#. module: web_widgets
-#: model:ir.model,name:web_widgets.model_ir_module_module
-msgid "Module"
-msgstr "模块"
-
-#. module: web_widgets
-#. odoo-javascript
-#: code:addons/web_widgets/static/src/views/fields/password_char/password_char.js:0
-#, python-format
-msgid "String decrypted"
-msgstr ""
-
-#. module: web_widgets
-#. odoo-javascript
-#: code:addons/web_widgets/static/src/views/fields/password_char/password_char.js:0
-#, python-format
-msgid "String encrypted"
-msgstr ""
-
-#. module: web_widgets
-#. odoo-python
-#: code:addons/web_widgets/models/ir_module.py:0
-#, python-format
-msgid "Successfully uploaded %s"
-msgstr "已成功上传 %s"
-
-#. module: web_widgets
-#. odoo-javascript
-#: code:addons/web_widgets/static/src/views/fields/password_char/password_char.js:0
-#, python-format
-msgid "Text is displayed in password characters"
-msgstr "文本以密码字符显示"
diff --git a/web_widgets/models/__init__.py b/web_widgets/models/__init__.py
deleted file mode 100644
index 85469dc0e..000000000
--- a/web_widgets/models/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from . import ir_module
diff --git a/web_widgets/models/ir_module.py b/web_widgets/models/ir_module.py
deleted file mode 100644
index 61108242c..000000000
--- a/web_widgets/models/ir_module.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import os
-import platform
-import base64
-import pathlib
-from datetime import datetime, timedelta
-
-from odoo import api, fields, models, tools, _
-from odoo.tools.misc import file_path
-import logging
-
-_logger = logging.getLogger(__name__)
-
-
-class Module(models.Model):
- _inherit = "ir.module.module"
-
- @api.model
- def get_module_installation_status(self, addon_name=None):
- """
- 获取 addon 是否安装
- """
- addon = self.sudo().search([("name", "=", addon_name)])
- if not addon:
- # return {
- # "exist": False,
- # "moduleId": 0,
- # }
- return False
- else:
- # addon.button_install()
- # return {
- # "exist": True,
- # "moduleId": addon.id,
- # }
- return True
diff --git a/web_widgets/readme.md b/web_widgets/readme.md
deleted file mode 100644
index 00d0db9b9..000000000
--- a/web_widgets/readme.md
+++ /dev/null
@@ -1,106 +0,0 @@
-# 企微 Widget
-
-## Json编辑器
-
-创建一个 `fields.Json` 的字段,然后在视图中使用 `json_editor` 的 `widget`,即可使用 `json` 编辑器
-```python
-report_data_set = fields.Json(string="Report Data Set", translate=False, help="Report Data Set.")
-```
-```xml
-
-```
-> `options` 参数说明:
-
-| 选项| 说明 |
-|----------|-----:|
-|mode| 默认模式 |
-|modes| 模式清单,可选有: `code`, `form`, `text`, `tree`, `view`, `preview`|
-
-
-## Markdown 编辑器
-
-### 使用
-```xml
-
-```
-
-> `options` 参数说明:
-
-| 选项| 类型 |说明 |
-|----------|-----:|-----:|
-|height|字符串 |高度 例如 `300px` 或者 `auto`|
-|theme|字符串 |主题 `dark` 或者为 空 |
-|previewStyle| 字符串|预览样式,可选有: 选项卡 `tab`, 垂直 `vertical`|
-|userPlugin| 布尔值|使用组件,默认为`false`|
-
-
-> 组件列表说明:
-
-| 名称| 说明 |链接 |
-|----------|-----:|-----:|
-|chart|图表插件,`测试无法正常使用`| 打开链接 |
-|code-syntax-highlight|代码语法突出显示插件,`可以正常使用`| 打开链接 |
-|colorSyntax|颜色语法插件,`测试无法正常使用`| 打开链接 |
-|tableMergedCell|表格合并单元格插件,`测试无法正常使用`| 打开链接 |
-|uml|UML 插件,`测试无法正常使用`| 打开链接 |
-
-
-## 扫码
-1. 支持条码及二维码
-2. 支持同时扫码多个条码及二维码
-3. 调用 `企业微信扫一扫` 仅支持单个条码及二维码
-
-### `ScanCodeChar`
-```xml
-
-```
-
-### `ScanCodeText`
-```xml
-
-```
-
-### `ScanCodeURL`
-```xml
-
-```
-
-## 密码显示 `display_password`
-```xml
-
-```
-
-
-
-## 一对多配置 one2many_config
-```xml
-
-
-
-
-
-
-
-
-```
-
-## 从 form 视图 返回 list 视图,模拟 alt+b 的组合键
-
-> 应一个客户的需求开发
-
-### 在form 视图添加一个按钮,如下:
-
-```html
-
-```
-
-### 此按钮python 代码如下:
-```python
-def action_confirm(self):
- # 省略一万字的代码字符串
- action = {
- "type": "ir.actions.client",
- "tag": "open_list_action",
- }
- return action
-```
\ No newline at end of file
diff --git a/web_widgets/static/audio/beep.mp3 b/web_widgets/static/audio/beep.mp3
deleted file mode 100644
index ebb528aed..000000000
Binary files a/web_widgets/static/audio/beep.mp3 and /dev/null differ
diff --git a/web_widgets/static/description/icon.png b/web_widgets/static/description/icon.png
deleted file mode 100644
index de4efefaf..000000000
Binary files a/web_widgets/static/description/icon.png and /dev/null differ
diff --git a/web_widgets/static/fonts/fonts.scss b/web_widgets/static/fonts/fonts.scss
deleted file mode 100644
index 80bd98ebc..000000000
--- a/web_widgets/static/fonts/fonts.scss
+++ /dev/null
@@ -1,4 +0,0 @@
-@font-face {
- font-family: 'password';
- src: url('/web_widgets/static/fonts/password.ttf');
-}
diff --git a/web_widgets/static/fonts/password.ttf b/web_widgets/static/fonts/password.ttf
deleted file mode 100644
index f0f2a85e2..000000000
Binary files a/web_widgets/static/fonts/password.ttf and /dev/null differ
diff --git a/web_widgets/static/src/views/fields/fields.scss b/web_widgets/static/src/views/fields/fields.scss
deleted file mode 100644
index 0db936cab..000000000
--- a/web_widgets/static/src/views/fields/fields.scss
+++ /dev/null
@@ -1,13 +0,0 @@
-.o_field_widget {
-
- // MS Office Viewer
- &.o_field_ms_office_viewer {
- .o_msoffice_view_iframe {
- width: 100%;
- height: 450px;
- border: 0;
- margin-top: 10px;
- }
- }
-
-}
\ No newline at end of file
diff --git a/web_widgets/static/src/views/fields/onlyoffice_editor/.gitkeep b/web_widgets/static/src/views/fields/onlyoffice_editor/.gitkeep
deleted file mode 100644
index e69de29bb..000000000
diff --git a/web_widgets/static/src/views/fields/onlyoffice_viewer/.gitkeep b/web_widgets/static/src/views/fields/onlyoffice_viewer/.gitkeep
deleted file mode 100644
index e69de29bb..000000000
diff --git a/web_widgets/static/src/views/fields/password_char/password_char copy.bak b/web_widgets/static/src/views/fields/password_char/password_char copy.bak
deleted file mode 100644
index e81882f6f..000000000
--- a/web_widgets/static/src/views/fields/password_char/password_char copy.bak
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/web_widgets/static/src/views/fields/password_char/password_char.js b/web_widgets/static/src/views/fields/password_char/password_char.js
deleted file mode 100644
index c5d3bbf37..000000000
--- a/web_widgets/static/src/views/fields/password_char/password_char.js
+++ /dev/null
@@ -1,103 +0,0 @@
-/** @odoo-module **/
-
-import { _t } from "@web/core/l10n/translation";
-import { registry } from "@web/core/registry";
-import { useInputField } from "@web/views/fields/input_field_hook";
-import { standardFieldProps } from "@web/views/fields/standard_field_props";
-import { useService } from "@web/core/utils/hooks";
-
-
-const { Component, useState, useRef, onMounted, onRendered, onPatched } = owl;
-
-
-// --------------------------------------------------------------------------------
-// DisplayPasswordChar
-// --------------------------------------------------------------------------------
-export class PasswordCharField extends Component {
-
- static template = "web.PasswordCharField";
-
- static props = {
- ...standardFieldProps,
- string: { type: String, optional: true },
- className: { type: String, optional: true },
- placeholder: { type: String, optional: true },
- shouldTrim: { type: Boolean, optional: true },
- encrypted: { type: Boolean, optional: true },
- };
-
- setup() {
- this.state = useState({
- ...this.state,
- encrypted: true,
- });
-
- // this.encrypted = true; // 是否加密
- this.input = useRef("input");
- this.button = useRef("button");
- this.popover = useService("popover");
-
- useInputField({
- getValue: () => this.props.record.data[this.props.name] || "",
- refName: "input",
- // parse: (v) => this.parse(v),
- });
- onMounted(() => {
- // console.log("-------onMounted", this.input.el)
- if (this.props.record.data[this.props.name].trim() != "" && this.input.el) {
- this.input.el.dataset.encrypted = "true";
- } else if (this.props.record.data[this.props.name].trim() == "" && this.input.el) {
- this.input.el.dataset.encrypted = "false";
- }
- });
-
- // onRendered(() => {
- // // console.log("-------2", this.formattedValue)
- // // if (this.props.record.data[this.props.name].trim() != "") {
- // // // this.state.encrypted = true;
- // // this.input.el.dataset.encrypted = "true";
- // // } else {
- // // // this.state.encrypted = false;
- // // this.input.el.dataset.encrypted = "false";
- // // }
- // });
- }
-
- parse(value) {
- if (this.shouldTrim) {
- return value.trim();
- }
- return value;
- }
-
- // onClick(event, value) {
- onClick() {
- let icon = this.button.el.firstChild;
-
- if (this.state.encrypted) {
- // 当前状态为加密状态,点击后变为解密状态
- icon.classList.remove("fa-eye");
- icon.classList.add("fa-eye-slash");
- this.input.el.dataset.encrypted = "false";
- this.state.encrypted = false;
- } else {
- // 当前状态为解密状态,点击后变为加密状态
- icon.classList.remove("fa-eye-slash");
- icon.classList.add("fa-eye");
- this.input.el.dataset.encrypted = "true";
- this.state.encrypted = true;
- }
- }
-}
-
-
-export const passwordCharField = {
- component: PasswordCharField,
- displayName: _t("Text is displayed in password characters"),
- supportedTypes: ["char"],
- extractProps: ({ attrs }) => ({
- placeholder: attrs.placeholder,
- }),
-};
-
-registry.category("fields").add("password_char", passwordCharField);
\ No newline at end of file
diff --git a/web_widgets/static/src/views/fields/password_char/password_char.scss b/web_widgets/static/src/views/fields/password_char/password_char.scss
deleted file mode 100644
index be30cfc6e..000000000
--- a/web_widgets/static/src/views/fields/password_char/password_char.scss
+++ /dev/null
@@ -1,51 +0,0 @@
-.o_field_password_char {
- width: 100% !important;
- border: 1px solid $primary;
- display: flex !important;
- justify-content: space-between !important;
-
- &[data-encrypted="true"] {
- font-family: "password";
- font-size: smaller;
- }
-
- span {
- width: 100% !important;
- }
-
- span,
- input {
- &[data-encrypted="true"] {
- font-family: "password";
- font-size: smaller;
- }
-
- &[data-encrypted="false"] {
- font-family: inherit;
- font-size: inherit;
- }
-
- padding: 1px 0;
- }
-
- // input:empty {
- // font-family: inherit;
- // }
-
- input::placeholde {
- font-family: inherit;
- }
-
- button {
- border-radius: 0;
- }
-
- .form-control {
- &:focus {
- // @include print-variable(o-input-border-color, $o-brand-primary);
- box-shadow: none;
- // background-color: #FFFFFF;
- border-color: transparent;
- }
- }
-}
\ No newline at end of file
diff --git a/web_widgets/static/src/views/fields/password_char/password_char.xml b/web_widgets/static/src/views/fields/password_char/password_char.xml
deleted file mode 100644
index add8393ae..000000000
--- a/web_widgets/static/src/views/fields/password_char/password_char.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/web_widgets/static/src/webclient/actions/api_error_dialog/api_error_dialog.js b/web_widgets/static/src/webclient/actions/api_error_dialog/api_error_dialog.js
deleted file mode 100644
index 74fa9867f..000000000
--- a/web_widgets/static/src/webclient/actions/api_error_dialog/api_error_dialog.js
+++ /dev/null
@@ -1,26 +0,0 @@
-/** @odoo-module **/
-
-import { Dialog } from "@web/core/dialog/dialog";
-import { _lt } from "@web/core/l10n/translation";
-import { markup } from "@odoo/owl";
-const { Component, } = owl;
-
-
-export class ApiErrorDialog extends Component {
- setup() {
- this.title = this.props.title;
- this.size = this.props.size;
- this.code = this.props.code;
- this.description = this.props.description;
- this.method = markup(this.props.method);
- this.details = this.props.details;
-
- this.bodyClass = "bg-warning";
- this.contentClass = "bg-warning";
- }
-}
-ApiErrorDialog.components = {
- Dialog
-};
-ApiErrorDialog.template = "web.ApiErrorDialog";
-ApiErrorDialog.title = _lt("API Error");
\ No newline at end of file
diff --git a/web_widgets/static/src/webclient/actions/api_error_dialog/api_error_dialog.xml b/web_widgets/static/src/webclient/actions/api_error_dialog/api_error_dialog.xml
deleted file mode 100644
index 60b52ee3f..000000000
--- a/web_widgets/static/src/webclient/actions/api_error_dialog/api_error_dialog.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
-
- Error code:
-
-
-
- Error description:
-
-
-
- Error troubleshooting method:
-
-
-
- Error Details:
-
-
-
-
-
-
\ No newline at end of file
diff --git a/web_widgets/static/src/webclient/actions/api_error_dialog/client_actions.js b/web_widgets/static/src/webclient/actions/api_error_dialog/client_actions.js
deleted file mode 100644
index f31e6af30..000000000
--- a/web_widgets/static/src/webclient/actions/api_error_dialog/client_actions.js
+++ /dev/null
@@ -1,12 +0,0 @@
-/** @odoo-module **/
-
-import { registry } from "@web/core/registry";
-import { ApiErrorDialog } from "./api_error_dialog";
-
-
-
-export function apiDialogAction(env, action) {
- const params = action.params || {};
- env.services.dialog.add(ApiErrorDialog, params, {});
-}
-registry.category("actions").add("api_error_dialog", apiDialogAction);
\ No newline at end of file
diff --git a/web_widgets/static/src/webclient/actions/open_list_action/client_actions.js b/web_widgets/static/src/webclient/actions/open_list_action/client_actions.js
deleted file mode 100644
index e509d0f39..000000000
--- a/web_widgets/static/src/webclient/actions/open_list_action/client_actions.js
+++ /dev/null
@@ -1,25 +0,0 @@
-/** @odoo-module **/
-
-
-import { registry } from '@web/core/registry';
-
-export function openListAction(env, action) {
-
- if (Object.keys(action).length > 0) {
- window.dispatchEvent(
- new KeyboardEvent('keydown', {
- key: 'b',
- ctrlKey: false,
- shiftKey: false,
- altKey: true,
- metaKey: false,
- bubbles: true,
- cancelable: true
- })
- );
- } else {
- return;
- }
-}
-
-registry.category('actions').add('open_list_action', openListAction);
diff --git a/wecom_api/__init__.py b/wecom_api/__init__.py
deleted file mode 100644
index 1f6a952e1..000000000
--- a/wecom_api/__init__.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from odoo.tools import sql
-from . import api
-from . import tools
-from . import models
-from . import controllers
-
-
-# from odoo import api, SUPERUSER_ID, _
-
-
-# def post_init_hook(cr, registry):
-# # 安装模块后清理 清除所有的记录,并且索引号从0开始
-# env = api.Environment(cr, SUPERUSER_ID, {})
-# query = """
-# TRUNCATE TABLE wecom_app_config RESTART IDENTITY CASCADE;
-# """
-# env.cr.execute(query)
diff --git a/wecom_api/__manifest__.py b/wecom_api/__manifest__.py
deleted file mode 100644
index d7760b2da..000000000
--- a/wecom_api/__manifest__.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# -*- coding: utf-8 -*-
-{
- "name": "WeCom API",
- "author": "RStudio",
- "website": "https://gitee.com/rainbowstudio/wecom",
- "sequence": 600,
- "installable": True,
- "application": False,
- "auto_install": False,
- "category": "WeCom Suites/Settings",
- "version": "17.0.0.1",
- "summary": """
-WeCom Service-side API and Client-side API
- """,
- "description": """
- WeCom Service-side API and Client-side API
- Reconstruction based on project "https://github.com/sbzhu/weworkapi_python"
- """,
- "depends": [],
- "data": [
- "security/ir.model.access.csv",
- "data/ir_config_parameter.xml",
- "data/wecom_server_api_error_data.xml",
- "data/service_api_list_data.xml",
- ],
- "assets": {
- "web.assets_common": [
- # JS
- # "wecom_api/static/src/js/*.js",
- ],
- "web.assets_backend": [
- # JS
- ],
- },
- "external_dependencies": {
- "python": [
- "requests_toolbelt",
- # "pandas",
- "xmltodict",
- "pycryptodome",
- "html2text",
- ],
- },
- "license": "AGPL-3",
- # "post_init_hook": "post_init_hook",
-}
diff --git a/wecom_api/api/__init__.py b/wecom_api/api/__init__.py
deleted file mode 100644
index 1dfe7361d..000000000
--- a/wecom_api/api/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from . import wecom_abstract_api
-from . import wecom_server_api
-from . import wecom_message_api
-from . import wecom_client_api
diff --git a/wecom_api/api/wecom_abstract_api.py b/wecom_api/api/wecom_abstract_api.py
deleted file mode 100644
index 0bd5dfd79..000000000
--- a/wecom_api/api/wecom_abstract_api.py
+++ /dev/null
@@ -1,198 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import json
-import requests
-from odoo import api, fields, models, _, SUPERUSER_ID
-from odoo.exceptions import UserError
-import warnings
-
-
-class ApiException(Exception):
- def __init__(self, errCode, errMsg):
- super().__init__(errCode, errMsg)
- self.errCode = errCode
- self.errMsg = errMsg
-
-
-class WecomAbstractApi(models.AbstractModel):
- _name = "wecom.abstract_api"
- _description = "Wecom Abstract API"
-
- code = fields.Integer("API error code", copy=False)
- message = fields.Char("API error message", copy=False)
-
- def get_api_debug(self):
- """
- 获取 API 调试模式
- """
- ir_config = self.env["ir.config_parameter"].sudo()
- return True if ir_config.get_param("wecom.debug_enabled") == "True" else False
-
- def getAccessToken(self):
- raise NotImplementedError
-
- def refreshAccessToken(self):
- raise NotImplementedError
-
- def getSuiteAccessToken(self):
- raise NotImplementedError
-
- def refreshSuiteAccessToken(self):
- raise NotImplementedError
-
- def getProviderAccessToken(self):
- raise NotImplementedError
-
- def refreshProviderAccessToken(self):
- raise NotImplementedError
-
- def httpCall(self, urlType, args=None, include_agentid=False):
- """
- 调用API
- :param urlType : 服务端API类型和请求方式("GET" or "POST")
- :param args : 请求参数
- :param include_agentid : 标识args含有 "agentid" 关键字,需要进行处理
- :returns 返回结果
- """
- shortUrl = urlType[0]
- method = urlType[1]
- response = {}
- for retryCnt in range(0, 3):
- try:
- if "POST" == method:
- url = self.__makeUrl(shortUrl)
- if "agentid" in args and include_agentid: # type: ignore
- url = self.__appendArgs(url, {"agentid": args["agentid"]}) # type: ignore
- del args["agentid"] # type: ignore
- response = self.__httpPost(url, args)
- elif "GET" == method:
- url = self.__makeUrl(shortUrl)
- url = self.__appendArgs(url, args)
- response = self.__httpGet(url)
- else:
- raise ApiException(-1, _("unknown method type"))
- except Exception as e:
- raise ApiException(-2, e) # 其他错误
-
- # 检查令牌是否过期
- if self.__tokenExpired(response.get("errcode")):
- self.__refreshToken(shortUrl)
- retryCnt += 1
- continue
- else:
- break
- # 检测响应
- return self.__checkResponse(response)
-
- def httpPostFile(self, urlType, args=None, data=None, headers=None):
- shortUrl = urlType[0]
- response = {}
- for retryCnt in range(0, 3):
- url = self.__makeUrl(shortUrl)
- url = self.__appendArgs(url, args)
- response = self.__httpPostFile(url, data, headers)
-
- # 检查令牌是否过期
- if self.__tokenExpired(response.get("errcode")):
- self.__refreshToken(shortUrl)
- retryCnt += 1
- continue
- else:
- break
- return self.__checkResponse(response)
-
- @staticmethod
- def __appendArgs(url, args):
- if args is None:
- return url
-
- for key, value in args.items():
- if "?" in url:
- url += "&" + key + "=" + value
- else:
- url += "?" + key + "=" + value
- return url
-
- @staticmethod
- def __makeUrl(shortUrl):
- base = "https://qyapi.weixin.qq.com"
- if shortUrl[0] == "/":
- return base + shortUrl
- else:
- return base + "/" + shortUrl
-
- def __appendToken(self, url):
- if "SUITE_ACCESS_TOKEN" in url:
- return url.replace("SUITE_ACCESS_TOKEN", self.getSuiteAccessToken())
- elif "PROVIDER_ACCESS_TOKEN" in url:
- return url.replace("PROVIDER_ACCESS_TOKEN", self.getProviderAccessToken())
- elif "ACCESS_TOKEN" in url:
- return url.replace("ACCESS_TOKEN", self.getAccessToken())
- else:
- return url
-
- def __httpPost(self, url, args):
- realUrl = self.__appendToken(url)
-
- if self.get_api_debug() is True:
- print("Wecom API POST", realUrl, args)
-
- return requests.post(
- realUrl, data=json.dumps(args, ensure_ascii=False).encode("utf-8")
- ).json()
-
- def __httpPostFile(self, url, data, headers):
- realUrl = self.__appendToken(url)
-
- if self.get_api_debug() is True:
- print("Wecom API POST FILE", realUrl, data, headers)
-
- # response = requests.post(url=realUrl, data=data, headers=headers).json()
- return requests.post(url=realUrl, data=data, headers=headers).json()
-
- def __post_file(self, url, media_file):
- if self.get_api_debug() is True:
- print("Wecom API POST FILE", url, media_file)
- return requests.post(url, file=media_file).json() # type: ignore
-
- def __httpGet(self, url):
- realUrl = self.__appendToken(url)
-
- if self.get_api_debug() is True:
- print("Wecom API GET", realUrl)
-
- return requests.get(realUrl).json()
-
- @staticmethod
- def __checkResponse(response):
- """
- 检查 返回 值是否合法,
- """
- errCode = response.get("errcode")
- errMsg = response.get("errmsg")
-
- if errCode == 0:
- return response
- else:
- raise ApiException(errCode, errMsg)
-
- @staticmethod
- def __tokenExpired(errCode):
- """
- 检查 令牌 是否过期
- """
- if errCode == 40014 or errCode == 42001 or errCode == 42007 or errCode == 42009:
- return True
- else:
- return False
-
- def __refreshToken(self, url):
- """
- 刷新令牌
- """
- if "SUITE_ACCESS_TOKEN" in url:
- self.refreshSuiteAccessToken()
- elif "PROVIDER_ACCESS_TOKEN" in url:
- self.refreshProviderAccessToken()
- elif "ACCESS_TOKEN" in url:
- self.refreshAccessToken()
diff --git a/wecom_api/api/wecom_client_api.py b/wecom_api/api/wecom_client_api.py
deleted file mode 100644
index e44979b14..000000000
--- a/wecom_api/api/wecom_client_api.py
+++ /dev/null
@@ -1,96 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import json
-import requests
-from datetime import datetime, timedelta
-import time
-from odoo import api, fields, models, SUPERUSER_ID, _
-from collections import OrderedDict
-
-
-class WecomClientApi(models.TransientModel):
- _name = "wecom.client_api"
- _description = "Wecom Client API"
-
- @api.model
- def geContactsDisplayAgentConfig(self, postDatas):
- """
- 获取企业微信通讯录展示组件的应用配置
- """
- configs = []
- result = {}
- for data in postDatas:
- config = {}
- company = self.env["res.company"].search([("id", "=", data["company_id"])])
- self_built_app = company.self_built_app_id
-
- timestamp = int(time.time())
- nonceStr = self.env["wecomapi.tools.security"].random_str(8)
- jsapi_ticket = company.contacts_app_id.jsapi_ticket
- signature = self.env["wecomapi.tools.security"].generate_jsapi_signature(
- jsapi_ticket, nonceStr, timestamp
- )
-
- config.update(
- {
- "company_id": company.id,
- "corpid": company.corpid,
- "agentid": self_built_app.agentid,
- "timestamp": timestamp,
- "nonceStr": nonceStr,
- "signature": signature,
- "jsApiList": ["selectExternalContact"],
- }
- )
- configs.append(config)
- result.update(
- {
- "code": 0,
- "msg": "ok",
- "configs": configs,
- }
- )
- return result
-
- @api.model
- def getBarcodeWXConfig(self, postDatas):
- """
- 获取企业微信扫码组件的应用配置
- """
- configs = []
- result = {}
- for data in postDatas:
- config = {}
- company = (
- self.env["res.company"].sudo().search([("id", "=", data["company_id"])])
- )
- # wecom_apps = self.env['wecom.apps'].sudo().search([('type','=','self'), ('subtype_ids.code','=','auth')], limit=1)
- timestamp = int(time.time())
- nonceStr = self.env["wecomapi.tools.security"].sudo().random_str(8)
- jsapi_ticket = company.corp_jsapi_ticket
- signature = (
- self.env["wecomapi.tools.security"]
- .sudo()
- .generate_jsapi_signature(jsapi_ticket, nonceStr, timestamp)
- )
-
- config.update(
- {
- "company_id": company.id,
- "corpid": company.corpid,
- # "agentid":wecom_apps.agentid,
- "timestamp": timestamp,
- "nonceStr": nonceStr,
- "signature": signature,
- "jsApiList": ["scanQRCode"],
- }
- )
- configs.append(config)
- result.update(
- {
- "code": 0,
- "msg": "ok",
- "configs": configs,
- }
- )
- return result
diff --git a/wecom_api/api/wecom_message_api.py b/wecom_api/api/wecom_message_api.py
deleted file mode 100644
index 30ef706cd..000000000
--- a/wecom_api/api/wecom_message_api.py
+++ /dev/null
@@ -1,260 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import logging
-from odoo import api, models, _
-
-
-from odoo.addons.wecom_api.api.wecom_abstract_api import ApiException # type: ignore
-
-from datetime import datetime, timedelta
-import pytz
-import json
-
-_logger = logging.getLogger(__name__)
-
-
-class WeComMessageApi(models.AbstractModel):
- _name = "wecom.message.api"
- _description = "WeCom Message API"
-
- def get_message_api(self, company):
- """"""
- wxapi = self.env["wecom.service_api"].InitServiceApi(
- company, "message_secret", "message"
- )
- return wxapi
-
- def send_by_api(self, message, api):
- params = self.env["ir.config_parameter"].sudo()
- debug = params.get_param("wecom.debug_enabled")
-
- try:
- del message["company"] # 删除message中的 company
-
- response = api.httpCall(
- self.env["wecom.service_api_list"].get_server_api_call("MESSAGE_SEND"),
- message,
- )
- return response
-
- except ApiException as ex:
- if debug:
- _logger.warning(_("Error sending message: %s") % (ex))
-
- def build_message(
- self,
- msgtype,
- toall=None,
- touser=None,
- toparty=None,
- totag=None,
- subject=None,
- media_id=None,
- description=None,
- author_id=None,
- body_html=None,
- body_json=None,
- body_markdown=None,
- safe=None,
- enable_id_trans=None,
- enable_duplicate_check=None,
- duplicate_check_interval=None,
- company=None,
- ):
- """
- 构建消息
- :msgtype: 消息类型,根据消息类型来构建消息内容
- :toall: 发送给全体人员
- :touser: 指定接收消息的成员,成员ID列表(多个接收者用‘|’分隔,最多支持1000个)。
- 特殊情况:指定为”@all”,则向该企业应用的全部成员发送
- :toparty: 指定接收消息的部门,部门ID列表,多个接收者用‘|’分隔,最多支持100个。
- 当touser为”@all”时忽略本参数
- :totag: 指定接收消息的标签,标签ID列表,多个接收者用‘|’分隔,最多支持100个。
- 当touser为”@all”时忽略本参数
- :subject: 标题 ,不同消息类型,长度限制不一样
- :media_id: media_id, 可以通过素材管理接口获得
- :body_html: 图文消息的内容,支持html标签,不超过666 K个字节,仅用于图文消息(mpnews)
- :body_json: 非图文消息的内容,不同消息类型,长度限制不一样
- :safe: 表示是否是保密消息,0表示可对外分享,1表示不能分享且内容显示水印,默认为0
- :enable_id_trans: 表示是否开启id转译,0表示否,1表示是,默认0。仅第三方应用需要用到,企业自建应用可以忽略。
- :enable_duplicate_check: Indicates whether to enable duplicate message checking. 0 indicates no, 1 indicates yes. The default is 0
- :duplicate_check_interval: Indicates whether the message check is repeated. The default is 1800s and the maximum is no more than 4 hours
-
- """
- if not company:
- company = self.env.company
-
- messages_content = self.get_messages_content(
- msgtype,
- description,
- author_id,
- body_html,
- body_json,
- body_markdown,
- subject,
- media_id,
- )
- messages_options = self.get_messages_options(
- msgtype,
- safe,
- enable_id_trans,
- enable_duplicate_check,
- duplicate_check_interval,
- )
-
- messages = {
- "touser": "@all" if toall else touser,
- "toparty": "" if toall else toparty,
- "totag": "" if toall else totag,
- "msgtype": msgtype,
- "agentid": company.message_agentid,
- "company": company,
- }
- messages.update(messages_content)
- messages.update(messages_options)
- return messages
-
- @api.model
- def send_message(self, message):
- """
- 发送一条企业微信消息 到多个人员
- """
- return self.send_by_api(message)
-
- @api.model
- def _send_message_batch(self, messages):
- """
- 批量模式发送企业微信消息
- """
- params = {
- "messages": messages,
- }
- return self._wecom_message_send_api(params)
-
- def get_messages_content(
- self,
- msgtype,
- description=None,
- author_id=None,
- body_html=None,
- body_json=None,
- body_markdown=None,
- subject=None,
- media_id=None,
- ):
- # material_info = (
- # self.env["wecom.material"].sudo().browse(int(media_id)).read(["name"])
- # )
-
- messages_content = {}
- if msgtype == "text":
- # 文本消息
- messages_content = {
- "text": body_json,
- }
- elif msgtype == "mpnews":
- # 图文消息(mpnews)
- material = (
- self.sudo()
- .env["wecom.material"]
- .search(
- [
- ("id", "=", media_id),
- ],
- limit=1,
- )
- )
- # material_media_id = self.check_material_file_expiration(material)
- messages_content = {
- "mpnews": {
- "articles": [
- {
- "title": subject,
- "thumb_media_id": material._check_material_file_expiration(),
- "author": author_id.display_name,
- "content": body_html,
- "digest": description,
- }
- ]
- },
- }
- elif msgtype == "markdown":
- # markdown消息
- messages_content = {
- "markdown": {
- "content": body_markdown,
- }
- }
-
- elif msgtype == "template_card":
- # 模板卡片消息
- messages_content = {
- "template_card": json.loads(body_json, strict=False),
- }
- return messages_content
-
- def get_messages_options(
- self,
- msgtype,
- safe=None,
- enable_id_trans=None,
- enable_duplicate_check=None,
- duplicate_check_interval=None,
- ):
- """[summary]
- 获取企业微信消息的选项
- Args:
- msgtype ([type]): [description]
- safe ([type], optional): [description]. Defaults to None.
- enable_id_trans ([type], optional): [description]. Defaults to None.
- enable_duplicate_check ([type], optional): [description]. Defaults to None.
- duplicate_check_interval ([type], optional): [description]. Defaults to None.
-
- Returns:
- [type]: [description]
- """
- messages_options = {
- "safe": int(safe),
- "enable_id_trans": int(enable_id_trans),
- "enable_duplicate_check": int(enable_duplicate_check),
- "duplicate_check_interval": duplicate_check_interval,
- }
-
- if msgtype == "markdown":
- # markdown消息
- del messages_options["safe"]
- del messages_options["enable_id_trans"]
- if msgtype == "template_card":
- # 模板卡片消息
- del messages_options["safe"]
-
- return messages_options
-
- # def check_material_file_expiration(self, material):
- # """[summary]
- # 检查素材文件是否过期
- # Args:
- # material ([type]): [description]
-
- # Returns:
- # [type]: [description]
- # """
- # media_id = ""
- # if material.created_at:
- # # 有创建日期
- # created_time = material.created_at
- # MAX_FAIL_TIME = 3
-
- # # 检查是否超过3天
- # overdue = self.env["wecom.tools"].cheeck_days_overdue(
- # created_time, MAX_FAIL_TIME
- # )
- # if overdue:
- # # 临时素材超期,重新上传
- # material.upload_media()
- # media_id = material.media_id
- # else:
- # # 无创建日期,执行第一次上传临时素材
- # material.upload_media()
- # media_id = material.media_id
- # return media_id
diff --git a/wecom_api/api/wecom_msg_crtpt.py b/wecom_api/api/wecom_msg_crtpt.py
deleted file mode 100644
index affa8f064..000000000
--- a/wecom_api/api/wecom_msg_crtpt.py
+++ /dev/null
@@ -1,301 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from odoo import api, fields, models, tools, _
-import logging
-import base64
-import random
-import hashlib
-import time
-import struct
-from Crypto.Cipher import AES
-import xml.etree.cElementTree as ET
-import socket
-import hashlib
-import werkzeug.urls
-import werkzeug.utils
-
-_logger = logging.getLogger(__name__)
-
-#########################################################################
-# Description:定义错误码含义
-#########################################################################
-WXBizMsgCrypt_OK = 0
-WXBizMsgCrypt_ValidateSignature_Error = -40001
-WXBizMsgCrypt_ParseXml_Error = -40002
-WXBizMsgCrypt_ComputeSignature_Error = -40003
-WXBizMsgCrypt_IllegalAesKey = -40004
-WXBizMsgCrypt_ValidateCorpid_Error = -40005
-WXBizMsgCrypt_EncryptAES_Error = -40006
-WXBizMsgCrypt_DecryptAES_Error = -40007
-WXBizMsgCrypt_IllegalBuffer = -40008
-WXBizMsgCrypt_EncodeBase64_Error = -40009
-WXBizMsgCrypt_DecodeBase64_Error = -40010
-WXBizMsgCrypt_GenReturnXml_Error = -40011
-
-
-class FormatException(Exception):
- pass
-
-
-def throw_exception(message, exception_class=FormatException):
- """自定义引发异常函数"""
- raise exception_class(message)
-
-
-class SHA1:
- """计算企业微信的消息签名接口"""
-
- def getSHA1(self, token, timestamp, nonce, encrypt):
- """用SHA1算法生成安全签名
- @param token: 票据
- @param timestamp: 时间戳
- @param encrypt: 密文
- @param nonce: 随机字符串
- @return: 安全签名
- """
- try:
- sortlist = [token, timestamp, nonce, encrypt]
- sortlist.sort()
- sha = hashlib.sha1()
- sha.update("".join(sortlist).encode())
- return WXBizMsgCrypt_OK, sha.hexdigest()
- except Exception as e:
- logger = logging.getLogger()
- logger.error(e)
- return WXBizMsgCrypt_ComputeSignature_Error, None
-
-
-class XMLParse:
- """提供提取消息格式中的密文及生成回复消息格式的接口"""
-
- # xml消息模板
- AES_TEXT_RESPONSE_TEMPLATE = """
-
-
-%(timestamp)s
-
- """
-
- def extract(self, xmltext):
- """提取出xml数据包中的加密消息
- @param xmltext: 待提取的xml字符串
- @return: 提取出的加密消息字符串
- """
- try:
- xml_tree = ET.fromstring(xmltext)
- encrypt = xml_tree.find("Encrypt")
- return WXBizMsgCrypt_OK, encrypt.text # type: ignore
- except Exception as e:
- logger = logging.getLogger()
- logger.error(e)
- return WXBizMsgCrypt_ParseXml_Error, None, None
-
- def generate(self, encrypt, signature, timestamp, nonce):
- """生成xml消息
- @param encrypt: 加密后的消息密文
- @param signature: 安全签名
- @param timestamp: 时间戳
- @param nonce: 随机字符串
- @return: 生成的xml字符串
- """
- resp_dict = {
- "msg_encrypt": encrypt,
- "msg_signaturet": signature,
- "timestamp": timestamp,
- "nonce": nonce,
- }
- resp_xml = self.AES_TEXT_RESPONSE_TEMPLATE % resp_dict
- return resp_xml
-
-
-class PKCS7Encoder:
- """提供基于PKCS7算法的加解密接口"""
-
- block_size = 32
-
- def encode(self, text):
- """ 对需要加密的明文进行填充补位
- @param text: 需要进行填充补位操作的明文
- @return: 补齐明文字符串
- """
- text_length = len(text)
- # 计算需要填充的位数
- amount_to_pad = self.block_size - (text_length % self.block_size)
- if amount_to_pad == 0:
- amount_to_pad = self.block_size
- # 获得补位所用的字符
- pad = chr(amount_to_pad)
- return text + (pad * amount_to_pad).encode()
-
- def decode(self, decrypted):
- """删除解密后明文的补位字符
- @param decrypted: 解密后的明文
- @return: 删除补位字符后的明文
- """
- pad = ord(decrypted[-1])
- if pad < 1 or pad > 32:
- pad = 0
- return decrypted[:-pad]
-
-
-class Prpcrypt(object):
- """提供接收和推送给企业微信消息的加解密接口"""
-
- def __init__(self, key):
-
- # self.key = base64.b64decode(key+"=")
- self.key = key
- # 设置加解密模式为AES的CBC模式
- self.mode = AES.MODE_CBC
-
- def encrypt(self, text, receiveid):
- """对明文进行加密
- @param text: 需要加密的明文
- @return: 加密得到的字符串
- """
- # 16位随机字符串添加到明文开头
- text = text.encode()
- text = (
- self.get_random_str()
- + struct.pack("I", socket.htonl(len(text)))
- + text
- + receiveid.encode()
- )
-
- # 使用自定义的填充方式对明文进行补位填充
- pkcs7 = PKCS7Encoder()
- text = pkcs7.encode(text)
- # 加密
- cryptor = AES.new(self.key, self.mode, self.key[:16]) # type: ignore
- try:
- ciphertext = cryptor.encrypt(text)
- # 使用BASE64对加密后的字符串进行编码
- return WXBizMsgCrypt_OK, base64.b64encode(ciphertext)
- except Exception as e:
- logger = logging.getLogger()
- logger.error(e)
- return WXBizMsgCrypt_EncryptAES_Error, None
-
- def decrypt(self, text, receiveid):
- """对解密后的明文进行补位删除
- @param text: 密文
- @return: 删除填充补位后的明文
- """
- try:
- cryptor = AES.new(self.key, self.mode, self.key[:16]) # type: ignore
- # 使用BASE64对密文进行解码,然后AES-CBC解密
- plain_text = cryptor.decrypt(base64.b64decode(text))
- except Exception as e:
- logger = logging.getLogger()
- logger.error(e)
- return WXBizMsgCrypt_DecryptAES_Error, None
- try:
- pad = plain_text[-1]
- # 去掉补位字符串
- # pkcs7 = PKCS7Encoder()
- # plain_text = pkcs7.encode(plain_text)
- # 去除16位随机字符串
- content = plain_text[16:-pad]
- xml_len = socket.ntohl(struct.unpack("I", content[:4])[0])
- xml_content = content[4 : xml_len + 4]
- from_receiveid = content[xml_len + 4 :]
- except Exception as e:
- logger = logging.getLogger()
- logger.error(e)
- return WXBizMsgCrypt_IllegalBuffer, None
-
- if from_receiveid.decode("utf8") != receiveid:
- return WXBizMsgCrypt_ValidateCorpid_Error, None
- return 0, xml_content
-
- def get_random_str(self):
- """ 随机生成16位字符串
- @return: 16位字符串
- """
- return str(random.randint(1000000000000000, 9999999999999999)).encode()
-
-
-class WecomMsgCrypt(object):
- # 消息加解密
- # _name = "wecom.msg_crypt"
- # _description = "Wecom Message encryption and decryption"
-
- def __init__(self, sToken, sEncodingAESKey, sReceiveId):
- """
- 初始化消息加解密对象
- :return:
- """
- try:
- self.key = base64.b64decode(sEncodingAESKey + "=")
- assert len(self.key) == 32
- except:
- throw_exception("[error]: EncodingAESKey unvalid !", FormatException)
- # return WXBizMsgCrypt_IllegalAesKey,None
- self.m_sToken = sToken
- self.m_sReceiveId = sReceiveId
-
- def VerifyURL(self, sMsgSignature, sTimeStamp, sNonce, sEchoStr):
- """验证URL
- @param sMsgSignature: 签名串,对应URL参数的msg_signature
- @param sTimeStamp: 时间戳,对应URL参数的timestamp
- @param sNonce: 随机串,对应URL参数的nonce
- @param sEchoStr: 随机串,对应URL参数的echostr
- @param sReplyEchoStr: 解密之后的echostr,当return返回0时有效
- @return: 成功0,失败返回对应的错误码
- """
- sha1 = SHA1()
- ret, signature = sha1.getSHA1(self.m_sToken, sTimeStamp, sNonce, sEchoStr)
- if ret != 0:
- return ret, None
- if not signature == sMsgSignature:
- return WXBizMsgCrypt_ValidateSignature_Error, None
- pc = Prpcrypt(self.key)
- ret, sReplyEchoStr = pc.decrypt(sEchoStr, self.m_sReceiveId)
- return ret, sReplyEchoStr
-
- def EncryptMsg(self, sReplyMsg, sNonce, timestamp=None):
- """将企业回复用户的消息加密打包
- @param sReplyMsg: 企业号待回复用户的消息,xml格式的字符串
- @param sTimeStamp: 时间戳,可以自己生成,也可以用URL参数的timestamp,如为None则自动用当前时间
- @param sNonce: 随机串,可以自己生成,也可以用URL参数的nonce
- sEncryptMsg: 加密后的可以直接回复用户的密文,包括msg_signature, timestamp, nonce, encrypt的xml格式的字符串,
- return:成功0,sEncryptMsg,失败返回对应的错误码None
- """
- pc = Prpcrypt(self.key)
- ret, encrypt = pc.encrypt(sReplyMsg, self.m_sReceiveId)
- encrypt = encrypt.decode("utf8") # type: ignore
- if ret != 0:
- return ret, None
- if timestamp is None:
- timestamp = str(int(time.time()))
- # 生成安全签名
- sha1 = SHA1()
- ret, signature = sha1.getSHA1(self.m_sToken, timestamp, sNonce, encrypt)
- if ret != 0:
- return ret, None
- xmlParse = XMLParse()
- return ret, xmlParse.generate(encrypt, signature, timestamp, sNonce)
-
- def DecryptMsg(self, sPostData, sMsgSignature, sTimeStamp, sNonce):
- """检验消息的真实性,并且获取解密后的明文
- # @param sMsgSignature: 签名串,对应URL参数的msg_signature
- # @param sTimeStamp: 时间戳,对应URL参数的timestamp
- # @param sNonce: 随机串,对应URL参数的nonce
- # @param sPostData: 密文,对应POST请求的数据
- # xml_content: 解密后的原文,当return返回0时有效
- # @return: 成功0,失败返回对应的错误码
- # 验证安全签名
- """
- xmlParse = XMLParse()
- ret, encrypt = xmlParse.extract(sPostData) # type: ignore
- if ret != 0:
- return ret, None
- sha1 = SHA1()
- ret, signature = sha1.getSHA1(self.m_sToken, sTimeStamp, sNonce, encrypt)
- if ret != 0:
- return ret, None
- if not signature == sMsgSignature:
- return WXBizMsgCrypt_ValidateSignature_Error, None
- pc = Prpcrypt(self.key)
- ret, xml_content = pc.decrypt(encrypt, self.m_sReceiveId)
- return ret, xml_content
diff --git a/wecom_api/api/wecom_server_api.py b/wecom_api/api/wecom_server_api.py
deleted file mode 100644
index 1e139716a..000000000
--- a/wecom_api/api/wecom_server_api.py
+++ /dev/null
@@ -1,100 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import json
-import requests
-from datetime import datetime, timedelta
-from odoo import api, fields, models, SUPERUSER_ID, _
-
-# from .wecom_abstract_api import ApiException
-
-
-class WecomServerApi(models.TransientModel):
- _inherit = "wecom.abstract_api"
- _name = "wecom.service_api"
- _description = "Wecom Server API"
- _table = "wecom_service_api"
-
- corpid = fields.Char(string="Corp Id", readonly=True)
- secret = fields.Char(string="Secret", readonly=True)
- access_token = fields.Char(string="Access Token", readonly=True, default=None)
- token_expiration_time = fields.Datetime(
- string="Token Expiration Time", readonly=True
- )
-
- @api.model
- def InitServiceApi(self, corpid, secret):
- """
- 初始化企业微信API 对象
- :param corpid : 企业ID
- :param secret : 应用密钥
- :returns 模型"wecom.service_api"对象
- """
- api = self.search(
- [
- ("corpid", "=", corpid),
- ("secret", "=", secret),
- ],
- limit=1,
- )
- if not api:
- # 创建API令牌记录
- api = self.sudo().create(
- {
- "corpid": corpid,
- "secret": secret,
- }
- )
- if api["access_token"] is False or api["access_token"] == "": # type: ignore
- # token为空,刷新API令牌记录
- api.refreshAccessToken() # type: ignore
- if (
- api["token_expiration_time"] is False # type: ignore
- or api["token_expiration_time"] < datetime.now() # type: ignore
- ):
- # token过期,刷新API令牌记录
- api.refreshAccessToken() # type: ignore
-
- return api
-
- def getAccessToken(self):
- """
- 获取令牌
- """
- if self.access_token is None:
- self.refreshAccessToken()
- return self.access_token
-
- def refreshAccessToken(self):
- """
- 刷新模型 'wecom.service_api' 的令牌
- 同时刷新发起请求的模型 'wecom.apps' 的令牌
- """
- response = self.httpCall( # type: ignore
- self.env["wecom.service_api_list"].get_server_api_call("GET_ACCESS_TOKEN"),
- {"corpid": self.corpid, "corpsecret": self.secret},
- )
- expiration_second = timedelta(seconds=response["expires_in"])
-
- dict = {
- "access_token": response.get("access_token"),
- "token_expiration_time": datetime.now() + expiration_second,
- }
-
- self.sudo().write(dict)
-
- # 写对应的应用的值
- compay_id = self.env["res.company"].search(
- [("corpid", "=", self.corpid)], limit=1
- )
- app_id = self.env["wecom.apps"].search(
- [("company_id", "=", compay_id.id), ("secret", "=", self.secret)], limit=1
- )
-
- app_id.sudo().write(dict)
-
- def get_api_debug(self):
- """
- 获取 API 调试模式
- """
- ir_config = self.env["ir.config_parameter"].sudo()
- return True if ir_config.get_param("wecom.debug_enabled") == "True" else False
diff --git a/wecom_api/controllers/__init__.py b/wecom_api/controllers/__init__.py
deleted file mode 100644
index 65a8c1201..000000000
--- a/wecom_api/controllers/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from . import main
diff --git a/wecom_api/controllers/main.py b/wecom_api/controllers/main.py
deleted file mode 100644
index c34bfe090..000000000
--- a/wecom_api/controllers/main.py
+++ /dev/null
@@ -1,131 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import json
-import logging
-import xml.etree.cElementTree as ET
-from lxml import etree
-import sys
-from odoo.addons.wecom_api.api.wecom_msg_crtpt import WecomMsgCrypt # type: ignore
-from odoo import http, models, fields, _
-from odoo.http import request
-from odoo.http import Response
-
-_logger = logging.getLogger(__name__)
-
-
-class StripeController(http.Controller):
- """ """
-
- @http.route(
- ["/wecom_callback", "/wecom_callback/"],
- type="http",
- auth="public",
- methods=["GET", "POST"],
- )
- def WecomCallbackService(self): # type: ignore
- """
- 企业微信回调服务
- """
-
- @http.route(
- ["/wecom_callback//", "/wecom_callback/contacts"],
- type="http",
- auth="public",
- methods=["GET", "POST"],
- csrf=False,
- )
- def WecomCallbackService(self, service, id, **kw):
- """
- 企业微信回调服务
- :param id: 公司id
- :param service: 回调服务名称 code
- 文档URL: https://work.weixin.qq.com/api/doc/90000/90135/90930#3.2%20%E6%94%AF%E6%8C%81Http%20Post%E8%AF%B7%E6%B1%82%E6%8E%A5%E6%94%B6%E4%B8%9A%E5%8A%A1%E6%95%B0%E6%8D%AE
- """
- company_id = request.env["res.company"].sudo().search([("id", "=", id)]) # type: ignore
- sCorpID = company_id.corpid
-
- callback_service = (
- company_id.contacts_app_id.app_callback_service_ids.sudo().search(
- [
- ("app_id", "=", company_id.contacts_app_id.id),
- ("code", "=", service),
- "|",
- ("active", "=", True),
- ("active", "=", False),
- ]
- )
- )
- if callback_service.active is False:
- _logger.info(
- _("App [%s] does not have service [%s] enabled")
- % (company_id.contacts_app_id.name, callback_service.name)
- )
- return Response("success", status=200)
- else:
- wxcpt = WecomMsgCrypt(
- callback_service.callback_url_token,
- callback_service.callback_aeskey,
- sCorpID,
- )
-
- # 获取企业微信发送的相关参数
- sVerifyMsgSig = kw["msg_signature"]
- sVerifyTimeStamp = kw["timestamp"]
- sVerifyNonce = kw["nonce"]
-
- if request.httprequest.method == "GET": # type: ignore
- # ^ 假设企业的接收消息的URL设置为http://api.3dept.com。
- # ^ 企业管理员在保存回调配置信息时,企业微信会发送一条验证消息到填写的URL,请求内容如下:
- # ^ 请求方式:GET
- # ^ http://api.3dept.com/?msg_signature=ASDFQWEXZCVAQFASDFASDFSS×tamp=13500001234&nonce=123412323&echostr=ENCRYPT_STR
- # ^ 请求参数:
- # ^ msg_signature: 企业微信加密签名,msg_signature计算结合了企业填写的token、请求中的timestamp、nonce、加密的消息体。
- # ^ timestamp: 时间戳。与nonce结合使用,用于防止请求重放攻击。
- # ^ nonce: 随机数。用于保证签名不可预测。与timestamp结合使用,用于防止请求重放攻击。
- # ^ echostr: 加密的随机字符串。用于保证签名不可预测。
- sVerifyEchoStr = kw["echostr"]
- ret, msg = wxcpt.VerifyURL(
- sVerifyMsgSig, sVerifyTimeStamp, sVerifyNonce, sVerifyEchoStr
- )
- if ret != 0:
- logging.error("ERR: VerifyURL ret: " + str(ret))
- sys.exit(1)
- return msg
-
- if request.httprequest.method == "POST": # type: ignore
- # ^ 假设企业的接收消息的URL设置为http://api.3dept.com。
- # ^ 当用户触发回调行为时,企业微信会发送回调消息到填写的URL,请求内容如下:
- # ^ 请求方式:POST
- # ^ 请求地址 :http://api.3dept.com/?msg_signature=ASDFQWEXZCVAQFASDFASDFSS×tamp=13500001234&nonce=123412323
- # ^ 请求参数:
- # ^ msg_signature: 企业微信加密签名,msg_signature计算结合了企业填写的token、请求中的timestamp、nonce、加密的消息体。
- # ^ timestamp: 时间戳。与nonce结合使用,用于防止请求重放攻击。
- # ^ nonce: 随机数。用于保证签名不可预测。与timestamp结合使用,用于防止请求重放攻击。
- # ^ ToUserName: 企业微信的CorpID,当为第三方应用回调事件时,CorpID的内容为suiteid
- # ^ AgentID: 接收的应用id,可在应用的设置页面获取。仅应用相关的回调会带该字段。
- # ^ Encrypt: 消息结构体加密后的字符串
- sReqData = request.httprequest.data # type: ignore
- ret, msg = wxcpt.DecryptMsg(
- sReqData, sVerifyMsgSig, sVerifyTimeStamp, sVerifyNonce
- )
- if ret != 0:
- logging.error("ERR: DecryptMsg ret: " + str(ret))
- sys.exit(1)
- # 解密成功,msg即明文的xml消息结构体
- # xml_tree = etree.fromstring(msg) # xml解析为一个xml元素
- # print("解密成功", msg)
- try:
- return (
- request.env["wecom.app.event_type"] # type: ignore
- .sudo()
- .with_context(xml_tree=msg, company_id=company_id)
- .handle_event()
- ) # 传递xml元素和公司
- except:
- pass
- finally:
- # ^ 正确响应企业微信本次的POST请求,企业微信将不会再次发送请求
- # ^ ·企业微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次
- # ^ ·当接收成功后,http头部返回200表示接收ok,其他错误码企业微信后台会一律当做失败并发起重试
- # return Response("success", status=200)
- pass
diff --git a/wecom_api/data/ir_config_parameter.xml b/wecom_api/data/ir_config_parameter.xml
deleted file mode 100644
index 25a8dd357..000000000
--- a/wecom_api/data/ir_config_parameter.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
-
- wecom.global_error_code_url
- https://developer.work.weixin.qq.com/document/path/90313
-
-
-
-
-
-
- wecom.global_error_code_item_selection_code
- //h5
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_api/data/ir_cron_data.xml b/wecom_api/data/ir_cron_data.xml
deleted file mode 100644
index 79e2b661c..000000000
--- a/wecom_api/data/ir_cron_data.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/wecom_api/data/reptile.py b/wecom_api/data/reptile.py
deleted file mode 100644
index 60b27868f..000000000
--- a/wecom_api/data/reptile.py
+++ /dev/null
@@ -1,98 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-
-# ----------------------------------------
-# 使用爬虫爬取微信错误码 生成 XML 数据文件
-# ----------------------------------------
-import os
-from io import BytesIO
-import requests
-from lxml import etree
-
-
-nodes = "//table/tbody/tr"
-url = "https://developer.work.weixin.qq.com/document/path/90313"
-page_text = requests.get(url=url).text
-tree = etree.HTML(page_text) # type: ignore
-lines = tree.xpath(nodes)
-
-
-# 输出一个错误代码列表
-codes = []
-for line in lines:
- code = line.xpath("./td[1]/text()")[0]
- try:
- name = line.xpath("./td[2]/text()")[0]
- except:
- name = line.xpath("./td[3]/text()")[0]
- # print(name)
-
- # xml 转义
- if '"' in name:
- name.replace('"', """)
- if "&" in name:
- name.replace('"', "&")
- if "<" in name:
- name.replace('"', "<")
- if "<" in name:
- name.replace(">", ">")
-
- codes.append(
- {
- "code": int(code),
- "name": name,
- }
- )
-
-# 排序
-new_codes = sorted(codes, key=lambda c: int(c["code"]))
-
-# ----------------------------
-# https://lxml.de/tutorial.html
-# ----------------------------
-# 生成生成根节点
-root = etree.Element("odoo") # type: ignore
-
-# 生成 data 节点
-data_node = etree.Element("data", attrib={"noupdate": "0"}) # type: ignore
-root.append(data_node)
-
-for code in new_codes:
- id = "wechat_error_codes_"
- if code == -1:
- id += "minus_1"
- else:
- id += str(code["code"])
-
- record_attrs = {
- "id": id,
- "model": "wechat.error_codes",
- }
- record_node = etree.Element("record", attrib=record_attrs) # type: ignore
-
- code_field_node = etree.Element("field", attrib={"name": "code"}) # type: ignore
- code_field_node.text = str(code["code"])
- name_field_node = etree.Element("field", attrib={"name": "name"}) # type: ignore
- name_field_node.text = code["name"]
- record_node.append(code_field_node)
- record_node.append(name_field_node)
- data_node.append(record_node)
-
-# 保存xml
-xml = (
- """
-%s
-"""
- % etree.tostring(root, pretty_print=True).decode()
-)
-
-
-current_dir = os.path.dirname(os.path.abspath(__file__))
-xml_file_name = "reptile.xml"
-xml_file_path = os.path.join(current_dir, xml_file_name)
-
-if not os.path.exists(xml_file_path):
- os.system(r"touch {}".format(xml_file_path)) # 调用系统命令行来创建文件
-
-with open(xml_file_path, "w", encoding="gb2312") as f:
- f.write(xml)
diff --git a/wecom_api/data/service_api_list_data.xml b/wecom_api/data/service_api_list_data.xml
deleted file mode 100644
index ac498b603..000000000
--- a/wecom_api/data/service_api_list_data.xml
+++ /dev/null
@@ -1,3021 +0,0 @@
-
-
-
-
-
-
-
- 1
- 获取access_token
-
- 获取access_token是调用企业微信API接口的第一步,相当于创建了一个登录凭证,其它的业务API接口,都需要依赖于access_token来鉴权调用者身份。 因此开发者,在使用业务接口前,要明确access_token的颁发来源,使用正确的access_token。
-
- GET_ACCESS_TOKEN
- GET
- /cgi-bin/gettoken
- 1
-
-
-
- 1
- 获取企业的jsapi_ticket
-
- 生成签名之前必须先了解一下jsapi_ticket,jsapi_ticket是H5应用调用企业微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒 ,通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限(一小时内,一个企业最多可获取400次,且单个应用不能超过100次),频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket。
-
-
- GET_JSAPI_TICKET
- GET
- /cgi-bin/get_jsapi_ticket?access_token=ACCESS_TOKEN
- 2
-
-
-
- 1
- 获取企业微信API域名IP段
-
- API域名IP即qyapi.weixin.qq.com的解析地址,由开发者调用企业微信端的接入IP。如果企业需要做防火墙配置,那么可以通过这个接口获取到所有相关的IP段。IP段有变更可能,当IP段变更时,新旧IP段会同时保留一段时间。建议企业每天定时拉取IP段,更新防火墙设置,避免因IP段变更导致网络不通。
-
- GET_API_DOMAIN_IP
- GET
- /cgi-bin/get_api_domain_ip?access_token=ACCESS_TOKEN
- 3
-
-
-
-
-
- 2
- 通讯录管理 > 成员管理 > 创建成员
- USER_CREATE
- GET
- /cgi-bin/user/create?access_token=ACCESS_TOKEN
- 11001
-
-
- 2
- 通讯录管理 > 成员管理 > 读取成员
-
- 在通讯录同步助手中此接口可以读取企业通讯录的所有成员的信息,而自建应用可以读取该应用设置的可见范围内的成员信息。
-
- USER_GET
- GET
- /cgi-bin/user/get?access_token=ACCESS_TOKEN
- 11002
-
- 应用只能获取可见范围内的成员信息,且每种应用获取的字段有所不同,在返回结果说明中会逐个说明。企业通讯录安全特别重要,企业微信将持续升级加固通讯录接口的安全机制,以下是关键的变更点:
-
- 从2022年6月20号20点开始,除通讯录同步以外的基础应用(如客户联系、微信客服、会话存档、日程等),以及新创建的自建应用与代开发应用,调用该接口时,不再返回以下字段:头像、性别、手机、邮箱、企业邮箱、员工个人二维码、地址,应用需要通过oauth2手工授权 的方式获取管理员与员工本人授权的字段。
-
-
- 【重要】 从2022年8月15日10点开始,“企业管理后台 - 管理工具 - 通讯录同步”的新增IP将不能再调用此接口,企业可通过「获取成员ID列表」 和 「获取部门ID列表」 接口获取userid和部门ID列表。查看调整详情 。
-
-
-
-
-
- 2
- 通讯录管理 > 成员管理 > 更新成员
- USER_UPDATE
- GET
- /cgi-bin/user/get?access_token=ACCESS_TOKEN
- 11003
-
-
- 2
- 通讯录管理 > 成员管理 > 删除成员
-
- 仅通讯录同步助手或第三方通讯录应用可调用。
- 若是绑定了腾讯企业邮,则会同时删除邮箱帐号。
-
-
- USER_DELETE
- POST
- /cgi-bin/user/delete?access_token=ACCESS_TOKEN
- 11004
-
-
- 2
- 通讯录管理 > 成员管理 > 批量删除成员
- USER_BATCH_DELETE
- POST
- /cgi-bin/user/batchdelete?access_token=ACCESS_TOKEN
- 11005
-
-
- 2
- 通讯录管理 > 成员管理 > 获取部门成员
- USER_SIMPLE_LIST
- GET
- /cgi-bin/user/simplelist?access_token=ACCESS_TOKEN
- 11006
-
- 企业通讯录安全特别重要,企业微信将持续升级加固通讯录接口的安全机制,以下是关键的变更点::
-
-
-
-
- 2
- 通讯录管理 > 成员管理 > 获取部门成员详情
- USER_LIST
- GET
- /cgi-bin/user/list?access_token=ACCESS_TOKEN
- 11007
-
- 应用只能获取可见范围内的成员信息,且每种应用获取的字段有所不同,在返回结果说明中会逐个说明。企业通讯录安全特别重要,企业微信持续升级加固通讯录接口的安全机制,以下是关键的变更点:
-
-
- 从2022年6月20号20点开始,除通讯录同步以外的基础应用(如客户联系、微信客服、会话存档、日程等),以及新创建的自建应用与代开发应用,调用该接口时,不再返回以下字段:头像、性别、手机、邮箱、企业邮箱、员工个人二维码、地址,应用需要通过oauth2手工授权 的方式获取管理员与员工本人授权的字段。
-
-
- 【重要】 从2022年8月15日10点开始,“企业管理后台 - 管理工具 - 通讯录同步”的新增IP将不能再调用此接口,企业可通过「获取成员ID列表」 和 「获取部门ID列表」 接口获取userid和部门ID列表。查看调整详情 。
-
-
-
-
-
- 2
- 通讯录管理 > 成员管理 > userid与openid互换 > userid转openid
-
- 该接口使用场景为企业支付,在使用企业红包和向员工付款时,需要自行将企业微信的userid转成openid。
-
- 注:需要成员使用微信登录企业微信或者关注微信插件(原企业号)才能转成openid;
- 如果是外部联系人,请使用 外部联系人openid转换 转换openid
-
-
- USERID_TO_OPENID
- POST
- /cgi-bin/user/convert_to_openid?access_token=ACCESS_TOKEN
- 11008
-
-
- 2
- 通讯录管理 > 成员管理 > userid与openid互换 > openid转userid
-
- 该接口主要应用于使用企业支付之后的结果查询。
- 开发者需要知道某个结果事件的openid对应企业微信内成员的信息时,可以通过调用该接口进行转换查询。
-
- OPENID_TO_USERID
- POST
- /cgi-bin/user/convert_to_userid?access_token=ACCESS_TOKEN
- 11009
-
-
- 2
- 通讯录管理 > 成员管理 > 二次验证
- USER_AUTH_SUCCESS
- GET
- /cgi-bin/user/authsucc?access_token=ACCESS_TOKEN
- 11010
-
-
- 2
- 通讯录管理 > 成员管理 > 邀请成员
-
- 企业可通过接口批量邀请成员使用企业微信,邀请后将通过短信或邮件下发通知。
-
- BATCH_INVITE
- /cgi-bin/batch/invite?access_token=ACCESS_TOKEN
- POST
- 11011
-
-
- 2
- 通讯录管理 > 成员管理 > 获取加入企业二维码
-
- 支持企业用户获取实时成员加入二维码。
-
- GET_JOIN_QRCODE
- /cgi-bin/corp/get_join_qrcode?access_token=ACCESS_TOKEN
- GET
- 11012
-
-
- 2
- 通讯录管理 > 成员管理 > 获取企业活跃成员数
- GET_ACTIVE_MEMBERS
- /cgi-bin/corp/get_join_qrcode?access_token=ACCESS_TOKEN
- POST
- 11013
-
-
- 2
- 通讯录管理 > 成员管理 > 手机号获取userid
-
- 通过手机号获取其所对应的userid。
-
- GETUSERID
- /cgi-bin/user/getuserid?access_token=ACCESS_TOKEN
- POST
- 11013
-
-
- 2
- 通讯录管理 > 成员管理 > 获取成员授权列表
-
- 当企业当前授权模式为成员授权时,可调用该接口获取成员授权列表。
-
- LIST_MEMBER_AUTH
- /cgi-bin/user/list_member_auth?access_token=ACCESS_TOKEN
- POST
- 11014
-
-
- 2
- 通讯录管理 > 成员管理 > 查询成员用户是否已授权
-
- 当企业当前授权模式为成员授权时,可调用该接口查询成员用户是否已授权。
-
- CHECK_MEMBER_AUTH
- /cgi-bin/user/check_member_auth?access_token=ACCESS_TOKEN
- POST
- 11015
-
-
- 2
- 通讯录管理 > 成员管理 > 获取选人ticket对应的用户
-
- 当企业以成员授权的方式安装了第三方应用,成员在企业微信终端通过选人jsapi选择通讯录,应用获取到selectedTicket后,可调用该接口获取SelectedTicket对应的用户open_userid列表。
-
- LIST_SELECTED_TICKET_USER
- /cgi-bin/user/list_selected_ticket_user?access_token=ACCESS_TOKEN
- POST
- 11016
-
-
- 2
- 通讯录管理 > 成员管理 > userid转换为open_userid
-
- 将自建应用或代开发应用获取的userid转换为第三方应用的userid
-
- USERID_TO_OPENUSERID
- /cgi-bin/user/userid_to_openuserid?access_token=ACCESS_TOKEN
- POST
- 11017
-
-
-
- 2
- 通讯录管理 > 成员管理 > 邮箱获取userid
-
- 通过邮箱获取其所对应的userid。
-
- GET_USERID_BY_EMAIL
- /cgi-bin/user/get_userid_by_email?access_token=ACCESS_TOKEN
- POST
- 11018
-
-
- 2
- 通讯录管理 > 成员管理 > 获取成员ID列表
-
- 获取企业成员的open_userid与对应的部门ID列表。
-
- USER_LIST_ID
- /cgi-bin/user/list_id?access_token=ACCESS_TOKEN
- POST
- 11019
-
-
-
-
- 2
- 通讯录管理 > 部门管理 > 创建部门
- DEPARTMENT_CREATE
- /cgi-bin/department/create?access_token=ACCESS_TOKEN
- POST
- 12001
-
-
- 2
- 通讯录管理 > 部门管理 > 更新部门
- DEPARTMENT_UPDATE
- /cgi-bin/department/update?access_token=ACCESS_TOKEN
- POST
- 12002
-
-
- 2
- 通讯录管理 > 部门管理 > 删除部门
- DEPARTMENT_DELETE
- /cgi-bin/department/delete?access_token=ACCESS_TOKEN
- GET
- 12003
-
-
- 2
- 通讯录管理 > 部门管理 > 获取部门列表
-
- 企业通讯录安全特别重要,企业微信将持续升级加固通讯录接口的安全机制,以下是关键的变更点:
-
-
- 【重要】 从2022年8月15日10点开始,“企业管理后台 - 管理工具 - 通讯录同步”的新增IP将不能再调用此接口,企业可通过「获取部门ID列表」 接口获取部门ID列表。查看调整详情 。
-
-
-
- DEPARTMENT_LIST
- /cgi-bin/department/list?access_token=ACCESS_TOKEN
- GET
- 12004
-
-
- 2
- 通讯录管理 > 部门管理 > 获取子部门ID列表
- DEPARTMENT_SIMPLELIST
- /cgi-bin/department/simplelist?access_token=ACCESS_TOKEN
- GET
- 12005
-
-
- 2
- 通讯录管理 > 部门管理 > 获取单个部门详情
- DEPARTMENT_DETAILS
- /cgi-bin/department/get?access_token=ACCESS_TOKEN
- GET
- 12006
-
- 企业通讯录安全特别重要,企业微信将持续升级加固通讯录接口的安全机制,以下是关键的变更点:
-
-
- 【重要】 从2022年8月15日10点开始,“企业管理后台 - 管理工具 - 通讯录同步”的新增IP将不能再调用此接口,企业可通过「获取部门ID列表」 接口获取部门ID列表。查看调整详情 。
-
-
-
-
-
-
-
- 2
- 通讯录管理 > 标签管理 > 创建标签
- TAG_CREATE
- /cgi-bin/tag/create?access_token=ACCESS_TOKEN
- POST
- 13001
-
-
- 2
- 通讯录管理 > 标签管理 > 更新标签名字
- TAG_UPDATE
- /cgi-bin/tag/update?access_token=ACCESS_TOKEN
- POST
- 13002
-
-
- 2
- 通讯录管理 > 标签管理 > 删除标签
- TAG_DELETE
- /cgi-bin/tag/delete?access_token=ACCESS_TOKEN
- GET
- 13003
-
-
- 2
- 通讯录管理 > 标签管理 > 获取标签成员
- TAG_GET_MEMBER
- /cgi-bin/tag/get?access_token=ACCESS_TOKEN
- GET
- 13004
-
-
- 2
- 通讯录管理 > 标签管理 > 增加标签成员
- TAG_ADD_MEMBER
- /cgi-bin/tag/addtagusers?access_token=ACCESS_TOKEN
- POST
- 13005
-
-
- 2
- 通讯录管理 > 标签管理 > 删除标签成员
- TAG_DELETE_MEMBER
- /cgi-bin/tag/deltagusers?access_token=ACCESS_TOKEN
- POST
- 13006
-
-
- 2
- 通讯录管理 > 标签管理 > 获取标签列表
- TAG_GET_LIST
- /cgi-bin/tag/list?access_token=ACCESS_TOKEN
- GET
- 13007
-
-
-
-
- 2
- 通讯录管理 > 异步批量接口 > 增量更新成员
-
-
-本接口以userid(帐号)为主键,增量更新企业微信通讯录成员。请先下载CSV模板(下载增量更新成员模版),根据需求填写文件内容。
- 注意事项:
-
-
-
- 模板中的部门需填写部门ID,多个部门用分号分隔,部门ID必须为数字,根部门的部门id默认为1
-
-
- 文件中存在、通讯录中也存在的成员,更新成员在文件中指定的字段值
-
-
- 文件中存在、通讯录中不存在的成员,执行添加操作
-
-
- 通讯录中存在、文件中不存在的成员,保持不变
-
-
- 成员字段更新规则:可自行添加扩展字段。文件中有指定的字段,以指定的字段值为准;文件中没指定的字段,不更新
-
-
-
-
- BATCH_SYNCUSER
- /cgi-bin/batch/syncuser?access_token=ACCESS_TOKEN
- POST
- 14001
-
-
- 2
- 通讯录管理 > 异步批量接口 > 全量覆盖成员
-
-
-本接口以userid为主键,全量覆盖企业的通讯录成员,任务完成后企业的通讯录成员与提交的文件完全保持一致。请先下载CSV文件(下载全量覆盖成员模版),根据需求填写文件内容。
- 注意事项:
-
-
-
- 文件中存在、通讯录中也存在的成员,完全以文件为准
-
-
- 文件中存在、通讯录中不存在的成员,执行添加操作
-
-
- 文件中存在、通讯录中不存在的成员,执行添加操作
-
-
- 通讯录中存在、文件中不存在的成员,执行删除操作。出于安全考虑,下面两种情形系统将中止导入并返回相应的错误码。
-
- 需要删除的成员多于50人,且多于现有人数的20%以上
- 需要删除的成员少于50人,且多于现有人数的80%以上
-
-
-
- 成员字段更新规则:可自行添加扩展字段。文件中有指定的字段,以指定的字段值为准;文件中没指定的字段,不更新
-
-
-
-
- BATCH_REPLACEUSER
- /cgi-bin/batch/replaceuser?access_token=ACCESS_TOKEN
- POST
- 14002
-
-
- 2
- 通讯录管理 > 异步批量接口 > 全量覆盖部门
-
-
-本接口以partyid为键,全量覆盖企业的通讯录组织架构,任务完成后企业的通讯录组织架构与提交的文件完全保持一致。请先下载CSV文件(下载全量覆盖部门模版),根据需求填写文件内容。
- 注意事项:
-
-
-
- 文件中存在、通讯录中也存在的部门,执行修改操作
-
-
- 文件中存在、通讯录中不存在的部门,执行添加操作
-
-
- 文件中不存在、通讯录中存在的部门,当部门下没有任何成员或子部门时,执行删除操作
-
-
- 文件中不存在、通讯录中存在的部门,当部门下仍有成员或子部门时,暂时不会删除,当下次导入成员把人从部门移出后自动删除
-
-
- CSV文件中,部门名称、部门ID、父部门ID为必填字段,部门ID必须为数字,根部门的部门id默认为1;排序为可选字段,置空或填0不修改排序, order值大的排序靠前。
-
-
-
-
- BATCH_REPLACEPARTY
- /cgi-bin/batch/replaceparty?access_token=ACCESS_TOKEN
- POST
- 14003
-
-
- 2
- 通讯录管理 > 异步批量接口 > 获取异步任务结果
- BATCH_TASK_GET_RESULT
- /cgi-bin/batch/getresult?access_token=ACCESS_TOKEN
- GET
- 14004
-
-
-
-
- 2
- 通讯录管理 > 互联企业 > 获取应用的可见范围
-
- 本接口只返回互联企业中非本企业内的成员和部门的信息,如果要获取本企业的可见范围,请调用“获取应用”接口
-
- LINKEDCORP_GET_PERM_LIST
- /cgi-bin/linkedcorp/agent/get_perm_list?access_token=ACCESS_TOKEN
- POST
- 15001
-
-
- 2
- 通讯录管理 > 互联企业 > 获取互联企业成员详细信息
- LINKEDCORP_USER_GET
- /cgi-bin/linkedcorp/user/get?access_token=ACCESS_TOKEN
- POST
- 15002
-
-
- 2
- 通讯录管理 > 互联企业 > 获取互联企业部门成员
- INKEDCORP_USER_SIMPLELIST
- /cgi-bin/linkedcorp/user/simplelist?access_token=ACCESS_TOKEN
- POST
- 15003
-
-
- 2
- 通讯录管理 > 互联企业 > 获取互联企业部门成员详情
- LINKEDCORP_USER_LIST
- /cgi-bin/linkedcorp/user/list?access_token=ACCESS_TOKEN
- POST
- 15004
-
-
- 2
- 通讯录管理 > 互联企业 > 获取互联企业部门列表
- LINKEDCORP_DEPARTMENT_LIST
- /cgi-bin/linkedcorp/department/list?access_token=ACCESS_TOKEN
- POST
- 15005
-
-
-
-
- 2
- 通讯录管理 > 异步导出接口 > 导出成员
- EXPORT_SIMPLE_USER
- /cgi-bin/export/simple_user?access_token=ACCESS_TOKEN
- POST
- 16001
-
-
- 2
- 通讯录管理 > 异步导出接口 > 导出成员详情
- EXPORT_USER
- /cgi-bin/export/user?access_token=ACCESS_TOKEN
- POST
- 16002
-
-
- 2
- 通讯录管理 > 异步导出接口 > 导出部门
- EXPORT_DEPARTMENT
- /cgi-bin/export/department?access_token=ACCESS_TOKEN
- POST
- 16003
-
-
- 2
- 通讯录管理 > 异步导出接口 > 导出标签成员
- EXPORT_TAGUSER
- /cgi-bin/export/taguser?access_token=ACCESS_TOKEN
- POST
- 16004
-
-
- 2
- 通讯录管理 > 异步导出接口 > 获取导出结果
- EXPORT_GET_RESULT
- /cgi-bin/export/get_result?access_token=ACCESS_TOKEN
- GET
- 16005
-
-
-
-
-
-
- 3
- 客户联系 > 企业服务人员管理 > 获取配置了客户联系功能的成员列表
-
- 企业和第三方服务商可通过此接口获取配置了客户联系功能的成员列表。
-
- EXTERNALCONTACT_GET_FOLLOW_USER_LIST
- /cgi-bin/externalcontact/get_follow_user_list?access_token=ACCESS_TOKEN
- GET
- 21001
-
-
- 3
- 客户联系 > 企业服务人员管理 > 客户联系「联系我」管理 > 配置客户联系「联系我」方式
-
- 企业可以在管理后台-客户联系-加客户中配置成员的「联系我」的二维码或者小程序按钮,客户通过扫描二维码或点击小程序上的按钮,即可获取成员联系方式,主动联系到成员。
- 企业可通过此接口为具有客户联系功能的成员生成专属的「联系我」二维码或者「联系我」按钮。 如果配置的是「联系我」按钮,需要开发者的小程序接入小程序插件。
- 注意:
- 通过API添加的「联系我」不会在管理端进行展示,每个企业可通过API最多配置50万个「联系我」。
- 用户需要妥善存储返回的config_id,config_id丢失可能导致用户无法编辑或删除「联系我」。
- 临时会话模式不占用「联系我」数量,但每日最多添加10万个,并且仅支持单人。
- 临时会话模式的二维码,添加好友完成后该二维码即刻失效。
-
-
- EXTERNALCONTACT_ADD_CONTACT_WAY
- /cgi-bin/externalcontact/add_contact_way?access_token=ACCESS_TOKEN
- POST
- 21002
-
-
- 3
- 客户联系 > 企业服务人员管理 > 客户联系「联系我」管理 > 取企业已配置的「联系我」方式
-
- 获取企业配置的「联系我」二维码和「联系我」小程序按钮。
-
- EXTERNALCONTACT_GET_CONTACT_WAY
- /cgi-bin/externalcontact/get_contact_way?access_token=ACCESS_TOKEN
- POST
- 21003
-
-
- 3
- 客户联系 > 企业服务人员管理 > 客户联系「联系我」管理 > 获取企业已配置的「联系我」列表
-
- 获取企业配置的「联系我」二维码和「联系我」小程序插件列表。不包含临时会话。
- 注意,该接口仅可获取2021年7月10日以后创建的「联系我」
-
- EXTERNALCONTACT_LIST_CONTACT_WAY
- /cgi-bin/externalcontact/list_contact_way?access_token=ACCESS_TOKEN
- POST
- 21004
-
-
- 3
- 客户联系 > 企业服务人员管理 > 客户联系「联系我」管理 > 更新企业已配置的「联系我」方式
-
- 更新企业配置的「联系我」二维码和「联系我」小程序按钮中的信息,如使用人员和备注等。
-
- EXTERNALCONTACT_UPDATE_CONTACT_WAY
- /cgi-bin/externalcontact/update_contact_way?access_token=ACCESS_TOKEN
- POST
- 21005
-
-
- 3
- 客户联系 > 企业服务人员管理 > 客户联系「联系我」管理 > 删除企业已配置的「联系我」方式
-
- 删除一个已配置的「联系我」二维码或者「联系我」小程序按钮。
-
- EXTERNALCONTACT_DEL_CONTACT_WAY
- /cgi-bin/externalcontact/del_contact_way?access_token=ACCESS_TOKEN
- POST
- 21006
-
-
- 3
- 客户联系 > 企业服务人员管理 > 客户联系「联系我」管理 > 结束临时会话
-
- 将指定的企业成员和客户之前的临时会话断开,断开前会自动下发已配置的结束语。
-
- EXTERNALCONTACT_CLOSE_TEMP_CHAT
- /cgi-bin/externalcontact/close_temp_chat?access_token=ACCESS_TOKEN
- POST
- 21007
-
-
-
-
- 3
- 客户联系 > 客户管理 > 获取客户列表
-
- 企业可通过此接口获取指定成员添加的客户列表。客户是指配置了客户联系功能的成员所添加的外部联系人。没有配置客户联系功能的成员,所添加的外部联系人将不会作为客户返回。
-
- EXTERNALCONTACT_LIST
- /cgi-bin/externalcontact/list?access_token=ACCESS_TOKEN
- GET
- 22001
-
-
- 3
- 客户联系 > 客户管理 > 获取客户详情
-
- 企业可通过此接口,根据外部联系人的userid,拉取客户详情。
-
- EXTERNALCONTACT_GET
- /cgi-bin/externalcontact/get?access_token=ACCESS_TOKEN
- GET
- 22002
-
-
- 3
- 客户联系 > 客户管理 > 批量获取客户详情
-
- 企业/第三方可通过此接口获取指定成员添加的客户信息列表。
-
- EXTERNALCONTACT_BATCH_GET_BY_USER
- /cgi-bin/externalcontact/batch/get_by_user?access_token=ACCESS_TOKEN
- POST
- 22003
-
-
-
- 3
- 客户联系 > 客户管理 > 客户联系规则组管理 > 获取规则组列表
-
- 企业可通过此接口获取企业配置的所有客户规则组id列表。
-
- EXTERNALCONTACT_CUSTOMER_STRATEGY_LIST
- /cgi-bin/externalcontact/customer_strategy/list?access_token=ACCESS_TOKEN
- POST
- 22005
-
-
- 3
- 客户联系 > 客户管理 > 客户联系规则组管理 > 获取规则组详情
-
- 企业可以通过此接口获取某个客户规则组的详细信息。
-
- EXTERNALCONTACT_CUSTOMER_STRATEGY_GET
- /cgi-bin/externalcontact/customer_strategy/get?access_token=ACCESS_TOKEN
- POST
- 22006
-
-
- 3
- 客户联系 > 客户管理 > 客户联系规则组管理 > 获取规则组管理范围
-
- 企业可通过此接口获取某个客户规则组管理的成员和部门列表
-
- EXTERNALCONTACT_CUSTOMER_STRATEGY_GET_RANGE
- /cgi-bin/externalcontact/customer_strategy/get_range?access_token=ACCESS_TOKEN
- POST
- 22007
-
-
- 3
- 客户联系 > 客户管理 > 客户联系规则组管理 > 创建新的规则组
-
- 企业可通过此接口创建一个新的客户规则组。该接口仅支持串行调用,请勿并发创建规则组。
-
- EXTERNALCONTACT_CUSTOMER_STRATEGY_CREATE
- /cgi-bin/externalcontact/customer_strategy/create?access_token=ACCESS_TOKEN
- POST
- 22008
-
-
- 3
- 客户联系 > 客户管理 > 客户联系规则组管理 > 编辑规则组及其管理范围
-
- 企业可通过此接口编辑规则组的基本信息和修改客户规则组管理范围。该接口仅支持串行调用,请勿并发修改规则组。
-
- EXTERNALCONTACT_CUSTOMER_STRATEGY_EDIT
- /cgi-bin/externalcontact/customer_strategy/edit?access_token=ACCESS_TOKEN
- POST
- 22009
-
-
- 3
- 客户联系 > 客户管理 > 客户联系规则组管理 > 删除规则组
-
- 企业可通过此接口删除某个规则组。
-
- EXTERNALCONTACT_CUSTOMER_STRATEGY_DEL
- /cgi-bin/externalcontact/customer_strategy/del?access_token=ACCESS_TOKEN
- POST
- 22010
-
-
-
-
- 3
- 客户联系 > 客户标签管理 > 管理企业标签 > 获取企业标签库
-
- 企业可通过此接口获取企业客户标签详情。
-
- EXTERNALCONTACT_GET_CORP_TAG_LIST
- /cgi-bin/externalcontact/get_corp_tag_list?access_token=ACCESS_TOKEN
- POST
- 23001
-
-
- 3
- 客户联系 > 客户标签管理 > 管理企业标签 > 添加企业客户标签
-
- 企业可通过此接口向客户标签库中添加新的标签组和标签,每个企业最多可配置3000个企业标签。
-
- EXTERNALCONTACT_ADD_CORP_TAG
- /cgi-bin/externalcontact/add_corp_tag?access_token=ACCESS_TOKEN
- POST
- 23002
-
-
- 3
- 客户联系 > 客户标签管理 > 管理企业标签 > 编辑企业客户标签
-
- 企业可通过此接口编辑客户标签/标签组的名称或次序值。
-
- EXTERNALCONTACT_EDIT_CORP_TAG
- /cgi-bin/externalcontact/edit_corp_tag?access_token=ACCESS_TOKEN
- POST
- 23003
-
-
- 3
- 客户联系 > 客户标签管理 > 管理企业标签 > 删除企业客户标签
-
- 企业可通过此接口删除客户标签库中的标签,或删除整个标签组。
-
- EXTERNALCONTACT_DEL_CORP_TAG
- /cgi-bin/externalcontact/del_corp_tag?access_token=ACCESS_TOKEN
- POST
- 23004
-
-
- 3
- 客户联系 > 客户标签管理 > 管理企业规则组下的客户标签 > 获取指定规则组下的企业客户标签
-
- 企业可通过此接口获取某个规则组内的企业客户标签详情
-
- EXTERNALCONTACT_GET_STRATEGY_TAG_LIST
- /cgi-bin/externalcontact/get_strategy_tag_list?access_token=ACCESS_TOKEN
- POST
- 23005
-
-
- 3
- 客户联系 > 客户标签管理 > 管理企业规则组下的客户标签 > 为指定规则组创建企业客户标签
-
- 企业可通过此接口向规则组中添加新的标签组和标签, 每个企业的企业标签和规则组标签合计最多可配置3000个 。注意, 仅可在一级规则组下添加标签 。
-
-
- EXTERNALCONTACT_ADD_STRATEGY_TAG
- /cgi-bin/externalcontact/add_strategy_tag?access_token=ACCESS_TOKEN
- POST
- 23006
-
-
- 3
- 客户联系 > 客户标签管理 > 管理企业规则组下的客户标签 > 编辑指定规则组下的企业客户标签
-
- 企业可通过此接口编辑指定规则组下的客户标签/标签组的名称或次序值,但不可重新指定标签/标签组所属规则组。
-
-
- EXTERNALCONTACT_EDIT_STRATEGY_TAG
- /cgi-bin/externalcontact/edit_strategy_tag?access_token=ACCESS_TOKEN
- POST
- 23007
-
-
- 3
- 客户联系 > 客户标签管理 > 管理企业规则组下的客户标签 > 删除指定规则组下的企业客户标签
-
- 企业可通过此接口删除某个规则组下的标签,或删除整个标签组。
-
- EXTERNALCONTACT_DEL_STRATEGY_TAG
- /cgi-bin/externalcontact/del_strategy_tag?access_token=ACCESS_TOKEN
- POST
- 23008
-
-
- 3
- 客户联系 > 客户标签管理 > 编辑客户企业标签
-
- 企业可通过此接口为指定成员的客户添加上由企业统一配置的标签
-
- EXTERNALCONTACT_MARK_TAG
- /cgi-bin/externalcontact/mark_tag?access_token=ACCESS_TOKEN
- POST
- 23009
-
-
-
-
- 3
- 客户联系 > 在职继承 > 分配在职成员的客户
-
- 企业可通过此接口,转接在职成员的客户给其他成员。
-
- EXTERNALCONTACT_TRANSFER_CUSTOMER
- /cgi-bin/externalcontact/transfer_customer?access_token=ACCESS_TOKEN
- POST
- 24001
-
-
- 3
- 客户联系 > 在职继承 > 查询客户接替状态
-
- 企业和第三方可通过此接口查询在职成员的客户转接情况。
-
- EXTERNALCONTACT_TRANSFER_RESULT
- /cgi-bin/externalcontact/transfer_result?access_token=ACCESS_TOKEN
- POST
- 24002
-
-
-
-
- 3
- 客户联系 > 离职继承 > 获取待分配的离职成员列表
-
- 企业和第三方可通过此接口,获取所有离职成员的客户列表,并可进一步调用分配离职成员的客户接口将这些客户重新分配给其他企业成员。
-
- EXTERNALCONTACT_GET_UNASSIGNED_LIST
- /cgi-bin/externalcontact/get_unassigned_list?access_token=ACCESS_TOKEN
- POST
- 25001
-
-
- 3
- 客户联系 > 离职继承 > 分配离职成员的客户
-
- 企业可通过此接口,分配离职成员的客户给其他成员
-
- EXTERNALCONTACT_RESIGNED_TRANSFER_CUSTOMER
- /cgi-bin/externalcontact/resigned/transfer_customer?access_token=ACCESS_TOKEN
- POST
- 25002
-
-
- 3
- 客户联系 > 离职继承 > 查询客户接替状态
-
- 企业和第三方可通过此接口查询离职成员的客户分配情况
-
- EXTERNALCONTACT_RESIGNED_TRANSFER_RESULT
- /cgi-bin/externalcontact/resigned/transfer_result?access_token=ACCESS_TOKEN
- POST
- 25003
-
-
- 3
- 客户联系 > 离职继承 > 分配离职成员的客户群
-
- 企业可通过此接口,将已离职成员为群主的群,分配给另一个客服成员。
-
- EXTERNALCONTACT_GROUPCHAT_TRANSFER
- /cgi-bin/externalcontact/groupchat/transfer?access_token=ACCESS_TOKEN
- POST
- 25004
-
-
-
-
- 3
- 客户联系 > 客户群管理 > 获取客户群列表
-
- 该接口用于获取配置过客户群管理的客户群列表。
-
- EXTERNALCONTACT_GROUPCHAT_LIST
- /cgi-bin/externalcontact/groupchat/list?access_token=ACCESS_TOKEN
- POST
- 26001
-
-
- 3
- 客户联系 > 客户群管理 > 获取客户群详情
-
- 通过客户群ID,获取详情。包括群名、群成员列表、群成员入群时间、入群方式。(客户群是由具有客户群使用权限的成员创建的外部群)
- 需注意的是,如果发生群信息变动,会立即收到群变更事件,但是部分信息是异步处理,可能需要等一段时间调此接口才能得到最新结果
-
- EXTERNALCONTACT_GROUPCHAT_GET
- /cgi-bin/externalcontact/groupchat/get?access_token=ACCESS_TOKEN
- POST
- 26002
-
-
- 3
- 客户联系 > 客户群管理 > 客户群opengid转换
-
- 用户在微信里的客户群里打开小程序时,某些场景下可以获取到群的opengid,如果该群是企业微信的客户群,则企业或第三方可以调用此接口将一个opengid转换为客户群chat_id
-
- EXTERNALCONTACT_GROUPCHAT_OPENGID_TO_CHATID
- /cgi-bin/externalcontact/groupchat/opengid_to_chatid?access_token=ACCESS_TOKEN
- POST
- 26003
-
-
-
-
-
- 3
- 客户联系 > 联系我与客户入群方式 > 客户联系「联系我」管理 > 配置客户联系「联系我」方式
-
- 企业可以在管理后台-客户联系-加客户中配置成员的「联系我」的二维码或者小程序按钮,客户通过扫描二维码或点击小程序上的按钮,即可获取成员联系方式,主动联系到成员。
- 企业可通过此接口为具有客户联系功能的成员生成专属的「联系我」二维码或者「联系我」按钮。
- 如果配置的是「联系我」按钮,需要开发者的小程序接入小程序插件。
-
- 注意:
- 通过API添加的「联系我」不会在管理端进行展示,每个企业可通过API最多配置50万 个「联系我」。
-
- 用户需要妥善存储返回的config_id,config_id丢失可能导致用户无法编辑或删除「联系我」 。
-
- 临时会话模式不占用「联系我」数量,但每日最多添加 10万 个,并且仅支持单人。
-
- 临时会话模式的二维码,添加好友完成后该二维码即刻失效。
-
- EXTERNALCONTACT_ADD_CONTACT_WAY
- /cgi-bin/externalcontact/add_contact_way?access_token=ACCESS_TOKEN
- POST
- 27001
-
-
- 3
- 客户联系 > 联系我与客户入群方式 > 客户联系「联系我」管理 > 获取企业已配置的「联系我」方式
-
- 获取企业配置的「联系我」二维码和「联系我」小程序按钮。
-
- EXTERNALCONTACT_GET_CONTACT_WAY
- /cgi-bin/externalcontact/get_contact_way?access_token=ACCESS_TOKEN
- POST
- 27002
-
-
- 3
- 客户联系 > 联系我与客户入群方式 > 客户联系「联系我」管理 > 获取企业已配置的「联系我」列表
-
- 获取企业配置的「联系我」二维码和「联系我」小程序插件列表。不包含临时会话。
- 注意, 该接口仅可获取2021年7月10日以后创建的「联系我」
-
-
- EXTERNALCONTACT_LIST_CONTACT_WAY
- /cgi-bin/externalcontact/list_contact_way?access_token=ACCESS_TOKEN
- POST
- 27003
-
-
- 3
- 客户联系 > 联系我与客户入群方式 > 客户联系「联系我」管理 > 更新企业已配置的「联系我」方式
-
- 更新企业配置的「联系我」二维码和「联系我」小程序按钮中的信息,如使用人员和备注等。
-
- EXTERNALCONTACT_UPDATE_CONTACT_WAY
- /cgi-bin/externalcontact/update_contact_way?access_token=ACCESS_TOKEN
- POST
- 27004
-
-
- 3
- 客户联系 > 联系我与客户入群方式 > 客户联系「联系我」管理 > 删除企业已配置的「联系我」方式
-
- 删除一个已配置的「联系我」二维码或者「联系我」小程序按钮。
-
- EXTERNALCONTACT_DEL_CONTACT_WAY
- /cgi-bin/externalcontact/del_contact_way?access_token=ACCESS_TOKEN
- POST
- 27005
-
-
- 3
- 客户联系 > 联系我与客户入群方式 > 客户联系「联系我」管理 > 结束临时会话
-
- 将指定的企业成员和客户之前的临时会话断开,断开前会自动下发已配置的结束语。
-
- EXTERNALCONTACT_CLOSE_TEMP_CHAT
- /cgi-bin/externalcontact/close_temp_chat?access_token=ACCESS_TOKEN
- POST
- 27006
-
-
-
- 3
- 客户联系 > 联系我与客户入群方式 > 户群「加入群聊」管理 > 配置客户群进群方式
-
- 企业可以在管理后台-客户联系中配置「加入群聊」的二维码或者小程序按钮,客户通过扫描二维码或点击小程序上的按钮,即可加入特定的客户群
- 企业可以在管理后台-企业可通过此接口为具有客户联系功能的成员生成专属的二维码或者小程序按钮。
- 企业可以在管理后台-如果配置的是小程序按钮,需要开发者的小程序接入小程序插件。
-
- 注意:
-
-
- 通过API添加的配置不会在管理端进行展示,每个企业可通过API最多配置50万个「加入群聊」(与「联系我」共用50万的额度)。
-
-
- EXTERNALCONTACT_GROUPCHAT_ADD_JOIN_WAY
- /cgi-bin/externalcontact/groupchat/add_join_way?access_token=ACCESS_TOKEN
- POST
- 27010
-
-
- 3
- 客户联系 > 联系我与客户入群方式 > 户群「加入群聊」管理 > 获取客户群进群方式配置
-
- 获取企业配置的群二维码或小程序按钮。
-
- EXTERNALCONTACT_GROUPCHAT_GET_JOIN_WAY
- /cgi-bin/externalcontact/groupchat/get_join_way?access_token=ACCESS_TOKEN
- POST
- 27011
-
-
- 3
- 客户联系 > 联系我与客户入群方式 > 户群「加入群聊」管理 > 更新客户群进群方式配置
-
- 更新进群方式配置信息。注意:使用覆盖的方式更新。
-
- EXTERNALCONTACT_GROUPCHAT_UPDATE_JOIN_WAY
- /cgi-bin/externalcontact/groupchat/update_join_way?access_token=ACCESS_TOKEN
- POST
- 27012
-
-
- 3
- 客户联系 > 联系我与客户入群方式 > 户群「加入群聊」管理 > 删除客户群进群方式配置
-
- 删除一个进群方式配置。
-
- EXTERNALCONTACT_GROUPCHAT_DEL_JOIN_WAY
- /cgi-bin/externalcontact/groupchat/del_join_way?access_token=ACCESS_TOKEN
- POST
- 27012
-
-
-
-
-
- 3
- 客户联系 > 客户朋友圈 > 企业发表内容到客户的朋友圈 > 创建发表任务
-
- 企业和第三方应用可通过该接口创建客户朋友圈的发表任务。
-
- EXTERNALCONTACT_ADD_MOMENT_TASK
- /cgi-bin/externalcontact/add_moment_task?access_token=ACCESS_TOKEN
- POST
- 27001
-
-
- 3
- 客户联系 > 客户朋友圈 > 企业发表内容到客户的朋友圈 > 获取任务创建结果
-
- 由于发表任务的创建是异步执行的,应用需要再调用该接口以获取创建的结果。
-
- EXTERNALCONTACT_GET_MOMENT_TASK_RESULT
- /cgi-bin/externalcontact/get_moment_task_result?access_token=ACCESS_TOKEN
- GET
- 27002
-
-
- 3
- 客户联系 > 客户朋友圈 > 获取客户朋友圈全部的发表记录 > 获取企业全部的发表列表
-
- 企业和第三方应用可通过该接口获取企业全部的发表内容。
-
- EXTERNALCONTACT_GET_MOMENT_LIST
- /cgi-bin/externalcontact/get_moment_list?access_token=ACCESS_TOKEN
- POST
- 27003
-
-
- 3
- 客户联系 > 客户朋友圈 > 获取客户朋友圈全部的发表记录 > 获取客户朋友圈企业发表的列表
-
- 企业和第三方应用可通过该接口获取企业发表的朋友圈成员执行情况
-
- EXTERNALCONTACT_GET_MOMENT_TASK
- /cgi-bin/externalcontact/get_moment_task?access_token=ACCESS_TOKEN
- POST
- 27004
-
-
- 3
- 客户联系 > 客户朋友圈 > 获取客户朋友圈全部的发表记录 > 获取客户朋友圈发表时选择的可见范围
-
- 企业和第三方应用可通过该接口获取客户朋友圈创建时,选择的客户可见范围
-
- EXTERNALCONTACT_GET_MOMENT_CUSTOMER_LIST
- /cgi-bin/externalcontact/get_moment_customer_list?access_token=ACCESS_TOKEN
- POST
- 27005
-
-
- 3
- 客户联系 > 客户朋友圈 > 获取客户朋友圈全部的发表记录 > 获取客户朋友圈发表后的可见客户列表
-
- 企业和第三方应用可通过该接口获取客户朋友圈发表后,可在微信朋友圈中查看的客户列表
-
- EXTERNALCONTACT_GET_MOMENT_SEND_RESULT
- /cgi-bin/externalcontact/get_moment_send_result?access_token=ACCESS_TOKEN
- POST
- 27006
-
-
-
- 3
- 客户联系 > 客户朋友圈 > 客户朋友圈规则组管理 > 获取规则组列表
-
- 企业可通过此接口获取企业配置的所有客户朋友圈规则组id列表。
-
- EXTERNALCONTACT_MOMENT_STRATEGY_LIST
- /cgi-bin/externalcontact/moment_strategy/list?access_token=ACCESS_TOKEN
- POST
- 27008
-
-
- 3
- 客户联系 > 客户朋友圈 > 客户朋友圈规则组管理 > 获取规则组详情
-
- 企业可以通过此接口获取某个客户朋友圈规则组的详细信息。
-
- EXTERNALCONTACT_MOMENT_STRATEGY_GET
- /cgi-bin/externalcontact/moment_strategy/get?access_token=ACCESS_TOKEN
- POST
- 27009
-
-
- 3
- 客户联系 > 客户朋友圈 > 客户朋友圈规则组管理 > 获取规则组管理范围
-
- 企业可通过此接口获取某个朋友圈规则组管理的成员和部门列表
-
- EXTERNALCONTACT_MOMENT_STRATEGY_GET_RANGE
- /cgi-bin/externalcontact/moment_strategy/get_range?access_token=ACCESS_TOKEN
- POST
- 27010
-
-
- 3
- 客户联系 > 客户朋友圈 > 客户朋友圈规则组管理 > 创建新的规则组
-
- 企业可通过此接口创建一个新的客户朋友圈规则组。该接口仅支持串行调用,请勿并发创建规则组。
-
- EXTERNALCONTACT_MOMENT_STRATEGY_CREATE
- /cgi-bin/externalcontact/moment_strategy/create?access_token=ACCESS_TOKEN
- POST
- 27011
-
-
- 3
- 客户联系 > 客户朋友圈 > 客户朋友圈规则组管理 > 编辑规则组及其管理范围
-
- 企业可通过此接口编辑规则组的基本信息和修改客户朋友圈规则组管理范围。该接口仅支持串行调用,请勿并发修改规则组。
-
- EXTERNALCONTACT_MOMENT_STRATEGY_EDIT
- /cgi-bin/externalcontact/moment_strategy/edit?access_token=ACCESS_TOKEN
- POST
- 27012
-
-
- 3
- 客户联系 > 客户朋友圈 > 客户朋友圈规则组管理 > 删除规则组
-
- 企业可通过此接口删除某个客户朋友圈规则组。
-
- EXTERNALCONTACT_MOMENT_STRATEGY_DEL
- /cgi-bin/externalcontact/moment_strategy/del?access_token=ACCESS_TOKEN
- POST
- 27013
-
-
-
-
-
- 3
- 客户联系 > 消息推送 > 创建企业群发
-
- 企业跟第三方应用可通过此接口添加企业群发消息的任务并通知成员发送给相关客户或客户群。(注:企业微信终端需升级到2.7.5版本及以上
-
- 注意:调用该接口并不会直接发送消息给客户/客户群,需要成员确认后才会执行发送(客服人员的企业微信需要升级到2.7.5及以上版本
-
-
- 旧接口创建企业群发已经废弃,接口升级后支持发送视频文件,并且支持最多同时发送9个附件。
-
-
- 仅会推送给最后跟客户进行聊天互动的企业成员。
-
- 每位客户/每个客户群每天可接收1条群发消息,可以是企业统一创建发送的,也可以是成员自己创建发送的;超过接收上限的客户/客户群将无法再收到群发消息。
-
- EXTERNALCONTACT_ADD_MSG_TEMPLATE
- /cgi-bin/externalcontact/add_msg_template?access_token=ACCESS_TOKEN
- POST
- 28001
-
-
-
- 3
- 客户联系 > 消息推送 > 获取企业的全部群发记录 > 获取群发记录列表
-
- 企业和第三方应用可通过此接口获取企业与成员的群发记录。
-
- EXTERNALCONTACT_GET_GROUPMSG_LIST_V2
- /cgi-bin/externalcontact/get_groupmsg_list_v2?access_token=ACCESS_TOKEN
- POST
- 28002
-
-
- 3
- 客户联系 > 消息推送 > 获取企业的全部群发记录 > 获取群发成员发送任务列表
-
-
-
- EXTERNALCONTACT_GET_GROUPMSG_TASK
- /cgi-bin/externalcontact/get_groupmsg_task?access_token=ACCESS_TOKEN
- POST
- 28003
-
-
- 3
- 客户联系 > 消息推送 > 获取企业的全部群发记录 > 获取企业群发成员执行结果
-
-
-
- EXTERNALCONTACT_GET_GROUPMSG_SEND_RESULT
- /cgi-bin/externalcontact/get_groupmsg_send_result?access_token=ACCESS_TOKEN
- POST
- 28004
-
-
-
-
- 3
- 客户联系 > 消息推送 > 发送新客户欢迎语
-
-
-
- 企业微信在向企业推送添加外部联系人事件时,会额外返回一个welcome_code,企业以此为凭据调用接口,即可通过成员向新添加的客户发送个性化的欢迎语。
- 为了保证用户体验以及避免滥用,企业仅可在收到相关事件后20秒内调用,且只可调用一次。
-
- 如果企业已经在管理端为相关成员配置了可用的欢迎语,则推送添加外部联系人事件时不会返回welcome_code。
-
- 每次添加新客户时 可能有多个企业自建应用/第三方应用收到带有welcome_code的回调事件,但仅有最先调用的可以发送成功 。后续调用将返回 41051(externaluser has started chatting) 错误,请用户根据实际使用需求,合理设置应用可见范围,避免冲突
-
-
- 旧接口发送新客户欢迎语已经废弃,接口升级后支持发送视频文件,并且最多支持同时发送9个附件
-
-
-
-
- EXTERNALCONTACT_SEND_WELCOME_MSG
- /cgi-bin/externalcontact/send_welcome_msg?access_token=ACCESS_TOKEN
- POST
- 28005
-
-
-
-
- 3
- 客户联系 > 消息推送 > 入群欢迎语素材管理 > 添加入群欢迎语素材
-
- 企业可通过此API向企业的入群欢迎语素材库中添加素材。每个企业的入群欢迎语素材库中,最多容纳100个素材。
-
- EXTERNALCONTACT_GROUP_WELCOME_TEMPLATE_ADD
- /cgi-bin/externalcontact/group_welcome_template/add?access_token=ACCESS_TOKEN
- POST
- 28006
-
-
- 3
- 客户联系 > 消息推送 > 入群欢迎语素材管理 > 编辑入群欢迎语素材
-
- 企业可通过此API编辑入群欢迎语素材库中的素材,且仅能够编辑调用方自己创建的入群欢迎语素材
-
- EXTERNALCONTACT_GROUP_WELCOME_TEMPLATE_EDIT
- /cgi-bin/externalcontact/group_welcome_template/edit?access_token=ACCESS_TOKEN
- POST
- 28007
-
-
- 3
- 客户联系 > 消息推送 > 入群欢迎语素材管理 > 获取入群欢迎语素材
-
- 企业可通过此API获取入群欢迎语素材。
-
- EXTERNALCONTACT_GROUP_WELCOME_TEMPLATE_GET
- /cgi-bin/externalcontact/group_welcome_template/get?access_token=ACCESS_TOKEN
- POST
- 28008
-
-
- 3
- 客户联系 > 消息推送 > 入群欢迎语素材管理 > 删除入群欢迎语素材
-
- 企业可通过此API删除入群欢迎语素材,且仅能删除调用方自己创建的入群欢迎语素材。
-
- EXTERNALCONTACT_GROUP_WELCOME_TEMPLATE_DEL
- /cgi-bin/externalcontact/group_welcome_template/del?access_token=ACCESS_TOKEN
- POST
- 28009
-
-
-
-
- 3
- 客户联系 > 统计管理 > 获取「联系客户统计」数据
-
- 企业可通过此接口获取成员联系客户的数据,包括发起申请数、新增客户数、聊天数、发送消息数和删除/拉黑成员的客户数等指标。
-
- EXTERNALCONTACT_GET_USER_BEHAVIOR_DATA
- /cgi-bin/externalcontact/get_user_behavior_data?access_token=ACCESS_TOKEN
- POST
- 28010
-
-
- 3
- 客户联系 > 统计管理 > 获取「群聊数据统计」数据 > 按群主聚合的方式
-
- 按群主聚合的方式获取指定日期的统计数据。注意,企业微信仅存储180天的数据。
-
- EXTERNALCONTACT_GROUPCHAT_STATISTIC
- /cgi-bin/externalcontact/groupchat/statistic?access_token=ACCESS_TOKEN
- POST
- 28011
-
-
- 3
- 客户联系 > 统计管理 > 获取「群聊数据统计」数据 > 按自然日聚合的方式
-
- 按自然日聚合的方式获取指定日期的统计数据。注意,企业微信仅存储180天的数据。
-
- EXTERNALCONTACT_GROUPCHAT_STATISTIC_GROUP_BY_DAY
- /cgi-bin/externalcontact/groupchat/statistic_group_by_day?access_token=ACCESS_TOKEN
- POST
- 28012
-
-
-
-
- 3
- 客户联系 > 管理商品图册 > 创建商品图册
-
- 企业和第三方应用可以通过此接口增加商品
-
- EXTERNALCONTACT_ADD_PRODUCT_ALBUM
- /cgi-bin/externalcontact/add_product_album?access_token=ACCESS_TOKEN
- POST
- 29001
-
-
- 3
- 客户联系 > 管理商品图册 > 获取商品图册
-
- 企业和第三方应用可以通过此接口获取商品信息
-
- EXTERNALCONTACT_GET_PRODUCT_ALBUM
- /cgi-bin/externalcontact/get_product_album?access_token=ACCESS_TOKEN
- POST
- 29002
-
-
- 3
- 客户联系 > 管理商品图册 > 获取商品图册列表
-
- 企业和第三方应用可以通过此接口导出商品
-
- EXTERNALCONTACT_GET_PRODUCT_ALBUM_LIST
- /cgi-bin/externalcontact/get_product_album_list?access_token=ACCESS_TOKEN
- POST
- 29003
-
-
- 3
- 客户联系 > 管理商品图册 > 编辑商品图册
-
- 企业和第三方应用可以通过此接口修改商品信息
-
- EXTERNALCONTACT_UPDATE_PRODUCT_ALBUM
- /cgi-bin/externalcontact/update_product_album?access_token=ACCESS_TOKEN
- POST
- 29004
-
-
- 3
- 客户联系 > 管理商品图册 > 删除商品图册
-
- 企业和第三方应用可以通过此接口删除商品信息
-
- EXTERNALCONTACT_DELETE_PRODUCT_ALBUM
- /cgi-bin/externalcontact/delete_product_album?access_token=ACCESS_TOKEN
- POST
- 29005
-
-
-
-
- 3
- 客户联系 > 管理聊天敏感词 > 新建敏感词规则
-
- 企业和第三方应用可以通过此接口新建敏感词规则
-
- EXTERNALCONTACT_ADD_INTERCEPT_RULE
- /cgi-bin/externalcontact/add_intercept_rule?access_token=ACCESS_TOKEN
- POST
- 21001
-
-
- 3
- 客户联系 > 管理聊天敏感词 > 获取敏感词规则列表
-
- 企业和第三方应用可以通过此接口获取敏感词规则列表
-
- EXTERNALCONTACT_GET_INTERCEPT_RULE_LIST
- /cgi-bin/externalcontact/get_intercept_rule_list?access_token=ACCESS_TOKEN
- GET
- 21002
-
-
- 3
- 客户联系 > 管理聊天敏感词 > 获取敏感词规则详情
-
- 企业和第三方应用可以通过此接口获取敏感词规则详情
-
- EXTERNALCONTACT_GET_INTERCEPT_RULE
- /cgi-bin/externalcontact/get_intercept_rule?access_token=ACCESS_TOKEN
- POST
- 21003
-
-
- 3
- 客户联系 > 管理聊天敏感词 > 修改敏感词规则
-
- 企业和第三方应用可以通过此接口修改敏感词规则
-
- EXTERNALCONTACT_UPDATE_INTERCEPT_RULE
- /cgi-bin/externalcontact/update_intercept_rule?access_token=ACCESS_TOKEN
- POST
- 21004
-
-
- 3
- 客户联系 > 管理聊天敏感词 > 删除敏感词规则
-
- 企业和第三方应用可以通过此接口修改敏感词规则
-
- EXTERNALCONTACT_DEL_INTERCEPT_RULE
- /cgi-bin/externalcontact/del_intercept_rule?access_token=ACCESS_TOKEN
- POST
- 21005
-
-
-
-
- 3
- 客户联系 > 上传附件资源
-
- 素材上传得到media_id,该media_id仅三天内有效
- media_id在同一企业内应用之间可以共享
-
- EXTERNALCONTACT_DEL_INTERCEPT_RULE
- /cgi-bin/media/upload_attachment?access_token=ACCESS_TOKEN&media_type=TYPE&attachment_type=1
- POST
- 21101
-
-
-
-
-
- 4
- 微信客服 > 客服账号管理 > 添加客服帐号
-
- 添加客服帐号,并可设置客服名称和头像。目前一家企业最多可添加 5000个 客服帐号。
-
-
- KF_ACCOUNT_ADD
- /cgi-bin/kf/account/add?access_token=ACCESS_TOKEN
- POST
- 31001
-
-
- 4
- 微信客服 > 客服账号管理 > 删除客服帐号
-
- 删除已有的客服帐号
-
- KF_ACCOUNT_DEL
- /cgi-bin/kf/account/del?access_token=ACCESS_TOKEN
- POST
- 31002
-
-
- 4
- 微信客服 > 客服账号管理 > 修改客服帐号
-
- 修改已有的客服帐号,可修改客服名称和头像。
-
- KF_ACCOUNT_UPDATE
- /cgi-bin/kf/account/update?access_token=ACCESS_TOKEN
- POST
- 31003
-
-
- 4
- 微信客服 > 客服账号管理 > 获取客服帐号列表
-
- 获取客服帐号列表,包括所有的客服帐号的客服ID、名称和头像。
-
- KF_ACCOUNT_LIST
- /cgi-bin/kf/account/list?access_token=ACCESS_TOKEN
- GET
- 31004
-
-
- 4
- 微信客服 > 客服账号管理 > 获取客服帐号链接
-
- 企业可通过此接口获取带有不同参数的客服链接,不同客服帐号对应不同的客服链接。获取后,企业可将链接嵌入到网页等场景中,微信用户点击链接即可向对应的客服帐号发起咨询。企业可依据参数来识别用户的咨询来源等。
-
- KF_ADD_CONTACT_WAY
- /cgi-bin/kf/add_contact_way?access_token=ACCESS_TOKEN
- POST
- 31005
-
-
-
-
- 4
- 微信客服 > 接待人员管理 > 添加接待人员
-
- 添加指定客服帐号的接待人员,每个客服帐号目前最多可添加 2000个 接待人员, 20个 部门。
-
-
- KF_SERVICER_ADD
- /cgi-bin/kf/servicer/add?access_token=ACCESS_TOKEN
- POST
- 32001
-
-
- 4
- 微信客服 > 接待人员管理 > 删除接待人员
-
- 从客服帐号删除接待人员
-
- KF_SERVICER_DEL
- /cgi-bin/kf/servicer/del?access_token=ACCESS_TOKEN
- POST
- 32002
-
-
- 4
- 微信客服 > 接待人员管理 > 获取接待人员列表
-
- 获取某个客服帐号的接待人员列表
-
- KF_SERVICER_LIST
- /cgi-bin/kf/servicer/list?access_token=ACCESS_TOKEN
- GET
- 32003
-
-
-
-
-
- 4
- 微信客服 > 会话分配与消息收发 > 分配客服会话 > 获取会话状态
-
-
-
- KF_SERVICE_STATE_GET
- /cgi-bin/kf/service_state/get?access_token=ACCESS_TOKEN
- POST
- 33001
-
-
- 4
- 微信客服 > 会话分配与消息收发 > 分配客服会话 > 变更会话状态
-
-
-
- KF_SERVICE_STATE_TRANS
- /cgi-bin/kf/service_state/trans?access_token=ACCESS_TOKEN
- POST
- 33002
-
-
-
-
- 4
- 微信客服 > 会话分配与消息收发 > 接收消息和事件 > 读取消息
-
- 微信客户发送的消息、接待人员在企业微信回复的消息、发送消息接口发送失败事件(如被用户拒收)、客户点击菜单消息的回复消息,可以通过该接口获取具体的消息内容和事件。不支持读取通过发送消息接口发送的消息。
- 支持的消息类型:文本、图片、语音、视频、文件、位置、链接、名片、小程序、菜单、事件。
-
- KF_SYNC_MSG
- /cgi-bin/kf/sync_msg?access_token=ACCESS_TOKEN
- POST
- 33003
-
-
-
-
- 4
- 微信客服 > 会话分配与消息收发 > 发送消息
-
- 当微信客户处于“新接入待处理”或“由智能助手接待”状态下,可调用该接口给用户发送消息。
- 注意仅当微信客户在主动发送消息给客服后的48小时内,企业可发送消息给客户,最多可发送5条消息;若用户继续发送消息,企业可再次下发消息。
- 支持发送消息类型:文本、图片、语音、视频、文件、图文、小程序、菜单消息、地理位置。
- 目前该接口允许下发消息条数和下发时限如下:
-
-
-
-
- 用户动作
- 允许下发条数限制
- 下发时限
-
-
-
-
- 用户发送消息
- 5条
- 48 小时
-
-
-
-
-
- KF_SEND_MSG
- /cgi-bin/kf/send_msg?access_token=ACCESS_TOKEN
- POST
- 33004
-
-
-
-
- 4
- 微信客服 > 会话分配与消息收发 > 送欢迎语等事件响应消息
-
- 当特定的事件回调消息包含code字段,或通过接口变更到特定的会话状态,会返回code字段
- 开发者可以此code为凭证,调用该接口给用户发送相应事件场景下的消息,如客服欢迎语、客服提示语和会话结束语等。
- 除"用户进入会话事件"以外,响应消息仅支持会话处于获取该code的会话状态时发送,如将会话转入待接入池时获得的code仅能在会话状态为”待接入池排队中“时发送。
-
- 目前支持的事件场景和相关约束如下:
-
-
-
-
- 事件场景
- 允许下发条数
- code有效期
- 支持的消息类型
- 获取code途径
-
-
-
-
- 用户进入会话,用于发送客服欢迎语
- 1条
- 20秒
- 文本、菜单
- 事件回调
-
-
- 进入接待池,用于发送排队提示语等
- 1条
- 48小时
- 文本
- 转接会话接口
-
-
- 从接待池接入会话,用于发送非工作时间的提示语或超时未回复的提示语等
- 1条
- 48小时
- 文本
- 事件回调、转接会话接口
-
-
- 结束会话,用于发送结束会话提示语或满意度评价等
- 1条
- 20秒
- 文本、菜单
- 事件回调、转接会话接口
-
-
-
-
-
- KF_SEND_MSG_ON_EVENT
- /cgi-bin/kf/send_msg_on_event?access_token=ACCESS_TOKEN
- POST
- 33005
-
-
-
-
- 4
- 微信客服 > 「升级服务」配置 > 获取配置的专员与客户群
-
- 企业需要在管理后台或移动端中的「微信客服」-「升级服务」中,配置专员和客户群。该接口提供获取配置的专员与客户群列表的能力。
-
- KF_CUSTOMER_GET_UPGRADE_SERVICE_CONFIG
- /cgi-bin/kf/customer/get_upgrade_service_config?access_token=ACCESS_TOKEN
- GET
- 34001
-
-
- 4
- 微信客服 > 「升级服务」配置 > 为客户升级为专员或客户群服务
-
- 企业可通过其他接口获知客户的 external_userid 以及客户与接待人员的聊天内容,因此可以结合实际业务场景,为客户推荐指定的服务专员或客户群。
- 通过该 API 为客户指定专员或客户群后,接待人员可在企业微信中,见到特殊的状态提示(Windows 为 icon 样式变化,移动端为出现一条 bar ),便于接待人员知晓企业的指定动作。
-
-
-
-
- KF_CUSTOMER_UPGRADE_SERVICE
- /cgi-bin/kf/customer/upgrade_service?access_token=ACCESS_TOKEN
- POST
- 34002
-
-
- 4
- 微信客服 > 「升级服务」配置 > 为客户取消推荐
-
- 当企业通过 API 为客户指定了专员或客户群后,如果客户已经完成服务升级,或是企业需要取消推荐,则可调用该接口清空之前为客户指定的专员或客户群。清空后,企业微信中的特殊状态提示也会同步消失。
-
- KF_CUSTOMER_CANCEL_UPGRADE_SERVICE
- /cgi-bin/kf/customer/cancel_upgrade_service?access_token=ACCESS_TOKEN
- POST
- 34003
-
-
-
-
- 4
- 微信客服 > 其他基础信息获取 > 获取客户基础信息
-
-
-
- KF_CUSTOMER_BATCHGET
- /cgi-bin/kf/customer/batchget?access_token=ACCESS_TOKEN
- POST
- 35001
-
-
-
- 4
- 微信客服 > 统计管理 > 获取「客户数据统计」企业汇总数据
-
- 通过此接口,可以获取咨询会话数、咨询客户数等企业汇总统计数据
-
- KF_GET_CORP_STATISTIC
- /cgi-bin/kf/get_corp_statistic?access_token=ACCESS_TOKEN
- POST
- 36001
-
-
- 4
- 微信客服 > 统计管理 > 获取「客户数据统计」接待人员明细数据
-
- 通过此接口,可获取接入人工会话数、咨询会话数等与接待人员相关的统计信息
-
- KF_GET_SERVICER_STATISTIC
- /cgi-bin/kf/get_servicer_statistic?access_token=ACCESS_TOKEN
- POST
- 36002
-
-
-
-
- 5
- 身份验证 > 获取访问用户身份
-
- 该接口用于根据code获取成员信息
-
- GET_USER_INFO_BY_CODE
- /cgi-bin/user/getuserinfo?access_token=ACCESS_TOKEN
- GET
- 41001
-
-
-
- 5
- 身份验证 > 获取访问用户敏感信息
-
- 自建应用与代开发应用可通过该接口获取成员授权的敏感字段
-
- GET_USER_DETAIL_BY_USER_TICKET
- /cgi-bin/user/getuserdetail?access_token=ACCESS_TOKEN
- POST
- 41002
-
-
-
-
-
-
- 6
- 应用管理 > 获取应用 > 获取应用的jsapi_ticket
-
- 应用的jsapi_ticket用于计算agentConfig(参见“通过agentConfig注入应用的权限 ”)的签名,签名计算方法与上述介绍的config的签名算法完全相同,但需要注意以下区别:
-
- 签名的jsapi_ticket必须使用以下接口获取。且必须用wx.agentConfig中的agentid对应的应用去获取access_token。
- 签名用的noncestr和timestamp必须与wx.agentConfig中的nonceStr和timestamp相同。
-
- 正常情况下, 应用的jsapi_ticket的有效期为7200秒 ,通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限(一小时内,每个应用不能超过100次),频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存应用的jsapi_ticket 。
-
-
- AGENT_GET_TICKET
- /cgi-bin/ticket/get?access_token=ACCESS_TOKEN&type=agent_config
- GET
- 51000
-
-
-
- 6
- 应用管理 > 获取应用 > 获取指定的应用详情
-
- 对于互联企业的应用,如果需要获取应用可见范围内其他互联企业的部门与成员,请调用互联企业-获取应用可见范围接口
-
- AGENT_GET
- /cgi-bin/agent/get?access_token=ACCESS_TOKEN
- GET
- 51001
-
-
-
-
- 6
- 应用管理 > 获取应用 > 获取access_token对应的应用列表
-
-
-
- AGENT_LIST
- /cgi-bin/agent/list?access_token=ACCESS_TOKEN
- GET
- 51002
-
-
-
- 6
- 应用管理 > 设置应用
-
-
-
- AGENT_SET
- /cgi-bin/agent/set?access_token=ACCESS_TOKEN
- POST
- 51003
-
-
-
-
-
-
-
- 6
- 应用管理 > 设置工作台自定义展示 > 设置应用在工作台展示的模版
-
- 请求说明:该接口指定应用自定义模版类型。同时也支持设置企业默认模版数据。若type指定为 "normal" 则为取消自定义模式,改为普通展示模式
-
- AGENT_SET_WORKBENCH_TEMPLATE
- /cgi-bin/agent/set_workbench_template?access_token=ACCESS_TOKEN
- POST
- 51007
-
-
-
- 6
- 应用管理 > 设置工作台自定义展示 > 获取应用在工作台展示的模版
-
-
-
- AGENT_GET_WORKBENCH_TEMPLATE
- /cgi-bin/agent/get_workbench_template?access_token=ACCESS_TOKEN
- POST
- 51008
-
-
-
- 6
- 应用管理 > 设置工作台自定义展示 > 设置应用在用户工作台展示的数据
-
-
-
- AGENT_SET_WORKBENCH_DATA
- /cgi-bin/agent/set_workbench_data?access_token=ACCESS_TOKEN
- POST
- 51009
-
-
-
-
- 7
- 消息推送 > 发送应用消息
-
- 应用支持推送文本、图片、视频、文件、图文等类型。
-
- MESSAGE_SEND
- /cgi-bin/message/send?access_token=ACCESS_TOKEN
- POST
- 61001
-
-
- 7
- 消息推送 > 更新模版卡片消息
-
- 应用可以发送模板卡片消息,发送之后可再通过接口更新可回调的用户任务卡片消息的替换文案信息(仅原卡片为 按钮交互型、投票选择型、多项选择型的卡片以及填写了action_menu字段的文本通知型、图文展示型可以调用本接口更新)。
- 请注意,当应用调用发送模版卡片消息后,接口会返回一个response_code,通过response_code用户可以调用本接口一次。后续如果有用户点击任务卡片,回调接口也会带上response_code,开发者通过该code也可以调用本接口一次,注意response_code的有效期是24小时,超过24小时后将无法使用。
-
- MESSAGE_UPDATE_TEMPLATE_CARD
- /cgi-bin/message/update_template_card?access_token=ACCESS_TOKEN
- POST
- 61002
-
-
- 7
- 消息推送 > 撤回应用消息
-
-
-
- MESSAGE_RECALL
- /cgi-bin/message/recall?access_token=ACCESS_TOKEN
- POST
- 61003
-
-
-
- 7
- 消息推送 > 发送消息到群聊会话 > 创建群聊会话
-
-
-
- APPCHAT_CREATE
- /cgi-bin/appchat/create?access_token=ACCESS_TOKEN
- POST
- 61004
-
-
- 7
- 消息推送 > 发送消息到群聊会话 > 修改群聊会话
-
-
-
- APPCHAT_UPDATE
- /cgi-bin/appchat/update?access_token=ACCESS_TOKEN
- POST
- 61005
-
-
- 7
- 消息推送 > 发送消息到群聊会话 > 获取群聊会话
-
-
-
- APPCHAT_GET
- /cgi-bin/appchat/get?access_token=ACCESS_TOKEN
- GET
- 61006
-
-
- 7
- 消息推送 > 发送消息到群聊会话 > 应用推送消息
-
- 应用支持推送文本、图片、视频、文件、图文等类型。
-
- APP_CHAT_SEND
- /cgi-bin/appchat/send?access_token=ACCESS_TOKEN
- POST
- 61007
-
-
-
-
- 7
- 消息推送 > 互联企业消息推送 > 发送应用消息
-
- 互联企业是企业微信提供的满足集团与子公司、企业与上下游供应商进行连接的功能,企业可以共享通讯录以及应用给互联企业,如需要,你可以前往管理后台-通讯录创建互联企业,之后你可以在自建应用的可见范围设置互联企业的通讯录;此接口主要满足开发者给互联企业成员推送消息的诉求。
-
- LINKEDCORP_MESSAGE_SEND
- /cgi-bin/linkedcorp/message/send?access_token=ACCESS_TOKEN
- POST
- 61008
-
-
-
- 7
- 消息推送 > 家校消息推送 > 发送「学校通知」
-
- 学校可以通过此接口来给家长发送不同类型的学校通知,来满足多种场景下的学校通知需求。目前支持的消息类型为文本、图片、语音、视频、文件、图文。。
-
- EXTERNALCONTACT_MESSAGE_SEND
- /cgi-bin/externalcontact/message/send?access_token=ACCESS_TOKEN
- POST
- 61009
-
-
-
-
- 8
- 素材管理 > 上传临时素材
-
- 素材上传得到media_id,该media_id仅三天内有效
- media_id在同一企业内应用之间可以共享
-
- MEDIA_UPLOAD
- /cgi-bin/media/upload?access_token=ACCESS_TOKEN
- POST
- 71001
-
-
- 8
- 素材管理 > 上传图片
-
- 上传图片得到图片URL,该URL永久有效
- 返回的图片URL,仅能用于图文消息正文中的图片展示,或者给客户发送欢迎语等;若用于非企业微信环境下的页面,图片将被屏蔽。
- 每个企业每月最多可上传3000张图片,每天最多可上传1000张图片
-
- MEDIA_UPLOADIMG
- /cgi-bin/media/uploadimg?access_token=ACCESS_TOKEN
- POST
- 71002
-
-
- 8
- 素材管理 > 获取临时素材
-
-
-
- MEDIA_GET
- /cgi-bin/media/get?access_token=ACCESS_TOKEN
- POST
- 71003
-
-
- 8
- 素材管理 > 获取高清语音素材
-
- 可以使用本接口获取从JSSDK的uploadVoice接口上传的临时语音素材,格式为speex,16K采样率。该音频比上文的临时素材获取接口(格式为amr,8K采样率)更加清晰,适合用作语音识别等对音质要求较高的业务。
-
- MEDIA_GET_JSSDK
- /cgi-bin/media/get/jssdk?access_token=ACCESS_TOKEN
- GET
- 71004
-
-
-
-
-
- 9
- OA > 打卡 > 获取企业所有打卡规则
-
- 企业可通过打卡应用Secret调用本接口,获取企业内所有打卡规则数据。
-
- GET_CORP_CHECKIN_OPTION
- /cgi-bin/checkin/getcorpcheckinoption?access_token=ACCESS_TOKEN
- POST
- 81001
-
-
- 9
- OA > 打卡 > 获取员工打卡规则
-
- 企业可通过打卡应用Secret获取的token,获取指定员工指定日期的打卡规则
- 第三方应用可获取应用可见范围内指定员工指定日期的打卡规则
-
- GET_CHECKIN_OPTION
- /cgi-bin/checkin/getcheckinoption?access_token=ACCESS_TOKEN
- POST
- 81002
-
-
- 9
- OA > 打卡 > 获取打卡记录数据
-
- 企业可通过打卡应用Secret调用本接口,获取指定员工指定时间段内的打卡记录数据。
- 第三方应用可获取应用可见范围内指定员工指定日期的打卡记录数据。
-
- GET_CHECKIN_DATA
- /cgi-bin/checkin/getcheckindata?access_token=ACCESS_TOKEN
- POST
- 81003
-
-
- 9
- OA > 打卡 > 获取打卡日报数据
-
- 企业可通过打卡应用Secret调用本接口,获取指定员工指定时间段内的打卡日报统计数据。
- 第三方应用可获取应用可见范围内指定员工指定日期内的打卡日报统计数据。
-
- GET_CHECKIN_DAY_DATA
- /cgi-bin/checkin/getcheckin_daydata?access_token=ACCESS_TOKEN
- POST
- 81004
-
-
- 9
- OA > 打卡 > 获取打卡月报数据
-
- 企业可通过打卡应用Secret调用本接口,获取指定员工指定时间段内的打卡月报统计数据
- 第三方应用可获取应用可见范围内指定员工指定日期内的打卡月报统计数据。
-
- GET_CHECKIN_MONTH_DATA
- /cgi-bin/checkin/getcheckin_monthdata?access_token=ACCESS_TOKEN
- POST
- 81005
-
-
-
- 9
- OA > 打卡 > 获取打卡人员排班信息
-
- 企业可通过打卡应用Secret调用本接口,获取打卡规则为“按班次上下班”规则的指定员工指定时间段内的排班信息。
- 第三方应用获取应用可见范围内、打卡规则为“按班次上下班”规则的指定员工指定时间段内的排班信息。
-
- GET_CHECKIN_SCHEDU_LIST
- /cgi-bin/checkin/getcheckinschedulist?access_token=ACCESS_TOKEN
- POST
- 81006
-
-
-
- 9
- OA > 打卡 > 为打卡人员排班
-
- 企业可通过打卡应用Secret调用本接口,为打卡规则为“按班次上下班”规则的指定员工排班。
- 第三方应用可通过本接口为应用可见范围内、打卡规则为“按班次上下班”规则的指定员工排班。
-
- SET_CHECKIN_SCHEDU_LIST
- /cgi-bin/checkin/setcheckinschedulist?access_token=ACCESS_TOKEN
- POST
- 81007
-
-
-
- 9
- OA > 打卡 > 录入打卡人员人脸信息
-
- 企业可通过打卡应用Secret调用本接口,为企业打卡人员录入人脸信息,人脸信息仅用于人脸打卡
-
- ADD_CHECKIN_USER_FACE
- /cgi-bin/checkin/addcheckinuserface?access_token=ACCESS_TOKEN
- POST
- 81008
-
-
-
- 9
- OA > 打卡 > 获取设备打卡数据
-
- 可通过此接口,获取考勤设备上产生的所有原始打卡记录,包括未被打卡应用记录的不符合打卡规则的记录。
- 第三方应用可获取应用可见范围内员工在考勤设备上产生的所有原始打卡记录,包括未被打卡应用记录的不符合打卡规则的记录。
-
- GET_HARDWARE_CHECKIN_DATA
- /cgi-bin/hardware/get_hardware_checkin_data?access_token=ACCESS_TOKEN
- POST
- 7008
-
-
-
-
- 9
- OA > 审批 > 获取审批模板详情
-
- 企业可通过审批应用或自建应用Secret调用本接口,获取企业微信“审批应用”内指定审批模板的详情。
-
- APPROVAL_GET_TEMPLATE_DETAIL
- /cgi-bin/oa/gettemplatedetail?access_token=ACCESS_TOKEN
- POST
- 82001
-
-
- 9
- OA > 审批 > 提交审批申请
-
- 企业可通过审批应用或自建应用Secret调用本接口,代应用可见范围内员工在企业微信“审批应用”内提交指定类型的审批申请。
-
- APPROVAL_SUBMIT
- /cgi-bin/oa/applyevent?access_token=ACCESS_TOKEN
- POST
- 82002
-
-
-
- 9
- OA > 审批 > 批量获取审批单号
-
- 审批应用及有权限的自建应用,可通过Secret调用本接口,以获取企业一段时间内企业微信“审批应用”单据的审批编号,支持按模板类型、申请人、部门、申请单审批状态等条件筛选。
- 自建应用调用此接口,需在“管理后台-应用管理-审批-API-审批数据权限”中,授权应用允许提交审批单据。
-
- 一次拉取调用最多拉取100个审批记录,可以通过多次拉取的方式来满足需求,但调用频率不可超过600次/分。
- 推荐使用此接口获取审批数据,旧接口后续将不再维护。
-
- GET_APPROVAL_INFO
- /cgi-bin/oa/getapprovalinfo?access_token=ACCESS_TOKEN
- POST
- 82003
-
-
- 9
- OA > 审批 > 获取审批申请详情
-
- 企业可通过审批应用或自建应用Secret调用本接口,根据审批单号查询企业微信“审批应用”的审批申请详情。
-
- GET_APPROVAL_DETAIL
- /cgi-bin/oa/getapprovaldetail?access_token=ACCESS_TOKEN
- POST
- 82004
-
-
-
-
- 9
- OA > 审批 > 获取企业假期管理配置
-
- 企业可通过审批应用或自建应用Secret调用本接口,获取可见范围内员工的“假期管理”配置,包括:各个假期的id、名称、请假单位、时长计算方式、发放规则等。
- 第三方应用可获取应用可见范围内员工的“假期管理”配置,包括:各个假期的id、名称、请假单位、时长计算方式、发放规则等。
-
- GET_CORP_VACATIONL_CONF
- /cgi-bin/oa/vacation/getcorpconf?access_token=ACCESS_TOKEN
- POST
- 82005
-
-
- 9
- OA > 审批 > 获取成员假期余额
-
- 企业可通过审批应用或自建应用Secret调用本接口,获取可见范围内各个员工的假期余额数据。
- 第三方应用可获取应用可见范围内各个员工的假期余额数据。
-
- GET_USER_VACATION_QUOTA
- /cgi-bin/oa/vacation/getuservacationquota?access_token=ACCESS_TOKEN
- POST
- 82006
-
-
- 9
- OA > 审批 > 修改成员假期余额
-
- 企业可通过审批应用或自建应用Secret调用本接口,修改可见范围内员工的“假期余额”。
- 第三方应用可通过应本接口修改应用可见范围内指定员工的“假期余额”。
-
- SET_USER_VACATION_QUOTA
- /cgi-bin/oa/vacation/setoneuserquota?access_token=ACCESS_TOKEN
- POST
- 82007
-
-
-
-
- 9
- OA > 汇报 > 批量获取汇报记录单号
-
- 企业可通过access_token调用本接口,以获取企业一段时间内企业微信“汇报应用”汇报记录编号,支持按汇报表单ID、申请人、部门等条件筛选。
-
- 一次拉取调用最多拉取100个汇报记录,可以通过多次拉取的方式来满足需求,但调用频率不可超过600次/分。
- 表单ID的获取方式:
- 管理后台--汇报应用--某个汇报的内容设置页--点击“汇报名称”,即可获取
-
-
-
-
- GET_JOURNAL_RECORD_LIST
- /cgi-bin/oa/journal/get_record_list?access_token=ACCESS_TOKEN
- POST
- 83001
-
-
- 9
- OA > 审批 > 获取汇报记录详情
-
- 企业可通过access_token调用本接口,根据汇报记录单号查询企业微信“汇报应用”的汇报详情。
-
- JOURNAL_GET_RECORD_DETAIL
- /cgi-bin/oa/journal/get_record_detail?access_token=ACCESS_TOKEN
- POST
- 83002
-
-
- 9
- OA > 审批 > 获取汇报统计数据
-
- 企业可通过access_token调用本接口,根据汇报表单id查询企业微信“汇报应用”的汇报统计汇总信息。该接口只能拉取到已经汇总的统计数据,对于尚未完成汇总的周期不会返回。
-
- JOURNAL_GET_STAT_LIST
- /cgi-bin/oa/journal/get_stat_list?access_token=ACCESS_TOKEN
- POST
- 83003
-
-
-
-
- 9
- OA > 自建应用 > 审批流程引擎 > 查询自建应用审批单当前状态
-
- 开发者也可主动查询审批单的当前审批状态。
-
- CORP_GET_OPEN_APPROVAL_DATA
- /cgi-bin/corp/getopenapprovaldata?access_token=ACCESS_TOKEN
- POST
- 84001
-
-
-
-
- 9
- OA > 会议室 > 会议室管理 > 添加会议室
-
- 企业可通过此接口添加一个会议室。
-
- MEETINGROOM_ADD
- /cgi-bin/oa/meetingroom/add?access_token=ACCESS_TOKEN
- POST
- 85001
-
-
- 9
- OA > 会议室 > 会议室管理 > 查询会议室
-
- 企业可通过此接口查询满足条件的会议室。
-
- MEETINGROOM_LIST
- /cgi-bin/oa/meetingroom/list?access_token=ACCESS_TOKEN
- POST
- 85002
-
-
- 9
- OA > 会议室 > 会议室管理 > 编辑会议室
-
- 企业可通过此接口编辑相关会议室的基本信息。
-
- MEETINGROOM_EDIT
- /cgi-bin/oa/meetingroom/edit?access_token=ACCESS_TOKEN
- POST
- 85003
-
-
- 9
- OA > 会议室 > 会议室管理 > 删除会议室
-
- 企业可通过此接口删除指定的会议室。
-
- MEETINGROOM_DEL
- /cgi-bin/oa/meetingroom/del?access_token=ACCESS_TOKEN
- POST
- 85004
-
-
-
- 9
- OA > 会议室 > 会议室预定管理 > 查询会议室的预定信息
-
- 企业可通过此接口查询相关会议室在指定时间段的预定情况,如是否已被预定,预定者的userid等信息,不支持跨天查询。
-
-
- MEETINGROOM_GET_BOOKING_INFO
- /cgi-bin/oa/meetingroom/get_booking_info?access_token=ACCESS_TOKEN
- POST
- 85005
-
-
- 9
- OA > 会议室 > 会议室预定管理 > 预定会议室
-
- 企业可通过此接口预定会议室并自动关联日程。
-
- MEETINGROOM_BOOK
- /cgi-bin/oa/meetingroom/book?access_token=ACCESS_TOKEN
- POST
- 85006
-
-
- 9
- OA > 会议室 > 会议室预定管理 > 企业可通过此接口取消会议室的预定
-
-
-
- MEETINGROOM_CANCEL_BOOK
- /cgi-bin/oa/meetingroom/cancel_book?access_token=ACCESS_TOKEN
- POST
- 85007
-
-
- 9
- OA > 会议室 > 会议室预定管理 > 根据会议ID查询会议室的预定信息
-
- 企业可通过此接口按照会议ID查询相关会议室的预定情况
-
- MEETINGROOM_GET_BOOKING_INFO_BY_MEETING_ID
- /cgi-bin/oa/meetingroom/get_booking_info_by_meeting_id?access_token=ACCESS_TOKEN
- POST
- 85008
-
-
-
-
- 9
- OA > 紧急通知应用 > 发起语音电话
-
- 通过此接口发起语音电话,提醒员工查看应用推送的重要消息。
-
- PSTNCC_CALL
- /cgi-bin/pstncc/call?access_token=ACCESS_TOKEN
- POST
- 86001
-
-
- 9
- OA > 紧急通知应用 > 获取接听状态
-
- 通过此接口,了解员工是否已接听语音电话。
-
- GET_PSTNCC_STATES
- /cgi-bin/pstncc/getstates?access_token=ACCESS_TOKEN
- POST
- 86002
-
-
-
-
-
-
-
-
- 10
- 效率工具 > 微盘 > 空间管理 > 新建空间
-
- 该接口用于在微盘内新建空间,可以指定人创建空间。
-
- WEDRIVE_SPACE_CREATE
- /cgi-bin/wedrive/space_create?access_token=ACCESS_TOKEN
- POST
- 94001
-
-
- 10
- 效率工具 > 微盘 > 空间管理 > 重命名空间
-
- 该接口用于重命名已有空间,接收userid参数,以空间管理员身份来重命名。
-
- WEDRIVE_SPACE_RENAME
- /cgi-bin/wedrive/space_rename?access_token=ACCESS_TOKEN
- POST
- 94002
-
-
- 10
- 效率工具 > 微盘 > 空间管理 > 解散空间
-
- 该接口用于解散已有空间,需要以空间管理员身份来解散。
-
- WEDRIVE_SPACE_DISMISS
- /cgi-bin/wedrive/space_dismiss?access_token=ACCESS_TOKEN
- POST
- 94003
-
-
- 10
- 效率工具 > 微盘 > 空间管理 > 获取空间信息
-
- 该接口用于获取空间成员列表、信息、权限等信息。
-
- WEDRIVE_SPACE_INFO
- /cgi-bin/wedrive/space_info?access_token=ACCESS_TOKEN
- POST
- 94004
-
-
-
- 10
- 效率工具 > 微盘 > 空间权限 > 添加成员/部门
-
- 该接口用于对指定空间添加成员/部门,可一次性添加多个。
-
- WEDRIVE_SPACE_ACL_ADD
- /cgi-bin/wedrive/space_acl_add?access_token=ACCESS_TOKEN
- POST
- 94005
-
-
- 10
- 效率工具 > 微盘 > 空间权限 > 移除成员/部门
-
- 该接口用于对指定空间移除成员/部门,操作者需要有移除权限。
-
- WEDRIVE_SPACE_ACL_DEL
- /cgi-bin/wedrive/space_acl_del?access_token=ACCESS_TOKEN
- POST
- 94006
-
-
- 10
- 效率工具 > 微盘 > 空间权限 > 权限管理
-
- 该接口用于修改空间权限,需要传入userid,修改权限范围继承传入用户的权限范围。
-
- WEDRIVE_SPACE_SETTING
- /cgi-bin/wedrive/space_setting?access_token=ACCESS_TOKEN
- POST
- 94007
-
-
- 10
- 效率工具 > 微盘 > 空间权限 > 获取邀请链接
-
- 该接口用于获取空间邀请分享链接。
-
- WEDRIVE_SPACE_SHARE
- /cgi-bin/wedrive/space_share?access_token=ACCESS_TOKEN
- POST
- 94008
-
-
-
- 10
- 效率工具 > 微盘 > 文件管理 > 获取文件列表
-
- 该接口用于获取指定地址下的文件列表。
-
- WEDRIVE_FILE_LIST
- /cgi-bin/wedrive/file_list?access_token=ACCESS_TOKEN
- POST
- 94010
-
-
- 10
- 效率工具 > 微盘 > 文件管理 > 上传文件
-
- 该接口用于向微盘中的指定位置上传文件。
-
- WEDRIVE_FILE_UPLOAD
- /cgi-bin/wedrive/file_upload?access_token=ACCESS_TOKEN
- POST
- 94011
-
-
- 10
- 效率工具 > 微盘 > 文件管理 > 下载文件
-
- 该接口用于下载文件,请求的userid需有下载权限
-
- WEDRIVE_FILE_DOWNLOADD
- /cgi-bin/wedrive/file_download?access_token=ACCESS_TOKEN
- POST
- 94012
-
-
- 10
- 效率工具 > 微盘 > 文件管理 > 新建文件/微文档
-
- 该接口用于在微盘指定位置新建文件、微文档。
-
- WEDRIVE_FILE_CREATE
- /cgi-bin/wedrive/file_create?access_token=ACCESS_TOKEN
- POST
- 94013
-
-
- 10
- 效率工具 > 微盘 > 文件管理 > 重命名文件
-
- 该接口用于对指定文件进行重命名。
-
- WEDRIVE_FILE_RENAME
- /cgi-bin/wedrive/file_rename?access_token=ACCESS_TOKEN
- POST
- 94014
-
-
- 10
- 效率工具 > 微盘 > 文件管理 > 移动文件
-
- 该接口用于将文件移动到指定位置。
-
- WEDRIVE_FILE_MOVE
- /cgi-bin/wedrive/file_move?access_token=ACCESS_TOKEN
- POST
- 94015
-
-
- 10
- 效率工具 > 微盘 > 文件管理 > 删除文件
-
- 该接口用于删除指定文件。
-
- WEDRIVE_FILE_DELETE
- /cgi-bin/wedrive/file_delete?access_token=ACCESS_TOKEN
- POST
- 94016
-
-
- 10
- 效率工具 > 微盘 > 文件管理 > 文件信息
-
- 该接口用于获取指定文件的信息。
-
- WEDRIVE_FILE_INFO
- /cgi-bin/wedrive/file_info?access_token=ACCESS_TOKEN
- POST
- 94017
-
-
-
- 10
- 效率工具 > 微盘 > 文件权限 > 新增指定人
-
- 该接口用于对指定文件添加指定人/部门。
-
- WEDRIVE_FILE_ACL_ADD
- /cgi-bin/wedrive/file_acl_add?access_token=ACCESS_TOKEN
- POST
- 94021
-
-
- 10
- 效率工具 > 微盘 > 文件权限 > 删除指定人
-
- 该接口用于删除指定文件的指定人/部门。
-
- WEDRIVE_FILE_ACL_DEL
- /cgi-bin/wedrive/file_acl_del?access_token=ACCESS_TOKEN
- POST
- 94022
-
-
- 10
- 效率工具 > 微盘 > 文件权限 > 分享设置
-
- 该接口用于文件的分享设置。
-
- WEDRIVE_FILE_SETTING
- /cgi-bin/wedrive/file_setting?access_token=ACCESS_TOKEN
- POST
- 94023
-
-
- 10
- 效率工具 > 微盘 > 文件权限 > 获取分享链接
-
- 该接口用于获取文件的分享链接
-
- WEDRIVE_FILE_SHARE
- /cgi-bin/wedrive/file_share?access_token=ACCESS_TOKEN
- POST
- 94024
-
-
-
-
- 10
- 效率工具 > 公费电话 > 获取公费电话拨打记录
-
- 企业可通过此接口,按时间范围拉取成功接通的公费电话拨打记录。
-
- GET_DIAL_RECORD
- /cgi-bin/dial/get_dial_record?access_token=ACCESS_TOKEN
- POST
- 95001
-
-
-
-
-
-
-
-
- 11
- 企业支付 > 对外收款 > 收款商户号管理 > 新增商户号
-
- 使用该接口时需要开通对外收款能力并绑定第一个商户号。(说明:第一个商户号的绑定需要由企业管理员手动绑定,绑定入口在:手机端工作台-对外收款,或管理后台-应用管理-对外收款-启用)
- 通过该接口可以导入其他商户号,同一个企业最多绑定5000个商户号。
-
- ADDMERCHANT
- /cgi-bin/externalpay/addmerchant?access_token=ACCESS_TOKEN
- POST
- 114001
-
-
-
- 11
- 企业支付 > 对外收款 > 收款商户号管理 > 查询商户号详情
-
- 通过该接口可以查询已绑定商户号信息以及商户号使用范围
-
- GETMERCHANT
- /cgi-bin/externalpay/getmerchant?access_token=ACCESS_TOKEN
- POST
- 114002
-
-
-
- 11
- 企业支付 > 对外收款 > 收款商户号管理 > 删除商户号
-
- 通过该接口可以删除未绑定的商户号
-
- DELMERCHANT
- /cgi-bin/externalpay/delmerchant?access_token=ACCESS_TOKEN
- POST
- 114003
-
-
-
- 11
- 企业支付 > 对外收款 > 收款商户号管理 > 设置商户号使用范围
-
- 通过该接口可以设置已绑定商户号的使用范围
-
- SET_MCH_USE_SCOPE
- /cgi-bin/externalpay/set_mch_use_scope?access_token=ACCESS_TOKEN
- POST
- 114004
-
-
-
- 11
- 企业支付 > 对外收款 > 获取对外收款记录
-
- 企业和服务商可通过此接口获取企业的对外收款记录。
-
- GET_BILL_LIST
- /cgi-bin/externalpay/get_bill_list?access_token=ACCESS_TOKEN
- POST
- 114004
-
-
-
-
- 12
- 企业互联 > 获取应用共享信息
-
- 上级/上游企业通过该接口可以获取某个应用分享给的所有企业列表。
- 对于有敏感权限的应用,需要下级/下游企业确认后才能共享成功,若下级/下游企业未确认,则不会存在于该接口的返回列表
-
- CORP_LIST_APP_SHARE_INFO
- /cgi-bin/corpgroup/corp/list_app_share_info?access_token=ACCESS_TOKEN
- POST
- 120001
-
-
-
- 12
- 企业互联 > 获取下级/下游企业的access_token
-
- 获取应用可见范围内下级/下游企业的access_token,该access_token可用于调用下级/下游企业通讯录的只读接口。
-
- CORP_GETTOKEN
- /cgi-bin/corpgroup/corp/gettoken?access_token=ACCESS_TOKEN
- POST
- 120002
-
-
-
- 12
- 企业互联 > 获取下级/下游企业小程序session
-
- 上级/上游企业通过该接口转换为下级/下游企业的小程序session
-
- CORP_MINIPROGRAM_TRANSFER_SESSION
- /cgi-bin/miniprogram/transfer_session?access_token=ACCESS_TOKEN
- POST
- 120003
-
-
-
-
-
-
- 14
- 会话内容存档 > 获取会话同意情况 > 单聊请求
-
- 企业可通过下述接口,获取会话中外部成员的同意情况
-
- MSGAUDIT_CHECK_SINGLE_AGREE
- /cgi-bin/msgaudit/check_single_agree?access_token=ACCESS_TOKEN
- POST
- 140001
-
-
-
- 14
- 会话内容存档 > 获取会话同意情况 > 群聊请求
-
- 企业可通过下述接口,获取会话中外部成员的同意情况
-
- MSGAUDIT_CHECK_ROOM_AGREE
- /cgi-bin/msgaudit/check_room_agree?access_token=ACCESS_TOKEN
- POST
- 140001
-
-
-
- 14
- 会话内容存档 > 获取会话内容存档内部群信息
-
- 企业可通过此接口,获取会话内容存档本企业的内部群信息,包括群名称、群主id、公告、群创建时间以及所有群成员的id与加入时间
-
- MSGAUDIT_GROUPCHAT_GET
- /cgi-bin/msgaudit/groupchat/get?access_token=ACCESS_TOKEN
- POST
- 140003
-
-
-
-
-
-
-
-
diff --git a/wecom_api/data/wecom_server_api_error_data.xml b/wecom_api/data/wecom_server_api_error_data.xml
deleted file mode 100644
index 2518a0fcc..000000000
--- a/wecom_api/data/wecom_server_api_error_data.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
- Python Code Error
- -2
- Python Code Error,Please check your code for errors. Python代码错误,请检查您的代码是否有错误
- 0
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_api/i18n/zh_CN.po b/wecom_api/i18n/zh_CN.po
deleted file mode 100644
index f6c7f884e..000000000
--- a/wecom_api/i18n/zh_CN.po
+++ /dev/null
@@ -1,371 +0,0 @@
-# Translation of Odoo Server.
-# This file contains the translation of the following modules:
-# * wecom_api
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: Odoo Server 16.0beta\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2022-10-04 07:34+0000\n"
-"PO-Revision-Date: 2022-10-04 15:35+0800\n"
-"Last-Translator: \n"
-"Language-Team: \n"
-"Language: zh_CN\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: \n"
-"X-Generator: Poedit 3.1.1\n"
-
-#. module: wecom_api
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_abstract_api__code
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api__code
-msgid "API error code"
-msgstr "API错误代码"
-
-#. module: wecom_api
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_abstract_api__message
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api__message
-msgid "API error message"
-msgstr "API错误消息"
-
-#. module: wecom_api
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api__access_token
-msgid "Access Token"
-msgstr "访问令牌"
-
-#. module: wecom_api
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api_list__request_type
-msgid "Api Request Type"
-msgstr "Api请求类型"
-
-#. module: wecom_api
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api_list__type
-msgid "Api Type"
-msgstr "Api类型"
-
-#. module: wecom_api
-#: code:addons/wecom_api/controllers/main.py:0
-#, python-format
-msgid "App [%s] does not have service [%s] enabled"
-msgstr "应用 [%s] 未启用服务 [%s]"
-
-#. module: wecom_api
-#: model:ir.model.fields.selection,name:wecom_api.selection__wecom_service_api_list__type__6
-msgid "Application management"
-msgstr "应用管理"
-
-#. module: wecom_api
-#: model:ir.model.fields.selection,name:wecom_api.selection__wecom_service_api_list__type__1
-msgid "Base"
-msgstr "基础"
-
-#. module: wecom_api
-#: model:ir.model.fields.selection,name:wecom_api.selection__wecom_service_api_list__type__2
-msgid "Contacts"
-msgstr "通讯录管理"
-
-#. module: wecom_api
-#: model:ir.model.fields.selection,name:wecom_api.selection__wecom_service_api_list__type__13
-msgid "Corp Chain"
-msgstr "上下游(公司链)"
-
-#. module: wecom_api
-#: model:ir.model.fields.selection,name:wecom_api.selection__wecom_service_api_list__type__12
-msgid "Corp Group"
-msgstr "企业互联"
-
-#. module: wecom_api
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api__corpid
-msgid "Corp Id"
-msgstr "企业ID"
-
-#. module: wecom_api
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api__create_uid
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api_error__create_uid
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api_list__create_uid
-msgid "Created by"
-msgstr "创建者"
-
-#. module: wecom_api
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api__create_date
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api_error__create_date
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api_list__create_date
-msgid "Created on"
-msgstr "创建于"
-
-#. module: wecom_api
-#: model:ir.model.fields.selection,name:wecom_api.selection__wecom_service_api_list__type__3
-msgid "Customer contact"
-msgstr "客户联系"
-
-#. module: wecom_api
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api_list__description
-msgid "Description"
-msgstr "说明"
-
-#. module: wecom_api
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api__display_name
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api_error__display_name
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api_list__display_name
-msgid "Display Name"
-msgstr "显示名称"
-
-#. module: wecom_api
-#: model:ir.model.fields.selection,name:wecom_api.selection__wecom_service_api_list__type__10
-msgid "Efficiency tools"
-msgstr "效率工具"
-
-#. module: wecom_api
-#: model:ir.model.fields.selection,name:wecom_api.selection__wecom_service_api_list__type__15
-msgid "Electronic invoice"
-msgstr "电子发票"
-
-#. module: wecom_api
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api_error__code
-msgid "Error code"
-msgstr "错误代码"
-
-#. module: wecom_api
-#: code:addons/wecom_api/tools/action.py:0
-#, python-format
-msgid ""
-"Error code: %s,Error description: %s,Error troubleshooting method: %s,Error "
-"Details:%s"
-msgstr "错误代码:%s,错误描述:%s,故障排除方法:%s,出错详细信息:%s"
-
-#. module: wecom_api
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api_error__name
-msgid "Error description"
-msgstr "错误说明"
-
-#. module: wecom_api
-#: code:addons/wecom_api/api/wecom_message_api.py:0
-#, python-format
-msgid "Error sending message: %s"
-msgstr "发送消息时出错:%s"
-
-#. module: wecom_api
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api__token_expiration_time
-msgid "Token Expiration Time"
-msgstr "Token过期时间"
-
-#. module: wecom_api
-#: code:addons/wecom_api/tools/action.py:0
-#, python-format
-msgid "Failed"
-msgstr "失败"
-
-#. module: wecom_api
-#: code:addons/wecom_api/models/wecom_server_api_error.py:0
-#, python-format
-msgid "Failed to pull WeCom global error code, reason:%s"
-msgstr "无法拉取企微全局错误代码,原因:%s"
-
-#. module: wecom_api
-#: model:ir.model.fields.selection,name:wecom_api.selection__wecom_service_api_list__request_type__get
-msgid "GET"
-msgstr ""
-
-#. module: wecom_api
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api__id
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api_error__id
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api_list__id
-msgid "ID"
-msgstr ""
-
-#. module: wecom_api
-#: model:ir.model.fields.selection,name:wecom_api.selection__wecom_service_api_list__type__5
-msgid "Identity authentication"
-msgstr "身份验证"
-
-#. module: wecom_api
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api____last_update
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api_error____last_update
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api_list____last_update
-msgid "Last Modified on"
-msgstr "最后修改"
-
-#. module: wecom_api
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api__write_uid
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api_error__write_uid
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api_list__write_uid
-msgid "Last Updated by"
-msgstr "最后更新者"
-
-#. module: wecom_api
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api__write_date
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api_error__write_date
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api_list__write_date
-msgid "Last Updated on"
-msgstr "最后更新于"
-
-#. module: wecom_api
-#: model:ir.model.fields.selection,name:wecom_api.selection__wecom_service_api_list__type__8
-msgid "Media material"
-msgstr "素材管理"
-
-#. module: wecom_api
-#: model:ir.model.fields.selection,name:wecom_api.selection__wecom_service_api_list__type__7
-msgid "Message push"
-msgstr "消息推送"
-
-#. module: wecom_api
-#: model:ir.model.fields.selection,name:wecom_api.selection__wecom_service_api_list__type__9
-msgid "OA"
-msgstr ""
-
-#. module: wecom_api
-#: model:ir.model.fields.selection,name:wecom_api.selection__wecom_service_api_list__request_type__post
-msgid "POST"
-msgstr ""
-
-#. module: wecom_api
-#: model:ir.model.fields.selection,name:wecom_api.selection__wecom_service_api_list__type__18
-msgid "Report"
-msgstr "政民沟通"
-
-#. module: wecom_api
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api_list__function_name
-msgid "Request Function Name"
-msgstr "请求函数名称"
-
-#. module: wecom_api
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api_list__name
-msgid "Request Name"
-msgstr "请求名称"
-
-#. module: wecom_api
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api_list__short_url
-msgid "Request Short Url"
-msgstr "请求短Url"
-
-#. module: wecom_api
-#: model:ir.model.fields.selection,name:wecom_api.selection__wecom_service_api_list__type__16
-msgid "School"
-msgstr "家校沟通"
-
-#. module: wecom_api
-#: model:ir.model.fields.selection,name:wecom_api.selection__wecom_service_api_list__type__17
-msgid "School Apps"
-msgstr "家校应用"
-
-#. module: wecom_api
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api__secret
-msgid "Secret"
-msgstr "密钥"
-
-#. module: wecom_api
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api_error__sequence
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api_list__sequence
-msgid "Sequence"
-msgstr "序列"
-
-#. module: wecom_api
-#: model:ir.model.fields.selection,name:wecom_api.selection__wecom_service_api_list__type__14
-msgid "Session content archiving"
-msgstr "会话内容存档"
-
-#. module: wecom_api
-#: code:addons/wecom_api/models/wecom_server_api_error.py:0
-#, python-format
-msgid "Start pulling the global error code of WeCom."
-msgstr "开始拉取企微全局错误代码。"
-
-#. module: wecom_api
-#: code:addons/wecom_api/models/wecom_server_api_error.py:0
-#, python-format
-msgid "Successfully pulled the WeCom global error code!"
-msgstr "已成功拉取企微全局错误代码!"
-
-#. module: wecom_api
-#: model:ir.model.constraint,message:wecom_api.constraint_wecom_service_api_list_function_name_uniq
-msgid "The function is unique !"
-msgstr "功能是唯一的!"
-
-#. module: wecom_api
-#: model:ir.model.fields,field_description:wecom_api.field_wecom_service_api_error__method
-msgid "Treatment method"
-msgstr "排查方法"
-
-#. module: wecom_api
-#: model:ir.model,name:wecom_api.model_wecom_message_api
-msgid "WeCom Message API"
-msgstr "企微消息API"
-
-#. module: wecom_api
-#: model:ir.model.fields.selection,name:wecom_api.selection__wecom_service_api_list__type__4
-msgid "Wechat customer service"
-msgstr "微信客服"
-
-#. module: wecom_api
-#: model:ir.model,name:wecom_api.model_wecomapi_tools_action
-msgid "Wecom API Tools - Action"
-msgstr "企微API工具-动作"
-
-#. module: wecom_api
-#: model:ir.model,name:wecom_api.model_wecomapi_tools_data
-msgid "Wecom API Tools - Data"
-msgstr "企微API工具-数据"
-
-#. module: wecom_api
-#: model:ir.model,name:wecom_api.model_wecomapi_tools_datetime
-msgid "Wecom API Tools - Datetime"
-msgstr "企微API工具-日期时间"
-
-#. module: wecom_api
-#: model:ir.model,name:wecom_api.model_wecomapi_tools_file
-msgid "Wecom API Tools - File"
-msgstr "企微API工具-文件"
-
-#. module: wecom_api
-#: model:ir.model,name:wecom_api.model_wecomapi_tools_message
-msgid "Wecom API Tools - Message"
-msgstr "企微API工具-消息"
-
-#. module: wecom_api
-#: model:ir.model,name:wecom_api.model_wecomapi_tools_security
-msgid "Wecom API Tools - Security"
-msgstr "企微API工具-安全"
-
-#. module: wecom_api
-#: code:addons/wecom_api/tools/action.py:0
-#, python-format
-msgid "Wecom API error: %s, error name: %s, error message: %s"
-msgstr "企微API错误: %s, 错误名称: %s, 错误消息: %s"
-
-#. module: wecom_api
-#: model:ir.model,name:wecom_api.model_wecom_abstract_api
-msgid "Wecom Abstract API"
-msgstr "企微抽象API"
-
-#. module: wecom_api
-#: model:ir.model,name:wecom_api.model_wecom_service_api
-msgid "Wecom Server API"
-msgstr "企微服务端API"
-
-#. module: wecom_api
-#: model:ir.model,name:wecom_api.model_wecom_service_api_error
-msgid "Wecom Server API Error"
-msgstr "企微服务端API错误"
-
-#. module: wecom_api
-#: model:ir.model,name:wecom_api.model_wecom_service_api_list
-msgid "Wecom Server API List"
-msgstr "企微服务端API列表"
-
-#. module: wecom_api
-#: model:ir.model,name:wecom_api.model_wecom_tools
-msgid "Wecom Tools"
-msgstr "企微工具"
-
-#. module: wecom_api
-#: model:ir.model.fields.selection,name:wecom_api.selection__wecom_service_api_list__type__11
-msgid "externalpay"
-msgstr "企业支付"
-
-#. module: wecom_api
-#: code:addons/wecom_api/api/wecom_abstract_api.py:0
-#, python-format
-msgid "unknown method type"
-msgstr "未知方法类型"
diff --git a/wecom_api/models/__init__.py b/wecom_api/models/__init__.py
deleted file mode 100644
index 9b15437af..000000000
--- a/wecom_api/models/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# -*- coding: utf-8 -*-
-
-
-from . import wecom_server_api_error
-from . import wecom_server_api_list
diff --git a/wecom_api/models/res_config_settings.py b/wecom_api/models/res_config_settings.py
deleted file mode 100644
index cd04487e4..000000000
--- a/wecom_api/models/res_config_settings.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from odoo import api, fields, models, tools, _
-
-class ResConfigSettings(models.TransientModel):
- _inherit = "res.config.settings"
-
-
\ No newline at end of file
diff --git a/wecom_api/models/temp.py b/wecom_api/models/temp.py
deleted file mode 100644
index 171e28aa2..000000000
--- a/wecom_api/models/temp.py
+++ /dev/null
@@ -1,64 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import requests
-import pandas as pd
-pd.set_option('display.max_columns', 10)
-pd.set_option("max_colwidth", 200)
-pd.set_option("display.width", 200)
-pd.set_option('display.max_rows', 200)
-from lxml import etree
-
-
-url = "https://developer.work.weixin.qq.com/document/path/90313"
-anchor = "//h2[@data-sign='12309549435022fd54b0549f5968b4c2']"
-codes = "//h5"
-methods ="//p[@data-type='p']"
-
-page_text = requests.get(url=url).text
-tree = etree.HTML(page_text) # type: ignore
-
-anchor_elemen = tree.xpath(anchor)
-codes_elements = tree.xpath(codes)
-methods_elements = tree.xpath(methods)
-
-methods = []
-for code_element in codes_elements:
- code_element_str = code_element.xpath("text()")[0]
- error_code = code_element_str.split(":", 1)[1:][0]
- method_element = code_element.getnext()
- method = etree.tostring(method_element, encoding="utf-8", pretty_print=True ).decode() # type: ignore
-
- if " " in error_code:
- # 一个元素存在多个错误码
- multiple_codes = error_code.split(" ", 1)
- for multiple_code in multiple_codes:
- multiple_dic = {}
- multiple_dic["code"] = multiple_code
- multiple_dic["method"] = method
- methods.append(multiple_dic)
- else:
- dic = {}
- dic["code"] = error_code
- dic["method"] = method
- methods.append(dic)
-
-table = tree.xpath("//div[@class='cherry-table-container']/table") # 取出表格
-table = etree.tostring(
- table[0], encoding="utf-8" # type: ignore
-).decode() # 将第一个表格转成string格式
-table = table.replace("错误码 ", "code ")
-table = table.replace("错误说明 ", "name ")
-table = table.replace("排查方法 ", "method ")
-
-df = pd.read_html(table, encoding="utf-8", header=0)[0] # pandas读取table
-if 'Unnamed: 3' in df.columns:
- del df['Unnamed: 3']
-error_results = list(df.T.to_dict().values()) # 转换成列表嵌套字典的格式
-
-errors = []
-for index, error in enumerate(error_results):
- error["sequence"] = index
-
- errors.append(error)
-df = pd.DataFrame(errors)
-print(df)
diff --git a/wecom_api/models/wecom_server_api_error.py b/wecom_api/models/wecom_server_api_error.py
deleted file mode 100644
index 1aea89c4b..000000000
--- a/wecom_api/models/wecom_server_api_error.py
+++ /dev/null
@@ -1,175 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import operator
-import requests
-import logging
-from urllib.parse import quote, unquote
-import pandas as pd
-
-# pd.set_option("max_colwidth", 4096)
-# pd.set_option("max_colwidth", 10)
-
-from lxml import etree
-from odoo import api, fields, models, SUPERUSER_ID, _
-
-_logger = logging.getLogger(__name__)
-
-
-class WecomServerApiError(models.Model):
- _name = "wecom.service_api_error"
- _description = "Wecom Server API Error"
- _order = "sequence"
-
- name = fields.Char(
- "Error description",
- required=True,
- readonly=True,
- )
- code = fields.Integer(
- "Error code",
- required=True,
- readonly=True,
- )
-
- method = fields.Html(
- "Treatment method",
- readonly=True,
- )
-
- sequence = fields.Integer(default=0)
-
- def get_error_by_code(self, code):
- res = self.search(
- [("code", "=", code)],
- limit=1,
- )
- return {
- "code": res.code, # type: ignore
- "name": res.name, # type: ignore
- "method": res.method, # type: ignore
- }
-
- def cron_pull_global_error_code(self):
- self.get_api_error_eode()
-
- @api.model
- def get_api_error_eode(self):
- """
- 使用爬虫爬取 全局错误码
- URL的一般格式为: protocol://hostname[:port]/path/[;parameters][?query]#fragment
- """
- ir_config = self.env["ir.config_parameter"].sudo()
- url = ir_config.get_param("wecom.global_error_code_url")
-
- codes = ir_config.get_param("wecom.global_error_code_item_selection_code")
-
- state = False
- msg= ""
- try:
- _logger.info(_("Start pulling the global error code of WeCom."))
- page_text = requests.get(url=url).text
- tree = etree.HTML(page_text) # type: ignore
-
- codes_elements = tree.xpath(codes)
-
- methods = []
-
- for code_element in codes_elements:
- code_element_str = code_element.xpath("text()")[0]
- error_code = code_element_str.split(":", 1)[1:][0]
-
- method_element = code_element.getnext()
- method = etree.tostring(method_element, encoding="utf-8", pretty_print=True ).decode() # type: ignore
-
- if " " in error_code:
- # 一个元素存在多个错误码
- multiple_codes = error_code.split(" ", 1)
- for multiple_code in multiple_codes:
- multiple_dic = {}
- multiple_dic["code"] = multiple_code
- multiple_dic["method"] = method
- methods.append(multiple_dic)
- else:
- dic = {}
- dic["code"] = error_code
- dic["method"] = method
- methods.append(dic)
-
- table = tree.xpath("//div[@class='cherry-table-container']/table") # 取出表格
- table = etree.tostring(
- table[0], encoding="utf-8" # type: ignore
- ).decode() # 将第一个表格转成string格式
- table = table.replace("错误码 ", "code ")
- table = table.replace("错误说明 ", "name ")
- table = table.replace("排查方法 ", "method ")
-
- df = pd.read_html(table, encoding="utf-8", header=0)[0] # pandas读取table
- if 'Unnamed: 3' in df.columns:
- del df['Unnamed: 3']
-
- error_results = list(df.T.to_dict().values()) # 转换成列表嵌套字典的格式
-
- errors = []
- for index, error in enumerate(error_results):
- if (error["code"] == 40054) or (error["code"] == 40055):
- error["method"] = self.replaceMethod(str(error["code"]), methods)
- elif error["method"] == "查看帮助":
- error["method"] = self.replaceMethod(str(error["code"]), methods)
- error["sequence"] = index
- errors.append(error)
-
- except Exception as e:
- msg = _("Failed to pull WeCom global error code, reason:%s") % str(e)
- _logger.warning(msg)
- state = False
- else:
- # 写入到odoo
- for error in errors:
- res = self.search(
- [("code", "=", error["code"])],
- limit=1,
- )
- if not res:
- self.sudo().create(
- {
- "code": error["code"],
- "name": error["name"],
- "method": error["method"],
- "sequence": error["sequence"],
- }
- )
- else:
- res.sudo().write( # type: ignore
- {
- "name": error["name"],
- "method": error["method"],
- "sequence": error["sequence"],
- }
- )
- state = True
- msg = _("Successfully pulled the WeCom global error code!")
- _logger.info(msg)
-
- finally:
- return {"state": state, "msg": msg}
-
- def replaceMethod(self, code, methods):
- """
- 替换 排查方法
- """
- df = pd.DataFrame(methods)
- method = df["method"][df["code"] == code].to_string(
- index=False
- ) # 取 包含指定code 值的 "method"列
-
- if method[-2:] == "\\n":
- method = method[:-2] # 去掉最后的换行符
-
- return method
-
- def getMiddleStr(self, content, startStr, endStr):
- startIndex = content.index(startStr)
- if startIndex >= 0:
- startIndex += len(startStr)
- endIndex = content.index(endStr)
- return content[startIndex:endIndex]
diff --git a/wecom_api/models/wecom_server_api_list.py b/wecom_api/models/wecom_server_api_list.py
deleted file mode 100644
index b1978a1a3..000000000
--- a/wecom_api/models/wecom_server_api_list.py
+++ /dev/null
@@ -1,67 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import re
-from odoo import api, fields, models, SUPERUSER_ID, _
-
-
-class WecomServerApiList(models.Model):
- _name = "wecom.service_api_list"
- _description = "Wecom Server API List"
- _order = "sequence,type"
-
- type = fields.Selection(
- [
- ("1", "Base"), # 基础
- ("2", "Contacts"), # 通讯录,
- ("3", "Customer contact"), # 客户联系
- ("4", "Wechat customer service"), # 微信客服
- ("5", "Identity authentication"), # 身份验证
- ("6", "Application management"), # 应用管理
- ("7", "Message push"), # 消息推送
- ("8", "Media material"), # 媒体素材
- ("9", "OA"), # OA
- ("10", "Efficiency tools"), # 效率工具
- ("11", "externalpay"), # 企业支付
- ("12", "Corp Group"), # 企业互联
- ("13", "Corp Chain"), # 企业链,上下游
- ("14", "Session content archiving"), # 会话内容存档
- ("15", "Electronic invoice"), # 电子发票
- ("16", "School"), # 家校沟通
- ("17", "School Apps"), # 家校应用
- ("18", "Report"), # 政民沟通
- ],
- string="Api Type",
- required=True,
- default="GET",
- )
-
- name = fields.Char("Request Name", required=True,)
- function_name = fields.Char("Request Function Name", required=True, readonly=True,)
-
- short_url = fields.Char("Request Short Url", required=True,)
-
- request_type = fields.Selection(
- [("GET", "GET"), ("POST", "POST"),],
- string="Api Request Type",
- required=True,
- default="GET",
- )
- description = fields.Html(string="Description")
- sequence = fields.Integer(default=0)
-
- _sql_constraints = [
- ("function_name_uniq", "unique (function_name)", "The function is unique !",),
- ]
-
- def get_server_api_call(self, function_name):
- """
- 根据函数名称获取 企业微信API的路由和请求方式
- :param function_name : 函数名称
- :returns 企业微信API的路由和请求方式的集合
- """
- # ['/cgi-bin/gettoken', 'GET']
- data = []
- res = self.search([("function_name", "=", function_name)], limit=1,)
- data.append(res.short_url) # type: ignore
- data.append(res.request_type) # type: ignore
- return data
diff --git a/wecom_api/security/ir.model.access.csv b/wecom_api/security/ir.model.access.csv
deleted file mode 100644
index c31288906..000000000
--- a/wecom_api/security/ir.model.access.csv
+++ /dev/null
@@ -1,7 +0,0 @@
-id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
-
-wecom_service_api_access_right,access.wecom.service_api,model_wecom_service_api,base.group_erp_manager,1,1,1,1
-wecom_service_api_access_right_user,access.wecom.service_api,model_wecom_service_api,base.group_user,1,0,0,0
-
-wecom_service_api_error_access_right,access.wecom.service_api_error,model_wecom_service_api_error,base.group_erp_manager,1,1,1,1
-wecom_service_api_error_access_right_user,access.wecom.service_api_error,model_wecom_service_api_error,base.group_user,1,0,0,0
\ No newline at end of file
diff --git a/wecom_api/static/description/icon.png b/wecom_api/static/description/icon.png
deleted file mode 100644
index 6e158c119..000000000
Binary files a/wecom_api/static/description/icon.png and /dev/null differ
diff --git a/wecom_api/tools/__init__.py b/wecom_api/tools/__init__.py
deleted file mode 100644
index 59bfb7b70..000000000
--- a/wecom_api/tools/__init__.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# -*- coding: utf-8 -*-
-
-
-from . import action
-from . import file
-from . import string
-from . import datetime
-from . import message
-from . import security
-from . import data
-from . import convert
-from . import dictionary
-
-
-from . import wx_tools
diff --git a/wecom_api/tools/action.py b/wecom_api/tools/action.py
deleted file mode 100644
index f6f3dc98e..000000000
--- a/wecom_api/tools/action.py
+++ /dev/null
@@ -1,125 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from odoo import models, _
-import logging
-
-_logger = logging.getLogger(__name__)
-
-
-class WecomApiToolsAction(models.AbstractModel):
- _name = "wecomapi.tools.action"
- _description = "Wecom API Tools - Action"
-
- def ApiExceptionDialog(
- self,
- ex,
- raise_exception=False,
- ):
- """
- API 错误弹框
- """
- ir_config = self.env["ir.config_parameter"].sudo()
- debug = ir_config.get_param("wecom.debug_enabled")
- error = self.env["wecom.service_api_error"].get_error_by_code(ex.errCode)
-
- if debug:
- _logger.warning(
- _("Wecom API error: %s, error name: %s, error message: %s")
- % (str(ex.errCode), error["name"], ex.errMsg)
- )
- if raise_exception:
- params = {
- "title": _("Failed"),
- "message": _(
- "Error code: %s,Error description: %s,Error troubleshooting method: %s,Error Details:%s"
- )
- % (
- str(ex.errCode),
- str(error["name"]),
- error["method"],
- ex.errMsg,
- ),
- "size": "md", # medium
- }
- action = {
- "type": "ir.actions.client",
- "tag": "api_error_dialog",
- "params": {
- "title": params["title"],
- "size": params["size"],
- "code": str(ex.errCode),
- "description": str(error["name"]),
- "method": str(error["method"]),
- "details": ex.errMsg,
- },
- }
- return action
-
- def WecomInfoNotification(self, msg):
- """
- API 提示信息
- """
- action = {
- "type": "ir.actions.client",
- "tag": "display_notification",
- "params": {
- "title": msg["title"],
- "type": "info",
- "message": msg["message"],
- "sticky": msg["sticky"],
- },
- }
- return action
-
- def WecomSuccessNotification(self, msg):
- """
- API 成功提示信息
- """
- params = {
- "title": msg["title"],
- "type": "success",
- "message": msg["message"],
- "sticky": msg["sticky"],
- }
- if "next" in msg:
- params.update({"next": msg["next"]})
-
- action = {
- "type": "ir.actions.client",
- "tag": "display_notification",
- "params": params,
- }
- return action
-
- def WecomWarningNotification(self, msg):
- """
- API 警告提示信息
- """
- action = {
- "type": "ir.actions.client",
- "tag": "display_notification",
- "params": {
- "title": msg["title"],
- "type": "warning",
- "message": msg["message"],
- "sticky": msg["sticky"],
- },
- }
- return action
-
- def WecomErrorNotification(self, msg):
- """
- API 错误提示信息
- """
-
- action = {
- "type": "ir.actions.client",
- "tag": "display_notification",
- "params": {
- "title": msg["title"],
- "type": "error",
- "message": msg["message"],
- "sticky": msg["sticky"],
- },
- }
- return action
diff --git a/wecom_api/tools/convert.py b/wecom_api/tools/convert.py
deleted file mode 100644
index 00be1ae91..000000000
--- a/wecom_api/tools/convert.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import html2text
-from odoo import api, models, tools, _
-
-class WecomApiToolsTypeConvert(models.AbstractModel):
- _name = "wecomapi.tools.convert"
- _description = "Wecom API Tools - Type convert"
-
- def html2text_handle(self, body_html):
- # 转换markdown格式
- if bool(body_html):
- return html2text.html2text(body_html)
- else:
- return None
-
- def str2bool(self):
- """
- 字符串转布尔值
- :param val: 字符串
- :return: 布尔值
- """
- # return self.value.lower() in ("yes", "true", "t", "1")
-
- if self.value.lower() in ["true", "t", "1"]: # type: ignore
- return True
- elif self.value.lower() in ["false", "f", "0"]: # type: ignore
- return False
- else:
- return False
-
- def sex2gender(self, sex):
- """
- 性别转换
- """
- if sex == "1":
- return "male"
- elif sex == "2":
- return "female"
- else:
- return "other"
-
- def gendge2sex(self, gender):
- if gender == "male":
- return "1"
- elif gender == "female":
- return "2"
\ No newline at end of file
diff --git a/wecom_api/tools/data.py b/wecom_api/tools/data.py
deleted file mode 100644
index e5e329458..000000000
--- a/wecom_api/tools/data.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from odoo import api, models, tools, _
-
-import logging
-
-_logger = logging.getLogger(__name__)
-
-class WecomApiToolsData(models.AbstractModel):
- _name = "wecomapi.tools.data"
- _description = "Wecom API Tools - Data"
-
-
- def union_data_set(self, set1, set2):
- """
- 2个数据集的并集
- :param set1: 数据集1
- :param set2: 数据集2
- :returns: 并集 的
- """
- # set1.union(set2)
- return set1 | set2
-
- def difference_data_set(self, set1, set2):
- """
- 2个数据集的差集
- :param set1: 数据集1
- :param set2: 数据集2
- :returns: 差集
- """
- # set1.difference(set2)
- return set1 - set2
-
- def intersection_data_set(self, set1, set2):
- """
- 2个数据集的交集
- :param set1: 数据集1
- :param set2: 数据集2
- :returns: 交集
- """
- # set1.intersection(set2)
- return set1 & set2
\ No newline at end of file
diff --git a/wecom_api/tools/datetime.py b/wecom_api/tools/datetime.py
deleted file mode 100644
index cc20b770a..000000000
--- a/wecom_api/tools/datetime.py
+++ /dev/null
@@ -1,82 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import time
-from odoo import api, models, tools, _
-from datetime import datetime, timedelta
-import logging
-
-_logger = logging.getLogger(__name__)
-
-
-class WecomApiToolsDatetime(models.AbstractModel):
- _name = "wecomapi.tools.datetime"
- _description = "Wecom API Tools - Datetime"
-
- def timestamp2datetime(self, time_stamp):
- """
- 时间戳转日期时间
- """
- if len(str(time_stamp)) > 10:
- # 一般爬取下来的时间戳长度都是13位的数字,而time.localtime的参数要的长度是10位,所以我们需要将其/1000并取整即可
- time_stamp = int(time_stamp / 1000)
- loc_time = time.localtime(time_stamp)
- return time.strftime("%Y-%m-%d %H:%M:%S", loc_time)
-
- def cheeck_days_overdue(self, datetime_start, maxday):
- """[summary]
- 检查天数是否超期
- Args:
- datetime_start_str ([type]): [description]
- datetime_end_str ([type]): [description]
- maxday ([type]): [description] 天数
-
- Returns:
- True: 超期
- False:未超期
- """
-
- now = datetime.now()
- # print(now - datetime_start)
- if datetime_start > (now - timedelta(days=maxday)):
- return False
- else:
- return True
-
- def cheeck_hours_overdue(self, datetime_start, maxhour):
- """[summary]
- 检查小时是否超期
- Args:
- datetime_start_str ([type]): [description]
- datetime_end_str ([type]): [description]
- maxhour ([type]): [description] 小时
-
- Returns:
- True: 超期
- False:未超期
- """
-
- now = datetime.now()
- if datetime_start > (now - timedelta(hours=maxhour)):
- return False
- else:
- return True
-
- def cheeck_minutes_overdue(self, datetime_start, maxminute):
- """[summary]
- 检查分钟是否超期
- Args:
- datetime_start_str ([type]): [description]
- datetime_end_str ([type]): [description]
- maxminute ([type]): [description] 分钟
-
- Returns:
- True: 超期
- False:未超期
- """
-
- now = datetime.now()
-
- if datetime_start > (now - timedelta(minutes=maxminute)):
- return False
- else:
- return True
diff --git a/wecom_api/tools/dictionary.py b/wecom_api/tools/dictionary.py
deleted file mode 100644
index db072b94f..000000000
--- a/wecom_api/tools/dictionary.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from odoo import api, models, tools, _
-
-class WecomApiToolsDictionary(models.AbstractModel):
- _name = "wecomapi.tools.dictionary"
- _description = "Wecom API Tools - Dictionary"
-
-
- def check_dictionary_keywords(self, dictionary, key):
- """
- 检查字典中是否存在key
- """
- # dictionary, key = (self.value[0], self.value[1])
- if key in dictionary.keys():
- return dictionary[key]
- else:
- return None
\ No newline at end of file
diff --git a/wecom_api/tools/file.py b/wecom_api/tools/file.py
deleted file mode 100644
index 90a04a21d..000000000
--- a/wecom_api/tools/file.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from odoo import api, models, tools, _
-import base64
-import requests
-import io
-import os
-import platform
-import logging
-from odoo.modules.module import get_module_resource
-
-_logger = logging.getLogger(__name__)
-
-
-class WecomApiToolsFile(models.AbstractModel):
- _name = "wecomapi.tools.file"
- _description = "Wecom API Tools - File"
-
- def path_is_exists(self, path, subpath):
- """
- 检文件夹路径是否存在,不存在则创建路径
- return:返回路径
- """
- if platform.system() == "Windows":
- filepath = path.replace("\\", "/") + subpath + "/"
- else:
- filepath = path + subpath + "/"
- # print(filepath)
- if not os.path.exists(filepath):
- os.makedirs(filepath)
- return filepath
-
- def get_avatar_base64(self, use_default_avatar, gender, avatar_url):
- """
- 获取企业微信用户头像的base64编码
- return:返回base64
- """
- imgbase64 = ""
- if use_default_avatar or avatar_url == "":
- image_name = "default_image.png"
- if gender == "1":
- image_name = "default_male_image.png"
- elif gender == "2":
- image_name = "default_female_image.png"
-
- default_image = get_module_resource("hrms_base", "static/src/img", image_name)
- # print(default_image)
- with open(default_image, "rb") as f:
- imgbase64 = base64.b64encode(f.read())
- else:
- imgbase64 = base64.b64encode(requests.get(avatar_url).content)
- return imgbase64
diff --git a/wecom_api/tools/message.py b/wecom_api/tools/message.py
deleted file mode 100644
index 53568d637..000000000
--- a/wecom_api/tools/message.py
+++ /dev/null
@@ -1,14 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from odoo import api, models, tools, _
-import logging
-
-_logger = logging.getLogger(__name__)
-
-
-class WecomApiToolsMessage(models.AbstractModel):
- _name = "wecomapi.tools.message"
- _description = "Wecom API Tools - Message"
-
- def message_split(self,text):
- """ """
diff --git a/wecom_api/tools/security.py b/wecom_api/tools/security.py
deleted file mode 100644
index 1e2de7f9d..000000000
--- a/wecom_api/tools/security.py
+++ /dev/null
@@ -1,83 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from odoo import api, fields, models, tools, _
-import logging
-import hashlib
-import random
-import hashlib
-from Crypto.Cipher import AES
-from passlib.context import CryptContext
-import xml.etree.cElementTree as ET
-import hashlib
-
-
-_logger = logging.getLogger(__name__)
-
-NUMLIST = ["0","1","2","3","4","5","6","7","8","9","q","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","W","R","S","T","U","V","W","X","Y","Z",]
-
-
-class WecomApiToolsSecurity(models.AbstractModel):
- _name = "wecomapi.tools.security"
- _description = "Wecom API Tools - Security"
-
- def random_str(self, num):
- """
- 生成随机字符串
- :return:
- """
- rang = num
- if rang == None:
- random_str = "".join(random.choice(NUMLIST) for i in range(8))
- else:
- random_str = "".join(random.choice(NUMLIST) for i in range(int(rang)))
- return random_str
-
- def random_passwd(self, num):
- """
- 生成随机密码
- :return:
- """
- rang = num
- if rang == None:
- passwd = "".join(random.choice(NUMLIST) for i in range(8))
- else:
- passwd = "".join(random.choice(NUMLIST) for i in range(int(rang)))
-
- crypt_context = CryptContext(
- schemes=["pbkdf2_sha512", "plaintext"], deprecated=["plaintext"]
- )
- hash_password = (
- crypt_context.hash
- if hasattr(crypt_context, "hash")
- else crypt_context.encrypt
- )
- return hash_password(passwd)
-
- def generate_jsapi_signature(self, jsapi_ticket, nonceStr, timestamp):
- """
- 使用sha1加密算法,生成JSAPI的签名
- ------------------------------
- company: 公司
- nonceStr: 生成签名的随机串
- timestamp: 生成签名的时间戳
- url: 当前网页的URL, 不包含#及其后面部分
- """
-
- # 生成签名前,刷新 ticke .search([(("is_wecom_organization", "=", True))])
- # company.sudo().get_jsapi_ticket()
-
- ICP = self.env["ir.config_parameter"].sudo()
- web_base_url = ICP.get_param("web.base.url", default="http://localhost:8069")
- if web_base_url[-1] == "/":
- web_base_url = web_base_url + "web"
- else:
- web_base_url = web_base_url + "/web"
-
- jsapi_ticket_str = ("jsapi_ticket=%s&noncestr=%s×tamp=%s&url=%s") % (
- jsapi_ticket,
- nonceStr,
- timestamp,
- web_base_url,
- )
- encrypts = hashlib.sha1(jsapi_ticket_str.encode("utf-8")).hexdigest()
- return encrypts
diff --git a/wecom_api/tools/string.py b/wecom_api/tools/string.py
deleted file mode 100644
index 34904fb2a..000000000
--- a/wecom_api/tools/string.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import random
-from odoo import api, models, tools, _
-
-import logging
-
-_logger = logging.getLogger(__name__)
-
-
-class WecomApiToolsString(models.AbstractModel):
- _name = "wecomapi.tools.string"
- _description = "Wecom API Tools - Fields"
-
- def str2bool(self):
- """
- 字符串转布尔值
- :param val: 字符串
- :return: 布尔值
- """
- # return self.value.lower() in ("yes", "true", "t", "1")
-
- if self.value.lower() in ["true", "t", "1"]: # type: ignore
- return True
- elif self.value.lower() in ["false", "f", "0"]: # type: ignore
- return False
- else:
- return False
-
- # def int2bool(self):
- # """
- # 整形转布尔值
- # :param val: 整形
- # :return: 布尔值
- # """
- # if self.value.lower() in ["true", "t", "1"]:
- # return True
- # elif self.value.lower() in ["false", "f", "0"]:
- # return False
- # else:
- # return False
-
diff --git a/wecom_api/tools/wx_tools.py b/wecom_api/tools/wx_tools.py
deleted file mode 100644
index 29a8758e6..000000000
--- a/wecom_api/tools/wx_tools.py
+++ /dev/null
@@ -1,105 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from PIL import Image
-import os
-import base64
-import random
-import html2text
-import platform
-import hashlib
-from passlib.context import CryptContext
-
-from odoo import api, models, tools, _
-from odoo.modules.module import get_module_resource
-from datetime import datetime, timedelta
-
-import logging
-
-_logger = logging.getLogger(__name__)
-
-
-class WxTools(models.AbstractModel):
- _name = "wecom.tools"
- _description = "Wecom Tools"
-
- def recipients_split(text): # type: ignore
- """
- 使用 | 拆分企业微信消息的接收对象
- """
- if not text:
- return []
-
- def wecom_user_enable(self):
- """
- 企业微信用户是否启用
- :param value:
- :return:
- """
- if self.value == "0": # type: ignore
- self.result = False
- if self.value == "1": # type: ignore
- self.result = True
- return self.result
-
- def encode_avatar_image_as_base64(self, gender):
- if gender == "1":
- default_image = get_module_resource(
- "wecom_api", "static/src/img", "default_male_image.png"
- )
- elif gender == "2":
- default_image = get_module_resource(
- "wecom_api",
- "static/src/img",
- "default_female_image.png",
- )
- else:
- default_image = get_module_resource(
- "wecom_api", "static/src/img", "default_image.png"
- )
-
- with open(default_image, "rb") as f:
- return base64.b64encode(f.read())
-
- def get_default_avatar_url(self, gender):
- params = self.env["ir.config_parameter"].sudo()
- base_url = params.get_param("web.base.url")
- if gender == "1":
- default_image_url = (
- base_url + "/wecom_api/static/src/img/default_male_image.png"
- )
- elif gender == "2":
- default_image_url = (
- base_url + "/wecom_api/static/src/img/default_female_image.png"
- )
-
- return default_image_url # type: ignore
-
- def encode_image_as_base64(self):
- if not self.value: # type: ignore
- pass
- else:
- with open(self.value, "rb") as f: # type: ignore
- encoded_string = base64.b64encode(f.read())
- return encoded_string
-
- def is_exists(self):
- """
- 判断是否存在值
- :return:
- """
- if not self.value: # type: ignore
- self.result = False
- else:
- self.result = True
- return self.result
-
- def mail_is_exists(self):
- """
- 判断是否存在值
- :return:
- """
- if not self.value: # type: ignore
- self.result = ""
- else:
- self.result = self.value # type: ignore
- return self.result
diff --git a/wecom_auth_oauth/__init__.py b/wecom_auth_oauth/__init__.py
deleted file mode 100644
index c3d410ea1..000000000
--- a/wecom_auth_oauth/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from . import models
-from . import controllers
diff --git a/wecom_auth_oauth/__manifest__.py b/wecom_auth_oauth/__manifest__.py
deleted file mode 100644
index 650692aea..000000000
--- a/wecom_auth_oauth/__manifest__.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# -*- coding: utf-8 -*-
-{
- "name": "WeCom Authentication",
- "author": "RStudio",
- "website": "https://gitee.com/rainbowstudio/wecom",
- "sequence": 605,
- "installable": True,
- "application": True,
- "auto_install": False,
- "category": "WeCom Suites/Authentication",
- "version": "17.0.0.1",
- "summary": """
- One click login, code scanning login.
- """,
- "description": """
-
- """,
- "depends": [
- "portal",
- "auth_oauth",
- "wecom_material",
- ],
- "data": [
- "data/wecom_apps_data.xml",
- "data/wecom_app_config_data.xml",
- "data/wecom_oauth_data.xml",
- "views/res_config_settings_views.xml",
- "views/auth_oauth_views.xml",
- # "views/wecom_apps_views.xml",
- # "views/auth_signup_login_templates.xml",
- ],
- "assets": {
- "web.assets_backend": [
- # "wecom_auth_oauth/static/src/webclient/**/*",
- ],
- "web.assets_frontend": [
- "wecom_auth_oauth/static/src/js/wecom_login/*",
- ],
- },
- "bootstrap": True, # 加载登录屏幕的翻译,
- "license": "Other proprietary",
-}
diff --git a/wecom_auth_oauth/controllers/__init__.py b/wecom_auth_oauth/controllers/__init__.py
deleted file mode 100644
index 65a8c1201..000000000
--- a/wecom_auth_oauth/controllers/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from . import main
diff --git a/wecom_auth_oauth/controllers/main.py b/wecom_auth_oauth/controllers/main.py
deleted file mode 100644
index 6a117b8a1..000000000
--- a/wecom_auth_oauth/controllers/main.py
+++ /dev/null
@@ -1,110 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# !参考 \addons\auth_oauth\controllers\main.py
-
-import base64
-import functools
-import json
-import logging
-import os
-
-import werkzeug.urls
-import werkzeug.utils
-from werkzeug.exceptions import BadRequest
-
-from odoo import api, http, SUPERUSER_ID, _
-from odoo.exceptions import AccessDenied
-from odoo.http import request, Response
-from odoo import registry as registry_get
-from odoo.tools.misc import clean_context
-
-from odoo.addons.auth_signup.controllers.main import AuthSignupHome as Home
-from odoo.addons.web.controllers.utils import ensure_db, _get_login_redirect_url
-
-
-_logger = logging.getLogger(__name__)
-
-WECOM_BROWSER_MESSAGES = {
- "not_wecom_browser": _(
- "The current browser is not an WeCom built-in browser, so the one-click login function cannot be used."
- ),
- "is_wecom_browser": _(
- "It is detected that the page is opened in the built-in browser of WeCom, please select company."
- ),
-}
-
-
-class WeComOAuthLogin(Home):
- def list_providers(self):
- providers = super(WeComOAuthLogin, self).list_providers()
-
- for provider in providers:
- if (
- "login.work.weixin.qq.com/wwlogin/sso/login"
- in provider["auth_endpoint"]
- ):
- # 链接格式
- # https://login.work.weixin.qq.com/wwlogin/sso/login?login_type=LOGIN_TYPE&appid=APPID&redirect_uri=REDIRECT_URI&state=STATE
- return_url = request.httprequest.url_root + "wecom/authorize"
- state = self.get_state(provider)
- params = dict(
- appid=False,
- redirect_uri=return_url,
- response_type="code",
- scope=provider["scope"],
- state=json.dumps(state),
- )
- provider["auth_link"] = "%s?%s%s" % (
- provider["auth_endpoint"],
- werkzeug.urls.url_encode(params), # type: ignore
- "#wechat_redirect",
- )
-
- return providers
-
-
-class OAuthController(http.Controller):
- @http.route("/wwcom_login_info", type="json", auth="none")
- def wecom_get_login_info(self, **kwargs):
- data = {}
- if "is_wecom_browser" in kwargs:
- if kwargs["is_wecom_browser"]:
- data = {
- "is_wecom_browser": True,
- "msg": WECOM_BROWSER_MESSAGES["is_wecom_browser"],
- "companies": [],
- }
- else:
- data = {
- "is_wecom_browser": False,
- "msg": WECOM_BROWSER_MESSAGES["not_wecom_browser"],
- "companies": [],
- }
- else:
- data = {
- "join_button_name": _("Join WeCom,Become our employee."),
- "companies": [],
- }
-
- # 获取 标记为 企业微信组织 的公司
- companies = request.env["res.company"].search( # type: ignore
- [(("is_wecom_organization", "=", True))]
- )
-
- if len(companies) > 0:
- for company in companies:
- # app_config = request.env["wecom.app_config"].sudo()
- # contacts_app = company.contacts_app_id.sudo() # 通讯录应用
- auth_app = company.auth_app_id.sudo() # 验证登录应用
- data["companies"].append(
- {
- "id": company["id"],
- "name": company["abbreviated_name"],
- "fullname": company["name"],
- "appid": company["corpid"],
- "agentid": auth_app.agentid if auth_app else 0,
- "enabled_join": company["wecom_contacts_join_qrcode_enabled"],
- "join_qrcode": company["wecom_contacts_join_qrcode"],
- }
- )
- return data
diff --git a/wecom_auth_oauth/data/wecom_app_config_data.xml b/wecom_auth_oauth/data/wecom_app_config_data.xml
deleted file mode 100644
index f22c4369b..000000000
--- a/wecom_auth_oauth/data/wecom_app_config_data.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-
-
- Callback link address redirected after authorization
- auth_redirect_uri
- char
- http://xxx.xxx.com:port/wecom_auth_oauth/authorize
-
-
- Fill in the "Corp ID", "AgentId" and "Secret" that require authentication and authorization, and use the domain name to access,
-
- Click the button "One-click to set up WeCom OAuth"
-
-
-
-
-
-
-
-
- Scan the QR code to log in and call back the link address
- auth_qr_redirect_uri
- char
- http://xxx.xxx.com:port/wecom_auth_oauth/qr
-
-
- Fill in the "Corp ID", "AgentId" and "Secret" that require authentication and authorization, and use the domain name to access,
-
- Click the button "One-click to set up WeCom OAuth"
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_auth_oauth/data/wecom_apps_data.xml b/wecom_auth_oauth/data/wecom_apps_data.xml
deleted file mode 100644
index 7958069d0..000000000
--- a/wecom_auth_oauth/data/wecom_apps_data.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_auth_oauth/data/wecom_oauth_data.xml b/wecom_auth_oauth/data/wecom_oauth_data.xml
deleted file mode 100644
index e39a73343..000000000
--- a/wecom_auth_oauth/data/wecom_oauth_data.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
-
-
-
-
-
- WeCom Quick Login
-
- https://login.work.weixin.qq.com/wwlogin/sso/login
-
- snsapi_base
-
- https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo
-
- https://qyapi.weixin.qq.com/cgi-bin/auth/getuserdetail
- fa fa-fw fa-wechat wecom_auth_quick
- WeCom quick login
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_auth_oauth/i18n/zh_CN.po b/wecom_auth_oauth/i18n/zh_CN.po
deleted file mode 100644
index cfa072982..000000000
--- a/wecom_auth_oauth/i18n/zh_CN.po
+++ /dev/null
@@ -1,287 +0,0 @@
-# Translation of Odoo Server.
-# This file contains the translation of the following modules:
-# * wecom_auth_oauth
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: Odoo Server 17.0\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2024-03-12 09:11+0000\n"
-"PO-Revision-Date: 2024-03-12 17:20+0800\n"
-"Last-Translator: \n"
-"Language-Team: \n"
-"Language: zh_CN\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Poedit 3.4.2\n"
-
-#. module: wecom_auth_oauth
-#: model_terms:ir.ui.view,arch_db:wecom_auth_oauth.res_config_settings_view_form
-msgid " "
-msgstr ""
-
-#. module: wecom_auth_oauth
-#: model_terms:ir.ui.view,arch_db:wecom_auth_oauth.res_config_settings_view_form
-msgid " "
-msgstr ""
-
-#. module: wecom_auth_oauth
-#: model_terms:ir.ui.view,arch_db:wecom_auth_oauth.res_config_settings_view_form
-msgid " "
-msgstr ""
-
-#. module: wecom_auth_oauth
-#: model_terms:ir.ui.view,arch_db:wecom_auth_oauth.res_config_settings_view_form
-msgid ""
-" "
-msgstr ""
-
-#. module: wecom_auth_oauth
-#: model_terms:ir.ui.view,arch_db:wecom_auth_oauth.res_config_settings_view_form
-msgid " "
-msgstr ""
-""
-
-#. module: wecom_auth_oauth
-#: model_terms:ir.ui.view,arch_db:wecom_auth_oauth.res_config_settings_view_form
-msgid "Save this page and come back here to set up other feature."
-msgstr "保存 此页面并返回此处以设置其它功能。"
-
-#. module: wecom_auth_oauth
-#: model:ir.model.fields,field_description:wecom_auth_oauth.field_res_config_settings__auth_agentid
-msgid "Agent ID"
-msgstr "应用ID"
-
-#. module: wecom_auth_oauth
-#: model:ir.model.fields,field_description:wecom_auth_oauth.field_res_company__auth_app_id
-#: model:ir.model.fields,field_description:wecom_auth_oauth.field_res_config_settings__auth_app_id
-msgid "Application"
-msgstr "应用"
-
-#. module: wecom_auth_oauth
-#: model:ir.model.fields,field_description:wecom_auth_oauth.field_res_config_settings__auth_app_config_ids
-msgid "Application Configuration"
-msgstr "应用配置"
-
-#. module: wecom_auth_oauth
-#: model_terms:ir.ui.view,arch_db:wecom_auth_oauth.res_config_settings_view_form
-msgid ""
-"Application Management→Application→Open the application that needs to be "
-"verified and authorized, copy 'AgentId'"
-msgstr "应用程序管理→应用→打开需要验证和授权的应用程序,复制“AgentId”"
-
-#. module: wecom_auth_oauth
-#: model_terms:ir.ui.view,arch_db:wecom_auth_oauth.res_config_settings_view_form
-msgid ""
-"Application Management→Application→Open the application that needs to be "
-"verified and authorized, copy 'Secret'"
-msgstr "应用程序管理→应用→打开需要验证和授权的应用程序,复制“Secret”"
-
-#. module: wecom_auth_oauth
-#. odoo-python
-#: code:addons/wecom_auth_oauth/models/res_config_settings.py:0
-#, python-format
-msgid "Auth application ID and secret cannot be empty!"
-msgstr "身份验证应用ID和Secret 不能为空!"
-
-#. module: wecom_auth_oauth
-#: model_terms:ir.ui.view,arch_db:wecom_auth_oauth.res_config_settings_view_form
-msgid "Binding Auth Application"
-msgstr "绑定验证应用"
-
-#. module: wecom_auth_oauth
-#: model_terms:ir.ui.view,arch_db:wecom_auth_oauth.res_config_settings_view_form
-msgid "Button group"
-msgstr "按钮组"
-
-#. module: wecom_auth_oauth
-#: model:wecom.app_config,name:wecom_auth_oauth.wecom_app_config_authentication_auth_redirect_uri
-msgid "Callback link address redirected after authorization"
-msgstr ""
-
-#. module: wecom_auth_oauth
-#: model:ir.model,name:wecom_auth_oauth.model_res_company
-msgid "Companies"
-msgstr "公司"
-
-#. module: wecom_auth_oauth
-#: model:ir.model.fields,field_description:wecom_auth_oauth.field_res_config_settings__company_id
-msgid "Company"
-msgstr "公司"
-
-#. module: wecom_auth_oauth
-#: model:ir.model,name:wecom_auth_oauth.model_res_config_settings
-msgid "Config Settings"
-msgstr "配置设置"
-
-#. module: wecom_auth_oauth
-#: model:ir.model.fields,field_description:wecom_auth_oauth.field_auth_oauth_provider__description
-msgid "Description"
-msgstr "说明"
-
-#. module: wecom_auth_oauth
-#: model_terms:ir.ui.view,arch_db:wecom_auth_oauth.res_config_settings_view_form
-msgid "Enable WeCom quick login"
-msgstr "启用企微快速登录"
-
-#. module: wecom_auth_oauth
-#: model_terms:ir.ui.view,arch_db:wecom_auth_oauth.res_config_settings_view_form
-msgid "Expiration time"
-msgstr "过期时间"
-
-#. module: wecom_auth_oauth
-#: model_terms:wecom.app_config,description:wecom_auth_oauth.wecom_app_config_authentication_auth_redirect_uri
-#: model_terms:wecom.app_config,description:wecom_auth_oauth.wecom_app_config_authentication_qr_redirect_uri
-msgid ""
-"Fill in the \"Corp ID\", \"AgentId\" and \"Secret\" that require authentication "
-"and authorization, and use the domain name to access,\n"
-" \n"
-" Click the button \"One-click to set up WeCom OAuth\"\n"
-" "
-msgstr ""
-"在需要认证和授权的“企业ID”、“AgentId”和“Secret”中,使用域名进行访问,\n"
-" \n"
-" Click the button \"One-click to set up WeCom OAuth\"\n"
-" "
-
-#. module: wecom_auth_oauth
-#: model_terms:ir.ui.view,arch_db:wecom_auth_oauth.res_config_settings_view_form
-msgid "Get JSAPI Ticket"
-msgstr "获取JSAPI临时凭证"
-
-#. module: wecom_auth_oauth
-#: model_terms:ir.ui.view,arch_db:wecom_auth_oauth.res_config_settings_view_form
-msgid "Get application info"
-msgstr "获取应用信息"
-
-#. module: wecom_auth_oauth
-#: model_terms:ir.ui.view,arch_db:wecom_auth_oauth.res_config_settings_view_form
-msgid ""
-"Is a temporary ticket for the H5 application to call the Wecom JS interface. "
-"Under normal circumstances, the validity period of jsapi_ticket is 7200 "
-"seconds , obtained by access_token. Since the number of API calls to the "
-"jsapi_ticket is very limited (an enterprise can get up to 400 times in an hour, "
-"and a single application cannot get more than 100 times), frequent refresh "
-"jsapi_ticket will cause the API call to be limited, affecting their own "
-"business, and developers must cache jsapi_ticket in their own service global "
-"cache ."
-msgstr ""
-"jsapi_ticket是H5应用调用企业微信JS接口的临时票据。正常情况下,jsapi_ticket的有"
-"效期为7200秒 ,通过access_token获得。由于API调用jsapi_ticket的次数非常有限(一"
-"小时内,一个企业最多可获取400次,且单个应用不能超过100次),频繁刷新jsapi_ticket"
-"会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存应用的"
-"jsapi_ticket 中。"
-
-#. module: wecom_auth_oauth
-#: model:ir.model.fields,field_description:wecom_auth_oauth.field_res_config_settings__auth_app_jsapi_ticket
-msgid "JSAPI Ticket"
-msgstr "JSAPI临时凭证"
-
-#. module: wecom_auth_oauth
-#: model:ir.model.fields,field_description:wecom_auth_oauth.field_res_config_settings__auth_app_jsapi_ticket_expiration_time
-msgid "JSAPI Ticket Expiration Time"
-msgstr "JSAPI临时凭证有效时间"
-
-#. module: wecom_auth_oauth
-#: model_terms:ir.ui.view,arch_db:wecom_auth_oauth.res_config_settings_view_form
-msgid "Management application"
-msgstr "管理应用"
-
-#. module: wecom_auth_oauth
-#: model:ir.model,name:wecom_auth_oauth.model_auth_oauth_provider
-msgid "OAuth2 provider"
-msgstr "OAuth2服务商"
-
-#. module: wecom_auth_oauth
-#. odoo-python
-#: code:addons/wecom_auth_oauth/models/wecom_apps.py:0
-#, python-format
-msgid "Please click on the 'Generate Parameters' button!"
-msgstr ""
-
-#. module: wecom_auth_oauth
-#: model:wecom.app_config,name:wecom_auth_oauth.wecom_app_config_authentication_qr_redirect_uri
-msgid "Scan the QR code to log in and call back the link address"
-msgstr ""
-
-#. module: wecom_auth_oauth
-#: model:ir.model.fields,field_description:wecom_auth_oauth.field_res_config_settings__auth_secret
-msgid "Secret"
-msgstr "密钥"
-
-#. module: wecom_auth_oauth
-#. odoo-python
-#: code:addons/wecom_auth_oauth/models/res_config_settings.py:0
-#, python-format
-msgid "Start getting ticket for company [%s]"
-msgstr ""
-
-#. module: wecom_auth_oauth
-#. odoo-python
-#: code:addons/wecom_auth_oauth/models/res_config_settings.py:0
-#, python-format
-msgid "Successfully obtained ticket!"
-msgstr ""
-
-#. module: wecom_auth_oauth
-#. odoo-python
-#: code:addons/wecom_auth_oauth/models/wecom_apps.py:0
-#, python-format
-msgid ""
-"The parameter \"Callback link address redirected after authorization\" does not "
-"exist!\n"
-"Please click on the 'Generate Parameters' button!\n"
-" "
-msgstr ""
-
-#. module: wecom_auth_oauth
-#. odoo-python
-#: code:addons/wecom_auth_oauth/models/wecom_apps.py:0
-#, python-format
-msgid ""
-"The parameter \"Scan the QR code to log in and call back the link address\" does "
-"not exist!\n"
-"Please click on the 'Generate Parameters' button!\n"
-" "
-msgstr ""
-
-#. module: wecom_auth_oauth
-#. odoo-python
-#: code:addons/wecom_auth_oauth/models/res_config_settings.py:0
-#, python-format
-msgid "Ticket is still valid, and no update is required!"
-msgstr "临时凭证仍然有效,不需要更新!"
-
-#. module: wecom_auth_oauth
-#. odoo-python
-#: code:addons/wecom_auth_oauth/models/res_config_settings.py:0
-#, python-format
-msgid "Tips"
-msgstr "提示"
-
-#. module: wecom_auth_oauth
-#: model:ir.model,name:wecom_auth_oauth.model_res_users
-msgid "User"
-msgstr "用户"
-
-#. module: wecom_auth_oauth
-#: model_terms:ir.ui.view,arch_db:wecom_auth_oauth.res_config_settings_view_form
-msgid "View OAuth providers"
-msgstr "查看OAuth提供程序"
-
-#. module: wecom_auth_oauth
-#: model:ir.model.fields,field_description:wecom_auth_oauth.field_auth_oauth_provider__is_woecom
-msgid "WeCom OAuth"
-msgstr "企业微信OAuth"
-
-#. module: wecom_auth_oauth
-#: model:auth.oauth.provider,body:wecom_auth_oauth.provider_wecom_quick_login
-msgid "WeCom quick login"
-msgstr "企微快速登录"
-
-#. module: wecom_auth_oauth
-#: model:ir.model,name:wecom_auth_oauth.model_wecom_apps
-msgid "Wecom Application"
-msgstr "企微应用"
diff --git a/wecom_auth_oauth/models/__init__.py b/wecom_auth_oauth/models/__init__.py
deleted file mode 100644
index b950dbe90..000000000
--- a/wecom_auth_oauth/models/__init__.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# -*- coding: utf-8 -*-
-
-
-from . import res_company
-from . import res_config_settings
-from . import auth_oauth
-from . import wecom_apps
-from . import res_users
diff --git a/wecom_auth_oauth/models/auth_oauth.py b/wecom_auth_oauth/models/auth_oauth.py
deleted file mode 100644
index 971a9fa59..000000000
--- a/wecom_auth_oauth/models/auth_oauth.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from odoo import fields, models
-
-
-class AuthOAuthProvider(models.Model):
- _inherit = "auth.oauth.provider"
-
- is_woecom = fields.Boolean(string="WeCom OAuth", default=False)
- description = fields.Html(string="Description", translate=True)
diff --git a/wecom_auth_oauth/models/res_company.py b/wecom_auth_oauth/models/res_company.py
deleted file mode 100644
index a87bcbcc5..000000000
--- a/wecom_auth_oauth/models/res_company.py
+++ /dev/null
@@ -1,82 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from odoo import models, fields, api, _
-from odoo.addons.wecom_api.api.wecom_abstract_api import ApiException # type: ignore
-
-
-import werkzeug.urls
-import werkzeug.utils
-import urllib
-import datetime
-import logging
-
-_logger = logging.getLogger(__name__)
-
-
-class Company(models.Model):
- _inherit = "res.company"
-
- auth_app_id = fields.Many2one(
- "wecom.apps",
- string="Application",
- # required=True,
- # default=lambda self: self.env.company,
- # domain="[('company_id', '=', current_company_id)]",
- domain="[('company_id', '=', current_company_id)]",
- )
-
- def set_oauth_provider_wxwork(self):
- web_base_url = self.env["ir.config_parameter"].get_param("web.base.url")
-
- new_auth_redirect_uri = (
- urllib.parse.urlparse(web_base_url).scheme # type: ignore
- + "://"
- + urllib.parse.urlparse(web_base_url).netloc # type: ignore
- + urllib.parse.urlparse(self.auth_redirect_uri).path # type: ignore
- )
- new_qr_redirect_uri = (
- urllib.parse.urlparse(web_base_url).scheme # type: ignore
- + "://"
- + urllib.parse.urlparse(web_base_url).netloc # type: ignore
- + urllib.parse.urlparse(self.qr_redirect_uri).path # type: ignore
- )
-
- # 设置回调链接地址
- self.auth_redirect_uri = new_auth_redirect_uri
- self.qr_redirect_uri = new_qr_redirect_uri
-
- auth_endpoint = "https://open.weixin.qq.com/connect/oauth2/authorize"
- qr_auth_endpoint = "https://open.work.weixin.qq.com/wwopen/sso/qrConnect"
-
- try:
- providers = (
- self.env["auth.oauth.provider"]
- .sudo()
- .search(
- [
- "|",
- ("enabled", "=", True),
- ("enabled", "=", False),
- ]
- )
- )
- except Exception:
- providers = []
-
- for provider in providers:
- if auth_endpoint in provider["auth_endpoint"]:
- provider.write(
- {
- # "client_id": client_id,
- "validation_endpoint": self.auth_redirect_uri,
- "enabled": True,
- }
- )
- if qr_auth_endpoint in provider["auth_endpoint"]:
- provider.write(
- {
- # "client_id": client_id,
- "validation_endpoint": self.qr_redirect_uri,
- "enabled": True,
- }
- )
diff --git a/wecom_auth_oauth/models/res_config_settings.py b/wecom_auth_oauth/models/res_config_settings.py
deleted file mode 100644
index 7a2cb3c6f..000000000
--- a/wecom_auth_oauth/models/res_config_settings.py
+++ /dev/null
@@ -1,149 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from datetime import datetime, timedelta
-from odoo import models, fields, api, _
-from odoo.exceptions import UserError, ValidationError
-
-from odoo.addons.wecom_api.api.wecom_abstract_api import ApiException # type: ignore
-
-
-import werkzeug.urls
-import werkzeug.utils
-import urllib
-import datetime
-import logging
-
-_logger = logging.getLogger(__name__)
-
-
-class ResConfigSettings(models.TransientModel):
- _inherit = "res.config.settings"
-
- company_id = fields.Many2one(
- "res.company",
- string="Company",
- required=True,
- default=lambda self: self.env.company,
- )
-
- auth_app_id = fields.Many2one(
- related="company_id.auth_app_id",
- readonly=False,
- )
- auth_agentid = fields.Integer(related="auth_app_id.agentid", readonly=False)
- auth_secret = fields.Char(related="auth_app_id.secret", readonly=False)
-
- auth_app_jsapi_ticket = fields.Char(
- related="auth_app_id.jsapi_ticket", readonly=False
- )
- auth_app_jsapi_ticket_expiration_time = fields.Datetime(
- related="auth_app_id.jsapi_ticket_expiration_time", readonly=False
- )
-
- auth_app_config_ids = fields.One2many(
- # related="company_id.contacts_auto_sync_hr_enabled", readonly=False
- related="auth_app_id.app_config_ids",
- # domain="[('company_id', '=', company_id),('app_id', '=', contacts_app_id)]",
- readonly=False,
- )
-
- def enable_wecom_quick_login(self):
- ir_model_data = self.env["ir.model.data"]
- provider_wecom_quick_login = ir_model_data._xmlid_lookup(
- "wecom_auth_oauth.provider_wecom_quick_login",
- )[1]
- providers = [provider_wecom_quick_login]
- for provider in providers:
- p = self.env["auth.oauth.provider"].search([("id", "=", provider)], limit=1)
- if p:
- p.enabled = True
-
- def set_oauth_provider_wecom(self):
- self.auth_app_id.set_oauth_provider_wecom() # type: ignore
-
- def generate_parameters(self):
- """
- 生成参数
- :return:
- """
- code = self.env.context.get("code")
- if bool(code) and code == "auth":
- for record in self:
- # if not record.contacts_app_id:
- # raise ValidationError(_("Please bind contact app!"))
- # else:
- record.auth_app_id.with_context(code=code).generate_parameters() # type: ignore
- super(ResConfigSettings, self).generate_parameters() # type: ignore
-
- def get_app_info(self):
- """
- 获取应用信息
- :return:
- """
- app = self.env.context.get("app")
- for record in self:
- if app == "auth" and (
- record.auth_app_id.agentid == 0 or record.auth_app_id.secret == "" # type: ignore
- ):
- raise UserError(_("Auth application ID and secret cannot be empty!"))
- else:
- record.auth_app_id.get_app_info() # type: ignore
- super(ResConfigSettings, self).get_app_info() # type: ignore
-
- def get_auth_app_jsapi_ticket(self):
- """
- 获取身份认证应用的jsapi_ticket
- :return:
- """
- ir_config = self.env["ir.config_parameter"].sudo()
- debug = ir_config.get_param("wecom.debug_enabled")
- if debug:
- _logger.info(
- _("Start getting ticket for company [%s]") % (self.company_id.name) # type: ignore
- )
- try:
- if (
- self.auth_app_jsapi_ticket_expiration_time
- and self.auth_app_jsapi_ticket_expiration_time > datetime.now()
- ):
- # 未过期,
- # print("未过期")
- msg = {
- "title": _("Tips"),
- "message": _("Ticket is still valid, and no update is required!"),
- "sticky": False,
- }
- return self.env["wecomapi.tools.action"].WecomInfoNotification(msg)
- else:
- # print("过期")
- wecom_api = self.env["wecom.service_api"].InitServiceApi(self.company_id.corpid, self.auth_app_id.secret) # type: ignore
- response = wecom_api.httpCall(
- self.env["wecom.service_api_list"].get_server_api_call(
- "AGENT_GET_TICKET"
- ),
- {"type": "agent_config"},
- )
- # print(response)
- except ApiException as ex:
- return self.env["wecomapi.tools.action"].ApiExceptionDialog(
- ex, raise_exception=True
- )
- else:
- if response["errcode"] == 0:
- self.write(
- {
- "auth_app_jsapi_ticket": response["ticket"],
- "auth_app_jsapi_ticket_expiration_time": datetime.now()
- + timedelta(seconds=response["expires_in"]),
- }
- )
- msg = {
- "title": _("Tips"),
- "message": _("Successfully obtained ticket!"),
- "sticky": False,
- "next": {
- "type": "ir.actions.client",
- "tag": "reload",
- },
- }
- return self.env["wecomapi.tools.action"].WecomSuccessNotification(msg)
diff --git a/wecom_auth_oauth/models/res_users.py b/wecom_auth_oauth/models/res_users.py
deleted file mode 100644
index 85789ec14..000000000
--- a/wecom_auth_oauth/models/res_users.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from odoo import models, api, _
-from odoo.exceptions import AccessDenied
-
-
-class ResUsers(models.Model):
- _inherit = "res.users"
-
- # ---------------------
- # 验证
- # ---------------------
- @api.model
- def wecom_auth_oauth(self, provider, params):
- """
- 允许一键登录和扫码登录且标记了企业微信的用户登录系统
- :param provider:
- :param params:
- :return:
- """
- wecom_web_auth_endpoint = "https://open.weixin.qq.com/connect/oauth2/authorize"
- wecom_qr_auth_endpoint = "https://open.work.weixin.qq.com/wwopen/sso/qrConnect"
-
- wecom_providers = (
- self.env["auth.oauth.provider"].sudo().search([("id", "=", provider),])
- )
-
- if (
- wecom_web_auth_endpoint in wecom_providers["auth_endpoint"]
- or wecom_qr_auth_endpoint in wecom_providers["auth_endpoint"]
- ):
- # 扫码登录
- oauth_userid = params["UserId"].lower()
- oauth_user = self.search(
- [
- # ("oauth_uid", "=", oauth_userid),
- ("wecom_userid", "=", oauth_userid),
- ("is_wecom_user", "=", True),
- ("active", "=", True),
- ]
- )
-
- if not oauth_user or len(oauth_user) > 1:
- return AccessDenied
- return (self.env.cr.dbname, oauth_user.login, oauth_userid) # type: ignore
- else:
- return AccessDenied
-
-
- def _check_credentials(self, password, env):
- # password为企业微信的用户ID
- try:
- return super(ResUsers, self)._check_credentials(password, env) # type: ignore
- except AccessDenied:
- res = self.sudo().search(
- [("id", "=", self.env.uid), ("wecom_userid", "=", password)]
- )
- if not res:
- raise
diff --git a/wecom_auth_oauth/models/wecom_apps.py b/wecom_auth_oauth/models/wecom_apps.py
deleted file mode 100644
index 7b46c9736..000000000
--- a/wecom_auth_oauth/models/wecom_apps.py
+++ /dev/null
@@ -1,152 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import logging
-import datetime
-import werkzeug.utils
-import urllib
-from odoo import _, api, fields, models
-from odoo.exceptions import UserError
-
-
-_logger = logging.getLogger(__name__)
-
-
-class WeComApps(models.Model):
- _inherit = "wecom.apps"
-
- def generate_parameters_by_code(self, code):
- """
- 根据code生成参数
- :param code:
- :return:
- """
- if code == "auth":
- ir_model_data = self.env["ir.model.data"]
- auth_redirect_uri = ir_model_data.get_object_reference(
- "wecom_auth_oauth", "wecom_app_config_authentication_auth_redirect_uri"
- )[1]
- qr_redirect_uri = ir_model_data.get_object_reference(
- "wecom_auth_oauth", "wecom_app_config_authentication_qr_redirect_uri"
- )[1]
- vals_list = [
- auth_redirect_uri,
- qr_redirect_uri,
- ]
-
- for id in vals_list:
- app_config_id = self.env["wecom.app_config"].search([("id", "=", id)])
- app_config = (
- self.env["wecom.app_config"]
- .sudo()
- .search([("app_id", "=", self.id), ("key", "=", app_config_id.key)]) # type: ignore
- )
- if not app_config:
- app_config = (
- self.env["wecom.app_config"]
- .sudo()
- .create(
- {
- "name": app_config_id.name,
- "app_id": self.id, # type: ignore
- "key": app_config_id.key,
- "ttype": app_config_id.ttype,
- "value": app_config_id.value,
- "description": app_config_id.description,
- }
- )
- )
- else:
- app_config.sudo().write(
- {
- "name": app_config_id.name,
- "value": app_config_id.value,
- "description": app_config_id.description,
- }
- )
- super(WeComApps, self).generate_parameters_by_code(code) # type: ignore
-
- # ————————————————————————————————————
- # 设置认证应用配置
- # ————————————————————————————————————
- def set_oauth_provider_wecom(self):
- web_base_url = self.env["ir.config_parameter"].get_param("web.base.url")
- auth_redirect_uri = None
- qr_redirect_uri = None
- if len(self.app_config_ids) > 0: # type: ignore
- for record in self.app_config_ids: # type: ignore
- if record["key"] == "auth_redirect_uri":
- auth_redirect_uri = record
- else:
- raise UserError(
- _(
- """The parameter "Callback link address redirected after authorization" does not exist!
-Please click on the 'Generate Parameters' button!
- """
- )
- )
-
- if record["key"] == "qr_redirect_uri":
- qr_redirect_uri = record
- else:
- raise UserError(
- _(
- """The parameter "Scan the QR code to log in and call back the link address" does not exist!
-Please click on the 'Generate Parameters' button!
- """
- )
- )
-
- new_auth_redirect_uri = (
- urllib.parse.urlparse(web_base_url).scheme # type: ignore
- + "://"
- + urllib.parse.urlparse(web_base_url).netloc # type: ignore
- + urllib.parse.urlparse(auth_redirect_uri.value).path # type: ignore
- )
- new_qr_redirect_uri = (
- urllib.parse.urlparse(web_base_url).scheme # type: ignore
- + "://"
- + urllib.parse.urlparse(web_base_url).netloc # type: ignore
- + urllib.parse.urlparse(qr_redirect_uri.value).path # type: ignore
- )
-
- # 设置应用参数中的回调链接地址
- auth_redirect_uri.write({"value": new_auth_redirect_uri}) # type: ignore
- qr_redirect_uri.write({"value": new_qr_redirect_uri}) # type: ignore
-
- auth_endpoint = "https://open.weixin.qq.com/connect/oauth2/authorize"
- qr_auth_endpoint = "https://open.work.weixin.qq.com/wwopen/sso/qrConnect"
-
- try:
- providers = (
- self.env["auth.oauth.provider"]
- .sudo()
- .search(
- [
- "|",
- ("enabled", "=", True),
- ("enabled", "=", False),
- ]
- )
- )
- except Exception:
- providers = []
-
- for provider in providers:
- if auth_endpoint in provider["auth_endpoint"]:
- provider.write(
- {
- # "client_id": client_id,
- "validation_endpoint": auth_redirect_uri,
- "enabled": True,
- }
- )
- if qr_auth_endpoint in provider["auth_endpoint"]:
- provider.write(
- {
- # "client_id": client_id,
- "validation_endpoint": qr_redirect_uri,
- "enabled": True,
- }
- )
- else:
- raise UserError(_("Please click on the 'Generate Parameters' button!"))
diff --git a/wecom_auth_oauth/static/description/icon.png b/wecom_auth_oauth/static/description/icon.png
deleted file mode 100644
index d9ad0e0b3..000000000
Binary files a/wecom_auth_oauth/static/description/icon.png and /dev/null differ
diff --git a/wecom_auth_oauth/static/src/js/wecom_join/wecom_join.js b/wecom_auth_oauth/static/src/js/wecom_join/wecom_join.js
deleted file mode 100644
index bad1b22c7..000000000
--- a/wecom_auth_oauth/static/src/js/wecom_join/wecom_join.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/** @odoo-module **//** @odoo-module **/
-
-import publicWidget from "@web/legacy/js/public/public_widget";
-// import * as ww from '@wecom/jssdk'
-
-publicWidget.registry.WecomJion = publicWidget.Widget.extend({
- selector: 'form.oe_login_form',
-
- init() {
- this._super(...arguments);
- this.rpc = this.bindService("rpc");
- },
- start: function () {
- this.companies = this.rpc({
- route: "/wecom_login_info",
- params: {
-
- },
- });
- },
-});
diff --git a/wecom_auth_oauth/static/src/js/wecom_join/wecom_join.xml b/wecom_auth_oauth/static/src/js/wecom_join/wecom_join.xml
deleted file mode 100644
index e3d8171ea..000000000
--- a/wecom_auth_oauth/static/src/js/wecom_join/wecom_join.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/wecom_auth_oauth/static/src/js/wecom_login/wecom_login.js b/wecom_auth_oauth/static/src/js/wecom_login/wecom_login.js
deleted file mode 100644
index 9d73eb0ab..000000000
--- a/wecom_auth_oauth/static/src/js/wecom_login/wecom_login.js
+++ /dev/null
@@ -1,20 +0,0 @@
-/** @odoo-module **/
-
-import publicWidget from "@web/legacy/js/public/public_widget";
-// import * as ww from '@wecom/jssdk'
-
-publicWidget.registry.WecomLogin = publicWidget.Widget.extend({
- selector: '.o_login_auth',
-
- events: {
- 'click a': '_onClick',
- },
- jsLibs: [
- document.location.protocol + "//wwcdn.weixin.qq.com/node/open/js/wecom-jssdk-1.3.1.js",
- ],
- _onClick: async function (ev) {
- ev.preventDefault(); //阻止默认行为
- let auth_url = $(ev.currentTarget).attr('href');
- console.log(auth_url);
- },
-});
diff --git a/wecom_auth_oauth/static/src/js/wecom_login/wecom_login.xml b/wecom_auth_oauth/static/src/js/wecom_login/wecom_login.xml
deleted file mode 100644
index e3d8171ea..000000000
--- a/wecom_auth_oauth/static/src/js/wecom_login/wecom_login.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/wecom_auth_oauth/views/auth_oauth_views.xml b/wecom_auth_oauth/views/auth_oauth_views.xml
deleted file mode 100644
index 223f8e784..000000000
--- a/wecom_auth_oauth/views/auth_oauth_views.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
- auth.oauth.provider.tree
- auth.oauth.provider
-
-
-
-
-
-
-
-
-
-
-
- auth.oauth.provider.form
- auth.oauth.provider
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_auth_oauth/views/res_config_settings_views.xml b/wecom_auth_oauth/views/res_config_settings_views.xml
deleted file mode 100644
index 98779c255..000000000
--- a/wecom_auth_oauth/views/res_config_settings_views.xml
+++ /dev/null
@@ -1,130 +0,0 @@
-
-
-
-
- Settings
- res.config.settings
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Save this page and come back here to set up other feature.
-
-
-
-
-
-
-
-
-
-
-
-
- Application Management→Application→Open the application that needs to be verified and authorized, copy 'AgentId'
-
-
-
-
-
-
-
-
-
-
-
-
-
- Application Management→Application→Open the application that needs to be verified and authorized, copy 'Secret'
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Is a temporary ticket for the H5 application to call the Wecom JS interface. Under normal circumstances, the validity period of jsapi_ticket is 7200 seconds , obtained by access_token. Since the number of API calls to the jsapi_ticket is very limited (an enterprise can get up to 400 times in an hour, and a single application cannot get more than 100 times), frequent refresh jsapi_ticket will cause the API call to be limited, affecting their own business, and developers must cache jsapi_ticket in their own service global cache .
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/wecom_base/__init__.py b/wecom_base/__init__.py
deleted file mode 100644
index 8cbcc732a..000000000
--- a/wecom_base/__init__.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from . import models
-
-
-def post_init_hook(env):
- # env["ir.http"].clear_caches()
- # env["ir.ui.view"].clear_caches()
- env["ir.http"]._invalidate_cache()
- env["ir.ui.view"]._invalidate_cache()
diff --git a/wecom_base/__manifest__.py b/wecom_base/__manifest__.py
deleted file mode 100644
index ec32486f3..000000000
--- a/wecom_base/__manifest__.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# -*- coding: utf-8 -*-
-
-{
- "name": "WeCom Base",
- "author": "RStudio",
- "sequence": 601,
- "installable": True,
- "application": True,
- "auto_install": False,
- "category": "WeCom Suites/Settings",
- "website": "https://gitee.com/rainbowstudio/wecom",
- "version": "17.0.0.1",
- "summary": """
-
- """,
- "description": """
-
- """,
- "depends": ["base_setup", "wecom_widget", "wecom_api"],
- "data": [
- "security/wecom_security.xml",
- "security/ir.model.access.csv",
- "data/ir_module_category_data.xml",
- "data/ir_config_parameter.xml",
- "data/ir_cron_data.xml",
- "data/wecom_app_type_data.xml",
- "views/ir_cron_views.xml",
- "views/res_config_settings_views.xml",
- "views/res_company_views.xml",
- "views/wecom_service_api_list_views.xml",
- "views/wecom_service_api_error_views.xml",
- "views/wecom_apps_views.xml",
- "views/wecom_app_config_views.xml",
- "views/wecom_app_callback_service_views.xml",
- "views/wecom_app_event_type_views.xml",
- "views/wecom_app_type_views.xml",
- "views/wecom_app_subtype_views.xml",
- "views/wecom_base_views.xml",
- "views/menu_views.xml",
- ],
- "assets": {
- "web.assets_backend": [
- "wecom_base/static/src/views/**/*",
- ],
- },
- "license": "AGPL-3",
- "bootstrap": True,
- "post_init_hook": "post_init_hook",
-}
diff --git a/wecom_base/data/ir_config_parameter.xml b/wecom_base/data/ir_config_parameter.xml
deleted file mode 100644
index 3860b7d55..000000000
--- a/wecom_base/data/ir_config_parameter.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_base/data/ir_cron_data.xml b/wecom_base/data/ir_cron_data.xml
deleted file mode 100644
index 50be60bbf..000000000
--- a/wecom_base/data/ir_cron_data.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
- WeCom: Get the global error code of WeCom.
-
- code
- model.cron_pull_global_error_code()
-
- 7
- days
- -1
-
-
-
-
-
- WeCom: Get app token
-
- code
- model.cron_get_app_token()
-
- 2
- hours
- -1
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_base/data/ir_module_category_data.xml b/wecom_base/data/ir_module_category_data.xml
deleted file mode 100644
index b2d8f9991..000000000
--- a/wecom_base/data/ir_module_category_data.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
- WeCom Settings
- 1
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_base/data/res_company_data.xml b/wecom_base/data/res_company_data.xml
deleted file mode 100644
index 66ed4cc2b..000000000
--- a/wecom_base/data/res_company_data.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
- My Company
-
-
-
\ No newline at end of file
diff --git a/wecom_base/data/wecom_app_type_data.xml b/wecom_base/data/wecom_app_type_data.xml
deleted file mode 100644
index bcbfadfd2..000000000
--- a/wecom_base/data/wecom_app_type_data.xml
+++ /dev/null
@@ -1,186 +0,0 @@
-
-
-
-
-
-
-
-
- Manage Tools
- manage
- 1
-
-
-
-
- Base application
- base
- 2
-
-
-
-
- External contact
- external_contact
- 3
-
-
-
-
- Self built application
- self
- 4
-
-
-
-
- Third party application
- third
- 5
-
-
-
-
-
-
- Contacts management
-
- contacts
- 1
-
-
-
-
- Customer contact
-
- customer
- 2
-
-
-
-
- Wechat customer service
-
- kf
- 3
-
-
-
-
- Authentication
-
- auth
- 4
-
-
-
-
- Application management
-
- app
- 5
-
-
-
-
- Message push
-
- message
- 6
-
-
-
-
- Material management
-
- material
- 7
-
-
-
-
- OA:Checkin
-
- checkin
- 8
-
-
-
-
- OA:Approval
-
- approval
- 9
-
-
-
-
- OA:Journal
-
- journal
- 10
-
-
-
-
- OA:Meeting room
-
- meetingroom
- 11
-
-
-
-
- Efficiency tools:Corporate email
-
- exmail
- 12
-
-
-
-
- Efficiency tools:Calendar
-
- calendar
- 13
-
-
-
-
- Efficiency tools:Living
-
- living
- 14
-
-
-
-
- Efficiency tools:We Drive
-
- wedrive
- 15
-
-
-
-
- Efficiency tools:Public telephone
-
- dial
- 16
-
-
-
-
- Session content archiving
-
- msgaudit
- 17
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_base/i18n/zh_CN.po b/wecom_base/i18n/zh_CN.po
deleted file mode 100644
index ea97afb4c..000000000
--- a/wecom_base/i18n/zh_CN.po
+++ /dev/null
@@ -1,1318 +0,0 @@
-# Translation of Odoo Server.
-# This file contains the translation of the following modules:
-# * wecom_base
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: Odoo Server 17.0\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2024-03-12 09:03+0000\n"
-"PO-Revision-Date: 2024-03-12 17:04+0800\n"
-"Last-Translator: \n"
-"Language-Team: \n"
-"Language: zh_CN\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Poedit 3.4.2\n"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_apps_form
-msgid ""
-"Callback AES Key: Copy the randomly generated \"EncodingAESKey\" in the \"event "
-"receiving server\" of the Wecom application to the \"callback AES key\" input box on the "
-"current page."
-msgstr ""
-"回调AES密钥: 将企业微信应用程序“事件接收服务器”中随机生成的“EncodingAESKey”复制到"
-"\"当前页面的“回调AES密钥”输入框中。"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_apps_form
-msgid ""
-"Callback URL Token: Copy the randomly generated \"Token\" in the \"event "
-"receiving server\" of the Wecom application to the \"callback URL token\" input box of "
-"the current page."
-msgstr ""
-"回调URL令牌: 将企业微信应用“事件接收服务器”中随机生成的“令牌”复制到当前页面的“回"
-"调URL令牌”输入框中。"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_apps_form
-msgid ""
-"Callback URL: Copy the automatically generated callback URL to the URL in the "
-"\"event receiving server\" of the Wecom application."
-msgstr ""
-"回调URL: 将自动生成的回调URL复制到企业微信应用程序“事件接收服务器”中的URL。"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_apps_form
-msgid ""
-"Change: When the value of \"receiving event server\" of the current page and "
-"Wecom application changes, please ensure that the values at both ends are consistent."
-msgstr ""
-"更改: 当前页面的“回调服务设置”和企业微信应用的“接收事件服务器”值发生变化时,请确保"
-"两端的值一致。"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_apps_form
-msgid ""
-"Controller: Make sure the \"Callback Service Name\" exists in your controller "
-"code."
-msgstr "控制器: 确保控制器代码中存在“回调服务名称”。"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.res_config_settings_view_form
-msgid ""
-" "
-msgstr ""
-""
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_apps_kanban
-msgid ""
-msgstr ""
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_apps_kanban
-msgid ""
-msgstr ""
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.res_config_settings_view_form
-msgid " "
-msgstr ""
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.res_config_settings_view_form
-msgid ""
-" "
-msgstr ""
-""
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.res_config_settings_view_form
-msgid ""
-" "
-msgstr ""
-""
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.res_config_settings_view_form
-msgid ""
-" "
-msgstr ""
-" "
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.res_config_settings_view_form
-msgid "Save this page and come back here to set up other feature."
-msgstr "保存 此页面并返回此处以设置其它功能。"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.res_config_settings_view_form
-msgid "Save this page and come back here to set up the feature."
-msgstr "保存 此页面并返回此处以设置功能。"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_callback_service__callback_aeskey
-msgid "AES Key"
-msgstr "AES密钥"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_service_api_list_filter
-msgid "API"
-msgstr ""
-
-#. module: wecom_base
-#: model:ir.actions.act_window,name:wecom_base.action_view_wecom_service_api_list
-msgid "API List"
-msgstr "API列表"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__access_token
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_apps_form
-msgid "Access Token"
-msgstr "访问令牌"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_callback_service__active
-msgid "Active"
-msgstr "有效"
-
-#. module: wecom_base
-#: model:res.groups,name:wecom_base.group_wecom_settings_manager
-msgid "Administrator"
-msgstr "管理员"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__agentid
-msgid "Agent ID"
-msgstr "应用ID"
-
-#. module: wecom_base
-#: model:ir.actions.act_window,name:wecom_base.action_view_wecom_apps_list
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_callback_service__app_id
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_config__app_id
-msgid "Application"
-msgstr "应用"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__app_config_ids
-msgid "Application Configuration"
-msgstr "应用配置"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__app_name
-msgid "Application Name"
-msgstr "应用名称"
-
-#. module: wecom_base
-#: model:ir.actions.act_window,name:wecom_base.wecom_app_config_list_action
-#: model:ir.ui.menu,name:wecom_base.menu_wecom_agent_config
-msgid "Application Parameters"
-msgstr "应用参数"
-
-#. module: wecom_base
-#: model:ir.actions.act_window,name:wecom_base.wecom_app_subtype_list_action
-msgid "Application SubType"
-msgstr "应用子类型"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_type__subtype_ids
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__subtype_ids
-msgid "Application Subtype"
-msgstr "应用子类型"
-
-#. module: wecom_base
-#: model:ir.actions.act_window,name:wecom_base.wecom_app_type_list_action
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__type
-#: model:ir.ui.menu,name:wecom_base.menu_wecom_agent_type
-msgid "Application Type"
-msgstr "应用类型"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__type_id
-msgid "Application Types"
-msgstr "应用类型"
-
-#. module: wecom_base
-#: model:ir.ui.menu,name:wecom_base.menu_wecom_agent_event
-msgid "Application event"
-msgstr "应用事件"
-
-#. module: wecom_base
-#: model:ir.ui.menu,name:wecom_base.menu_wecom_agent_list
-msgid "Application list"
-msgstr "应用列表"
-
-#. module: wecom_base
-#: model:wecom.app.subtype,name:wecom_base.wecom_app_subtype_app
-msgid "Application management"
-msgstr "应用管理"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__menu_body
-msgid "Application menu data"
-msgstr "应用菜单数据"
-
-#. module: wecom_base
-#: model:ir.actions.act_window,name:wecom_base.wecom_app_callback_service_list_action
-msgid "Application receive event service"
-msgstr "应用接收事件服务"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__type_code
-msgid "Application type code"
-msgstr "应用类型代码"
-
-#. module: wecom_base
-#: model:wecom.app.subtype,name:wecom_base.wecom_app_subtype_auth
-msgid "Authentication"
-msgstr "身份验证"
-
-#. module: wecom_base
-#. odoo-python
-#: code:addons/wecom_base/models/wecom_apps.py:0
-#, python-format
-msgid "Automatic task: start to get the application [%s] token of company [%s]"
-msgstr "自动任务:开始获取公司[%s]的应用[%s]令牌基础应用"
-
-#. module: wecom_base
-#: model:wecom.app.type,name:wecom_base.wecom_app_type_base
-msgid "Base application"
-msgstr "基础应用"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_apps_form
-msgid "Button group"
-msgstr "按钮组"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_apps_form
-msgid "Callback service settings"
-msgstr "回调服务设置"
-
-#. module: wecom_base
-#. odoo-python
-#: code:addons/wecom_base/models/wecom_app_event_type.py:0
-#, python-format
-msgid "Cannot find [%s] change type for executing company [%s], ignoring it."
-msgstr "找不到执行公司 [%s] 的 [%s] 更改类型,将忽略它。"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_event_type__change_type
-msgid "Change Type"
-msgstr "变更类型"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.res_config_settings_view_form
-msgid ""
-"Check, print some debugging information in IDE and log;\n"
-" \n"
-" For debugging"
-msgstr ""
-"启用, 在IED和Odoo日志中显示日志;\n"
-" \n"
-" 于调试"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_subtype__code
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_type__code
-msgid "Code"
-msgstr "代码"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_app_event_type_form
-msgid "Code and Command"
-msgstr "代码和指令"
-
-#. module: wecom_base
-#. odoo-python
-#: code:addons/wecom_base/models/wecom_app_subtype.py:0
-#: code:addons/wecom_base/models/wecom_app_type.py:0
-#: model:ir.model.constraint,message:wecom_base.constraint_wecom_app_subtype_code_uniq
-#: model:ir.model.constraint,message:wecom_base.constraint_wecom_app_type_code_uniq
-#, python-format
-msgid "Code must be unique !"
-msgstr "代码必须是唯一的!"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_event_type__command
-msgid "Command"
-msgstr "指令"
-
-#. module: wecom_base
-#: model:ir.model,name:wecom_base.model_res_company
-#: model_terms:ir.ui.view,arch_db:wecom_base.res_config_settings_view_form
-msgid "Companies"
-msgstr "公司"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_config__company_id
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__company_id
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_apps_filter
-msgid "Company"
-msgstr "公司"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_res_config_settings__company_name
-msgid "Company Name"
-msgstr "公司名称"
-
-#. module: wecom_base
-#: model:ir.model,name:wecom_base.model_res_config_settings
-msgid "Config Settings"
-msgstr "配置设置"
-
-#. module: wecom_base
-#: model:ir.model,name:wecom_base.model_res_partner
-msgid "Contact"
-msgstr "通讯录"
-
-#. module: wecom_base
-#: model:wecom.app.subtype,name:wecom_base.wecom_app_subtype_contacts_management
-msgid "Contacts management"
-msgstr "通讯录管理"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_res_company__corpid
-#: model:ir.model.fields,field_description:wecom_base.field_res_config_settings__corpid
-msgid "Corp ID"
-msgstr "企业Id"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_res_company__corp_jsapi_ticket
-#: model:ir.model.fields,field_description:wecom_base.field_res_config_settings__corp_jsapi_ticket
-msgid "Corp JSAPI Ticket"
-msgstr "公司JSAPI临时凭证"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_callback_service__create_uid
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_config__create_uid
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_event_type__create_uid
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_subtype__create_uid
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_type__create_uid
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__create_uid
-msgid "Created by"
-msgstr "创建者"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_callback_service__create_date
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_config__create_date
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_event_type__create_date
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_subtype__create_date
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_type__create_date
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__create_date
-msgid "Created on"
-msgstr "创建时间"
-
-#. module: wecom_base
-#: model:wecom.app.subtype,name:wecom_base.wecom_app_subtype_customer_contact
-msgid "Customer contact"
-msgstr "客户联系"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_callback_service__description
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_config__description
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__description
-msgid "Description"
-msgstr "应用详情"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_apps_form
-msgid ""
-"Developers need to cache access_token for subsequent interface calls (note: gettoken "
-"interfaces cannot be called frequently or are frequently blocked). When access_token "
-"expires or expires, it needs to be re-acquired."
-msgstr ""
-"开发者需要缓存access_token,用于后续接口的调用(注意:不能频繁调用gettoken接口,否则会受"
-"到频率拦截)。当access_token失效或过期时,需要重新获取。"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__close
-msgid "Disabled"
-msgstr "停用"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_callback_service__display_name
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_config__display_name
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_event_type__display_name
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_subtype__display_name
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_type__display_name
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__display_name
-msgid "Display Name"
-msgstr "显示名称"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_apps_form
-msgid ""
-"Each app has a separate access_token can only be used by this app, so the access_token "
-"for each app should be obtained separately"
-msgstr ""
-"每个应用有独立的secret,获取到的access_token只能本应用使用,所以每个应用的access_token应"
-"该分开来获取"
-
-#. module: wecom_base
-#: model:wecom.app.subtype,name:wecom_base.wecom_app_subtype_efficiency_tools_calendar
-msgid "Efficiency tools:Calendar"
-msgstr "效率工具:日程"
-
-#. module: wecom_base
-#: model:wecom.app.subtype,name:wecom_base.wecom_app_subtype_efficiency_tools_exmail
-msgid "Efficiency tools:Corporate email"
-msgstr "效率工具:企业邮箱"
-
-#. module: wecom_base
-#: model:wecom.app.subtype,name:wecom_base.wecom_app_subtype_efficiency_tools_living
-msgid "Efficiency tools:Living"
-msgstr "效率工具:直播"
-
-#. module: wecom_base
-#: model:wecom.app.subtype,name:wecom_base.wecom_app_subtype_efficiency_tools_dial
-msgid "Efficiency tools:Public telephone"
-msgstr "效率工具:公费电话"
-
-#. module: wecom_base
-#: model:wecom.app.subtype,name:wecom_base.wecom_app_subtype_efficiency_tools_wedrive
-msgid "Efficiency tools:We Drive"
-msgstr "效率工具:微盘"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.wecom_service_api_error_tree
-msgid "Error"
-msgstr "错误"
-
-#. module: wecom_base
-#: model:ir.actions.act_window,name:wecom_base.action_view_wecom_service_api_error
-#: model:ir.ui.menu,name:wecom_base.menu_wecom_service_api_error
-msgid "Error Code"
-msgstr "错误代码"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_service_api_error_filter
-msgid "Errors"
-msgstr "错误"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_event_type__event
-msgid "Event Code"
-msgstr "事件代码"
-
-#. module: wecom_base
-#: model:ir.actions.act_window,name:wecom_base.action_view_wecom_app_event_type_list
-#: model:ir.ui.menu,name:wecom_base.menu_wecom_agent_event_type
-msgid "Event Type"
-msgstr "事件类型"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_res_company__corp_jsapi_ticket_expiration_time
-#: model:ir.model.fields,field_description:wecom_base.field_res_config_settings__corp_jsapi_ticket_expiration_time
-msgid "Expiration time of Corp JSAPI ticket"
-msgstr "企微JSAPI临时凭证的有效时间"
-
-#. module: wecom_base
-#: model:wecom.app.type,name:wecom_base.wecom_app_type_external_contact
-msgid "External contact"
-msgstr "外部联系"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_config__ttype
-msgid "Field Type"
-msgstr "字段类型"
-
-#. module: wecom_base
-#. odoo-python
-#: code:addons/wecom_base/models/wecom_app_event_type.py:0
-#, python-format
-msgid "Function [%s] does not exist in model [%s]"
-msgstr "模型[%s]中不存在函数[%s]"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_app_callback_service_form
-msgid "Generate contact service"
-msgstr "生成通讯录服务"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_apps_form
-msgid "Generate parameters"
-msgstr "生成参数"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_apps_form
-msgid "Generate service"
-msgstr "生成服务"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_apps_form
-msgid "Get Access Token"
-msgstr "获取访问令牌"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_apps_form
-msgid "Get JSAPI Ticket"
-msgstr "获取JSAPI临时凭证"
-
-#. module: wecom_base
-#: model:ir.ui.menu,name:wecom_base.menu_wecom_app_get_token
-msgid "Get app token"
-msgstr "获取应用令牌"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_apps_form
-msgid "Get application"
-msgstr "获取应用"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.res_config_settings_view_form
-msgid ""
-"Get the [Code Name] and [Troubleshooting Method] of the global error code through the "
-"code"
-msgstr "通过路径代码获取全局错误代码的[代码号]和[排查方法]"
-
-#. module: wecom_base
-#: model:ir.ui.menu,name:wecom_base.menu_wecom_service_api_error_get
-msgid "Get the global error code"
-msgstr "获取全局错误代码"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_apps_form
-msgid ""
-"Getting access_token is the first step in calling the Wecom API interface, which is "
-"equivalent to creating a login credential, and other business API interfaces all need to "
-"rely on access_token to authentice the caller's identity."
-msgstr ""
-"获取access_token是调用企业微信API接口的第一步,相当于创建了一个登录凭证,其它的业务API接"
-"口,都需要依赖于access_token来鉴权调用者身份。"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_res_config_settings__global_error_code_item_selection_code
-msgid "Global error code item selection code"
-msgstr "全局错误代码项路径选择代码"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_res_config_settings__global_error_code_url
-msgid "Global error code page URL"
-msgstr "全局错误代码页URL"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_apps_filter
-msgid "Group By"
-msgstr "分组"
-
-#. module: wecom_base
-#: model:ir.model,name:wecom_base.model_ir_http
-msgid "HTTP Routing"
-msgstr "HTTP 路由"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__home_url
-msgid "Home page"
-msgstr "首页"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_callback_service__id
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_config__id
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_event_type__id
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_subtype__id
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_type__id
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__id
-msgid "ID"
-msgstr ""
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__jsapi_ticket
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_apps_form
-msgid "JSAPI Ticket"
-msgstr "JSAPI临时凭证"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__jsapi_ticket_expiration_time
-msgid "JSAPI Ticket Expiration Time"
-msgstr "JSAPI临时凭证有效时间"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_config__key
-msgid "Key"
-msgstr "键"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_callback_service__write_uid
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_config__write_uid
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_event_type__write_uid
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_subtype__write_uid
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_type__write_uid
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__write_uid
-msgid "Last Updated by"
-msgstr "最后更新人"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_callback_service__write_date
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_config__write_date
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_event_type__write_date
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_subtype__write_date
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_type__write_date
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__write_date
-msgid "Last Updated on"
-msgstr "最后修改时间"
-
-#. module: wecom_base
-#: model:ir.ui.menu,name:wecom_base.menu_wecom_service_api_list
-msgid "List"
-msgstr "列表"
-
-#. module: wecom_base
-#: model:wecom.app.type,name:wecom_base.wecom_app_type_manage
-msgid "Manage Tools"
-msgstr "管理工具"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.res_config_settings_view_form
-msgid "Manage all companies"
-msgstr "管理所有公司"
-
-#. module: wecom_base
-#: model:wecom.app.subtype,name:wecom_base.wecom_app_subtype_material_management
-msgid "Material management"
-msgstr "素材管理"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_event_type__msg_type
-msgid "Message Type"
-msgstr "消息的类型"
-
-#. module: wecom_base
-#: model:wecom.app.subtype,name:wecom_base.wecom_app_subtype_message_push
-msgid "Message push"
-msgstr "消息推送"
-
-#. module: wecom_base
-#. odoo-python
-#: code:addons/wecom_base/models/wecom_app_event_type.py:0
-#, python-format
-msgid "Method [%s] to execute model [%s]"
-msgstr "执行模型 [%s] 的方法 [%s]"
-
-#. module: wecom_base
-#: model:ir.model,name:wecom_base.model_ir_module_module
-msgid "Module"
-msgstr "模块"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_config__name
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_event_type__name
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_subtype__name
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_type__name
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__name
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_app_subtype_filter
-msgid "Name"
-msgstr "名称"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_apps_form
-msgid ""
-"Normally, the app's jsapi_ticket is valid for 7200 seconds and is obtained by "
-"access_token. Since the number of API calls to get jsapi_ticket is very limited (each "
-"application cannot exceed 100 times in an hour), frequent refresh jsapi_ticket will "
-"cause the API call to be limited, affecting their own business, and developers must "
-"globally cache the jsapi_ticket of the application in their own services."
-msgstr ""
-"正常情况下,应用的jsapi_ticket的有效期为7200秒,通过access_token来获取。由于获取"
-"jsapi_ticket的api调用次数非常有限(一小时内,每个应用不能超过100次),频繁刷新"
-"jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存应用的"
-"jsapi_ticket。"
-
-#. module: wecom_base
-#: model:wecom.app.subtype,name:wecom_base.wecom_app_subtype_oa_approval
-msgid "OA:Approval"
-msgstr "OA:审批"
-
-#. module: wecom_base
-#: model:wecom.app.subtype,name:wecom_base.wecom_app_subtype_oa_checkin
-msgid "OA:Checkin"
-msgstr "OA:打卡"
-
-#. module: wecom_base
-#: model:wecom.app.subtype,name:wecom_base.wecom_app_subtype_oa_journal
-msgid "OA:Journal"
-msgstr "OA:汇报"
-
-#. module: wecom_base
-#: model:wecom.app.subtype,name:wecom_base.wecom_app_subtype_oa_meetingroom
-msgid "OA:Meeting room"
-msgstr "OA:会议室"
-
-#. module: wecom_base
-#: model:res.groups,name:wecom_base.group_wecom_settings_user
-msgid "Officer"
-msgstr "主管"
-
-#. module: wecom_base
-#. odoo-python
-#: code:addons/wecom_base/models/wecom_apps.py:0
-#, python-format
-msgid "Only one subtype can be selected for the current app type!"
-msgstr "当前应用类型只能选择一个子类型!"
-
-#. module: wecom_base
-#: model:ir.actions.client,name:wecom_base.action_open_wecom_configurator
-msgid "Open Wecom Configurator"
-msgstr "打开企微配置"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__report_location_flag
-msgid "Open the geographic location and report"
-msgstr "打开地理位置上报"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_apps_form
-msgid "Option"
-msgstr "选项"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_apps_form
-msgid "Parameter"
-msgstr "参数"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_subtype__parent_id
-msgid "Parent"
-msgstr "上级"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_app_subtype_filter
-msgid "Parent type"
-msgstr "上级类型"
-
-#. module: wecom_base
-#. odoo-python
-#: code:addons/wecom_base/models/wecom_app_callback_service.py:0
-#, python-format
-msgid "Please bind contact app!"
-msgstr "请绑定通讯录应用!"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.res_config_settings_view_form
-msgid "Please enter the enterprise id"
-msgstr "请输入企微企业ID"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_event_type__code
-msgid "Python Code"
-msgstr "Python代码"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_res_config_settings__module_web_theme
-msgid "Rainbow Theme"
-msgstr "彩虹主题"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__app_callback_service_ids
-#: model:ir.ui.menu,name:wecom_base.menu_wecom_agent_event_service
-msgid "Receive event service"
-msgstr "接收事件服务"
-
-#. module: wecom_base
-#. odoo-python
-#: code:addons/wecom_base/models/wecom_app_event_type.py:0
-#, python-format
-msgid "Received the callback notification of Wecom, event [%s], change type [%s]."
-msgstr "已收到企业微信的回调通知,事件[%s],更改类型[%s]。"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_event_type__model_ids
-msgid "Related Model"
-msgstr "关联模型"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__isreportenter
-msgid "Report user entry event"
-msgstr "打开进入会话上报"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__secret
-msgid "Secret"
-msgstr "密钥"
-
-#. module: wecom_base
-#: model:wecom.app.type,name:wecom_base.wecom_app_type_self
-msgid "Self built application"
-msgstr "自建应用"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_subtype__sequence
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_type__sequence
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__sequence
-msgid "Sequence"
-msgstr "排序"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_callback_service__code
-msgid "Service Code"
-msgstr "服务代码"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_callback_service__name
-msgid "Service Name"
-msgstr "服务名称"
-
-#. module: wecom_base
-#: model:wecom.app.subtype,name:wecom_base.wecom_app_subtype_msgaudit
-msgid "Session content archiving"
-msgstr "会话内容存档"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_apps_form
-msgid "Setting method"
-msgstr "设置方法"
-
-#. module: wecom_base
-#: model:ir.actions.act_window,name:wecom_base.wecom_config_settings_action
-msgid "Settings"
-msgstr "设置"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.res_config_settings_view_form
-msgid "Settings on this page will apply to this company."
-msgstr "此页面上的设置将应用于此公司。"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_res_company__short_name
-#: model:ir.model.fields,field_description:wecom_base.field_res_config_settings__short_name
-msgid "Short Name"
-msgstr "公司简称"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__square_logo_url
-msgid "Square Logo"
-msgstr "方形Logo"
-
-#. module: wecom_base
-#. odoo-python
-#: code:addons/wecom_base/models/wecom_apps.py:0
-#, python-format
-msgid "Start getting app [%s] ticket for company [%s]"
-msgstr "开始获取应用 [%s] 的临时凭证,公司 [%s]"
-
-#. module: wecom_base
-#. odoo-python
-#: code:addons/wecom_base/models/wecom_apps.py:0
-#, python-format
-msgid "Start getting app [%s] token for company [%s]"
-msgstr "开始为应用 [%s] 的令牌,公司 [%s]"
-
-#. module: wecom_base
-#. odoo-python
-#: code:addons/wecom_base/models/res_config_settings.py:0
-#, python-format
-msgid "Start getting ticket for company [%s]"
-msgstr "开始获取公司 [%s] 的临时凭证"
-
-#. module: wecom_base
-#: model:ir.ui.menu,name:wecom_base.menu_wecom_agent_subtype_list
-msgid "SubType"
-msgstr "子类型"
-
-#. module: wecom_base
-#. odoo-python
-#: code:addons/wecom_base/models/wecom_apps.py:0
-#, python-format
-msgid "Successfully obtained application ticket!"
-msgstr "成功获取到了应用的临时凭证!"
-
-#. module: wecom_base
-#. odoo-python
-#: code:addons/wecom_base/models/res_config_settings.py:0
-#, python-format
-msgid "Successfully obtained ticket!"
-msgstr "成功获取到了临时凭证!"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.res_config_settings_view_form
-msgid "The URL of the Wecom API global error code page for automatic crawling."
-msgstr "用于自动爬取的企业微信API全局错误代码页面的URL。"
-
-#. module: wecom_base
-#. odoo-python
-#: code:addons/wecom_base/models/wecom_apps.py:0
-#: model:ir.model.constraint,message:wecom_base.constraint_wecom_apps_company_id_key_uniq
-#, python-format
-msgid "The application name of each company must be unique !"
-msgstr "每个公司的应用程序名称必须是唯一的!"
-
-#. module: wecom_base
-#. odoo-python
-#: code:addons/wecom_base/models/wecom_app_callback_service.py:0
-#: model:ir.model.constraint,message:wecom_base.constraint_wecom_app_callback_service_app_code_uniq
-#, python-format
-msgid "The code of each application must be unique !"
-msgstr "每个应用的代码必须是唯一的!"
-
-#. module: wecom_base
-#. odoo-python
-#: code:addons/wecom_base/models/wecom_app_config.py:0
-#: model:ir.model.constraint,message:wecom_base.constraint_wecom_app_config_app_id_key_uniq
-#, python-format
-msgid "The key of each application must be unique !"
-msgstr "每个应用的密钥必须是唯一的!"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.res_config_settings_view_form
-msgid ""
-"The path used to save WeCom resources,Need to have read and "
-"write permissions on the path. \n"
-" \n"
-" reference:Windows: D:\\\\resources\\\\ \n"
-" Linux or Docker: /var/lib/odoo/resources/"
-msgstr ""
-"用于存储企微资源的路径,需要对路径具有读写权"
-"限。 \n"
-" \n"
-" reference:Windows: D:\\\\resources\\\\ \n"
-" Linux or Docker: /var/lib/odoo/resources/"
-
-#. module: wecom_base
-#: model:res.groups,comment:wecom_base.group_wecom_settings_user
-msgid "The user will be able to approve document created by employees."
-msgstr "用户将能够批准员工创建的文档。"
-
-#. module: wecom_base
-#: model:res.groups,comment:wecom_base.group_wecom_settings_manager
-msgid "The user will have access to the wecom configuration as well as statistic reports."
-msgstr "用户可以访问企微配置以及统计报告。"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_apps_form
-msgid ""
-"Therefore, developers should identify the source of the issuance of access_token and use "
-"the correct access_token before using the business interface."
-msgstr ""
-"因此开发者,在使用业务接口前,要明确access_token的颁发来源,使用正确的access_token。"
-
-#. module: wecom_base
-#: model:wecom.app.type,name:wecom_base.wecom_app_type_third
-msgid "Third party application"
-msgstr "第三方应用"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.res_config_settings_view_form
-msgid "This company is an WeCom organization"
-msgstr "此公司为企业微信组织"
-
-#. module: wecom_base
-#. odoo-python
-#: code:addons/wecom_base/models/res_config_settings.py:0
-#: code:addons/wecom_base/models/wecom_apps.py:0
-#, python-format
-msgid "Ticket is still valid, and no update is required!"
-msgstr "临时凭证仍然有效,不需要更新!"
-
-#. module: wecom_base
-#. odoo-python
-#: code:addons/wecom_base/models/res_config_settings.py:0
-#: code:addons/wecom_base/models/wecom_apps.py:0
-#, python-format
-msgid "Tips"
-msgstr "提示"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_callback_service__callback_url_token
-msgid "Token"
-msgstr "令牌"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__token_expiration_time
-msgid "Token Expiration Time"
-msgstr "Token有效时间"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__redirect_domain
-msgid "Trusted domain name"
-msgstr "可信域名"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_res_config_settings__debug_enabled
-msgid "Turn on debug mode"
-msgstr "开启调试模式"
-
-#. module: wecom_base
-#: model:ir.ui.menu,name:wecom_base.menu_wecom_agent_type_list
-msgid "Type"
-msgstr "类型"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_callback_service__callback_url
-msgid "URL"
-msgstr ""
-
-#. module: wecom_base
-#. odoo-python
-#: code:addons/wecom_base/models/wecom_app_event_type.py:0
-#, python-format
-msgid "Unable to execute [%s] change type for company [%s], ignoring it. reason: %s"
-msgstr "无法为公司 [%s] 执行 [%s] 变更类型,将忽略它。原因:%s"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.res_config_settings_view_form
-msgid "Update Info"
-msgstr "更新信息"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.res_config_settings_view_form
-msgid ""
-"Used for event triggered synchronization of address book information, such as "
-"departments, members, tags, etc."
-msgstr "用于事件触发的通讯录信息同步,如部门、成员、标签等。"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_app_config__value
-msgid "Value"
-msgstr "值"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__allow_partys
-msgid "Visible range (Department)"
-msgstr "可见范围(部门)"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__allow_tags
-msgid "Visible range (Tag))"
-msgstr "可见范围(标签)"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_wecom_apps__allow_userinfos
-msgid "Visible range (personnel)"
-msgstr "可见范围(人员)"
-
-#. module: wecom_base
-#: model:ir.ui.menu,name:wecom_base.menu_wecom_root
-#: model_terms:ir.ui.view,arch_db:wecom_base.res_config_settings_view_form
-msgid "WeCom"
-msgstr "企业微信"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_res_config_settings__module_wecom_contacts
-msgid "WeCom Contacts"
-msgstr "企微通讯录"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_res_config_settings__module_wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_base.res_config_settings_view_form
-msgid "WeCom Contacts Synchronized"
-msgstr "企微通讯录同步"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_company_form
-msgid "WeCom Information"
-msgstr "企业微信信息"
-
-#. module: wecom_base
-#: model:ir.module.category,name:wecom_base.module_category_wecom_settings
-msgid "WeCom Settings"
-msgstr "企微设置"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_res_company__is_wecom_organization
-#: model:ir.model.fields,field_description:wecom_base.field_res_config_settings__is_wecom_organization
-msgid "WeCom organization"
-msgstr "企业微信组织"
-
-#. module: wecom_base
-#: model:ir.model.fields,field_description:wecom_base.field_res_config_settings__resources_path
-msgid "WeCom resources storage path"
-msgstr "企业微信资源存储路径"
-
-#. module: wecom_base
-#: model:ir.actions.server,name:wecom_base.ir_cron_get_app_token_ir_actions_server
-msgid "WeCom: Get app token"
-msgstr "企微:获取应用令牌"
-
-#. module: wecom_base
-#: model:ir.actions.act_window,name:wecom_base.ir_cron_act_get_app_token
-msgid "WeCom: Get app token."
-msgstr "企微:获取应用令牌。"
-
-#. module: wecom_base
-#: model:ir.actions.act_window,name:wecom_base.ir_cron_act_pull_wecom_service_api_error
-#: model:ir.actions.server,name:wecom_base.ir_cron_pull_wecom_service_api_error_ir_actions_server
-msgid "WeCom: Get the global error code of WeCom."
-msgstr "企微: 获取企微的全局错误代码。"
-
-#. module: wecom_base
-#: model:wecom.app.subtype,name:wecom_base.wecom_app_subtype_kf
-msgid "Wechat customer service"
-msgstr "微信客服"
-
-#. module: wecom_base
-#: model:ir.ui.menu,name:wecom_base.menu_wecom_api
-msgid "Wecom API"
-msgstr "企微API"
-
-#. module: wecom_base
-#: model:ir.model,name:wecom_base.model_wecom_apps
-#: model:ir.ui.menu,name:wecom_base.menu_wecom_agent
-msgid "Wecom Application"
-msgstr "企微应用"
-
-#. module: wecom_base
-#: model:ir.model,name:wecom_base.model_wecom_app_config
-msgid "Wecom Application Configuration"
-msgstr "企微应用配置"
-
-#. module: wecom_base
-#: model:ir.model,name:wecom_base.model_wecom_app_event_type
-msgid "Wecom Application Event"
-msgstr "企微应用事件"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_app_config_form
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_app_config_list
-msgid "Wecom Application Parameters"
-msgstr "企微应用参数"
-
-#. module: wecom_base
-#: model:ir.model,name:wecom_base.model_wecom_app_subtype
-msgid "Wecom Application Subtype"
-msgstr "企微应用子类型"
-
-#. module: wecom_base
-#: model:ir.model,name:wecom_base.model_wecom_app_type
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_app_subtype_form
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_app_subtype_list
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_app_type_form
-#: model_terms:ir.ui.view,arch_db:wecom_base.view_wecom_app_type_list
-msgid "Wecom Application Type"
-msgstr "企微应用类型"
-
-#. module: wecom_base
-#: model:ir.model,name:wecom_base.model_wecom_app_callback_service
-msgid "Wecom Application receive event service"
-msgstr "msgstr \"企微应用接收事件服务\""
-
-#. module: wecom_base
-#: model:ir.ui.menu,name:wecom_base.menu_wecom_attendance
-msgid "Wecom Attendances"
-msgstr "企微出勤"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.res_config_settings_view_form
-msgid "Wecom Companies Settings"
-msgstr "企微公司设置"
-
-#. module: wecom_base
-#: model:ir.actions.act_window,name:wecom_base.wecom_configurator
-msgid "Wecom Configurator"
-msgstr "企微配置"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.res_config_settings_view_form
-msgid "Wecom Contact Settings"
-msgstr "企微通讯录设置"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.res_config_settings_view_form
-msgid "Wecom Contact Synchronization Settings"
-msgstr "企微通讯录同步设置"
-
-#. module: wecom_base
-#: model:ir.ui.menu,name:wecom_base.menu_wecom_contacts
-msgid "Wecom Contacts"
-msgstr "企微通讯录"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.res_config_settings_view_form
-msgid "Wecom Global Settings"
-msgstr "企微全局设置"
-
-#. module: wecom_base
-#: model:ir.model,name:wecom_base.model_wecom_service_api
-msgid "Wecom Server API"
-msgstr "企微服务端API"
-
-#. module: wecom_base
-#: model:ir.model,name:wecom_base.model_wecom_service_api_error
-msgid "Wecom Server API Error"
-msgstr "企微服务端API错误"
-
-#. module: wecom_base
-#: model:ir.model,name:wecom_base.model_wecom_service_api_list
-msgid "Wecom Server API List"
-msgstr "企微服务端API列表"
-
-#. module: wecom_base
-#: model:ir.ui.menu,name:wecom_base.menu_wecom_configuration
-msgid "Wecom Settings"
-msgstr "企微设置"
-
-#. module: wecom_base
-#: model_terms:ir.ui.view,arch_db:wecom_base.res_config_settings_view_form
-msgid ""
-"Wecom address book can be read through API interface,Synchronize with the Wecom address "
-"book to avoid maintaining multiple sets of address books at the same time."
-msgstr "企微通讯录可以通过API接口读取,与企微通讯簿同步,避免同时维护多套通讯录。"
-
-#. module: wecom_base
-#: model:ir.ui.menu,name:wecom_base.menu_wecom_cron
-msgid "Wecom tasks"
-msgstr "企微任务"
-
-#. module: wecom_base
-#: model:ir.model.fields.selection,name:wecom_base.selection__wecom_app_config__ttype__binary
-msgid "binary"
-msgstr "二进制"
-
-#. module: wecom_base
-#: model:ir.model.fields.selection,name:wecom_base.selection__wecom_app_config__ttype__boolean
-msgid "boolean"
-msgstr "布尔型"
-
-#. module: wecom_base
-#: model:ir.model.fields.selection,name:wecom_base.selection__wecom_app_config__ttype__char
-msgid "char"
-msgstr "字符"
-
-#. module: wecom_base
-#: model:ir.model.fields.selection,name:wecom_base.selection__wecom_app_config__ttype__date
-msgid "date"
-msgstr "日期"
-
-#. module: wecom_base
-#: model:ir.model.fields.selection,name:wecom_base.selection__wecom_app_config__ttype__datetime
-msgid "datetime"
-msgstr "日期时间"
-
-#. module: wecom_base
-#: model:ir.model.fields.selection,name:wecom_base.selection__wecom_app_config__ttype__float
-msgid "float"
-msgstr "浮点型"
-
-#. module: wecom_base
-#: model:ir.model.fields.selection,name:wecom_base.selection__wecom_app_config__ttype__html
-msgid "html"
-msgstr ""
-
-#. module: wecom_base
-#: model:ir.model.fields.selection,name:wecom_base.selection__wecom_app_config__ttype__integer
-msgid "integer"
-msgstr "整数"
-
-#. module: wecom_base
-#: model:ir.model.fields.selection,name:wecom_base.selection__wecom_app_config__ttype__json
-msgid "json"
-msgstr ""
-
-#. module: wecom_base
-#: model:ir.model.fields.selection,name:wecom_base.selection__wecom_app_config__ttype__many2many
-msgid "many2many"
-msgstr "多对多"
-
-#. module: wecom_base
-#: model:ir.model.fields.selection,name:wecom_base.selection__wecom_app_config__ttype__many2one
-msgid "many2one"
-msgstr "多对一"
-
-#. module: wecom_base
-#: model:ir.model.fields.selection,name:wecom_base.selection__wecom_app_config__ttype__many2one_reference
-msgid "many2one_reference"
-msgstr "多对一参考"
-
-#. module: wecom_base
-#: model:ir.model.fields.selection,name:wecom_base.selection__wecom_app_config__ttype__monetary
-msgid "monetary"
-msgstr "货币"
-
-#. module: wecom_base
-#: model:ir.model.fields.selection,name:wecom_base.selection__wecom_app_config__ttype__one2many
-msgid "one2many"
-msgstr "一对多"
-
-#. module: wecom_base
-#: model:ir.model.fields.selection,name:wecom_base.selection__wecom_app_config__ttype__properties
-msgid "properties"
-msgstr "属性"
-
-#. module: wecom_base
-#: model:ir.model.fields.selection,name:wecom_base.selection__wecom_app_config__ttype__properties_definition
-msgid "properties_definition"
-msgstr ""
-
-#. module: wecom_base
-#: model:ir.model.fields.selection,name:wecom_base.selection__wecom_app_config__ttype__reference
-msgid "reference"
-msgstr "参考"
-
-#. module: wecom_base
-#: model:ir.model.fields.selection,name:wecom_base.selection__wecom_app_config__ttype__selection
-msgid "selection"
-msgstr "选择项"
-
-#. module: wecom_base
-#: model:ir.model.fields.selection,name:wecom_base.selection__wecom_app_config__ttype__text
-msgid "text"
-msgstr "文本"
diff --git a/wecom_base/models/__init__.py b/wecom_base/models/__init__.py
deleted file mode 100644
index fb72a8891..000000000
--- a/wecom_base/models/__init__.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from . import ir_http
-
-from . import wecom_server_api
-from . import wecom_server_api_error
-from . import wecom_server_api_list
-
-from . import ir_module
-from . import res_company
-from . import res_config_settings
-from . import res_partner
-
-from . import wecom_app_type
-from . import wecom_app_subtype
-from . import wecom_apps
-from . import wecom_app_callback_service
-from . import wecom_app_config
-from . import wecom_app_event_type
diff --git a/wecom_base/models/ir_http.py b/wecom_base/models/ir_http.py
deleted file mode 100644
index 748e16808..000000000
--- a/wecom_base/models/ir_http.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from odoo import models
-from odoo.http import request
-
-class Http(models.AbstractModel):
- _inherit = 'ir.http'
-
- def session_info(self):
- session_info = super(Http, self).session_info() # type: ignore
- user = request.env.user # type: ignore
- if self.env.user.has_group('base.group_user'):
- allowed_companies = session_info["user_companies"]["allowed_companies"]
-
- allowed_companies = {
- comp.id: {
- 'id': comp.id,
- 'name': comp.name,
- 'is_wecom_organization': comp.is_wecom_organization,
- 'sequence': comp.sequence,
- } for comp in user.company_ids
- }
- session_info["user_companies"]["allowed_companies"] = allowed_companies
-
- return session_info
\ No newline at end of file
diff --git a/wecom_base/models/ir_module.py b/wecom_base/models/ir_module.py
deleted file mode 100644
index 333d211b4..000000000
--- a/wecom_base/models/ir_module.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from odoo import api, fields, models, tools, _
-
-
-class Module(models.Model):
- _inherit = "ir.module.module"
-
- def wecom_check_module_installed(self, modules_name):
- # modules 输入参数是个 list,如 ['base', 'sale']
- module = self.sudo().search([("name", "=", modules_name)])
- if not module or module.state != "installed": # type: ignore
- return False
- else:
- return True
diff --git a/wecom_base/models/res_company.py b/wecom_base/models/res_company.py
deleted file mode 100644
index 8fa572fe2..000000000
--- a/wecom_base/models/res_company.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# -*- coding: utf-8 -*-
-
-
-import io
-import logging
-import os
-
-from odoo import api, fields, models, tools, _
-
-
-class Company(models.Model):
- _inherit = "res.company"
-
- # 基础
- short_name = fields.Char("Short Name", translate=True)
- is_wecom_organization = fields.Boolean("WeCom organization", default=False)
- corpid = fields.Char("Corp ID")
-
- # 企业的jsapi_ticket
- corp_jsapi_ticket = fields.Char(string="Corp JSAPI Ticket", copy=False)
- corp_jsapi_ticket_expiration_time = fields.Datetime(
- string="Expiration time of Corp JSAPI ticket", copy=False
- )
diff --git a/wecom_base/models/res_config_settings.py b/wecom_base/models/res_config_settings.py
deleted file mode 100644
index ed2798bcf..000000000
--- a/wecom_base/models/res_config_settings.py
+++ /dev/null
@@ -1,167 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from datetime import datetime, timedelta
-from random import weibullvariate
-from odoo import models, fields, api, _
-from odoo.addons.wecom_api.api.wecom_abstract_api import ApiException # type: ignore
-
-import logging
-
-_logger = logging.getLogger(__name__)
-
-
-class ResConfigSettings(models.TransientModel):
- _inherit = "res.config.settings"
-
- # 基础
- is_wecom_organization = fields.Boolean(
- related="company_id.is_wecom_organization", readonly=False
- )
- company_name = fields.Char(
- related="company_id.name", string="Company Name", readonly=False
- )
- short_name = fields.Char(related="company_id.short_name", readonly=False)
- corpid = fields.Char(string="Corp ID", related="company_id.corpid", readonly=False)
-
- corp_jsapi_ticket = fields.Char(
- related="company_id.corp_jsapi_ticket",
- readonly=False,
- )
- corp_jsapi_ticket_expiration_time = fields.Datetime(
- related="company_id.corp_jsapi_ticket_expiration_time",
- readonly=False,
- )
-
- debug_enabled = fields.Boolean("Turn on debug mode", default=True)
-
- resources_path = fields.Char(
- "WeCom resources storage path",
- config_parameter="wecom.resources_path",
- )
-
- global_error_code_url = fields.Char(
- "Global error code page URL",
- config_parameter="wecom.global_error_code_url",
- )
-
- global_error_code_item_selection_code = fields.Char(
- "Global error code item selection code",
- config_parameter="wecom.global_error_code_item_selection_code",
- ) # 错误码排查方法的选取属性。
-
- module_web_theme = fields.Boolean("Rainbow Theme")
- module_wecom_contacts = fields.Boolean("WeCom Contacts")
- module_wecom_contacts_sync = fields.Boolean("WeCom Contacts Synchronized")
-
- @api.model
- def get_values(self):
- res = super(ResConfigSettings, self).get_values() # type: ignore
- ir_config = self.env["ir.config_parameter"].sudo()
-
- debug_enabled = (
- True if ir_config.get_param("wecom.debug_enabled") == "True" else False
- )
-
- res.update(
- debug_enabled=debug_enabled,
- )
- return res
-
- def set_values(self):
- super(ResConfigSettings, self).set_values() # type: ignore
- ir_config = self.env["ir.config_parameter"].sudo()
- ir_config.set_param("wecom.debug_enabled", self.debug_enabled or "False")
-
- def open_wecom_company(self):
- return {
- "type": "ir.actions.act_window",
- "name": "My Company",
- "view_mode": "form",
- "res_model": "res.company",
- "res_id": self.env.company.id,
- "target": "current",
- "context": {
- "form_view_initial_mode": "edit",
- },
- }
-
- @api.depends("company_id")
- def _compute_wecom_company_corpid(self):
- company_corpid = self.company_id.corpid if self.company_id.corpid else "" # type: ignore
-
- for record in self:
- record.wecom_company_corpid = company_corpid # type: ignore
-
- @api.model
- def open_wecom_settings(self):
- action = self.env["ir.actions.actions"]._for_xml_id(
- "wecom_base.res_config_settings_view_form"
- )
- action["target"] = "new"
-
- return action
-
- def get_app_info(self):
- """
- 获取企业应用信息
- :param agentid:
- :return:
- """
-
- def get_corp_jsapi_ticket(self):
- """
- 获取企业的jsapi_ticket
- :return:
- """
- ir_config = self.env["ir.config_parameter"].sudo()
- debug = ir_config.get_param("wecom.debug_enabled")
- if debug:
- _logger.info(
- _("Start getting ticket for company [%s]") % (self.company_id.name) # type: ignore
- )
- try:
- if (
- self.corp_jsapi_ticket_expiration_time
- and self.corp_jsapi_ticket_expiration_time > datetime.now()
- ):
- # 未过期,
- # print("未过期")
- msg = {
- "title": _("Tips"),
- "message": _("Ticket is still valid, and no update is required!"),
- "sticky": False,
- }
- return self.env["wecomapi.tools.action"].WecomInfoNotification(msg)
- else:
- # print("过期")
- wecom_api = self.env["wecom.service_api"].InitServiceApi(self.company_id.corpid, self.contacts_app_id.secret) # type: ignore
- response = wecom_api.httpCall(
- self.env["wecom.service_api_list"].get_server_api_call(
- "GET_JSAPI_TICKET"
- ),
- {},
- )
- # print(response)
- except ApiException as ex:
- return self.env["wecomapi.tools.action"].ApiExceptionDialog(
- ex, raise_exception=True
- )
- else:
- if response["errcode"] == 0:
- self.write(
- {
- "corp_jsapi_ticket": response["ticket"],
- "corp_jsapi_ticket_expiration_time": datetime.now()
- + timedelta(seconds=response["expires_in"]),
- }
- )
- msg = {
- "title": _("Tips"),
- "message": _("Successfully obtained ticket!"),
- "sticky": False,
- "next": {
- "type": "ir.actions.client",
- "tag": "reload",
- },
- }
- return self.env["wecomapi.tools.action"].WecomSuccessNotification(msg)
diff --git a/wecom_base/models/res_partner.py b/wecom_base/models/res_partner.py
deleted file mode 100644
index afe498446..000000000
--- a/wecom_base/models/res_partner.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from odoo import fields, models, _
-
-
-class Partner(models.Model):
- _inherit = "res.partner"
diff --git a/wecom_base/models/wecom_app_callback_service.py b/wecom_base/models/wecom_app_callback_service.py
deleted file mode 100644
index 2f66a44ac..000000000
--- a/wecom_base/models/wecom_app_callback_service.py
+++ /dev/null
@@ -1,103 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from datetime import datetime, timedelta
-from odoo import _, api, fields, models
-from odoo.exceptions import ValidationError
-
-
-class WeComAppCallbackService(models.Model):
- """
- 接收事件服务器配置
- https://work.weixin.qq.com/api/doc/90000/90135/90930
- """
-
- _name = "wecom.app_callback_service"
- _description = "Wecom Application receive event service"
-
- app_id = fields.Many2one(
- "wecom.apps",
- string="Application",
- copy=False,
- ondelete="cascade",
- default=lambda self: self.env["wecom.apps"].id,
- # domain="[('company_id', '=', company_id)]",
- required=True,
- )
-
- name = fields.Char(string="Service Name", required=True, translate=True)
- code = fields.Char(
- string="Service Code",
- copy=False,
- required=True,
- )
-
- callback_url = fields.Char(
- string="URL",
- store=True,
- readonly=True,
- compute="_default_callback_url",
- copy=False,
- ) # 回调服务地址
- callback_url_token = fields.Char(string="Token", copy=False) # Token用于计算签名
- callback_aeskey = fields.Char(string="AES Key", copy=False) # 用于消息内容加密
-
- description = fields.Text(string="Description", translate=True, copy=True)
- active = fields.Boolean("Active", default=False)
-
- _sql_constraints = [
- (
- "app_code_uniq",
- "unique (app_id,code)",
- _("The code of each application must be unique !"),
- )
- ]
-
- @api.depends("app_id", "code")
- def _default_callback_url(self):
- """
- 默认回调地址
- :return:"""
- params = self.env["ir.config_parameter"].sudo()
- base_url = params.get_param("web.base.url")
- callback_url = ""
- for server in self:
- if server.app_id.company_id and server.code: # type: ignore
- callback_url = base_url + "/wecom_callback/%s/%s" % ( # type: ignore
- server.app_id.company_id.id, # type: ignore
- server.code, # type: ignore
- )
-
- server.callback_url = callback_url # type: ignore
-
- @api.onchange("app_id", "code")
- def _onchange_callback_url(self):
- """
- 当应用发生变化时,更新回调服务地址
- :return:
- """
- params = self.env["ir.config_parameter"].sudo()
- base_url = params.get_param("web.base.url")
-
- if self.app_id:
- self.callback_url = base_url + "/wecom_callback/%s/%s" % (
- self.app_id.company_id.id, # type: ignore
- self.code,
- )
- else:
- self.callback_url = ""
-
- def generate_contact_service(self):
- """
- 生成通讯录回调服务
- :return:
- """
- params = self.env["ir.config_parameter"].sudo()
- base_url = params.get_param("web.base.url")
- if not self.app_id:
- raise ValidationError(_("Please bind contact app!"))
- else:
- callback_url = base_url + "/wecom_callback/%s/%s" % (
- self.app_id.company_id.id, # type: ignore
- self.code,
- )
- return callback_url
diff --git a/wecom_base/models/wecom_app_config.py b/wecom_base/models/wecom_app_config.py
deleted file mode 100644
index 0f48e2d7d..000000000
--- a/wecom_base/models/wecom_app_config.py
+++ /dev/null
@@ -1,161 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from odoo import fields, models, api, _
-from odoo.tools import config, ormcache, mute_logger
-
-FIELD_TYPES = [(key, key) for key in sorted(fields.Field.by_type)]
-
-
-class WeComAppConfig(models.Model):
- _name = "wecom.app_config"
- _description = "Wecom Application Configuration"
- _table = "wecom_app_config"
- # _rec_name = "key"
- _order = "id"
-
- app_id = fields.Many2one( # type: ignore
- "wecom.apps",
- string="Application",
- copy=False,
- ondelete="cascade",
- default=lambda self: self.env["wecom.apps"].id,
- # domain="[('company_id', '=', company_id)]",
- required=True,
- )
- company_id = fields.Many2one(related="app_id.company_id", store=True)
- name = fields.Char(string="Name", translate=True, required=True, copy=True)
- key = fields.Char(
- required=True,
- )
- ttype = fields.Selection(
- selection=FIELD_TYPES, string="Field Type", required=True, copy=True
- )
- value = fields.Text(required=True)
- description = fields.Html(string="Description", translate=True, copy=True)
-
- _sql_constraints = [
- (
- "app_id_key_uniq",
- "unique (app_id,key)",
- _("The key of each application must be unique !"),
- )
- ]
-
- def get_format_field_value_and_type(self, res_id=False, field_name=""):
- """
- JS 获取需要格式化的字段的类型和值
- :return:
- """
- res = self.browse(res_id)
- return res.ttype # type: ignore
- # return {
- # "id": res_id,
- # "value_type": res.ttype,
- # "value": res.value,
- # }
-
- def update_config(self, res_id=False, value=""):
- """
- 更新参数
- """
- # res = self.browse(res_id)
- app_config = (
- self.env["wecom.app_config"]
- .sudo()
- .search(
- [
- ("id", "=", res_id),
- ]
- )
- )
-
- app_config.sudo().write({"value": value})
- print(app_config.value)
- return app_config.value
-
- @api.model
- def get_param(self, app_id, key, default=False):
- """检索给定key的value
-
- :param string key: 要检索的参数值的键。
- :param string default: 如果缺少参数,则为默认值。
- :return: 参数的值, 如果不存在,则为 ``default``.
- :rtype: string
- """
- return self._get_param(app_id, key) or default
-
- def _get_param(self, app_id, key):
- params = self.search_read(
- [("app_id", "=", app_id), ("key", "=", key)],
- fields=["ttype", "value"],
- limit=1,
- )
- value = None
- ttype = None
- if not params:
- # 如果没有找到,搜索其他公司相同应用配置参数 进行复制
- copy_app_config = self.search([("key", "=", key)], limit=1)
- if copy_app_config:
- new_app_config = self.create(
- {
- "app_id": app_id,
- "name": copy_app_config.name, # type: ignore
- "key": copy_app_config.key, # type: ignore
- "ttype": copy_app_config.ttype, # type: ignore
- "value": copy_app_config.value, # type: ignore
- "description": copy_app_config.description, # type: ignore
- }
- )
- value = new_app_config.value
- ttype = new_app_config.ttype
- else:
- pass
- else:
- value = params[0]["value"]
- ttype = params[0]["ttype"]
-
- if ttype == "boolean":
- boolean_value = str(value).lower()
- if boolean_value in ["true", "yes", "t", "1"]:
- return True
- elif boolean_value in ["false", "no", "f", "0"]:
- return False
- else:
- return False
- return value if params else None
-
- @api.model
- def set_param(self, app_id, key, value):
- """设置参数的值。
-
- :param string key: 要设置的参数值的键。
- :param string value: 要设置的值。
- :return: 参数的上一个值,如果不存在,则为False。
- :rtype: string
- """
- param = self.search([("app_id", "=", app_id), ("key", "=", key)])
- if param:
- old = param.value # type: ignore
- if value is not False and value is not None:
- if str(value) != old:
- param.write({"value": value}) # type: ignore
- else:
- param.unlink() # type: ignore
- return old
- else:
- if value is not False and value is not None:
- self.create({"app_id": app_id, "key": key, "value": value})
- return False
-
- @api.model_create_multi
- def create(self, vals_list):
- self._invalidate_cache()
- return super(WeComAppConfig, self).create(vals_list)
-
- def write(self, vals):
- self._invalidate_cache()
- return super(WeComAppConfig, self).write(vals)
-
- def unlink(self):
- self._invalidate_cache()
- return super(WeComAppConfig, self).unlink()
diff --git a/wecom_base/models/wecom_app_event_type.py b/wecom_base/models/wecom_app_event_type.py
deleted file mode 100644
index 019b8738f..000000000
--- a/wecom_base/models/wecom_app_event_type.py
+++ /dev/null
@@ -1,152 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import logging
-import base64
-from odoo import _, api, fields, models
-from odoo.exceptions import MissingError, UserError, ValidationError, AccessError
-from odoo.tools.safe_eval import safe_eval, test_python_expr
-from lxml import etree
-from lxml import etree as ET
-from odoo.http import Response
-
-# from lxml_to_dict import lxml_to_dict
-# from xmltodict import lxml_to_dict
-import xmltodict, json
-
-_logger = logging.getLogger(__name__)
-
-
-class WeComAppEventType(models.Model):
-
- _name = "wecom.app.event_type"
- _description = "Wecom Application Event"
- _order = "id"
-
- DEFAULT_PYTHON_CODE = """# Available variables:
-# - env: Odoo Environment on which the action is triggered
-# - model: Odoo Model of the record on which the action is triggered; is a void recordset
-# - record: record on which the action is triggered; may be void
-# - records: recordset of all records on which the action is triggered in multi-mode; may be void
-# - time, datetime, dateutil, timezone: useful Python libraries
-# - float_compare: Odoo function to compare floats based on specific precisions
-# - log: log(message, level='info'): logging function to record debug information in ir.logging table
-# - UserError: Warning Exception to use with raise
-# To return an action, assign: action = {...}\n\n\n\n"""
-
- name = fields.Char(
- string="Name",
- translate=True,
- copy=False,
- required=True,
- )
- model_ids = fields.Many2many(
- "ir.model",
- string="Related Model",
- )
- msg_type = fields.Char(
- string="Message Type", copy=False, required=True, default="event"
- )
- event = fields.Char(
- string="Event Code",
- copy=False,
- required=True,
- )
- change_type = fields.Char(string="Change Type", copy=False)
- code = fields.Char(
- string="Python Code",
- default="",
- )
- command = fields.Char(string="Command", copy=False)
-
- def handle_event(self):
- """
- 处理事件
- """
- xml_tree = self.env.context.get("xml_tree")
- company_id = self.env.context.get("company_id")
- event_str = etree.fromstring(xml_tree).find("Event").text # type: ignore
- changetype_str = etree.fromstring(xml_tree).find("ChangeType").text # type: ignore
-
- _logger.info(
- _(
- "Received the callback notification of Wecom, event [%s], change type [%s]."
- )
- % (
- event_str,
- changetype_str,
- )
- )
- event = (
- self.env["wecom.app.event_type"]
- .sudo()
- .search(
- [
- ("event", "=", event_str),
- ("change_type", "=", changetype_str),
- ]
- )
- )
- if not event:
- _logger.warning(
- _(
- "Cannot find [%s] change type for executing company [%s], ignoring it."
- )
- % (
- event.name,
- company_id.name,
- )
- )
- return
-
- if event.code:
- # ^ 正确响应企业微信本次的POST请求,企业微信将不会再次发送请求
- # ^ ·企业微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次
- # ^ ·当接收成功后,http头部返回200表示接收ok,其他错误码企业微信后台会一律当做失败并发起重试
- try:
- event.with_context(
- xml_tree=xml_tree, company_id=company_id
- ).sudo().run()
- except Exception as e:
- _logger.warning(
- _(
- "Unable to execute [%s] change type for company [%s], ignoring it. reason: %s"
- )
- % (event.name, company_id.name, str(e))
- )
- return Response("success", status=200)
- else:
- return Response("success", status=200)
-
- def run(self):
- """
- 执行事件
- """
- xml_tree = self.env.context.get("xml_tree")
- company_id = self.env.context.get("company_id")
- func_name = self.code.split("model.")[1]
- cmd = self.command
-
- for m in self.model_ids:
- model_obj = self.env.get(m.model) # type: ignore
- if hasattr(model_obj, func_name):
- # 存在函数
- func = getattr(
- model_obj.with_context(xml_tree=xml_tree, company_id=company_id),
- func_name,
- )
- func(cmd)
- _logger.info(
- _("Method [%s] to execute model [%s]")
- % (
- func_name,
- model_obj,
- )
- )
- else:
- _logger.warning(
- _("Function [%s] does not exist in model [%s]")
- % (
- func_name,
- model_obj,
- )
- )
diff --git a/wecom_base/models/wecom_app_subtype.py b/wecom_base/models/wecom_app_subtype.py
deleted file mode 100644
index e14030530..000000000
--- a/wecom_base/models/wecom_app_subtype.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from odoo import _, api, fields, models
-
-
-class WeComAppType(models.Model):
- _name = "wecom.app.subtype"
- _description = "Wecom Application Subtype"
- _order = "parent_id,sequence"
-
- name = fields.Char(string="Name", translate=True, copy=False, required=True,)
-
- parent_id = fields.Many2one(
- "wecom.app.type",
- ondelete="cascade",
- string="Parent",
- index=True,
- copy=False,
- required=True,
- )
- code = fields.Char(string="Code", copy=False, required=True,)
- sequence = fields.Integer(default=0, copy=True)
-
- _sql_constraints = [("code_uniq", "unique (code)", _("Code must be unique !"),)]
diff --git a/wecom_base/models/wecom_app_type.py b/wecom_base/models/wecom_app_type.py
deleted file mode 100644
index c5840a900..000000000
--- a/wecom_base/models/wecom_app_type.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from odoo import _, api, fields, models
-
-
-class WeComAppType(models.Model):
- _name = "wecom.app.type"
- _description = "Wecom Application Type"
- _order = "sequence"
-
- name = fields.Char(
- string="Name",
- translate=True,
- copy=False,
- required=True,
- )
- code = fields.Char(
- string="Code",
- copy=False,
- required=True,
- )
- subtype_ids = fields.One2many(
- "wecom.app.subtype",
- "parent_id",
- string="Application Subtype",
- )
- sequence = fields.Integer(default=0, copy=True)
-
- _sql_constraints = [
- (
- "code_uniq",
- "unique (code)",
- _("Code must be unique !"),
- )
- ]
diff --git a/wecom_base/models/wecom_apps.py b/wecom_base/models/wecom_apps.py
deleted file mode 100644
index 15fe0f4de..000000000
--- a/wecom_base/models/wecom_apps.py
+++ /dev/null
@@ -1,432 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import logging
-import time
-from datetime import datetime, timedelta
-from odoo import _, api, fields, models
-from odoo.exceptions import UserError
-from odoo.addons.wecom_api.api.wecom_abstract_api import ApiException # type: ignore
-
-_logger = logging.getLogger(__name__)
-
-
-class WeComApps(models.Model):
- _name = "wecom.apps"
- _description = "Wecom Application"
- _order = "sequence"
-
- name = fields.Char(
- string="Name",
- copy=False,
- compute="_compute_name",
- store=True,
- index=True,
- ) # 企业应用名称
- app_name = fields.Char(
- string="Application Name",
- translate=True,
- copy=True,
- ) # 应用名称
-
- company_id = fields.Many2one(
- "res.company",
- string="Company",
- domain="[('is_wecom_organization', '=', True)]",
- copy=False,
- store=True,
- )
- # model_ids = fields.Many2many("ir.model", string="Related Model",)
- # 应用类型 required=True
- type = fields.Selection(
- selection=lambda self: self._type_selection_values(),
- string="Application Type",
- required=True,
- copy=True,
- default="manage",
- )
- type_id = fields.Many2one("wecom.app.type", string="Application Types", store=True)
-
- subtype_ids = fields.Many2many(
- "wecom.app.subtype",
- string="Application Subtype",
- )
- type_code = fields.Char(
- string="Application type code",
- store=True,
- readonly=True,
- compute="_computet_type_code",
- )
-
- def write(self, vals):
- for app in self:
- labels = dict(self.fields_get(allfields=["type"])["type"]["selection"])[app.type] # type: ignore
- if "company_id" in vals:
- company = app.company_id # type: ignore
- vals["name"] = "%s/%s/%s" % (
- company.short_name,
- labels,
- app.app_name, # type: ignore
- )
- else:
- vals["name"] = "%s/%s" % (labels, app.app_name) # type: ignore
- result = super(WeComApps, self).write(vals)
-
- return result
-
- @api.depends("subtype_ids")
- def _computet_type_code(self):
- """
- 计算应用类型代码
- """
- if self.subtype_ids:
- self.type_code = str(self.subtype_ids.mapped("code")) # type: ignore
- else:
- self.type_code = "[]"
-
- def get_type_code(self):
- """
- 测试代码
- """
- type_code = str(self.subtype_ids.mapped("code")) # type: ignore
- print(type_code, type(type_code))
-
- @api.onchange("subtype_ids")
- def _onchange_subtype_ids(self):
- """
- 变更子类型
- :return:
- """
- if self.type_id.code == "manage" or self.type_id.code == "base": # type: ignore
- if len(self.subtype_ids) > 1:
- raise UserError(
- _("Only one subtype can be selected for the current app type!")
- )
-
- @api.model
- def _type_selection_values(self):
- models = self.env["wecom.app.type"].sudo().search([]).sorted("sequence")
- return [(model.code, model.name) for model in models]
-
- @api.onchange("type")
- def _onchange_type(self):
- # self.subtype_ids = False
- # self.type_code = ""
- # if self.type:
- # type = self.env["wecom.app.type"].sudo().search([("code", "=", self.type)])
- # self.type_id = type
- # return {"domain": {"subtype_ids": [("parent_id", "=", type.id)]}}
- # else:
- # self.type_id = False
- # return {"domain": {"subtype": []}}
- if self.subtype_ids:
- self.type_code = str(self.subtype_ids.mapped("code")) # type: ignore
- else:
- self.type_code = "[]"
-
- agentid = fields.Integer(string="Agent ID", copy=False) # 企业应用id
- secret = fields.Char("Secret", default="", copy=False)
- square_logo_url = fields.Char(string="Square Logo", copy=True) # 企业应用方形头像
- description = fields.Text(string="Description", translate=True, copy=True) # 企业应用详情
- allow_userinfos = fields.Char(
- string="Visible range (personnel)", copy=False
- ) # 企业应用可见范围(人员),其中包括userid
- allow_partys = fields.Char(
- string="Visible range (Department)", copy=False
- ) # 企业应用可见范围(部门)
- allow_tags = fields.Char(string="Visible range (Tag))", copy=False) # 企业应用可见范围(标签)
- close = fields.Boolean(string="Disabled", copy=False) # 企业应用是否被停用
- redirect_domain = fields.Char(string="Trusted domain name", copy=True) # 企业应用可信域名
- report_location_flag = fields.Boolean(
- string="Open the geographic location and report", copy=False
- ) # 企业应用是否打开地理位置上报 0:不上报;1:进入会话上报;
- isreportenter = fields.Boolean(
- string="Report user entry event", copy=False
- ) # 企业应用是否打开进入会话上报 0:不上报;1:进入会话上报;
- home_url = fields.Char(string="Home page", copy=True) # 企业应用主页url
-
- sequence = fields.Integer(default=0, copy=True)
- menu_body = fields.Text(
- "Application menu data",
- translate=True,
- default="{}",
- copy=False,
- )
-
- # 访问令牌
- access_token = fields.Char(string="Access Token", readonly=True, copy=False)
- token_expiration_time = fields.Datetime(
- string="Token Expiration Time", readonly=True, copy=False
- )
-
- # 应用的jsapi_ticket
- jsapi_ticket = fields.Char(string="JSAPI Ticket", readonly=True, copy=False)
- jsapi_ticket_expiration_time = fields.Datetime(
- string="JSAPI Ticket Expiration Time", readonly=True, copy=False
- )
-
- _sql_constraints = [
- (
- "company_id_key_uniq",
- "unique (company_id,app_name)",
- _("The application name of each company must be unique !"),
- )
- ]
-
- @api.model_create_multi
- def create(self, values):
- res = super(WeComApps, self).create(values)
- if res.subtype_ids:
- res.type_code = str(res.subtype_ids.mapped("code"))
- else:
- res.type_code = "[]"
- return res
-
- @api.depends("company_id", "app_name", "type")
- def _compute_name(self):
- for app in self:
- labels = dict(self.fields_get(allfields=["type"])["type"]["selection"])[app.type] # type: ignore
- if app.company_id: # type: ignore
- app.name = "%s/%s/%s" % (app.company_id.short_name,labels,app.app_name,) # type: ignore
- else:
- app.name = "%s/%s" % (labels, app.app_name) # type: ignore
-
- # 回调服务
- app_callback_service_ids = fields.One2many(
- "wecom.app_callback_service",
- "app_id",
- string="Receive event service",
- domain="['|', ('active', '=', True), ('active', '=', False)]",
- context={"active_test": False},
- )
-
- # 应用参数配置
- app_config_ids = fields.One2many(
- "wecom.app_config",
- "app_id",
- string="Application Configuration",
- # context={
- # "default_company_id": lambda self: self.company_id,
- # },
- ) # 应用参数配置
-
- # ————————————————————————————————————
- # 应用回调服务
- # ————————————————————————————————————
- def generate_service(self):
- """
- 生成回调服务
- :return:
- """
- code = self.env.context.get("code") # 按钮的传递值
- if bool(code):
- # 存在按钮的传递值,通过按钮的传递值生成回调服务
- self.generate_service_by_code(code)
- else:
- # 不存在按钮的传递值,通过子类型生成生成回调服务
- self.generate_service_by_subtype()
-
- def generate_service_by_subtype(self):
- """
- 通过子类型生成生成回调服务
- """
- for record in self.subtype_ids:
- self.generate_service_by_code(record.code) # type: ignore
-
- def generate_service_by_code(self, code):
- """
- 根据code生成回调服务
- :param code:
- :return:
- """
-
- # ————————————————————————————————————
- # 应用参数配置
- # ————————————————————————————————————
- def generate_parameters(self):
- """
- 生成参数
- :return:
- """
- code = self.env.context.get("code") # 按钮的传递值
- if bool(code):
- # 存在按钮的传递值,通过按钮的传递值生成回调服务
- self.generate_parameters_by_code(code)
- else:
- # 不存在按钮的传递值,通过子类型生成生成回调服务
- self.generate_parameters_by_subtype()
-
- def generate_parameters_by_subtype(self):
- """
- 通过子类型生成生成参数
- """
- for record in self.subtype_ids:
- self.generate_parameters_by_code(record.code) # type: ignore
-
- def generate_parameters_by_code(self, code):
- """
- 根据code生成参数
- :param code:
- :retur
- """
-
- # ————————————————————————————————————
- # 应用信息
- # ————————————————————————————————————
- def get_app_info(self):
- """
- 获取企业应用信息
- :param agentid:
- :return:
- """
- for record in self:
- try:
- wecomapi = self.env["wecom.service_api"].InitServiceApi(record.company_id.corpid, record.secret) # type: ignore
- response = wecomapi.httpCall(
- self.env["wecom.service_api_list"].get_server_api_call("AGENT_GET"),
- {"agentid": str(record.agentid)}, # type: ignore
- )
- except ApiException as e:
- return self.env["wecomapi.tools.action"].ApiExceptionDialog(
- e, raise_exception=True
- )
- else:
- if response["errcode"] == 0:
- record.write(
- {
- "app_name": response["name"],
- "square_logo_url": response["square_logo_url"],
- "description": response["description"],
- "allow_userinfos": response["allow_userinfos"]
- if "allow_userinfos" in response
- else "{}",
- "allow_partys": response["allow_partys"]
- if "allow_partys" in response
- else "{}",
- "allow_tags": response["allow_tags"]
- if "allow_tags" in response
- else "{}",
- "close": response["close"],
- "redirect_domain": response["redirect_domain"],
- "report_location_flag": response["report_location_flag"],
- "isreportenter": response["isreportenter"],
- "home_url": response["home_url"],
- }
- )
- # msg = {
- # "title": _("Tips"),
- # "message": _("Successfully obtained application information!"),
- # "sticky": False,
- # }
- # return self.env["wecomapi.tools.action"].WecomSuccessNotification(msg)
-
- def set_app_info(self):
- """
- 设置企业应用信息
- :param agentid:
- :return:
- """
-
- # ————————————————————————————————————
- # 应用令牌
- # ————————————————————————————————————
- def get_access_token(self):
- """获取企业应用接口调用凭据(令牌)
- :return:
- """
- ir_config = self.env["ir.config_parameter"].sudo()
- debug = ir_config.get_param("wecom.debug_enabled")
- if debug:
- _logger.info(
- _("Start getting app [%s] token for company [%s]")% (self.name, self.company_id.name) # type: ignore
- )
- try:
- wecom_api = self.env["wecom.service_api"].InitServiceApi(self.company_id.corpid, self.secret) # type: ignore
- except ApiException as ex:
- return self.env["wecomapi.tools.action"].ApiExceptionDialog(
- ex, raise_exception=True
- )
- # finally:
- # if self.token_expiration_time and self.token_expiration_time > datetime.now():
- # # 令牌未过期,则直接返回 提示信息
- # msg = {
- # "title": _("Tips"),
- # "message": _("Token is still valid, and no update is required!"),
- # "sticky": False,
- # }
- # return self.env["wecomapi.tools.action"].WecomInfoNotification(msg)
-
- def cron_get_app_token(self):
- """
- 自动任务定时获取应用token
- """
- for app in self.search([("company_id", "!=", False)]): # type: ignore
- _logger.info(
- _(
- "Automatic task: start to get the application [%s] token of company [%s]"
- )
- % (app.name, app.company_id.name)
- )
- app.get_access_token()
-
- # ————————————————————————————————————
- # 应用 jsapi_ticket
- # ————————————————————————————————————
- def get_app_jsapi_ticket(self):
- """
- 获取应用的jsapi_ticket
- """
- ir_config = self.env["ir.config_parameter"].sudo()
- debug = ir_config.get_param("wecom.debug_enabled")
- if debug:
- _logger.info(
- _("Start getting app [%s] ticket for company [%s]")
- % (self.name, self.company_id.name) # type: ignore
- )
- try:
- if (
- self.jsapi_ticket_expiration_time
- and self.jsapi_ticket_expiration_time > datetime.now()
- ):
- # 未过期,
- # print("未过期")
- msg = {
- "title": _("Tips"),
- "message": _("Ticket is still valid, and no update is required!"),
- "sticky": False,
- }
- return self.env["wecomapi.tools.action"].WecomInfoNotification(msg)
- else:
- # print("过期")
- wecom_api = self.env["wecom.service_api"].InitServiceApi(
- self.company_id.corpid, self.secret # type: ignore
- )
- response = wecom_api.httpCall(
- self.env["wecom.service_api_list"].get_server_api_call(
- "AGENT_GET_TICKET"
- ),
- {"type": "agent_config"},
- )
- except ApiException as ex:
- return self.env["wecomapi.tools.action"].ApiExceptionDialog(
- ex, raise_exception=True
- )
- else:
- if response["errcode"] == 0:
- self.write(
- {
- "jsapi_ticket": response["ticket"],
- "jsapi_ticket_expiration_time": datetime.now()
- + timedelta(seconds=response["expires_in"]),
- }
- )
- msg = {
- "title": _("Tips"),
- "message": _("Successfully obtained application ticket!"),
- "sticky": False,
- "next": {
- "type": "ir.actions.client",
- "tag": "reload",
- },
- }
- finally:
- return self.env["wecomapi.tools.action"].WecomSuccessNotification(msg) # type: ignore
diff --git a/wecom_base/models/wecom_server_api.py b/wecom_base/models/wecom_server_api.py
deleted file mode 100644
index 03ed52780..000000000
--- a/wecom_base/models/wecom_server_api.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from datetime import datetime, timedelta
-from odoo import api, fields, models, SUPERUSER_ID, _
-
-class WecomServerApi(models.TransientModel):
- _inherit = "wecom.service_api"
\ No newline at end of file
diff --git a/wecom_base/models/wecom_server_api_error.py b/wecom_base/models/wecom_server_api_error.py
deleted file mode 100644
index b02078ce2..000000000
--- a/wecom_base/models/wecom_server_api_error.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# -*- coding: utf-8 -*-
-
-
-import requests
-import logging
-from urllib.parse import quote, unquote
-import pandas as pd
-
-pd.set_option("max_colwidth", 4096)
-
-from lxml import etree
-import requests
-from odoo import api, fields, models, SUPERUSER_ID, _
-
-_logger = logging.getLogger(__name__)
-
-
-class WecomServerApiError(models.Model):
- _inherit = "wecom.service_api_error"
-
diff --git a/wecom_base/models/wecom_server_api_list.py b/wecom_base/models/wecom_server_api_list.py
deleted file mode 100644
index b6aca56b2..000000000
--- a/wecom_base/models/wecom_server_api_list.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import re
-from odoo import api, fields, models, SUPERUSER_ID, _
-
-
-class WecomServerApiList(models.Model):
- _inherit = "wecom.service_api_list"
-
\ No newline at end of file
diff --git a/wecom_base/security/ir.model.access.csv b/wecom_base/security/ir.model.access.csv
deleted file mode 100644
index 0d0376f1f..000000000
--- a/wecom_base/security/ir.model.access.csv
+++ /dev/null
@@ -1,17 +0,0 @@
-id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
-wecom_service_api_access_right,access.wecom.service_api,model_wecom_service_api,group_wecom_settings_manager,1,1,1,1
-wecom_service_api_access_right_user,access.wecom.service_api,model_wecom_service_api,group_wecom_settings_user,1,0,0,0
-
-wecom_service_api_list_access_right,access.wecom.service_api_list,model_wecom_service_api_list,group_wecom_settings_manager,1,1,1,1
-wecom_service_api_list_access_right_user,access.wecom.service_api_list,model_wecom_service_api_list,group_wecom_settings_user,1,0,0,0
-
-wecom_service_api_error_access_right,access.wecom.service_api_error,model_wecom_service_api_error,group_wecom_settings_manager,1,1,1,1
-wecom_service_api_error_access_right_user,access.wecom.service_api_error,model_wecom_service_api_error,group_wecom_settings_user,1,0,0,0
-wecom_service_api_error_access_right_public,access.wecom.service_api_error,model_wecom_service_api_error,base.group_public,1,0,0,0
-
-wecom_app_type_access_right,access.wecom.app.type,model_wecom_app_type,group_wecom_settings_manager,1,1,1,1
-wecom_app_subtype_access_right,access.wecom.app.subtype,model_wecom_app_subtype,group_wecom_settings_manager,1,1,1,1
-wecom_apps_access_right,access.wecom.apps,model_wecom_apps,group_wecom_settings_manager,1,1,1,1
-wecom_app_callback_service_access_right,access.wecom.app.callback_service_right,model_wecom_app_callback_service,group_wecom_settings_manager,1,1,1,1
-wecom_app_config_access_right,access.wecom.app.config,model_wecom_app_config,group_wecom_settings_manager,1,1,1,1
-wecom_app_event_type_access_right,access.wecom.app.event_type_right,model_wecom_app_event_type,group_wecom_settings_manager,1,1,1,1
\ No newline at end of file
diff --git a/wecom_base/security/wecom_security.xml b/wecom_base/security/wecom_security.xml
deleted file mode 100644
index 23a53db91..000000000
--- a/wecom_base/security/wecom_security.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
- Helps you manage your WeCom.
- 1
-
-
-
- Officer
-
-
- The user will be able to approve document created by employees.
-
-
-
- Administrator
- The user will have access to the wecom configuration as well as statistic reports.
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_base/static/description/icon.png b/wecom_base/static/description/icon.png
deleted file mode 100644
index a08a666ef..000000000
Binary files a/wecom_base/static/description/icon.png and /dev/null differ
diff --git a/wecom_base/views/assets_templates.xml b/wecom_base/views/assets_templates.xml
deleted file mode 100644
index 4bcae1df6..000000000
--- a/wecom_base/views/assets_templates.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_base/views/ir_cron_views.xml b/wecom_base/views/ir_cron_views.xml
deleted file mode 100644
index 47a6dc2ac..000000000
--- a/wecom_base/views/ir_cron_views.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
- WeCom: Get the global error code of WeCom.
- ir.cron
- form
-
-
-
-
-
- WeCom: Get app token.
- ir.cron
- form
-
-
-
-
\ No newline at end of file
diff --git a/wecom_base/views/menu_views.xml b/wecom_base/views/menu_views.xml
deleted file mode 100644
index e2fa93914..000000000
--- a/wecom_base/views/menu_views.xml
+++ /dev/null
@@ -1,64 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_base/views/res_company_views.xml b/wecom_base/views/res_company_views.xml
deleted file mode 100644
index 6f18288b0..000000000
--- a/wecom_base/views/res_company_views.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
-
-
-
- res.company.form.inherit.wecom_base
- res.company
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- res.company.tree
- res.company
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_base/views/res_config_settings_views.xml b/wecom_base/views/res_config_settings_views.xml
deleted file mode 100644
index b035023c3..000000000
--- a/wecom_base/views/res_config_settings_views.xml
+++ /dev/null
@@ -1,207 +0,0 @@
-
-
-
-
- Settings
- res.config.settings
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Check, print some debugging information in IDE and log;
-
- For debugging
-
-
-
-
-
-
-
-
-
-
-
-
-
- The path used to save WeCom resources,Need to have read and write permissions on the path.
-
- reference:Windows: D:\\resources\\
- Linux or Docker: /var/lib/odoo/resources/
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The URL of the Wecom API global error code page for automatic crawling.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Get the [Code Name] and [Troubleshooting Method] of the global error code through the code
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Settings
- ir.actions.act_window
- res.config.settings
-
- form
- inline
- { 'module' : 'wecom_base', 'bin_size': False}
-
-
-
\ No newline at end of file
diff --git a/wecom_base/views/res_users_views.xml b/wecom_base/views/res_users_views.xml
deleted file mode 100644
index 028854c84..000000000
--- a/wecom_base/views/res_users_views.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
-
- users
- res.users
- tree,form
-
- [('is_wecom_user','=',1)]
- {}
-
-
-
-
-
- Click to add a new user.
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_base/views/wecom_app_callback_service_views.xml b/wecom_base/views/wecom_app_callback_service_views.xml
deleted file mode 100644
index c55f1a9c4..000000000
--- a/wecom_base/views/wecom_app_callback_service_views.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
-
-
- wecom.app_callback_service
-
-
-
-
-
-
-
-
-
-
-
-
- wecom.app_callback_service
-
-
-
-
-
-
- Application receive event service
- wecom.app_callback_service
- {'group_by':['app_id'],'active_test': False}
-
-
-
\ No newline at end of file
diff --git a/wecom_base/views/wecom_app_config_views.xml b/wecom_base/views/wecom_app_config_views.xml
deleted file mode 100644
index a113070c7..000000000
--- a/wecom_base/views/wecom_app_config_views.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
-
-
-
-
- wecom.app_config
-
-
-
-
-
-
-
-
-
-
-
-
-
- wecom.app_config
-
-
-
-
-
-
- Application Parameters
- wecom.app_config
- {'group_by':['company_id']}
-
-
-
\ No newline at end of file
diff --git a/wecom_base/views/wecom_app_event_type_views.xml b/wecom_base/views/wecom_app_event_type_views.xml
deleted file mode 100644
index 0031dfcfb..000000000
--- a/wecom_base/views/wecom_app_event_type_views.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-
-
-
-
-
- wecom.app.event_type.form
- wecom.app.event_type
-
-
-
-
-
- wecom.app.event_type.tree
- wecom.app.event_type
-
-
-
-
-
-
-
-
-
-
-
-
-
- Event Type
- wecom.app.event_type
- tree,form
- {}
-
-
-
-
\ No newline at end of file
diff --git a/wecom_base/views/wecom_app_subtype_views.xml b/wecom_base/views/wecom_app_subtype_views.xml
deleted file mode 100644
index f45d9cc4e..000000000
--- a/wecom_base/views/wecom_app_subtype_views.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
-
-
-
- wecom.app.subtype.search
- wecom.app.subtype
-
-
-
-
-
-
-
-
-
-
- wecom.app.subtype.tree
- wecom.app.subtype
-
-
-
-
-
-
-
-
-
-
- wecom.app.subtype.form
- wecom.app.subtype
-
-
-
-
-
-
- Application SubType
- wecom.app.subtype
- tree,form
- {}
-
-
-
-
\ No newline at end of file
diff --git a/wecom_base/views/wecom_app_type_views.xml b/wecom_base/views/wecom_app_type_views.xml
deleted file mode 100644
index 427107728..000000000
--- a/wecom_base/views/wecom_app_type_views.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
- wecom.app.type.tree
- wecom.app.type
-
-
-
-
-
-
-
-
-
- wecom.app.type.form
- wecom.app.type
-
-
-
-
-
-
- Application Type
- wecom.app.type
- tree,form
- {}
-
-
-
\ No newline at end of file
diff --git a/wecom_base/views/wecom_apps_views.xml b/wecom_base/views/wecom_apps_views.xml
deleted file mode 100644
index d997c6261..000000000
--- a/wecom_base/views/wecom_apps_views.xml
+++ /dev/null
@@ -1,258 +0,0 @@
-
-
-
-
- wecom.apps.search
- wecom.apps
-
-
-
-
-
-
-
-
-
-
-
-
-
- wecom.apps.kanban
- wecom.apps
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- wecom.apps.form
- wecom.apps
-
-
-
-
-
-
-
- wecom.apps.tree
- wecom.apps
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Application
- wecom.apps
- kanban,tree,form
- {'group_by':['company_id']}
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_base/views/wecom_base_views.xml b/wecom_base/views/wecom_base_views.xml
deleted file mode 100644
index 25c80bd9e..000000000
--- a/wecom_base/views/wecom_base_views.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
- Wecom Configurator
- ir.actions.act_window
- res.config.settings
- form
- main
- {'module' : 'wecom_base', 'bin_size': False}
-
-
-
- Open Wecom Configurator
- reload
-
-
-
-
- Start Wecom Configurator
-
- 0
-
-
-
\ No newline at end of file
diff --git a/wecom_base/views/wecom_service_api_error_views.xml b/wecom_base/views/wecom_service_api_error_views.xml
deleted file mode 100644
index f0c554f10..000000000
--- a/wecom_base/views/wecom_service_api_error_views.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
-
-
- wecom.service_api_error.search
- wecom.service_api_error
-
-
-
-
-
-
-
-
- wecom.service_api_error.form
- wecom.service_api_error
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- wecom.service_api_error.tree
- wecom.service_api_error
-
-
-
-
-
-
-
-
-
-
- Error Code
- wecom.service_api_error
- tree,form
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_base/views/wecom_service_api_list_views.xml b/wecom_base/views/wecom_service_api_list_views.xml
deleted file mode 100644
index 2780862b9..000000000
--- a/wecom_base/views/wecom_service_api_list_views.xml
+++ /dev/null
@@ -1,64 +0,0 @@
-
-
-
-
- wecom.service_api_list.search
- wecom.service_api_list
-
-
-
-
-
-
-
-
- wecom.service_api_list.form
- wecom.service_api_list
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- wecom.service_api_list.tree
- wecom.service_api_list
-
-
-
-
-
-
-
-
-
-
-
-
-
- API List
- wecom.service_api_list
- tree,form
- {'group_by':['type']}
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_contacts/__init__.py b/wecom_contacts/__init__.py
deleted file mode 100644
index 54a8ac548..000000000
--- a/wecom_contacts/__init__.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- coding: utf-8 -*-
-
-
-from . import models
-
-
-def post_init_hook(env):
- # env["ir.http"].clear_caches()
- # env["ir.ui.view"].clear_caches()
- env["ir.http"]._invalidate_cache()
- env["ir.ui.view"]._invalidate_cache()
diff --git a/wecom_contacts/__manifest__.py b/wecom_contacts/__manifest__.py
deleted file mode 100644
index af3458692..000000000
--- a/wecom_contacts/__manifest__.py
+++ /dev/null
@@ -1,48 +0,0 @@
-# -*- coding: utf-8 -*-
-{
- "name": "WeCom Contacts",
- "author": "RStudio",
- "website": "https://gitee.com/rainbowstudio/wecom",
- "sequence": 602,
- "installable": True,
- "application": True,
- "auto_install": False,
- "category": "WeCom Suites/CRM",
- "version": "17.0.0.1",
- "summary": """
- WeCom Contacts
- """,
- "description": """
-
-
- """,
- "depends": [
- "contacts",
- "hr",
- "wecom_base",
- "wecom_widget",
- ],
- "data": [
- "security/ir.model.access.csv",
- "data/ir_cron_data.xml",
- "data/wecom_apps_data.xml",
- "views/res_partner_views.xml",
- "views/res_partner_category_views.xml",
- "views/res_users_views.xml",
- "views/res_config_settings_views.xml",
- "views/res_company_views.xml",
- "views/ir_cron_views.xml",
- "views/menu_views.xml",
- ],
- "assets": {
- "web.assets_backend": [
- "wecom_contacts/static/src/webclient/**/*",
- ],
- },
- "external_dependencies": {
- "python": [],
- },
- "post_init_hook": "post_init_hook",
- "license": "AGPL-3",
- "bootstrap": True,
-}
diff --git a/wecom_contacts/data/ir_cron_data.xml b/wecom_contacts/data/ir_cron_data.xml
deleted file mode 100644
index 5a78ef7de..000000000
--- a/wecom_contacts/data/ir_cron_data.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-
-
-
-
-
- WeCom: Get API Domain IP
-
- code
- model.get_wecom_api_domain_ip()
-
- 2
- hours
- -1
-
-
-
-
-
- WeCom: Get join enterprise QR code
-
- code
- model.cron_get_join_qrcode()
-
- 2
- hours
- -1
-
-
-
-
-
- WeCom: Get Corp JSAPI Ticket
-
- code
- model.cron_get_corp_jsapi_ticket()
-
- 2
- hours
- -1
-
-
-
-
-
- WeCom: Get App JSAPI Ticket
-
- code
- model.cron_get_app_jsapi_ticket()
-
- 2
- hours
- -1
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_contacts/data/wecom_apps_data.xml b/wecom_contacts/data/wecom_apps_data.xml
deleted file mode 100644
index 75a888e1a..000000000
--- a/wecom_contacts/data/wecom_apps_data.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
-
- Contacts
- manage
-
-
-
- Contacts can be synchronized through the API interface or through third-party applications
- https://wwcdn.weixin.qq.com/node/wwmng/wwmng/style/images/icons/AppAddressSyncBig$c4dae6e7.svg
- 0
-
-
-
-
-
-
- The first application you built yourself.
- self
-
-
-
-
- 1
-
-
-
-
\ No newline at end of file
diff --git a/wecom_contacts/i18n/zh_CN.po b/wecom_contacts/i18n/zh_CN.po
deleted file mode 100644
index b9f33b4d2..000000000
--- a/wecom_contacts/i18n/zh_CN.po
+++ /dev/null
@@ -1,622 +0,0 @@
-# Translation of Odoo Server.
-# This file contains the translation of the following modules:
-# * wecom_contacts
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: Odoo Server 17.0\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2024-03-12 08:52+0000\n"
-"PO-Revision-Date: 2024-03-12 16:55+0800\n"
-"Last-Translator: \n"
-"Language-Team: \n"
-"Language: zh_CN\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Poedit 3.4.2\n"
-
-#. module: wecom_contacts
-#: model:ir.model.fields.selection,name:wecom_contacts.selection__res_company__wecom_contacts_join_qrcode_size_type__1
-msgid "171px x 171px"
-msgstr ""
-
-#. module: wecom_contacts
-#: model:ir.model.fields.selection,name:wecom_contacts.selection__res_company__wecom_contacts_join_qrcode_size_type__4
-msgid "2052px x 2052px"
-msgstr ""
-
-#. module: wecom_contacts
-#: model:ir.model.fields.selection,name:wecom_contacts.selection__res_company__wecom_contacts_join_qrcode_size_type__2
-msgid "399px x 399px"
-msgstr ""
-
-#. module: wecom_contacts
-#: model:ir.model.fields.selection,name:wecom_contacts.selection__res_company__wecom_contacts_join_qrcode_size_type__3
-msgid "741px x 741px"
-msgstr ""
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.res_config_settings_view_form
-msgid " "
-msgstr ""
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.res_config_settings_view_form
-msgid " "
-msgstr ""
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.res_config_settings_view_form
-msgid " "
-msgstr ""
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.res_config_settings_view_form
-msgid " "
-msgstr ""
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.view_res_users_kanban
-msgid " "
-msgstr " "
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.res_config_settings_view_form
-msgid "Save this page and come back here to set up other feature."
-msgstr "保存 此页面并返回此处以设置其它功能。"
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.res_config_settings_view_form
-msgid "Address book synchronization secret. Check it in \"Administrative Tools\" → \"Address Book Synchronization\" (need to turn on \"API interface synchronization\"). To ensure data security, the key must not be leaked."
-msgstr "通讯簿同步密钥。 在“管理工具”→“地址簿同步”中进行检查(需要打开“ API接口同步”)。 为了确保数据安全,切勿泄露密钥。"
-
-#. module: wecom_contacts
-#. odoo-javascript
-#: code:addons/wecom_contacts/static/src/webclient/settings_form_view/widgets/navigation.xml:0
-#, python-format
-msgid "Authentication settings"
-msgstr "身份认证设置"
-
-#. module: wecom_contacts
-#. odoo-python
-#: code:addons/wecom_contacts/models/res_config_settings.py:0
-#, python-format
-msgid "Automatic task:End obtaining joining enterprise QR code of company [%s]"
-msgstr "自动任务:结束获取公司[%s]的加入企业微信二维码"
-
-#. module: wecom_contacts
-#. odoo-python
-#: code:addons/wecom_contacts/models/res_config_settings.py:0
-#, python-format
-msgid "Automatic task:Error in obtaining the QR code of joining company [%s],error code: %s, error name: %s, error message: %s"
-msgstr "自动任务:获取加入公司[%s]的企微二维码出错,错误代码:%s,错误名称:%s,错误消息:%s"
-
-#. module: wecom_contacts
-#. odoo-python
-#: code:addons/wecom_contacts/models/res_config_settings.py:0
-#, python-format
-msgid "Automatic task:Please bind the contact app of company [%s]!"
-msgstr "自动任务:请绑定公司[%s]的通讯录应用!"
-
-#. module: wecom_contacts
-#. odoo-python
-#: code:addons/wecom_contacts/models/res_config_settings.py:0
-#, python-format
-msgid "Automatic task:Please enable the company [%s] to join the Wecom QR code function!"
-msgstr "自动任务:请启用公司[%s]加入企业微信二维码功能!"
-
-#. module: wecom_contacts
-#. odoo-python
-#: code:addons/wecom_contacts/models/res_config_settings.py:0
-#, python-format
-msgid "Automatic task:Start to get join enterprise QR code of company [%s]"
-msgstr "自动任务:开始获取公司[%s]的加入企业二维码"
-
-#. module: wecom_contacts
-#. odoo-python
-#: code:addons/wecom_contacts/models/res_company.py:0
-#, python-format
-msgid "Automatic tasks:End of company [%s] JSAPI ticket update"
-msgstr "自动任务:结束公司 [%s] JSAPI 临时凭证更新"
-
-#. module: wecom_contacts
-#. odoo-python
-#: code:addons/wecom_contacts/models/wecom_apps.py:0
-#, python-format
-msgid "Automatic tasks:Failed to get JSAPI ticket for app [%s], error: %s"
-msgstr "自动任务:无法获取应用 [%s] 的 JSAPI 临时凭证,错误:%s"
-
-#. module: wecom_contacts
-#. odoo-python
-#: code:addons/wecom_contacts/models/wecom_apps.py:0
-#, python-format
-msgid "Automatic tasks:JSAPI ticket for app [%s] is not expired, no need to update"
-msgstr "自动任务:应用 [%s] 的 JSAPI 临时凭证未过期,无需更新"
-
-#. module: wecom_contacts
-#. odoo-python
-#: code:addons/wecom_contacts/models/wecom_apps.py:0
-#, python-format
-msgid "Automatic tasks:Start getting JSAPI ticket for app [%s]"
-msgstr "自动任务:开始获取应用的 JSAPI 临时凭证 [%s]"
-
-#. module: wecom_contacts
-#. odoo-python
-#: code:addons/wecom_contacts/models/res_company.py:0
-#, python-format
-msgid "Automatic tasks:Start getting JSAPI ticket for company [%s]"
-msgstr "自动任务:开始获取公司的 JSAPI 临时凭证 [%s]"
-
-#. module: wecom_contacts
-#. odoo-python
-#: code:addons/wecom_contacts/models/wecom_apps.py:0
-#, python-format
-msgid "Automatic tasks:Start getting app [%s] ticket for company [%s]"
-msgstr "自动任务:开始获取应用 [%s] 的临时票证,公司 [%s]"
-
-#. module: wecom_contacts
-#. odoo-python
-#: code:addons/wecom_contacts/models/wecom_apps.py:0
-#, python-format
-msgid "Automatic tasks:Successfully get JSAPI ticket for app [%s]"
-msgstr "自动任务:成功获取应用 [%s]的 JSAPI 临时凭证"
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.res_config_settings_view_form
-msgid "Binding contacts application"
-msgstr "绑定通讯录应用"
-
-#. module: wecom_contacts
-#: model:ir.model,name:wecom_contacts.model_res_company
-msgid "Companies"
-msgstr "公司"
-
-#. module: wecom_contacts
-#: model:ir.model.fields,field_description:wecom_contacts.field_res_config_settings__company_id model:ir.model.fields,field_description:wecom_contacts.field_res_partner_category__company_id model_terms:ir.ui.view,arch_db:wecom_contacts.res_partner_category_view_search
-msgid "Company"
-msgstr "公司"
-
-#. module: wecom_contacts
-#: model:ir.model,name:wecom_contacts.model_res_config_settings
-msgid "Config Settings"
-msgstr "配置设置"
-
-#. module: wecom_contacts
-#: model:ir.model,name:wecom_contacts.model_res_partner
-msgid "Contact"
-msgstr "通讯录"
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.view_partner_category_form
-msgid "Contact Tag"
-msgstr "通讯录标签"
-
-#. module: wecom_contacts
-#: model:wecom.apps,app_name:wecom_contacts.wecom_app_contacts model_terms:ir.ui.view,arch_db:wecom_contacts.view_company_form
-msgid "Contacts"
-msgstr "通讯录"
-
-#. module: wecom_contacts
-#: model:ir.model.fields,field_description:wecom_contacts.field_res_company__contacts_app_id model:ir.model.fields,field_description:wecom_contacts.field_res_config_settings__contacts_app_id
-msgid "Contacts Application"
-msgstr "通讯录应用"
-
-#. module: wecom_contacts
-#: model:wecom.apps,description:wecom_contacts.wecom_app_contacts
-msgid "Contacts can be synchronized through the API interface or through third-party applications"
-msgstr "可通过API接口或第三方应用同步通讯录"
-
-#. module: wecom_contacts
-#: model:ir.model.fields,field_description:wecom_contacts.field_res_partner_category__display_name
-msgid "Display Name"
-msgstr "显示名称"
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.res_config_settings_view_form
-msgid "Display Wecom related functions on the personal portal page, and create a menu of Wecom applications."
-msgstr "在个人门户页面上显示企业微信相关功能,并创建企业微信应用菜单。"
-
-#. module: wecom_contacts
-#: model:ir.model.fields,field_description:wecom_contacts.field_res_company__wecom_contacts_join_qrcode_enabled model:ir.model.fields,field_description:wecom_contacts.field_res_config_settings__contacts_join_qrcode_enabled
-msgid "Enable to join the enterprise QR code"
-msgstr "启用加入企业微信二维码"
-
-#. module: wecom_contacts
-#. odoo-python
-#: code:addons/wecom_contacts/models/res_config_settings.py:0
-#, python-format
-msgid "End getting join enterprise QR code of company [%s]"
-msgstr "结束获取公司[%s]的加入企业微信二维码"
-
-#. module: wecom_contacts
-#. odoo-python
-#: code:addons/wecom_contacts/models/res_company.py:0 code:addons/wecom_contacts/models/res_config_settings.py:0
-#, python-format
-msgid "End obtaining Wecom API domain name IP segment"
-msgstr "结束获取企业微信API域名IP段"
-
-#. module: wecom_contacts
-#. odoo-python
-#: code:addons/wecom_contacts/models/res_company.py:0
-#, python-format
-msgid "Error in obtaining company [%s] ticket, reason: %s"
-msgstr "获取公司 [%s] 临时凭证时出错,原因:%s"
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.res_config_settings_view_form
-msgid "Expiration time"
-msgstr "到期时间"
-
-#. module: wecom_contacts
-#. odoo-python
-#: code:addons/wecom_contacts/models/res_partner_category.py:0
-#, python-format
-msgid "Failed to download tag [%s] member of company [%s]!"
-msgstr "未能下载标签成员[%s] ,其公司为[%s]!"
-
-#. module: wecom_contacts
-#: model:ir.ui.menu,name:wecom_contacts.menu_get_wecom_api_domain_ip model_terms:ir.ui.view,arch_db:wecom_contacts.res_config_settings_view_form
-msgid "Get API Domain IP"
-msgstr "获取API域名IP段"
-
-#. module: wecom_contacts
-#: model:ir.ui.menu,name:wecom_contacts.menu_get_wecom_app_jsapi_ticket
-msgid "Get App JSAPI Ticket"
-msgstr "获取应用JSAPI临时凭证"
-
-#. module: wecom_contacts
-#: model:ir.ui.menu,name:wecom_contacts.menu_get_wecom_corp_jsapi_ticket model_terms:ir.ui.view,arch_db:wecom_contacts.res_config_settings_view_form
-msgid "Get Corp JSAPI Ticket"
-msgstr "获取公司JSAPI临时凭证"
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.view_partner_form model_terms:ir.ui.view,arch_db:wecom_contacts.wecom_view_users_form
-msgid "Get OpenID"
-msgstr "获取OpenID"
-
-#. module: wecom_contacts
-#: model:ir.ui.menu,name:wecom_contacts.menu_wecom_app_join_qrcode
-msgid "Get join enterprise QR code"
-msgstr "获取加入企业微信二维码"
-
-#. module: wecom_contacts
-#: model:ir.model.fields,field_description:wecom_contacts.field_res_company__wecom_contacts_join_qrcode_last_time model:ir.model.fields,field_description:wecom_contacts.field_res_config_settings__contacts_join_qrcode_last_time
-msgid "Get the last time of QR code (UTC)"
-msgstr "获取二维码的最后时间(UTC)"
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.res_partner_category_view_search
-msgid "Group By"
-msgstr "分组"
-
-#. module: wecom_contacts
-#: model:ir.model.fields,field_description:wecom_contacts.field_res_partner__is_wecom_user model:ir.model.fields,field_description:wecom_contacts.field_res_users__is_wecom_user
-msgid "Is WeCom user"
-msgstr "是企微用户"
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.res_config_settings_view_form
-msgid ""
-"Is a temporary ticket for the H5 application to call the Wecom JS interface. Under normal circumstances, the validity period of jsapi_ticket is 7200 seconds , obtained by access_token. Since the number of API calls to the jsapi_ticket is very limited (an enterprise can get up to 400 times in "
-"an hour, and a single application cannot get more than 100 times), frequent refresh jsapi_ticket will cause the API call to be limited, affecting their own business, and developers must cache jsapi_ticket in their own service global cache ."
-msgstr ""
-"jsapi_ticket是H5应用调用企业微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒 ,通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限(一小时内,一个企业最多可获取400次,且单个应用不能超过100次),频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己"
-"的服务全局缓存\"\n"
-"\"jsapi_ticket 。"
-
-#. module: wecom_contacts
-#: model:ir.model.fields,field_description:wecom_contacts.field_res_company__wecom_contacts_join_qrcode model:ir.model.fields,field_description:wecom_contacts.field_res_config_settings__contacts_join_qrcode
-msgid "Join Wecom QR code"
-msgstr "加入企业微信二维码"
-
-#. module: wecom_contacts
-#: model:ir.model.fields,field_description:wecom_contacts.field_res_company__wecom_contacts_join_qrcode_size_type model:ir.model.fields,field_description:wecom_contacts.field_res_config_settings__contacts_join_qrcode_size_type
-msgid "Join Wecom QR code size type"
-msgstr "加入企微二维码大小类型"
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.res_config_settings_view_form
-msgid "Last Updated on"
-msgstr "最后更新时间"
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.wecom_view_users_form
-msgid "Login account"
-msgstr "登录帐户"
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.res_config_settings_view_form
-msgid "Management application"
-msgstr "管理应用"
-
-#. module: wecom_contacts
-#. odoo-javascript
-#: code:addons/wecom_contacts/static/src/webclient/settings_form_view/widgets/navigation.xml:0
-#, python-format
-msgid "Material settings"
-msgstr "素材设置"
-
-#. module: wecom_contacts
-#: model:ir.model,name:wecom_contacts.model_res_partner_category
-msgid "Partner Tags"
-msgstr "联系人标签"
-
-#. module: wecom_contacts
-#: model:ir.model.fields,field_description:wecom_contacts.field_res_partner__qr_code model:ir.model.fields,field_description:wecom_contacts.field_res_users__qr_code
-msgid "Personal QR code"
-msgstr "个人二维码"
-
-#. module: wecom_contacts
-#. odoo-python
-#: code:addons/wecom_contacts/models/res_company.py:0 code:addons/wecom_contacts/models/res_config_settings.py:0
-#, python-format
-msgid "Please bind contact app!"
-msgstr "请绑定通讯录应用!"
-
-#. module: wecom_contacts
-#. odoo-python
-#: code:addons/wecom_contacts/models/res_config_settings.py:0
-#, python-format
-msgid "Please enable the function of join enterprise QR code!"
-msgstr "请启用加入企业微信二维码功能!"
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.res_config_settings_view_form
-msgid "QR code"
-msgstr "二维码"
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.res_config_settings_view_form
-msgid "QR code size"
-msgstr "二维码尺寸"
-
-#. module: wecom_contacts
-#: model:ir.model.fields,field_description:wecom_contacts.field_res_config_settings__contacts_app_callback_service_ids
-msgid "Receive event service"
-msgstr "企微应用接收事件服务"
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.res_config_settings_view_form
-msgid "Refresh the QR code"
-msgstr "刷新二维码"
-
-#. module: wecom_contacts
-#: model:ir.model.fields,field_description:wecom_contacts.field_res_config_settings__contacts_secret
-msgid "Secret"
-msgstr "密钥"
-
-#. module: wecom_contacts
-#. odoo-python
-#: code:addons/wecom_contacts/models/res_config_settings.py:0
-#, python-format
-msgid "Start getting join enterprise QR code of company [%s]"
-msgstr "开始获取公司 [%s] 的加入企业微信二维码"
-
-#. module: wecom_contacts
-#. odoo-python
-#: code:addons/wecom_contacts/models/res_company.py:0 code:addons/wecom_contacts/models/res_config_settings.py:0
-#, python-format
-msgid "Start to get Wecom API domain name IP segment"
-msgstr "开始获取企业微信API域名IP段"
-
-#. module: wecom_contacts
-#. odoo-python
-#: code:addons/wecom_contacts/models/res_partner_category.py:0
-#, python-format
-msgid "Tag list downloaded successfully."
-msgstr "标签列表下载成功。"
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.res_config_settings_view_form
-msgid ""
-"The API domain name IP is the resolved address of the qyapi.weixin.qq.com, and the developer calls the access IP address of the Wecom terminal. If you need to configure a firewall, you can obtain all relevant IP segments through this interface. When the IP segment changes, the new and old IP "
-"segments will be retained for a period of time at the same time. We recommend that enterprises regularly pull IP segments every day and update firewall settings to avoid network blockage due to IP segment changes."
-msgstr "API域名IP即qyapi.weixin.qq.com的解析地址,由开发者调用企业微信端的接入IP。如果企业需要做防火墙配置,那么可以通过这个接口获取到所有相关的IP段。IP段有变更可能,当IP段变更时,新旧IP段会同时保留一段时间。建议企业每天定时拉取IP段,更新防火墙设置,避免因IP段变更导致网络不通。"
-
-#. module: wecom_contacts
-#. odoo-python
-#: code:addons/wecom_contacts/models/res_company.py:0
-#, python-format
-msgid "The company [%s] ticket is still valid and does not need to be updated!"
-msgstr "公司 [%s] 临时凭证仍然有效,不需要更新!"
-
-#. module: wecom_contacts
-#. odoo-python
-#: code:addons/wecom_contacts/models/res_partner_category.py:0
-#, python-format
-msgid "The current company does not identify the Wecom organization. Please configure or switch the company."
-msgstr "当前公司未标识为企业微信组织。请配置或切换公司。"
-
-#. module: wecom_contacts
-#: model:ir.model,name:wecom_contacts.model_res_users
-msgid "User"
-msgstr "用户"
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.wecom_view_users_form
-msgid "WeCom"
-msgstr "企微"
-
-#. module: wecom_contacts
-#: model:ir.model.fields,field_description:wecom_contacts.field_res_config_settings__module_wecom_approval
-msgid "WeCom Approvals"
-msgstr "企微审批"
-
-#. module: wecom_contacts
-#: model:ir.model.fields,field_description:wecom_contacts.field_res_config_settings__module_wecom_attendance
-msgid "WeCom Attendances"
-msgstr "企微出勤"
-
-#. module: wecom_contacts
-#: model:ir.model.fields,field_description:wecom_contacts.field_res_config_settings__module_wecom_auth_oauth
-msgid "WeCom Authentication"
-msgstr "企微身份验证"
-
-#. module: wecom_contacts
-#: model:ir.model.fields,field_description:wecom_contacts.field_res_config_settings__module_wecom_material
-msgid "WeCom Material"
-msgstr "企微素材"
-
-#. module: wecom_contacts
-#: model:ir.model.fields,field_description:wecom_contacts.field_res_config_settings__module_wecom_message
-msgid "WeCom Message"
-msgstr "企微消息"
-
-#. module: wecom_contacts
-#: model:ir.model.fields,field_description:wecom_contacts.field_res_partner__wecom_openid model:ir.model.fields,field_description:wecom_contacts.field_res_users__wecom_openid
-msgid "WeCom OpenID"
-msgstr "企微用户OpenID"
-
-#. module: wecom_contacts
-#. odoo-python
-#: code:addons/wecom_contacts/models/res_partner_category.py:0 model:ir.model.fields,field_description:wecom_contacts.field_res_partner_category__is_wecom_tag
-#, python-format
-msgid "WeCom Tag"
-msgstr "企微标签"
-
-#. module: wecom_contacts
-#: model:ir.model.fields,field_description:wecom_contacts.field_res_partner_category__tagid
-msgid "WeCom Tag ID"
-msgstr "企微标签ID"
-
-#. module: wecom_contacts
-#: model:ir.model.fields,field_description:wecom_contacts.field_res_partner__wecom_userid model:ir.model.fields,field_description:wecom_contacts.field_res_users__wecom_userid
-msgid "WeCom User ID"
-msgstr "企微用户ID"
-
-#. module: wecom_contacts
-#: model:ir.model.fields,field_description:wecom_contacts.field_res_partner__wecom_user_order model:ir.model.fields,field_description:wecom_contacts.field_res_users__wecom_user_order
-msgid "WeCom User sequence"
-msgstr "企微用户排序"
-
-#. module: wecom_contacts
-#: model:ir.actions.server,name:wecom_contacts.ir_cron_get_wecom_api_domain_ip_ir_actions_server
-msgid "WeCom: Get API Domain IP"
-msgstr "企微:获取API域名IP段"
-
-#. module: wecom_contacts
-#: model:ir.actions.act_window,name:wecom_contacts.ir_cron_act_get_wecom_api_domain_ip
-msgid "WeCom: Get API Domain IP."
-msgstr "企微:获取API域名IP段。"
-
-#. module: wecom_contacts
-#: model:ir.actions.server,name:wecom_contacts.ir_cron_get_app_jsapi_ticket_ir_actions_server
-msgid "WeCom: Get App JSAPI Ticket"
-msgstr "企微:获取应用JSAPI临时凭证"
-
-#. module: wecom_contacts
-#: model:ir.actions.act_window,name:wecom_contacts.ir_cron_act_get_app_jsapi_ticket
-msgid "WeCom: Get App JSAPI Ticket."
-msgstr "企微:获取应用JSAPI临时凭证。"
-
-#. module: wecom_contacts
-#: model:ir.actions.server,name:wecom_contacts.ir_cron_get_corp_jsapi_ticket_ir_actions_server
-msgid "WeCom: Get Corp JSAPI Ticket"
-msgstr "企微:获取公司JSAPI临时凭证"
-
-#. module: wecom_contacts
-#: model:ir.actions.act_window,name:wecom_contacts.ir_cron_act_get_corp_jsapi_ticket
-msgid "WeCom: Get Corp JSAPI Ticket."
-msgstr "企微:获取公司JSAPI临时凭证。"
-
-#. module: wecom_contacts
-#: model:ir.actions.server,name:wecom_contacts.ir_cron_get_join_qrcode_ir_actions_server
-msgid "WeCom: Get join enterprise QR code"
-msgstr "企微:获取加入企业二维码"
-
-#. module: wecom_contacts
-#: model:ir.actions.act_window,name:wecom_contacts.ir_cron_act_get_join_qrcode
-msgid "WeCom: Get join enterprise QR code."
-msgstr "企微:获取加入企业二维码。"
-
-#. module: wecom_contacts
-#: model:ir.model.fields,field_description:wecom_contacts.field_res_config_settings__wecom_api_domain_ip
-msgid "Wecom API Domain IP"
-msgstr "企微API域名IP段"
-
-#. module: wecom_contacts
-#: model:ir.model,name:wecom_contacts.model_wecom_apps
-msgid "Wecom Application"
-msgstr "企微应用"
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.res_config_settings_view_form
-msgid "Wecom Authentication Settings"
-msgstr "企微身份验证设置"
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.view_partner_category_form
-msgid "Wecom Info"
-msgstr "企微信息"
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.res_config_settings_view_form
-msgid "Wecom Material settings"
-msgstr "企微素材设置"
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.res_config_settings_view_form
-msgid "Wecom Message Settings"
-msgstr "企微消息设置"
-
-#. module: wecom_contacts
-#: model:ir.model.fields,field_description:wecom_contacts.field_res_config_settings__module_wecom_portal
-msgid "Wecom Portal"
-msgstr "企微门户"
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.res_config_settings_view_form
-msgid "Wecom Portal Settings"
-msgstr "企微门户设置"
-
-#. module: wecom_contacts
-#: model:ir.model.fields,field_description:wecom_contacts.field_res_config_settings__module_wecom_msgaudit
-msgid "Wecom Session Content Archive"
-msgstr "企微会话内容存档"
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.res_config_settings_view_form
-msgid "Wecom has opened message sending interfaces. Enterprises can use these interfaces to enable two-way communication between custom applications and Wecom background or users."
-msgstr "企业微信开放了消息发送接口,企业可以使用这些接口让自定义应用与企业微信后台或用户间进行双向通信。"
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.view_partner_form
-msgid "Wecom information"
-msgstr "企微信息"
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.res_config_settings_view_form
-msgid ""
-"Wecom provides OAuth's authorized login mode, which allows you to obtain the identity information of members from the web page opened by the Wecom terminal, thus eliminating the login link.\n"
-" \n"
-" Wecom provides OAuth code scanning login authorization method, which can guide members to use Wecom code scanning login authorization when the enterprise website is opened in the browser, so as to obtain the identity information of members and avoid the login link."
-msgstr ""
-"企业微信提供了OAuth的授权登录方式,可以让从企业微信终端打开的网页获取成员的身份信息,从而免去登录的环节。\n"
-" \n"
-" 企业微信提供了OAuth的扫码登录授权方式,可以让企业的网站在浏览器内打开时,引导成员使用企业微信扫码登录授权,从而获取成员的身份信息,免去登录的环节。"
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.res_partner_kanban_view
-msgid "Wecom user"
-msgstr "企微用户"
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.res_config_settings_view_form
-msgid ""
-"When using the Wecom API interface, developers often need to use custom resources, such as sending local picture messages, setting address book custom avatars, etc. \n"
-" In order to realize the same resource file, one upload can be used multiple times. Here is a material management interface: media_ ID to identify resource files and realize file upload and download."
-msgstr ""
-"在使用企业微信API接口中,往往开发者需要使用自定义的资源,比如发送本地图片消息,设置通讯录自定义头像等。 \n"
-" 为了实现同一资源文件,一次上传可以多次使用,这里提供了素材管理接口:以media_id来标识资源文件,实现文件的上传与下载。"
-
-#. module: wecom_contacts
-#: model_terms:ir.ui.view,arch_db:wecom_contacts.view_partner_category_form
-msgid "e.g. \"Consulting Services\""
-msgstr "例如:咨询服务"
-
-#. module: wecom_contacts
-#: model:wecom.apps,app_name:wecom_contacts.wecom_app_first_self_app
-msgid "iERP"
-msgstr ""
diff --git a/wecom_contacts/models/__init__.py b/wecom_contacts/models/__init__.py
deleted file mode 100644
index 7413b85cd..000000000
--- a/wecom_contacts/models/__init__.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- coding: utf-8 -*-
-
-
-from . import res_users
-from . import res_partner
-from . import res_partner_category
-from . import res_company
-from . import res_config_settings
-from . import wecom_apps
-
diff --git a/wecom_contacts/models/hr_employee.py b/wecom_contacts/models/hr_employee.py
deleted file mode 100644
index ecd05ed17..000000000
--- a/wecom_contacts/models/hr_employee.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from odoo import api, fields, models
-
-class HrEmployeePrivate(models.Model):
- _inherit = "hr.employee"
-
-
\ No newline at end of file
diff --git a/wecom_contacts/models/res_company.py b/wecom_contacts/models/res_company.py
deleted file mode 100644
index 307dca4df..000000000
--- a/wecom_contacts/models/res_company.py
+++ /dev/null
@@ -1,170 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from ast import literal_eval
-from collections import defaultdict
-
-from odoo.exceptions import UserError, ValidationError
-from datetime import datetime, timedelta
-from odoo.http import request
-from odoo import api, fields, models, tools, _
-from odoo.addons.wecom_api.api.wecom_abstract_api import ApiException # type: ignore
-import logging
-
-_logger = logging.getLogger(__name__)
-
-
-class Company(models.Model):
- _inherit = "res.company"
-
- # 通讯录
- contacts_app_id = fields.Many2one(
- "wecom.apps",
- string="Contacts Application",
- # required=True,
- # default=lambda self: self.env.company,
- domain="[('company_id', '=', current_company_id)]",
- )
-
- # contacts_app_event_service_state = fields.Boolean(
- # string="Contacts Application Event Service State",
- # )
- # contacts_app_event_service_url = fields.Char(
- # string="Contacts Application Event Service URL",
- # )
- # contacts_app_event_service_token = fields.Char(
- # string="Contacts Application Event Service Token",
- # )
- # contacts_app_event_service_key = fields.Char(
- # string="Contacts Application Event Service AES Key",
- # )
-
- wecom_contacts_join_qrcode_enabled = fields.Boolean(
- string="Enable to join the enterprise QR code",
- default=True,
- copy=False,
- )
- wecom_contacts_join_qrcode = fields.Char(
- string="Join Wecom QR code",
- copy=False,
- readonly=True,
- )
- wecom_contacts_join_qrcode_size_type = fields.Selection(
- [
- ("1", "171px x 171px"),
- ("2", "399px x 399px"),
- ("3", "741px x 741px"),
- ("4", "2052px x 2052px"),
- ],
- string="Join Wecom QR code size type",
- default="2",
- required=True,
- )
- wecom_contacts_join_qrcode_last_time = fields.Datetime(
- string="Get the last time of QR code (UTC)",
- copy=False,
- )
-
- def generate_contacts_app_event_service_url(self):
- """
- 生产通讯录事件服务的URL
- """
- ICP = self.env["ir.config_parameter"].sudo()
- base_url = ICP.get_param("web.base.url")
- if not self.contacts_app_id:
- raise ValidationError(_("Please bind contact app!"))
- else:
- callback_url = base_url + "/wecom_callback/%s/contacts" % self.id
- self.write({"contacts_app_event_service_url": callback_url})
- # return callback_url
-
- def cron_get_corp_jsapi_ticket(self):
- """
- 定时任务,每隔两小时更新企业的jsapi_ticket
- """
- for company in self:
- if company.is_wecom_organization and company.corpid and company.contacts_app_id: # type: ignore
- _logger.info(
- _("Automatic tasks:Start getting JSAPI ticket for company [%s]")
- % (company.name) # type: ignore
- )
- if (
- company.corp_jsapi_ticket_expiration_time # type: ignore
- and company.corp_jsapi_ticket_expiration_time > datetime.now() # type: ignore
- ):
- _logger.info(
- _(
- "The company [%s] ticket is still valid and does not need to be updated!"
- )
- % (company.name) # type: ignore
- )
- else:
- try:
- wecom_api = self.env["wecom.service_api"].InitServiceApi(
- self.company_id.corpid, self.contacts_app_id.secret # type: ignore
- )
- response = wecom_api.httpCall(
- self.env["wecom.service_api_list"].get_server_api_call(
- "GET_JSAPI_TICKET"
- ),
- {},
- )
- except ApiException as ex:
- _logger.error(
- _("Error in obtaining company [%s] ticket, reason: %s")
- % (company.name, ex) # type: ignore
- )
- else:
- if response["errcode"] == 0:
- company.write(
- {
- "corp_jsapi_ticket": response["ticket"],
- "corp_jsapi_ticket_expiration_time": datetime.now()
- + timedelta(seconds=response["expires_in"]),
- }
- )
- finally:
- _logger.info(
- _("Automatic tasks:End of company [%s] JSAPI ticket update")
- % (company.name) # type: ignore
- )
-
- # TODO: 使用任务 获取IP
-
- # def cron_get_wecom_api_domain_ip(self):
- def get_wecom_api_domain_ip(self):
- """
- 获取企业微信API域名IP段
- """
- ir_config = self.env["ir.config_parameter"].sudo()
- debug = ir_config.get_param("wecom.debug_enabled")
- companies = self.search([])
-
- for company in companies: # type: ignore
- if not company.contacts_app_id: # type: ignore
- raise ValidationError(_("Please bind contact app!"))
-
- if debug:
- _logger.info(_("Start to get Wecom API domain name IP segment"))
- try:
- wecomapi = self.env["wecom.service_api"].InitServiceApi(company.corpid, company.contacts_app_id.secret) # type: ignore
-
- response = wecomapi.httpCall(
- self.env["wecom.service_api_list"].get_server_api_call(
- "GET_API_DOMAIN_IP"
- ),
- {},
- )
- if response["errcode"] == 0:
- self.env["ir.config_parameter"].set_param(
- "wecom.api_domain_ip", response["ip_list"]
- )
- return {"type": "ir.actions.client", "tag": "reload"} # 刷新页面
-
- except ApiException as ex:
- return self.env["wecomapi.tools.action"].ApiExceptionDialog(
- ex, raise_exception=True
- )
-
- finally:
- if debug:
- _logger.info(_("End obtaining Wecom API domain name IP segment"))
diff --git a/wecom_contacts/models/res_config_settings.py b/wecom_contacts/models/res_config_settings.py
deleted file mode 100644
index 7222cff39..000000000
--- a/wecom_contacts/models/res_config_settings.py
+++ /dev/null
@@ -1,244 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import datetime
-from odoo import models, fields, api, _
-from odoo.exceptions import UserError, ValidationError
-import time
-
-from odoo.addons.wecom_api.api.wecom_abstract_api import ApiException # type: ignore
-
-import logging
-
-_logger = logging.getLogger(__name__)
-
-
-class ResConfigSettings(models.TransientModel):
- _inherit = "res.config.settings"
-
- company_id = fields.Many2one(
- "res.company",
- string="Company",
- required=True,
- default=lambda self: self.env.company,
- )
-
- wecom_api_domain_ip = fields.Char(
- "Wecom API Domain IP",
- config_parameter="wecom.api_domain_ip",
- )
-
- # 加入企微微信二维码
- contacts_join_qrcode_enabled = fields.Boolean(
- related="company_id.wecom_contacts_join_qrcode_enabled", readonly=False
- )
- contacts_join_qrcode = fields.Char(
- related="company_id.wecom_contacts_join_qrcode", readonly=False
- )
- contacts_join_qrcode_size_type = fields.Selection(
- related="company_id.wecom_contacts_join_qrcode_size_type", readonly=False
- )
- contacts_join_qrcode_last_time = fields.Datetime(
- related="company_id.wecom_contacts_join_qrcode_last_time", readonly=False
- )
-
- # 通讯录应用
- contacts_app_id = fields.Many2one(
- related="company_id.contacts_app_id", readonly=False, store=True
- )
-
- contacts_secret = fields.Char(related="contacts_app_id.secret", readonly=False)
-
- # contacts_access_token = fields.Char(related="contacts_app_id.access_token")
-
- # contacts_app_config_ids = fields.One2many(
- # related="contacts_app_id.app_config_ids",
- # readonly=False,
- # )
-
- contacts_app_callback_service_ids = fields.One2many(
- related="contacts_app_id.app_callback_service_ids", readonly=False
- )
-
- # 其他应用
-
- module_wecom_material = fields.Boolean("WeCom Material")
- module_wecom_auth_oauth = fields.Boolean("WeCom Authentication")
- module_wecom_message = fields.Boolean("WeCom Message")
- module_wecom_portal = fields.Boolean("Wecom Portal")
- module_wecom_msgaudit = fields.Boolean("Wecom Session Content Archive")
- module_wecom_attendance = fields.Boolean("WeCom Attendances")
- module_wecom_approval = fields.Boolean("WeCom Approvals")
-
- def cron_get_join_qrcode(self):
- """
- 自动任务获取加入企业二维码
- """
- companies = self.env["res.company"].search(
- [
- ("is_wecom_organization", "=", True),
- ("wecom_contacts_join_qrcode_enabled", "=", True),
- ]
- )
- for company in companies:
- _logger.info(
- _("Automatic task:Start to get join enterprise QR code of company [%s]")
- % (company.name)
- )
- if not company.contacts_app_id:
- _logger.info(
- _("Automatic task:Please bind the contact app of company [%s]!")
- % (company.name)
- )
- elif not company.wecom_contacts_join_qrcode_enabled:
- _logger.info(
- _(
- "Automatic task:Please enable the company [%s] to join the Wecom QR code function!"
- )
- % (company.name)
- )
- else:
- try:
- wecomapi = self.env["wecom.service_api"].InitServiceApi(
- company.corpid, company.contacts_app_id.secret
- )
-
- last_time = company.wecom_contacts_join_qrcode_last_time
- size_type = company.wecom_contacts_join_qrcode_size_type
- # 超期
- overdue = False
- if last_time:
- overdue = self.env[
- "wecomapi.tools.datetime"
- ].cheeck_days_overdue(last_time, 7)
- if not last_time or overdue:
- response = wecomapi.httpCall(
- self.env["wecom.service_api_list"].get_server_api_call(
- "GET_JOIN_QRCODE"
- ),
- {"size_type": size_type},
- )
- if response["errcode"] == 0:
- company.write(
- {
- "wecom_contacts_join_qrcode": response[
- "join_qrcode"
- ],
- "wecom_contacts_join_qrcode_last_time": datetime.datetime.now(),
- }
- )
- except ApiException as ex:
- error = self.env["wecom.service_api_error"].get_error_by_code(
- ex.errCode
- )
- _logger.warning(
- _(
- "Automatic task:Error in obtaining the QR code of joining company [%s],error code: %s, error name: %s, error message: %s"
- )
- % (company.name, str(ex.errCode), error["name"], ex.errMsg)
- )
- _logger.info(
- _(
- "Automatic task:End obtaining joining enterprise QR code of company [%s]"
- )
- % (company.name)
- )
-
- def get_join_qrcode(self):
- """
- 获取加入企业二维码
- """
- # self.contacts_app_id.get_join_qrcode()
- ir_config = self.env["ir.config_parameter"].sudo()
- debug = ir_config.get_param("wecom.debug_enabled")
-
- if not self.contacts_app_id:
- raise ValidationError(_("Please bind contact app!"))
-
- if not self.contacts_join_qrcode_enabled:
- raise ValidationError(
- _("Please enable the function of join enterprise QR code!")
- )
-
- if debug:
- _logger.info(
- _("Start getting join enterprise QR code of company [%s]")
- % (self.company_id.name) # type: ignore
- )
- try:
- wecomapi = self.env["wecom.service_api"].InitServiceApi(
- self.company_id.corpid, self.contacts_app_id.secret # type: ignore
- )
-
- last_time = self.contacts_join_qrcode_last_time
- size_type = self.contacts_join_qrcode_size_type
- # 超期
- overdue = False
- if last_time:
- overdue = self.env["wecomapi.tools.datetime"].cheeck_days_overdue(
- last_time, 7
- )
- if not last_time or overdue:
- response = wecomapi.httpCall(
- self.env["wecom.service_api_list"].get_server_api_call(
- "GET_JOIN_QRCODE"
- ),
- {"size_type": size_type},
- )
- if response["errcode"] == 0:
- self.company_id.write( # type: ignore
- {
- "wecom_contacts_join_qrcode": response["join_qrcode"],
- "wecom_contacts_join_qrcode_last_time": datetime.datetime.now(),
- }
- )
- return {"type": "ir.actions.client", "tag": "reload"} # 刷新页面
- # self.contacts_join_qrcode=response["join_qrcode"]
- # self.contacts_join_qrcode_last_time = datetime.datetime.now()
-
- except ApiException as ex:
- return self.env["wecomapi.tools.action"].ApiExceptionDialog(
- ex, raise_exception=True
- )
-
- finally:
- if debug:
- _logger.info(
- _("End getting join enterprise QR code of company [%s]")
- % (self.company_id.name) # type: ignore
- )
-
- def get_wecom_api_domain_ip(self):
- """
- 获取企业微信API域名IP段
- """
- ir_config = self.env["ir.config_parameter"].sudo()
- debug = ir_config.get_param("wecom.debug_enabled")
-
- if not self.company_id.contacts_app_id: # type: ignore
- raise ValidationError(_("Please bind contact app!"))
-
- if debug:
- _logger.info(_("Start to get Wecom API domain name IP segment"))
- try:
- wecomapi = self.env["wecom.service_api"].InitServiceApi(self.company_id.corpid, self.company_id.contacts_app_id.secret) # type: ignore
-
- response = wecomapi.httpCall(
- self.env["wecom.service_api_list"].get_server_api_call(
- "GET_API_DOMAIN_IP"
- ),
- {},
- )
- if response["errcode"] == 0:
- self.env["ir.config_parameter"].set_param(
- "wecom.api_domain_ip", response["ip_list"]
- )
- return {"type": "ir.actions.client", "tag": "reload"} # 刷新页面
-
- except ApiException as ex:
- return self.env["wecomapi.tools.action"].ApiExceptionDialog(
- ex, raise_exception=True
- )
-
- finally:
- if debug:
- _logger.info(_("End obtaining Wecom API domain name IP segment"))
diff --git a/wecom_contacts/models/res_partner.py b/wecom_contacts/models/res_partner.py
deleted file mode 100644
index 187471d8f..000000000
--- a/wecom_contacts/models/res_partner.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import logging
-from odoo import api, fields, models, Command, _
-
-from odoo.addons.wecom_api.api.wecom_abstract_api import ApiException # type: ignore
-
-_logger = logging.getLogger(__name__)
-
-
-class Partner(models.Model):
- _inherit = "res.partner"
-
- wecom_userid = fields.Char(
- string="WeCom User ID",
- readonly=True,
- )
- wecom_openid = fields.Char(
- string="WeCom OpenID",
- readonly=True,
- )
-
- is_wecom_user = fields.Boolean(
- "Is WeCom user",
- readonly=True,
- )
- qr_code = fields.Char(
- string="Personal QR code",
- readonly=True,
- )
- wecom_user_order = fields.Char(
- "WeCom User sequence",
- default="0",
- readonly=True,
- )
-
- def get_wecom_openid(self):
- """
- 获取企微OpenID
- """
- for partner in self:
- print(partner.company_id) # type: ignore
- try:
- wxapi = self.env["wecom.service_api"].InitServiceApi(
- partner.company_id.corpid, # type: ignore
- partner.company_id.contacts_app_id.secret, # type: ignore
- )
- response = wxapi.httpCall(
- self.env["wecom.service_api_list"].get_server_api_call(
- "USERID_TO_OPENID"
- ),
- {
- "userid": partner.wecom_userid, # type: ignore
- },
- )
- except ApiException as ex:
- self.env["wecomapi.tools.action"].ApiExceptionDialog(
- ex, raise_exception=True
- )
- else:
- partner.wecom_openid = response["openid"] # type: ignore
diff --git a/wecom_contacts/models/res_partner_category.py b/wecom_contacts/models/res_partner_category.py
deleted file mode 100644
index 3bafba3f1..000000000
--- a/wecom_contacts/models/res_partner_category.py
+++ /dev/null
@@ -1,297 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import logging
-import base64
-import time
-from lxml import etree
-from odoo import api, fields, models, _
-
-# from lxml_to_dict import lxml_to_dict
-import xmltodict
-from odoo.addons.wecom_api.api.wecom_abstract_api import ApiException # type: ignore
-
-_logger = logging.getLogger(__name__)
-
-WECOM_USER_MAPPING_ODOO_PARTNER_CATEGORY = {
- "TagId": "tagid", # 标签Id
- "AddUserItems": "add_partner_ids", # 标签中新增的成员userid列表,用逗号分隔
- "DelUserItems": "del_partner_ids", # 标签中删除的成员userid列表,用逗号分隔
- "AddPartyItems": "", # 标签中新增的部门id列表,用逗号分隔
- "DelPartyItems": "", # 标签中删除的部门id列表,用逗号分隔
-}
-
-
-class PartnerCategory(models.Model):
- _inherit = "res.partner.category"
-
- company_id = fields.Many2one(
- "res.company",
- string="Company",
- index=True,
- default=lambda self: self.env.company,
- readonly=True,
- )
-
- display_name = fields.Char(string="Display Name", compute="_compute_display_name")
- tagid = fields.Integer(
- string="WeCom Tag ID",
- readonly=True,
- default=0,
- )
- is_wecom_tag = fields.Boolean(
- string="WeCom Tag",
- default=False,
- )
-
- @api.depends("is_wecom_tag")
- def _compute_display_name(self):
- tag = _("WeCom Tag")
- for rec in self:
- if rec.is_wecom_tag: # type: ignore
- rec.display_name = "%s:%s" % (tag, rec.name) # type: ignore
- else:
- rec.display_name = rec.name # type: ignore
-
- @api.model
- def download_wecom_contact_tags(self):
- """
- 下载企微标签列表 res.partner.category
- """
- start_time = time.time()
- company = self.env.context.get("company_id")
-
- tasks = []
- if not company:
- company = self.env.company
- if company.is_wecom_organization:
- try:
- wxapi = self.env["wecom.service_api"].InitServiceApi(
- company.corpid, company.contacts_app_id.secret
- )
- response = wxapi.httpCall(
- self.env["wecom.service_api_list"].get_server_api_call(
- "TAG_GET_LIST"
- )
- )
-
- except ApiException as ex:
- end_time = time.time()
- self.env["wecomapi.tools.action"].ApiExceptionDialog(
- ex, raise_exception=False
- )
- tasks = [
- {
- "name": "download_tag_data",
- "state": False,
- "time": end_time - start_time,
- "msg": str(ex),
- }
- ]
- except Exception as e:
- end_time = time.time()
- tasks = [
- {
- "name": "download_tag_data",
- "state": False,
- "time": end_time - start_time,
- "msg": str(e),
- }
- ]
- else:
- tags = response["taglist"]
- for tag in tags:
- category = self.search(
- [
- ("tagid", "=", tag["tagid"]),
- ("company_id", "=", company.id),
- ],
- limit=1,
- )
-
- if not category:
- category.create( # type: ignore
- {
- "name": tag["tagname"],
- "tagid": tag["tagid"],
- "is_wecom_tag": True,
- }
- )
- else:
- category.write( # type: ignore
- {
- "name": tag["tagname"],
- "is_wecom_tag": True,
- }
- )
- result = self.download_wecom_tag_member(
- category, wxapi, tag["tagid"], company
- )
- if result:
- tasks.append(
- {
- "name": "download_tag_members",
- "state": False,
- "time": 0,
- "msg": _(
- "Failed to download tag [%s] member of company [%s]!"
- )
- % (tag["tagname"], company.name),
- }
- )
- finally:
- end_time = time.time()
- task = {
- "name": "download_tag_data",
- "state": True,
- "time": end_time - start_time,
- "msg": _("Tag list downloaded successfully."),
- }
- tasks.append(task)
- else:
- end_time = time.time()
- tasks = [
- {
- "name": "download_tag_data",
- "state": False,
- "time": end_time - start_time,
- "msg": _(
- "The current company does not identify the Wecom organization. Please configure or switch the company."
- ),
- }
- ]
- return tasks
-
- def download_wecom_tag_member(self, category, wxapi, tagid, company):
- """
- 下载企微标签成员
- """
- res = {}
- try:
- response = wxapi.httpCall(
- self.env["wecom.service_api_list"].get_server_api_call(
- "TAG_GET_MEMBER"
- ),
- {"tagid": str(tagid)},
- )
- except ApiException as ex:
- self.env["wecomapi.tools.action"].ApiExceptionDialog(
- ex, raise_exception=False
- )
- res = {
- "name": "download_tag_members",
- "state": False,
- "time": 0,
- "msg": repr(ex),
- }
- except Exception as e:
- res = {
- "name": "download_tag_members",
- "state": False,
- "time": 0,
- "msg": repr(e),
- }
- else:
- partner_ids = []
- for user in response["userlist"]:
- partner = (
- self.env["res.partner"]
- .sudo()
- .search(
- [
- ("wecom_userid", "=", user["userid"].lower()),
- ("company_id", "=", company.id),
- ("is_wecom_user", "=", True),
- "|",
- ("active", "=", True),
- ("active", "=", False),
- ],
- limit=1,
- )
- )
- if partner:
- partner_ids.append(partner.id)
- if len(partner_ids) > 0:
- category.write({"partner_ids": [(6, 0, partner_ids)]})
-
- finally:
- return res # 返回失败的结果
-
- # ------------------------------------------------------------
- # 企微通讯录事件
- # ------------------------------------------------------------
- # def wecom_event_change_contact_tag(self, cmd):
- # """
- # 通讯录事件更新标签
- # """
- # xml_tree = self.env.context.get("xml_tree")
- # company_id = self.env.context.get("company_id")
- # xml_tree_str = etree.fromstring(bytes.decode(xml_tree))
- # dic = lxml_to_dict(xml_tree_str)["xml"]
-
- # callback_tag = self.sudo().search(
- # [("company_id", "=", company_id.id), ("tagid", "=", dic["TagId"])],
- # limit=1,
- # )
-
- # domain = [
- # "|",
- # ("active", "=", True),
- # ("active", "=", False),
- # ]
- # partner = (
- # self.env["res.partner"]
- # .sudo()
- # .search([("company_id", "=", company_id.id)] + domain)
- # )
- # update_dict = {}
-
- # for key, value in dic.items():
- # if (
- # key == "ToUserName"
- # or key == "FromUserName"
- # or key == "CreateTime"
- # or key == "Event"
- # or key == "MsgType"
- # or key == "ChangeType"
- # ):
- # # 忽略掉 不需要的key
- # pass
- # else:
- # if key in WECOM_USER_MAPPING_ODOO_PARTNER_CATEGORY.keys():
- # if WECOM_USER_MAPPING_ODOO_PARTNER_CATEGORY[key] != "":
- # update_dict[
- # WECOM_USER_MAPPING_ODOO_PARTNER_CATEGORY[key]
- # ] = value
- # else:
- # _logger.info(
- # _(
- # "There is no mapping for field [%s], please contact the developer."
- # )
- # % key
- # )
-
- # add_partner_list = []
- # del_partner_list = []
-
- # if "add_partner_ids" in update_dict.keys():
- # for wecom_userid in update_dict["add_partner_ids"].split(","):
- # add_partner_list.append(
- # partner.search(
- # [("wecom_userid", "=", wecom_userid.lower())], limit=1
- # ).id
- # )
- # elif "del_partner_ids" in update_dict.keys():
- # for wecom_userid in update_dict["del_partner_ids"].split(","):
- # del_partner_list.append(
- # partner.search(
- # [("wecom_userid", "=", wecom_userid.lower())], limit=1
- # ).id
- # )
- # if len(add_partner_list) > 0:
- # callback_tag.write(
- # {"partner_ids": [(4, res, False) for res in add_partner_list]}
- # )
- # if len(del_partner_list) > 0:
- # callback_tag.write(
- # {"partner_ids": [(3, res, False) for res in del_partner_list]}
- # )
diff --git a/wecom_contacts/models/res_users.py b/wecom_contacts/models/res_users.py
deleted file mode 100644
index 01db7227a..000000000
--- a/wecom_contacts/models/res_users.py
+++ /dev/null
@@ -1,34 +0,0 @@
-# -*- coding: utf-8 -*-
-
-
-from odoo import models, _
-from odoo.addons.wecom_api.api.wecom_abstract_api import ApiException # type: ignore
-
-
-class User(models.Model):
- _inherit = ["res.users"]
-
- def get_wecom_openid(self):
- """
- 获取企微OpenID
- """
- for user in self:
- try:
- wxapi = self.env["wecom.service_api"].InitServiceApi(
- user.company_id.corpid, # type: ignore
- user.company_id.contacts_app_id.secret, # type: ignore
- )
- response = wxapi.httpCall(
- self.env["wecom.service_api_list"].get_server_api_call(
- "USERID_TO_OPENID"
- ),
- {
- "userid": user.wecom_userid, # type: ignore
- },
- )
- except ApiException as ex:
- self.env["wecomapi.tools.action"].ApiExceptionDialog(
- ex, raise_exception=True
- )
- else:
- user.wecom_openid = response["openid"] # type: ignore
diff --git a/wecom_contacts/models/wecom_apps.py b/wecom_contacts/models/wecom_apps.py
deleted file mode 100644
index 654f37ada..000000000
--- a/wecom_contacts/models/wecom_apps.py
+++ /dev/null
@@ -1,74 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import logging
-import time
-from datetime import datetime, timedelta
-from odoo import _, api, fields, models
-from odoo.exceptions import UserError
-from odoo.addons.wecom_api.api.wecom_abstract_api import ApiException # type: ignore
-
-_logger = logging.getLogger(__name__)
-
-
-class WeComApps(models.Model):
- _inherit = "wecom.apps"
-
- def cron_get_app_jsapi_ticket(self):
- """
- 定时任务,每隔两小时更新应用的jsapi_ticket
- """
- for app in self:
- if (
- app.company_id.is_wecom_organization # type: ignore
- and app.company_id.corpid # type: ignore
- and app.secret # type: ignore
- ):
- _logger.info(
- _("Automatic tasks:Start getting JSAPI ticket for app [%s]")
- % (app.name) # type: ignore
- )
- if (
- app.jsapi_ticket_expiration_time # type: ignore
- and app.jsapi_ticket_expiration_time > datetime.now() # type: ignore
- ):
- _logger.info(
- _(
- "Automatic tasks:JSAPI ticket for app [%s] is not expired, no need to update"
- )
- % (app.name) # type: ignore
- )
- else:
- try:
- wecom_api = self.env["wecom.service_api"].InitServiceApi(
- app.company_id.corpid, app.secret # type: ignore
- )
- response = wecom_api.httpCall(
- self.env["wecom.service_api_list"].get_server_api_call(
- "AGENT_GET_TICKET"
- ),
- {"type": "agent_config"},
- )
- except ApiException as e:
- _logger.error(
- _(
- "Automatic tasks:Failed to get JSAPI ticket for app [%s], error: %s"
- )
- % (app.name, e) # type: ignore
- )
- else:
- if response["errcode"] == 0:
- app.write(
- {
- "jsapi_ticket": response["ticket"],
- "jsapi_ticket_expiration_time": datetime.now()
- + timedelta(seconds=response["expires_in"]),
- }
- )
- _logger.info(
- _("Automatic tasks:Successfully get JSAPI ticket for app [%s]")
- % (app.name) # type: ignore
- )
- _logger.info(
- _("Automatic tasks:Start getting app [%s] ticket for company [%s]")
- % (app.name, app.company_id.name) # type: ignore
- )
diff --git a/wecom_contacts/security/ir.model.access.csv b/wecom_contacts/security/ir.model.access.csv
deleted file mode 100644
index 97dd8b917..000000000
--- a/wecom_contacts/security/ir.model.access.csv
+++ /dev/null
@@ -1 +0,0 @@
-id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
diff --git a/wecom_contacts/static/description/icon.png b/wecom_contacts/static/description/icon.png
deleted file mode 100644
index 90ed3eee7..000000000
Binary files a/wecom_contacts/static/description/icon.png and /dev/null differ
diff --git a/wecom_contacts/static/src/webclient/settings_form_view/widgets/navigation.xml b/wecom_contacts/static/src/webclient/settings_form_view/widgets/navigation.xml
deleted file mode 100644
index 2b2c96b70..000000000
--- a/wecom_contacts/static/src/webclient/settings_form_view/widgets/navigation.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
-
-
-
-
-
- Material settings
-
-
-
-
- Authentication settings
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_contacts/views/ir_cron_views.xml b/wecom_contacts/views/ir_cron_views.xml
deleted file mode 100644
index 5d6fcb4c7..000000000
--- a/wecom_contacts/views/ir_cron_views.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
-
-
- WeCom: Get Corp JSAPI Ticket.
- ir.cron
- form
-
-
-
-
- WeCom: Get App JSAPI Ticket.
- ir.cron
- form
-
-
-
-
- WeCom: Get API Domain IP.
- ir.cron
- form
-
-
-
-
- WeCom: Get join enterprise QR code.
- ir.cron
- form
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_contacts/views/menu_views.xml b/wecom_contacts/views/menu_views.xml
deleted file mode 100644
index a8c7aedd2..000000000
--- a/wecom_contacts/views/menu_views.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_contacts/views/res_company_views.xml b/wecom_contacts/views/res_company_views.xml
deleted file mode 100644
index 3cd1fad9c..000000000
--- a/wecom_contacts/views/res_company_views.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
-
- res.company.form.inherit.wecom_contacts
- res.company
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_contacts/views/res_config_settings_views.xml b/wecom_contacts/views/res_config_settings_views.xml
deleted file mode 100644
index e877c8d8a..000000000
--- a/wecom_contacts/views/res_config_settings_views.xml
+++ /dev/null
@@ -1,233 +0,0 @@
-
-
-
-
- Settings
- res.config.settings
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The API domain name IP is the resolved address of the qyapi.weixin.qq.com, and the developer calls the access IP address of the Wecom terminal. If you need to configure a firewall, you can obtain all relevant IP segments through this interface. When the IP segment changes, the new and old IP segments will be retained for a period of time at the same time. We recommend that enterprises regularly pull IP segments every day and update firewall settings to avoid network blockage due to IP segment changes.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Is a temporary ticket for the H5 application to call the Wecom JS interface. Under normal circumstances, the validity period of jsapi_ticket is 7200 seconds , obtained by access_token. Since the number of API calls to the jsapi_ticket is very limited (an enterprise can get up to 400 times in an hour, and a single application cannot get more than 100 times), frequent refresh jsapi_ticket will cause the API call to be limited, affecting their own business, and developers must cache jsapi_ticket in their own service global cache .
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- When using the Wecom API interface, developers often need to use custom resources, such as sending local picture messages, setting address book custom avatars, etc.
- In order to realize the same resource file, one upload can be used multiple times. Here is a material management interface: media_ ID to identify resource files and realize file upload and download.
-
-
-
- Save this page and come back here to set up other feature.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Wecom provides OAuth's authorized login mode, which allows you to obtain the identity information of members from the web page opened by the Wecom terminal, thus eliminating the login link.
-
- Wecom provides OAuth code scanning login authorization method, which can guide members to use Wecom code scanning login authorization when the enterprise website is opened in the browser, so as to obtain the identity information of members and avoid the login link.
-
-
-
- Save this page and come back here to set up other feature.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Display Wecom related functions on the personal portal page, and create a menu of Wecom applications.
-
-
-
- Save this page and come back here to set up other feature.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Wecom has opened message sending interfaces. Enterprises can use these interfaces to enable two-way communication between custom applications and Wecom background or users.
-
-
-
- Save this page and come back here to set up other feature.
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/wecom_contacts/views/res_partner_category_views.xml b/wecom_contacts/views/res_partner_category_views.xml
deleted file mode 100644
index 9e1d48602..000000000
--- a/wecom_contacts/views/res_partner_category_views.xml
+++ /dev/null
@@ -1,71 +0,0 @@
-
-
-
-
-
- res.partner.category.view.search
- res.partner.category
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Contact Tags
- res.partner.category
-
-
-
-
- res_partner_category_tree_download
-
-
-
-
-
-
-
-
-
-
-
-
- Contact Tags
- res.partner.category
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_contacts/views/res_partner_views.xml b/wecom_contacts/views/res_partner_views.xml
deleted file mode 100644
index 05c49c4c5..000000000
--- a/wecom_contacts/views/res_partner_views.xml
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
- res.partner.kanban
- res.partner
-
-
-
- res_partner_kanban_download
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- res.partner.form
- res.partner
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- res.partner.tree
- res.partner
-
-
-
- res_partner_tree_download
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_contacts/views/res_users_views.xml b/wecom_contacts/views/res_users_views.xml
deleted file mode 100644
index 88c7bb288..000000000
--- a/wecom_contacts/views/res_users_views.xml
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
- wecom users list
- res.users
-
-
-
-
-
-
-
-
-
-
-
- res.users.kanban
- res.users
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- wecom users form
- res.users
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_contacts_sync/__init__.py b/wecom_contacts_sync/__init__.py
deleted file mode 100644
index 3616b3002..000000000
--- a/wecom_contacts_sync/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from . import models
-from . import wizard
\ No newline at end of file
diff --git a/wecom_contacts_sync/__manifest__.py b/wecom_contacts_sync/__manifest__.py
deleted file mode 100644
index 4eaec55a7..000000000
--- a/wecom_contacts_sync/__manifest__.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# -*- coding: utf-8 -*-
-{
- "name": "WeCom Contacts Synchronization",
- "author": "RStudio",
- "website": "https://eis-solution.coding.net/public/odoo/oec/git",
- "sequence": 603,
- "installable": True,
- "application": True,
- "auto_install": False,
- "category": "WeCom Suites/CRM",
- "version": "17.0.0.1",
- "summary": """
-
- """,
- "description": """
-
-
- """,
- "depends": [
- "wecom_contacts",
- "hr",
- ],
- "external_dependencies": {
- "python": ["pandas"],
- },
- "data": [
- "security/ir.model.access.csv",
- "data/wecom_app_config_data.xml",
- "data/wecom_app_event_type_data.xml",
- "data/ir_cron_data.xml",
- "data/hr_data.xml",
- # "wizard/employee_bind_wecom_views.xml",
- # "wizard/user_bind_wecom_views.xml",
- "wizard/wecom_contacts_sync_wizard_views.xml",
- # "wizard/wecom_users_sync_wizard_views.xml",
- "views/wecom_user_views.xml",
- "views/wecom_department_views.xml",
- "views/wecom_tag_views.xml",
- # "views/wecom_contacts_block_views.xml",
- "views/res_company_views.xml",
- "views/res_config_settings_views.xml",
- "views/res_users_views.xml",
- # "views/wecom_apps_views.xml",
- # "views/hr_department_view.xml",
- # "views/hr_employee_view.xml",
- # "views/hr_employee_category_views.xml",
- "views/ir_cron_views.xml",
- "views/menu_views.xml",
- ],
- "assets": {
- "web._assets_common_styles": [
- "wecom_contacts_sync/static/src/scss/sync_result_dialog.scss",
- ],
- "web.assets_backend": [
- # SCSSS
- # JS
- # "wecom_contacts_sync/static/src/js/*.js",
- ],
- },
- "license": "AGPL-3",
-}
diff --git a/wecom_contacts_sync/data/hr_data.xml b/wecom_contacts_sync/data/hr_data.xml
deleted file mode 100644
index 2afd4403c..000000000
--- a/wecom_contacts_sync/data/hr_data.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_contacts_sync/data/ir_cron_data.xml b/wecom_contacts_sync/data/ir_cron_data.xml
deleted file mode 100644
index f9e628efb..000000000
--- a/wecom_contacts_sync/data/ir_cron_data.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
- WeCom: Synchronize contacts
-
- code
- model.cron_sync_contacts()
-
- 2
- hours
- -1
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_contacts_sync/data/wecom_app_config_data.xml b/wecom_contacts_sync/data/wecom_app_config_data.xml
deleted file mode 100644
index 135c28df3..000000000
--- a/wecom_contacts_sync/data/wecom_app_config_data.xml
+++ /dev/null
@@ -1,165 +0,0 @@
-
-
-
-
-
-
- Allow wecom contacts to synchronize HR
- contacts_allow_sync_hr
- boolean
- True
-
-
- If the value is true, the wizard and task are allowed to synchronize the organization structure of wecom contacts to HR;
- If the value is false, you need to manually bind HR employees to wecom users. At the same time, only employees with wecom user ID can be updated by events;
- The default is true;
-
- Value: True or False
-
-
-
-
-
-
-
- Department ID to be synchronized
- contacts_sync_hr_department_id
- integer
- 1
-
-
- Department id. Get the specified department and its sub-departments. If you don’t fill in, get the full organization structure by default
- Value: Department id.
-
-
-
-
-
-
-
- Allow API to edit WeCom contacts
- contacts_edit_enabled
- boolean
- False
-
-
- Wecom Contacts can be read and edited through API interface
- Value: True or False
-
-
-
-
-
-
-
- Allow wecom contacts to add system users
- contacts_allow_add_system_users
- boolean
- False
-
-
- If the value is true, system users can be added through wizards, tasks and events;
- If the value is false, you can only update;
- The default is false;
-
- Value: True or False
-
-
-
-
-
-
-
- Use the system default avatar when adding employees
- contacts_use_default_avatar_when_adding_employees
- boolean
- True
-
-
- Enable this, Employee photos will use the default avatar. Will save a lot of synchronization time.
- Valid only when synchronizing new employees.
- Value: True or False
-
-
-
-
-
-
-
- Update employees avatar every time sync
- contacts_update_avatar_every_time_sync_employees
- boolean
- False
-
-
- Enable this,Each update will overwrite the employee photos you have set up.
- Use this feature with caution.
- Value: True or False
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_contacts_sync/data/wecom_app_event_type_data.xml b/wecom_contacts_sync/data/wecom_app_event_type_data.xml
deleted file mode 100644
index dcd71e029..000000000
--- a/wecom_contacts_sync/data/wecom_app_event_type_data.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-
-
-
-
-
- Add member events
-
- change_contact
- create_user
- model.wecom_event_change_contact_user
- create
-
-
-
- Update member events
-
- change_contact
- update_user
- model.wecom_event_change_contact_user
- update
-
-
-
- Delete member events
-
- change_contact
- delete_user
- model.wecom_event_change_contact_user
- delete
-
-
-
- New departmental events
-
- change_contact
- create_party
- model.wecom_event_change_contact_party
- create
-
-
-
- Update department events
-
- change_contact
- update_party
- model.wecom_event_change_contact_party
- update
-
-
-
- Delete Department events
-
- change_contact
- delete_party
- model.wecom_event_change_contact_party
- delete
-
-
-
- Tag change events
-
- change_contact
- update_tag
- model.wecom_event_change_contact_tag
- update
-
-
-
- Contacts asynchronous task completion notification
- batch_job_result
-
-
-
-
\ No newline at end of file
diff --git a/wecom_contacts_sync/i18n/zh_CN.po b/wecom_contacts_sync/i18n/zh_CN.po
deleted file mode 100644
index e51a20cc8..000000000
--- a/wecom_contacts_sync/i18n/zh_CN.po
+++ /dev/null
@@ -1,1515 +0,0 @@
-# Translation of Odoo Server.
-# This file contains the translation of the following modules:
-# * wecom_contacts_sync
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: Odoo Server 17.0\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2024-03-10 10:56+0000\n"
-"PO-Revision-Date: 2024-03-10 19:00+0800\n"
-"Last-Translator: \n"
-"Language-Team: \n"
-"Language: zh_CN\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Poedit 3.4.2\n"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_apps.py:0
-#, python-format
-msgid ""
-"\n"
-"Automatic task: end the synchronization of the Wecom organizational structure of all "
-"companies.\n"
-"=======================================================================================================================\n"
-"Task Synchronization status:%s, Synchronization task time:%s seconds,\n"
-"Synchronization results:\n"
-"%s\n"
-"-----------------------------------------------------------------------------------------------------------------------\n"
-"Wecom department sync status:%s, Synchronize Wecom department time: %s seconds,\n"
-"Synchronize Wecom department results:\n"
-"%s\n"
-"-----------------------------------------------------------------------------------------------------------------------\n"
-"Wecom User sync status:%s, Synchronize Wecom User time: %s seconds,\n"
-"Synchronize Wecom User results:\n"
-"%s\n"
-"-----------------------------------------------------------------------------------------------------------------------\n"
-"Wecom tag sync status:%s, Synchronize Wecom tag time: %s seconds,\n"
-"Synchronize Wecom tag results:\n"
-"%s\n"
-"======================================================================================================================="
-msgstr ""
-"\n"
-"自动任务:结束所有公司企业微信组织结构的同步。\n"
-"=======================================================================================================================\n"
-"任务同步状态:%s,同步任务时间:%s秒,\n"
-"同步结果:\n"
-"%s\n"
-"-----------------------------------------------------------------------------------------------------------------------\n"
-"企微部门同步状态:%s,同步企微部门时间:%s秒,\n"
-"同步企微部门结果:\n"
-"%s\n"
-"-----------------------------------------------------------------------------------------------------------------------\n"
-"企微用户同步状态:%s,同步企微用户时间:%s秒,\n"
-"同步企微用户结果:\n"
-"%s\n"
-"-----------------------------------------------------------------------------------------------------------------------\n"
-"企微标签同步状态:%s,同步企微标签时间:%s秒,\n"
-"同步企微标签结果:\n"
-"%s\n"
-"======================================================================================================================="
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.res_config_settings_view_form
-msgid " "
-msgstr ""
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.res_config_settings_view_form
-msgid ""
-""
-msgstr ""
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.res_config_settings_view_form
-msgid ""
-" "
-msgstr ""
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.res_config_settings_view_form
-msgid ""
-" "
-msgstr ""
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.res_config_settings_view_form
-msgid " "
-msgstr ""
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_form_wecom_contacts_sync_wizard
-msgid "tail -f /var/log/odoo/odoo-server.log "
-msgstr "tail -f /var/log/odoo/odoo-server.log "
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_user_kanban
-msgid ""
-"\n"
-" "
-msgstr ""
-"\n"
-" "
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_user_kanban
-msgid ""
-"\n"
-" "
-msgstr ""
-"\n"
-" "
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_user_kanban
-msgid ""
-"\n"
-" "
-msgstr ""
-"\n"
-" "
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_user_form
-msgid ""
-"Copy \n"
-" As Employee "
-msgstr ""
-"复制 \n"
-" 为员工 "
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_user_form
-msgid ""
-"Copy \n"
-" As System User "
-msgstr ""
-"复制 \n"
-" 为系统用户 "
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_tag_form
-msgid ""
-"Download \n"
-" Tag member "
-msgstr ""
-"下载 \n"
-" 标签成员 "
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_department_form
-msgid ""
-"Download \n"
-" department information "
-msgstr ""
-"下载 \n"
-" 部门信息 "
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_user_form
-msgid ""
-"Download \n"
-" user information "
-msgstr ""
-"下载 \n"
-" 用户信息 "
-
-#. module: wecom_contacts_sync
-#: model_terms:wecom.app_config,description:wecom_contacts_sync.wecom_app_config_contacts_use_default_avatar_when_adding_employees
-msgid ""
-"Valid only when synchronizing new employees."
-"span>\n"
-" Value: True or False"
-msgstr ""
-"仅在同步新员工时有效。 \n"
-" 值: True 或 False"
-
-#. module: wecom_contacts_sync
-#: model_terms:wecom.app_config,description:wecom_contacts_sync.wecom_app_config_contacts_update_avatar_every_time_sync_employees
-msgid ""
-"Use this feature with caution. \n"
-" Value: True or False"
-msgstr ""
-"请谨慎使用此功能。 \n"
-" 值: True 或 False"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_user.py:0
-#: model:ir.model.fields.selection,name:wecom_contacts_sync.selection__wecom_user__status_name__1
-#, python-format
-msgid "Activated"
-msgstr "已激活"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__active
-msgid "Active"
-msgstr "启用"
-
-#. module: wecom_contacts_sync
-#: model:wecom.app.event_type,name:wecom_contacts_sync.wecom_app_event_change_contact_create_user
-msgid "Add member events"
-msgstr "新增成员事件"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__address
-msgid "Address"
-msgstr "地址"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_res_config_settings__contacts_sync_app_agentid
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_res_config_settings__self_built_app_agentid
-msgid "Agent ID"
-msgstr "应用ID"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__alias
-msgid "Alias"
-msgstr "别名"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_apps.py:0
-#: model:ir.model.fields.selection,name:wecom_contacts_sync.selection__wecom_contacts_sync_wizard__state__completed
-#: model:ir.model.fields.selection,name:wecom_contacts_sync.selection__wecom_contacts_sync_wizard__wecom_department_sync_state__completed
-#: model:ir.model.fields.selection,name:wecom_contacts_sync.selection__wecom_contacts_sync_wizard__wecom_tag_sync_state__completed
-#: model:ir.model.fields.selection,name:wecom_contacts_sync.selection__wecom_contacts_sync_wizard__wecom_user_sync_state__completed
-#, python-format
-msgid "All completed"
-msgstr "全部完成"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_apps.py:0
-#: model:ir.model.fields.selection,name:wecom_contacts_sync.selection__wecom_contacts_sync_wizard__state__fail
-#: model:ir.model.fields.selection,name:wecom_contacts_sync.selection__wecom_contacts_sync_wizard__wecom_department_sync_state__fail
-#: model:ir.model.fields.selection,name:wecom_contacts_sync.selection__wecom_contacts_sync_wizard__wecom_tag_sync_state__fail
-#: model:ir.model.fields.selection,name:wecom_contacts_sync.selection__wecom_contacts_sync_wizard__wecom_user_sync_state__fail
-#, python-format
-msgid "All failed"
-msgstr "全部失败"
-
-#. module: wecom_contacts_sync
-#: model:wecom.app_config,name:wecom_contacts_sync.wecom_app_config_contacts_edit_enabled
-msgid "Allow API to edit WeCom contacts"
-msgstr "允许API编辑企业微信通讯录"
-
-#. module: wecom_contacts_sync
-#: model:wecom.app_config,name:wecom_contacts_sync.wecom_app_config_contacts_allow_add_system_users
-msgid "Allow wecom contacts to add system users"
-msgstr "允许企微通讯录添加系统用户"
-
-#. module: wecom_contacts_sync
-#: model:wecom.app_config,name:wecom_contacts_sync.wecom_app_config_contacts_allow_sync_hr
-msgid "Allow wecom contacts to synchronize HR"
-msgstr "允许企微通讯录同步人力资源"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_res_config_settings__contacts_sync_app_config_ids
-msgid "Application Configuration"
-msgstr "应用配置"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.res_config_settings_view_form
-msgid ""
-"Application Management→Application→Open the application that needs to be verified and "
-"authorized, copy 'AgentId'"
-msgstr "应用程序管理→应用→打开需要验证和授权的应用程序,复制“AgentId”"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.res_config_settings_view_form
-msgid ""
-"Application Management→Application→Open the application that needs to be verified and "
-"authorized, copy 'Secret'"
-msgstr "应用程序管理→应用→打开需要验证和授权的应用程序,复制“Secret”"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_user_form
-msgid "Archived"
-msgstr "已归档"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_apps.py:0
-#, python-format
-msgid ""
-"Automatic task: end synchronizing the Wecom organizational structure of the company [%s]"
-msgstr "自动任务:结束同步公司 [%s] 的企业微信组织架构"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_apps.py:0
-#, python-format
-msgid ""
-"Automatic task: start to synchronize the Wecom organizational structure of the company [%s]"
-msgstr "自动任务:开始同步公司 [%s] 的企业微信组织架构"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__avatar
-msgid "Avatar"
-msgstr "头像"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__thumb_avatar
-msgid "Avatar thumbnail"
-msgstr "头像缩略图"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/res_users.py:0
-#, python-format
-msgid "Before clicking the 'Change User Type' button, you must modify the new user type"
-msgstr "在单击“更改用户类型”按钮之前,必须修改新的用户类型"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__biz_mail
-msgid "BizMail"
-msgstr "企业邮箱"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.res_config_settings_view_form
-msgid "Button group"
-msgstr "按钮组"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.change_type_wizard_view
-msgid "Cancel"
-msgstr "取消"
-
-#. module: wecom_contacts_sync
-#: model:ir.actions.act_window,name:wecom_contacts_sync.change_type_wizard_action
-msgid "Change Type"
-msgstr "更改类型"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.change_type_wizard_view
-msgid "Change type"
-msgstr "更改类型"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.change_type_wizard_view
-msgid "Change user type"
-msgstr "更改用户类型"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_department__child_ids
-msgid "Child Departments"
-msgstr "子部门"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_form_wecom_contacts_sync_result
-msgid "Close"
-msgstr "关闭"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_form_wecom_contacts_sync_result
-msgid "Close and refresh"
-msgstr "关闭并刷新"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_department__color
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__color
-msgid "Color Index"
-msgstr "颜色索引"
-
-#. module: wecom_contacts_sync
-#: model:ir.model,name:wecom_contacts_sync.model_res_company
-msgid "Companies"
-msgstr "公司"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_block__company_id
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_sync_wizard__company_id
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_department__company_id
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_tag__company_id
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__company_id
-msgid "Company"
-msgstr "公司"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_department__complete_name
-msgid "Complete Name"
-msgstr "完整名称"
-
-#. module: wecom_contacts_sync
-#: model:ir.model,name:wecom_contacts_sync.model_res_config_settings
-msgid "Config Settings"
-msgstr "配置设定"
-
-#. module: wecom_contacts_sync
-#: model:ir.actions.act_window,name:wecom_contacts_sync.actions_wecom_contacts_sync_wizard
-msgid "Contact synchronization Wizard"
-msgstr "通讯录同步向导"
-
-#. module: wecom_contacts_sync
-#: model:ir.ui.menu,name:wecom_contacts_sync.menu_wecom_contacts_management
-msgid "Contacts"
-msgstr "通讯录"
-
-#. module: wecom_contacts_sync
-#: model:ir.ui.menu,name:wecom_contacts_sync.menu_wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_company_form
-msgid "Contacts Sync"
-msgstr "通讯录同步"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_res_company__contacts_sync_app_id
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_res_config_settings__contacts_sync_app_id
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.res_config_settings_view_form
-msgid "Contacts Synchronization Application"
-msgstr "通讯录同步应用"
-
-#. module: wecom_contacts_sync
-#: model:wecom.app.event_type,name:wecom_contacts_sync.wecom_app_event_change_contact_asyn_task_completion_notification
-msgid "Contacts asynchronous task completion notification"
-msgstr "通讯录异步任务完成通知"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/res_users.py:0
-#, python-format
-msgid "Contacts list downloaded successfully."
-msgstr "联系人列表下载成功。"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_apps.py:0
-#, python-format
-msgid "Contacts synchronization"
-msgstr "通讯录同步"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_user_form
-msgid "Copy as System User"
-msgstr "复制为系统用户"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_change_type_user__create_uid
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_change_type_wizard__create_uid
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_block__create_uid
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_sync_wizard__create_uid
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_department__create_uid
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_tag__create_uid
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__create_uid
-msgid "Created by"
-msgstr "创建人"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_change_type_user__create_date
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_change_type_wizard__create_date
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_block__create_date
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_sync_wizard__create_date
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_department__create_date
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_tag__create_date
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__create_date
-msgid "Created on"
-msgstr "创建日期"
-
-#. module: wecom_contacts_sync
-#: model:wecom.app.event_type,name:wecom_contacts_sync.wecom_app_event_change_contact_delete_party
-msgid "Delete Department events"
-msgstr "删除部门事件"
-
-#. module: wecom_contacts_sync
-#: model:wecom.app.event_type,name:wecom_contacts_sync.wecom_app_event_change_contact_delete_user
-msgid "Delete member events"
-msgstr "删除成员事件"
-
-#. module: wecom_contacts_sync
-#: model:ir.actions.act_window,name:wecom_contacts_sync.actions_wecom_contacts_department
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_department_tree
-msgid "Department"
-msgstr "部门"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_department__department_id
-msgid "Department ID"
-msgstr "部门ID"
-
-#. module: wecom_contacts_sync
-#: model:wecom.app_config,name:wecom_contacts_sync.wecom_app_config_contacts_sync_hr_department_id
-msgid "Department ID to be synchronized"
-msgstr "需要同步的部门ID"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_department__department_json
-msgid "Department Json"
-msgstr "部门Json"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_department__department_leader
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_department__department_leader_ids
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__department_leader
-msgid "Department Leader"
-msgstr "部门负责人"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_department.py:0
-#, python-format
-msgid "Department [id:%s, name:%s] downloaded successfully"
-msgstr "部门 [id:%s, 名称:%s] 下载成功"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_department.py:0
-#, python-format
-msgid "Department [id:%s, name:%s] failed to download,Reason: %s"
-msgstr "部门 [id:%s, 名称:%s] 下载失败,原因%s"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__department_complete_name
-msgid "Department complete Name"
-msgstr "部门完整名称"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_user.py:0
-#, python-format
-msgid "Department head [%s]: %s ;"
-msgstr "部门 [%s] 的负责人:%s ;"
-
-#. module: wecom_contacts_sync
-#: model_terms:wecom.app_config,description:wecom_contacts_sync.wecom_app_config_contacts_sync_hr_department_id
-msgid ""
-"Department id. Get the specified department and its sub-departments. If you don’t fill in, "
-"get the full organization structure by default\n"
-" Value: Department id."
-msgstr ""
-"部门id。获取指定的部门及其子部门。如果不填写,默认情况下获取完整的组织架构\n"
-" 值:部门id。"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_department.py:0
-#, python-format
-msgid "Department list sync completed."
-msgstr "部门列表同步完成。"
-
-#. module: wecom_contacts_sync
-#: model:ir.ui.menu,name:wecom_contacts_sync.menu_wecom_contacts_department
-msgid "Department management"
-msgstr "部门管理"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_tag__department_ids
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_tag_form
-msgid "Departments"
-msgstr "部门"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__direct_leader
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__direct_leader_id
-msgid "Direct Leader"
-msgstr "直属上级"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_user.py:0
-#: model:ir.model.fields.selection,name:wecom_contacts_sync.selection__wecom_user__status_name__2
-#, python-format
-msgid "Disabled"
-msgstr "已禁用"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_change_type_user__display_name
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_change_type_wizard__display_name
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_block__display_name
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_sync_wizard__display_name
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_department__display_name
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_tag__display_name
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__display_name
-msgid "Display Name"
-msgstr "显示名称"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_department.py:0
-#: code:addons/wecom_contacts_sync/models/wecom_tag.py:0
-#: code:addons/wecom_contacts_sync/models/wecom_user.py:0
-#, python-format
-msgid "Download Success!"
-msgstr "下载成功!"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_tag_form
-msgid "Download Tag Member"
-msgstr "下载标签成员"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_department_form
-msgid "Download department information"
-msgstr "下载部门信息"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_department.py:0
-#: code:addons/wecom_contacts_sync/models/wecom_tag.py:0
-#: code:addons/wecom_contacts_sync/models/wecom_user.py:0
-#, python-format
-msgid "Download failed!"
-msgstr "下载失败!"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_user_form
-msgid "Download user information"
-msgstr "下载用户信息"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__email
-msgid "Email"
-msgstr "邮件"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_user_form
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_user_kanban
-msgid "Employee's Name"
-msgstr "员工的名称"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__enable
-msgid "Enable"
-msgstr "启用"
-
-#. module: wecom_contacts_sync
-#: model_terms:wecom.app_config,description:wecom_contacts_sync.wecom_app_config_contacts_use_default_avatar_when_adding_employees
-msgid ""
-"Enable this, Employee photos will use the default avatar. Will save a lot of synchronization "
-"time."
-msgstr "启用此选项,员工照片将使用默认头像。将节省大量的同步时间。"
-
-#. module: wecom_contacts_sync
-#: model_terms:wecom.app_config,description:wecom_contacts_sync.wecom_app_config_contacts_update_avatar_every_time_sync_employees
-msgid "Enable this,Each update will overwrite the employee photos you have set up."
-msgstr "启用此选项后,每次更新都将覆盖您设置的员工照片。"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_department__name_en
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__english_name
-msgid "English name"
-msgstr "英文名称"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/res_users.py:0
-#, python-format
-msgid "Error creating company %s partner %s %s, error reason: %s"
-msgstr "创建公司 [%s] 合作伙伴 [%s %s] 时出错,错误原因:%s"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_department.py:0
-#, python-format
-msgid "Error creating company [%s]'s department [%s], error reason: %s"
-msgstr "创建公司 [%s] 的部门 [%s] 时出错,错误原因:%s"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_tag.py:0
-#, python-format
-msgid "Error creating company [%s]'s tag [%s], error reason: %s"
-msgstr "创建公司 [%s] 的标签 [%s] 时出错,错误原因:%s"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_user.py:0
-#, python-format
-msgid "Error creating company [%s]'s user [%s], error reason: %s"
-msgstr "创建公司 [%s] 的用户 [%s] 时出错,错误原因:%s"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_department.py:0
-#, python-format
-msgid "Error setting parent department for company [%s], Error details:%s"
-msgstr "设置公司[%s]的上级部门时出错,错误详细信息:%s"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_department.py:0
-#, python-format
-msgid "Error update company [%s]'s Department [%s], error reason: %s"
-msgstr "更新公司 [%s] 的部门 [%s] 时出错,错误原因:%s"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_tag.py:0
-#, python-format
-msgid "Error update company [%s]'s tag [%s], error reason: %s"
-msgstr "更新公司[%s]的标签[%s]时出错,错误原因:%s"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_user.py:0
-#, python-format
-msgid "Error update company [%s]'s user [%s], error reason: %s"
-msgstr "更新公司 [%s] 的用户 [%s] 时出错,错误原因:%s"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_department.py:0
-#, python-format
-msgid "Error updating Department [%s], error details:%s"
-msgstr "更新部门 [%s] 时出错,错误详细:%s"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_user.py:0
-#, python-format
-msgid "Error!"
-msgstr "错误!"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_user.py:0
-#: model:ir.model.fields.selection,name:wecom_contacts_sync.selection__wecom_user__status_name__5
-#, python-format
-msgid "Exit the enterprise"
-msgstr "退出企业"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__extattr
-msgid "Extended attributes"
-msgstr "扩展属性"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__external_profile
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_user_form
-msgid "External attributes"
-msgstr "对外属性"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__external_position
-msgid "External position"
-msgstr "对外职务"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_user.py:0
-#: model:ir.model.fields.selection,name:wecom_contacts_sync.selection__wecom_user__gender_name__2
-#, python-format
-msgid "Female"
-msgstr "女性"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__gender
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__gender_name
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_user_form
-msgid "Gender"
-msgstr "性别"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.res_config_settings_view_form
-msgid "Generate parameters"
-msgstr "生成参数"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.res_config_settings_view_form
-msgid "Generate service"
-msgstr "生成服务"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_user_form
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_user_tree
-msgid "Get OpenID"
-msgstr "获取OpenID"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_form_wecom_contacts_sync_wizard
-msgid "Help"
-msgstr "帮助"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__hide_mobile
-msgid "Hide mobile"
-msgstr "隐藏手机"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_change_type_user__id
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_change_type_wizard__id
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_block__id
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_sync_wizard__id
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_department__id
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_tag__id
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__id
-msgid "ID"
-msgstr ""
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_user_form
-msgid "Identity information"
-msgstr "身份信息"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_form_wecom_contacts_sync_wizard
-msgid "If an error occurs, please check the help file."
-msgstr "如果发生错误,请查看帮助文件。"
-
-#. module: wecom_contacts_sync
-#: model_terms:wecom.app_config,description:wecom_contacts_sync.wecom_app_config_contacts_allow_add_system_users
-msgid ""
-"If the value is true, system users can be added through wizards, tasks and events; \n"
-" If the value is false, you can only update; \n"
-" The default is false; "
-msgstr ""
-"如果该值为true,则可以通过向导、任务和事件添加系统用户; \n"
-" 如果该值为false,则只能更新; \n"
-" 默认值 false; "
-
-#. module: wecom_contacts_sync
-#: model_terms:wecom.app_config,description:wecom_contacts_sync.wecom_app_config_contacts_allow_sync_hr
-msgid ""
-"If the value is true, the wizard and task are allowed to synchronize the organization "
-"structure of wecom contacts to HR; \n"
-" If the value is false, you need to manually bind HR employees to wecom "
-"users. At the same time, only employees with wecom user ID can be updated by events; \n"
-" The default is true;"
-msgstr ""
-"如果该值为true,则允许向导和任务将企微通讯录的组织架构同步到HR; \n"
-" 如果该值为false,则需要手动将HR员工绑定到企微用户。同时,只有拥有企微用户"
-"ID的员工才能通过事件进行更新; \n"
-" 默认值 true;"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/res_users.py:0
-#: model:ir.model.fields.selection,name:wecom_contacts_sync.selection__change_type_user__new_type__1
-#, python-format
-msgid "Internal User"
-msgstr "内部用户"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__is_leader_in_dept
-msgid "Is Department Leader"
-msgstr "是部门负责人"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__isleader
-msgid "Is leader"
-msgstr "是负责人"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_user_form
-msgid "Job Position"
-msgstr "工作岗位"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_tag_form
-msgid "Json"
-msgstr ""
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_change_type_user__write_uid
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_change_type_wizard__write_uid
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_block__write_uid
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_sync_wizard__write_uid
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_department__write_uid
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_tag__write_uid
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__write_uid
-msgid "Last Updated by"
-msgstr "最后更新人"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_change_type_user__write_date
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_change_type_wizard__write_date
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_block__write_date
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_sync_wizard__write_date
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_department__write_date
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_tag__write_date
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__write_date
-msgid "Last Updated on"
-msgstr "上次更新日期"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_form_wecom_contacts_sync_wizard
-msgid "Linux production server uses the following command to view real-time logs:"
-msgstr ""
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_change_type_user__user_login
-msgid "Login account"
-msgstr "登陆账号"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_change_type_user__user_name
-msgid "Login name"
-msgstr "登陆名称"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__department_id
-msgid "Main Department"
-msgstr "主部门"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__main_department
-msgid "Main department"
-msgstr "主部门"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_user.py:0
-#: model:ir.model.fields.selection,name:wecom_contacts_sync.selection__wecom_user__gender_name__1
-#, python-format
-msgid "Male"
-msgstr "男性"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_sync_wizard__manage_multiple_companies
-msgid "Manage multiple companies"
-msgstr "管理多公司"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.res_config_settings_view_form
-msgid "Management application"
-msgstr "管理应用"
-
-#. module: wecom_contacts_sync
-#: model:ir.actions.act_window,name:wecom_contacts_sync.actions_wecom_contacts_member
-msgid "Member"
-msgstr "成员"
-
-#. module: wecom_contacts_sync
-#: model:ir.ui.menu,name:wecom_contacts_sync.menu_wecom_contacts_member
-msgid "Member management"
-msgstr "成员管理"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_department__user_ids
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_tag__user_ids
-msgid "Members"
-msgstr "成员"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_user_form
-msgid "Metadata"
-msgstr "元数据"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__department
-msgid "Multiple Department ID"
-msgstr "多部门ID"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__department_ids
-msgid "Multiple Departments"
-msgstr "多部门"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_block__name
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_department__name
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_tag__name
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__name
-msgid "Name"
-msgstr "名称"
-
-#. module: wecom_contacts_sync
-#: model:wecom.app.event_type,name:wecom_contacts_sync.wecom_app_event_change_contact_create_party
-msgid "New departmental events"
-msgstr "新增部门事件"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_user.py:0
-#, python-format
-msgid "No"
-msgstr "否"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_user.py:0
-#: model:ir.model.fields.selection,name:wecom_contacts_sync.selection__wecom_user__status_name__4
-#, python-format
-msgid "Not active"
-msgstr "未激活"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__open_userid
-msgid "Open userid"
-msgstr "企微Open userid"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_department__parent_id
-msgid "Parent Department"
-msgstr "上级部门"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_department__parentid
-msgid "Parent department id"
-msgstr "上级部门Id"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_apps.py:0
-#: model:ir.model.fields.selection,name:wecom_contacts_sync.selection__wecom_contacts_sync_wizard__state__partially
-#: model:ir.model.fields.selection,name:wecom_contacts_sync.selection__wecom_contacts_sync_wizard__wecom_department_sync_state__partially
-#: model:ir.model.fields.selection,name:wecom_contacts_sync.selection__wecom_contacts_sync_wizard__wecom_tag_sync_state__partially
-#: model:ir.model.fields.selection,name:wecom_contacts_sync.selection__wecom_contacts_sync_wizard__wecom_user_sync_state__partially
-#, python-format
-msgid "Partially complete"
-msgstr "部分完成"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_tag__partylist
-msgid "Party list"
-msgstr "部门列表"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__qr_code
-msgid "Personal QR code"
-msgstr "个人二维码"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/res_config_settings.py:0
-#, python-format
-msgid "Please bind contact application!"
-msgstr "请绑定通讯录应用!"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/res_config_settings.py:0
-#, python-format
-msgid "Please bind contact synchronization application!"
-msgstr "请绑定通讯录同步应用!"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/res_users.py:0
-#: model:ir.model.fields.selection,name:wecom_contacts_sync.selection__change_type_user__new_type__9
-#, python-format
-msgid "Portal User"
-msgstr "门户用户"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__position
-msgid "Position"
-msgstr "职务"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_user_form
-msgid "Private Contact"
-msgstr "私人联系"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_user_form
-msgid "Private Information"
-msgstr "私人信息"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/res_users.py:0
-#: model:ir.model.fields.selection,name:wecom_contacts_sync.selection__change_type_user__new_type__10
-#, python-format
-msgid "Public User"
-msgstr "公众用户"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_res_config_settings__contacts_sync_secret
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_res_config_settings__self_built_app_secret
-msgid "Secret"
-msgstr "密钥"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_res_company__self_built_app_id
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_res_config_settings__self_built_app_id
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_company_form
-msgid "Self-built Application"
-msgstr "自建应用"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_department__order
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__order
-msgid "Sequence"
-msgstr "排序"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__order_in_department
-msgid "Sequence in department"
-msgstr "部门排序"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_form_wecom_contacts_sync_wizard
-msgid "Start syncing"
-msgstr "开始同步"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_form_wecom_contacts_sync_result
-msgid "Starting time"
-msgstr "启动时间"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_sync_wizard__state
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__status
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__status_name
-msgid "Status"
-msgstr "状态"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_sync_wizard__companies
-msgid "Sync Companies"
-msgstr "同步公司"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_sync_wizard__sync_result
-msgid "Sync result"
-msgstr "同步结果"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_form_wecom_contacts_sync_result
-msgid "Synchronization status"
-msgstr "同步状态"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_sync_wizard__sync_all
-msgid "Synchronize all companies"
-msgstr "同步所有公司"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_form_wecom_contacts_sync_wizard
-msgid "Synchronize all companies?"
-msgstr "同步所有公司?"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/wizard/wecom_contacts_sync_wizard.py:0
-#, python-format
-msgid "Synchronize results using the wizard"
-msgstr "使用向导同步结果"
-
-#. module: wecom_contacts_sync
-#: model:ir.actions.act_window,name:wecom_contacts_sync.actions_wecom_contacts_tag
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_tag_tree
-msgid "Tag"
-msgstr "标签"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_tag__tagid
-msgid "Tag ID"
-msgstr "标签ID"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_tag__tag_json
-msgid "Tag Json"
-msgstr "标签Json"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_tag.py:0
-#, python-format
-msgid "Tag [id:%s, name:%s] downloaded successfully"
-msgstr "标签 [id:%s, 名称:%s] 下载成功"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_tag.py:0
-#, python-format
-msgid "Tag [id:%s, name:%s] failed to download,Reason: %s"
-msgstr "标签 [id:%s, name:%s] 下载失败,原因%s"
-
-#. module: wecom_contacts_sync
-#: model:wecom.app.event_type,name:wecom_contacts_sync.wecom_app_event_change_contact_update_tag
-msgid "Tag change events"
-msgstr "标签变更事件"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_tag.py:0
-#, python-format
-msgid "Tag list sync completed."
-msgstr "标签列表同步完成。"
-
-#. module: wecom_contacts_sync
-#: model:ir.ui.menu,name:wecom_contacts_sync.menu_wecom_contacts_tag
-msgid "Tag management"
-msgstr "标签管理"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_tag__tagname
-msgid "Tag name"
-msgstr "标签名称"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_department__tag_ids
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__tag_ids
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_tag_form
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_user_form
-msgid "Tags"
-msgstr "标签"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__telephone
-msgid "Telephone"
-msgstr "固话"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/res_users.py:0
-#, python-format
-msgid ""
-"The current company does not identify the Wecom organization. Please configure or switch the "
-"company."
-msgstr "当前公司未标识为企业微信组织。请配置或切换公司。"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_user.py:0
-#, python-format
-msgid "The current configuration does not allow replication as a system user!"
-msgstr "当前配置不允许复制为系统用户!"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.constraint,message:wecom_contacts_sync.constraint_wecom_contacts_block_userid_company_uniq
-msgid "The user ID of each company must be unique!"
-msgstr "每个公司的用户ID必须唯一!"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/res_users.py:0
-#, python-format
-msgid "There is no mapping for field [%s], please contact the developer."
-msgstr "字段 [%s] 没有映射,请与开发人员联系。"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.res_config_settings_view_form
-msgid "To synchronize contacts, you need to bind a self-built application."
-msgstr "要同步通讯录,您需要绑定一个自建的应用程序。"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_sync_wizard__total_time
-msgid "Total time(seconds)"
-msgstr "时间(秒)"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_user.py:0
-#: model:ir.model.fields.selection,name:wecom_contacts_sync.selection__wecom_user__gender_name__0
-#, python-format
-msgid "Undefined"
-msgstr "未定义"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_apps.py:0
-#, python-format
-msgid "Unknown"
-msgstr "未知"
-
-#. module: wecom_contacts_sync
-#: model:wecom.app.event_type,name:wecom_contacts_sync.wecom_app_event_change_contact_update_party
-msgid "Update department events"
-msgstr "更新部门事件"
-
-#. module: wecom_contacts_sync
-#: model:wecom.app_config,name:wecom_contacts_sync.wecom_app_config_contacts_update_avatar_every_time_sync_employees
-msgid "Update employees avatar every time sync"
-msgstr "每次同步时更新员工头像"
-
-#. module: wecom_contacts_sync
-#: model:wecom.app.event_type,name:wecom_contacts_sync.wecom_app_event_change_contact_update_user
-msgid "Update member events"
-msgstr "更新成员事件"
-
-#. module: wecom_contacts_sync
-#: model:wecom.app_config,name:wecom_contacts_sync.wecom_app_config_contacts_use_default_avatar_when_adding_employees
-msgid "Use the system default avatar when adding employees"
-msgstr "在添加员工时使用系统默认头像"
-
-#. module: wecom_contacts_sync
-#: model:ir.model,name:wecom_contacts_sync.model_res_users
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_change_type_user__user_id
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_user_filter
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_user_form
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_user_kanban
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_user_tree
-msgid "User"
-msgstr "用户"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__userid
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_user_filter
-msgid "User ID"
-msgstr "用户ID"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__user_json
-msgid "User Json"
-msgstr "用户Json"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_change_type_user__new_type
-msgid "User Type"
-msgstr "用户类型"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_user.py:0
-#, python-format
-msgid "User [id:%s, name:%s] downloaded successfully"
-msgstr "用户 [id:%s, 名称:%s] 下载成功"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_user.py:0
-#, python-format
-msgid "User [id:%s, name:%s] failed to download,Reason: %s"
-msgstr "用户 [id:%s, 名称:%s] 下载失败,原因: %s"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_tag__userlist
-msgid "User list"
-msgstr "用户列表"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_user.py:0
-#, python-format
-msgid "User list sync completed."
-msgstr "用户列表同步完成。"
-
-#. module: wecom_contacts_sync
-#: model:ir.model,name:wecom_contacts_sync.model_change_type_user
-msgid "User, Change Type Wizard"
-msgstr "用户,变更类型向导"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_change_type_wizard__user_ids
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.change_type_wizard_user_tree_view
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_tag_form
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_user_filter
-msgid "Users"
-msgstr "用户"
-
-#. module: wecom_contacts_sync
-#: model_terms:wecom.app_config,description:wecom_contacts_sync.wecom_app_config_contacts_allow_add_system_users
-#: model_terms:wecom.app_config,description:wecom_contacts_sync.wecom_app_config_contacts_allow_sync_hr
-msgid "Value: True or False"
-msgstr "值:True 或 False"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_res_config_settings__module_wecom_hr_sync
-msgid "WeCom HR synchronization"
-msgstr ""
-
-#. module: wecom_contacts_sync
-#: model:ir.model,name:wecom_contacts_sync.model_wecom_contacts_sync_wizard
-msgid "WeCom contacts synchronization wizard"
-msgstr "企微通讯录同步向导"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_block__wecom_userid
-msgid "WeCom user Id"
-msgstr "企微用户Id"
-
-#. module: wecom_contacts_sync
-#: model:ir.actions.server,name:wecom_contacts_sync.ir_cron_sync_wecom_contacts_ir_actions_server
-msgid "WeCom: Synchronize contacts"
-msgstr "企微:同步通讯录"
-
-#. module: wecom_contacts_sync
-#: model:ir.actions.act_window,name:wecom_contacts_sync.ir_cron_act_sync_wecom_contacts
-msgid "WeCom: Synchronize contacts regularly"
-msgstr "企微:定时同步通讯录"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_tag.py:0
-#, python-format
-msgid "Wecom API acquisition company[%s]'s tag [id:%s] member failed, error details: %s"
-msgstr "企微API获取公司 [%s] 的标签 [id:%s] 成员失败,错误详细信息:%s"
-
-#. module: wecom_contacts_sync
-#: model:ir.model,name:wecom_contacts_sync.model_wecom_apps
-msgid "Wecom Application"
-msgstr "企微应用"
-
-#. module: wecom_contacts_sync
-#: model_terms:wecom.app_config,description:wecom_contacts_sync.wecom_app_config_contacts_edit_enabled
-msgid ""
-"Wecom Contacts can be read and edited through API interface\n"
-" Value: True or False"
-msgstr ""
-"企业微信通讯录可以通过API接口读取和编辑\n"
-" 值: True 或 False"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_form_wecom_contacts_sync_result
-msgid "Wecom Department sync"
-msgstr "企微部门同步"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_form_wecom_contacts_sync_result
-msgid "Wecom Tag sync"
-msgstr "企微标签同步"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_form_wecom_contacts_sync_result
-msgid "Wecom User sync"
-msgstr "企微用户同步"
-
-#. module: wecom_contacts_sync
-#: model:ir.model,name:wecom_contacts_sync.model_wecom_contacts_block
-msgid "Wecom contacts synchronization block list"
-msgstr "企微通讯录同步阻止列表"
-
-#. module: wecom_contacts_sync
-#: model:ir.model,name:wecom_contacts_sync.model_wecom_department
-msgid "Wecom department"
-msgstr "企微部门"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_sync_wizard__wecom_department_sync_state
-msgid "Wecom department synchronization Status"
-msgstr "企微部门同步状态"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_sync_wizard__wecom_department_sync_result
-msgid "Wecom department synchronization results"
-msgstr "企微部门同步结果"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_sync_wizard__wecom_department_sync_times
-msgid "Wecom department synchronization time (seconds)"
-msgstr "企微部门同步时间(秒)"
-
-#. module: wecom_contacts_sync
-#: model:ir.model,name:wecom_contacts_sync.model_wecom_tag
-msgid "Wecom tag"
-msgstr "企微标签"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_sync_wizard__wecom_tag_sync_state
-msgid "Wecom tag synchronization Status"
-msgstr "企微标签同步状态"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_sync_wizard__wecom_tag_sync_result
-msgid "Wecom tag synchronization results"
-msgstr "企微标签同步结果"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_sync_wizard__wecom_tag_sync_times
-msgid "Wecom tag synchronization time (seconds)"
-msgstr "企微标签同步时间(秒)"
-
-#. module: wecom_contacts_sync
-#: model:ir.model,name:wecom_contacts_sync.model_wecom_user
-msgid "Wecom user"
-msgstr "企微用户"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_sync_wizard__wecom_user_sync_state
-msgid "Wecom user synchronization Status"
-msgstr "企微用户同步状态"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_sync_wizard__wecom_user_sync_result
-msgid "Wecom user synchronization results"
-msgstr "企微用户同步结果"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_contacts_sync_wizard__wecom_user_sync_times
-msgid "Wecom user synchronization time (seconds)"
-msgstr "企微用户同步时间(秒)"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_apps.py:0
-#, python-format
-msgid ""
-"When members modify their personal information, the modified information will be pushed to "
-"the following URL in the form of events to ensure the synchronization of the address book."
-msgstr "当成员修改个人信息时,被修改的信息将以事件的形式推送到以下URL,保证通讯录同步。"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_change_type_user__wizard_id
-msgid "Wizard"
-msgstr "向导"
-
-#. module: wecom_contacts_sync
-#: model:ir.model,name:wecom_contacts_sync.model_change_type_wizard
-msgid "Wizard to change user type(WeCom)"
-msgstr "变更用户类型向导(企微)"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_user_form
-msgid "Work Information"
-msgstr "工作信息"
-
-#. module: wecom_contacts_sync
-#. odoo-python
-#: code:addons/wecom_contacts_sync/models/wecom_user.py:0
-#, python-format
-msgid "Yes"
-msgstr "是"
-
-#. module: wecom_contacts_sync
-#: model_terms:ir.ui.view,arch_db:wecom_contacts_sync.view_wecom_department_form
-msgid "department"
-msgstr "部门"
-
-#. module: wecom_contacts_sync
-#: model:ir.model.fields,field_description:wecom_contacts_sync.field_wecom_user__mobile
-msgid "mobile phone"
-msgstr "手机"
diff --git a/wecom_contacts_sync/models/__init__.py b/wecom_contacts_sync/models/__init__.py
deleted file mode 100644
index 4d6292e3c..000000000
--- a/wecom_contacts_sync/models/__init__.py
+++ /dev/null
@@ -1,13 +0,0 @@
-# -*- coding: utf-8 -*-
-
-
-from . import res_company
-from . import res_config_settings
-from . import res_users
-
-
-from . import wecom_apps
-from . import wecom_contacts_block
-from . import wecom_user
-from . import wecom_department
-from . import wecom_tag
diff --git a/wecom_contacts_sync/models/res_company.py b/wecom_contacts_sync/models/res_company.py
deleted file mode 100644
index 3b55974ac..000000000
--- a/wecom_contacts_sync/models/res_company.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# -*- coding: utf-8 -*-
-
-
-from odoo.http import request
-from odoo import api, fields, models, tools, _
-
-
-class Company(models.Model):
- _inherit = "res.company"
-
- self_built_app_id = fields.Many2one(
- "wecom.apps",
- string="Self-built Application",
- domain="[('company_id', '=', current_company_id)]",
- )
-
- contacts_sync_app_id = fields.Many2one(
- "wecom.apps",
- string="Contacts Synchronization Application",
- domain="[('company_id', '=', current_company_id)]",
- )
\ No newline at end of file
diff --git a/wecom_contacts_sync/models/res_config_settings.py b/wecom_contacts_sync/models/res_config_settings.py
deleted file mode 100644
index fe9e7664e..000000000
--- a/wecom_contacts_sync/models/res_config_settings.py
+++ /dev/null
@@ -1,71 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from odoo import models, fields, api, _
-from odoo.exceptions import ValidationError
-
-import logging
-
-_logger = logging.getLogger(__name__)
-
-
-class ResConfigSettings(models.TransientModel):
- _inherit = "res.config.settings"
-
- # 通讯录同步应用
- contacts_sync_app_id = fields.Many2one(
- related="company_id.contacts_sync_app_id", readonly=False
- )
- contacts_sync_app_agentid = fields.Integer(
- related="contacts_sync_app_id.agentid", readonly=False
- )
- contacts_sync_secret = fields.Char(
- related="contacts_sync_app_id.secret", readonly=False
- )
-
- contacts_sync_app_config_ids = fields.One2many(
- related="contacts_sync_app_id.app_config_ids",
- readonly=False,
- )
-
- # 自建应用
- self_built_app_id = fields.Many2one(
- related="company_id.self_built_app_id", readonly=False
- )
- self_built_app_agentid = fields.Integer(
- related="self_built_app_id.agentid", readonly=False
- )
- self_built_app_secret = fields.Char(
- related="self_built_app_id.secret", readonly=False
- )
-
- module_wecom_hr_sync = fields.Boolean("WeCom HR synchronization")
-
- def generate_service(self):
- """
- 生成服务
- :return:
- """
- code = self.env.context.get("code")
- if bool(code) and code == "contacts":
- for record in self:
- if not record.contacts_app_id: # type: ignore
- raise ValidationError(_("Please bind contact application!"))
- else:
- record.contacts_app_id.with_context(code=code).generate_service() # type: ignore
- # super(ResConfigSettings, self).generate_service()
-
- def generate_parameters(self):
- """
- 生成参数
- :return:
- """
- code = self.env.context.get("code")
- if bool(code) and code == "contacts_sync":
- for record in self:
- if not record.contacts_sync_app_id: # type: ignore
- raise ValidationError(
- _("Please bind contact synchronization application!")
- )
- else:
- record.contacts_sync_app_id.with_context(code=code).generate_parameters() # type: ignore
- # super(ResConfigSettings, self).generate_parameters()
diff --git a/wecom_contacts_sync/models/res_users.py b/wecom_contacts_sync/models/res_users.py
deleted file mode 100644
index 2fce9d9ab..000000000
--- a/wecom_contacts_sync/models/res_users.py
+++ /dev/null
@@ -1,663 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import logging
-import time
-from odoo import fields, models, api, Command, tools, _
-from odoo.exceptions import UserError
-from lxml import etree
-
-import xmltodict
-from odoo.addons.wecom_api.api.wecom_abstract_api import ApiException # type: ignore
-from odoo.addons.base.models.ir_mail_server import MailDeliveryException
-
-_logger = logging.getLogger(__name__)
-
-
-WECOM_USER_MAPPING_ODOO_USER = {
- "UserID": "wecom_userid", # 成员UserID
- "Name": "name", # 成员名称;
- "Department": "", # 成员部门列表,仅返回该应用有查看权限的部门id
- "MainDepartment": "", # 主部门
- "IsLeaderInDept": "", # 表示所在部门是否为上级,0-否,1-是,顺序与Department字段的部门逐一对应
- "DirectLeader": "", # 直属上级
- "Mobile": "mobile_phone", # 手机号码
- "Position": "", # 职位信息
- "Gender": "", # 企微性别:0表示未定义,1表示男性,2表示女性;odoo性别:male为男性,female为女性,other为其他
- "Email": "work_email", # 邮箱;
- "Status": "active", # 激活状态:1=已激活 2=已禁用 4=未激活 已激活代表已激活企业微信或已关注微工作台(原企业号)5=成员退出
- "Avatar": "", # 头像url。注:如果要获取小图将url最后的”/0”改成”/100”即可。
- "Alias": "", # 成员别名
- "Telephone": "work_phone", # 座机;
- "Address": "", # 地址;
- "ExtAttr": {
- "Type": "", # 扩展属性类型: 0-本文 1-网页
- "Text": "", # 文本属性类型,扩展属性类型为0时填写
- "Value": "", # 文本属性内容
- "Web": "", # 网页类型属性,扩展属性类型为1时填写
- "Title": "", # 网页的展示标题
- "Url": "", # 网页的url
- }, # 扩展属性;
-}
-
-
-class User(models.Model):
- _inherit = ["res.users"]
-
- # employee_id = fields.Many2one(
- # "hr.employee",
- # string="Company employee",
- # compute="_compute_company_employee",
- # search="_search_company_employee",
- # store=True,
- # ) # 变更用户类型时,需要绑定用户,避免出现“创建员工”的按钮,故 store=True
-
- # ----------------------------------------------------------------------------------
- # 开发人员注意:hr模块中
- # hr.employee.work_email = res.users.email
- # hr.employee.private_email = res.partner.email
- # ----------------------------------------------------------------------------------
- # base 模块中
- # res.user.email = res.partner.email
- # res.user.private_email = res.partner.email
- # ------------------------------------------
- # hr.employee.create() 方法中 创建hr.employee.work_email时会将 res.users.email更新到hr.employee.work_email
- # res.users.write() 方法中 更新res.users.email时会将 res.users.email更新到hr.employee.work_email
- # ------------------------------------------
- # 故重写了 将 private_email = address_home_id.email 修改为 private_email=employee_id.private_email
- # 故重写了 SELF_WRITEABLE_FIELDS
- # ----------------------------------------------------------------------------------
-
- # private_email = fields.Char(related='employee_id.private_email', string="Private Email")
-
- def _get_or_create_user_by_wecom_userid(self, object, send_mail, send_message):
- """
- 通过企微用户id获取odoo用户
- """
- login = tools.ustr(object.wecom_userid)
- self.env.cr.execute(
- "SELECT id, active FROM res_users WHERE lower(login)=%s", (login,)
- )
- res = self.env.cr.fetchone()
- if res:
- if res[1]:
- return res[0]
- else:
- group_portal_id = self.env["ir.model.data"]._xmlid_to_res_id(
- "base.group_portal"
- ) # 门户用户组
- SudoUser = self.sudo()
- values = {
- "name": object.name,
- "login": login,
- "notification_type": "inbox",
- "groups_id": [(6, 0, [group_portal_id])],
- "share": False,
- "active": object.active,
- "image_1920": object.image_1920,
- "password": self.env["wecomapi.tools.security"].random_passwd(8),
- "company_ids": [(6, 0, [object.company_id.id])],
- "company_id": object.company_id.id,
- "employee_ids": [(6, 0, [object.id])],
- "employee_id": object.id,
- "lang": self.env.lang,
- "company_id": object.company_id.id,
- # 以下为企业微信字段
- "wecom_userid": object.wecom_userid.lower(),
- "wecom_openid": object.wecom_openid,
- "is_wecom_user": object.is_wecom_user,
- "qr_code": object.qr_code,
- "wecom_user_order": object.wecom_user_order,
- }
-
- # 判断是否已存在 partner
- partner = (
- self.env["res.partner"]
- .sudo()
- .search(
- [
- ("wecom_userid", "=", object.wecom_userid),
- ("company_id", "=", object.company_id.id),
- ("is_wecom_user", "=", True),
- "|",
- ("active", "=", True),
- ("active", "=", False),
- ],
- limit=1,
- )
- )
-
- if not partner:
- pass
- else:
- values.update({"partner_id": partner.id})
- """
- MailThread功能可以通过上下文键进行一定程度的控制:
-
- -'mail_create_nosubscribe':在create或message_post上,不要订阅记录线程的uid
- -'mail_create_nolog':在创建时,不要记录自动的““创建”消息
- -'mail_notrack':在创建和写入时,不要执行值跟踪创建消息
- -'tracking_disable':在创建和写入时,不执行邮件线程功能(自动订阅、跟踪、发布等)
- -'mail_notify_force_send': 如果要发送的电子邮件通知少于50封,直接发送,而不是使用队列;默认情况下为True
- """
- return (
- SudoUser.with_context(
- mail_create_nosubscribe=True,
- mail_create_nolog=True,
- mail_notrack=True,
- tracking_disable=True,
- send_mail=send_mail,
- send_message=send_message,
- )
- .create(values)
- .id
- )
- # return SudoUser.with_context(send_mail=send_mail).create(values).id
-
- @api.model_create_multi
- def create(self, vals_list):
- """
- 重写以自动邀请用户注册
- send_mail: true 表示发送邀请邮件, false 表示不发送邀请邮件
- 批量创建用户时,建议 send_mail=False
- """
- users = super(User, self).create(vals_list)
-
- if not self.env.context.get("no_reset_password") and self.env.context.get(
- "send_mail"
- ):
- users_with_email = users.filtered("email")
- if users_with_email:
- try:
- users_with_email.with_context(
- create_user=True
- ).action_reset_password()
- except MailDeliveryException:
- users_with_email.partner_id.with_context(
- create_user=True
- ).signup_cancel()
-
- return users
-
- # ------------------------------------------------------------
- # 企微部门下载
- # ------------------------------------------------------------
- @api.model
- def download_wecom_contacts(self):
- """
- 下载企微通讯录
- """
- start_time = time.time()
- company = self.env.context.get("company_id")
-
- tasks = []
- if not company:
- company = self.env.company
- if company.is_wecom_organization:
- try:
- wxapi = self.env["wecom.service_api"].InitServiceApi(
- company.corpid, company.contacts_app_id.secret
- )
- app_config = self.env["wecom.app_config"].sudo()
- contacts_sync_hr_department_id = app_config.get_param(
- company.contacts_app_id.id, "contacts_sync_hr_department_id"
- ) # 需要同步的企业微信部门ID
- response = wxapi.httpCall(
- self.env["wecom.service_api_list"].get_server_api_call("USER_LIST"),
- {
- "department_id": contacts_sync_hr_department_id,
- "fetch_child": "1",
- },
- )
- except ApiException as ex:
- end_time = time.time()
- self.env["wecomapi.tools.action"].ApiExceptionDialog(
- ex, raise_exception=False
- )
- tasks = [
- {
- "name": "download_contact_data",
- "state": False,
- "time": end_time - start_time,
- "msg": str(ex),
- }
- ]
- except Exception as e:
- end_time = time.time()
- tasks = [
- {
- "name": "download_contact_data",
- "state": False,
- "time": end_time - start_time,
- "msg": str(e),
- }
- ]
- else:
- wecom_users = response["userlist"]
-
- # 获取block
- blocks = (
- self.env["wecom.contacts.block"]
- .sudo()
- .search(
- [
- ("company_id", "=", company.id),
- ]
- )
- )
- block_list = []
-
- # 生成 block_list
- if len(blocks) > 0:
- for obj in blocks:
- if obj.wecom_userid != None:
- block_list.append(obj.wecom_userid)
-
- # 从 wecom_users 移除 block_list
- for b in block_list:
- for item in wecom_users:
- # userid不区分大小写
- if item["userid"].lower() == b.lower():
- wecom_users.remove(item)
-
- # 1. 下载联系人
- for wecom_user in wecom_users:
- download_user_result = self.download_user(company, wecom_user)
- if download_user_result:
- for r in download_user_result:
- tasks.append(r) # 加入设置下载联系人失败结果
-
- # 2.完成下载
- end_time = time.time()
- task = {
- "name": "download_contact_data",
- "state": True,
- "time": end_time - start_time,
- "msg": _("Contacts list downloaded successfully."),
- }
- tasks.append(task)
- else:
- end_time = time.time()
- tasks = [
- {
- "name": "download_contact_data",
- "state": False,
- "time": end_time - start_time,
- "msg": _(
- "The current company does not identify the Wecom organization. Please configure or switch the company."
- ),
- }
- ] # 返回失败结果
- return tasks
-
- def download_user(self, company, wecom_user):
- """
- 下载联系人
- """
- user = self.sudo().search(
- [
- ("wecom_userid", "=", wecom_user["userid"].lower()),
- ("company_id", "=", company.id),
- ("is_wecom_user", "=", True),
- "|",
- ("active", "=", True),
- ("active", "=", False),
- ],
- limit=1,
- )
- result = {}
- app_config = self.env["wecom.app_config"].sudo()
- contacts_allow_add_system_users = app_config.get_param(
- company.contacts_app_id.id, "contacts_allow_add_system_users"
- ) # 允许创建用户
-
- if contacts_allow_add_system_users == "True":
- contacts_allow_add_system_users = True
- elif contacts_allow_add_system_users is None:
- contacts_allow_add_system_users = False
- else:
- contacts_allow_add_system_users = False
-
- if not user and contacts_allow_add_system_users:
- result = self.create_user(company, user, wecom_user)
- else:
- result = self.update_user(company, user, wecom_user)
- return result
-
- def create_user(self, company, user, wecom_user):
- """
- 创建联系人
- """
- params = self.env["ir.config_parameter"].sudo()
- debug = params.get_param("wecom.debug_enabled")
-
- app_config = self.env["wecom.app_config"].sudo()
- contacts_use_default_avatar = app_config.get_param(
- company.contacts_app_id.id,
- "contacts_use_default_avatar_when_adding_employees",
- ) # 使用系统微信默认头像的标识
-
- try:
- groups_id = (
- self.sudo()
- .env["res.groups"]
- .search(
- [
- ("id", "=", 9),
- ],
- limit=1,
- )
- .id
- ) # id=1是内部用户, id=9是门户用户
- user.create(
- {
- "notification_type": "inbox",
- "company_ids": [Command.link(user.company_id.id)],
- "company_id": user.company_id.id,
- "name": wecom_user["name"],
- "login": wecom_user[
- "userid"
- ].lower(), # 登陆账号 使用 企业微信用户id的小写
- "password": self.env["wecomapi.tools.security"].random_passwd(8),
- "email": wecom_user["email"],
- "work_phone": wecom_user["telephone"],
- "mobile_phone": wecom_user["mobile"],
- "employee_phone": wecom_user["mobile"],
- "work_email": wecom_user["email"],
- "gender": self.env["wecomapi.tools.convert"].sex2gender(
- wecom_user["gender"]
- ),
- "wecom_userid": wecom_user["userid"].lower(),
- "image_1920": self.env["wecomapi.tools.file"].get_avatar_base64(
- contacts_use_default_avatar,
- wecom_user["gender"],
- wecom_user["avatar"],
- ),
- "qr_code": wecom_user["qr_code"],
- "active": True if wecom_user["status"] == 1 else False,
- "is_wecom_user": True,
- "is_company": False,
- "share": False,
- "groups_id": [(6, 0, [groups_id])], # 设置用户为门户用户
- "tz": "Asia/Shanghai",
- "lang": "zh_CN",
- }
- )
- except Exception as e:
- result = _("Error creating company %s partner %s %s, error reason: %s") % (
- company.name,
- wecom_user["userid"].lower(),
- wecom_user["name"],
- repr(e),
- )
- if debug:
- _logger.warning(result)
- return {
- "name": "add_partner",
- "state": False,
- "time": 0,
- "msg": result,
- } # 返回失败结果
-
- def update_user(self, company, user, wecom_user):
- """
- 更新联系人
- """
- params = self.env["ir.config_parameter"].sudo()
- debug = params.get_param("wecom.debug_enabled")
- app_config = self.env["wecom.app_config"].sudo()
- contacts_use_default_avatar = app_config.get_param(
- company.contacts_app_id.id,
- "contacts_use_default_avatar_when_adding_employees",
- ) # 使用系统微信默认头像的标识
-
- try:
- user.write(
- {
- "notification_type": "inbox",
- "name": wecom_user["name"],
- "login": wecom_user[
- "userid"
- ].lower(), # 登陆账号 使用 企业微信用户id的小写
- "email": wecom_user["email"],
- "work_phone": wecom_user["telephone"],
- "mobile_phone": wecom_user["mobile"],
- "employee_phone": wecom_user["mobile"],
- "work_email": wecom_user["email"],
- "gender": self.env["wecomapi.tools.convert"].sex2gender(
- wecom_user["gender"]
- ),
- "wecom_userid": wecom_user["userid"].lower(),
- # "image_1920": self.env["wecomapi.tools.file"].get_avatar_base64(
- # contacts_use_default_avatar,
- # wecom_user["gender"],
- # wecom_user["avatar"],
- # ),
- "qr_code": wecom_user["qr_code"],
- "active": True if wecom_user["status"] == 1 else False,
- }
- )
- except Exception as e:
- result = _("Error creating company %s partner %s %s, error reason: %s") % (
- company.name,
- wecom_user["userid"].lower(),
- wecom_user["name"],
- repr(e),
- )
- if debug:
- _logger.warning(result)
- return {
- "name": "update_partner",
- "state": False,
- "time": 0,
- "msg": result,
- } # 返回失败结果
-
- # ------------------------------------------------------------
- # 企微通讯录事件
- # ------------------------------------------------------------
- def wecom_event_change_contact_user(self, cmd):
- """
- 通讯录事件变更系统用户
- """
- xml_tree = self.env.context.get("xml_tree")
- company_id = self.env.context.get("company_id")
- xml_tree_str = etree.fromstring(bytes.decode(xml_tree)) # type: ignore
- dic = lxml_to_dict(xml_tree_str)["xml"] # type: ignore
-
- domain = [
- "|",
- ("active", "=", True),
- ("active", "=", False),
- ]
- user = self.sudo().search([("company_id", "=", company_id.id)] + domain)
- callback_user = user.search( # type: ignore
- [("wecom_userid", "=", dic["UserID"].lower())] + domain,
- limit=1,
- )
- # print("用户CMD", cmd)
- if callback_user:
- # 如果存在,则更新
- # 用于退出企业微信又重新加入企业微信的员工
- cmd = "update"
- else:
- # 如果不存在且不允许添加系统用户,停止
- app_config = self.env["wecom.app_config"].sudo()
- allow_add_system_users = app_config.get_param(
- company_id.contacts_app_id.id,
- "contacts_allow_add_system_users",
- ) # 使用系统微信默认头像的标识
- if allow_add_system_users is False:
- return
-
- update_dict = {}
-
- for key, value in dic.items():
- if (
- key == "ToUserName"
- or key == "FromUserName"
- or key == "CreateTime"
- or key == "Event"
- or key == "MsgType"
- or key == "ChangeType"
- ):
- # 忽略掉 不需要的key
- pass
- else:
- if key in WECOM_USER_MAPPING_ODOO_USER.keys():
- if WECOM_USER_MAPPING_ODOO_USER[key] != "":
- if WECOM_USER_MAPPING_ODOO_USER[key] == "wecom_userid":
- update_dict.update({"wecom_userid": value.lower()})
- elif WECOM_USER_MAPPING_ODOO_USER[key] == "active":
- # 状态
- # 激活状态: 1=已激活,2=已禁用,4=未激活,5=退出企业。
- # 已激活代表已激活企业微信或已关注微工作台(原企业号)。未激活代表既未激活企业微信又未关注微工作台(原企业号)。
- if value == "1":
- update_dict.update({"active": True})
- else:
- update_dict.update({"active": False})
- elif WECOM_USER_MAPPING_ODOO_USER[key] == "gender":
- gender = self.env["wecomapi.tools.convert"].sex2gender(
- value
- )
- update_dict.update({"gender": gender})
- else:
- update_dict[WECOM_USER_MAPPING_ODOO_USER[key]] = value
- else:
- _logger.info(
- _(
- "There is no mapping for field [%s], please contact the developer."
- )
- % key
- )
-
- if cmd == "create":
- update_dict.update(
- {
- "is_wecom_user": True,
- }
- )
- try:
- wecomapi = self.env["wecom.service_api"].InitServiceApi(
- company_id.corpid, company_id.contacts_app_id.secret
- )
- response = wecomapi.httpCall(
- self.env["wecom.service_api_list"].get_server_api_call("USER_GET"),
- {"userid": update_dict["wecom_userid"]},
- )
- if response.get("errcode") == 0:
- update_dict.update({"qr_code": response.get("qr_code")})
- except:
- pass
-
- callback_user.create(update_dict) # type: ignore
- elif cmd == "update":
- if "wecom_userid" in update_dict:
- del update_dict["wecom_userid"]
- callback_user.write(update_dict) # type: ignore
- elif cmd == "delete":
- callback_user.write( # type: ignore
- {
- "active": False,
- }
- )
-
-
-# ------------------------------------------------------------
-# 变更用户类型向导
-# ------------------------------------------------------------
-class ChangeTypeWizard(models.TransientModel):
- _name = "change.type.wizard"
- _description = "Wizard to change user type(WeCom)"
-
- def _default_user_ids(self):
- user_ids = (
- self._context.get("active_model") == "res.users"
- and self._context.get("active_ids")
- or []
- )
- return [
- (
- 0,
- 0,
- {
- "user_id": user.id,
- "user_login": user.login,
- "user_name": user.name,
- },
- )
- for user in self.env["res.users"].browse(user_ids)
- ]
-
- user_ids = fields.One2many(
- "change.type.user", "wizard_id", string="Users", default=_default_user_ids
- )
-
- def change_type_button(self):
- self.ensure_one()
- self.user_ids.change_type_button() # type: ignore
- if self.env.user in self.mapped("user_ids.user_id"):
- return {"type": "ir.actions.client", "tag": "reload"}
- return {"type": "ir.actions.act_window_close"}
-
-
-class ChangeTypeUser(models.TransientModel):
- _name = "change.type.user"
- _description = "User, Change Type Wizard"
-
- wizard_id = fields.Many2one(
- "change.type.wizard", string="Wizard", required=True, ondelete="cascade"
- )
-
- user_id = fields.Many2one(
- "res.users", string="User", required=True, ondelete="cascade"
- )
- user_login = fields.Char(
- string="Login account",
- readonly=True,
- )
- user_name = fields.Char(string="Login name", readonly=True)
- # 用户类型参见res_group
- new_type = fields.Selection(
- [
- ("1", _("Internal User")),
- ("9", _("Portal User")),
- ("10", _("Public User")),
- ],
- string="User Type",
- default="1",
- )
-
- def change_type_button(self):
- for line in self:
- if not line.new_type: # type: ignore
- raise UserError(
- _(
- "Before clicking the 'Change User Type' button, you must modify the new user type"
- )
- )
- if (
- # 排除初始系统自带的用户
- line.user_id.id == 1 # type: ignore
- or line.user_id.id == 2 # type: ignore
- or line.user_id.id == 3 # type: ignore
- or line.user_id.id == 4 # type: ignore
- or line.user_id.id == 5 # type: ignore
- ):
- pass
- else:
- if line.new_type == "1": # type: ignore
- try:
- line.user_id.employee_id = ( # type: ignore
- self.env["hr.employee"].search(
- [
- ("id", "in", line.user_id.employee_ids.ids), # type: ignore
- ("company_id", "=", line.user_id.company_id.id), # type: ignore
- ],
- limit=1,
- ),
- )
- except Exception as e:
- print("用户 %s 类型变更错误,错误:%s" % (line.user_id.name, repr(e))) # type: ignore
-
- line.user_id.write({"groups_id": [(6, 0, line.new_type)]}) # type: ignore
- self.write({"new_type": False})
diff --git a/wecom_contacts_sync/models/wecom_apps.py b/wecom_contacts_sync/models/wecom_apps.py
deleted file mode 100644
index 840ca469c..000000000
--- a/wecom_contacts_sync/models/wecom_apps.py
+++ /dev/null
@@ -1,505 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import logging
-import datetime
-import re
-from odoo import _, api, fields, models
-from odoo.exceptions import UserError, ValidationError
-
-from io import StringIO
-import pandas as pd
-
-pd.set_option("max_colwidth", 4096) # 设置最大列宽
-pd.set_option("display.max_columns", 30) # 设置最大列数
-pd.set_option("expand_frame_repr", False) # 当列太多时不换行
-import time
-
-from odoo.addons.wecom_api.api.wecom_abstract_api import ApiException # type: ignore
-
-_logger = logging.getLogger(__name__)
-
-
-class WeComApps(models.Model):
- _inherit = "wecom.apps"
-
- # ————————————————————————————————————
- # 应用回调服务
- # ————————————————————————————————————
-
- def generate_service_by_code(self, code):
- """
- 根据code生成回调服务
- :param code:
- :return:
- """
- if code == "contacts":
- service = self.app_callback_service_ids.sudo().search( # type: ignore
- [
- ("app_id", "=", self.id), # type: ignore
- ("code", "=", code),
- "|",
- ("active", "=", True),
- ("active", "=", False),
- ]
- )
-
- if not service:
- service.create(
- {
- "app_id": self.id, # type: ignore
- "name": _("Contacts synchronization"),
- "code": code,
- "callback_url_token": "",
- "callback_aeskey": "",
- "description": _(
- "When members modify their personal information, the modified information will be pushed to the following URL in the form of events to ensure the synchronization of the address book."
- ),
- }
- )
- else:
- service.write(
- {
- "name": _("Contacts synchronization"),
- "code": code,
- "callback_url": service.generate_contact_service(),
- "description": _(
- "When members modify their personal information, the modified information will be pushed to the following URL in the form of events to ensure the synchronization of the address book."
- ),
- }
- )
-
- # ————————————————————————————————————
- # 应用参数配置
- # ————————————————————————————————————
-
- def generate_parameters_by_code(self, code):
- """
- 根据code生成参数
- :param code:
- :return:
- 注意: 14使用 get_object_reference 方法, 后续版本 使用 _xmlid_lookup 方法,
- 故在 '\wecom_base\models\ir_model.py' 添加了 get_object_reference方 法
- """
- self.ensure_one()
- if code == "contacts_sync":
- # 从xml 获取数据
- ir_model_data = self.env["ir.model.data"]
- contacts_allow_sync_hr = ir_model_data._xmlid_lookup(
- "wecom_contacts_sync.wecom_app_config_contacts_allow_sync_hr"
- )[
- 1
- ] # 1
- contacts_sync_hr_department_id = ir_model_data._xmlid_lookup(
- "wecom_contacts_sync.wecom_app_config_contacts_sync_hr_department_id",
- )[
- 1
- ] # 2
- contacts_edit_enabled = ir_model_data._xmlid_lookup(
- "wecom_contacts_sync.wecom_app_config_contacts_edit_enabled"
- )[
- 1
- ] # 3
- contacts_allow_add_system_users = ir_model_data._xmlid_lookup(
- "wecom_contacts_sync.wecom_app_config_contacts_allow_add_system_users",
- )[
- 1
- ] # 4
- contacts_use_default_avatar_when_adding_employees = ir_model_data._xmlid_lookup(
- "wecom_contacts_sync.wecom_app_config_contacts_use_default_avatar_when_adding_employees",
- )[
- 1
- ] # 5
- contacts_update_avatar_every_time_sync_employees = ir_model_data._xmlid_lookup(
- "wecom_contacts_sync.wecom_app_config_contacts_update_avatar_every_time_sync_employees",
- )[
- 1
- ] # 6
- # enabled_join_qrcode = ir_model_data._xmlid_lookup(
- # "wecom_contacts_sync.wecom_app_config_contacts_enabled_join_qrcode"
- # )[
- # 1
- # ] # 7
- # join_qrcode = ir_model_data._xmlid_lookup(
- # "wecom_contacts_sync.wecom_app_config_contacts_join_qrcode"
- # )[
- # 1
- # ] # 8
- # join_qrcode_size_type = ir_model_data._xmlid_lookup(
- # "wecom_contacts_sync.wecom_app_config_contacts_join_qrcode_size_type"
- # )[
- # 1
- # ] # 9
- # join_qrcode_last_time = ir_model_data._xmlid_lookup(
- # "wecom_contacts_sync.wecom_app_config_acontacts_join_qrcode_last_time",
- # )[
- # 1
- # ] # 10
-
- vals_list = [
- contacts_allow_sync_hr, # 1
- contacts_sync_hr_department_id, # 2
- contacts_edit_enabled, # 3
- contacts_allow_add_system_users, # 4
- contacts_use_default_avatar_when_adding_employees, # 5
- contacts_update_avatar_every_time_sync_employees, # 6
- # enabled_join_qrcode, # 7
- # join_qrcode, # 8
- # join_qrcode_size_type, # 9
- # join_qrcode_last_time, # 10
- ]
-
- for id in vals_list:
- app_config_id = self.env["wecom.app_config"].search([("id", "=", id)])
- app_config = (
- self.env["wecom.app_config"]
- .sudo()
- .search([("app_id", "=", self.id), ("key", "=", app_config_id.key)]) # type: ignore
- )
-
- if not app_config:
- app_config.sudo().create(
- {
- "name": app_config_id.name,
- "app_id": self.id, # type: ignore
- "key": app_config_id.key,
- "ttype": app_config_id.ttype,
- "value": (
- ""
- if app_config_id.key == "join_qrcode"
- or app_config_id.key == "join_qrcode_last_time"
- else app_config_id.value
- ),
- "description": app_config_id.description,
- }
- )
- else:
- app_config.sudo().write(
- {
- "name": app_config_id.name,
- "description": app_config_id.description,
- }
- )
-
- super(WeComApps, self).generate_parameters_by_code(code) # type: ignore
-
- # ————————————————————————————————————
- # 通讯录
- # ————————————————————————————————————
-
- def cron_sync_contacts(self):
- """
- 自动任务同步组织架构
- 同步内容: 1. wecom.department
- 2. wecom.user
- 3. wecom.tag
- """
- results = []
- total_time = 0
- sync_start_time = time.time()
-
- for app in self.search(
- [("company_id", "!=", False), ("type_code", "=", "['contacts']")] # type: ignore
- ):
- _logger.info(
- _(
- "Automatic task: start to synchronize the Wecom organizational structure of the company [%s]"
- )
- % (app.company_id.name)
- )
-
- result = app.sync_contacts()
- results.append(result)
-
- _logger.info(
- _(
- "Automatic task: end synchronizing the Wecom organizational structure of the company [%s]"
- )
- % (app.company_id.name)
- )
- df = pd.DataFrame(results)
-
- (
- sync_task_state,
- wecom_department_sync_state,
- wecom_user_sync_state,
- wecom_tag_sync_state,
- ) = self.handle_sync_all_state(
- df
- ) # 处理同步状态
-
- # 处理同步结果和时间
- sync_task_result = ""
- wecom_department_sync_result = ""
- wecom_user_sync_result = ""
- wecom_tag_sync_result = ""
-
- wecom_department_sync_times = 0
- wecom_user_sync_times = 0
- wecom_tag_sync_times = 0
-
- rows = len(df) # 获取所有行数
-
- for index, row in df.iterrows():
- if row["sync_state"] == "fail":
- sync_task_result += self.handle_sync_result(
- index, rows, row["sync_result"]
- )
-
- wecom_department_sync_result += self.handle_sync_result(
- index, rows, row["wecom_department_sync_result"]
- )
- wecom_user_sync_result += self.handle_sync_result(
- index, rows, row["wecom_user_sync_result"]
- )
- wecom_tag_sync_result += self.handle_sync_result(
- index, rows, row["wecom_tag_sync_result"]
- )
-
- wecom_department_sync_times += row["wecom_department_sync_times"]
- wecom_user_sync_times += row["wecom_user_sync_times"]
- wecom_tag_sync_times += row["wecom_tag_sync_times"]
-
- sync_end_time = time.time()
- total_time = sync_end_time - sync_start_time
- _logger.info(
- _(
- """
-Automatic task: end the synchronization of the Wecom organizational structure of all companies.
-=======================================================================================================================
-Task Synchronization status:%s, Synchronization task time:%s seconds,
-Synchronization results:
-%s
------------------------------------------------------------------------------------------------------------------------
-Wecom department sync status:%s, Synchronize Wecom department time: %s seconds,
-Synchronize Wecom department results:
-%s
------------------------------------------------------------------------------------------------------------------------
-Wecom User sync status:%s, Synchronize Wecom User time: %s seconds,
-Synchronize Wecom User results:
-%s
------------------------------------------------------------------------------------------------------------------------
-Wecom tag sync status:%s, Synchronize Wecom tag time: %s seconds,
-Synchronize Wecom tag results:
-%s
-======================================================================================================================="""
- )
- % (
- # 任务
- self.get_state_name(sync_task_state),
- total_time,
- sync_task_result,
- # 企微部门
- self.get_state_name(wecom_department_sync_state),
- wecom_department_sync_times,
- wecom_department_sync_result,
- # 企微员工
- self.get_state_name(wecom_user_sync_state),
- wecom_user_sync_times,
- wecom_user_sync_result,
- # 企微标签
- self.get_state_name(wecom_tag_sync_state),
- wecom_tag_sync_times,
- wecom_tag_sync_result,
- )
- )
-
- def sync_contacts(self):
- """
- 同步通讯录
- """
- # result = {
-
- # }
- result = {}
- result.update(
- {
- "company_name": self.company_id.name, # type: ignore
- "sync_state": "completed",
- "wecom_department_sync_state": "fail",
- "wecom_department_sync_times": 0,
- "wecom_department_sync_result": "",
- "wecom_user_sync_state": "fail",
- "wecom_user_sync_times": 0,
- "wecom_user_sync_result": "",
- "wecom_tag_sync_state": "fail",
- "wecom_tag_sync_times": 0,
- "wecom_tag_sync_result": "",
- }
- )
-
- # 同步企微部门
- sync_department_result = self.env["wecom.department"].with_context(company_id=self.company_id).download_wecom_deps() # type: ignore
-
- # [{'name': 'download_department_data', 'state': True, 'time': 0.3037421703338623, 'msg': 'Department list sync completed.'}]
-
- (
- wecom_department_sync_state,
- wecom_department_sync_times,
- wecom_department_sync_result,
- ) = self.handle_sync_task_state(
- sync_department_result, self.company_id
- ) # type: ignore
-
- result.update(
- {
- "wecom_department_sync_state": wecom_department_sync_state,
- "wecom_department_sync_times": wecom_department_sync_times,
- "wecom_department_sync_result": wecom_department_sync_result,
- }
- )
-
- if result["wecom_department_sync_state"] == "fail":
- return result
-
- # 同步企微用户
- sync_user_result = self.env["wecom.user"].with_context(company_id=self.company_id).download_wecom_users() # type: ignore
-
- (
- wecom_user_sync_state,
- wecom_user_sync_times,
- wecom_user_sync_result,
- ) = self.handle_sync_task_state(
- sync_user_result, self.company_id
- ) # type: ignore
- result.update(
- {
- "wecom_user_sync_state": wecom_user_sync_state,
- "wecom_user_sync_times": wecom_user_sync_times,
- "wecom_user_sync_result": wecom_user_sync_result,
- }
- )
-
- if result["wecom_user_sync_state"] == "fail":
- return result
-
- # 同步企微标签
- sync_wecom_tag_result = self.env["wecom.tag"].with_context(company_id=self.company_id).download_wecom_tags() # type: ignore
- (
- wecom_tag_sync_state,
- wecom_tag_sync_times,
- wecom_tag_sync_result,
- ) = self.handle_sync_task_state(
- sync_wecom_tag_result, self.company_id
- ) # type: ignore
- result.update(
- {
- "wecom_tag_sync_state": wecom_tag_sync_state,
- "wecom_tag_sync_times": wecom_tag_sync_times,
- "wecom_tag_sync_result": wecom_tag_sync_result,
- }
- )
-
- if result["wecom_tag_sync_state"] == "fail":
- return result
-
- return result
-
- def get_state_name(self, key):
- """
- 获取状态名称
- """
- STATE = {
- "completed": _("All completed"),
- "partially": _("Partially complete"),
- "fail": _("All failed"),
- }
- return dict(STATE).get(key, _("Unknown")) # 如果没有找到,返回Unknown
-
- def handle_sync_result(self, index, rows, result):
- """
- 处理同步结果
- """
- if result is None:
- return ""
- if index < rows - 1:
- result = "%s:%s \n" % (str(index + 1), result)
- else:
- result = "%s:%s" % (str(index + 1), result)
- return result
-
- def handle_sync_all_state(self, df):
- """
- 处理同步状态
- """
- all_state_rows = len(df) # 获取所有行数
- fail_state_rows = len(df[df["sync_state"] == "fail"]) # 获取失败行数
-
- # 获取部门失败行数
- fail_department_state_rows = len(
- df[df["wecom_department_sync_state"] == "fail"]
- )
-
- # 获取用户失败行数
- fail_user_state_rows = len(df[df["wecom_user_sync_state"] == "fail"])
-
- # 获取标签失败行数
- fail_tag_state_rows = len(df[df["wecom_tag_sync_state"] == "fail"])
-
- sync_state = None
- wecom_department_sync_state = None
- wecom_user_sync_state = None
- wecom_tag_sync_state = None
-
- if fail_state_rows == all_state_rows:
- sync_state = "fail"
- elif fail_state_rows > 0 and fail_state_rows < all_state_rows:
- sync_state = "partially"
- elif fail_state_rows == 0:
- sync_state = "completed"
-
- # 部门
- if fail_department_state_rows == all_state_rows:
- wecom_department_sync_state = "fail"
- elif (
- fail_department_state_rows > 0
- and fail_department_state_rows < all_state_rows
- ):
- wecom_department_sync_state = "partially"
- elif fail_department_state_rows == 0:
- wecom_department_sync_state = "completed"
-
- # 员工
- if fail_user_state_rows == all_state_rows:
- wecom_user_sync_state = "fail"
- elif fail_user_state_rows > 0 and fail_user_state_rows < all_state_rows:
- wecom_user_sync_state = "partially"
- elif fail_user_state_rows == 0:
- wecom_user_sync_state = "completed"
-
- if fail_tag_state_rows == all_state_rows:
- wecom_tag_sync_state = "fail"
- elif fail_tag_state_rows > 0 and fail_tag_state_rows < all_state_rows:
- wecom_tag_sync_state = "partially"
- elif fail_tag_state_rows == 0:
- wecom_tag_sync_state = "completed"
-
- return (
- sync_state,
- wecom_department_sync_state,
- wecom_user_sync_state, # type: ignore
- wecom_tag_sync_state,
- )
-
- def handle_sync_task_state(self, result, company):
- """
- 处理部门、用户、标签的 同步状态
- """
- df = pd.DataFrame(result)
- all_rows = len(df) # 获取所有行数
- fail_rows = len(df[df["state"] == False]) # 获取失败行数
-
- sync_state = None
- if fail_rows == all_rows:
- sync_state = "fail"
- elif fail_rows > 0 and fail_rows < all_rows:
- sync_state = "partially"
- elif fail_rows == 0:
- sync_state = "completed"
-
- sync_result = ""
- sync_times = 0
- for index, row in df.iterrows():
- sync_times += row["time"]
- sync_result += "[%s] %s" % (company.name, row["msg"])
-
- return sync_state, sync_times, sync_result
diff --git a/wecom_contacts_sync/models/wecom_contacts_block.py b/wecom_contacts_sync/models/wecom_contacts_block.py
deleted file mode 100644
index 0d707ba96..000000000
--- a/wecom_contacts_sync/models/wecom_contacts_block.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from odoo import api, fields, models, _
-from odoo.exceptions import UserError, ValidationError
-
-from odoo.addons.wecom_api.api.wecom_abstract_api import ApiException # type: ignore
-import logging
-
-_logger = logging.getLogger(__name__)
-
-
-class WxworkContactsBlock(models.Model):
- _name = "wecom.contacts.block"
- _description = "Wecom contacts synchronization block list"
-
- name = fields.Char(
- string="Name",
- readonly=True,
- copy=False,
- compute="_compute_name",
- store=True,
- ) # required=True,readonly=True, store=True
- company_id = fields.Many2one(
- "res.company",
- string="Company",
- domain="[('is_wecom_organization', '=', True)]",
- copy=False,
- required=True,
- )
-
- wecom_userid = fields.Char(string="WeCom user Id", required=True)
-
- _sql_constraints = [
- (
- "userid_company_uniq",
- "unique (wecom_userid, company_id)",
- "The user ID of each company must be unique!",
- ),
- ]
-
- @api.depends("company_id", "wecom_userid")
- def _compute_name(self):
- for block in self:
- if block.company_id and block.wecom_userid: # type: ignore
- company = block.company_id # type: ignore
- name = ""
- try:
- wxapi = self.env["wecom.service_api"].InitServiceApi(
- company.corpid, company.contacts_app_id.secret
- )
- response = wxapi.httpCall(
- self.env["wecom.service_api_list"].get_server_api_call(
- "USER_GET"
- ),
- {"userid": block.wecom_userid}, # type: ignore
- )
- name = response["name"]
- except ApiException as ex:
- return self.env["wecomapi.tools.action"].ApiExceptionDialog(
- ex, raise_exception=True
- )
- finally:
- block.name = name # type: ignore
diff --git a/wecom_contacts_sync/models/wecom_department.py b/wecom_contacts_sync/models/wecom_department.py
deleted file mode 100644
index 8b3e83d05..000000000
--- a/wecom_contacts_sync/models/wecom_department.py
+++ /dev/null
@@ -1,478 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import logging
-import json
-import time
-from odoo import fields, models, api, Command, tools, _
-from odoo.exceptions import UserError
-import xmltodict
-from odoo.addons.wecom_api.api.wecom_abstract_api import ApiException # type: ignore
-from odoo.addons.base.models.ir_mail_server import MailDeliveryException
-
-_logger = logging.getLogger(__name__)
-
-
-class WecomDepartment(models.Model):
- _name = "wecom.department"
- _description = "Wecom department"
- _order = "complete_name"
-
- # 企微字段
- department_id = fields.Integer(
- string="Department ID", readonly=True, default=0
- ) # 部门id
- name = fields.Char(
- string="Name",
- readonly=True,
- default="",
-
- ) # 部门名称 compute="_compute_name",
- name_en = fields.Char(string="English name", readonly=True, default="") # 英部门文名称
- department_leader = fields.Char(
- string="Department Leader", readonly=True, default="[]"
- ) # 部门负责人的UserID;第三方仅通讯录应用可获取
- parentid = fields.Integer(
- string="Parent department id",
- readonly=True,
- default=0,
- domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]",
- ) # 父部门id。根部门为1
- order = fields.Integer(
- string="Sequence",
- readonly=True,
- default=0,
- ) # 在父部门中的次序值。order值大的排序靠前。值范围是[0, 2^32)
-
- # odoo字段
- company_id = fields.Many2one(
- "res.company",
- required=True,
- domain="[('is_wecom_organization', '=', True)]",
- copy=False,
- store=True,
- )
- parent_id = fields.Many2one(
- "wecom.department",
- string="Parent Department",
- index=True,
- domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]",
- store=True,
- compute="_compute_parent_id",
- )
- child_ids = fields.One2many(
- "wecom.department", "parentid", string="Child Departments"
- )
-
- complete_name = fields.Char(
- "Complete Name", compute="_compute_complete_name", recursive=True, store=True
- )
- department_leader = fields.Char(string="Department Leader", readonly=True, default="[]")
- department_leader_ids = fields.Many2many(
- "wecom.user",
- "user_department_rel",
- "tag_id",
- "user_id",
- string="Department Leader",
- )
- user_ids = fields.Many2many(
- "wecom.user",
- "wecom_user_department_rel",
- "department_id",
- "user_id",
- string="Members",
- )
- tag_ids = fields.Many2many("wecom.tag","wecom_department_tag_rel","wecom_department_id","wecom_tag_id",string="Tags",)
- color = fields.Integer("Color Index")
-
- department_json = fields.Json(string="Department Json", readonly=True)
-
- @api.depends("department_id", "company_id")
- def _compute_name(self):
- for department in self:
- if not department.name: # type: ignore
- department.name = "%s:%s" % ( # type: ignore
- department.company_id.name, # type: ignore
- department.department_id, # type: ignore
- )
-
- @api.depends("parentid", "company_id")
- def _compute_parent_id(self):
- for department in self:
- if department.parentid: # type: ignore
- parent_department = self.sudo().search(
- [
- ("department_id", "=", department.parentid), # type: ignore
- ("company_id", "=", department.company_id.id), # type: ignore
- ]
- )
- department.parent_id = parent_department.id # type: ignore
-
- @api.depends("name", "parent_id", "company_id")
- def _compute_complete_name(self):
- for department in self:
- if department.parent_id: # type: ignore
- department.complete_name = "%s / %s" % ( # type: ignore
- department.parent_id.complete_name, # type: ignore
- department.name, # type: ignore
- )
- else:
- department.complete_name = department.name # type: ignore
-
- # @api.onchange('parent_id')
- # def _onchange_parentid(self):
- # for department in self:
- # if department.parent_id:
- # department.complete_name = "%s / %s" % (
- # department.parent_id.complete_name,
- # department.name,
- # )
-
- # ------------------------------------------------------------
- # 企微部门下载
- # ------------------------------------------------------------
- @api.model
- def download_wecom_deps(self):
- """
- 下载部门列表
- """
- start_time = time.time()
-
- company = self.env.context.get("company_id")
- if type(company) == int:
- company = self.env["res.company"].browse(company)
-
- tasks = []
-
- try:
- wxapi = self.env["wecom.service_api"].InitServiceApi(
- company.corpid, company.contacts_sync_app_id.secret
- ) # 使用自建应用
-
- # 2023-08-24 使用自建应用获取数据
- response = wxapi.httpCall(
- self.env["wecom.service_api_list"].get_server_api_call(
- "DEPARTMENT_LIST"
- ),
- )
- except ApiException as ex:
- end_time = time.time()
- self.env["wecomapi.tools.action"].ApiExceptionDialog(
- str(ex), raise_exception=False
- )
- tasks = [
- {
- "name": "download_department_data",
- "state": False,
- "time": end_time - start_time,
- "msg": str(ex),
- }
- ]
- except Exception as e:
- end_time = time.time()
- tasks = [
- {
- "name": "download_department_data",
- "state": False,
- "time": end_time - start_time,
- "msg": str(e),
- }
- ]
- else:
- if response["errcode"] == 0:
- wecom_departments = response["department"]
-
- # 1.下载部门
- for wecom_department in wecom_departments:
- download_department_result = self.download_department(
- company, wecom_department
- )
- if download_department_result:
- for r in download_department_result:
- tasks.append(r) # 加入 下载部门失败结果
-
- # 3.完成
- end_time = time.time()
- task = {
- "name": "download_department_data",
- "state": True,
- "time": end_time - start_time,
- "msg": _("Department list sync completed."),
- }
- tasks.append(task)
- finally:
- return tasks # 返回结果
-
- def download_department(self, company, wecom_department):
- """
- 下载部门
- """
- # 查询数据库是否存在相同的企业微信部门ID,有则更新,无则新建
- department = self.sudo().search(
- [
- ("department_id", "=", wecom_department["id"]),
- ("company_id", "=", company.id),
- ],
- limit=1,
- )
-
- result = {}
-
- if not department:
- result = self.create_department(company, department, wecom_department)
- else:
- result = self.update_department(company, department, wecom_department)
-
-
- return result
-
- def create_department(self, company, department, wecom_department):
- """
- 创建部门
- """
- try:
- department.create(
- {
- "name": wecom_department["name"],
- "department_id": wecom_department["id"],
- "parentid": wecom_department["parentid"],
- "order": wecom_department["order"],
- "department_leader": wecom_department["department_leader"],
- "department_json": wecom_department,
- "company_id": company.id,
- }
- )
-
- except Exception as e:
- result = _(
- "Error creating company [%s]'s department [%s], error reason: %s"
- ) % (
- company.name,
- wecom_department["id"],
- repr(e),
- )
- _logger.warning(result)
- return {
- "name": "add_department",
- "state": False,
- "time": 0,
- "msg": result,
- }
-
-
- def update_department(self, company, department, wecom_department):
- """
- 更新部门
- """
- try:
- department.write(
- {
- "name": wecom_department["name"],
- "parentid": wecom_department["parentid"],
- "order": wecom_department["order"],
- "department_leader": wecom_department["department_leader"],
- "department_json": wecom_department,
- }
- )
- except Exception as e:
- result = _("Error updating Department [%s], error details:%s") % (
- wecom_department["name"],
- str(e),
- )
- result = _(
- "Error update company [%s]'s Department [%s], error reason: %s"
- ) % (
- company.name,
- wecom_department["id"],
- repr(e),
- )
- _logger.warning(result)
- return {
- "name": "update_department",
- "state": False,
- "time": 0,
- "msg": result,
- }
-
-
- def set_parent_department(self, company):
- """[summary]
- 由于json数据是无序的,故在同步到本地数据库后,需要设置新增企业微信部门的上级部门
- """
- params = self.env["ir.config_parameter"].sudo()
- debug = params.get_param("wecom.debug_enabled")
-
- departments = self.search([("company_id", "=", company.id)])
-
- results = []
- for department in departments: # type: ignore
- if department.parentid and department.parentid != 0:
- # 忽略 parentid 为 0的部门
- parent_department = self.get_parent_department_by_department_id(
- department, company
- )
-
- try:
- department.write(
- {
- "parent_id": parent_department.id, # type: ignore
- }
- )
- except Exception as e:
- result = _(
- "Error setting parent department for company [%s], Error details:%s"
- ) % (company.name, repr(e))
- if debug:
- _logger.warning(result)
- results.append(
- {
- "name": "set_parent_department",
- "state": False,
- "time": 0,
- "msg": result,
- }
- )
- return results # 返回失败的结果
-
- def get_parent_department_by_department_id(self, department, company):
- """[summary]
- 通过企微部门id 获取上级部门
- Args:
- department ([type]): [description]
- departments ([type]): [descriptions]
- """
- parent_department = self.search(
- [
- ("department_id", "=", department.parentid),
- ("company_id", "=", company.id),
- ]
- )
- return parent_department
-
- def download_single_department(self):
- """
- 下载单个部门
- """
- company = self.company_id
- params = {}
- message = ""
- try:
- wxapi = self.env["wecom.service_api"].InitServiceApi(
- company.corpid, company.contacts_app_id.secret # type: ignore
- )
- response = wxapi.httpCall(
- self.env["wecom.service_api_list"].get_server_api_call(
- "DEPARTMENT_DETAILS"
- ),
- {"id": str(self.department_id)},
- )
- department = response["department"]
- for key in department.keys():
- if type(department[key]) in (list, dict) and department[key]:
- json_str = json.dumps(
- department[key],
- sort_keys=False,
- indent=2,
- separators=(",", ":"),
- ensure_ascii=False,
- )
- department[key] = json_str
- self.sudo().write(
- {
- "name": department["name"],
- "name_en": self.env[
- "wecomapi.tools.dictionary"
- ].check_dictionary_keywords(department, "name_en"),
- "department_leader": department["department_leader"],
- "parentid": department["parentid"],
- "order": department["order"],
- }
- )
- except ApiException as ex:
- message = _("Department [id:%s, name:%s] failed to download,Reason: %s") % (
- self.department_id,
- self.name,
- str(ex),
- )
- _logger.warning(message)
- params = {
- "title": _("Download failed!"),
- "message": message,
- "sticky": True, # 延时关闭
- "className": "bg-danger",
- "type": "danger",
- }
- except Exception as e:
- message = _("Department [id:%s, name:%s] failed to download,Reason: %s") % (
- self.department_id,
- self.name,
- str(e),
- )
- _logger.warning(message)
- params = {
- "title": _("Download failed!"),
- "message": message,
- "sticky": True, # 延时关闭
- "className": "bg-danger",
- "type": "danger",
- }
- else:
- message = _("Department [id:%s, name:%s] downloaded successfully") % (
- self.department_id,
- self.name,
- )
- params = {
- "title": _("Download Success!"),
- "message": message,
- "sticky": False, # 延时关闭
- "className": "bg-success",
- "type": "success",
- "next": {
- "type": "ir.actions.client",
- "tag": "reload",
- }, # 刷新窗体
- }
- finally:
- action = {
- "type": "ir.actions.client",
- "tag": "display_notification",
- "params": params,
- }
- return action
-
- # ------------------------------------------------------------
- # 企微通讯录事件
- # ------------------------------------------------------------
- def wecom_event_change_contact_party(self, cmd):
- xml_tree = self.env.context.get("xml_tree")
- company_id = self.env.context.get("company_id")
- department_dict = xmltodict.parse(xml_tree)["xml"]
-
- departments = self.sudo().search([("company_id", "=", company_id.id)])
- callback_department = departments.search( # type: ignore
- [("department_id", "=", department_dict["Id"])],
- limit=1,
- )
- update_dict = {}
-
- for key, value in department_dict.items():
- if key.lower() in self._fields.keys(): # type: ignore
- update_dict.update({key.lower(): value})
- else:
- if key == "Id":
- update_dict.update({"department_id": value})
-
- if "parentid" in update_dict:
- parent_id = departments.search( # type: ignore
- [("department_id", "=", update_dict["parentid"])],
- limit=1,
- ).id # type: ignore
- update_dict.update({"parent_id": parent_id})
-
- if cmd == "create":
- callback_department.create(update_dict) # type: ignore
- elif cmd == "update":
- if "department_id" in update_dict:
- del update_dict["department_id"]
- callback_department.write(update_dict) # type: ignore
- elif cmd == "delete":
- callback_department.unlink() # type: ignore
diff --git a/wecom_contacts_sync/models/wecom_tag.py b/wecom_contacts_sync/models/wecom_tag.py
deleted file mode 100644
index db672980e..000000000
--- a/wecom_contacts_sync/models/wecom_tag.py
+++ /dev/null
@@ -1,481 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import logging
-import json
-import time
-from odoo import fields, models, api, Command, tools, _
-from odoo.exceptions import UserError
-import xmltodict
-from odoo.addons.wecom_api.api.wecom_abstract_api import ApiException # type: ignore
-from odoo.addons.base.models.ir_mail_server import MailDeliveryException
-
-_logger = logging.getLogger(__name__)
-
-
-class WecomTag(models.Model):
- _name = "wecom.tag"
- _description = "Wecom tag"
-
- company_id = fields.Many2one(
- "res.company",
- required=True,
- domain="[('is_wecom_organization', '=', True)]",
- copy=False,
- store=True,
- )
-
- name = fields.Char(string="Name", readonly=True, compute="_compute_name") # 标签名称
- tagid = fields.Integer(
- string="Tag ID",
- readonly=True,
- default="0",
- ) # 标签id
- tagname = fields.Char(string="Tag name", readonly=True, default="") # 标签名称
- userlist = fields.Text(
- string="User list", readonly=True, default="[]"
- ) # 标签中包含的成员列表
- partylist = fields.Text(
- string="Party list", readonly=True, default="[]"
- ) # 标签中包含的部门id列表
-
- # odoo 字段
- user_ids = fields.Many2many(
- "wecom.user",
- "wecom_user_tag_rel",
- "wecom_tag_id",
- "wecom_user_id",
- string="Members",compute="_compute_user_ids",
- )
-
- department_ids = fields.Many2many("wecom.department","wecom_department_tag_rel","wecom_tag_id","wecom_department_id",string="Departments",compute="_compute_department_ids",)
-
- tag_json = fields.Json(string="Tag Json", readonly=True)
-
- def _compute_name(self):
- for tag in self:
- tag.name = tag.tagname # type: ignore
-
- @api.depends("userlist")
- def _compute_user_ids(self):
- """
- 计算用户 eval( )
- """
- for tag in self:
- users = eval(tag.userlist) # type: ignore
- user_ids = []
- for user in users:
- user_id = self.env["wecom.user"].search(
- [("userid", "=", user)],limit=1,
- )
- if user_id:
- user_ids.append(user_id.id)
- tag.write({"user_ids": [(6, 0, user_ids)]})
-
- @api.depends("partylist")
- def _compute_department_ids(self):
- """
- 计算部门 eval( )
- """
- for tag in self:
- departments = eval(tag.partylist) # type: ignore
- department_ids = []
- for department in departments:
- department_id = self.env["wecom.department"].search(
- [("department_id", "=", department)],limit=1,
- )
- if department_id:
- department_ids.append(department_id.id)
- tag.write({"department_ids": [(6, 0, department_ids)]})
-
-
- # ------------------------------------------------------------
- # 企微标签下载
- # ------------------------------------------------------------
- @api.model
- def download_wecom_tags(self):
- """
- 下载标签列表
- """
- start_time = time.time()
- company = self.env.context.get("company_id")
- if type(company) == int:
- company = self.env["res.company"].browse(company)
- tasks = []
-
- try:
- wxapi = self.env["wecom.service_api"].InitServiceApi(
- company.corpid, company.contacts_sync_app_id.secret
- )
- response = wxapi.httpCall(
- self.env["wecom.service_api_list"].get_server_api_call("TAG_GET_LIST")
- )
-
- except ApiException as ex:
- end_time = time.time()
- self.env["wecomapi.tools.action"].ApiExceptionDialog(
- ex, raise_exception=False
- )
- tasks = [
- {
- "name": "download_tag_data",
- "state": False,
- "time": end_time - start_time,
- "msg": str(ex),
- }
- ]
- except Exception as e:
- end_time = time.time()
-
- tasks = [
- {
- "name": "download_tag_data",
- "state": False,
- "time": end_time - start_time,
- "msg": str(e),
- }
- ]
- else:
- if response["errcode"] == 0:
- wecom_tags = response["taglist"] # 列表类型数据
-
- # 下载标签
- for wecom_tag in wecom_tags:
- download_tag_result = self.download_tag(company, wecom_tag)
- if download_tag_result:
- for r in download_tag_result:
- tasks.append(r) # 加入 下载标签失败结果
- end_time = time.time()
- task = {
- "name": "download_tag_data",
- "state": True,
- "time": end_time - start_time,
- "msg": _("Tag list sync completed."),
- }
- tasks.append(task)
- finally:
- return tasks # 返回结果
-
- def download_tag(self, company, wecom_tag):
- """
- 下载标签
- """
- tag = self.sudo().search(
- [
- ("tagid", "=", wecom_tag["tagid"]),
- ("company_id", "=", company.id),
- ],
- limit=1,
- )
- result = {}
- try:
- wxapi = self.env["wecom.service_api"].InitServiceApi(
- company.corpid, company.contacts_app_id.secret
- )
-
- response = wxapi.httpCall(
- self.env["wecom.service_api_list"].get_server_api_call(
- "TAG_GET_MEMBER"
- ),
- {"tagid": str(wecom_tag["tagid"])},
- )
- response["userlist"] = [user["userid"] for user in response["userlist"]]
- wecom_tag.update(
- {
- "userlist": self.env[
- "wecomapi.tools.dictionary"
- ].check_dictionary_keywords(response, "userlist"),
- "partylist": self.env[
- "wecomapi.tools.dictionary"
- ].check_dictionary_keywords(response, "partylist"),
- }
- )
-
- except ApiException as ex:
- result = _(
- "Wecom API acquisition company[%s]'s tag [id:%s] member failed, error details: %s"
- ) % (company.name, wecom_tag["tagid"], str(ex))
- _logger.warning(result)
- except Exception as e:
- result = _(
- "Wecom API acquisition company[%s]'s tag [id:%s] member failed, error details: %s"
- ) % (company.name, wecom_tag["tagid"], str(e))
- _logger.warning(result)
- else:
- for key in wecom_tag.keys():
- if type(wecom_tag[key]) in (list, dict) and wecom_tag[key]:
- json_str = json.dumps(
- wecom_tag[key],
- sort_keys=False,
- indent=2,
- separators=(",", ":"),
- ensure_ascii=False,
- )
- wecom_tag[key] = json_str
- if not tag:
- result = self.create_tag(company, tag, wecom_tag,response)
- else:
- result = self.update_tag(company, tag, wecom_tag,response)
- finally:
- return result
-
- def create_tag(self, company, tag, wecom_tag,response):
- """
- 创建标签
- """
- try:
- tag.create(
- {
- "tagname": wecom_tag["tagname"],
- "tagid": wecom_tag["tagid"],
- "userlist": wecom_tag["userlist"],
- "partylist": wecom_tag["partylist"],
- "tag_json": response,
- "company_id": company.id,
- }
- )
- except Exception as e:
- result = _("Error creating company [%s]'s tag [%s], error reason: %s") % (
- company.name,
- wecom_tag["tagname"],
- repr(e),
- )
-
- _logger.warning(result)
- return {
- "name": "add_tag",
- "state": False,
- "time": 0,
- "msg": result,
- } # 返回失败结果
-
- def update_tag(self, company, tag, wecom_tag,response):
- """
- 更新标签
- """
- try:
- # print(wecom_tag,type(wecom_tag))
- tag.write(
- {
- "tagname": wecom_tag["tagname"],
- "userlist": wecom_tag["userlist"],
- "partylist": wecom_tag["partylist"],
- "tag_json": response,
- }
- )
- except Exception as e:
- result = _("Error update company [%s]'s tag [%s], error reason: %s") % (
- company.name,
- wecom_tag["tagname"],
- repr(e),
- )
-
- _logger.warning(result)
- return {
- "name": "update_tag",
- "state": False,
- "time": 0,
- "msg": result,
- } # 返回失败结果
-
- def download_single_tag(self):
- """
- 下载单个标签
- """
- company = self.company_id
- params = {}
- message = ""
- try:
- wxapi = self.env["wecom.service_api"].InitServiceApi(
- company.corpid, company.contacts_app_id.secret # type: ignore
- )
- response = wxapi.httpCall(
- self.env["wecom.service_api_list"].get_server_api_call(
- "TAG_GET_MEMBER"
- ),
- {"tagid": str(self.tagid)},
- )
-
- response["userlist"] = [user["userid"] for user in response["userlist"]]
- for key in response.keys():
- if type(response[key]) in (list, dict) and response[key]:
- json_str = json.dumps(
- response[key],
- sort_keys=False,
- indent=2,
- separators=(",", ":"),
- ensure_ascii=False,
- )
- response[key] = json_str
- self.write(
- {
- "tagname": response["tagname"],
- "userlist": response["userlist"],
- "partylist": response["partylist"],
- }
- )
- except ApiException as ex:
- message = _("Tag [id:%s, name:%s] failed to download,Reason: %s") % (
- self.tagid,
- self.tagname,
- str(ex),
- )
- _logger.warning(message)
- params = {
- "title": _("Download failed!"),
- "message": message,
- "sticky": True, # 延时关闭
- "className": "bg-danger",
- "type": "danger",
- }
- except Exception as e:
- message = _("Tag [id:%s, name:%s] failed to download,Reason: %s") % (
- self.tagid,
- self.tagname,
- str(e),
- )
- _logger.warning(message)
- params = {
- "title": _("Download failed!"),
- "message": message,
- "sticky": True, # 延时关闭
- "className": "bg-danger",
- "type": "danger",
- }
- else:
- message = _("Tag [id:%s, name:%s] downloaded successfully") % (
- self.tagid,
- self.tagname,
- )
- params = {
- "title": _("Download Success!"),
- "message": message,
- "sticky": False, # 延时关闭
- "className": "bg-success",
- "type": "success",
- "next": {
- "type": "ir.actions.client",
- "tag": "reload",
- }, # 刷新窗体
- }
- finally:
- action = {
- "type": "ir.actions.client",
- "tag": "display_notification",
- "params": params,
- }
- return action # 返回结果
-
- # ------------------------------------------------------------
- # 企微通讯录事件
- # ------------------------------------------------------------
- def wecom_event_change_contact_tag(self, cmd):
- """
- 通讯录事件更新标签
- """
- xml_tree = self.env.context.get("xml_tree")
- company_id = self.env.context.get("company_id")
- tag_dict = xmltodict.parse(xml_tree)["xml"]
-
- tags = self.sudo().search([("company_id", "=", company_id.id)])
- callback_tag = tags.search( # type: ignore
- [("tagid", "=", tag_dict["TagId"])],
- limit=1,
- )
-
- update_dict = {}
-
- for key, value in tag_dict.items():
- if key.lower() in self._fields.keys(): # type: ignore
- update_dict.update({key.lower(): value})
- else:
- if key == "AddUserItems":
- # 标签中新增的成员userid列表,用逗号分隔
- update_dict.update({"add_users": value})
- if key == "DelUserItems":
- # 标签中删除的成员userid列表,用逗号分隔
- update_dict.update({"del_users": value})
- if key == "AddPartyItems":
- # 标签中新增的部门id列表,用逗号分隔
- update_dict.update({"add_departments": value})
- if key == "DelPartyItems":
- # 标签中删除的部门id列表,用逗号分隔
- update_dict.update({"del_departments": value})
-
- if callback_tag:
- userlist = json.loads(callback_tag.userlist) # type: ignore
- partylist = json.loads(callback_tag.partylist) # type: ignore
-
- if "add_users" in update_dict:
- # 需要增加的成员
- userids = update_dict["add_users"].split(",")
- add_users_set = self.env["wecomapi.tools.data"].difference_data_set(
- set(userids), set(userlist)
- )
- add_users = list(add_users_set)
-
- for userid in add_users:
- userlist.append(userid)
-
- del update_dict["add_users"]
-
- if "del_users" in update_dict:
- # 需要删除的成员
- userids = update_dict["del_users"].split(",")
- del_users_set = self.env["wecomapi.tools.data"].intersection_data_set(
- set(userlist), set(userids)
- )
- del_users = list(del_users_set)
-
- for user in del_users:
- if user in userlist:
- userlist.remove(user)
-
- del update_dict["del_users"]
-
- if "add_departments" in update_dict:
- # 需要增加的部门
- department_ids = update_dict["add_departments"].split(",")
- add_departments_set = self.env[
- "wecomapi.tools.data"
- ].difference_data_set(set(department_ids), set(partylist))
- add_departments = list(add_departments_set)
- for department_id in add_departments:
- partylist.append(department_id)
-
- del update_dict["add_departments"]
-
- if "del_departments" in update_dict:
- # 需要删除的部门
- department_ids = update_dict["del_departments"].split(",")
- del_departments_set = self.env[
- "wecomapi.tools.data"
- ].intersection_data_set(set(department_ids), set(partylist))
- del_departments = list(del_departments_set)
-
- for department in del_departments:
- if department in partylist:
- partylist.remove(department)
-
- del update_dict["del_departments"]
-
- update_dict.update(
- {
- "userlist": json.dumps(
- userlist,
- sort_keys=False,
- indent=2,
- separators=(",", ":"),
- ensure_ascii=False,
- ),
- "partylist": json.dumps(
- partylist,
- sort_keys=False,
- indent=2,
- separators=(",", ":"),
- ensure_ascii=False,
- ),
- }
- )
-
- del update_dict["tagid"]
- callback_tag.write(update_dict) # type: ignore
diff --git a/wecom_contacts_sync/models/wecom_user.py b/wecom_contacts_sync/models/wecom_user.py
deleted file mode 100644
index e29668a5a..000000000
--- a/wecom_contacts_sync/models/wecom_user.py
+++ /dev/null
@@ -1,783 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import re
-import logging
-import json
-from collections import defaultdict
-import time
-from odoo import fields, models, api, Command, tools, _
-from odoo.exceptions import UserError
-import xmltodict
-from odoo.addons.wecom_api.api.wecom_abstract_api import ApiException # type: ignore
-from odoo.addons.base.models.ir_mail_server import MailDeliveryException
-import ast
-
-import re
-
-LEADER_REGEX = re.compile(r"['(.*?)']")
-
-_logger = logging.getLogger(__name__)
-
-
-class WecomUser(models.Model):
- _name = "wecom.user"
- _description = "Wecom user"
- _order = "order_in_department"
-
- # 企微字段
- userid = fields.Char(
- string="User ID",
- readonly=True,
- default="",
- ) # 成员UserID。对应管理端的帐号
- name = fields.Char(string="Name", readonly=True, default="") # 成员名称
- english_name = fields.Char(
- string="English name", readonly=True, default=""
- ) # 英部门文名称
- mobile = fields.Char(string="mobile phone", readonly=True, default="") # 手机号码
- department = fields.Char(
- string="Multiple Department ID", readonly=True, store=True, default="[]"
- ) # 成员所属部门id列表
-
- main_department = fields.Integer(
- string="Main department", readonly=True, default=0
- ) # 主部门
- order = fields.Char(
- string="Sequence", readonly=True, default="[]"
- ) # 部门内的排序值,默认为0。数量必须和department一致,数值越大排序越前面。值范围是[0, 2^32)
- position = fields.Char(string="Position", readonly=True, default="") # 职务信息;
- gender = fields.Char(
- string="Gender", readonly=True, default=""
- ) # 性别。0表示未定义,1表示男性,2表示女性。
- email = fields.Char(string="Email", readonly=True, default="") # 邮箱
- biz_mail = fields.Char(string="BizMail", readonly=True, default="") # 企业邮箱
- is_leader_in_dept = fields.Char(
- string="Is Department Leader", readonly=True, default="[]"
- ) # 表示在所在的部门内是否为部门负责人。0-否;1-是。是一个列表,数量必须与department一致。
-
- direct_leader = fields.Char(
- string="Direct Leader", readonly=True, default="[]"
- ) # 直属上级UserID,返回在应用可见范围内的直属上级列表,最多有五个直属上级
-
- avatar = fields.Char(string="Avatar", readonly=True, default="") # 头像url
- thumb_avatar = fields.Char(
- string="Avatar thumbnail", readonly=True, default=""
- ) # 头像缩略图url
- telephone = fields.Char(string="Telephone", readonly=True, default="") # 座机号码
- alias = fields.Char(string="Alias", readonly=True, default="") # 别名
- extattr = fields.Text(
- string="Extended attributes", readonly=True, default=""
- ) # 扩展属性
- external_profile = fields.Text(
- string="External attributes", readonly=True, default=""
- ) # 成员对外属性
- external_position = fields.Char(
- string="External position", readonly=True, default=""
- ) # 对外职务,如果设置了该值,则以此作为对外展示的职务,否则以position来展示。
- enable = fields.Boolean(
- string="Enable", readonly=True, default=True
- ) # 启用/禁用成员。1表示启用成员,0表示禁用成员
- isleader = fields.Boolean(
- string="Is leader", readonly=True, default=False
- ) # 上级字段,标识是否为上级。第三方仅通讯录应用可获取
- hide_mobile = fields.Boolean(
- string="Hide mobile", readonly=True, default=False
- ) # 是否隐藏手机号
- status = fields.Integer(
- string="Status", readonly=True, default=""
- ) # 激活状态: status 1=已激活,2=已禁用,4=未激活,5=退出企业。已激活代表已激活企业微信或已关注微信插件(原企业号)。未激活代表既未激活企业微信又未关注微信插件(原企业号)。
- qr_code = fields.Char(
- string="Personal QR code", readonly=True, default=""
- ) # 员工个人二维码,扫描可添加为外部联系人
- address = fields.Char(string="Address", readonly=True, default="") # 地址
- open_userid = fields.Char(
- string="Open userid", readonly=True, default=None
- ) # 开放用户Id,全局唯一,对于同一个服务商,不同应用获取到企业内同一个成员的open_userid是相同的,最多64个字节。仅第三方应用可获取
- user_json = fields.Json(string="User Json", readonly=True) #
-
- # odoo 字段
- company_id = fields.Many2one(
- "res.company",
- required=True,
- domain="[('is_wecom_organization', '=', True)]",
- copy=False,
- store=True,
- readonly=True,
- )
- department_id = fields.Many2one(
- "wecom.department",
- "Main Department",
- domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]",
- compute="_compute_department_id",
- store=True,
- )
- department_ids = fields.Many2many(
- "wecom.department",
- "wecom_user_department_rel",
- "user_id",
- "department_id",
- string="Multiple Departments",
- readonly=True,
- compute="_compute_department_ids",
- )
-
- department_leader = fields.Char(
- string="Department Leader",
- default="",
- compute="_compute_department_leader",
- store=True,
- ) # 部门领导 readonly=True,
-
- direct_leader_id = fields.Many2one(
- "wecom.user",
- "Direct Leader",
- domain="[('company_id', '=', company_id)]",
- compute="_compute_direct_leader_id",
- store=True,
- ) #
-
- tag_ids = fields.Many2many(
- "wecom.tag",
- "wecom_user_tag_rel",
- "wecom_user_id",
- "wecom_tag_id",
- string="Tags",
- )
-
- department_complete_name = fields.Char(
- string="Department complete Name", related="department_id.complete_name"
- )
- order_in_department = fields.Integer(
- string="Sequence in department",
- readonly=True,
- default="0",
- ) # 成员在对应部门中的排序值,默认为0。数量必须和department一致
- status_name = fields.Selection(
- [
- ("1", _("Activated")),
- ("2", _("Disabled")),
- ("4", _("Not active")),
- ("5", _("Exit the enterprise")),
- ],
- string="Status",
- readonly=True,
- compute="_compute_status_name",
- ) # 激活状态: 1=已激活,2=已禁用,4=未激活,5=退出企业。已激活代表已激活企业微信或已关注微信插件(原企业号)。未激活代表既未激活企业微信又未关注微信插件(原企业号)。 ,
-
- gender_name = fields.Selection(
- [("1", _("Male")), ("2", _("Female")), ("0", _("Undefined"))],
- string="Gender",
- ) # compute="_compute_gender_name",
- color = fields.Integer("Color Index")
- active = fields.Boolean(
- "Active",
- default=True,
- store=True,
- readonly=True,
- ) # compute="_compute_active",
-
- @api.depends("status")
- def _compute_status_name(self):
- for user in self:
- user.status_name = str(user.status) # type: ignore
-
- @api.depends("status")
- def _compute_active(self):
- for user in self:
- if user.status == 1: # type: ignore
- user.active = True # type: ignore
- else:
- user.active = False # type: ignore
-
- @api.depends("main_department")
- def _compute_department_id(self):
- for user in self:
- department_id = self.env["wecom.department"].search(
- [
- ("department_id", "=", user.main_department),
- ("company_id", "=", user.company_id.id),
- ],
- limit=1,
- ) # type: ignore
- if department_id:
- user.department_id = department_id # type: ignore
-
- @api.depends("gender")
- def _compute_gender_name(self):
- for user in self:
- user.gender_name = str(user.gender) # type: ignore
-
- @api.depends("department")
- def _compute_department_ids(self):
- """
- 计算多部门 ast.literal_eval( )
- """
- for user in self:
- department_list = ast.literal_eval(user.department) # type: ignore
- department_ids = self.get_parent_department(
- user.company_id, department_list # type: ignore
- )
- user.write({"department_ids": [(6, 0, department_ids)]})
-
- @api.depends("department", "is_leader_in_dept", "isleader")
- def _compute_department_leader(self):
- """
- 计算多部门的领导
- """
- for user in self:
- department_list = user.department.strip("[") # type: ignore
- department_list = department_list.strip("]") # type: ignore
- if "," in department_list:
- department_list = department_list.split(",")
-
- leader_list = user.is_leader_in_dept.replace(" ", "").strip("[") # type: ignore
- leader_list = leader_list.strip("]")
- if "," in leader_list:
- leader_list = leader_list.split(",")
-
- if user.isleader: # type: ignore
- department_leader = ""
- for index, department in enumerate(department_list):
- department_id = self.env["wecom.department"].search(
- [
- ("department_id", "=", int(department)),
- ("company_id", "=", user.company_id.id),
- ],
- limit=1,
- ) # type: ignore
-
- is_leader = _("No")
- if leader_list[index] == "1":
- is_leader = _("Yes")
- department_leader_str = _("Department head [%s]: %s ;") % (
- department_id.name,
- is_leader,
- )
- # if len(department_list) > 1 and (index < len(department_list) -1) :
- # department_leader_str += "\n"
- department_leader += department_leader_str
-
- user.department_leader = department_leader # type: ignore
- else:
- user.department_leader = "" # type: ignore
-
- @api.depends("direct_leader")
- def _compute_direct_leader_id(self):
- """
- 计算直属上级
- """
- for user in self:
- user_id = self.env["wecom.user"].search(
- [
- ("userid", "=", user.direct_leader),
- ("company_id", "=", user.company_id.id),
- ],
- limit=1,
- ) # type: ignore
- # print(user_id)
- if user_id:
- user.direct_leader_id = user_id # type: ignore
-
- def get_parent_department(self, company, departments):
- """
- 获取上级部门
- """
- department_ids = []
- for department in departments:
- department_id = self.env["wecom.department"].search(
- [
- ("department_id", "=", department),
- ("company_id", "=", company.id),
- ],
- limit=1,
- )
- if department_id:
- department_ids.append(department_id.id)
- return department_ids
-
- def copy_as_system_user(self):
- """
- 复制为系统用户
- """
- app_config = self.env["wecom.app_config"].sudo()
- contacts_allow_add_system_users = app_config.get_param(
- self.company_id.contacts_sync_app_id.id, "contacts_allow_add_system_users" # type: ignore
- ) # 允许创建用户
- print(contacts_allow_add_system_users, type(contacts_allow_add_system_users))
-
- if contacts_allow_add_system_users:
- # 允许 通讯录 生成系统用户
- login = tools.ustr(self.userid)
- domain = [
- ("wecom_userid", "=", login),
- "|",
- ("active", "=", True),
- ("active", "=", False),
- ]
- user = self.env["res.users"].search(domain, limit=1)
- if not user:
- # 不存在系统用户,则创建系统用户
-
- group_portal_id = self.env["ir.model.data"]._xmlid_to_res_id(
- "base.group_portal"
- ) # 门户用户组
- user.create(
- {
- "name": self.name if self.name else login,
- "login": login,
- "groups_id": [(6, 0, [group_portal_id])],
- "share": False,
- "active": True if self.status == 1 else False,
- # "image_1920": self.avatar,
- "company_id": self.company_id.id, # type: ignore
- # 以下为企业微信字段
- "wecom_userid": login,
- "wecom_openid": self.open_userid,
- "is_wecom_user": True,
- "qr_code": self.qr_code,
- "wecom_user_order": self.order,
- }
- )
- else:
- # 不允许 通讯录 生成系统用户
- msg = {
- "title": _("Error!"),
- "message": _(
- "The current configuration does not allow replication as a system user!"
- ),
- "sticky": False,
- }
- return self.env["wecomapi.tools.action"].WecomWarningNotification(msg)
-
- def copy_as_employee(self):
- """
- 复制为员工
- """
-
- # ------------------------------------------------------------
- # 企微用户下载
- # ------------------------------------------------------------
- @api.model
- def download_wecom_users(self):
- """
- 下载用户列表
- """
- start_time = time.time()
-
- company = self.env.context.get("company_id")
- if type(company) == int:
- company = self.env["res.company"].browse(company)
-
- app_config = self.env["wecom.app_config"].sudo()
- contacts_sync_hr_department_id = "1" # 需要同步的企业微信部门ID
- sync_hr_department_id = app_config.get_param(
- company.contacts_sync_app_id.id, "contacts_sync_hr_department_id"
- )
- if sync_hr_department_id:
- contacts_sync_hr_department_id = sync_hr_department_id
- tasks = []
- try:
- wxapi = self.env["wecom.service_api"].InitServiceApi(
- company.corpid, company.contacts_sync_app_id.secret
- )
-
- # ----------------------------------------------
- # 2023-8-24 使用自建应用获取成员列表
- # 参数:
- # department_id: 需要获取成员的部门id
- # fetch_child: 1/0:是否递归获取子部门下面的成员
- # ----------------------------------------------
- response = wxapi.httpCall(
- self.env["wecom.service_api_list"].get_server_api_call("USER_LIST"),
- {
- "department_id": contacts_sync_hr_department_id,
- "fetch_child": "1",
- },
- )
- except ApiException as ex:
- end_time = time.time()
-
- self.env["wecomapi.tools.action"].ApiExceptionDialog(
- str(ex), raise_exception=False
- )
- tasks = [
- {
- "name": "download_user_data",
- "state": False,
- "time": end_time - start_time,
- "msg": str(ex),
- }
- ]
- except Exception as e:
- end_time = time.time()
- tasks = [
- {
- "name": "download_user_data",
- "state": False,
- "time": end_time - start_time,
- "msg": str(e),
- }
- ]
- else:
- if response["errcode"] == 0:
- userlist = response["userlist"]
-
- # 1.获取block, 生成 block_list
- blocks = (
- self.env["wecom.contacts.block"]
- .sudo()
- .search(
- [
- ("company_id", "=", company.id),
- ]
- )
- )
-
- block_list = []
- if len(blocks) > 0:
- for obj in blocks:
- if obj.wecom_userid != None:
- # block_list.append({"userid": obj.wecom_userid})
- block_list.append(obj.wecom_userid)
-
- # 从user_list移除block
- for b in block_list:
- for item in userlist:
- # userid不区分大小写
- if item["userid"].lower() == b.lower():
- userlist.remove(item)
-
- # 2.下载用户
- if userlist:
- for wecom_user in userlist:
- download_user_result = self.download_user(company, wecom_user)
- if download_user_result:
- for r in download_user_result:
- tasks.append(r) # 加入 下载员工失败结果
-
- # 3.设置直属上级
-
- # 4.判断企业微信员工list为空,为空跳过同步离职员工
-
- # 3.完成下载
- end_time = time.time()
- task = {
- "name": "download_user_data",
- "state": True,
- "time": end_time - start_time,
- "msg": _("User list sync completed."),
- }
- tasks.append(task)
- finally:
- return tasks # 返回结果
-
- def download_user(self, company, wecom_user):
- """
- 下载用户
- """
- user = self.sudo().search(
- [
- ("userid", "=", wecom_user["userid"].lower()),
- ("company_id", "=", company.id),
- "|",
- ("active", "=", True),
- ("active", "=", False),
- ],
- limit=1,
- )
-
- result = {}
- if not user:
- result = self.create_user(company, user, wecom_user)
- else:
- result = self.update_user(company, user, wecom_user)
- return result
-
- def create_user(self, company, user, wecom_user):
- """
- 创建用户
- """
- try:
- user.create(
- {
- "userid": wecom_user["userid"].lower(),
- "name": wecom_user["name"],
- "department": wecom_user["department"],
- "position": wecom_user["position"],
- "status": wecom_user["status"],
- "enable": True if wecom_user["enable"] == 1 else False,
- "isleader": True if wecom_user["isleader"] == 1 else False,
- "extattr": wecom_user["extattr"],
- "hide_mobile": True if wecom_user["hide_mobile"] == 1 else False,
- "telephone": wecom_user["telephone"],
- "order": wecom_user["order"],
- "external_profile": wecom_user["external_profile"]
- if "external_profile" in wecom_user
- else "",
- "main_department": wecom_user["main_department"],
- "alias": wecom_user["alias"],
- "is_leader_in_dept": wecom_user["is_leader_in_dept"],
- "direct_leader": wecom_user["direct_leader"][0]
- if len(wecom_user["direct_leader"]) > 0
- else wecom_user["direct_leader"],
- "user_json": wecom_user,
- "company_id": company.id,
- }
- )
- except Exception as e:
- result = _("Error creating company [%s]'s user [%s], error reason: %s") % (
- company.userid,
- wecom_user["userid"].lower(),
- repr(e),
- )
-
- _logger.warning(result)
- return {
- "name": "add_user",
- "state": False,
- "time": 0,
- "msg": result,
- }
-
- def update_user(self, company, user, wecom_user):
- """
- 更新用户
- """
- # print(wecom_user["direct_leader"],type(wecom_user["direct_leader"]))
- try:
- user.sudo().write(
- {
- "userid": wecom_user["userid"].lower(),
- "name": wecom_user["name"],
- "department": wecom_user["department"],
- "position": wecom_user["position"],
- "status": wecom_user["status"],
- "enable": True if wecom_user["enable"] == 1 else False,
- "isleader": True if wecom_user["isleader"] == 1 else False,
- "extattr": wecom_user["extattr"],
- "hide_mobile": True if wecom_user["hide_mobile"] == 1 else False,
- "telephone": wecom_user["telephone"],
- "order": wecom_user["order"],
- "external_profile": wecom_user["external_profile"]
- if "external_profile" in wecom_user
- else "",
- "main_department": wecom_user["main_department"],
- "alias": wecom_user["alias"],
- "is_leader_in_dept": wecom_user["is_leader_in_dept"],
- "direct_leader": wecom_user["direct_leader"][0]
- if len(wecom_user["direct_leader"]) > 0
- else wecom_user["direct_leader"],
- "user_json": wecom_user,
- }
- )
-
- except Exception as e:
- result = _("Error update company [%s]'s user [%s], error reason: %s") % (
- company.name,
- wecom_user["userid"].lower(),
- repr(e),
- )
- _logger.warning(result)
- return {
- "name": "update_user",
- "state": False,
- "time": 0,
- "msg": result,
- } # 返回失败结果
-
- def download_single_user(self):
- """
- 下载单个用户
- """
- company = self.company_id
- params = {}
- message = ""
-
- try:
- wxapi = self.env["wecom.service_api"].InitServiceApi(
- company.corpid, company.contacts_sync_app_id.secret # type: ignore
- )
- response = wxapi.httpCall(
- self.env["wecom.service_api_list"].get_server_api_call("USER_GET"),
- {"userid": self.userid},
- )
-
- # for key in response.keys():
- # if type(response[key]) in (list, dict) and response[key]:
- # json_str = json.dumps(
- # response[key],
- # sort_keys=False,
- # indent=2,
- # separators=(",", ":"),
- # ensure_ascii=False,
- # )
- # response[key] = json_str
-
- self.write(
- {
- "name": response["name"],
- "english_name": response["english_name"]
- if "english_name" in response
- else "",
- "mobile": response["mobile"] if "mobile" in response else "",
- "department": response["department"]
- if "department" in response
- else "",
- "main_department": response["main_department"]
- if "main_department" in response
- else 0,
- "order": response["order"] if "order" in response else "[]",
- "position": response["position"] if "position" in response else "",
- "gender": response["gender"] if "gender" in response else "",
- "email": response["email"] if "email" in response else "",
- "biz_mail": response["biz_mail"] if "biz_mail" in response else "",
- "is_leader_in_dept": response["is_leader_in_dept"]
- if "is_leader_in_dept" in response
- else "",
- "direct_leader": response["direct_leader"]
- if "direct_leader" in response
- else "[]",
- "avatar": response["avatar"] if "avatar" in response else "",
- "thumb_avatar": response["thumb_avatar"]
- if "thumb_avatar" in response
- else "",
- "telephone": response["telephone"]
- if "telephone" in response
- else "",
- "alias": response["alias"] if "alias" in response else "",
- "extattr": response["extattr"] if "extattr" in response else "",
- "external_profile": response["external_profile"]
- if "external_profile" in response
- else "",
- "external_position": response["external_position"]
- if "external_position" in response
- else "",
- "status": response["status"],
- "qr_code": response["qr_code"] if "qr_code" in response else "",
- "address": response["address"] if "address" in response else "",
- "open_userid": response["open_userid"]
- if "open_userid" in response
- else "",
- }
- )
- except ApiException as ex:
- message = _("User [id:%s, name:%s] failed to download,Reason: %s") % (
- self.userid,
- self.name,
- str(ex),
- )
- _logger.warning(message)
- params = {
- "title": _("Download failed!"),
- "message": message,
- "sticky": True, # 延时关闭
- "className": "bg-danger",
- "type": "danger",
- }
- else:
- message = _("User [id:%s, name:%s] downloaded successfully") % (
- self.userid,
- self.name,
- )
- params = {
- "title": _("Download Success!"),
- "message": message,
- "sticky": False, # 延时关闭
- "className": "bg-success",
- "type": "success",
- "next": {
- "type": "ir.actions.client",
- "tag": "reload",
- }, # 刷新窗体
- }
- finally:
- action = {
- "type": "ir.actions.client",
- "tag": "display_notification",
- "params": params,
- }
- return action
-
- def get_open_userid(self):
- """
- 获取企微 open_userid
- """
- for user in self:
- try:
- wxapi = self.env["wecom.service_api"].InitServiceApi(
- user.company_id.corpid, # type: ignore
- user.company_id.contacts_sync_app_id.secret, # type: ignore
- )
- response = wxapi.httpCall(
- self.env["wecom.service_api_list"].get_server_api_call(
- "USERID_TO_OPENID"
- ),
- {
- "userid": user.userid, # type: ignore
- },
- )
- except ApiException as ex:
- self.env["wecomapi.tools.action"].ApiExceptionDialog(
- ex, raise_exception=True
- )
- else:
- user.open_userid = response["openid"] # type: ignore
-
- # ------------------------------------------------------------
- # 企微通讯录事件
- # ------------------------------------------------------------
- def wecom_event_change_contact_user(self, cmd):
- """
- 通讯录事件变更成员
- """
- xml_tree = self.env.context.get("xml_tree")
- company_id = self.env.context.get("company_id")
- user_dict = xmltodict.parse(xml_tree)["xml"]
- # print("wecom_event_change_contact_user", user_dict)
- domain = [
- "|",
- ("active", "=", True),
- ("active", "=", False),
- ]
-
- users = self.sudo().search([("company_id", "=", company_id.id)] + domain)
- callback_user = users.search( # type: ignore
- [("userid", "=", user_dict["UserID"])],
- limit=1,
- )
-
- if callback_user:
- # 如果存在,则更新
- # 用于退出企业微信又重新加入企业微信的员工
- cmd = "update"
- else:
- # 如果不存在,停止
- return
-
- update_dict = {}
-
- for key, value in user_dict.items():
- if key.lower() in self._fields.keys(): # type: ignore
- update_dict.update({key.lower(): value})
- else:
- if key == "MainDepartment":
- update_dict.update({"main_department": value})
- elif key == "IsLeaderInDept":
- update_dict.update({"is_leader_in_dept": value})
- elif key == "DirectLeader":
- update_dict.update({"direct_leader": value})
- elif key == "BizMail":
- update_dict.update({"biz_mail": value})
- if cmd == "create":
- update_dict.update({"company_id": company_id.id})
- callback_user.create(update_dict) # type: ignore
- elif cmd == "update":
- if "userid" in update_dict:
- del update_dict["userid"]
- callback_user.write(update_dict) # type: ignore
- elif cmd == "delete":
- callback_user.write( # type: ignore
- {
- "active": False,
- }
- )
diff --git a/wecom_contacts_sync/security/ir.model.access.csv b/wecom_contacts_sync/security/ir.model.access.csv
deleted file mode 100644
index 7977397b7..000000000
--- a/wecom_contacts_sync/security/ir.model.access.csv
+++ /dev/null
@@ -1,12 +0,0 @@
-id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
-
-"access_change_type_wizard","access.change.type.wizard","model_change_type_wizard","wecom_base.group_wecom_settings_manager",1,1,1,0
-"access_change_type_user","access.change.type.user","model_change_type_user","wecom_base.group_wecom_settings_manager",1,1,1,0
-
-"access_wecom_contacts_block","access.wecom.contacts.block","model_wecom_contacts_block","wecom_base.group_wecom_settings_manager",1,1,1,1
-"access_wecom_contacts_sync_wizard","access.wecom.contacts.sync.wizard","model_wecom_contacts_sync_wizard","wecom_base.group_wecom_settings_manager",1,1,1,0
-
-
-"access_wecom_department_right","access.wecom.department","model_wecom_department","wecom_base.group_wecom_settings_manager",1,1,1,1
-"access_wecom_user_right","access.wecom.user","model_wecom_user","wecom_base.group_wecom_settings_manager",1,1,1,1
-"access_wecom_tag_right","access.wecom.tag","model_wecom_tag","wecom_base.group_wecom_settings_manager",1,1,1,1
diff --git a/wecom_contacts_sync/static/description/icon.png b/wecom_contacts_sync/static/description/icon.png
deleted file mode 100644
index d5dad65d7..000000000
Binary files a/wecom_contacts_sync/static/description/icon.png and /dev/null differ
diff --git a/wecom_contacts_sync/views/ir_cron_views.xml b/wecom_contacts_sync/views/ir_cron_views.xml
deleted file mode 100644
index 1dfd11655..000000000
--- a/wecom_contacts_sync/views/ir_cron_views.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
- WeCom: Synchronize contacts regularly
- ir.cron
- form
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_contacts_sync/views/menu_views.xml b/wecom_contacts_sync/views/menu_views.xml
deleted file mode 100644
index 032f02dd2..000000000
--- a/wecom_contacts_sync/views/menu_views.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_contacts_sync/views/res_company_views.xml b/wecom_contacts_sync/views/res_company_views.xml
deleted file mode 100644
index 8d7997f14..000000000
--- a/wecom_contacts_sync/views/res_company_views.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
- res.company.form.inherit.wecom_contacts
- res.company
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_contacts_sync/views/res_config_settings_views.xml b/wecom_contacts_sync/views/res_config_settings_views.xml
deleted file mode 100644
index 0c5f9530c..000000000
--- a/wecom_contacts_sync/views/res_config_settings_views.xml
+++ /dev/null
@@ -1,131 +0,0 @@
-
-
-
-
- Settings
- res.config.settings
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- To synchronize contacts, you need to bind a self-built application.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Application Management→Application→Open the application that needs to be verified and authorized, copy 'AgentId'
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Application Management→Application→Open the application that needs to be verified and authorized, copy 'Secret'
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/wecom_contacts_sync/views/res_users_views.xml b/wecom_contacts_sync/views/res_users_views.xml
deleted file mode 100644
index 7441cac84..000000000
--- a/wecom_contacts_sync/views/res_users_views.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-
-
-
-
-
-
-
- Change user type
- change.type.wizard
-
-
-
-
-
-
-
-
-
- Change Type Users
- change.type.user
-
-
-
-
-
-
-
-
-
-
-
- Change Type
- change.type.wizard
- form
- new
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_contacts_sync/views/wecom_department_views.xml b/wecom_contacts_sync/views/wecom_department_views.xml
deleted file mode 100644
index a0ef91bbf..000000000
--- a/wecom_contacts_sync/views/wecom_department_views.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-
-
-
-
- wecom.department.tree
- wecom.department
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- wecom.department.form
- wecom.department
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Department
- wecom.department
- ir.actions.act_window
- tree,kanban,form
-
-
- {}
-
-
-
-
\ No newline at end of file
diff --git a/wecom_contacts_sync/views/wecom_tag_views.xml b/wecom_contacts_sync/views/wecom_tag_views.xml
deleted file mode 100644
index 64feef243..000000000
--- a/wecom_contacts_sync/views/wecom_tag_views.xml
+++ /dev/null
@@ -1,67 +0,0 @@
-
-
-
-
-
- wecom.tag.tree
- wecom.tag
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- wecom.tag.form
- wecom.tag
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Tag
- wecom.tag
- ir.actions.act_window
- tree,kanban,form
-
-
- {}
-
-
-
-
\ No newline at end of file
diff --git a/wecom_contacts_sync/views/wecom_user_views.xml b/wecom_contacts_sync/views/wecom_user_views.xml
deleted file mode 100644
index b9b18f522..000000000
--- a/wecom_contacts_sync/views/wecom_user_views.xml
+++ /dev/null
@@ -1,233 +0,0 @@
-
-
-
-
-
- wecom.user.search
- wecom.user
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- wecom.user.tree
- wecom.user
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- wecom.user.kanban
- wecom.user
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- wecom.user.form
- wecom.user
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Member
- wecom.user
- ir.actions.act_window
- tree,kanban,form
-
-
- {"active_test": False}
-
-
-
-
\ No newline at end of file
diff --git a/wecom_contacts_sync/wizard/__init__.py b/wecom_contacts_sync/wizard/__init__.py
deleted file mode 100644
index 2dbfc1a9c..000000000
--- a/wecom_contacts_sync/wizard/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from . import wecom_contacts_sync_wizard
diff --git a/wecom_contacts_sync/wizard/wecom_contacts_sync_wizard.py b/wecom_contacts_sync/wizard/wecom_contacts_sync_wizard.py
deleted file mode 100644
index aed2d12f2..000000000
--- a/wecom_contacts_sync/wizard/wecom_contacts_sync_wizard.py
+++ /dev/null
@@ -1,359 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import logging
-from odoo import api, models, fields, _
-from odoo.exceptions import UserError
-
-import pandas as pd
-
-pd.set_option("max_colwidth", 4096) # 设置最大列宽
-pd.set_option("display.max_columns", 30) # 设置最大列数
-pd.set_option("expand_frame_repr", False) # 当列太多时不换行
-import time
-
-_logger = logging.getLogger(__name__)
-
-
-class WecomContactsSyncWizard(models.TransientModel):
- _name = "wecom.contacts.sync.wizard"
- _description = "WeCom contacts synchronization wizard"
-
- @api.model
- def _default_company_ids(self):
- """
- 默认公司
- """
- company_ids = self.env["res.company"].search(
- [
- ("is_wecom_organization", "=", True),
- ]
- )
- return company_ids
-
- def _default_right(self):
- return self.user_has_groups("base.group_multi_company")
-
- def _default_company_id(self):
- company = self.env.user.company_id
- if not company:
- company = self.env.company
- return company
-
- manage_multiple_companies = fields.Boolean(
- string="Manage multiple companies",
- readonly=True,
- default=_default_right,
- )
- sync_all = fields.Boolean(
- string="Synchronize all companies",
- default=False,
- required=True,
- # compute="_compute_sync_all",
- )
- companies = fields.Char(string="Sync Companies", compute="_compute_sync_companies")
- company_id = fields.Many2one(
- "res.company",
- string="Company",
- default=lambda self: self.env.company,
- domain="[('is_wecom_organization', '=', True)]",
- store=True,
- # default=_default_company_id,
- )
-
- @api.depends("manage_multiple_companies")
- def _compute_sync_all(self):
- # 有管理多公司的权限,则默认同步所有公司
- if not self.manage_multiple_companies:
- self.sync_all = False
-
- @api.depends("sync_all")
- def _compute_sync_companies(self):
- """
- 获取需要同步的公司名称
- """
- if self.sync_all:
- companies = (
- self.sudo()
- .env["res.company"]
- .search([(("is_wecom_organization", "=", True))])
- )
- companies_names = [company.name for company in companies]
- self.companies = ",".join(companies_names)
- else:
- self.companies = self.company_id.name # type: ignore
-
- @api.onchange("company_id")
- def onchange_company_id(self):
- if self.sync_all is False:
- self.companies = self.company_id.name # type: ignore
-
- state = fields.Selection(
- [
- ("completed", "All completed"),
- ("partially", "Partially complete"),
- ("fail", "All failed"),
- ],
- "Status",
- readonly=True,
- copy=False,
- default="completed",
- )
- sync_result = fields.Text("Sync result", readonly=1)
- total_time = fields.Float(
- string="Total time(seconds)",
- digits=(16, 3),
- readonly=True,
- )
-
- # 企微部门
- wecom_department_sync_state = fields.Selection(
- [
- ("completed", "All completed"),
- ("partially", "Partially complete"),
- ("fail", "All failed"),
- ],
- "Wecom department synchronization Status",
- readonly=True,
- copy=False,
- default="completed",
- )
- wecom_department_sync_times = fields.Float(
- string="Wecom department synchronization time (seconds)",
- digits=(16, 3),
- readonly=True,
- )
- wecom_department_sync_result = fields.Text(
- "Wecom department synchronization results", readonly=1
- )
-
- # 企微用户
- wecom_user_sync_state = fields.Selection(
- [
- ("completed", "All completed"),
- ("partially", "Partially complete"),
- ("fail", "All failed"),
- ],
- "Wecom user synchronization Status",
- readonly=True,
- copy=False,
- default="completed",
- )
- wecom_user_sync_times = fields.Float(
- string="Wecom user synchronization time (seconds)",
- digits=(16, 3),
- readonly=True,
- )
- wecom_user_sync_result = fields.Text(
- "Wecom user synchronization results", readonly=1
- )
-
- # 企微标签
- wecom_tag_sync_state = fields.Selection(
- [
- ("completed", "All completed"),
- ("partially", "Partially complete"),
- ("fail", "All failed"),
- ],
- "Wecom tag synchronization Status",
- readonly=True,
- copy=False,
- default="completed",
- )
- wecom_tag_sync_times = fields.Float(
- string="Wecom tag synchronization time (seconds)",
- digits=(16, 3),
- readonly=True,
- )
- wecom_tag_sync_result = fields.Text("Wecom tag synchronization results", readonly=1)
-
- def wizard_sync_contacts(self):
- results = []
- sync_start_time = time.time()
-
- if self.sync_all:
- # 同步所有公司
-
- companies = (
- self.sudo()
- .env["res.company"]
- .search([(("is_wecom_organization", "=", True))])
- )
-
- for company in companies:
- # 遍历公司,判断是否绑定了通讯录应用
- if company.contacts_sync_app_id:
- result = self.sync_contacts(company)
- results.append(result)
- else:
- pass
- else:
- # 同步当前选中公司
- result = self.sync_contacts(self.company_id)
- results.append(result)
-
- sync_end_time = time.time()
- self.total_time = sync_end_time - sync_start_time
-
- # 使用 pandas 处理数据
- df = pd.DataFrame(results)
-
- # 处理同步状态
- (
- self.state,
- self.wecom_department_sync_state,
- self.wecom_user_sync_state,
- self.wecom_tag_sync_state,
- ) = self.handle_sync_all_state(df)
-
- # 处理同步结果
- sync_result = ""
- wecom_department_sync_result = ""
- wecom_user_sync_result = ""
- wecom_tag_sync_result = ""
-
- # 处理同步时间
- wecom_department_sync_times = 0
- wecom_user_sync_times = 0
- wecom_tag_sync_times = 0
-
- rows = len(df) # 获取所有行数
-
- for index, row in df.iterrows():
- if row["sync_state"] == "fail":
- sync_result += self.handle_sync_result(index, rows, row["sync_result"])
- wecom_department_sync_result += self.handle_sync_result(
- index, rows, row["wecom_department_sync_result"]
- )
- wecom_user_sync_result += self.handle_sync_result(
- index, rows, row["wecom_user_sync_result"]
- )
- wecom_tag_sync_result += self.handle_sync_result(
- index, rows, row["wecom_tag_sync_result"]
- )
-
- wecom_department_sync_times += row["wecom_department_sync_times"]
- wecom_user_sync_times += row["wecom_user_sync_times"]
- wecom_tag_sync_times += row["wecom_tag_sync_times"]
-
- self.sync_result = sync_result
- self.wecom_department_sync_result = wecom_department_sync_result
- self.wecom_user_sync_result = wecom_user_sync_result
- self.wecom_tag_sync_result = wecom_tag_sync_result
-
- self.wecom_department_sync_times = wecom_department_sync_times
- self.wecom_user_sync_times = wecom_user_sync_times
- self.wecom_tag_sync_times = wecom_tag_sync_times
-
- # 显示同步结果
- form_view = self.env.ref(
- "wecom_contacts_sync.view_form_wecom_contacts_sync_result"
- )
- return {
- "name": _("Synchronize results using the wizard"),
- "view_type": "form",
- "view_mode": "form",
- "res_model": "wecom.contacts.sync.wizard",
- "res_id": self.id, # type: ignore
- "view_id": False,
- "views": [
- [form_view.id, "form"],
- ],
- "type": "ir.actions.act_window",
- # 'context': '{}',
- # 'context': self.env.context,
- "context": {
- # "form_view_ref": "hrms_syncing.dialog_wecom_contacts_sync_result"
- },
- "target": "new", # target: 打开新视图的方式, current 是在本视图打开, new 是弹出一个窗口打开
- # 'auto_refresh': 0, #为1时在视图中添加一个刷新功能
- # 'auto_search': False, #加载默认视图后,自动搜索
- # 'multi': False, #视图中有个更多按钮,若multi设为True, 更多按钮显示在tree视图,否则显示在form视图
- }
-
- def sync_contacts(self, company):
- """
- 同步通讯录
- """
- contacts_app = company.contacts_sync_app_id
- result = contacts_app.sync_contacts()
- return result
-
- def handle_sync_result(self, index, rows, result):
- """
- 处理同步结果
- """
- if result is None:
- return ""
- if index < rows - 1:
- result = "%s:%s \n" % (str(index + 1), result)
- else:
- result = "%s:%s" % (str(index + 1), result)
- return result
-
- def handle_sync_all_state(self, df):
- """
- 处理同步状态
- """
- all_state_rows = len(df) # 获取所有行数
- fail_state_rows = len(df[df["sync_state"] == "fail"]) # 获取失败行数
-
- fail_department_state_rows = len(
- df[df["wecom_department_sync_state"] == "fail"]
- ) # 获取HR部门失败行数
- fail_user_state_rows = len(
- df[df["wecom_user_sync_state"] == "fail"]
- ) # 获取HR员工失败行数
- fail_tag_state_rows = len(
- df[df["wecom_tag_sync_state"] == "fail"]
- ) # 获取HR标签失败行数
-
- sync_state = None
- wecom_department_sync_state = None
- wecom_user_sync_state = None
- wecom_tag_sync_state = None
-
- if fail_state_rows == all_state_rows:
- sync_state = "fail"
- elif fail_state_rows > 0 and fail_state_rows < all_state_rows:
- sync_state = "partially"
- elif fail_state_rows == 0:
- sync_state = "completed"
-
- # 部门
- if fail_department_state_rows == all_state_rows:
- wecom_department_sync_state = "fail"
- elif (
- fail_department_state_rows > 0
- and fail_department_state_rows < all_state_rows
- ):
- wecom_department_sync_state = "partially"
- elif fail_department_state_rows == 0:
- wecom_department_sync_state = "completed"
-
- # 员工
- if fail_user_state_rows == all_state_rows:
- wecom_user_sync_state = "fail"
- elif fail_user_state_rows > 0 and fail_user_state_rows < all_state_rows:
- wecom_user_sync_state = "partially"
- elif fail_user_state_rows == 0:
- wecom_user_sync_state = "completed"
-
- if fail_tag_state_rows == all_state_rows:
- wecom_tag_sync_state = "fail"
- elif fail_tag_state_rows > 0 and fail_tag_state_rows < all_state_rows:
- wecom_tag_sync_state = "partially"
- elif fail_tag_state_rows == 0:
- wecom_tag_sync_state = "completed"
-
- return (
- sync_state,
- wecom_department_sync_state,
- wecom_user_sync_state,
- wecom_tag_sync_state,
- )
-
- def reload(self):
- return {
- "type": "ir.actions.client",
- "tag": "reload",
- }
diff --git a/wecom_contacts_sync/wizard/wecom_contacts_sync_wizard_views.xml b/wecom_contacts_sync/wizard/wecom_contacts_sync_wizard_views.xml
deleted file mode 100644
index f51e1f0ca..000000000
--- a/wecom_contacts_sync/wizard/wecom_contacts_sync_wizard_views.xml
+++ /dev/null
@@ -1,101 +0,0 @@
-
-
-
-
- Contact synchronization Wizard
- wecom.contacts.sync.wizard
-
- form
-
-
-
-
-
-
-
-
-
-
-
-
- Linux production server uses the following command to view real-time logs:
-
-
- tail -f /var/log/odoo/odoo-server.log
-
-
- If an error occurs, please check the help file.
-
-
-
-
-
-
-
-
- Contact synchronization Result
- wecom.contacts.sync.wizard
-
- form
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Contact synchronization Wizard
- wecom.contacts.sync.wizard
- form
-
- {}
- new
-
-
-
-
\ No newline at end of file
diff --git a/wecom_l10n/__init__.py b/wecom_l10n/__init__.py
deleted file mode 100644
index 7c68785e9..000000000
--- a/wecom_l10n/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# -*- coding: utf-8 -*-
\ No newline at end of file
diff --git a/wecom_l10n/__manifest__.py b/wecom_l10n/__manifest__.py
deleted file mode 100644
index 191ca93c9..000000000
--- a/wecom_l10n/__manifest__.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# -*- coding: utf-8 -*-
-
-{
- "name": "WeCom localization",
- "author": "RStudio",
- "website": "https://gitee.com/rainbowstudio/wecom",
- "sequence": 600,
- "installable": True,
- "application": False,
- "auto_install": True,
- "category": "WeCom Suites/Localizations",
- "version": "17.0.0.1",
- "summary": """
-
- """,
- "description": """
-
- """,
- "license": "LGPL-3",
-}
diff --git a/wecom_l10n/i18n_extra/ zh_CN.po b/wecom_l10n/i18n_extra/ zh_CN.po
deleted file mode 100644
index 5b9615e9f..000000000
--- a/wecom_l10n/i18n_extra/ zh_CN.po
+++ /dev/null
@@ -1,439 +0,0 @@
-# Translation of Odoo Server.
-# This file contains the translation of the following modules:
-# * base
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: Odoo Server 15.0\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2022-07-09 13:38+0000\n"
-"PO-Revision-Date: 2022-08-02 12:40+0800\n"
-"Last-Translator: \n"
-"Language-Team: \n"
-"Language: zh_CN\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: \n"
-"X-Generator: Poedit 3.1.1\n"
-
-#. module: base
-#: model:ir.module.module,summary:base.module_wecom_message
-msgid "\n"
-" Odoo event notification to WeCom\n"
-" "
-msgstr "\n"
-" Odoo 事件通知到企业微信\n"
-" "
-
-#. module: base
-#: model:ir.module.module,summary:base.module_wecom_auth_oauth
-msgid "\n"
-" One click login, code scanning login.\n"
-" "
-msgstr "\n"
-" 一键登录,扫码登录。\n"
-" "
-
-#. module: base
-#: model:ir.module.module,summary:base.module_wecom_contacts
-msgid "\n"
-" WeCom Contacts\n"
-" "
-msgstr "\n"
-" 企微通讯录\n"
-" "
-
-#. module: base
-#: model:ir.module.module,summary:base.module_wecom_portal
-msgid "\n"
-" WeCom Portal\n"
-" "
-msgstr "\n"
-" 企微门户\n"
-" "
-
-#. module: base
-#: model:ir.module.module,summary:base.module_wecom_material
-msgid "\n"
-" WeCom material management \n"
-" "
-msgstr "\n"
-" 企微媒体素材管理 \n"
-" "
-
-#. module: base
-#: model:ir.module.category,name:base.module_category_wecom_suites_widget
-msgid "Widget"
-msgstr "小部件"
-
-#. module: base
-#: model:ir.module.module,description:base.module_wecom_api
-msgid "\n"
-" WeCom Service-side API and Client-side API\n"
-" Reconstruction based on project \"https://github.com/sbzhu/weworkapi_python\"\n"
-" "
-msgstr "\n"
-" 企业微信服务端API和客户端APIn\n"
-" Reconstruction based on project \"https://github.com/sbzhu/weworkapi_python\"\n"
-" "
-
-#. module: base
-#: model:ir.module.module,description:base.module_wecom_web_theme
-msgid "\n"
-"Wecom Web Client.\n"
-"===========================\n"
-"\n"
-"This module modifies the web addon to provide responsiveness.\n"
-" "
-msgstr "\n"
-"企业微信网络客户端。\n"
-"===========================\n"
-"\n"
-"此模块修改 Web 插件以提供响应能力。\n"
-" "
-
-#. module: base
-#: model:ir.module.module,summary:base.module_wecom_api
-msgid "\n"
-"WeCom Service-side API and Client-side API \n"
-" "
-msgstr "\n"
-"企微服务端API和客户端API \n"
-" "
-
-#. module: base
-#: model:ir.module.module,description:base.module_wecom_material
-msgid "\n"
-"please make sure ffmpeg, sox, and mediainfo are installed on your system, e.g.\n"
-"\n"
-"DOC:\n"
-"=============\n"
-"\n"
-"* https://github.com/jiaaro/pydub\n"
-"\n"
-"Install:\n"
-"=============\n"
-"\n"
-"::\n"
-"\n"
-" # libav\n"
-" apt-get install libav-tools libavcodec-extra\n"
-"\n"
-" # ffmpeg\n"
-" apt-get install ffmpeg libavcodec-extra\n"
-"\n"
-" # pydub\n"
-" pip install pydub ffmpy\n"
-" or\n"
-" pip3 install pydub ffmpy\n"
-"\n"
-msgstr "\n"
-"请确保您的系统上安装了ffmpeg、sox和mediainfo,例如。\n"
-"\n"
-"文档:\n"
-"=============\n"
-"\n"
-"* https://github.com/jiaaro/pydub\n"
-"\n"
-"安装:\n"
-"=============\n"
-"\n"
-"::\n"
-"\n"
-" # libav\n"
-" apt-get install libav-tools libavcodec-extra\n"
-"\n"
-" # ffmpeg\n"
-" apt-get install ffmpeg libavcodec-extra\n"
-"\n"
-" # pydub\n"
-" pip install pydub ffmpy\n"
-" or\n"
-" pip3 install pydub ffmpy\n"
-"\n"
-
-#. module: base
-#: model:ir.module.category,name:base.module_category_wecom_suites_approvals
-msgid "Approvals"
-msgstr "审批"
-
-#. module: base
-#: model:ir.module.module,summary:base.module_wecom_wedrive
-msgid "Enterprises can operate and set permissions for files on the microdisk through the microdisk related interfaces."
-msgstr "企业通过微盘相关接口,可以对微盘的文件进行操作和设置权限。"
-
-
-#. module: base
-#: model:ir.module.category,name:base.module_category_wecom_suites_settings
-msgid "Settings"
-msgstr "企微设置"
-
-#. module: base
-#: model:ir.module.category,name:base.module_category_wecom
-#: model:ir.module.category,name:base.module_category_wecom_suites_wecom
-#: model:ir.module.category,name:base.module_category_wecom_wecom
-msgid "WeCom"
-msgstr "企业微信"
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_wecom_api
-msgid "WeCom API"
-msgstr "企微API"
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_wecom_approval
-msgid "WeCom Approvals"
-msgstr "企微审批"
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_wecom_auth_oauth
-msgid "WeCom Authentication"
-msgstr "企微验证登陆"
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_wecom_base
-msgid "WeCom Base"
-msgstr "企微基础"
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_wecom_contacts
-msgid "WeCom Contacts"
-msgstr "企微通讯录"
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_wecom_contacts_sync
-msgid "WeCom Contacts Synchronized"
-msgstr "企微通讯录同步"
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_wecom_material
-msgid "WeCom Material"
-msgstr "企微媒体素材"
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_wecom_message
-msgid "WeCom Message"
-msgstr "企微消息"
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_wecom_portal
-msgid "WeCom Portal"
-msgstr "企微门户"
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_wecom_pro_widget
-msgid "WeCom Pro Widget"
-msgstr "企微专业版小部件"
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_wecom_msgaudit
-msgid "WeCom Session Content Archive"
-msgstr "企微会话内容存档"
-
-#. module: base
-#: model:ir.module.category,name:base.module_category_wecom_suites
-#: model_terms:ir.ui.view,arch_db:base.user_groups_view
-msgid "WeCom Suites"
-msgstr "企微套件"
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_wecom_web_theme
-msgid "WeCom Web Theme"
-msgstr "企微Web主题"
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_wecom_widget
-#: model:ir.module.module,summary:base.module_wecom_widget
-msgid "WeCom Widget"
-msgstr "企微小部件"
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_wecom_l10n
-msgid "WeCom localization"
-msgstr "企微本地化"
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_wecom_wedrive
-msgid "WeCom wedrive"
-msgstr "企微微盘"
-
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_wecom_attendance
-msgid "WeCom Attendances"
-msgstr "企微考勤"
-
-#. module: base
-#: model:ir.module.category,name:base.module_category_theme
-#: model:ir.module.category,name:base.module_category_wecom_suites_theme
-msgid "Theme"
-msgstr "主题"
-
-#. module: base
-#: model:ir.module.category,name:base.module_category_wecom_suites_authentication
-msgid "Authentication"
-msgstr "身份验证"
-
-#. module: base
-#: model:ir.module.category,name:base.module_category_wecom_suites_crm
-msgid "CRM"
-msgstr "客户关系管理"
-
-#. module: base
-#: model:ir.module.category,name:base.module_category_wecom_suites_chat_log
-msgid "Chat log"
-msgstr "企微聊天日志"
-
-#. module: base
-#: model:ir.module.category,name:base.module_category_wecom_suites_efficiency_tools
-msgid "Efficiency tools"
-msgstr "效率工具"
-
-#. module: base
-#: model:ir.module.category,description:base.module_category_wecom_suites_material
-#: model:ir.module.category,description:base.module_category_wecom_suites_settings
-msgid "Helps you manage your WeCom."
-msgstr "帮助管理您的企业微信。"
-
-#. module: base
-#: model:ir.module.category,name:base.module_category_wecom_suites_human_resources
-#: model_terms:ir.ui.view,arch_db:base.user_groups_view
-msgid "Human Resources"
-msgstr "人力资源"
-
-#. module: base
-#: model:ir.module.category,name:base.module_category_wecom_suites_localizations
-msgid "Localizations"
-msgstr "本地化"
-
-#. module: base
-#: model:ir.module.category,name:base.module_category_wecom_suites_material
-msgid "Material"
-msgstr "企微素材"
-
-#. module: base
-#: model:ir.module.category,name:base.module_category_wecom_suites_messages
-msgid "Messages"
-msgstr "企微消息"
-
-#. module: base
-#: model:ir.module.category,name:base.module_category_wecom_suites_oa_approval
-msgid "Approval"
-msgstr "企微OA审批"
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_hrms_base
-msgid "HRMS"
-msgstr "HRMS"
-
-#. module: base
-#: model:ir.module.module,summary:base.module_hrms_base
-msgid "Human Resource Management System"
-msgstr "人力资源管理系统"
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_hrms_recruitment
-msgid "HRMS Recruitment"
-msgstr "HRMS员工招聘"
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_hrms_recruitment_survey
-msgid "HRMS Recruitment Interview Forms"
-msgstr "HRMS招聘面试表单"
-
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_hrms_holidays
-msgid "HRMS Holidays"
-msgstr "HRMS员工休假"
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_hrms_attendance
-msgid "HRMS Attendances"
-msgstr "HRMS员工出勤"
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_hrms_expense
-msgid "HRMS Expenses"
-msgstr "HRMS员工费用"
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_hrms_empowerment
-msgid "HRMS Empowerment"
-msgstr "HRMS员工激励"
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_hrms_maintenance
-msgid "HRMS Maintenance"
-msgstr "HRMS员工维修"
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_wecom_message_digest
-msgid "Wecom KPI Digests Message"
-msgstr "企微KPI摘要消息"
-
-#. module: base
-#: model:ir.module.module,summary:base.module_web_multi_level_menu
-msgid "Let odoo support more than 4 levels of menus."
-msgstr "让odoo支持4级以上的菜单。"
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_web_multi_level_menu
-msgid "Web multi level menu"
-msgstr "Web多级菜单"
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_wecom_hr_approval
-msgid "Human Resources Approval"
-msgstr "HR审批"
-
-
-
-
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_hrms_payroll_expense
-msgid "Expenses in Payslips"
-msgstr "报销工资单中的费用"
-
-#. module: base
-#: model:ir.module.module,summary:base.module_hrms_payroll_expense
-msgid "Submit, validate and reinvoice employee expenses"
-msgstr "提交,验证,支付员工报销"
-
-#. module: base
-#: model:ir.module.module,description:base.module_hrms_payroll_expense
-msgid "\n"
-"Reimbursement of expenses in Payslips\n"
-"=====================================\n"
-"\n"
-"This application allows you to reimburse expenses in payslips.\n"
-" "
-msgstr "\n"
-"工资单中的费用报销\n"
-"=====================================\n"
-"\n"
-"此应用程序允许您在工资单中报销费用。\n"
-" "
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_hrms_payroll
-msgid "HRMS Payroll"
-msgstr "HRMS 工资表"
-
-#. module: base
-#: model:ir.module.module,summary:base.module_hrms_payroll
-msgid "Manage your employee payroll records"
-msgstr "管理员工工资记录"
-
-#. module: base
-#: model:ir.module.module,shortdesc:base.module_hrms_work_entry_contract
-msgid "HRMS Work Entries - Contract"
-msgstr "HRMS 工作分录 - 合同"
-
-#. module: base
-#: model:ir.module.module,summary:base.module_hrms_work_entry_contract
-msgid "Manage work entries"
-msgstr "管理工时记录"
-
diff --git a/wecom_l10n/static/description/icon.png b/wecom_l10n/static/description/icon.png
deleted file mode 100644
index ae5e48055..000000000
Binary files a/wecom_l10n/static/description/icon.png and /dev/null differ
diff --git a/wecom_material/__init__.py b/wecom_material/__init__.py
deleted file mode 100644
index 1113536d6..000000000
--- a/wecom_material/__init__.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from . import models
-
-
-import os.path
-from odoo import _
-from odoo.exceptions import UserError
-
-
-def pre_init_hook(env):
- path = env["ir.config_parameter"].get_param("wecom.resources_path")
-
- if path:
- if not os.path.exists(path):
- try:
- os.makedirs(path)
- except BaseException as e:
- raise UserError(
- _("Unable to create WeCom image storage path! Error:%s") % (repr(e))
- )
- else:
- raise UserError(_("WeCom image storage path has not been configured yet!"))
diff --git a/wecom_material/__manifest__.py b/wecom_material/__manifest__.py
deleted file mode 100644
index be041d3ae..000000000
--- a/wecom_material/__manifest__.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# -*- coding: utf-8 -*-
-{
- "name": "WeCom Material",
- "author": "RStudio",
- "website": "https://eis-solution.coding.net/public/odoo/oec/git",
- "sequence": 604,
- "installable": True,
- "application": True,
- "auto_install": False,
- "category": "WeCom Suites/Material",
- "version": "17.0.0.1",
- "summary": """
- WeCom material management
- """,
- "description": """
-please make sure ffmpeg, sox, and mediainfo are installed on your system, e.g.
-
-DOC:
-=============
-
-* https://github.com/jiaaro/pydub
-
-Install:
-=============
-
-::
-
- # libav
- apt-get install libav-tools libavcodec-extra
-
- # ffmpeg
- apt-get install ffmpeg libavcodec-extra
-
- # pydub
- pip install pydub ffmpy
- or
- pip3 install pydub ffmpy
-
-""",
- "depends": ["attachment_indexation", "wecom_contacts"],
- "data": [
- "security/wecom_material_security.xml",
- "security/ir.model.access.csv",
- "data/wecom_apps_data.xml",
- "data/material_data.xml",
- "views/material_views.xml",
- "views/res_config_settings_views.xml",
- "views/res_company_views.xml",
- "views/menu_views.xml",
- ],
- "assets": {},
- "external_dependencies": {
- "python": ["ffmpy", "pydub", "requests_toolbelt"],
- },
- "pre_init_hook": "pre_init_hook",
- "license": "AGPL-3",
-}
diff --git a/wecom_material/data/material_data.xml b/wecom_material/data/material_data.xml
deleted file mode 100644
index 5e8b490c8..000000000
--- a/wecom_material/data/material_data.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-
-
-
-
-
-
- Logo
- image
-
-
- logo.png
-
-
-
- KPI
- image
-
-
- kpi.png
-
-
-
- Welcome
- image
-
-
- welcome.png
-
-
-
- Account Created
- image
-
-
- account_created.png
-
-
-
- Message
- image
-
-
- message.png
-
-
-
- Reset Password
- image
-
-
- reset_password.png
-
-
-
- Warning
- image
-
-
- warn.png
-
-
- Gamification
- image
-
-
- gamification.png
-
-
-
-
\ No newline at end of file
diff --git a/wecom_material/data/wecom_apps_data.xml b/wecom_material/data/wecom_apps_data.xml
deleted file mode 100644
index 16b613ca1..000000000
--- a/wecom_material/data/wecom_apps_data.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_material/i18n/zh_CN.po b/wecom_material/i18n/zh_CN.po
deleted file mode 100644
index 607a620a5..000000000
--- a/wecom_material/i18n/zh_CN.po
+++ /dev/null
@@ -1,388 +0,0 @@
-# Translation of Odoo Server.
-# This file contains the translation of the following modules:
-# * wecom_material
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: Odoo Server 17.0\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2024-03-11 10:59+0000\n"
-"PO-Revision-Date: 2024-03-11 19:03+0800\n"
-"Last-Translator: \n"
-"Language-Team: \n"
-"Language: zh_CN\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Poedit 3.4.2\n"
-
-#. module: wecom_material
-#: model_terms:ir.ui.view,arch_db:wecom_material.res_config_settings_view_form
-msgid " "
-msgstr ""
-
-#. module: wecom_material
-#: model_terms:ir.ui.view,arch_db:wecom_material.res_config_settings_view_form
-msgid " "
-msgstr ""
-
-#. module: wecom_material
-#: model_terms:ir.ui.view,arch_db:wecom_material.res_config_settings_view_form
-msgid " "
-msgstr ""
-
-#. module: wecom_material
-#: model:ir.model.fields,field_description:wecom_material.field_res_config_settings__material_access_token
-msgid "Access Token"
-msgstr "访问令牌"
-
-#. module: wecom_material
-#: model:wecom.material,name:wecom_material.wecom_material_image_account_created
-msgid "Account Created"
-msgstr "创建的帐户"
-
-#. module: wecom_material
-#: model:res.groups,name:wecom_material.group_wecom_material_manager
-msgid "Administrator"
-msgstr "管理员"
-
-#. module: wecom_material
-#: model:ir.model.fields,field_description:wecom_material.field_res_config_settings__material_agentid
-msgid "Agent ID"
-msgstr "应用ID"
-
-#. module: wecom_material
-#. odoo-python
-#: code:addons/wecom_material/models/wecom_material.py:0
-#, python-format
-msgid "Allowed file formats are %s"
-msgstr "允许的文件格式为 %s"
-
-#. module: wecom_material
-#. odoo-python
-#: code:addons/wecom_material/models/wecom_material.py:0
-#, python-format
-msgid ""
-"Already uploaded, please do not upload again! You can create a new record to "
-"upload the file."
-msgstr "已上传,请不要再次上传! 您可以创建新记录后上传文件。"
-
-#. module: wecom_material
-#: model_terms:ir.ui.view,arch_db:wecom_material.res_config_settings_view_form
-msgid ""
-"Application Management→Application→Open the application that needs to be "
-"verified and authorized, copy 'AgentId'"
-msgstr "应用程序管理→应用→打开需要验证和授权的应用程序,复制“AgentId”"
-
-#. module: wecom_material
-#: model_terms:ir.ui.view,arch_db:wecom_material.res_config_settings_view_form
-msgid ""
-"Application Management→Application→Open the application that needs to be "
-"verified and authorized, copy 'Secret'"
-msgstr "应用程序管理→应用→打开需要验证和授权的应用程序,复制“Secret”"
-
-#. module: wecom_material
-#: model_terms:ir.ui.view,arch_db:wecom_material.res_config_settings_view_form
-msgid "Binding Material Application"
-msgstr "绑定素材应用"
-
-#. module: wecom_material
-#: model:ir.model,name:wecom_material.model_res_company
-#: model_terms:ir.ui.view,arch_db:wecom_material.wecom_material_filter
-msgid "Companies"
-msgstr "公司"
-
-#. module: wecom_material
-#: model:ir.model.fields,field_description:wecom_material.field_res_config_settings__company_id
-#: model:ir.model.fields,field_description:wecom_material.field_wecom_material__company_id
-msgid "Company"
-msgstr "公司"
-
-#. module: wecom_material
-#: model:ir.model,name:wecom_material.model_res_config_settings
-msgid "Config Settings"
-msgstr "配置设定"
-
-#. module: wecom_material
-#: model:ir.model.fields,field_description:wecom_material.field_wecom_material__create_uid
-msgid "Created by"
-msgstr "创建人"
-
-#. module: wecom_material
-#: model:ir.model.fields,field_description:wecom_material.field_wecom_material__create_date
-msgid "Created on"
-msgstr "创建时间"
-
-#. module: wecom_material
-#: model:ir.model.fields,field_description:wecom_material.field_wecom_material__display_name
-msgid "Display Name"
-msgstr "显示名称"
-
-#. module: wecom_material
-#. odoo-python
-#: code:addons/wecom_material/models/wecom_material.py:0
-#, python-format
-msgid "Error saving file to path %s!"
-msgstr "文件保存到路径 %s 错误!"
-
-#. module: wecom_material
-#: model:wecom.material,name:wecom_material.wecom_material_image_gamification
-msgid "Gamification"
-msgstr "游戏化"
-
-#. module: wecom_material
-#: model_terms:ir.ui.view,arch_db:wecom_material.res_config_settings_view_form
-msgid "Get application info"
-msgstr "获取应用信息"
-
-#. module: wecom_material
-#: model_terms:ir.ui.view,arch_db:wecom_material.wecom_material_filter
-msgid "Group By"
-msgstr "分组"
-
-#. module: wecom_material
-#: model:ir.model.fields,field_description:wecom_material.field_wecom_material__id
-msgid "ID"
-msgstr ""
-
-#. module: wecom_material
-#: model:wecom.material,name:wecom_material.wecom_material_image_kpi
-msgid "KPI"
-msgstr ""
-
-#. module: wecom_material
-#: model:ir.model.fields,field_description:wecom_material.field_wecom_material__write_uid
-msgid "Last Updated by"
-msgstr "最后更新人"
-
-#. module: wecom_material
-#: model:ir.model.fields,field_description:wecom_material.field_wecom_material__write_date
-msgid "Last Updated on"
-msgstr "最后更新时间"
-
-#. module: wecom_material
-#: model:wecom.material,name:wecom_material.wecom_material_image_logo
-msgid "Logo"
-msgstr ""
-
-#. module: wecom_material
-#: model_terms:ir.ui.view,arch_db:wecom_material.res_config_settings_view_form
-msgid "Management application"
-msgstr "管理应用"
-
-#. module: wecom_material
-#: model:ir.model.fields,field_description:wecom_material.field_res_company__material_app_id
-#: model:ir.model.fields,field_description:wecom_material.field_res_config_settings__material_app_id
-#: model_terms:ir.ui.view,arch_db:wecom_material.view_company_form
-msgid "Material Application"
-msgstr "素材应用"
-
-#. module: wecom_material
-#. odoo-python
-#: code:addons/wecom_material/models/res_config_settings.py:0
-#, python-format
-msgid "Material application ID and secret cannot be empty!"
-msgstr "素材应用 ID 和 Secret 不能为空!"
-
-#. module: wecom_material
-#: model:ir.model.fields,field_description:wecom_material.field_wecom_material__media_filename
-msgid "Media Filename"
-msgstr "媒体文件名"
-
-#. module: wecom_material
-#: model:ir.model.fields,field_description:wecom_material.field_wecom_material__media_id
-msgid "Media file identification"
-msgstr "媒体文件标识"
-
-#. module: wecom_material
-#. odoo-python
-#: code:addons/wecom_material/models/wecom_material.py:0
-#, python-format
-msgid "Media file size must be between %sB and %sMB"
-msgstr "媒体文件大小必须在 %sB 和 %sMB 之间"
-
-#. module: wecom_material
-#: model:ir.model.fields,field_description:wecom_material.field_wecom_material__media_type
-msgid "Media file type"
-msgstr "媒体文件类型"
-
-#. module: wecom_material
-#: model:ir.model.fields,help:wecom_material.field_wecom_material__created_at
-msgid "Media file upload timestamp (Beijing time)"
-msgstr "媒体文件上传时间戳(北京时间)"
-
-#. module: wecom_material
-#: model:ir.model.fields,field_description:wecom_material.field_wecom_material__media_file
-msgid "Media files"
-msgstr "媒体文件"
-
-#. module: wecom_material
-#: model:wecom.material,name:wecom_material.wecom_material_image_message
-msgid "Message"
-msgstr "消息"
-
-#. module: wecom_material
-#: model:ir.model.fields,field_description:wecom_material.field_wecom_material__name
-msgid "Name"
-msgstr "名称"
-
-#. module: wecom_material
-#: model:res.groups,name:wecom_material.group_wecom_material_user
-msgid "Officer"
-msgstr "主管"
-
-#. module: wecom_material
-#: model:ir.model.fields.selection,name:wecom_material.selection__wecom_material__media_type__file
-msgid "Ordinary file"
-msgstr "普通文件"
-
-#. module: wecom_material
-#: model:ir.model.fields.selection,name:wecom_material.selection__wecom_material__media_type__image
-msgid "Picture"
-msgstr "图片"
-
-#. module: wecom_material
-#: model:ir.model.fields,field_description:wecom_material.field_wecom_material__img_url
-msgid "Picture URL"
-msgstr "图片网址"
-
-#. module: wecom_material
-#: model:ir.model.fields,help:wecom_material.field_wecom_material__media_file
-msgid ""
-"Picture file size should be between 5B and 2MB;The voice file format supports "
-"AMR, and the file size should be between 5B and 2MBThe video file shall not "
-"exceed 10m, the file format: MP4, and the file size shall be between 5B and "
-"10MBNormal file size shall not exceed 20m"
-msgstr ""
-"图片文件大小应介于5B和2MB之间;语音文件格式支持AMR,文件大小应在5B到2MB之间视频文"
-"件不超过10m,文件格式:MP4,文件大小应在5B到10m之间正常文件大小不超过20m"
-
-#. module: wecom_material
-#. odoo-python
-#: code:addons/wecom_material/models/wecom_material.py:0
-#, python-format
-msgid "Please upload files!"
-msgstr "请上传文件!"
-
-#. module: wecom_material
-#: model:wecom.material,name:wecom_material.wecom_material_image_reset_password
-msgid "Reset Password"
-msgstr "重置密码"
-
-#. module: wecom_material
-#: model:ir.model.fields,field_description:wecom_material.field_res_config_settings__material_secret
-msgid "Secret"
-msgstr "密钥"
-
-#. module: wecom_material
-#: model:ir.model.fields,field_description:wecom_material.field_wecom_material__temporary
-msgid "Temporary material"
-msgstr "临时素材"
-
-#. module: wecom_material
-#: model:ir.model.fields,help:wecom_material.field_wecom_material__img_url
-msgid "The URL of the picture obtained after uploading. Permanently valid."
-msgstr "上传后获得的图片的URL。永久有效。"
-
-#. module: wecom_material
-#. odoo-python
-#: code:addons/wecom_material/models/wecom_material.py:0
-#, python-format
-msgid "The duration of the voice file exceeds 60 seconds!"
-msgstr "语音文件的时长超过60秒!"
-
-#. module: wecom_material
-#. odoo-python
-#: code:addons/wecom_material/models/wecom_material.py:0
-#, python-format
-msgid "The temporary material has not expired, please do not upload it repeatedly."
-msgstr "临时素材尚未过期,请不要重复上传。"
-
-#. module: wecom_material
-#: model:ir.model.fields,help:wecom_material.field_wecom_material__media_id
-msgid ""
-"The unique identification obtained after uploading the media file is valid for 3 "
-"days"
-msgstr "媒体文件上传后获取的唯一标识,3天内有效"
-
-#. module: wecom_material
-#: model:res.groups,comment:wecom_material.group_wecom_material_user
-msgid "The user will be able to approve document created by employees."
-msgstr "此用户将有权限审批员工创建的文档。"
-
-#. module: wecom_material
-#: model:res.groups,comment:wecom_material.group_wecom_material_manager
-msgid ""
-"The user will have access to the wecom material configuration as well as "
-"statistic reports."
-msgstr "用户可以访问企微素材配置以及统计报告。"
-
-#. module: wecom_material
-#. odoo-python
-#: code:addons/wecom_material/__init__.py:0
-#, python-format
-msgid "Unable to create WeCom image storage path! Error:%s"
-msgstr "无法创建企微图像存储路径!错误:%s"
-
-#. module: wecom_material
-#. odoo-python
-#: code:addons/wecom_material/models/wecom_material.py:0
-#, python-format
-msgid "Unknown type of media file!"
-msgstr "未知媒体文件类型!"
-
-#. module: wecom_material
-#: model_terms:ir.ui.view,arch_db:wecom_material.wecom_material_form
-msgid "Upload media files"
-msgstr "上传媒体文件"
-
-#. module: wecom_material
-#: model:ir.model.fields,field_description:wecom_material.field_wecom_material__created_at
-msgid "Upload time"
-msgstr "上传时间"
-
-#. module: wecom_material
-#: model:ir.model.fields.selection,name:wecom_material.selection__wecom_material__media_type__video
-msgid "Video"
-msgstr "视频"
-
-#. module: wecom_material
-#: model:ir.model.fields.selection,name:wecom_material.selection__wecom_material__media_type__voice
-msgid "Voice"
-msgstr "语音"
-
-#. module: wecom_material
-#: model:wecom.material,name:wecom_material.wecom_material_image_warn
-msgid "Warning"
-msgstr "警告"
-
-#. module: wecom_material
-#. odoo-python
-#: code:addons/wecom_material/__init__.py:0
-#, python-format
-msgid "WeCom image storage path has not been configured yet!"
-msgstr "尚未配置企微图像存储路径!"
-
-#. module: wecom_material
-#: model:ir.model,name:wecom_material.model_wecom_material
-msgid "WeCom material"
-msgstr "企微素材"
-
-#. module: wecom_material
-#. odoo-python
-#: code:addons/wecom_material/models/wecom_material.py:0
-#, python-format
-msgid "WeCom storage path has not been configured yet!"
-msgstr "企微存储路径尚未配置!"
-
-#. module: wecom_material
-#: model:ir.actions.act_window,name:wecom_material.action_view_wecom_material
-#: model:ir.ui.menu,name:wecom_material.menu_wecom_material
-msgid "Wecom Material"
-msgstr "企微素材"
-
-#. module: wecom_material
-#: model:wecom.material,name:wecom_material.wecom_material_image_welcome
-msgid "Welcome"
-msgstr "欢迎"
diff --git a/wecom_material/models/__init__.py b/wecom_material/models/__init__.py
deleted file mode 100644
index e4e7fe8a7..000000000
--- a/wecom_material/models/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from . import wecom_material
-from . import res_company
-from . import res_config_settings
diff --git a/wecom_material/models/res_company.py b/wecom_material/models/res_company.py
deleted file mode 100644
index 591460650..000000000
--- a/wecom_material/models/res_company.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from odoo import api, fields, models, tools, _
-
-
-class Company(models.Model):
- _inherit = "res.company"
-
- # material_agentid = fields.Char("Material Agent Id", default="0000000",)
- # material_secret = fields.Char(
- # "Material Secret", default="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
- # )
-
- # 素材库
- material_app_id = fields.Many2one(
- "wecom.apps",
- string="Material Application",
- # required=True,
- # default=lambda self: self.env.company,
- # domain="[('company_id', '=', current_company_id)]",
- domain="[('company_id', '=', current_company_id)]",
- )
diff --git a/wecom_material/models/res_config_settings.py b/wecom_material/models/res_config_settings.py
deleted file mode 100644
index eac9bc682..000000000
--- a/wecom_material/models/res_config_settings.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from odoo import api, fields, models, tools, SUPERUSER_ID, _
-from odoo.exceptions import UserError
-
-class ResConfigSettings(models.TransientModel):
- _inherit = "res.config.settings"
-
- company_id = fields.Many2one(
- "res.company",
- string="Company",
- required=True,
- default=lambda self: self.env.company,
- )
-
- material_app_id = fields.Many2one(
- related="company_id.material_app_id", readonly=False,
- )
-
- material_agentid = fields.Integer(related="material_app_id.agentid", readonly=False)
- material_secret = fields.Char(related="material_app_id.secret", readonly=False)
- material_access_token = fields.Char(related="material_app_id.access_token")
-
- def get_material_app_info(self):
- """
- 获取应用信息
- :return:
- """
- for record in self:
- # print(record.material_agentid,record.material_secret)
- if record.material_agentid== 0 or record.material_secret == '': # type: ignore
- raise UserError(_("Material application ID and secret cannot be empty!"))
- else:
- record.material_app_id.get_app_info() # type: ignore
-
diff --git a/wecom_material/models/wecom_material.py b/wecom_material/models/wecom_material.py
deleted file mode 100644
index 4deb73867..000000000
--- a/wecom_material/models/wecom_material.py
+++ /dev/null
@@ -1,409 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import os
-import base64
-import platform
-import subprocess
-import logging
-import time
-from pydub import AudioSegment # type: ignore
-from datetime import datetime, timedelta
-import pytz
-
-from odoo import _, api, fields, models, tools
-from odoo.exceptions import UserError, ValidationError
-
-from odoo.addons.wecom_api.api.wecom_abstract_api import ApiException # type: ignore
-
-from requests_toolbelt.multipart.encoder import MultipartEncoder
-
-
-_logger = logging.getLogger(__name__)
-
-extensions_and_size = {
- "image": {"extensions": [".jpg", ".png"], "size": [5, 2 * 1024 * 1024]},
- "voice": {"extensions": [".amr"], "size": [5, 2 * 1024 * 1024], "duration": 60},
- "video": {"extensions": [".mp4"], "size": [5, 10 * 1024 * 1024]},
- "file": {"extensions": [], "size": [5, 20 * 1024 * 1024]},
-}
-
-
-class WeComMaterial(models.Model):
- "Template for sending WeCom message"
- _name = "wecom.material"
- _description = "WeCom material"
- _order = "company_id,name"
-
- company_id = fields.Many2one(
- "res.company",
- string="Company",
- domain="[('is_wecom_organization', '=', True)]",
- copy=False,
- store=True,
- )
- name = fields.Char(
- "Name",
- required=True,
- translate=True,
- )
- media_type = fields.Selection(
- [
- ("image", "Picture"),
- ("voice", "Voice"),
- ("video", "Video"),
- ("file", "Ordinary file"),
- ],
- string="Media file type",
- required=True,
- default="image",
- )
- temporary = fields.Boolean(string="Temporary material", default=False)
- img_url = fields.Char(
- string="Picture URL",
- readonly=True,
- help="The URL of the picture obtained after uploading. Permanently valid.",
- copy=False,
- )
- media_id = fields.Char(
- string="Media file identification",
- readonly=True,
- help="The unique identification obtained after uploading the media file is valid for 3 days",
- copy=False,
- )
- created_at = fields.Datetime(
- string="Upload time",
- readonly=True,
- help="Media file upload timestamp (Beijing time)",
- copy=False,
- )
-
- media_file = fields.Binary(
- string="Media files",
- help="Picture file size should be between 5B and 2MB;"
- "The voice file format supports AMR, and the file size should be between 5B and 2MB"
- "The video file shall not exceed 10m, the file format: MP4, and the file size shall be between 5B and 10MB"
- "Normal file size shall not exceed 20m",
- store=True,
- required=True,
- )
- media_filename = fields.Char()
-
- _sql_constraints = [
- (
- "name_company_uniq",
- "unique (name, company_id)",
- "The material name of each company must be unique !",
- ),
- ]
-
- @api.onchange("media_type")
- def _onchange_media_type(self):
- if self.media_type != "image":
- self.temporary = True
- else:
- self.temporary = False
-
- @api.onchange("media_file")
- def _onchange_media_file(self):
- if self.media_file:
- self._check_file_size_and_extension(
- self.media_type, self.media_file, self.media_filename
- )
-
- def upload_media(self):
- if self.img_url:
- # 存在 上传后得到的永久有效图片URL。
- raise UserError(
- _(
- "Already uploaded, please do not upload again! You can create a new record to upload the file."
- )
- )
- if self.created_at:
- # 存在 媒体文件上传时间戳(北京时间)
- created_time = self.created_at
-
- overdue = self.env["wecomapi.tools.datetime"].cheeck_days_overdue(
- created_time, 3
- )
- if overdue:
- pass
- else:
- raise UserError(
- _(
- "The temporary material has not expired, please do not upload it repeatedly."
- )
- )
-
- if self.media_file:
- # 存在媒体文件
- sys_params = self.env["ir.config_parameter"].sudo()
- if self.company_id:
- file_path = self._check_file_path(
- self.media_file, "material", self.media_filename
- )
-
- if self.temporary:
- """
- 素材上传得到media_id,该media_id仅三天内有效
- media_id在同一企业内应用之间可以共享
- """
- try:
- multipart_encoder = MultipartEncoder(
- fields={
- self.media_filename: (
- "file",
- open(file_path, "rb"),
- "text/plain",
- )
- },
- )
- headers = {"Content-Type": multipart_encoder.content_type}
- wxapi = self.env["wecom.service_api"].InitServiceApi(
- self.company_id.corpid, # type: ignore
- self.company_id.material_app_id.secret, # type: ignore
- )
- response = wxapi.httpPostFile(
- self.env["wecom.service_api_list"].get_server_api_call(
- "MEDIA_UPLOAD"
- ),
- {"type": self.media_type},
- multipart_encoder,
- headers,
- )
-
- if response["errcode"] == 0:
- self.media_id = response["media_id"]
- timeStamp = int(response["created_at"])
- timeArray = time.localtime(timeStamp)
- self.created_at = time.strftime(
- "%Y-%m-%d %H:%M:%S", timeArray
- )
- except ApiException as ex:
- self.env["wecomapi.tools.action"].ApiExceptionDialog(
- ex, ex, raise_exception=True
- )
- else:
- """
- 上传图片得到图片URL,该URL永久有效
- 返回的图片URL,仅能用于图文消息正文中的图片展示,或者给客户发送欢迎语等;若用于非企业微信环境下的页面,图片将被屏蔽。
- 每个企业每天最多可上传100张图片
- """
- try:
- wxapi = self.env["wecom.service_api"].InitServiceApi(
- self.company_id.corpid, # type: ignore
- self.company_id.material_app_id.secret, # type: ignore
- )
- # files = {"media": open(file_path, "rb")}
- multipart_encoder = MultipartEncoder(
- fields={
- self.media_filename: (
- "file",
- open(file_path, "rb"),
- "text/plain",
- )
- },
- )
- headers = {"Content-Type": multipart_encoder.content_type}
-
- response = wxapi.httpPostFile(
- self.env["wecom.service_api_list"].get_server_api_call(
- "MEDIA_UPLOADIMG"
- ),
- {"type": self.media_type},
- multipart_encoder,
- headers,
- )
-
- if response["errcode"] == 0:
- self.img_url = response["url"]
- self.created_at = fields.Datetime.now()
- except ApiException as ex:
- return self.env["wecomapi.tools.action"].ApiExceptionDialog(
- ex, raise_exception=True
- )
- else:
- raise UserError(_("Please upload files!"))
-
- return self
-
- @api.model
- def create(self, vals):
- if vals.get("media_type") and vals.get("media_file"):
- # 检查文件的大小和格式,语音文件检查时长
- self._check_file_size_and_extension(
- vals.get("media_type"),
- vals.get("media_file"),
- vals.get("media_filename"),
- )
- # print(vals.get("media_type"),vals.get("media_file"),vals.get("media_filename"))
- # 检查文件路径
- self._check_file_path(
- vals.get("media_file"), "material", vals.get("media_filename")
- )
- material = super(WeComMaterial, self).create(vals)
- return material
-
- def write(self, vals):
- # if vals.get("media_id") or vals.get("img_url"):
- # raise UserError(
- # _(
- # "Already uploaded, please do not upload again! You can create a new record to upload the file."
- # )
- # )
- res = super(WeComMaterial, self).write(vals)
-
- if vals.get("media_type") and vals.get("media_file"):
- # 检查文件的大小和格式,语音文件检查时长
- self._check_file_size_and_extension(
- vals.get("media_type"),
- vals.get("media_file"),
- vals.get("media_filename"),
- )
- # 检查文件路径
- self._check_file_path(
- vals.get("media_file"), "material", vals.get("media_filename")
- )
- return res
-
- @api.returns("self", lambda value: value.id)
- def copy(self, default=None):
- if default:
- if not default.get("company_id"):
- pass
- return super(WeComMaterial, self).copy(default=default)
-
- @api.model
- def _check_material_file_expiration(self):
- """[summary]
- 检查素材文件是否过期
- Args:
- material ([type]): [description]
-
- Returns:
- [type]: [description]
- """
- # media_id = ""
- if self.created_at:
- # 有创建日期
- created_time = self.created_at
- MAX_FAIL_TIME = 3
-
- # 检查是否超过3天
- overdue = self.env["wecomapi.tools.datetime"].cheeck_days_overdue(
- created_time, MAX_FAIL_TIME
- )
- if overdue:
- # 临时素材超期,重新上传
- self.upload_media()
- # media_id = self.media_id
- else:
- # 无创建日期,执行第一次上传临时素材
- self.upload_media()
- # media_id = self.media_id
- return self.media_id
-
- @api.model
- def _check_file_path(self, file, subpath, filename):
- sys_params = self.env["ir.config_parameter"].sudo()
- path = sys_params.get_param("wecom.resources_path")
- if path:
- pass
- else:
- raise UserError(_("WeCom storage path has not been configured yet!"))
-
- file_path = self.env["wecomapi.tools.file"].path_is_exists(path, subpath)
- full_path = file_path + filename
-
- if not os.path.exists(full_path):
- try:
- with open(full_path, "wb") as fp:
- fp.write(base64.b64decode(file))
- fp.close()
- # return full_path
- except IOError:
- raise UserError(_("Error saving file to path %s!"), full_path) # type: ignore
-
- if platform.system() == "Windows":
- full_path = full_path.replace("/", "\\")
-
- return full_path
-
- @api.model
- def _check_file_size_and_extension(self, filetype, file, filename):
- file_extension_list = []
- file_size_list = []
- file_extension = os.path.splitext(filename)[1]
- file_size = int(len(file) * 3 / 4) # 以字节为单位计算file_size
-
- if filetype == "image":
- file_extension_list = extensions_and_size["image"]["extensions"]
- file_size_list = extensions_and_size["image"]["size"]
- if filetype == "voice":
- file_extension_list = extensions_and_size["voice"]["extensions"]
- file_size_list = extensions_and_size["voice"]["size"]
- # 语音文件先上传到本地文件夹进行时长检查
- file_path = self._check_file_path(file, "material", filename)
- duration, path = self.get_amr_duration(file_path) # type: ignore
- if int(duration) > 60:
- # 语音文件时长超过了60秒,删除mp3文件
- os.remove(os.path.abspath(path)) # type: ignore
- raise ValidationError(
- _("The duration of the voice file exceeds 60 seconds!")
- )
-
- if filetype == "video":
- file_extension_list = extensions_and_size["video"]["extensions"]
- file_size_list = extensions_and_size["video"]["size"]
- if filetype == "file":
- file_extension_list = extensions_and_size["file"]["extensions"]
- file_size_list = extensions_and_size["file"]["size"]
- if filetype is None:
- raise ValidationError(_("Unknown type of media file!"))
-
- if len(file_extension_list) > 0 and file_extension not in file_extension_list:
- raise ValidationError(
- _("Allowed file formats are %s")
- % (" or ".join(str(x) for x in file_extension_list))
- )
- # if file_size_list[0] != 0:
- if file_size > file_size_list[1] or file_size_list[1] < file_size_list[0]:
- raise ValidationError(
- _("Media file size must be between %sB and %sMB")
- % (file_size_list[0], file_size_list[1] / 1024 / 1024)
- )
- # elif file_size > file_size_list[1]:
- # raise ValidationError(
- # _("Media file size cannot be larger than %sMB")
- # % (file_size_list[1] / 1024 / 1024)
- # )
-
- def get_amr_duration(self, filepath):
- """
- 获取.amr语音文件的时长
- """
- path = os.path.split(filepath)[0]
- filename = os.path.split(filepath)[1].split(".")[0]
- mp3_audio_filepath = os.path.join(path, filename + ".mp3")
-
- mp3_transformat_path = self.amr_transformat_mp3(
- os.path.abspath(filepath), mp3_audio_filepath
- )
- if os.path.exists(mp3_transformat_path):
- mp3_audio = AudioSegment.from_file(
- os.path.abspath(mp3_transformat_path), format="mp3" # type: ignore
- )
- return mp3_audio.duration_seconds, mp3_transformat_path
-
- @classmethod
- def amr_transformat_mp3(self, amr_path, mp3_path=None):
- path, name = os.path.split(amr_path)
- if name.split(".")[-1] != "amr":
- print("not a amr file")
- return 0
- if mp3_path is None or mp3_path.split(".")[-1] != "mp3":
- mp3_path = os.path.join(path, name + ".mp3")
- error = subprocess.call(["ffmpeg", "-i", amr_path, mp3_path])
- if error:
- _logger.info("[Convert Error]:Convert file-%s to mp3 failed" % amr_path)
- return 0
- return mp3_path
diff --git a/wecom_material/security/ir.model.access.csv b/wecom_material/security/ir.model.access.csv
deleted file mode 100644
index 82113a7f5..000000000
--- a/wecom_material/security/ir.model.access.csv
+++ /dev/null
@@ -1,2 +0,0 @@
-id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
-access_wecom_material,access.wecom.material,model_wecom_material,group_wecom_material_manager,1,1,1,1
diff --git a/wecom_material/security/wecom_material_security.xml b/wecom_material/security/wecom_material_security.xml
deleted file mode 100644
index b3800da6d..000000000
--- a/wecom_material/security/wecom_material_security.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
- Helps you manage your WeCom.
- 2
-
-
-
- Officer
-
-
- The user will be able to approve document created by employees.
-
-
-
- Administrator
- The user will have access to the wecom material configuration as well as statistic reports.
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_material/static/description/icon.png b/wecom_material/static/description/icon.png
deleted file mode 100644
index 771f87a1b..000000000
Binary files a/wecom_material/static/description/icon.png and /dev/null differ
diff --git a/wecom_material/static/src/img/account_created.png b/wecom_material/static/src/img/account_created.png
deleted file mode 100644
index 4ccad96e7..000000000
Binary files a/wecom_material/static/src/img/account_created.png and /dev/null differ
diff --git a/wecom_material/static/src/img/gamification.png b/wecom_material/static/src/img/gamification.png
deleted file mode 100644
index c12626105..000000000
Binary files a/wecom_material/static/src/img/gamification.png and /dev/null differ
diff --git a/wecom_material/static/src/img/kpi.png b/wecom_material/static/src/img/kpi.png
deleted file mode 100644
index b137eaa98..000000000
Binary files a/wecom_material/static/src/img/kpi.png and /dev/null differ
diff --git a/wecom_material/static/src/img/logo.png b/wecom_material/static/src/img/logo.png
deleted file mode 100644
index 0645954d9..000000000
Binary files a/wecom_material/static/src/img/logo.png and /dev/null differ
diff --git a/wecom_material/static/src/img/message.png b/wecom_material/static/src/img/message.png
deleted file mode 100644
index af99f99bd..000000000
Binary files a/wecom_material/static/src/img/message.png and /dev/null differ
diff --git a/wecom_material/static/src/img/reset_password.png b/wecom_material/static/src/img/reset_password.png
deleted file mode 100644
index 8fca2766b..000000000
Binary files a/wecom_material/static/src/img/reset_password.png and /dev/null differ
diff --git a/wecom_material/static/src/img/warn.png b/wecom_material/static/src/img/warn.png
deleted file mode 100644
index c0ca13d3e..000000000
Binary files a/wecom_material/static/src/img/warn.png and /dev/null differ
diff --git a/wecom_material/static/src/img/welcome.png b/wecom_material/static/src/img/welcome.png
deleted file mode 100644
index 6f28a3674..000000000
Binary files a/wecom_material/static/src/img/welcome.png and /dev/null differ
diff --git a/wecom_material/views/material_views.xml b/wecom_material/views/material_views.xml
deleted file mode 100644
index eadc3f8d8..000000000
--- a/wecom_material/views/material_views.xml
+++ /dev/null
@@ -1,102 +0,0 @@
-
-
-
-
-
- wecom.material.form
- wecom.material
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- wecom.material.search
- wecom.material
-
-
-
-
-
-
-
-
-
-
-
- wecom.material.kanban
- wecom.material
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- wecom.material.tree
- wecom.material
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Wecom Material
- wecom.material
- tree,kanban,form
- {'group_by':['company_id']}
-
-
-
-
\ No newline at end of file
diff --git a/wecom_material/views/menu_views.xml b/wecom_material/views/menu_views.xml
deleted file mode 100644
index 3b0987523..000000000
--- a/wecom_material/views/menu_views.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/wecom_material/views/res_company_views.xml b/wecom_material/views/res_company_views.xml
deleted file mode 100644
index d875a29e8..000000000
--- a/wecom_material/views/res_company_views.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
- res.company.form.inherit.wecom_material
- res.company
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/wecom_material/views/res_config_settings_views.xml b/wecom_material/views/res_config_settings_views.xml
deleted file mode 100644
index 0dd1ebd6e..000000000
--- a/wecom_material/views/res_config_settings_views.xml
+++ /dev/null
@@ -1,75 +0,0 @@
-
-
-
-
- Settings
- res.config.settings
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Application Management→Application→Open the application that needs to be verified and authorized, copy 'AgentId'
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Application Management→Application→Open the application that needs to be verified and authorized, copy 'Secret'
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/wecom_widget/__init__.py b/wecom_widget/__init__.py
deleted file mode 100644
index cde864bae..000000000
--- a/wecom_widget/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from . import models
diff --git a/wecom_widget/__manifest__.py b/wecom_widget/__manifest__.py
deleted file mode 100644
index 20057464b..000000000
--- a/wecom_widget/__manifest__.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# -*- coding: utf-8 -*-
-
-{
- "name": "WeCom Widget",
- "author": "RStudio",
- "category": "WeCom Suites/Widget",
- "summary": "WeCom Widget",
- "website": "https://gitee.com/rainbowstudio/wecom",
- "version": "17.0.0.1",
- "description": """
-
-""",
- "depends": [
- "web",
- ],
- "data": [],
- "assets": {
- "web.assets_common": [],
- "web.assets_backend": [
- "wecom_widget/static/src/webclient/**/*",
- # "wecom_widget/static/src/views/**/*",
- "wecom_widget/static/src/components/**/*",
- ],
- },
- "sequence": 600,
- "installable": True,
- "auto_install": True,
- "application": False,
- "license": "AGPL-3",
-}
diff --git a/wecom_widget/i18n/zh_CN.po b/wecom_widget/i18n/zh_CN.po
deleted file mode 100644
index bdc26469f..000000000
--- a/wecom_widget/i18n/zh_CN.po
+++ /dev/null
@@ -1,55 +0,0 @@
-# Translation of Odoo Server.
-# This file contains the translation of the following modules:
-# * wecom_widget
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: Odoo Server 17.0\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2024-03-06 09:17+0000\n"
-"PO-Revision-Date: 2024-03-06 17:18+0800\n"
-"Last-Translator: \n"
-"Language-Team: \n"
-"Language: zh_CN\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Poedit 3.4.2\n"
-
-#. module: wecom_widget
-#. odoo-javascript
-#: code:addons/wecom/wecom_widget/static/src/webclient/settings_form_view/widgets/navigation.xml:0
-#: code:addons/wecom_widget/static/src/webclient/settings_form_view/widgets/navigation.xml:0
-#, python-format
-msgid "Companies settings"
-msgstr "公司设置"
-
-#. module: wecom_widget
-#. odoo-javascript
-#: code:addons/wecom/wecom_widget/static/src/webclient/settings_form_view/widgets/navigation.xml:0
-#: code:addons/wecom_widget/static/src/webclient/settings_form_view/widgets/navigation.xml:0
-#, python-format
-msgid "Contacts settings"
-msgstr "通讯录设置"
-
-#. module: wecom_widget
-#. odoo-javascript
-#: code:addons/wecom/wecom_widget/static/src/webclient/settings_form_view/widgets/navigation.xml:0
-#: code:addons/wecom_widget/static/src/webclient/settings_form_view/widgets/navigation.xml:0
-#, python-format
-msgid "Contacts synchronization settings"
-msgstr "通讯录同步设置"
-
-#. module: wecom_widget
-#: model:ir.model,name:wecom_widget.model_ir_module_module
-msgid "Module"
-msgstr "模块"
-
-#. module: wecom_widget
-#. odoo-javascript
-#: code:addons/wecom/wecom_widget/static/src/webclient/settings_form_view/widgets/navigation.xml:0
-#: code:addons/wecom_widget/static/src/webclient/settings_form_view/widgets/navigation.xml:0
-#, python-format
-msgid "Navigation"
-msgstr "导航"
diff --git a/wecom_widget/models/__init__.py b/wecom_widget/models/__init__.py
deleted file mode 100644
index fff9c671b..000000000
--- a/wecom_widget/models/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from . import ir_module
-
-# from . import ir_qweb_fields
-
diff --git a/wecom_widget/models/ir_module.py b/wecom_widget/models/ir_module.py
deleted file mode 100644
index 154ac8858..000000000
--- a/wecom_widget/models/ir_module.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from odoo import api, fields, models, tools, _
-import logging
-
-_logger = logging.getLogger(__name__)
-
-
-class Module(models.Model):
- _inherit = "ir.module.module"
-
- @api.model
- def check_wecom_addons_exist(self, addon_name=None):
- """
- 检查 企微 addon 是否存在
- """
- addon = self.sudo().search([("name", "=", addon_name)])
-
- if not addon:
- # return {
- # "exist": False,
- # "moduleId": 0,
- # }
- return False
- else:
- # addon.button_install()
- # return {
- # "exist": True,
- # "moduleId": addon.id,
- # }
- return True
diff --git a/wecom_widget/models/ir_qweb_fields.py b/wecom_widget/models/ir_qweb_fields.py
deleted file mode 100644
index e2b7c7c2c..000000000
--- a/wecom_widget/models/ir_qweb_fields.py
+++ /dev/null
@@ -1,14 +0,0 @@
-# -*- coding: utf-8 -*-
-import markdown
-
-from odoo import api, models, _
-
-
-class MarkdownConverter(models.AbstractModel):
- _name = "ir.qweb.field.markdown"
- _description = "Qweb Field Markdown"
- _inherit = "ir.qweb.field"
-
- @api.model
- def value_to_html(self, value, options):
- return markdown.markdown(value)
diff --git a/wecom_widget/static/description/icon.png b/wecom_widget/static/description/icon.png
deleted file mode 100644
index b05987cb2..000000000
Binary files a/wecom_widget/static/description/icon.png and /dev/null differ
diff --git a/wecom_widget/static/src/webclient/settings_form_view/widgets/navigation.js b/wecom_widget/static/src/webclient/settings_form_view/widgets/navigation.js
deleted file mode 100644
index 89832c8fd..000000000
--- a/wecom_widget/static/src/webclient/settings_form_view/widgets/navigation.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/** @odoo-module */
-
-import { registry } from '@web/core/registry';
-import { _t } from "@web/core/l10n/translation";
-import { Component } from "@odoo/owl";
-
-export class ResConfigWecomNavigation extends Component {
- static template = "res_config_wecom_navigation";
-
- setup() {
-
- }
-
- onClickJumpAnchor() {
-
- }
-}
-
-export const resConfigWecomNavigation = {
- component: ResConfigWecomNavigation,
-};
-resConfigWecomNavigation.template = 'res_config_wecom_navigation';
-resConfigWecomNavigation.props = {};
-registry.category('view_widgets').add('res_config_wecom_navigation', resConfigWecomNavigation);
\ No newline at end of file
diff --git a/wecom_widget/static/src/webclient/settings_form_view/widgets/navigation.scss b/wecom_widget/static/src/webclient/settings_form_view/widgets/navigation.scss
deleted file mode 100644
index 0f52be13d..000000000
--- a/wecom_widget/static/src/webclient/settings_form_view/widgets/navigation.scss
+++ /dev/null
@@ -1,10 +0,0 @@
-.res_config_wecom_navigation {
- sapn {
- margin-top: 0;
- margin-left: 4px;
- margin-bottom: 0.5rem;
- font-weight: bold;
- line-height: 1.2;
- color: #091124;
- }
-}
\ No newline at end of file
diff --git a/wecom_widget/static/src/webclient/settings_form_view/widgets/navigation.xml b/wecom_widget/static/src/webclient/settings_form_view/widgets/navigation.xml
deleted file mode 100644
index e81aedc6d..000000000
--- a/wecom_widget/static/src/webclient/settings_form_view/widgets/navigation.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-