业务场景:当用户小张通过onlyoffice打开附件编辑时,此时用户小李通过后台python语言修改此附件风险:一致性错误,版本混乱,小李通过odoo修改此附件后,随后小张又将此附件覆盖原因:小张在odoo编辑的附件与小李在onlyoffice的附件不一致。如果在onlyoffice设置的模式为“快速”,onlyoffice会对附件修改自动保存,但是此保存仅在onlyoffice缓存中,没有同步到odoo系统,有其他机制触发同步;如果在onlyoffice设置为“严格”,需人工点击保存按钮,随后将附件同步到odoo系统。解决方案:小张在修改附件前将onlyoffice的附件强制保存,同步到odoo,随后将onlyoffice此时编辑该附件的用户小李强制离线,如果想再次编辑,小李需从odoo中打开。1、调用onlyoffice接口的统一方法,具体详情可以登录官网查看APIimport requestsimport jsonimport loggingfrom odoo.addons.onlyoffice_odoo.utils import jwt_utils, config_utils_logger = logging.getLogger(__name__)def call_command_service_with_header_jwt(env, command_payload): """ 调用命令服务,并将 JWT Token 放在 Authorization Header 中。 command_payload 是命令本身需要的参数 (不含 token)。 """ token = jwt_utils.encode_payload(env, command_payload) DOC_SERVER_URL = config_utils.get_doc_server_public_url(env) COMMAND_SERVICE_URL = f"{DOC_SERVER_URL}/command" full_payload = { "token": token, **command_payload # 合并命令本身的参数 } jwt_header = config_utils.get_jwt_header(env) headers = { "Content-Type": "application/json", jwt_header: f"Bearer {token}" # 使用配置的 Header 名称和 "Bearer " 前缀 } _logger.info(f"--- command_payload: {command_payload} ---") _logger.info(f"Request Headers: {headers}") _logger.info(f"Request Payload: {json.dumps(full_payload, indent=2)}") try: response = requests.post( COMMAND_SERVICE_URL, headers=headers, json=full_payload # 将包含 token 和命令参数的 payload 发送 ) response.raise_for_status() _logger.info(f"Response Status Code: {response.status_code}") _logger.info(f"Response Body: {json.dumps(response.json(), indent=2)}") return response.json() except requests.exceptions.RequestException as e: _logger.info(f"Error calling command service for {command_payload}: {e}") if hasattr(e, 'response') and e.response is not None: _logger.info(f"Response Status Code: {e.response.status_code}") _logger.info(f"Response Body: {e.response.text}") return None
2、在odoo的model中实现业务逻辑,强制保存、获取正在编辑用户、强制离线def _out_user_with_of(self): """ 强制用户离线 """ for record in self: try: attachment = record.attachment_ids[0] data = attachment.read(["id", "checksum", "public", "name", "access_token"])[0] key = str(data["id"]) + str(data["checksum"]) # 强制保存 call_command_service_with_header_jwt(self.env, {"key": key, "c": "forcesave"}) # 获取用户 payload_info_cmd = {"key": key, "c": "info"} ol_info = call_command_service_with_header_jwt(self.env, payload_info_cmd) # 强制离线 if ol_info.get("error") == 0: call_command_service_with_header_jwt(self.env, {"key": key, "c": "drop", "users": ol_info.get('users')}) time.sleep(2) except Exception as e: _logger.error(f"强制onlyoffice用户离线异常:{e.args}") pass