delivery slot api creation
This commit is contained in:
97
repositories/deliverySlotRepository.go
Normal file
97
repositories/deliverySlotRepository.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
|
||||
"nearle/models"
|
||||
)
|
||||
|
||||
type DeliverySlotRepository interface {
|
||||
ListForBranch(tenantID, locationID int) ([]models.DeliverySlots, error)
|
||||
FindForBranch(tenantID, locationID, slotID int) (*models.DeliverySlots, error)
|
||||
Save(slots []models.DeliverySlots) error
|
||||
}
|
||||
|
||||
type deliverySlotRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewDeliverySlotRepository(db *gorm.DB) DeliverySlotRepository {
|
||||
return &deliverySlotRepository{db: db}
|
||||
}
|
||||
|
||||
// Ordered by start time so every caller — the console's editor and the app's
|
||||
// list alike — sees morning before evening without sorting it again.
|
||||
func (r *deliverySlotRepository) ListForBranch(tenantID, locationID int) ([]models.DeliverySlots, error) {
|
||||
slots := make([]models.DeliverySlots, 0, len(models.SlotKeys))
|
||||
|
||||
err := r.db.Table("deliveryslots").
|
||||
Where("tenantid = ? AND locationid = ?", tenantID, locationID).
|
||||
Order("starttime ASC").
|
||||
Find(&slots).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return slots, nil
|
||||
}
|
||||
|
||||
/*
|
||||
One window, scoped to the branch that claims it.
|
||||
|
||||
The tenant and location are in the WHERE and not checked afterwards: a slot id
|
||||
arrives from the app, which carries no session, so it is a claim about which
|
||||
shop it belongs to. Looking it up by id alone and trusting the row would let one
|
||||
shop's checkout name another shop's window.
|
||||
*/
|
||||
func (r *deliverySlotRepository) FindForBranch(tenantID, locationID, slotID int) (*models.DeliverySlots, error) {
|
||||
var slot models.DeliverySlots
|
||||
|
||||
err := r.db.Table("deliveryslots").
|
||||
Where("slotid = ? AND tenantid = ? AND locationid = ?", slotID, tenantID, locationID).
|
||||
First(&slot).Error
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
// Not an error: "this shop does not offer that" is an answer, and the
|
||||
// service turns it into something a shopper can read.
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &slot, nil
|
||||
}
|
||||
|
||||
/*
|
||||
Write a branch's windows, all of them or none.
|
||||
|
||||
── Upsert, not delete-then-insert ──────────────────────────────────────────
|
||||
|
||||
Slot ids are referenced by `orders.deliveryslotid`. Replacing the rows would
|
||||
renumber them, and every order already placed would point at a window that no
|
||||
longer means what it did — or at nothing. The unique index on
|
||||
(tenantid, locationid, slotkey) is what makes the conflict target work, so a
|
||||
branch keeps one morning however many times it is edited.
|
||||
|
||||
── One transaction ─────────────────────────────────────────────────────────
|
||||
|
||||
A shop editing all three and getting two is worse than getting none: the two
|
||||
that took are live and serving shoppers, and nothing on screen says which.
|
||||
*/
|
||||
func (r *deliverySlotRepository) Save(slots []models.DeliverySlots) error {
|
||||
if len(slots) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return r.db.Transaction(func(tx *gorm.DB) error {
|
||||
return tx.Table("deliveryslots").
|
||||
Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{
|
||||
{Name: "tenantid"}, {Name: "locationid"}, {Name: "slotkey"},
|
||||
},
|
||||
DoUpdates: clause.AssignmentColumns([]string{"name", "starttime", "endtime", "status", "updated"}),
|
||||
}).
|
||||
Create(&slots).Error
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user