File size: 3,871 Bytes
67aa1ca
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
"""Tipos compartidos, enumeraciones y objetos de valor embebidos.

Estos componentes se reutilizan tanto en los modelos de dominio
(:mod:`app.models`) como en los esquemas de la API (:mod:`app.schemas`),
manteniendo el sistema genérico y fácil de extender.
"""

from __future__ import annotations

from datetime import datetime, timezone
from enum import Enum
from typing import Annotated

from pydantic import BaseModel, BeforeValidator, ConfigDict, EmailStr, Field

# ---------------------------------------------------------------------------
# Identificadores
# ---------------------------------------------------------------------------

# El ``_id`` de MongoDB (ObjectId) se serializa siempre como cadena.
PyObjectId = Annotated[str, BeforeValidator(str)]

# Patrón de hora en formato 24h "HH:MM".
_HORA_PATTERN = r"^([01]\d|2[0-3]):[0-5]\d$"


def utcnow() -> datetime:
    """Devuelve la fecha y hora actual en UTC (con zona horaria)."""
    return datetime.now(timezone.utc)


# ---------------------------------------------------------------------------
# Enumeraciones
# ---------------------------------------------------------------------------


class TipoItem(str, Enum):
    """Tipo de item ofertado por un negocio."""

    menu = "menu"
    servicio = "servicio"
    producto = "producto"


class DiaSemana(str, Enum):
    """Días de la semana para los horarios de atención."""

    lunes = "lunes"
    martes = "martes"
    miercoles = "miercoles"
    jueves = "jueves"
    viernes = "viernes"
    sabado = "sabado"
    domingo = "domingo"


# ---------------------------------------------------------------------------
# Objetos de valor embebidos
# ---------------------------------------------------------------------------


class Telefono(BaseModel):
    """Número de teléfono de un negocio."""

    tipo: str = Field(default="principal", max_length=40)
    numero: str = Field(min_length=1, max_length=40)


class Correo(BaseModel):
    """Correo electrónico de contacto de un negocio."""

    tipo: str = Field(default="principal", max_length=40)
    correo: EmailStr


class RedSocial(BaseModel):
    """Enlace a una red social del negocio."""

    tipo: str = Field(min_length=1, max_length=40)
    url: str = Field(min_length=1, max_length=2048)


class Direccion(BaseModel):
    """Dirección física del negocio."""

    direccion: str = Field(min_length=1, max_length=512)
    referencias: str | None = Field(default=None, max_length=512)


class Ubicacion(BaseModel):
    """Coordenadas geográficas del negocio."""

    latitud: float = Field(ge=-90, le=90)
    longitud: float = Field(ge=-180, le=180)


class Horario(BaseModel):
    """Horario de atención para un día concreto."""

    dia: DiaSemana
    apertura: str = Field(pattern=_HORA_PATTERN)
    cierre: str = Field(pattern=_HORA_PATTERN)


class Imagen(BaseModel):
    """Imagen asociada a un negocio."""

    url: str = Field(min_length=1, max_length=2048)
    principal: bool = False


class ImagenItem(BaseModel):
    """Imagen asociada a un item."""

    url: str = Field(min_length=1, max_length=2048)


# ---------------------------------------------------------------------------
# Modelo base de documentos
# ---------------------------------------------------------------------------


class MongoModel(BaseModel):
    """Base para los modelos que representan documentos de MongoDB.

    Mapea el ``_id`` de Mongo al campo ``id`` y lo expone como cadena.
    """

    model_config = ConfigDict(
        populate_by_name=True,
        use_enum_values=True,
        arbitrary_types_allowed=True,
        json_schema_extra={"description": "Documento almacenado en MongoDB."},
    )

    # Lee el ``_id`` de Mongo y lo expone como ``id`` (cadena) en la salida.
    id: PyObjectId | None = Field(
        default=None, alias="_id", serialization_alias="id"
    )