stock request table created

This commit is contained in:
2026-07-04 17:49:54 +05:30
parent f220c24c17
commit abe2cb997b
24 changed files with 648 additions and 61 deletions

View File

@@ -377,7 +377,6 @@ func (ctl *OrderController) GetRevenueSummary(c *fiber.Ctx) error {
"status": false,
})
}
return c.Status(http.StatusOK).JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
@@ -386,3 +385,33 @@ func (ctl *OrderController) GetRevenueSummary(c *fiber.Ctx) error {
})
}
func (ctl *OrderController) GetSalesSummary(c *fiber.Ctx) error {
tid, _ := strconv.Atoi(c.Query("tenantid"))
lid, _ := strconv.Atoi(c.Query("locationid"))
fdate := c.Query("fromdate")
tdate := c.Query("todate")
if tid == 0 {
return c.Status(http.StatusBadRequest).JSON(fiber.Map{
"code": http.StatusBadRequest,
"message": "tenantid query parameter is required",
"status": false,
})
}
data, err := ctl.orderService.GetSalesSummary(tid, lid, fdate, tdate)
if err != nil {
return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
"code": http.StatusInternalServerError,
"message": err.Error(),
"status": false,
})
}
return c.Status(http.StatusOK).JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
"details": data,
})
}

View File

@@ -20,7 +20,7 @@ func (ctl *PartnerController) GetActiveRiders(c *fiber.Ctx) error {
pid, _ := strconv.Atoi(c.Query("partnerid"))
aid, _ := strconv.Atoi(c.Query("applocationid"))
uid, _ := strconv.Atoi(c.Query("userid"))
tid,_ := strconv.Atoi(c.Query("tenantid"))
tid, _ := strconv.Atoi(c.Query("tenantid"))
result, err := ctl.partnerService.GetActiveRiders(pid, aid, uid, tid)
if err != nil {
@@ -109,7 +109,6 @@ func (ctl *PartnerController) GetLocationConfig(c *fiber.Ctx) error {
}
func (ctl *PartnerController) GetRiderLogs(c *fiber.Ctx) error {
pid, _ := strconv.Atoi(c.Query("partnerid"))
aid, _ := strconv.Atoi(c.Query("applocationid"))
@@ -134,6 +133,29 @@ func (ctl *PartnerController) GetRiderLogs(c *fiber.Ctx) error {
})
}
func (ctl *PartnerController) GetFleetSummary(c *fiber.Ctx) error {
aid, _ := strconv.Atoi(c.Query("applocationid"))
tid, _ := strconv.Atoi(c.Query("tenantid"))
fdate := c.Query("fromdate")
tdate := c.Query("todate")
result, err := ctl.partnerService.GetFleetSummary(aid, tid, fdate, tdate)
if err != nil {
return c.JSON(fiber.Map{
"status": false,
"code": http.StatusInternalServerError,
"message": err.Error(),
})
}
return c.JSON(fiber.Map{
"status": true,
"code": http.StatusOK,
"message": "Successful",
"details": result,
})
}
func (ctl *PartnerController) GetRiderInfo(c *fiber.Ctx) error {
uid, _ := strconv.Atoi(c.Query("userid"))

View File

@@ -0,0 +1,69 @@
package controllers
import (
"net/http"
"strconv"
"nearle/models"
"nearle/services"
"github.com/gofiber/fiber/v2"
)
type StockRequestController struct {
stockRequestService services.StockRequestService
}
func NewStockRequestController(stockRequestService services.StockRequestService) *StockRequestController {
return &StockRequestController{stockRequestService: stockRequestService}
}
func (ctl *StockRequestController) CreateStockRequest(c *fiber.Ctx) error {
var input models.StockRequest
if err := c.BodyParser(&input); err != nil {
return c.JSON(fiber.Map{"code": http.StatusBadRequest, "message": "Invalid input", "status": false})
}
if input.Status == "" {
input.Status = "Pending"
}
err := ctl.stockRequestService.CreateStockRequest(&input)
if err != nil {
return c.JSON(fiber.Map{"code": http.StatusInternalServerError, "message": err.Error(), "status": false})
}
return c.JSON(fiber.Map{"code": 200, "message": "Stock request created", "status": true, "details": input})
}
func (ctl *StockRequestController) GetStockRequests(c *fiber.Ctx) error {
tenantID, _ := strconv.Atoi(c.Query("tenantid", "0"))
locationID, _ := strconv.Atoi(c.Query("locationid", "0"))
status := c.Query("status", "")
pageNo, _ := strconv.Atoi(c.Query("pageno", "1"))
pageSize, _ := strconv.Atoi(c.Query("pagesize", "50"))
data, err := ctl.stockRequestService.GetStockRequests(tenantID, locationID, status, pageNo, pageSize)
if err != nil {
return c.JSON(fiber.Map{"code": http.StatusInternalServerError, "message": err.Error(), "status": false})
}
return c.JSON(fiber.Map{"code": 200, "message": "Success", "status": true, "details": data})
}
func (ctl *StockRequestController) UpdateStockRequest(c *fiber.Ctx) error {
var input struct {
RequestID int `json:"requestid"`
Status string `json:"status"`
}
if err := c.BodyParser(&input); err != nil {
return c.JSON(fiber.Map{"code": http.StatusBadRequest, "message": "Invalid input", "status": false})
}
err := ctl.stockRequestService.UpdateStockRequest(input.RequestID, input.Status)
if err != nil {
return c.JSON(fiber.Map{"code": http.StatusInternalServerError, "message": err.Error(), "status": false})
}
return c.JSON(fiber.Map{"code": 200, "message": "Stock request updated", "status": true})
}

View File

@@ -252,6 +252,40 @@ func (ctl *TenantController) CreateLocation(c *fiber.Ctx) error {
})
}
func (ctl *TenantController) DeleteLocation(c *fiber.Ctx) error {
locationid, err := strconv.Atoi(c.Query("locationid"))
if err != nil {
return c.Status(http.StatusBadRequest).JSON(fiber.Map{
"code": http.StatusBadRequest,
"message": "Invalid location ID",
"status": false,
})
}
tenantid, err := strconv.Atoi(c.Query("tenantid"))
if err != nil {
return c.Status(http.StatusBadRequest).JSON(fiber.Map{
"code": http.StatusBadRequest,
"message": "Invalid tenant ID",
"status": false,
})
}
if err := ctl.tenantService.DeleteLocation(locationid, tenantid); err != nil {
return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
"code": http.StatusInternalServerError,
"message": err.Error(),
"status": false,
})
}
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Location Successfully Deleted",
"status": true,
})
}
func (ctl *TenantController) GetStaffs(c *fiber.Ctx) error {
tid, _ := strconv.Atoi(c.Query("tenantid"))

32
create_table.go Normal file
View File

@@ -0,0 +1,32 @@
package main
import (
"fmt"
"log"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
func CreateStockRequestsTable() {
dsn := "host=66.116.207.225 user=admin password=Package@123# dbname=nearledb port=5433 sslmode=disable TimeZone=Asia/Kolkata"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatalf("failed to connect database: %v", err)
}
query := `CREATE TABLE IF NOT EXISTS stockrequests (
requestid SERIAL PRIMARY KEY,
tenantid INT NOT NULL,
locationid INT NOT NULL,
productid INT NOT NULL,
qty INT NOT NULL,
status VARCHAR(50) DEFAULT 'Pending',
created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);`
if err := db.Exec(query).Error; err != nil {
log.Fatalf("failed to create table: %v", err)
}
fmt.Println("Table stockrequests created successfully")
}

View File

@@ -16,7 +16,8 @@ type Facade struct {
UtilsController *controllers.UtilsController
TenantController *controllers.TenantController
PartnerController *controllers.PartnerController
CustomerController *controllers.CustomerController
CustomerController *controllers.CustomerController
StockRequestController *controllers.StockRequestController
}
func NewFacade(db *gorm.DB) *Facade {
@@ -61,6 +62,11 @@ func NewFacade(db *gorm.DB) *Facade {
customerService := services.NewCustomerService(customerRepo)
customerController := controllers.NewCustomerController(customerService)
// Stock Request Module
stockRequestRepo := repositories.NewStockRequestRepository(db)
stockRequestService := services.NewStockRequestService(stockRequestRepo, productService)
stockRequestController := controllers.NewStockRequestController(stockRequestService)
return &Facade{
UserController: userController,
ProductController: productController,
@@ -68,7 +74,8 @@ func NewFacade(db *gorm.DB) *Facade {
DeliveriesController: deliveriesController,
UtilsController: utilsController,
TenantController: tenantController,
PartnerController: partnerController,
CustomerController: customerController,
PartnerController: partnerController,
CustomerController: customerController,
StockRequestController: stockRequestController,
}
}

View File

@@ -62,9 +62,8 @@ func selectDBMiddleware(c *fiber.Ctx) error {
}
var currentDB *gorm.DB
if flavour == "dev" {
currentDB = db.DB
} else if flavour == "live" {
switch flavour {
case "dev", "live":
currentDB = db.DB
}

View File

@@ -452,3 +452,21 @@ type LocationRevenueDetails struct {
Revenue float64 `json:"revenue"`
}
type SalesSummaryChartData struct {
Date string `json:"date"`
Revenue float64 `json:"revenue"`
Orders int `json:"orders"`
}
type SalesSummaryTopLocation struct {
Locationname string `json:"locationname"`
Revenue float64 `json:"revenue"`
}
type SalesSummaryResponse struct {
TotalRevenue float64 `json:"totalRevenue"`
TotalOrders int `json:"totalOrders"`
AverageOrderValue float64 `json:"averageOrderValue"`
ChartData []SalesSummaryChartData `json:"chartData"`
TopLocations []SalesSummaryTopLocation `json:"topLocations"`
}

View File

@@ -86,6 +86,31 @@ type Locationconfigs struct {
Status string `json:"status"`
}
type FleetCounts struct {
Totalriders int `json:"totalriders"`
Activeriders int `json:"activeriders"`
Ridersworked int `json:"ridersworked"`
Totallogins int `json:"totallogins"`
}
type FleetRiderSummary struct {
Userid int `json:"userid"`
Fullname string `json:"fullname"`
Contactno string `json:"contactno"`
Partnerid int `json:"partnerid"`
Status string `json:"status"`
Vehicleno string `json:"vehicleno"`
Vehiclename string `json:"vehiclename"`
Dayslogged int `json:"dayslogged"`
Totalworkhours float32 `json:"totalworkhours"`
Totalshorthours float32 `json:"totalshorthours"`
Totalbreakhours float32 `json:"totalbreakhours"`
}
type FleetSummary struct {
Counts FleetCounts `json:"counts"`
Riders []FleetRiderSummary `json:"riders"`
}
type RiderlogDetails struct {
Logid int `json:"logid"`
@@ -103,4 +128,4 @@ type RiderlogDetails struct {
Shorthours float32 `json:"shorthours"`
Breakhours float32 `json:"breakhours"`
Logstatus int `json:"logstatus"`
}
}

20
models/stockrequest.go Normal file
View File

@@ -0,0 +1,20 @@
package models
import "time"
type StockRequest struct {
Requestid int `json:"requestid" gorm:"primaryKey;autoIncrement;column:requestid"`
Tenantid int `json:"tenantid" gorm:"column:tenantid"`
Locationid int `json:"locationid" gorm:"column:locationid"`
Productid int `json:"productid" gorm:"column:productid"`
Productname string `json:"productname" gorm:"->"`
Productimage string `json:"productimage" gorm:"->"`
Qty int `json:"qty" gorm:"column:qty"`
Status string `json:"status" gorm:"column:status;default:Pending"`
Created time.Time `json:"created" gorm:"column:created;autoCreateTime"`
Updated time.Time `json:"updated" gorm:"column:updated;autoUpdateTime"`
}
func (StockRequest) TableName() string {
return "stockrequests"
}

View File

@@ -26,6 +26,7 @@ type OrderRepository interface {
CreateOrder(order models.Orders) (models.Orders, error)
GetCustomerOrdersv3(customerID, tenantID, moduleID, fromDate, toDate, orderStatus, keyword string, pageSize, offset int) ([]models.CustomerOrder, error)
GetRevenueSummary(tid, lid int, fdate, tdate string) (*models.TenantRevenueSummary, error)
GetSalesSummary(tid, lid int, fdate, tdate string) (*models.SalesSummaryResponse, error)
}
type orderRepository struct {
@@ -793,6 +794,100 @@ func (r *orderRepository) GetDistinctLocations() ([]models.OrderInsight, error)
return locations, nil
}
func (r *orderRepository) GetSalesSummary(tid, lid int, fdate, tdate string) (*models.SalesSummaryResponse, error) {
var summary models.SalesSummaryResponse
whereClause := "tenantid = ? AND orderstatus IN ('delivered', 'completed') AND configid = 1"
var params []interface{}
params = append(params, tid)
if lid != 0 {
whereClause += " AND locationid = ?"
params = append(params, lid)
}
if fdate != "" && tdate != "" {
whereClause += " AND orderdate::date BETWEEN ? AND ?"
params = append(params, fdate, tdate)
}
totalsQuery := fmt.Sprintf(`
SELECT
COALESCE(SUM(COALESCE(ordervalue, 0) + COALESCE(orderamount, 0) + COALESCE(deliveryamt, 0)), 0) AS total_revenue,
COUNT(orderheaderid) AS total_orders
FROM orders
WHERE %s`, whereClause)
var result struct {
TotalRevenue float64
TotalOrders int
}
if err := r.db.Raw(totalsQuery, params...).Scan(&result).Error; err != nil {
return nil, err
}
summary.TotalRevenue = result.TotalRevenue
summary.TotalOrders = result.TotalOrders
if summary.TotalOrders > 0 {
summary.AverageOrderValue = summary.TotalRevenue / float64(summary.TotalOrders)
}
chartQuery := fmt.Sprintf(`
SELECT
CAST(orderdate AS DATE) AS date,
COALESCE(SUM(COALESCE(ordervalue, 0) + COALESCE(orderamount, 0) + COALESCE(deliveryamt, 0)), 0) AS revenue,
COUNT(orderheaderid) AS orders
FROM orders
WHERE %s
GROUP BY CAST(orderdate AS DATE)
ORDER BY date ASC`, whereClause)
var chartData []models.SalesSummaryChartData
if err := r.db.Raw(chartQuery, params...).Scan(&chartData).Error; err != nil {
return nil, err
}
if chartData == nil {
chartData = []models.SalesSummaryChartData{}
}
summary.ChartData = chartData
var topLocations []models.SalesSummaryTopLocation
if lid == 0 {
topWhere := "o.tenantid = ? AND o.orderstatus IN ('delivered', 'completed') AND o.configid = 1"
var topParams []interface{}
topParams = append(topParams, tid)
if fdate != "" && tdate != "" {
topWhere += " AND o.orderdate::date BETWEEN ? AND ?"
topParams = append(topParams, fdate, tdate)
}
cleanTopLocQuery := fmt.Sprintf(`
SELECT
COALESCE(l.locationname, 'Unknown') AS locationname,
COALESCE(SUM(COALESCE(o.ordervalue, 0) + COALESCE(o.orderamount, 0) + COALESCE(o.deliveryamt, 0)), 0) AS revenue
FROM orders o
LEFT JOIN tenantlocations l ON o.locationid = l.locationid
WHERE %s
GROUP BY l.locationid, l.locationname
ORDER BY revenue DESC
LIMIT 5`, topWhere)
if err := r.db.Raw(cleanTopLocQuery, topParams...).Scan(&topLocations).Error; err != nil {
return nil, err
}
}
if topLocations == nil {
topLocations = []models.SalesSummaryTopLocation{}
}
summary.TopLocations = topLocations
return &summary, nil
}
func (r *orderRepository) GetMonthlyOrders(applocationid string) (*models.Ordermonths, error) {
var orderMonths models.Ordermonths
@@ -920,13 +1015,14 @@ func (r *orderRepository) getSequenceno(tid int, prefix string) string {
var q1 string
// Formats the ID as tenantid-subprefix+seqno (e.g., 908-20245189)
if prefix == "ORD" {
switch prefix {
case "ORD":
q1 = `SELECT CONCAT(tenantid, '-',
CASE WHEN subprefix IS NULL OR CAST(subprefix AS TEXT) IN ('0', '0.0', '') THEN '' ELSE CAST(subprefix AS TEXT) END,
COALESCE(MAX(orderseqno) + 1, 1)) AS orderseqno
FROM ordersequences WHERE tenantid = ?
GROUP BY tenantid, subprefix`
} else if prefix == "INV" {
case "INV":
q1 = `SELECT CONCAT(tenantid, '-',
CASE WHEN subprefix IS NULL OR CAST(subprefix AS TEXT) IN ('0', '0.0', '') THEN '' ELSE CAST(subprefix AS TEXT) END,
COALESCE(MAX(invoiceseqno) + 1, 1)) AS orderseqno
@@ -947,11 +1043,12 @@ func (r *orderRepository) getSequenceno(tid int, prefix string) string {
func (r *orderRepository) updateSeqno(tid int, prefix string) error {
var field string
if prefix == "ORD" {
switch prefix {
case "ORD":
field = "orderseqno"
} else if prefix == "INV" {
case "INV":
field = "invoiceseqno"
} else {
default:
return fmt.Errorf("invalid prefix: %s", prefix)
}

View File

@@ -15,6 +15,7 @@ type PartnerRepository interface {
GetLocationConfig(uid, cid int) ([]models.Locationconfigs, error)
GetRiderLogs(pid, aid int, fdate, tdate string) ([]models.RiderlogDetails, error)
GetRiderInfo(userid int) (models.RiderInfo, error)
GetFleetSummary(aid, tid int, fdate, tdate string) (models.FleetSummary, error)
}
type partnerRepository struct {
@@ -197,3 +198,100 @@ func (r *partnerRepository) GetRiderInfo(userid int) (models.RiderInfo, error) {
return data, nil
}
func (r *partnerRepository) GetFleetSummary(aid, tid int, fdate, tdate string) (models.FleetSummary, error) {
var summary models.FleetSummary
// --- Fleet membership filter (app_users aliased as a) ---
memberWhere := "a.configid = 6"
var memberArgs []interface{}
if aid != 0 {
memberWhere += " AND a.applocationid = ?"
memberArgs = append(memberArgs, aid)
}
if tid != 0 {
memberWhere += " AND a.tenantid = ?"
memberArgs = append(memberArgs, tid)
}
countsQuery := `
SELECT
COUNT(*) AS totalriders,
COUNT(*) FILTER (WHERE a.status = 'Active') AS activeriders
FROM app_users a
WHERE ` + memberWhere
if err := r.db.Raw(countsQuery, memberArgs...).Scan(&summary.Counts).Error; err != nil {
return models.FleetSummary{}, err
}
// --- Log-range filter (app_users aliased as b, riderlogs as a) ---
logWhere := "b.configid = 6"
var logArgs []interface{}
if aid != 0 {
logWhere += " AND b.applocationid = ?"
logArgs = append(logArgs, aid)
}
if tid != 0 {
logWhere += " AND b.tenantid = ?"
logArgs = append(logArgs, tid)
}
if fdate != "" && tdate != "" {
logWhere += " AND a.logdate::date BETWEEN ? AND ?"
logArgs = append(logArgs, fdate, tdate)
} else {
logWhere += " AND a.logdate::date = CURRENT_DATE"
}
var worked struct {
Ridersworked int `json:"ridersworked"`
Totallogins int `json:"totallogins"`
}
workedQuery := `
SELECT
COUNT(DISTINCT a.userid) AS ridersworked,
COUNT(*) AS totallogins
FROM riderlogs a
INNER JOIN app_users b ON a.userid = b.userid
WHERE ` + logWhere
if err := r.db.Raw(workedQuery, logArgs...).Scan(&worked).Error; err != nil {
return models.FleetSummary{}, err
}
summary.Counts.Ridersworked = worked.Ridersworked
summary.Counts.Totallogins = worked.Totallogins
// --- Per-rider breakdown over the range ---
// Breaks are pre-aggregated per log so the join cannot inflate the work/short-hour sums.
ridersQuery := `
SELECT
b.userid,
CONCAT(b.firstname, ' ', b.lastname) AS fullname,
b.contactno,
b.partnerid,
b.status,
rs.vehicleno,
rs.vehiclename,
COUNT(DISTINCT a.logdate::date) AS dayslogged,
COALESCE(SUM(a.workhours), 0) AS totalworkhours,
COALESCE(SUM(a.shorthours), 0) AS totalshorthours,
COALESCE(SUM(bk.breakhours), 0) AS totalbreakhours
FROM riderlogs a
INNER JOIN app_users b ON a.userid = b.userid
LEFT JOIN ridersettings rs ON b.userid = rs.userid
LEFT JOIN (
SELECT logid, userid, SUM(breakhours) AS breakhours
FROM riderbreaks
GROUP BY logid, userid
) bk ON a.logid = bk.logid AND a.userid = bk.userid
WHERE ` + logWhere + `
GROUP BY b.userid, b.firstname, b.lastname, b.contactno, b.partnerid, b.status, rs.vehicleno, rs.vehiclename
ORDER BY fullname ASC`
if err := r.db.Raw(ridersQuery, logArgs...).Find(&summary.Riders).Error; err != nil {
return models.FleetSummary{}, err
}
return summary, nil
}

View File

@@ -0,0 +1,56 @@
package repositories
import (
"nearle/models"
"gorm.io/gorm"
)
type StockRequestRepository interface {
CreateStockRequest(req *models.StockRequest) error
GetStockRequests(tenantID int, locationID int, status string, pageNo int, pageSize int) ([]models.StockRequest, error)
GetStockRequestByID(requestID int) (*models.StockRequest, error)
UpdateStockRequest(requestID int, status string) error
}
type stockRequestRepository struct {
db *gorm.DB
}
func NewStockRequestRepository(db *gorm.DB) StockRequestRepository {
return &stockRequestRepository{db: db}
}
func (r *stockRequestRepository) CreateStockRequest(req *models.StockRequest) error {
return r.db.Create(req).Error
}
func (r *stockRequestRepository) GetStockRequests(tenantID int, locationID int, status string, pageNo int, pageSize int) ([]models.StockRequest, error) {
var requests []models.StockRequest
query := r.db.Table("stockrequests").
Select("stockrequests.*, products.productname, products.productimage").
Joins("left join products on products.productid = stockrequests.productid").
Where("stockrequests.tenantid = ?", tenantID)
if locationID > 0 {
query = query.Where("stockrequests.locationid = ?", locationID)
}
if status != "" {
query = query.Where("stockrequests.status = ?", status)
}
offset := (pageNo - 1) * pageSize
err := query.Order("stockrequests.created DESC").Offset(offset).Limit(pageSize).Find(&requests).Error
return requests, err
}
func (r *stockRequestRepository) GetStockRequestByID(requestID int) (*models.StockRequest, error) {
var req models.StockRequest
err := r.db.Table("stockrequests").Where("requestid = ?", requestID).First(&req).Error
return &req, err
}
func (r *stockRequestRepository) UpdateStockRequest(requestID int, status string) error {
return r.db.Model(&models.StockRequest{}).Where("requestid = ?", requestID).Update("status", status).Error
}

View File

@@ -21,6 +21,7 @@ type TenantRepository interface {
GetTenantPricing(tid, aid int) (*models.Tenantpricing, error)
UpdateLocation(input models.Tenantlocations) error
CreateLocation(data models.Tenantlocations) error
DeleteLocation(locationid int, tenantid int) error
GetStaffs(tid int) ([]models.StaffInfo, error)
CreateStaff(user models.User) error
UpdateStaff(user models.User) error
@@ -290,52 +291,10 @@ func (r *tenantRepository) UpdateLocation(input models.Tenantlocations) error {
return nil
}
func (r *tenantRepository) CreateLocation(data models.Tenantlocations) error {
var cust models.Customers
var tcust models.Tenantcustomers
var custloc models.Customerlocations
func (r *tenantRepository) DeleteLocation(locationid int, tenantid int) error {
tx := r.db.Begin()
if err := tx.Create(&data).Error; err != nil {
tx.Rollback()
return err
}
cust.Firstname = data.Locationname
cust.Email = data.Email
cust.Contactno = data.Contactno
cust.Address = data.Address
cust.Suburb = data.Suburb
cust.City = data.City
cust.State = data.State
cust.Postcode = data.Postcode
cust.Applocationid = data.Applocationid
cust.Latitude = data.Latitude
cust.Longitude = data.Longitude
cust.Primaryaddress = 0
if err := tx.Table("customers").Create(&cust).Error; err != nil {
tx.Rollback()
return err
}
if err := copier.Copy(&custloc, &cust); err != nil {
tx.Rollback()
return err
}
if err := tx.Table("customerlocations").Create(&custloc).Error; err != nil {
tx.Rollback()
return err
}
tcust.Customerid = cust.Customerid
tcust.Tenantid = data.Tenantid
tcust.Locationid = data.Locationid
tcust.Moduleid = data.Moduleid
if err := tx.Table("tenantcustomers").Create(&tcust).Error; err != nil {
if err := tx.Where("locationid=? AND tenantid=?", locationid, tenantid).Delete(&models.Tenantlocations{}).Error; err != nil {
tx.Rollback()
return err
}
@@ -347,6 +306,13 @@ func (r *tenantRepository) CreateLocation(data models.Tenantlocations) error {
return nil
}
func (r *tenantRepository) CreateLocation(data models.Tenantlocations) error {
if err := r.db.Create(&data).Error; err != nil {
return err
}
return nil
}
func (r *tenantRepository) GetStaffs(tid int) ([]models.StaffInfo, error) {
var data []models.StaffInfo

View File

@@ -24,6 +24,7 @@ type UserRepository interface {
GetUserById(uid int) (models.UserInfo, error)
GetUserLogin(field, value string, configid int) (int, string, string, int)
UpdateUserFcmToken(uid int, token string) error
GetLocationStatus(locationid int) string
}
type userRepository struct {
@@ -277,3 +278,12 @@ func (r *userRepository) UpdateUserFcmToken(userid int, fcmToken string) error {
query := `UPDATE app_users SET userfcmtoken = ? WHERE userid = ?`
return r.db.Exec(query, fcmToken, userid).Error
}
func (r *userRepository) GetLocationStatus(locationid int) string {
var status string
query := `SELECT status FROM tenantlocations WHERE locationid = ?`
r.db.Raw(query, locationid).Row().Scan(&status)
return status
}

View File

@@ -24,6 +24,9 @@ func RegisterOrderRoutes(api fiber.Router, f *facade.Facade) {
orders.Put("/updateorder", f.OrderController.UpdateOrder)
orders.Post("/createorder", f.OrderController.CreateOrderv3)
reports := api.Group("/v1/web/reports")
reports.Get("/sales-summary", f.OrderController.GetSalesSummary)
orders = api.Group("/v1/mob/orders")
orders.Post("/createorder", f.OrderController.CreateOrderv3)

View File

@@ -15,6 +15,7 @@ func RegisterPartnerRoutes(api fiber.Router, f *facade.Facade) {
partner.Get("/getridershifts", f.PartnerController.GetRiderShifts)
partner.Get("/getlocations", f.PartnerController.GetLocationConfig)
partner.Get("/getriderlogs", f.PartnerController.GetRiderLogs)
partner.Get("/getfleetsummary", f.PartnerController.GetFleetSummary)
partner = api.Group("/v1/mob/partners")

View File

@@ -27,6 +27,10 @@ func RegisterProductRoutes(api fiber.Router, f *facade.Facade) {
products.Put("/updateproductlocation", f.ProductController.UpdateProductLocation)
products.Post("/createproductlocation", f.ProductController.CreateProductLocation)
products.Post("/createproductvariant", f.ProductController.CreateProductVariant)
products.Post("/createstockrequest", f.StockRequestController.CreateStockRequest)
products.Get("/getstockrequests", f.StockRequestController.GetStockRequests)
products.Put("/updatestockrequest", f.StockRequestController.UpdateStockRequest)
products = api.Group("/v1/mob/products")

View File

@@ -17,6 +17,7 @@ func RegisterTenantRoutes(api fiber.Router, f *facade.Facade) {
tenant.Post("/createtenantcustomer", f.TenantController.CreateTenantCustomer)
tenant.Put("/updatelocation", f.TenantController.UpdateLocation)
tenant.Post("/createlocation", f.TenantController.CreateLocation)
tenant.Delete("/deletelocation", f.TenantController.DeleteLocation)
tenant.Post("/createtenantlocation", f.TenantController.CreateTenantLocation)
tenant.Put("/updatetenantlocation", f.TenantController.UpdateTenantLocation)

View File

@@ -21,6 +21,7 @@ type OrderService interface {
GetCustomerOrdersv3(customerID, tenantID, moduleID, fromDate, toDate, orderStatus, keyword string, pageSize, offset int) ([]models.CustomerOrder, error)
GetTenantLocationOrders(input models.DeliveryQuery) ([]models.OrderInfo, error)
GetRevenueSummary(tid, lid int, fdate, tdate string) (*models.TenantRevenueSummary, error)
GetSalesSummary(tid, lid int, fdate, tdate string) (*models.SalesSummaryResponse, error)
}
type orderService struct {
@@ -91,3 +92,7 @@ func (s *orderService) GetRevenueSummary(tid, lid int, fdate, tdate string) (*mo
return s.repo.GetRevenueSummary(tid, lid, fdate, tdate)
}
func (s *orderService) GetSalesSummary(tid, lid int, fdate, tdate string) (*models.SalesSummaryResponse, error) {
return s.repo.GetSalesSummary(tid, lid, fdate, tdate)
}

View File

@@ -12,6 +12,7 @@ type PartnerService interface {
GetLocationConfig(uid, cid int) ([]models.Locationconfigs, error)
GetRiderLogs(pid, aid int, fdate, tdate string) ([]models.RiderlogDetails, error)
GetRiderInfo(userid int) (models.RiderInfo, error)
GetFleetSummary(aid, tid int, fdate, tdate string) (models.FleetSummary, error)
}
type partnerService struct {
@@ -53,3 +54,7 @@ func (s *partnerService) GetRiderLogs(pid, aid int, fdate, tdate string) ([]mode
func (s *partnerService) GetRiderInfo(userid int) (models.RiderInfo, error) {
return s.repo.GetRiderInfo(userid)
}
func (s *partnerService) GetFleetSummary(aid, tid int, fdate, tdate string) (models.FleetSummary, error) {
return s.repo.GetFleetSummary(aid, tid, fdate, tdate)
}

View File

@@ -0,0 +1,58 @@
package services
import (
"nearle/models"
"nearle/repositories"
"time"
)
type StockRequestService interface {
CreateStockRequest(req *models.StockRequest) error
GetStockRequests(tenantID int, locationID int, status string, pageNo int, pageSize int) ([]models.StockRequest, error)
UpdateStockRequest(requestID int, status string) error
}
type stockRequestService struct {
repo repositories.StockRequestRepository
productService ProductService
}
func NewStockRequestService(repo repositories.StockRequestRepository, productService ProductService) StockRequestService {
return &stockRequestService{repo: repo, productService: productService}
}
func (s *stockRequestService) CreateStockRequest(req *models.StockRequest) error {
return s.repo.CreateStockRequest(req)
}
func (s *stockRequestService) GetStockRequests(tenantID int, locationID int, status string, pageNo int, pageSize int) ([]models.StockRequest, error) {
return s.repo.GetStockRequests(tenantID, locationID, status, pageNo, pageSize)
}
func (s *stockRequestService) UpdateStockRequest(requestID int, status string) error {
// If the request is being marked as Received, we need to update the actual store inventory
if status == "Received" {
req, err := s.repo.GetStockRequestByID(requestID)
if err != nil {
return err
}
if req.Status != "Received" { // prevent double receiving
stk := models.Productstock{
Tenantid: req.Tenantid,
Locationid: req.Locationid,
Productid: req.Productid,
Quantity: req.Qty,
Stocktype: "Credit",
Stockdate: time.Now(),
}
err = s.productService.CreateProductStock([]models.Productstock{stk})
if err != nil {
return err
}
}
}
return s.repo.UpdateStockRequest(requestID, status)
}

View File

@@ -17,6 +17,7 @@ type TenantService interface {
GetTenantPricing(tid, aid int) (models.Tenantpricing, error)
UpdateLocation(input models.Tenantlocations) error
CreateLocation(data models.Tenantlocations) error
DeleteLocation(locationid int, tenantid int) error
GetStaffs(tid int) ([]models.StaffInfo, error)
CreateStaff(user models.User) error
UpdateStaff(user models.User) error
@@ -89,6 +90,10 @@ func (s *tenantService) CreateLocation(data models.Tenantlocations) error {
return s.repo.CreateLocation(data)
}
func (s *tenantService) DeleteLocation(locationid int, tenantid int) error {
return s.repo.DeleteLocation(locationid, tenantid)
}
func (s *tenantService) GetStaffs(tid int) ([]models.StaffInfo, error) {
return s.repo.GetStaffs(tid)
}

View File

@@ -143,6 +143,19 @@ func (s *userService) AppLogin(user models.User) (models.TenantUserInfo, fiber.M
// ✅ Fetch tenant user info
info := s.repo.GetTenantUserById(uid)
// ✅ Check if assigned store is inactive
if info.Locationid > 0 {
storeStatus := s.repo.GetLocationStatus(info.Locationid)
if storeStatus == "InActive" {
resp := fiber.Map{
"status": false,
"code": 403,
"message": "Assigned store is inactive. Contact admin.",
}
return models.TenantUserInfo{}, resp, errors.New("inactive store")
}
}
// ✅ Return success response
resp := fiber.Map{
"status": true,
@@ -247,8 +260,6 @@ func (s *userService) TenantWebLogin(user models.User) (models.TenantUserInfo, m
}
}
user.Userid = uid
// Step 4: Update FCM if provided
if user.Userfcmtoken != "" {
_ = s.repo.UpdateUserFcmToken(uid, user.Userfcmtoken)
@@ -257,6 +268,18 @@ func (s *userService) TenantWebLogin(user models.User) (models.TenantUserInfo, m
// Step 5: Get full tenant info
info := s.repo.GetTenantUserById(uid)
// Step 6: Check if assigned store is inactive
if info.Locationid > 0 {
storeStatus := s.repo.GetLocationStatus(info.Locationid)
if storeStatus == "InActive" {
return models.TenantUserInfo{}, map[string]interface{}{
"status": false,
"code": 403,
"message": "Assigned store is inactive. Contact admin.",
}
}
}
return info, map[string]interface{}{
"status": true,
"code": 200,