# addons/itsulu_blog_publisher/tests/factories.py """ Test data factory for itsulu_blog_publisher. Use this instead of demo data. Never rely on records seeded in another test. """ class BlogPublisherFactory: def __init__(self, env): self.env = env self._counter = 0 def _seq(self): self._counter += 1 return self._counter # ------------------------------------------------------------------ # # Core Odoo blog records # # ------------------------------------------------------------------ # def blog(self, **kw): defaults = { 'name': f'Test Blog {self._seq()}', } defaults.update(kw) return self.env['blog.blog'].create(defaults) def blog_tag(self, **kw): defaults = { 'name': f'Test Tag {self._seq()}', } defaults.update(kw) return self.env['blog.tag'].create(defaults) def blog_post(self, blog=None, **kw): blog = blog or self.blog() defaults = { 'name': f'Test Post {self._seq()}', 'blog_id': blog.id, 'website_published': False, 'is_published': False, 'body': '
Test body content for blog post.
', 'website_meta_title': '', 'website_meta_description': '', 'website_meta_keywords': '', } defaults.update(kw) return self.env['blog.post'].create(defaults) # ------------------------------------------------------------------ # # itsulu_blog_publisher models # # ------------------------------------------------------------------ # def blog_topic(self, **kw): """itsulu.blog.topic — a planned topic in the queue.""" defaults = { 'name': f'Test Topic {self._seq()}', 'priority': 'normal', 'state': 'pending', 'notes': '', } defaults.update(kw) return self.env['itsulu.blog.topic'].create(defaults) def blog_schedule(self, blog=None, **kw): """itsulu.blog.schedule — a cron slot configuration.""" blog = blog or self.blog() defaults = { 'name': f'Test Schedule {self._seq()}', 'slot': 'morning', 'trigger_time': 8.0, # 08:00 'active': True, 'blog_id': blog.id, 'llm_provider': 'anthropic', 'llm_model': 'claude-sonnet-4-20250514', 'auto_publish': True, } defaults.update(kw) return self.env['itsulu.blog.schedule'].create(defaults) def generation_log(self, blog_post=None, **kw): """itsulu.blog.generation.log — one attempt record.""" defaults = { 'state': 'success', 'trigger_source': 'manual', 'llm_provider': 'anthropic', 'llm_model': 'claude-sonnet-4-20250514', 'tokens_used': 1500, 'duration_seconds': 12.0, 'error_message': '', 'blog_post_id': blog_post.id if blog_post else False, } defaults.update(kw) return self.env['itsulu.blog.generation.log'].create(defaults) def blog_post_social(self, blog_post=None, **kw): """itsulu.blog.post.social — social media copy for one post.""" blog_post = blog_post or self.blog_post() defaults = { 'blog_post_id': blog_post.id, 'twitter_post_a': 'Twitter copy A placeholder.', 'twitter_post_b': 'Twitter copy B placeholder.', 'bluesky_post_a': 'BlueSky copy A placeholder.', 'bluesky_post_b': 'BlueSky copy B placeholder.', 'mastodon_post': 'Mastodon copy placeholder.', 'linkedin_post': 'LinkedIn copy placeholder.', 'sources_referenced': '', } defaults.update(kw) return self.env['itsulu.blog.post.social'].create(defaults)