151 lines
4.6 KiB
Python
151 lines
4.6 KiB
Python
"""Game-neutral card reference models."""
|
|
|
|
from odoo import _, api, fields, models
|
|
from odoo.exceptions import UserError
|
|
|
|
|
|
class MvdTcgCard(models.Model):
|
|
"""Represent a game-neutral card reference entry."""
|
|
|
|
_name = "mvd.tcg.card"
|
|
_description = "TCG Card"
|
|
_inherit = "image.mixin"
|
|
_order = "game_id, sequence, name, id"
|
|
|
|
active = fields.Boolean(default=True)
|
|
sequence = fields.Integer(default=10)
|
|
state = fields.Selection(
|
|
selection=[
|
|
("draft", "Draft"),
|
|
("validated", "Validated"),
|
|
],
|
|
default="draft",
|
|
required=True,
|
|
index=True,
|
|
copy=False,
|
|
)
|
|
name = fields.Char(required=True, translate=True, index="trigram")
|
|
game_id = fields.Many2one(
|
|
"mvd.tcg.game",
|
|
required=True,
|
|
index=True,
|
|
ondelete="restrict",
|
|
)
|
|
external_ref = fields.Char(
|
|
index=True,
|
|
help="Adapter-specific identifier for this card reference.",
|
|
)
|
|
description = fields.Html(
|
|
translate=True,
|
|
)
|
|
note = fields.Text(
|
|
translate=True,
|
|
help="Internal neutral note stored on the card reference.",
|
|
)
|
|
|
|
_external_ref_unique = models.Constraint(
|
|
"UNIQUE (game_id, external_ref)",
|
|
"The external reference must be unique per game.",
|
|
)
|
|
|
|
def _mvd_tcg_can_edit_external_ref(self):
|
|
"""Return whether the current user may edit adapter reference ids.
|
|
|
|
Returns:
|
|
bool: ``True`` for TCG administrators and system users.
|
|
"""
|
|
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):
|
|
"""Protect technical external references during card creation.
|
|
|
|
Args:
|
|
vals_list: Standard ORM payloads for new cards.
|
|
|
|
Returns:
|
|
Model: Created card records.
|
|
"""
|
|
prepared_vals_list = []
|
|
for vals in vals_list:
|
|
prepared_vals = dict(vals)
|
|
if (
|
|
prepared_vals.get("external_ref")
|
|
and not self.env.context.get("mvd_tcg_bypass_external_ref_write")
|
|
and not self._mvd_tcg_can_edit_external_ref()
|
|
):
|
|
raise UserError(
|
|
_(
|
|
"Adapter reference ids can only be set by TCG administrators."
|
|
)
|
|
)
|
|
prepared_vals_list.append(prepared_vals)
|
|
return super().create(prepared_vals_list)
|
|
|
|
def write(self, vals):
|
|
"""Prevent accidental edits on validated reference cards.
|
|
|
|
Args:
|
|
vals: Field values to update.
|
|
|
|
Returns:
|
|
bool: Result of the underlying ORM write.
|
|
|
|
Raises:
|
|
UserError: If a validated card is modified outside the allowed paths.
|
|
"""
|
|
if (
|
|
"external_ref" in vals
|
|
and not self.env.context.get("mvd_tcg_bypass_external_ref_write")
|
|
and not self._mvd_tcg_can_edit_external_ref()
|
|
):
|
|
raise UserError(
|
|
_(
|
|
"Adapter reference ids can only be changed by TCG administrators."
|
|
)
|
|
)
|
|
if not self.env.context.get("mvd_tcg_bypass_validated_write"):
|
|
validated_cards = self.filtered(lambda card: card.state == "validated")
|
|
is_reset_to_draft = set(vals) == {"state"} and vals.get("state") == "draft"
|
|
if validated_cards and not is_reset_to_draft:
|
|
raise UserError(
|
|
_(
|
|
"Validated cards are read-only. Reset the card to Draft first "
|
|
"if you really want to edit it."
|
|
)
|
|
)
|
|
return super().write(vals)
|
|
|
|
def action_validate(self):
|
|
"""Lock the current cards as validated reference data.
|
|
|
|
Returns:
|
|
bool: ``True`` when the operation completed.
|
|
"""
|
|
self.write({"state": "validated"})
|
|
return True
|
|
|
|
def action_reset_to_draft(self):
|
|
"""Move the current cards back into editable draft state.
|
|
|
|
Returns:
|
|
bool: ``True`` when the operation completed.
|
|
"""
|
|
self.write({"state": "draft"})
|
|
return True
|
|
|
|
def _mvd_tcg_get_deck_image_binary(self):
|
|
"""Return the preferred card image for deck previews.
|
|
|
|
Returns:
|
|
str | bool: Base64 image data for deck-related previews.
|
|
"""
|
|
self.ensure_one()
|
|
return self.image_512 or self.image_1920 or False
|