# -*- coding: utf-8 -*- import os import sys import subprocess import logging from odoo import models, fields from odoo.modules.module import get_module_path _logger = logging.getLogger(__name__) class GameStoryVolume(models.Model): _name = 'game.story.volume' _description = '小说卷' _order = 'sequence, id' _rec_name = 'name' name = fields.Char(string='卷名', required=True, index=True) sequence = fields.Integer(string='序号', default=10, index=True) intro = fields.Html(string='卷首语') chapter_ids = fields.One2many('game.story.chapter', 'volume_id', string='章节') def action_sync_novel(self): """由定时任务(ir.cron)调用:把 novel/ 下的 Markdown 增量同步进数据库。 走独立同步脚本(novel/sync_novel.py),单一实现来源。 注意:脚本依赖 venv 的 psycopg2,而 Odoo 可能跑在系统 Python 上, 因此显式使用项目 venv 的 python 执行,而非 sys.executable。""" base = get_module_path('game_base') script = os.path.normpath(os.path.join(base, '..', '..', 'novel', 'sync_novel.py')) if not os.path.exists(script): _logger.warning('小说同步脚本不存在: %s', script) return # 优先用项目 venv 的 python(自带 psycopg2);否则退化为当前解释器 venv_py = os.path.normpath(os.path.join(base, '..', '..', '..', '.venv', 'Scripts', 'python.exe')) python = venv_py if os.path.exists(venv_py) else sys.executable try: proc = subprocess.run([python, script], capture_output=True, text=True, timeout=180) if proc.returncode != 0: _logger.error('小说同步失败(%s): %s', proc.returncode, (proc.stderr or '')[-2000:]) else: last = (proc.stdout or '').strip().splitlines() _logger.info('小说同步完成: %s', last[-1] if last else 'ok') except Exception as e: _logger.exception('小说同步异常: %s', e) class GameStoryChapter(models.Model): _name = 'game.story.chapter' _description = '小说章节' _order = 'volume_id, sequence, id' _rec_name = 'name' volume_id = fields.Many2one('game.story.volume', string='所属卷', required=True, ondelete='cascade', index=True) name = fields.Char(string='章名', required=True, index=True) sequence = fields.Integer(string='序号', default=10, index=True) body_html = fields.Html(string='正文')