delivery slot api creation

This commit is contained in:
2026-10-06 17:35:51 +05:30
parent f67cbad79a
commit 03ae7d310b
12 changed files with 1137 additions and 104 deletions

111
models/deliveryslot.go Normal file
View File

@@ -0,0 +1,111 @@
package models
import (
"slices"
"time"
)
/*
When a shop delivers.
A branch offers at most three windows a day — morning, afternoon, evening — and
the shopper picks one at checkout. The window is a PREFERENCE, not a promise:
every order is accepted, there is no capacity limit, and a slot never fills up.
It tells the shop when to group a drop, and it tells the shopper roughly when to
expect one.
── Per branch, not per tenant ──────────────────────────────────────────────
Timings belong to a shop floor, not a company. A tenant with an outlet in a
market and another in an office park will run different hours, and discovering
that after the fact would mean migrating live rows. `locationid` is on the table
from the start for that reason, and onboarding simply fills it with the primary
branch it just created.
── A branch with no slots is not broken ────────────────────────────────────
Every tenant trading today has no slots at all, and must keep taking orders.
Absence means "order without a slot", exactly as before — never "this shop is
closed". The whole rollout rests on that, so nothing here may treat an empty
list as an error.
*/
type DeliverySlots struct {
Slotid int `json:"deliveryslotid" gorm:"primaryKey;autoIncrement;column:slotid"`
Tenantid int `json:"tenantid" gorm:"column:tenantid;index"`
Locationid int `json:"locationid" gorm:"column:locationid;index"`
// Which of the three this is. Fixed rather than free-form: the app shows
// them in a known order and may want an icon per slot, and a shop inventing
// a fourth would have nowhere to appear.
Slotkey string `json:"slotkey" gorm:"column:slotkey"`
// What the shopper reads. Separate from `slotkey` so a shop can say
// "Before work" without breaking the app's ordering.
Name string `json:"name" gorm:"column:name"`
// "HH:MM", 24-hour, in the shop's local time.
//
// Stored as text, not as a timestamp, because this is a time of DAY that
// recurs — it has no date until an order attaches one. A timestamp column
// would invite a timezone conversion on every read, which is the one thing
// this must not do: the shopkeeper typed 08:00 meaning eight in the morning
// where they are standing.
Starttime string `json:"starttime" gorm:"column:starttime"`
// Also the CUT-OFF. There is deliberately no separate cutoff column: a slot
// accepts orders right up to the moment it ends, and then stops being
// offered. Morning 08:00–10:00 takes an order at 09:59 and not at 10:01.
Endtime string `json:"endtime" gorm:"column:endtime"`
// "active" or "inactive". A shop that stops doing evenings turns the slot
// off rather than deleting it, so orders already placed against it still
// resolve to something with a name.
Status string `json:"status" gorm:"column:status"`
Created time.Time `json:"created" gorm:"column:created;autoCreateTime"`
Updated time.Time `json:"updated" gorm:"column:updated;autoUpdateTime"`
}
func (DeliverySlots) TableName() string {
return "deliveryslots"
}
// The three keys, in the order a shopper reads them.
const (
SlotMorning = "morning"
SlotAfternoon = "afternoon"
SlotEvening = "evening"
)
// SlotKeys is the whole set, in display order. Used to validate input and to
// seed a new branch.
var SlotKeys = []string{SlotMorning, SlotAfternoon, SlotEvening}
// IsSlotKey reports whether a key is one of the three.
func IsSlotKey(key string) bool {
return slices.Contains(SlotKeys, key)
}
/*
A slot offered to a shopper, with the day it falls on.
`DeliverySlots` describes a window that recurs; this is one concrete occurrence
of it. The app needs the date because "evening" alone cannot distinguish tonight
from tomorrow night, and once today's last window closes the next thing on offer
is tomorrow morning.
The app does NO time arithmetic. It renders what this list contains, and the
list already excludes anything that has closed.
*/
type AvailableDeliverySlot struct {
Slotid int `json:"deliveryslotid"`
Slotkey string `json:"slotkey"`
Name string `json:"name"`
Starttime string `json:"starttime"`
Endtime string `json:"endtime"`
// "YYYY-MM-DD", the day this window falls on.
Slotdate string `json:"slotdate"`
// True when `Slotdate` is not today. Saves the app comparing dates to
// decide whether to write "Tomorrow" beside the name.
IsTomorrow bool `json:"istomorrow"`
}