Help us shape the future of Go! Take the 2026 Go Developer Survey

businesscalendar

package module
v0.5.29 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 29, 2026 License: MIT Imports: 11 Imported by: 3

README

business_calendar

El calendario institucional para el ecosistema Velty: cuándo está abierto el establecimiento y cuándo está cerrado, independientemente del horario de cualquier profesional.

Posee tres cosas:

  1. Horarios de atención (business_hours) — la ventana semanal de apertura, una fila por día de la semana.
  2. Feriados (holidays) — cierres fechados con un origen legal/administrativo, editables en tiempo de ejecución (un nuevo feriado aparece por ley; nadie recompila).
  3. Cierres (closures) — cierres fechados con un origen local (mantenimiento, un evento).

No posee la agenda de ningún profesional. appointment_booking posee eso y consume este módulo a través del contrato de solo lectura Reader.

Reemplaza al archivado github.com/veltylabs/business_hours, cuya codificación de texto de hora de reloj ("HH:MM") se corrige aquí a 24h clock string (HH:MM) —la misma codificación que usa appointment_booking para los bloques de trabajo— y cuyos nombres de días en español prefijados han desaparecido (la traducción vive en la aplicación consumidora).

Inicio rápido

// En tiempo de despliegue, ejecutar las migraciones de esquema:
err := migrate.Migrate(conn, ddlCompiler)
if err != nil { /* ... */ }

// Al iniciar el proceso:
cal, err := businesscalendar.New(db, businesscalendar.Deps{
    IDs: idGenerator, // model.IDGenerator — requerido
    Publisher: broker, // events.Publisher — opcional; nil deshabilita la publicación
})
if err != nil { /* ... */ }

cal.MountOperations(opRegistry) // router.OpRegistry

reader := businesscalendar.Reader(cal) // el puerto que consume un módulo vecino
bounds, err := reader.GetDayBounds(dateMidnightUTC)

New asume que el esquema de la base de datos (business_hours, holiday, closure) ya existe. La aplicación que despliega llama a migrate.Migrate(conn, compiler) una vez, en tiempo de despliegue.

Operaciones (Ops)

Op Recurso Acción Args
list_business_hours business_hours read —
upsert_business_hours business_hours create | update day_of_week, open_min, close_min, is_open, notes
get_day_bounds business_hours read date (medianoche UTC, segundos)
list_holidays holiday read —
add_holiday holiday create specific_date, name, notes
remove_holiday holiday delete id
list_closures closure read —
add_closure closure create specific_date, reason
remove_closure closure delete id

API: BankDayAfter(desde, días): día hábil bancario N días después (lunes a viernes sin feriados; el horario de la clínica no cuenta).

Los tiempos se almacenan como 24h clock string (HH:MM); get_day_bounds responde "si el establecimiento está abierto esta fecha y entre qué minutos".

Para facilitar la lectura por parte de asistentes de IA, list_business_hours incluye campos legibles adicionales en cada fila ("day":"Tuesday", "opens":"08:00", "closes":"18:00"). Por ejemplo:

{
  "id": "id-1",
  "day_of_week": 2,
  "open_min": 480,
  "close_min": 1080,
  "is_open": true,
  "notes": "",
  "updated_at": 1789441200,
  "day": "Tuesday",
  "opens": "08:00",
  "closes": "18:00"
}

Los asistentes leen horas en formato HH:MM y nombres de días en inglés mejor que conteos de minutos.

El puerto Reader

interfaces.go declara el puerto de solo lectura del que depende un vecino:

type Reader interface {
    GetDayBounds(date time.Unix) (DayBounds, error)
}

*Module lo satisface estructuralmente. DayBounds lleva Open, OpenMin, CloseMin y ClosedBy —un ClosedReason que nombra el origen (WEEKLY | HOLIDAY | CLOSURE). Precedencia de resolución: Cierre local > Feriado > Regla semanal.

Eventos

Cada escritura exitosa publica EventCalendarChanged (business.calendar.changed) con un CalendarChangedPayload tipado que indica qué cambió, su rango de fechas afectado y Closed —la dirección. Closed es true solo cuando el cambio cierra el tiempo (un feriado agregado, horarios reducidos), que es la única dirección que puede invalidar una reserva existente.

Claves de traducción

Este módulo no renderiza ningún lenguaje humano codificado de forma rígida. Introduce estas claves canónicas en inglés, traducidas por la aplicación consumidora a través de webtyp.com/fmt/lang: Business hours, Holidays, Closures, Open, Closed, más los siete nombres de días de la semana de webtyp.com/date (date.WeekdayName).

View and demo

The module exports its own UI view, seed demo data, and executable WASM demo shell:

  • ui/ — exports ui.ID, ui.Label, and ui.Screens(caller router.Caller) []view.Screen.
  • seed/ — seed.Load(module) writes initial weekly business hours and Chilean holidays through domain service methods.
  • web/ — runnable in-browser demo (browser.go). Run webtyp at the repository root to launch the demo (in-browser, in-memory, no login).

Archivos clave

Archivo Rol
model.go Definiciones (registros + args de transporte), errores, tópico/payload de eventos
model_orm.go Generado por ormc — no editar
module.go Module, Deps, New, métodos de servicio, publicación de eventos
migrate/ Migración de esquema en tiempo de despliegue (Migrate)
interfaces.go El puerto Reader + precedencia de GetDayBounds
ops.go Constantes de Op, MountOperations, manejadores
view.go Tres presentadores (NewBusinessHoursView, NewHolidaysView, NewClosuresView)
ui/ Vista UI del módulo (ui.Screens(caller router.Caller) []view.Screen, ui.ID, ui.Label)
seed/ Datos semilla de demostración (seed.Load)
web/ Demo ejecutable en el navegador (web/browser.go)
tests/ Pruebas de casos de uso, pruebas de ops, conformidad (sobre storage/mem + router/mock/loopback)

Documentación


Este módulo forma parte de la colección de módulos de Velty Labs.

errores por rpc.WriteError; permisos por tabla (model.ResourceOf); guardar/borrar con view.MountSave/MountDelete; claves foráneas declaradas.

Documentation

Index

Constants

View Source
const (
	ErrNotFound       model.NotFound = "business_calendar: record not found"
	ErrInvalidDay     model.Invalid  = "business_calendar: day_of_week must be 0..6"
	ErrInvalidWeekday model.Invalid  = "business_calendar: day of week must be 0..6"
	ErrInvalidMinutes model.Invalid  = "business_calendar: minutes must be 0..1439 and open_min < close_min"
	ErrDuplicateDate  model.Conflict = "business_calendar: a record already exists for that date"
	ErrCannotRead     model.Invalid  = "business_calendar: cannot read the request"
)

domainError is the concrete type of this package's sentinel errors. Code compares them by asserting this type and comparing the value: == between two error values compiles, under TinyGo, to runtime.interfaceEqual, which pulls internal/reflectlite into the wasm binary.

View Source
const (
	CalendarKindBusinessHours = "BUSINESS_HOURS"
	CalendarKindHoliday       = "HOLIDAY"
	CalendarKindClosure       = "CLOSURE"
)

Payload kinds — the ONLY place these literals live. CalendarChangedPayload.Kind carries one of them.

View Source
const (
	OpListBusinessHours   = "list_business_hours"
	OpUpsertBusinessHours = "upsert_business_hours"
	OpListHolidays        = "list_holidays"
	OpAddHoliday          = "add_holiday"
	OpRemoveHoliday       = "remove_holiday"
	OpListClosures        = "list_closures"
	OpAddClosure          = "add_closure"
	OpRemoveClosure       = "remove_closure"
	OpGetDayBounds        = "get_day_bounds"

	DescListBusinessHours   = "" /* 143-byte string literal not displayed */
	DescUpsertBusinessHours = "Crea o cambia el horario de atención de un día de la semana."
	DescGetDayBounds        = "Si el consultorio abre en una fecha y en qué minutos del día, considerando feriados y cierres."
	DescListHolidays        = "Feriados registrados del consultorio."
	DescAddHoliday          = "Registra un feriado: el consultorio no atiende esa fecha."
	DescRemoveHoliday       = "Elimina un feriado registrado."
	DescListClosures        = "Cierres extraordinarios del consultorio (fechas u horas sin atención)."
	DescAddClosure          = "Registra un cierre extraordinario."
	DescRemoveClosure       = "Elimina un cierre extraordinario."
)
View Source
const ErrNegativeDays = model.Invalid("business_calendar: days must be zero or more")

ErrNegativeDays: BankDayAfter con días negativos.

View Source
const EventCalendarChanged = "business.calendar.changed"

EventCalendarChanged fires on every write. appointment_booking subscribes so a professional's editor reflects widened hours without a recompile (CU-03), a new holiday closes the day for everyone (CU-04), and reservations already booked on a day that just became closed are recomputed into conflict. Ejemplo: topic := businesscalendar.EventCalendarChanged

View Source
const ModelName = "business_calendar"

ModelName es la identidad de este módulo: mcp.HarvestOps califica cada operación como "business_calendar.<name>" en la red — la calificación que hace que su propio "get_day_bounds" sea distinto de la operación de appointment_booking con el mismo nombre base (la colisión que este mecanismo hace irrepresentable). Los tres constructores NewXView de view.go pasan esta misma constante como view.Ops.Module. Ejemplo: name := cal.ModelName()

Variables

View Source
var BusinessHoursModel = model.Definition{
	Name: "business_hours",
	Fields: model.Fields{
		{Name: "id", Type: model.Text(), DB: &model.FieldDB{PK: true}},
		{Name: "day_of_week", Type: input.Number(), Label: "Day of week", NotNull: true, DB: &model.FieldDB{Unique: true}, Item: model.ItemLabel},
		{Name: "open_min", Type: input.Hour(), Label: "Opens at", NotNull: true, Item: model.ItemDescription},
		{Name: "close_min", Type: input.Hour(), Label: "Closes at", NotNull: true, Item: model.ItemDescription},
		{Name: "is_open", Type: input.Checkbox(), Label: "Open", NotNull: true, Item: model.ItemDescription},
		{Name: "notes", Type: input.Textarea(), Label: "Notes", Item: model.ItemDescription},
		{Name: "updated_at", Type: model.NanoTime(), NotNull: true},
	},
}

BusinessHoursModel: one row per day of week. day_of_week is unique — this module never writes more than seven rows.

Times are MINUTES FROM MIDNIGHT (0..1439), the same encoding appointment_booking uses for work blocks. The archived business_hours module stored clock-time text and forced a conversion at the one boundary that has to compare the two; the encoding is fixed here instead.

Renderable fields use input.* widgets (Storage() unchanged: input.Number() is still FieldInt, input.Checkbox() still FieldBool, input.Textarea() still FieldText) — a plain model.Kind is not a form.Field.Type (see form-codegen skill): crudview.New called form.New(Presenter.Record(), ...) against a record with zero renderable fields and panicked BuildClient for every module in the registry, not just this one. Ejemplo: var bh BusinessHours

View Source
var BusinessHours_ = struct {
	Id        string
	DayOfWeek string
	OpenMin   string
	CloseMin  string
	IsOpen    string
	Notes     string
	UpdatedAt string
}{
	Id:        "id",
	DayOfWeek: "day_of_week",
	OpenMin:   "open_min",
	CloseMin:  "close_min",
	IsOpen:    "is_open",
	Notes:     "notes",
	UpdatedAt: "updated_at",
}
View Source
var ClosureModel = model.Definition{
	Name: "closure",
	Fields: model.Fields{
		{Name: "id", Type: model.Text(), DB: &model.FieldDB{PK: true}},
		{Name: "specific_date", Type: input.Number(), Label: "Date", NotNull: true, Item: model.ItemDescription},
		{Name: "reason", Type: input.Text(), Label: "Reason", NotNull: true, Item: model.ItemLabel},
		{Name: "updated_at", Type: model.NanoTime(), NotNull: true},
	},
}

ClosureModel: a dated closure the establishment itself decided (maintenance, an event). Separate from Holiday because the ORIGIN is what the UI shows and what an administrator filters by — collapsing both into one table with a "type" column would make the origin a magic string. Ejemplo: var c Closure

View Source
var Closure_ = struct {
	Id           string
	SpecificDate string
	Reason       string
	UpdatedAt    string
}{
	Id:           "id",
	SpecificDate: "specific_date",
	Reason:       "reason",
	UpdatedAt:    "updated_at",
}
View Source
var GetDayBoundsArgsModel = model.Definition{
	Name: "get_day_bounds_args",
	Fields: model.Fields{
		{Name: "date", Type: model.Int()},
	},
}

Transport-only Args Definitions.

Constraints follow the harness's NotNull semantics: on a base int/bool kind, NotNull rejects the ZERO value (ValidateFields: NotNull && IsZeroPtr), so day_of_week 0 (Sunday), is_open false, or midnight (0 minutes) would be unrepresentable if NotNull were set here. Required ints are therefore enforced as DOMAIN rules in the service (ErrInvalidDay/ErrInvalidMinutes), the single fail-closed chokepoint every write path crosses; NotNull stays only on the text fields where empty is never legal. Ejemplo: var args GetDayBoundsArgs

View Source
var HolidayModel = model.Definition{
	Name: "holiday",
	Fields: model.Fields{
		{Name: "id", Type: model.Text(), DB: &model.FieldDB{PK: true}},
		{Name: "specific_date", Type: input.Number(), Label: "Date", NotNull: true, Item: model.ItemDescription},
		{Name: "name", Type: input.Text(), Label: "Name", NotNull: true, Item: model.ItemLabel},
		{Name: "notes", Type: input.Textarea(), Label: "Notes"},
		{Name: "updated_at", Type: model.NanoTime(), NotNull: true},
	},
}

HolidayModel: a dated closure with a legal/administrative origin. Editable at runtime — a holiday that appears by law must never require a recompile. Ejemplo: var h Holiday

View Source
var Holiday_ = struct {
	Id           string
	SpecificDate string
	Name         string
	Notes        string
	UpdatedAt    string
}{
	Id:           "id",
	SpecificDate: "specific_date",
	Name:         "name",
	Notes:        "notes",
	UpdatedAt:    "updated_at",
}
View Source
var ListClosuresArgsModel = model.Definition{
	Name: "list_closures_args",
	Fields: model.Fields{
		{Name: "from", Type: model.Int()},
		{Name: "to", Type: model.Int()},
	},
}

Ejemplo: var args ListClosuresArgs

View Source
var ListHolidaysArgsModel = model.Definition{
	Name: "list_holidays_args",
	Fields: model.Fields{
		{Name: "from", Type: model.Int()},
		{Name: "to", Type: model.Int()},
	},
}

Ejemplo: var args ListHolidaysArgs

Functions

func NewBusinessHoursView added in v0.0.2

func NewBusinessHoursView(caller router.Caller, opts ...view.Option) view.Presenter

NewBusinessHoursView construye el Presenter de horas semanales.

func NewClosuresView added in v0.0.2

func NewClosuresView(caller router.Caller, opts ...view.Option) view.Presenter

NewClosuresView construye el Presenter de cierres.

func NewHolidaysView added in v0.0.2

func NewHolidaysView(caller router.Caller, opts ...view.Option) view.Presenter

NewHolidaysView construye el Presenter de feriados.

Types

type BusinessHours added in v0.0.2

type BusinessHours struct {
	Id        string
	DayOfWeek int64
	OpenMin   string
	CloseMin  string
	IsOpen    bool
	Notes     string
	UpdatedAt time.Nano
}

func ReadOneBusinessHours added in v0.0.2

func ReadOneBusinessHours(qb *orm.QB, model *BusinessHours) (*BusinessHours, error)

func (*BusinessHours) DecodeFields added in v0.0.2

func (m *BusinessHours) DecodeFields(r model.FieldReader)

func (*BusinessHours) EncodeFields added in v0.0.2

func (m *BusinessHours) EncodeFields(w model.FieldWriter)

func (*BusinessHours) IsNil added in v0.0.2

func (m *BusinessHours) IsNil() bool

func (*BusinessHours) Item added in v0.0.2

func (m *BusinessHours) Item() model.Item

func (*BusinessHours) ModelName added in v0.0.2

func (m *BusinessHours) ModelName() string

func (*BusinessHours) Pointers added in v0.0.2

func (m *BusinessHours) Pointers() []any

func (*BusinessHours) Schema added in v0.0.2

func (m *BusinessHours) Schema() []model.Field

func (*BusinessHours) Validate added in v0.0.2

func (m *BusinessHours) Validate(action byte) error

type BusinessHoursList added in v0.0.2

type BusinessHoursList []*BusinessHours

func ReadAllBusinessHours added in v0.0.2

func ReadAllBusinessHours(qb *orm.QB) (BusinessHoursList, error)

func (*BusinessHoursList) Append added in v0.0.2

func (s *BusinessHoursList) Append() model.Fielder

func (*BusinessHoursList) At added in v0.0.2

func (*BusinessHoursList) DecodeFields added in v0.0.2

func (s *BusinessHoursList) DecodeFields(_ model.FieldReader)

func (*BusinessHoursList) EncodeFields added in v0.0.2

func (s *BusinessHoursList) EncodeFields(_ model.FieldWriter)

func (*BusinessHoursList) IsNil added in v0.0.2

func (s *BusinessHoursList) IsNil() bool

func (*BusinessHoursList) Len added in v0.0.2

func (s *BusinessHoursList) Len() int

type CalendarChangedPayload added in v0.0.2

type CalendarChangedPayload struct {
	// FromDate/ToDate bound the affected dates (midnight UTC seconds).
	// For a holiday or closure both equal that single date. For a business
	// hours change they are 0/0 — a weekly rule has no bounded range, and the
	// subscriber must recompute its whole horizon.
	FromDate int64
	ToDate   int64
	// Kind names what moved, so a subscriber can skip work it does not care
	// about. One of CalendarKindBusinessHours | CalendarKindHoliday |
	// CalendarKindClosure.
	Kind string
	// Closed reports the direction. true when the change CLOSES time (a
	// holiday added, hours narrowed) — the only direction that can invalidate
	// an existing reservation. false when it opens time, which never does.
	Closed bool
}

CalendarChangedPayload says WHAT changed, not merely that something did. A subscriber that only learns "the calendar changed" has to recompute every reservation of every professional; with the range it recomputes a window.

Implements model.Encodable, which events.Event.Payload requires. Ejemplo: var p businesscalendar.CalendarChangedPayload

func (*CalendarChangedPayload) DecodeFields added in v0.0.2

func (p *CalendarChangedPayload) DecodeFields(r model.FieldReader)

func (*CalendarChangedPayload) EncodeFields added in v0.0.2

func (p *CalendarChangedPayload) EncodeFields(w model.FieldWriter)

func (*CalendarChangedPayload) IsNil added in v0.0.2

func (p *CalendarChangedPayload) IsNil() bool

type ClosedReason added in v0.0.2

type ClosedReason string

ClosedReason nombra el origen de un cierre. Los literales de cadena viven SOLAMENTE en estas constantes — nunca en línea en el lugar de llamada. Ejemplo: var reason businesscalendar.ClosedReason = businesscalendar.ClosedHoliday

const (
	ClosedWeekly  ClosedReason = "WEEKLY"  // business_hours says closed that weekday
	ClosedHoliday ClosedReason = "HOLIDAY" // a Holiday row falls on that date
	ClosedLocal   ClosedReason = "CLOSURE" // a Closure row falls on that date
)

type Closure added in v0.0.2

type Closure struct {
	Id           string
	SpecificDate int64
	Reason       string
	UpdatedAt    time.Nano
}

func ReadOneClosure added in v0.0.2

func ReadOneClosure(qb *orm.QB, model *Closure) (*Closure, error)

func (*Closure) DecodeFields added in v0.0.2

func (m *Closure) DecodeFields(r model.FieldReader)

func (*Closure) EncodeFields added in v0.0.2

func (m *Closure) EncodeFields(w model.FieldWriter)

func (*Closure) IsNil added in v0.0.2

func (m *Closure) IsNil() bool

func (*Closure) Item added in v0.0.2

func (m *Closure) Item() model.Item

func (*Closure) ModelName added in v0.0.2

func (m *Closure) ModelName() string

func (*Closure) Pointers added in v0.0.2

func (m *Closure) Pointers() []any

func (*Closure) Schema added in v0.0.2

func (m *Closure) Schema() []model.Field

func (*Closure) Validate added in v0.0.2

func (m *Closure) Validate(action byte) error

type ClosureList added in v0.0.2

type ClosureList []*Closure

func ReadAllClosure added in v0.0.2

func ReadAllClosure(qb *orm.QB) (ClosureList, error)

func (*ClosureList) Append added in v0.0.2

func (s *ClosureList) Append() model.Fielder

func (*ClosureList) At added in v0.0.2

func (s *ClosureList) At(i int) model.Fielder

func (*ClosureList) DecodeFields added in v0.0.2

func (s *ClosureList) DecodeFields(_ model.FieldReader)

func (*ClosureList) EncodeFields added in v0.0.2

func (s *ClosureList) EncodeFields(_ model.FieldWriter)

func (*ClosureList) IsNil added in v0.0.2

func (s *ClosureList) IsNil() bool

func (*ClosureList) Len added in v0.0.2

func (s *ClosureList) Len() int

type DayDetail added in v0.0.4

type DayDetail struct {
	Bounds tinytime.DayBounds
	// ClosedBy nombra por qué el día está cerrado. "" cuando Bounds.Open es true.
	ClosedBy ClosedReason
}

DayDetail es la propia respuesta de este módulo para una fecha: los límites neutrales MÁS el por qué un día cerrado está cerrado. ClosedBy es vocabulario de este módulo y nunca cruza a un vecino — vea Reader a continuación.

Es un modelo de resultado solo de salida: implementa model.Encodable para que la operación get_day_bounds pueda responder con él, y nunca es una tabla de BD. Ejemplo: detail, err := cal.GetDayDetail(date)

func (*DayDetail) EncodeFields added in v0.0.4

func (d *DayDetail) EncodeFields(w model.FieldWriter)

func (*DayDetail) IsNil added in v0.0.4

func (d *DayDetail) IsNil() bool

type Deps added in v0.0.2

type Deps struct {
	IDs       model.IDGenerator
	Publisher events.Publisher
}

Deps lleva los colaboradores inyectados que un módulo nunca debe construir por sí mismo. IDs es obligatorio; Publisher es opcional — nil deshabilita la publicación de eventos de forma silenciosa (no-op). Ejemplo: deps := businesscalendar.Deps{IDs: ids, Publisher: pub}

type GetDayBoundsArgs added in v0.0.2

type GetDayBoundsArgs struct {
	Date int64
}

func (*GetDayBoundsArgs) DecodeFields added in v0.0.2

func (m *GetDayBoundsArgs) DecodeFields(r model.FieldReader)

func (*GetDayBoundsArgs) EncodeFields added in v0.0.2

func (m *GetDayBoundsArgs) EncodeFields(w model.FieldWriter)

func (*GetDayBoundsArgs) IsNil added in v0.0.2

func (m *GetDayBoundsArgs) IsNil() bool

func (*GetDayBoundsArgs) ModelName added in v0.0.2

func (m *GetDayBoundsArgs) ModelName() string

func (*GetDayBoundsArgs) Pointers added in v0.0.2

func (m *GetDayBoundsArgs) Pointers() []any

func (*GetDayBoundsArgs) Schema added in v0.0.2

func (m *GetDayBoundsArgs) Schema() []model.Field

func (*GetDayBoundsArgs) Validate added in v0.0.2

func (m *GetDayBoundsArgs) Validate(action byte) error

type GetDayBoundsArgsList added in v0.0.2

type GetDayBoundsArgsList []*GetDayBoundsArgs

func (*GetDayBoundsArgsList) Append added in v0.0.2

func (s *GetDayBoundsArgsList) Append() model.Fielder

func (*GetDayBoundsArgsList) At added in v0.0.2

func (*GetDayBoundsArgsList) DecodeFields added in v0.0.2

func (s *GetDayBoundsArgsList) DecodeFields(_ model.FieldReader)

func (*GetDayBoundsArgsList) EncodeFields added in v0.0.2

func (s *GetDayBoundsArgsList) EncodeFields(_ model.FieldWriter)

func (*GetDayBoundsArgsList) IsNil added in v0.0.2

func (s *GetDayBoundsArgsList) IsNil() bool

func (*GetDayBoundsArgsList) Len added in v0.0.2

func (s *GetDayBoundsArgsList) Len() int

type Holiday added in v0.0.2

type Holiday struct {
	Id           string
	SpecificDate int64
	Name         string
	Notes        string
	UpdatedAt    time.Nano
}

func ReadOneHoliday added in v0.0.2

func ReadOneHoliday(qb *orm.QB, model *Holiday) (*Holiday, error)

func (*Holiday) DecodeFields added in v0.0.2

func (m *Holiday) DecodeFields(r model.FieldReader)

func (*Holiday) EncodeFields added in v0.0.2

func (m *Holiday) EncodeFields(w model.FieldWriter)

func (*Holiday) IsNil added in v0.0.2

func (m *Holiday) IsNil() bool

func (*Holiday) Item added in v0.0.2

func (m *Holiday) Item() model.Item

func (*Holiday) ModelName added in v0.0.2

func (m *Holiday) ModelName() string

func (*Holiday) Pointers added in v0.0.2

func (m *Holiday) Pointers() []any

func (*Holiday) Schema added in v0.0.2

func (m *Holiday) Schema() []model.Field

func (*Holiday) Validate added in v0.0.2

func (m *Holiday) Validate(action byte) error

type HolidayList added in v0.0.2

type HolidayList []*Holiday

func ReadAllHoliday added in v0.0.2

func ReadAllHoliday(qb *orm.QB) (HolidayList, error)

func (*HolidayList) Append added in v0.0.2

func (s *HolidayList) Append() model.Fielder

func (*HolidayList) At added in v0.0.2

func (s *HolidayList) At(i int) model.Fielder

func (*HolidayList) DecodeFields added in v0.0.2

func (s *HolidayList) DecodeFields(_ model.FieldReader)

func (*HolidayList) EncodeFields added in v0.0.2

func (s *HolidayList) EncodeFields(_ model.FieldWriter)

func (*HolidayList) IsNil added in v0.0.2

func (s *HolidayList) IsNil() bool

func (*HolidayList) Len added in v0.0.2

func (s *HolidayList) Len() int

type ListClosuresArgs added in v0.0.2

type ListClosuresArgs struct {
	From int64
	To   int64
}

func (*ListClosuresArgs) DecodeFields added in v0.0.2

func (m *ListClosuresArgs) DecodeFields(r model.FieldReader)

func (*ListClosuresArgs) EncodeFields added in v0.0.2

func (m *ListClosuresArgs) EncodeFields(w model.FieldWriter)

func (*ListClosuresArgs) IsNil added in v0.0.2

func (m *ListClosuresArgs) IsNil() bool

func (*ListClosuresArgs) ModelName added in v0.0.2

func (m *ListClosuresArgs) ModelName() string

func (*ListClosuresArgs) Pointers added in v0.0.2

func (m *ListClosuresArgs) Pointers() []any

func (*ListClosuresArgs) Schema added in v0.0.2

func (m *ListClosuresArgs) Schema() []model.Field

func (*ListClosuresArgs) Validate added in v0.0.2

func (m *ListClosuresArgs) Validate(action byte) error

type ListClosuresArgsList added in v0.0.2

type ListClosuresArgsList []*ListClosuresArgs

func (*ListClosuresArgsList) Append added in v0.0.2

func (s *ListClosuresArgsList) Append() model.Fielder

func (*ListClosuresArgsList) At added in v0.0.2

func (*ListClosuresArgsList) DecodeFields added in v0.0.2

func (s *ListClosuresArgsList) DecodeFields(_ model.FieldReader)

func (*ListClosuresArgsList) EncodeFields added in v0.0.2

func (s *ListClosuresArgsList) EncodeFields(_ model.FieldWriter)

func (*ListClosuresArgsList) IsNil added in v0.0.2

func (s *ListClosuresArgsList) IsNil() bool

func (*ListClosuresArgsList) Len added in v0.0.2

func (s *ListClosuresArgsList) Len() int

type ListHolidaysArgs added in v0.0.2

type ListHolidaysArgs struct {
	From int64
	To   int64
}

func (*ListHolidaysArgs) DecodeFields added in v0.0.2

func (m *ListHolidaysArgs) DecodeFields(r model.FieldReader)

func (*ListHolidaysArgs) EncodeFields added in v0.0.2

func (m *ListHolidaysArgs) EncodeFields(w model.FieldWriter)

func (*ListHolidaysArgs) IsNil added in v0.0.2

func (m *ListHolidaysArgs) IsNil() bool

func (*ListHolidaysArgs) ModelName added in v0.0.2

func (m *ListHolidaysArgs) ModelName() string

func (*ListHolidaysArgs) Pointers added in v0.0.2

func (m *ListHolidaysArgs) Pointers() []any

func (*ListHolidaysArgs) Schema added in v0.0.2

func (m *ListHolidaysArgs) Schema() []model.Field

func (*ListHolidaysArgs) Validate added in v0.0.2

func (m *ListHolidaysArgs) Validate(action byte) error

type ListHolidaysArgsList added in v0.0.2

type ListHolidaysArgsList []*ListHolidaysArgs

func (*ListHolidaysArgsList) Append added in v0.0.2

func (s *ListHolidaysArgsList) Append() model.Fielder

func (*ListHolidaysArgsList) At added in v0.0.2

func (*ListHolidaysArgsList) DecodeFields added in v0.0.2

func (s *ListHolidaysArgsList) DecodeFields(_ model.FieldReader)

func (*ListHolidaysArgsList) EncodeFields added in v0.0.2

func (s *ListHolidaysArgsList) EncodeFields(_ model.FieldWriter)

func (*ListHolidaysArgsList) IsNil added in v0.0.2

func (s *ListHolidaysArgsList) IsNil() bool

func (*ListHolidaysArgsList) Len added in v0.0.2

func (s *ListHolidaysArgsList) Len() int

type Module added in v0.0.2

type Module struct {
	// contains filtered or unexported fields
}

Module representa el módulo de dominio de horas y feriados. Ejemplo: var m *businesscalendar.Module = cal

func New

func New(db *orm.DB, deps Deps) (*Module, error)

New conecta el módulo a un *orm.DB ya conectado; se asume que el esquema ya existe — consulte el subpaquete migrate. Ejemplo: cal, err := businesscalendar.New(db, deps)

func (*Module) AddClosure added in v0.0.2

func (m *Module) AddClosure(c Closure) error

AddClosure registra un cierre fechado que el propio establecimiento decidió (mantenimiento, un evento). Las fechas del mismo tipo son únicas, por lo que un segundo cierre en una fecha ya cerrada por cierre es rechazado con ErrDuplicateDate. Ejemplo: err := cal.AddClosure(c)

func (*Module) AddHoliday added in v0.0.2

func (m *Module) AddHoliday(h Holiday) error

AddHoliday registra un cierre fechado legal/administrativo. Una segunda fila en la misma fecha es rechazada (ErrDuplicateDate) — un feriado duplicado cerraría dos veces un día y haría que RemoveHoliday parezca roto. Ejemplo: err := cal.AddHoliday(h)

func (*Module) BankDayAfter added in v0.5.0

func (m *Module) BankDayAfter(from tinytime.Unix, days int) (tinytime.Unix, error)

BankDayAfter devuelve la medianoche UTC del día hábil bancario que está days días hábiles después de from. Día hábil bancario: lunes a viernes que no es feriado legal (Holiday). El horario y los cierres propios del establecimiento no cuentan. days == 0 devuelve el mismo día si es hábil, si no el siguiente hábil. Ejemplo: deposito, err := cal.BankDayAfter(cobradoEl, 2) // cobro del viernes con abono a 2 días → martes

func (*Module) GetDayBounds added in v0.0.2

func (m *Module) GetDayBounds(date tinytime.Unix) (tinytime.DayBounds, error)

GetDayBounds es el puerto Reader: solo los límites neutrales, sin ninguna razón adjunta. Satisface estructuralmente cualquier interfaz propia con forma de BoundsReader de un hermano. Ejemplo: bounds, err := cal.GetDayBounds(date)

func (*Module) GetDayDetail added in v0.0.4

func (m *Module) GetDayDetail(date tinytime.Unix) (DayDetail, error)

func (*Module) GetWeekdayBounds added in v0.4.45

func (m *Module) GetWeekdayBounds(dayOfWeek int) (tinytime.DayBounds, error)

GetWeekdayBounds devuelve las horas regulares de un día de la semana (0 = domingo … 6 = sábado) — la plantilla semanal, sin feriados o cierres locales. Vea Reader para saber cuándo usarlo en lugar de GetDayBounds. Ejemplo: bounds, err := cal.GetWeekdayBounds(1)

func (*Module) ListBusinessHours added in v0.0.2

func (m *Module) ListBusinessHours() ([]BusinessHours, error)

ListBusinessHours devuelve las siete reglas de días de la semana ordenadas por day_of_week. Una semana vacía es un estado válido (cerrada por defecto), no un error. Ejemplo: rows, err := cal.ListBusinessHours()

func (*Module) ListClosures added in v0.0.2

func (m *Module) ListClosures(from, to int64) ([]Closure, error)

ListClosures devuelve cierres en el rango [from, to] (segundos UTC a medianoche, inclusivo). Un from/to en cero significa sin límite en esa dirección. Ejemplo: rows, err := cal.ListClosures(0, 0)

func (*Module) ListHolidays added in v0.0.2

func (m *Module) ListHolidays(from, to int64) ([]Holiday, error)

ListHolidays devuelve feriados en el rango [from, to] (segundos UTC a medianoche, inclusivo). Un from/to en cero significa sin límite en esa dirección. Ejemplo: rows, err := cal.ListHolidays(0, 0)

func (*Module) ModelName added in v0.0.2

func (m *Module) ModelName() string

func (*Module) MountOperations added in v0.0.2

func (m *Module) MountOperations(reg router.OperationRegistry)

func (*Module) RemoveClosure added in v0.0.2

func (m *Module) RemoveClosure(id string) error

RemoveClosure elimina un cierre por id. Ejemplo: err := cal.RemoveClosure(id)

func (*Module) RemoveHoliday added in v0.0.2

func (m *Module) RemoveHoliday(id string) error

RemoveHoliday elimina un feriado por id y reabre su día para reservas. Ejemplo: err := cal.RemoveHoliday(id)

func (*Module) UpsertBusinessHours added in v0.0.2

func (m *Module) UpsertBusinessHours(h BusinessHours) error

UpsertBusinessHours crea o actualiza la regla semanal para un día de la semana. Una fila nueva nunca puede invalidar la disponibilidad existente (el día no tenía horario antes, por lo que ya estaba cerrado por defecto), por lo que una creación publica Closed: false; solo una actualización que reduce la ventana publica Closed: true. Ejemplo: err := cal.UpsertBusinessHours(bh)

type Reader added in v0.0.2

type Reader interface {
	// GetDayBounds responde "si el establecimiento está abierto en esta fecha, y
	// entre qué minutos". date es la medianoche UTC en segundos.
	GetDayBounds(date tinytime.Unix) (tinytime.DayBounds, error)

	// GetWeekdayBounds responde "entre qué minutos trabaja normalmente el establecimiento
	// en este día de la semana" (0 = domingo … 6 = sábado) — solo la plantilla
	// semanal: los feriados y cierres locales son excepciones de fecha y NO se
	// aplican aquí (GetDayBounds los aplica). Un consumidor que valida un horario
	// semanal usa esto; uno que valida una fecha concreta usa GetDayBounds.
	//
	// Un día de la semana sin fila business_hours, o con is_open == false, está cerrado
	// (cerrado por defecto, misma regla que el paso 3 de GetDayDetail).
	GetWeekdayBounds(dayOfWeek int) (tinytime.DayBounds, error)
}

Reader es el puerto DE SOLO LECTURA del que dependen los propios consumidores de este módulo — un alias de conveniencia, no el contrato que nombra un módulo de dominio hermano.

Un vecino que solo necesita saber "si esta fecha es utilizable y entre qué minutos" (ej. veltylabs/appointment_booking) declara su PROPIA interfaz devolviendo tinytime.DayBounds — una hoja neutral que ambos lados ya importan — y este Module la satisface estructuralmente, sin adaptador y sin importación en ninguna dirección. Vea webtyp/docs/AGENDA_DOMAIN_MASTER_PLAN.md §3-bis para entender por qué: un módulo genérico de reservas no debe depender de ningún calendario institucional específico. Ejemplo: var reader businesscalendar.Reader = cal

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL