pos login edited with phone number
This commit is contained in:
170
repositories/posShiftRepository.go
Normal file
170
repositories/posShiftRepository.go
Normal file
@@ -0,0 +1,170 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"nearle/models"
|
||||
)
|
||||
|
||||
// Shift windows for till staff.
|
||||
//
|
||||
// Scoped by tenant *and* outlet in every statement rather than checked first,
|
||||
// the same shape the till-user queries use: a console naming somebody else's
|
||||
// shift id updates no rows and is told so, instead of quietly editing another
|
||||
// shop's hours.
|
||||
|
||||
var posTimeOfDay = regexp.MustCompile(`^([01]\d|2[0-3]):[0-5]\d$`)
|
||||
|
||||
// normaliseShiftTime accepts what a time input actually sends.
|
||||
//
|
||||
// `<input type="time">` gives "07:00", some browsers and most hand-typed values
|
||||
// give "07:00:00", and `ridershifts` already stores the seconds form. Both are
|
||||
// reduced to `HH:MM` so a shift written by one client reads the same to another.
|
||||
func normaliseShiftTime(raw string) (string, error) {
|
||||
t := strings.TrimSpace(raw)
|
||||
if t == "" {
|
||||
return "", fmt.Errorf("a start and end time are required")
|
||||
}
|
||||
if len(t) == 8 && strings.Count(t, ":") == 2 {
|
||||
t = t[:5]
|
||||
}
|
||||
if !posTimeOfDay.MatchString(t) {
|
||||
return "", fmt.Errorf("time must be 24-hour HH:MM; got %q", raw)
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// ListStaffShifts returns an outlet's shifts, newest last so a picker reads in
|
||||
// the order they were created rather than alphabetically by name.
|
||||
func (r *posRepository) ListStaffShifts(tenantID, locationID int, includeInactive bool) ([]models.StaffShifts, error) {
|
||||
if tenantID <= 0 || locationID <= 0 {
|
||||
return nil, fmt.Errorf("tenantid and locationid are required")
|
||||
}
|
||||
|
||||
shifts := make([]models.StaffShifts, 0)
|
||||
query := `SELECT * FROM staffshifts WHERE tenantid = ? AND locationid = ?`
|
||||
if !includeInactive {
|
||||
query += ` AND LOWER(COALESCE(status,'active')) <> 'inactive'`
|
||||
}
|
||||
query += ` ORDER BY staffshiftid`
|
||||
|
||||
if err := r.db.Raw(query, tenantID, locationID).Scan(&shifts).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return shifts, nil
|
||||
}
|
||||
|
||||
// CreateStaffShift adds a window at one outlet.
|
||||
func (r *posRepository) CreateStaffShift(tenantID, locationID int, req models.StaffShifts) (*models.StaffShifts, error) {
|
||||
if tenantID <= 0 || locationID <= 0 {
|
||||
return nil, fmt.Errorf("tenantid and locationid are required")
|
||||
}
|
||||
|
||||
name := strings.TrimSpace(req.Name)
|
||||
if name == "" {
|
||||
return nil, fmt.Errorf("a shift name is required")
|
||||
}
|
||||
|
||||
start, err := normaliseShiftTime(req.Starttime)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
end, err := normaliseShiftTime(req.Endtime)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// An end before a start is allowed on purpose — a night shift runs 22:00 to
|
||||
// 06:00 and wrapping midnight is ordinary in retail. Only the equal case is
|
||||
// refused, because a zero-length window cannot be what anyone meant.
|
||||
if start == end {
|
||||
return nil, fmt.Errorf("a shift cannot start and end at the same time")
|
||||
}
|
||||
|
||||
weekdays := strings.TrimSpace(req.Weekdays)
|
||||
if weekdays != "" && !regexp.MustCompile(`^[01]{7}$`).MatchString(weekdays) {
|
||||
return nil, fmt.Errorf("weekdays must be seven 0/1 characters starting Monday, e.g. 1111100")
|
||||
}
|
||||
|
||||
shift := models.StaffShifts{
|
||||
Tenantid: tenantID,
|
||||
Locationid: locationID,
|
||||
Name: name,
|
||||
Starttime: start,
|
||||
Endtime: end,
|
||||
Weekdays: weekdays,
|
||||
Status: "Active",
|
||||
}
|
||||
if err := r.db.Table("staffshifts").Create(&shift).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &shift, nil
|
||||
}
|
||||
|
||||
// UpdateStaffShift edits a window. Every field is optional; only the ones sent
|
||||
// are written, matching how the till-user update behaves.
|
||||
func (r *posRepository) UpdateStaffShift(tenantID, locationID int, req models.StaffShifts) (*models.StaffShifts, error) {
|
||||
if req.Staffshiftid <= 0 {
|
||||
return nil, fmt.Errorf("staff_shift_id is required")
|
||||
}
|
||||
|
||||
sets := []string{}
|
||||
args := []interface{}{}
|
||||
|
||||
if name := strings.TrimSpace(req.Name); name != "" {
|
||||
sets = append(sets, "name = ?")
|
||||
args = append(args, name)
|
||||
}
|
||||
if strings.TrimSpace(req.Starttime) != "" {
|
||||
t, err := normaliseShiftTime(req.Starttime)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sets = append(sets, "starttime = ?")
|
||||
args = append(args, t)
|
||||
}
|
||||
if strings.TrimSpace(req.Endtime) != "" {
|
||||
t, err := normaliseShiftTime(req.Endtime)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sets = append(sets, "endtime = ?")
|
||||
args = append(args, t)
|
||||
}
|
||||
if w := strings.TrimSpace(req.Weekdays); w != "" {
|
||||
if !regexp.MustCompile(`^[01]{7}$`).MatchString(w) {
|
||||
return nil, fmt.Errorf("weekdays must be seven 0/1 characters starting Monday")
|
||||
}
|
||||
sets = append(sets, "weekdays = ?")
|
||||
args = append(args, w)
|
||||
}
|
||||
if s := strings.TrimSpace(req.Status); s != "" {
|
||||
sets = append(sets, "status = ?")
|
||||
args = append(args, s)
|
||||
}
|
||||
|
||||
if len(sets) == 0 {
|
||||
return nil, fmt.Errorf("nothing to change")
|
||||
}
|
||||
|
||||
sets = append(sets, "updated = NOW()")
|
||||
args = append(args, req.Staffshiftid, tenantID, locationID)
|
||||
|
||||
res := r.db.Exec(
|
||||
fmt.Sprintf(`UPDATE staffshifts SET %s WHERE staffshiftid = ? AND tenantid = ? AND locationid = ?`,
|
||||
strings.Join(sets, ", ")), args...)
|
||||
if res.Error != nil {
|
||||
return nil, res.Error
|
||||
}
|
||||
if res.RowsAffected == 0 {
|
||||
return nil, fmt.Errorf("no shift %d at this outlet", req.Staffshiftid)
|
||||
}
|
||||
|
||||
var out models.StaffShifts
|
||||
if err := r.db.Raw(`SELECT * FROM staffshifts WHERE staffshiftid = ?`, req.Staffshiftid).Scan(&out).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
Reference in New Issue
Block a user