hub apis
This commit is contained in:
@@ -818,6 +818,7 @@ func UpdateMiler(c *fiber.Ctx) error {
|
||||
type MilerUpdate struct {
|
||||
Displayname string `json:"displayname"`
|
||||
Defaultvehicletype string `json:"defaultvehicletype"`
|
||||
Hubid *int `json:"hubid"`
|
||||
}
|
||||
|
||||
req := new(MilerUpdate)
|
||||
@@ -831,6 +832,9 @@ func UpdateMiler(c *fiber.Ctx) error {
|
||||
if req.Defaultvehicletype != "" {
|
||||
profile.Defaultvehicletype = req.Defaultvehicletype
|
||||
}
|
||||
if req.Hubid != nil {
|
||||
profile.Hubid = req.Hubid
|
||||
}
|
||||
profile.Updatedat = time.Now()
|
||||
|
||||
if err := db.DB.Save(&profile).Error; err != nil {
|
||||
|
||||
593
controllers/hubController.go
Normal file
593
controllers/hubController.go
Normal file
@@ -0,0 +1,593 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"doormile/config"
|
||||
"doormile/constants"
|
||||
"doormile/db"
|
||||
"doormile/dto"
|
||||
"doormile/models"
|
||||
"doormile/utils"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
// todayMidnight returns the start of the current day in server local time,
|
||||
// used to scope "today" counters on the hub dashboard.
|
||||
func todayMidnight() time.Time {
|
||||
now := time.Now()
|
||||
return time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
||||
}
|
||||
|
||||
// hubPincodePrefix returns the first 3 digits of a hub's pincode, following
|
||||
// the same zone-prefix convention used in pricing_helpers.go and city_gate.go.
|
||||
func hubPincodePrefix(hubID int) string {
|
||||
var hub models.Hub
|
||||
if err := db.DB.Where("hubid = ?", hubID).First(&hub).Error; err != nil || len(hub.Pincode) < 3 {
|
||||
return ""
|
||||
}
|
||||
return hub.Pincode[:3]
|
||||
}
|
||||
|
||||
func HubStaffLogin(cfg *config.Config) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
type LoginRequest struct {
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
req := new(LoginRequest)
|
||||
if err := c.BodyParser(req); err != nil {
|
||||
return utils.BadRequest(c, "invalid request body")
|
||||
}
|
||||
|
||||
if req.Email == "" || req.Password == "" {
|
||||
return utils.BadRequest(c, "email and password are required")
|
||||
}
|
||||
|
||||
var staff models.HubStaffAccount
|
||||
if err := db.DB.Where("email = ? AND isactive = ?", req.Email, true).First(&staff).Error; err != nil {
|
||||
return utils.Unauthorized(c, "incorrect email or password")
|
||||
}
|
||||
|
||||
if !utils.CheckPasswordHash(req.Password, staff.Passwordhash) {
|
||||
return utils.Unauthorized(c, "incorrect email or password")
|
||||
}
|
||||
|
||||
token, err := utils.GenerateHubStaffToken(staff.Hubstaffaccountid, staff.Email, staff.Hubid, cfg.JWTSecret)
|
||||
if err != nil {
|
||||
return utils.Internal(c, "failed to generate token")
|
||||
}
|
||||
|
||||
var hub models.Hub
|
||||
db.DB.Where("hubid = ?", staff.Hubid).First(&hub)
|
||||
|
||||
var loc models.AppLocation
|
||||
db.DB.Where("applocationid = ?", hub.Applocationid).First(&loc)
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"success": true,
|
||||
"token": token,
|
||||
"hub": fiber.Map{
|
||||
"hubid": hub.Hubid,
|
||||
"hubname": hub.Hubname,
|
||||
"hubtype": hub.Hubtype,
|
||||
"city": loc.Applocationname,
|
||||
"capacity": hub.Capacity,
|
||||
},
|
||||
"staff": fiber.Map{
|
||||
"displayname": staff.Displayname,
|
||||
"email": staff.Email,
|
||||
"role": staff.Roleid,
|
||||
},
|
||||
"is_doormile_staff": staff.Tenantid == nil,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// getCurrentHubStaff reloads the requesting hub staff account fresh from the
|
||||
// DB (rather than trusting JWT claims) so tenantid changes take effect
|
||||
// immediately without requiring the staff member to re-login.
|
||||
func getCurrentHubStaff(c *fiber.Ctx) (*models.HubStaffAccount, error) {
|
||||
staffID := c.Locals("userid").(int)
|
||||
var staff models.HubStaffAccount
|
||||
if err := db.DB.Where("hubstaffaccountid = ?", staffID).First(&staff).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &staff, nil
|
||||
}
|
||||
|
||||
func isDoormileStaff(staff *models.HubStaffAccount) bool {
|
||||
return staff.Tenantid == nil
|
||||
}
|
||||
|
||||
func GetHubDashboardStats(c *fiber.Ctx) error {
|
||||
hubID := c.Locals("hubid").(int)
|
||||
midnight := todayMidnight()
|
||||
prefix := hubPincodePrefix(hubID)
|
||||
|
||||
var parcelsReceivedToday int64
|
||||
db.DB.Model(&models.Consignment{}).
|
||||
Where("currenthubid = ? AND status = ? AND updatedat >= ?", hubID, constants.ConsignmentInwardedAtHub, midnight).
|
||||
Count(&parcelsReceivedToday)
|
||||
|
||||
var milersAvailable int64
|
||||
db.DB.Model(&models.MilerProfile{}).
|
||||
Where("hubid = ? AND availabilitystatus = ?", hubID, constants.MilerAvailable).
|
||||
Count(&milersAvailable)
|
||||
|
||||
var milersOnDuty int64
|
||||
db.DB.Model(&models.MilerProfile{}).
|
||||
Where("hubid = ? AND availabilitystatus != ?", hubID, constants.MilerOffline).
|
||||
Count(&milersOnDuty)
|
||||
|
||||
pendingQuery := db.DB.Model(&models.PickupBooking{}).Where("status = ?", constants.BookingPendingPickup)
|
||||
if prefix != "" {
|
||||
pendingQuery = pendingQuery.Where("pickuppincode LIKE ?", prefix+"%")
|
||||
}
|
||||
var pendingPickups int64
|
||||
pendingQuery.Count(&pendingPickups)
|
||||
|
||||
var batchesSentToday int64
|
||||
db.DB.Model(&models.Tripsheet{}).
|
||||
Where("sourcehubid = ? AND dispatchtime >= ?", hubID, midnight).
|
||||
Count(&batchesSentToday)
|
||||
|
||||
var exceptions int64
|
||||
db.DB.Model(&models.ConsignmentException{}).
|
||||
Where("hubid = ? AND createdat >= ?", hubID, midnight).
|
||||
Count(&exceptions)
|
||||
|
||||
return utils.OK(c, fiber.Map{
|
||||
"parcels_received_today": parcelsReceivedToday,
|
||||
"milers_available": milersAvailable,
|
||||
"milers_on_duty": milersOnDuty,
|
||||
"pending_pickups": pendingPickups,
|
||||
"batches_sent_today": batchesSentToday,
|
||||
"exceptions": exceptions,
|
||||
})
|
||||
}
|
||||
|
||||
func GetHubUnassignedBookings(c *fiber.Ctx) error {
|
||||
hubID := c.Locals("hubid").(int)
|
||||
prefix := hubPincodePrefix(hubID)
|
||||
|
||||
query := db.DB.Preload("Parcels").
|
||||
Where("assignedmileruserid IS NULL AND status = ?", constants.BookingPendingPickup)
|
||||
if prefix != "" {
|
||||
query = query.Where("pickuppincode LIKE ?", prefix+"%")
|
||||
}
|
||||
|
||||
var bookings []models.PickupBooking
|
||||
if err := query.Order("createdat DESC").Find(&bookings).Error; err != nil {
|
||||
return utils.Internal(c, "failed to fetch unassigned bookings")
|
||||
}
|
||||
|
||||
response := make([]fiber.Map, 0, len(bookings))
|
||||
for _, b := range bookings {
|
||||
var customer models.AppCustomer
|
||||
db.DB.Where("appcustomerid = ?", b.Appcustomerid).First(&customer)
|
||||
|
||||
response = append(response, fiber.Map{
|
||||
"bookingid": b.Bookingid,
|
||||
"bookingno": b.Bookingno,
|
||||
"customer_name": strings.TrimSpace(customer.Firstname + " " + customer.Lastname),
|
||||
"pickup_address": b.Pickupaddress,
|
||||
"pickup_pincode": b.Pickuppincode,
|
||||
"delivery_address": b.Deliveryaddress,
|
||||
"parcels": b.Parcels,
|
||||
"created_at": b.Createdat,
|
||||
})
|
||||
}
|
||||
|
||||
return utils.List(c, response, int64(len(response)))
|
||||
}
|
||||
|
||||
func GetHubInboundToday(c *fiber.Ctx) error {
|
||||
hubID := c.Locals("hubid").(int)
|
||||
midnight := todayMidnight()
|
||||
|
||||
var consignments []models.Consignment
|
||||
if err := db.DB.Where("currenthubid = ? AND status = ? AND updatedat >= ?", hubID, constants.ConsignmentInwardedAtHub, midnight).
|
||||
Order("updatedat DESC").Find(&consignments).Error; err != nil {
|
||||
return utils.Internal(c, "failed to fetch inbound consignments")
|
||||
}
|
||||
|
||||
return utils.List(c, consignments, int64(len(consignments)))
|
||||
}
|
||||
|
||||
func CreateInboundScan(c *fiber.Ctx) error {
|
||||
hubID := c.Locals("hubid").(int)
|
||||
idParam := c.Params("id")
|
||||
|
||||
type InboundRequest struct {
|
||||
TrackingID string `json:"tracking_id"`
|
||||
Condition string `json:"condition"`
|
||||
Temperature string `json:"temperature"`
|
||||
Shelf string `json:"shelf"`
|
||||
Weight string `json:"weight"`
|
||||
}
|
||||
req := new(InboundRequest)
|
||||
if err := c.BodyParser(req); err != nil {
|
||||
return utils.BadRequest(c, "invalid request body")
|
||||
}
|
||||
|
||||
var consignment models.Consignment
|
||||
found := false
|
||||
if id, err := strconv.Atoi(idParam); err == nil {
|
||||
if db.DB.Where("consignmentid = ?", id).First(&consignment).Error == nil {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if !found && idParam != "" {
|
||||
if db.DB.Where("trackingno = ?", idParam).First(&consignment).Error == nil {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if !found && req.TrackingID != "" {
|
||||
if db.DB.Where("trackingno = ?", req.TrackingID).First(&consignment).Error == nil {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return utils.NotFound(c, "consignment not found")
|
||||
}
|
||||
|
||||
recommendedShelf := req.Shelf
|
||||
if recommendedShelf == "" {
|
||||
switch {
|
||||
case strings.Contains(req.Condition, "Damaged"):
|
||||
recommendedShelf = "Exception Area"
|
||||
case req.Temperature != "" && req.Temperature != "N/A":
|
||||
recommendedShelf = "Zone C (Cold Room)"
|
||||
default:
|
||||
recommendedShelf = "Zone A"
|
||||
if n := len(consignment.Deliverypincode); n > 0 {
|
||||
lastDigit := consignment.Deliverypincode[n-1]
|
||||
if lastDigit >= '0' && lastDigit <= '9' && (lastDigit-'0')%2 == 0 {
|
||||
recommendedShelf = "Zone B"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
consignment.Status = constants.ConsignmentInwardedAtHub
|
||||
consignment.Currenthubid = &hubID
|
||||
consignment.Condition = req.Condition
|
||||
consignment.Shelf = recommendedShelf
|
||||
consignment.Updatedat = time.Now()
|
||||
|
||||
if err := db.DB.Save(&consignment).Error; err != nil {
|
||||
return utils.Internal(c, "failed to update consignment")
|
||||
}
|
||||
|
||||
history := models.ConsignmentHistory{
|
||||
Consignmentid: consignment.Consignmentid,
|
||||
Hubid: &hubID,
|
||||
Eventstatus: constants.ConsignmentInwardedAtHub,
|
||||
Remarks: fmt.Sprintf("Inbound scan at hub: condition=%s, shelf=%s", req.Condition, recommendedShelf),
|
||||
}
|
||||
db.DB.Create(&history)
|
||||
|
||||
if strings.Contains(req.Condition, "Damaged") {
|
||||
exception := models.ConsignmentException{
|
||||
Consignmentid: consignment.Consignmentid,
|
||||
Hubid: &hubID,
|
||||
Exceptiontype: constants.ExceptionDamaged,
|
||||
Description: fmt.Sprintf("Flagged during hub inbound scan: %s", req.Condition),
|
||||
}
|
||||
db.DB.Create(&exception)
|
||||
}
|
||||
|
||||
return utils.OK(c, fiber.Map{
|
||||
"consignment": consignment,
|
||||
"recommended_shelf": recommendedShelf,
|
||||
})
|
||||
}
|
||||
|
||||
// --------------------
|
||||
// HUB BATCHES (DISPATCH) — backed by the existing Tripsheet model
|
||||
// --------------------
|
||||
|
||||
func GetHubBatches(c *fiber.Ctx) error {
|
||||
hubID := c.Locals("hubid").(int)
|
||||
|
||||
var tripsheets []models.Tripsheet
|
||||
if err := db.DB.Where("sourcehubid = ? AND deletedat IS NULL", hubID).
|
||||
Order("createdat DESC").Find(&tripsheets).Error; err != nil {
|
||||
return utils.Internal(c, "failed to fetch batches")
|
||||
}
|
||||
|
||||
response := make([]fiber.Map, 0, len(tripsheets))
|
||||
for _, ts := range tripsheets {
|
||||
var itemCount int64
|
||||
db.DB.Model(&models.TripsheetItem{}).Where("tripsheetid = ?", ts.Tripsheetid).Count(&itemCount)
|
||||
|
||||
response = append(response, fiber.Map{
|
||||
"tripsheetid": ts.Tripsheetid,
|
||||
"tripsheetno": ts.Tripsheetno,
|
||||
"route": ts.Batchlabel,
|
||||
"destination": ts.Destinationlabel,
|
||||
"kind": ts.Batchkind,
|
||||
"status": ts.Status,
|
||||
"item_count": itemCount,
|
||||
"dispatchtime": ts.Dispatchtime,
|
||||
"createdat": ts.Createdat,
|
||||
})
|
||||
}
|
||||
|
||||
return utils.List(c, response, int64(len(response)))
|
||||
}
|
||||
|
||||
// resolveDestinationHubID best-effort matches a free-text destination (e.g.
|
||||
// "Mumbai Hub (BOM-02)") against a real Hub row by name, since
|
||||
// tripsheets.destinationhubid carries a NOT NULL foreign key to hubs. When no
|
||||
// internal hub matches (interstate transfer to a city we don't operate a hub
|
||||
// in yet), it falls back to the batch's own source hub, which is always a
|
||||
// valid id; the human-readable destination is preserved in Destinationlabel.
|
||||
func resolveDestinationHubID(destination string, fallback int) int {
|
||||
if destination == "" {
|
||||
return fallback
|
||||
}
|
||||
var hub models.Hub
|
||||
if err := db.DB.Where("hubname ILIKE ?", "%"+destination+"%").First(&hub).Error; err == nil {
|
||||
return hub.Hubid
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
func CreateHubBatch(c *fiber.Ctx) error {
|
||||
hubID := c.Locals("hubid").(int)
|
||||
staffID := c.Locals("userid").(int)
|
||||
|
||||
type BatchRequest struct {
|
||||
Route string `json:"route"`
|
||||
Destination string `json:"destination"`
|
||||
Vehicle string `json:"vehicle"`
|
||||
ParcelsCount int `json:"parcels_count"`
|
||||
Kind string `json:"kind"`
|
||||
}
|
||||
req := new(BatchRequest)
|
||||
if err := c.BodyParser(req); err != nil {
|
||||
return utils.BadRequest(c, "invalid request body")
|
||||
}
|
||||
|
||||
if req.Route == "" {
|
||||
return utils.BadRequest(c, "route is required")
|
||||
}
|
||||
|
||||
kind := req.Kind
|
||||
if kind == "" {
|
||||
kind = "local"
|
||||
}
|
||||
|
||||
tripsheet := models.Tripsheet{
|
||||
Tripsheetno: generateTripsheetNo(),
|
||||
Sourcehubid: hubID,
|
||||
Destinationhubid: resolveDestinationHubID(req.Destination, hubID),
|
||||
Batchlabel: req.Route,
|
||||
Batchkind: kind,
|
||||
Destinationlabel: req.Destination,
|
||||
Status: constants.TripsheetDraft,
|
||||
Createdby: staffID,
|
||||
Updatedby: staffID,
|
||||
}
|
||||
|
||||
if err := db.DB.Create(&tripsheet).Error; err != nil {
|
||||
return utils.Internal(c, "failed to create batch")
|
||||
}
|
||||
|
||||
return utils.Created(c, fiber.Map{
|
||||
"tripsheetid": tripsheet.Tripsheetid,
|
||||
"tripsheetno": tripsheet.Tripsheetno,
|
||||
"route": tripsheet.Batchlabel,
|
||||
"destination": tripsheet.Destinationlabel,
|
||||
"kind": tripsheet.Batchkind,
|
||||
"status": tripsheet.Status,
|
||||
"vehicle": req.Vehicle,
|
||||
"parcels_count": req.ParcelsCount,
|
||||
})
|
||||
}
|
||||
|
||||
func UpdateBatchStatus(c *fiber.Ctx) error {
|
||||
hubID := c.Locals("hubid").(int)
|
||||
id, _ := strconv.Atoi(c.Params("id"))
|
||||
|
||||
type StatusUpdate struct {
|
||||
Status string `json:"status"`
|
||||
}
|
||||
req := new(StatusUpdate)
|
||||
if err := c.BodyParser(req); err != nil {
|
||||
return utils.BadRequest(c, "invalid request body")
|
||||
}
|
||||
|
||||
validStatuses := map[string]bool{
|
||||
constants.TripsheetDraft: true,
|
||||
constants.TripsheetReady: true,
|
||||
constants.TripsheetDispatched: true,
|
||||
}
|
||||
if !validStatuses[req.Status] {
|
||||
return utils.BadRequest(c, "status must be one of Draft, Ready, Dispatched")
|
||||
}
|
||||
|
||||
var tripsheet models.Tripsheet
|
||||
if err := db.DB.Where("tripsheetid = ? AND sourcehubid = ? AND deletedat IS NULL", id, hubID).First(&tripsheet).Error; err != nil {
|
||||
return utils.NotFound(c, "batch not found")
|
||||
}
|
||||
|
||||
tripsheet.Status = req.Status
|
||||
tripsheet.Updatedat = time.Now()
|
||||
if req.Status == constants.TripsheetDispatched {
|
||||
now := time.Now()
|
||||
tripsheet.Dispatchtime = &now
|
||||
}
|
||||
|
||||
if err := db.DB.Save(&tripsheet).Error; err != nil {
|
||||
return utils.Internal(c, "failed to update batch status")
|
||||
}
|
||||
|
||||
return utils.OK(c, tripsheet)
|
||||
}
|
||||
|
||||
// GetHubMilers is the hub-scoped equivalent of admin's GetMilers, filtered to
|
||||
// only the milers assigned to the requesting hub staff's own hub.
|
||||
func GetHubMilers(c *fiber.Ctx) error {
|
||||
hubID := c.Locals("hubid").(int)
|
||||
|
||||
var profiles []models.MilerProfile
|
||||
if err := db.DB.Where("hubid = ?", hubID).Find(&profiles).Error; err != nil {
|
||||
return utils.Internal(c, "failed to fetch milers")
|
||||
}
|
||||
return utils.List(c, profiles, int64(len(profiles)))
|
||||
}
|
||||
|
||||
// --------------------
|
||||
// HUB MANAGEMENT (Doormile staff only)
|
||||
// --------------------
|
||||
|
||||
// CreateHubStaffAccount lets Doormile staff (tenantid == nil) provision new
|
||||
// hub staff accounts, including partner-tenant accounts scoped to one hub.
|
||||
func CreateHubStaffAccount(c *fiber.Ctx) error {
|
||||
current, err := getCurrentHubStaff(c)
|
||||
if err != nil {
|
||||
return utils.Internal(c, "failed to verify requesting staff account")
|
||||
}
|
||||
if !isDoormileStaff(current) {
|
||||
return utils.Forbidden(c, "only Doormile staff can create hub staff accounts")
|
||||
}
|
||||
|
||||
type CreateStaffRequest struct {
|
||||
Hubid int `json:"hubid"`
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
Displayname string `json:"displayname"`
|
||||
Tenantid *int `json:"tenantid"`
|
||||
}
|
||||
req := new(CreateStaffRequest)
|
||||
if err := c.BodyParser(req); err != nil {
|
||||
return utils.BadRequest(c, "invalid request body")
|
||||
}
|
||||
|
||||
if req.Hubid == 0 || req.Email == "" || req.Password == "" {
|
||||
return utils.BadRequest(c, "hubid, email and password are required")
|
||||
}
|
||||
|
||||
var hub models.Hub
|
||||
if err := db.DB.Where("hubid = ? AND deletedat IS NULL", req.Hubid).First(&hub).Error; err != nil {
|
||||
return utils.NotFound(c, "hub not found")
|
||||
}
|
||||
|
||||
passHash, err := utils.HashPassword(req.Password)
|
||||
if err != nil {
|
||||
return utils.Internal(c, "failed to hash password")
|
||||
}
|
||||
|
||||
staff := models.HubStaffAccount{
|
||||
Hubid: req.Hubid,
|
||||
Email: req.Email,
|
||||
Passwordhash: passHash,
|
||||
Displayname: req.Displayname,
|
||||
Roleid: 6,
|
||||
Isactive: true,
|
||||
Tenantid: req.Tenantid,
|
||||
}
|
||||
|
||||
if err := db.DB.Create(&staff).Error; err != nil {
|
||||
return utils.Internal(c, "failed to create hub staff account")
|
||||
}
|
||||
|
||||
return utils.Created(c, fiber.Map{
|
||||
"hubstaffaccountid": staff.Hubstaffaccountid,
|
||||
"hubid": staff.Hubid,
|
||||
"email": staff.Email,
|
||||
"displayname": staff.Displayname,
|
||||
"tenantid": staff.Tenantid,
|
||||
})
|
||||
}
|
||||
|
||||
// GetHubsInCity lists every hub in the requesting staff's city (same
|
||||
// applocationid as their own hub), noting whether each already has a staff
|
||||
// account so the console can flag hubs still needing one.
|
||||
func GetHubsInCity(c *fiber.Ctx) error {
|
||||
hubID := c.Locals("hubid").(int)
|
||||
|
||||
var myHub models.Hub
|
||||
if err := db.DB.Where("hubid = ?", hubID).First(&myHub).Error; err != nil {
|
||||
return utils.Internal(c, "failed to resolve current hub")
|
||||
}
|
||||
|
||||
var hubs []models.Hub
|
||||
if err := db.DB.Where("applocationid = ? AND deletedat IS NULL", myHub.Applocationid).
|
||||
Order("hubid").Find(&hubs).Error; err != nil {
|
||||
return utils.Internal(c, "failed to fetch hubs")
|
||||
}
|
||||
|
||||
response := make([]fiber.Map, 0, len(hubs))
|
||||
for _, h := range hubs {
|
||||
var staffCount int64
|
||||
db.DB.Model(&models.HubStaffAccount{}).Where("hubid = ?", h.Hubid).Count(&staffCount)
|
||||
|
||||
response = append(response, fiber.Map{
|
||||
"hubid": h.Hubid,
|
||||
"hubname": h.Hubname,
|
||||
"hubtype": h.Hubtype,
|
||||
"pincode": h.Pincode,
|
||||
"status": h.Status,
|
||||
"capacity": h.Capacity,
|
||||
"has_staff": staffCount > 0,
|
||||
})
|
||||
}
|
||||
|
||||
return utils.List(c, response, int64(len(response)))
|
||||
}
|
||||
|
||||
// CreateCityHub lets Doormile staff add a new hub, forced into their own
|
||||
// city (applocationid) regardless of what the request body sends.
|
||||
func CreateCityHub(c *fiber.Ctx) error {
|
||||
current, err := getCurrentHubStaff(c)
|
||||
if err != nil {
|
||||
return utils.Internal(c, "failed to verify requesting staff account")
|
||||
}
|
||||
if !isDoormileStaff(current) {
|
||||
return utils.Forbidden(c, "only Doormile staff can create new hubs")
|
||||
}
|
||||
|
||||
hubID := c.Locals("hubid").(int)
|
||||
var myHub models.Hub
|
||||
if err := db.DB.Where("hubid = ?", hubID).First(&myHub).Error; err != nil {
|
||||
return utils.Internal(c, "failed to resolve current hub")
|
||||
}
|
||||
|
||||
req := new(dto.HubCreateRequest)
|
||||
if err := c.BodyParser(req); err != nil {
|
||||
return utils.BadRequest(c, "invalid request body")
|
||||
}
|
||||
|
||||
if req.Hubname == "" || req.Hubtype == "" {
|
||||
return utils.BadRequest(c, "hubname and hubtype are required")
|
||||
}
|
||||
|
||||
hub := models.Hub{
|
||||
Hubname: req.Hubname,
|
||||
Hubtype: req.Hubtype,
|
||||
Applocationid: myHub.Applocationid,
|
||||
Contactno: req.Contactno,
|
||||
Address: req.Address,
|
||||
Latitude: req.Latitude,
|
||||
Longitude: req.Longitude,
|
||||
Pincode: req.Pincode,
|
||||
Status: req.Status,
|
||||
}
|
||||
if hub.Status == "" {
|
||||
hub.Status = "Active"
|
||||
}
|
||||
|
||||
if err := db.DB.Create(&hub).Error; err != nil {
|
||||
return utils.Internal(c, "failed to create hub")
|
||||
}
|
||||
|
||||
return utils.Created(c, hub)
|
||||
}
|
||||
Reference in New Issue
Block a user