231 lines
7.2 KiB
Python
231 lines
7.2 KiB
Python
"""Magic: The Gathering taxonomy models for cards and faceting."""
|
|
|
|
import re
|
|
|
|
from odoo import _, api, fields, models
|
|
from odoo.exceptions import UserError
|
|
|
|
|
|
class MvdTcgMtgTaxonomyMixin(models.AbstractModel):
|
|
"""Share technical code handling across MTG taxonomy models."""
|
|
|
|
_name = "mvd.tcg.mtg.taxonomy.mixin"
|
|
_description = "MTG Taxonomy Technical Code Mixin"
|
|
|
|
@api.model
|
|
def _mvd_tcg_generate_code(self, name):
|
|
"""Return a slug-like technical code for one taxonomy name."""
|
|
return re.sub(r"[^a-z0-9]+", "_", (name or "").strip().lower()).strip("_") or "item"
|
|
|
|
@api.model
|
|
def _mvd_tcg_get_unique_code(self, name):
|
|
"""Return a unique technical code for one taxonomy record name."""
|
|
base_code = self._mvd_tcg_generate_code(name)
|
|
existing_codes = set(self.search([]).mapped("code"))
|
|
if base_code not in existing_codes:
|
|
return base_code
|
|
suffix = 2
|
|
while f"{base_code}_{suffix}" in existing_codes:
|
|
suffix += 1
|
|
return f"{base_code}_{suffix}"
|
|
|
|
def _mvd_tcg_can_edit_code(self):
|
|
"""Return whether the current user may edit taxonomy codes."""
|
|
return self.env.is_superuser() or any(
|
|
self.env.user.has_group(xmlid)
|
|
for xmlid in (
|
|
"mvd_tcg_base.mvd_tcg_base_group_administrator",
|
|
"base.group_system",
|
|
)
|
|
)
|
|
|
|
@api.model_create_multi
|
|
def create(self, vals_list):
|
|
"""Generate missing technical codes for manually created taxonomy records."""
|
|
prepared_vals_list = []
|
|
for vals in vals_list:
|
|
prepared_vals = dict(vals)
|
|
if not prepared_vals.get("code"):
|
|
prepared_vals["code"] = self._mvd_tcg_get_unique_code(
|
|
prepared_vals.get("name")
|
|
)
|
|
prepared_vals_list.append(prepared_vals)
|
|
return super().create(prepared_vals_list)
|
|
|
|
def write(self, vals):
|
|
"""Protect taxonomy codes from normal business edits."""
|
|
if "code" in vals and not self.env.context.get("mvd_tcg_bypass_taxonomy_code_write"):
|
|
if not self._mvd_tcg_can_edit_code():
|
|
raise UserError(
|
|
_(
|
|
"MTG taxonomy codes are technical identifiers and can only be "
|
|
"changed by TCG administrators."
|
|
)
|
|
)
|
|
return super().write(vals)
|
|
|
|
|
|
class MvdTcgMtgRarity(models.Model):
|
|
"""Store normalized MTG rarity records."""
|
|
|
|
_name = "mvd.tcg.mtg.rarity"
|
|
_inherit = "mvd.tcg.mtg.taxonomy.mixin"
|
|
_description = "MTG Rarity"
|
|
_order = "sequence, name, id"
|
|
|
|
name = fields.Char(required=True, translate=True, index="trigram")
|
|
code = fields.Char(required=True, index=True)
|
|
active = fields.Boolean(default=True)
|
|
sequence = fields.Integer(default=10)
|
|
card_ids = fields.One2many("mvd.tcg.card", "mtg_rarity_id")
|
|
|
|
_code_unique = models.Constraint(
|
|
"UNIQUE (code)",
|
|
"The MTG rarity code must be unique.",
|
|
)
|
|
|
|
|
|
class MvdTcgMtgColor(models.Model):
|
|
"""Store normalized MTG colors for faceting and card metadata."""
|
|
|
|
_name = "mvd.tcg.mtg.color"
|
|
_inherit = "mvd.tcg.mtg.taxonomy.mixin"
|
|
_description = "MTG Color"
|
|
_order = "sequence, name, id"
|
|
|
|
name = fields.Char(required=True, translate=True, index="trigram")
|
|
code = fields.Char(required=True, index=True)
|
|
active = fields.Boolean(default=True)
|
|
sequence = fields.Integer(default=10)
|
|
card_ids = fields.Many2many(
|
|
"mvd.tcg.card",
|
|
"mvd_tcg_card_mtg_color_rel",
|
|
"color_id",
|
|
"card_id",
|
|
)
|
|
|
|
_code_unique = models.Constraint(
|
|
"UNIQUE (code)",
|
|
"The MTG color code must be unique.",
|
|
)
|
|
|
|
|
|
class MvdTcgMtgCardType(models.Model):
|
|
"""Store normalized MTG card types for faceting and grouping."""
|
|
|
|
_name = "mvd.tcg.mtg.card.type"
|
|
_inherit = "mvd.tcg.mtg.taxonomy.mixin"
|
|
_description = "MTG Card Type"
|
|
_order = "sequence, name, id"
|
|
|
|
name = fields.Char(required=True, translate=True, index="trigram")
|
|
code = fields.Char(required=True, index=True)
|
|
active = fields.Boolean(default=True)
|
|
sequence = fields.Integer(default=10)
|
|
card_ids = fields.Many2many(
|
|
"mvd.tcg.card",
|
|
"mvd_tcg_card_mtg_card_type_rel",
|
|
"type_id",
|
|
"card_id",
|
|
)
|
|
|
|
_code_unique = models.Constraint(
|
|
"UNIQUE (code)",
|
|
"The MTG card type code must be unique.",
|
|
)
|
|
|
|
|
|
class MvdTcgMtgKeyword(models.Model):
|
|
"""Store normalized MTG keywords imported from Scryfall."""
|
|
|
|
_name = "mvd.tcg.mtg.keyword"
|
|
_inherit = "mvd.tcg.mtg.taxonomy.mixin"
|
|
_description = "MTG Keyword"
|
|
_order = "sequence, name, id"
|
|
|
|
name = fields.Char(required=True, translate=True, index="trigram")
|
|
code = fields.Char(required=True, index=True)
|
|
active = fields.Boolean(default=True)
|
|
sequence = fields.Integer(default=10)
|
|
card_ids = fields.Many2many(
|
|
"mvd.tcg.card",
|
|
"mvd_tcg_card_mtg_keyword_rel",
|
|
"keyword_id",
|
|
"card_id",
|
|
)
|
|
|
|
_code_unique = models.Constraint(
|
|
"UNIQUE (code)",
|
|
"The MTG keyword code must be unique.",
|
|
)
|
|
|
|
|
|
class MvdTcgMtgFormat(models.Model):
|
|
"""Store normalized MTG formats for legality information."""
|
|
|
|
_name = "mvd.tcg.mtg.format"
|
|
_inherit = "mvd.tcg.mtg.taxonomy.mixin"
|
|
_description = "MTG Format"
|
|
_order = "sequence, name, id"
|
|
|
|
name = fields.Char(required=True, translate=True, index="trigram")
|
|
code = fields.Char(required=True, index=True)
|
|
active = fields.Boolean(default=True)
|
|
sequence = fields.Integer(default=10)
|
|
legality_ids = fields.One2many("mvd.tcg.mtg.card.legality", "format_id")
|
|
|
|
_code_unique = models.Constraint(
|
|
"UNIQUE (code)",
|
|
"The MTG format code must be unique.",
|
|
)
|
|
|
|
|
|
class MvdTcgMtgFinish(models.Model):
|
|
"""Store normalized MTG finishes such as foil and etched."""
|
|
|
|
_name = "mvd.tcg.mtg.finish"
|
|
_inherit = "mvd.tcg.mtg.taxonomy.mixin"
|
|
_description = "MTG Finish"
|
|
_order = "sequence, name, id"
|
|
|
|
name = fields.Char(required=True, translate=True, index="trigram")
|
|
code = fields.Char(required=True, index=True)
|
|
active = fields.Boolean(default=True)
|
|
sequence = fields.Integer(default=10)
|
|
card_ids = fields.Many2many(
|
|
"mvd.tcg.card",
|
|
"mvd_tcg_card_mtg_finish_rel",
|
|
"finish_id",
|
|
"card_id",
|
|
)
|
|
|
|
_code_unique = models.Constraint(
|
|
"UNIQUE (code)",
|
|
"The MTG finish code must be unique.",
|
|
)
|
|
|
|
|
|
class MvdTcgMtgPlatform(models.Model):
|
|
"""Store normalized MTG game platforms such as paper and Arena."""
|
|
|
|
_name = "mvd.tcg.mtg.platform"
|
|
_inherit = "mvd.tcg.mtg.taxonomy.mixin"
|
|
_description = "MTG Platform"
|
|
_order = "sequence, name, id"
|
|
|
|
name = fields.Char(required=True, translate=True, index="trigram")
|
|
code = fields.Char(required=True, index=True)
|
|
active = fields.Boolean(default=True)
|
|
sequence = fields.Integer(default=10)
|
|
card_ids = fields.Many2many(
|
|
"mvd.tcg.card",
|
|
"mvd_tcg_card_mtg_platform_rel",
|
|
"platform_id",
|
|
"card_id",
|
|
)
|
|
|
|
_code_unique = models.Constraint(
|
|
"UNIQUE (code)",
|
|
"The MTG platform code must be unique.",
|
|
)
|