intial commit

This commit is contained in:
2026-05-25 11:45:56 +05:30
commit 6ab508560f
73 changed files with 23713 additions and 0 deletions

14
.env Normal file
View File

@@ -0,0 +1,14 @@
APP_PORT=1009
DB_HOST=66.116.207.225
DB_PORT=6432
DB_NAME=nearledb
DB_USER=admin
DB_PASSWORD=Package@123#
DO_SPACES_REGION=sgp1
DO_SPACES_ENDPOINT=sgp1.digitaloceanspaces.com
DO_SPACES_BUCKET=nearle
DO_SPACES_ACCESS_KEY=DO00NQER7N2FRYZAB2HR
DO_SPACES_SECRET_KEY=nMDewX25IBEu1FM5dakK+v28/WbW3TzBAwq913+dxP0

50
.gitignore vendored Normal file
View File

@@ -0,0 +1,50 @@
# These are some examples of commonly ignored file patterns.
# You should customize this list as applicable to your project.
# Learn more about .gitignore:
# https://www.atlassian.com/git/tutorials/saving-changes/gitignore
# Node artifact files
node_modules/
dist/
# Compiled Java class files
*.class
# Compiled Python bytecode
*.py[cod]
# Log files
*.log
# Package files
*.jar
# Maven
target/
dist/
# JetBrains IDE
.idea/
# Unit test reports
TEST*.xml
# Generated by MacOS
.DS_Store
# Generated by Windows
Thumbs.db
# Applications
*.app
*.exe
*.war
# Large media files
*.mp4
*.tiff
*.avi
*.flv
*.mov
*.wmv

18
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,18 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Connect to server",
"type": "go",
"request": "attach",
"mode": "remote",
"remotePath": "${workspaceFolder}",
"port": 2345,
"host": "127.0.0.1"
}
]
}

24
Dockerfile Normal file
View File

@@ -0,0 +1,24 @@
# First Stage
FROM golang:1.24
RUN mkdir /app
ADD . /app/
WORKDIR /app
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o server .
# Second Stage
FROM alpine
# Fix: Alpine needs ca-certificates to verify Google API SSL certificates
RUN apk add --no-cache ca-certificates
# Copy from first stage
COPY --from=0 /app/server /app/server
COPY nearle-gear-firebase-adminsdk-l9oha-23ca3b3609.json /app/
WORKDIR /app
# Default startup command
CMD ["./server"]

View File

@@ -0,0 +1,35 @@
-- =============================================================================
-- Migration: Add GPS Tracking Fields
-- Date: 2026-03-11
-- Description: Adds raw GPS, velocity, speed and heading columns to the
-- deliveries and deliverylogs tables.
--
-- All columns are nullable so that:
-- 1. Old rider app versions that don't send these fields continue to work.
-- 2. Existing rows are not affected (they will have NULL values).
--
-- Safe to re-run: each ALTER uses IF NOT EXISTS column check pattern.
-- =============================================================================
-- -----------------------------------------------------------------------------
-- Table: deliverylogs
-- -----------------------------------------------------------------------------
ALTER TABLE deliverylogs
ADD COLUMN IF NOT EXISTS raw_latitude VARCHAR(20) NULL DEFAULT NULL COMMENT 'Raw (unfiltered) GPS latitude from device',
ADD COLUMN IF NOT EXISTS raw_longitude VARCHAR(20) NULL DEFAULT NULL COMMENT 'Raw (unfiltered) GPS longitude from device',
ADD COLUMN IF NOT EXISTS velocity_lat VARCHAR(20) NULL DEFAULT NULL COMMENT 'Kalman-filtered velocity component (latitude direction)',
ADD COLUMN IF NOT EXISTS velocity_lng VARCHAR(20) NULL DEFAULT NULL COMMENT 'Kalman-filtered velocity component (longitude direction)',
ADD COLUMN IF NOT EXISTS speed VARCHAR(10) NULL DEFAULT NULL COMMENT 'Calculated speed in m/s or km/h',
ADD COLUMN IF NOT EXISTS heading VARCHAR(10) NULL DEFAULT NULL COMMENT 'Bearing/direction in degrees (0-360)';
-- =============================================================================
-- Verification queries (run after migration to confirm columns exist):
-- =============================================================================
-- SHOW COLUMNS FROM deliveries LIKE 'raw_%';
-- SHOW COLUMNS FROM deliveries LIKE 'velocity_%';
-- SHOW COLUMNS FROM deliveries LIKE 'speed';
-- SHOW COLUMNS FROM deliveries LIKE 'heading';
-- SHOW COLUMNS FROM deliverylogs LIKE 'raw_%';
-- SHOW COLUMNS FROM deliverylogs LIKE 'velocity_%';
-- SHOW COLUMNS FROM deliverylogs LIKE 'speed';
-- SHOW COLUMNS FROM deliverylogs LIKE 'heading';

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,90 @@
package main
import (
"os"
"path/filepath"
"nearle/db"
"nearle/internal/backup"
"nearle/utils"
"github.com/joho/godotenv"
)
func main() {
// 👇 Load .env
if err := godotenv.Load(".env"); err != nil {
utils.Logger.Fatalf("❌ Failed to load .env file: %v", err)
}
utils.Logger.Infof("DB_USER = %s", os.Getenv("DB_USER"))
utils.Logger.Infof("DB_NAME = %s", os.Getenv("DB_NAME"))
// 🔌 Connect DB
db.Connect()
sqlDB, err := db.DB.DB()
if err != nil {
utils.Logger.Fatal(err)
}
// ================================
// 1⃣ deliverylogs
// ================================
utils.Info("▶ Backing up deliverylogs...")
deliveryLogsFile, err := backup.BackupDeliveryLogs(sqlDB)
if err != nil {
utils.Logger.Fatalf("❌ deliverylogs backup failed: %v", err)
}
utils.Info("☁️ Uploading deliverylogs parquet...")
url, err := backup.UploadParquetToSpaces(
deliveryLogsFile,
"parquet/deliverylogs/"+filepath.Base(deliveryLogsFile),
)
if err != nil {
utils.Logger.Fatalf("❌ deliverylogs upload failed: %v", err)
}
utils.Logger.Infof("✅ Uploaded: %s", url)
// ================================
// 2⃣ deliveries
// ================================
utils.Info("▶ Backing up deliveries...")
deliveriesFile, err := backup.BackupDeliveries(sqlDB)
if err != nil {
utils.Logger.Fatalf("❌ deliveries backup failed: %v", err)
}
utils.Info("☁️ Uploading deliveries parquet...")
url, err = backup.UploadParquetToSpaces(
deliveriesFile,
"parquet/deliveries/"+filepath.Base(deliveriesFile),
)
if err != nil {
utils.Logger.Fatalf("❌ deliveries upload failed: %v", err)
}
utils.Logger.Infof("✅ Uploaded: %s", url)
// ================================
// 3⃣ orders ✅ NEW
// ================================
utils.Info("▶ Backing up orders...")
ordersFile, err := backup.BackupOrders(sqlDB)
if err != nil {
utils.Logger.Fatalf("❌ orders backup failed: %v", err)
}
utils.Info("☁️ Uploading orders parquet...")
url, err = backup.UploadParquetToSpaces(
ordersFile,
"parquet/orders/"+filepath.Base(ordersFile),
)
if err != nil {
utils.Logger.Fatalf("❌ orders upload failed: %v", err)
}
utils.Logger.Infof("✅ Uploaded: %s", url)
utils.Info("🎉 Parquet backup + S3 upload completed successfully")
}

49
config/config.go Normal file
View File

@@ -0,0 +1,49 @@
package config
import (
"nearle/utils"
"os"
)
type Config struct {
Env string
Port string
DBName string
DBUser string
DBPassword string
DBPort string
DBHost string
UserContextKey string
JWTSecret string
}
func Load() *Config {
cfg := &Config{
Env: getEnv("ENV", "production"),
Port: getEnv("APP_PORT", "1009"),
// ✅ STANDARDIZED DB ENV KEYS
DBName: getEnv("DB_NAME", ""),
DBUser: getEnv("DB_USER", ""),
DBPassword: getEnv("DB_PASSWORD", ""),
DBPort: getEnv("DB_PORT", "5432"),
DBHost: getEnv("DB_HOST", "localhost"),
UserContextKey: getEnv("USER_CONTEXT_KEY", "nearle"),
JWTSecret: getEnv("JWT_SECRET_KEY", ""),
}
// ✅ Correct validation
if cfg.DBPassword == "" {
utils.Logger.Warn("Warning: DB_PASSWORD is not set")
}
return cfg
}
func getEnv(key, fallback string) string {
if v := os.Getenv(key); v != "" {
return v
}
return fallback
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,448 @@
package controllers
import (
"nearle/db"
"nearle/domain"
"nearle/models"
"nearle/utils"
"net/http"
"strconv"
"time"
"github.com/gofiber/fiber/v2"
)
func CreateCustomer(c *fiber.Ctx) error {
var data models.Customers
var id int
if err := c.BodyParser(&data); err != nil {
utils.Error("CreateCustomer body parse error", "error", err)
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"code": http.StatusBadRequest,
"message": err.Error(),
"status": false,
})
}
// return c.JSON(fiber.Map{
// "status": false,
// "code": http.StatusConflict,
// "message": "Customer Already available",
// })
cid := domain.CheckCustomer(data.Contactno)
if cid != 0 {
data.Customerid = cid
tcid := domain.CheckTenantCustomer(data.Customerid, data.Tenantid)
if tcid == 0 {
id = domain.CreateTenantCustomer(data)
} else {
return c.JSON(fiber.Map{
"status": false,
"code": http.StatusConflict,
"message": "Customer Already available",
})
}
} else {
id = domain.CreateCustomer(data)
}
if id != 0 {
result := domain.GetCustomer(id, "")
return c.JSON(fiber.Map{
"status": true,
"code": http.StatusCreated,
"message": "Successful",
"details": result,
})
} else {
return c.JSON(fiber.Map{
"status": false,
"code": http.StatusConflict,
"message": "Failed",
})
}
}
func UpdateCustomer(c *fiber.Ctx) error {
var data models.Customers
if err := c.BodyParser(&data); err != nil {
utils.Error("UpdateCustomer body parse error", "error", err)
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"code": http.StatusBadRequest,
"message": err.Error(),
"status": false,
})
}
result := domain.UpdateCustomer(data)
if !result.Status {
return c.JSON(fiber.Map{
"status": false,
"code": http.StatusConflict,
"message": "Failed",
})
}
return c.JSON(fiber.Map{
"status": true,
"code": http.StatusAccepted,
"message": "Customer update successful",
})
}
func GetCustomer(c *fiber.Ctx) error {
cid, _ := strconv.Atoi(c.Query("customerid"))
cno := c.Query("contactno")
result := domain.GetCustomer(cid, cno)
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
"details": result,
})
}
func GetTenantCustomers(c *fiber.Ctx) error {
tid, _ := strconv.Atoi(c.Query("tenantid"))
lid, _ := strconv.Atoi(c.Query("locationid"))
aid, _ := strconv.Atoi(c.Query("applocationid"))
pageno, _ := strconv.Atoi(c.Query("pageno"))
pagesize, _ := strconv.Atoi(c.Query("pagesize"))
keyword := c.Query("keyword")
result := domain.GetTenantCustomers(tid, lid, aid, pageno, pagesize, keyword)
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
"details": result,
})
}
func GetCustomersbytenent(c *fiber.Ctx) error {
tid, _ := strconv.Atoi(c.Query("tenantid"))
lid, _ := strconv.Atoi(c.Query("locationid"))
//aid, _ := strconv.Atoi(c.Query("applocationid"))
result := domain.GetCustomerbytenant(tid, lid)
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
"details": result,
})
}
func GetCustomersbyapplocation(c *fiber.Ctx) error {
tid, _ := strconv.Atoi(c.Query("applocationid"))
result := domain.GetCustomerbyApplocation(tid)
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
"details": result,
})
}
func GetallCustomers(c *fiber.Ctx) error {
pageno, _ := strconv.Atoi(c.Query("pageno"))
pagesize, _ := strconv.Atoi(c.Query("pagesize"))
aid, _ := strconv.Atoi(c.Query("applocationid"))
keyword := c.Query("keyword") // <-- new param
result := domain.GetallCustomers(aid, pageno, pagesize, keyword)
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
"details": result,
})
}
func SearchCustomer(c *fiber.Ctx) error {
keyword := c.Query("keyword")
tid, _ := strconv.Atoi(c.Query("tenantid"))
result := domain.SearchCustomer(keyword, tid)
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
"details": result,
})
}
func DeleteCustomer(c *fiber.Ctx) error {
cid, _ := strconv.Atoi(c.Query("customerid"))
count := GetCustomerOrderCount(cid)
if count == 0 {
tx := db.DB.Begin()
t1 := tx.Table("customers").Where("customerid = ?", cid).Delete(&models.Customers{})
if t1.Error != nil {
utils.Error("DeleteCustomer t1 delete error", "error", t1.Error)
tx.Rollback()
return c.JSON(fiber.Map{
"code": http.StatusInternalServerError,
"message": "Error deleting customer",
"status": false,
})
}
t2 := tx.Table("customerlocations").Where("customerid = ?", cid).Delete(&models.Customerlocations{})
if t2.Error != nil {
utils.Error("DeleteCustomer t2 delete error", "error", t2.Error)
tx.Rollback()
return c.JSON(fiber.Map{
"code": http.StatusInternalServerError,
"message": "Error deleting customer",
"status": false,
})
}
t3 := tx.Table("tenantcustomers").Where("customerid = ?", cid).Delete(&models.Tenantcustomers{})
if t3.Error != nil {
utils.Error("DeleteCustomer t3 delete error", "error", t3.Error)
tx.Rollback()
return c.JSON(fiber.Map{
"code": http.StatusInternalServerError,
"message": "Error deleting customer",
"status": false,
})
}
tx.Commit()
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
})
}
return c.JSON(fiber.Map{
"code": http.StatusConflict,
"message": "Orders available for customers",
"status": false,
})
}
func CreateCustomerLocation(c *fiber.Ctx) error {
var data models.Customerlocations
if err := c.BodyParser(&data); err != nil {
utils.Error("CreateCustomerLocation body parse error", "error", err)
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"code": http.StatusBadRequest,
"message": err.Error(),
"status": false,
})
}
id := domain.CreateCustomerLocation(data)
if id != 0 {
result := domain.GetCustomerLocation(id)
return c.JSON(result)
} else {
return c.JSON(fiber.Map{
"status": false,
"code": http.StatusConflict,
"message": "Failed",
})
}
}
func GetCustomerLocations(c *fiber.Ctx) error {
cid, _ := strconv.Atoi(c.Query("customerid"))
result := domain.GetCustomerLocation(cid)
return c.JSON(result)
}
func CreateCustomerRequest(c *fiber.Ctx) error {
var req models.CustomerRequest
if err := c.BodyParser(&req); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"code": 400,
"message": "Invalid request body",
"status": false,
})
}
now := time.Now()
req.Created = now
req.Updated = now
// Insert into database
if err := db.DB.Table("customerrequest").Create(&req).Error; err != nil {
utils.Error("CreateCustomerRequest DB error", "error", err)
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"code": 500,
"message": "Failed to create customer request",
"status": false,
})
}
return c.Status(fiber.StatusCreated).JSON(fiber.Map{
"code": 201,
"message": "Customer request created successfully",
"status": true,
"data": req,
})
}
func GetCustomerRequests(c *fiber.Ctx) error {
customerIDStr := c.Query("customerid")
pageNoStr := c.Query("pageno", "1")
pageSizeStr := c.Query("pagesize", "10")
pageNo, _ := strconv.Atoi(pageNoStr)
pageSize, _ := strconv.Atoi(pageSizeStr)
if pageNo < 1 {
pageNo = 1
}
if pageSize < 1 {
pageSize = 10
}
offset := (pageNo - 1) * pageSize
var requests []models.CustomerRequest
query := db.DB.Table("customerrequest")
// Optional filter by customerid
if customerIDStr != "" {
customerID, err := strconv.Atoi(customerIDStr)
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"code": 400,
"message": "Invalid customerid",
"status": false,
})
}
if customerID != 0 {
query = query.Where("customerid = ?", customerID)
}
}
var total int64
query.Count(&total)
if err := query.Order("created desc").Offset(offset).Limit(pageSize).Find(&requests).Error; err != nil {
utils.Error("GetCustomerRequests DB error", "error", err)
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"code": 500,
"message": "Failed to fetch customer requests",
"status": false,
})
}
return c.Status(fiber.StatusOK).JSON(fiber.Map{
"code": 200,
"message": "Customer requests fetched successfully",
"status": true,
"data": requests,
})
}
func GetCustomerSummary(c *fiber.Ctx) error {
aid, _ := strconv.Atoi(c.Query("applocationid", "0"))
tid, _ := strconv.Atoi(c.Query("tenantid", "0"))
// Initialize query builder
query := db.DB.Table("customers as a").
Joins("INNER JOIN customerlocations b ON a.customerid = b.customerid").
Where("b.primaryaddress = 1")
if aid != 0 {
query = query.Where("a.applocationid = ?", aid)
}
if tid != 0 {
query = query.Joins("INNER JOIN tenantcustomers ct ON a.customerid = ct.customerid").
Where("ct.tenantid = ?", tid)
}
type Summary struct {
Total int64
Active int64
Inactive int64
}
var summary Summary
// Execute consolidated summary counts
err := query.Select(`
COUNT(DISTINCT a.customerid) AS total,
COUNT(DISTINCT CASE WHEN a.status = 0 THEN a.customerid END) AS active,
COUNT(DISTINCT CASE WHEN a.status = 1 THEN a.customerid END) AS inactive`).
Scan(&summary).Error
if err != nil {
utils.Error("GetCustomerSummary DB error", "error", err)
return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
"code": http.StatusInternalServerError,
"message": "Failed to fetch customer summary",
"status": false,
})
}
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Customer summary fetched successfully",
"status": true,
"summary": summary,
})
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,153 @@
package controllers
import (
"nearle/domain"
"nearle/models"
"net/http"
"strconv"
"github.com/gofiber/fiber/v2"
)
func InvoiceSeqno(c *fiber.Ctx) error {
tid, _ := strconv.Atoi(c.Query("tenantid"))
seqno := domain.GetSequenceno(tid, "INV")
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
"Details": seqno,
})
}
func CreateInvoice(c *fiber.Ctx) error {
var data models.Tenantsales
if err := c.BodyParser(&data); err != nil {
return err
}
err := domain.CreateInvoice(data)
if err != nil {
return c.JSON(fiber.Map{
"code": http.StatusConflict,
"message": err.Error(),
"status": false,
})
}
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
})
}
func GetallInvoice(c *fiber.Ctx) error {
status, _ := strconv.Atoi(c.Query("billstatus"))
tid, _ := strconv.Atoi(c.Query("tenantid"))
result := domain.GetAllInvoice(status, tid)
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
"details": result,
})
}
func GetInvoiceOrders(c *fiber.Ctx) error {
fdate := c.Query("fromdate")
tdate := c.Query("todate")
tid, _ := strconv.Atoi(c.Query("tenantid"))
result := domain.GetInvoiceOrders(tid, fdate, tdate)
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
"details": result,
})
}
func GetInvoiceInsight(c *fiber.Ctx) error {
tid, _ := strconv.Atoi(c.Query("tenantid"))
result := domain.GetInvoiceInsight(tid)
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
"details": result,
})
}
func UpdateInvoice(c *fiber.Ctx) error {
var data models.Tenantsales
if err := c.BodyParser(&data); err != nil {
return err
}
err := domain.UpdateInvoice(data)
if err != nil {
return c.JSON(fiber.Map{
"code": http.StatusConflict,
"message": err.Error(),
"status": false,
})
}
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
})
}
func UpdateInvoiceStatus(c *fiber.Ctx) error {
var data models.InvoiceStatus
if err := c.BodyParser(&data); err != nil {
return err
}
err := domain.UpdateInvoiceStatus(data)
if err != nil {
return c.JSON(fiber.Map{
"code": http.StatusConflict,
"message": err.Error(),
"status": false,
})
}
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
})
}

View File

@@ -0,0 +1,141 @@
package controllers
import (
"context"
"nearle/domain"
"nearle/models"
"nearle/utils"
"net/http"
"sync"
firebase "firebase.google.com/go"
"firebase.google.com/go/messaging"
"github.com/gofiber/fiber/v2"
"google.golang.org/api/option"
)
var (
fcmApp *firebase.App
fcmClient *messaging.Client
fcmOnce sync.Once
fcmInitErr error
)
// getFCMClient handles the singleton initialization of Firebase
func getFCMClient() (*messaging.Client, error) {
fcmOnce.Do(func() {
ctx := context.Background()
opt := option.WithCredentialsFile("nearle-gear-firebase-adminsdk-l9oha-23ca3b3609.json")
app, err := firebase.NewApp(ctx, nil, opt)
if err != nil {
fcmInitErr = err
return
}
fcmApp = app
client, err := app.Messaging(ctx)
if err != nil {
fcmInitErr = err
return
}
fcmClient = client
})
return fcmClient, fcmInitErr
}
func NotifyUser(c *fiber.Ctx) error {
// Parse the request body
var body struct {
Token string `json:"token"`
Notification models.FcmNotification `json:"notification"`
Data map[string]string `json:"data"`
}
if err := c.BodyParser(&body); err != nil {
utils.Error("NotifyUser parsing body error", "error", err)
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"code": http.StatusBadRequest,
"message": err.Error(),
"status": false,
})
}
// Use shared client instead of initializing on every request
client, err := getFCMClient()
if err != nil {
utils.Error("NotifyUser Firebase initialization error", "error", err)
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"code": http.StatusInternalServerError,
"message": "FCM Initialization error: " + err.Error(),
"status": false,
})
}
// Construct the message
message := &messaging.Message{
Token: body.Token,
Notification: &messaging.Notification{
Title: body.Notification.Title,
Body: body.Notification.Body,
},
Android: &messaging.AndroidConfig{
Priority: "high",
Notification: &messaging.AndroidNotification{
Sound: "ring",
},
},
Data: body.Data,
}
// Send the message
_, err = client.Send(context.Background(), message)
if err != nil {
utils.Error("NotifyUser FCM send error", "error", err)
return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
"code": http.StatusInternalServerError,
"message": err.Error(),
"status": false,
})
}
// Return structured response
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "FCM message sent successfully!",
"status": true,
})
}
func NotifyUsers(c *fiber.Ctx) error {
var data models.Notifications
if err := c.BodyParser(&data); err != nil {
utils.Error("NotifyUsers parsing body error", "error", err)
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"code": http.StatusBadRequest,
"message": err.Error(),
"status": false,
})
}
result := domain.SendNotifications(data)
if !result {
utils.Error("NotifyUsers bulk send failed")
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Failed to send notifications",
"status": false,
})
}
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
})
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,55 @@
package controllers
import (
"nearle/db"
"nearle/models"
"net/http"
"strconv"
"github.com/gofiber/fiber/v2"
)
func CreatePaymentRequest(c *fiber.Ctx) error {
var data models.Paymentrequests
if err := c.BodyParser(&data); err != nil {
return err
}
err := db.DB.Create(&data).Error
if err != nil {
return c.JSON(fiber.Map{
"code": http.StatusConflict,
"message": err.Error(),
"status": false,
})
}
return c.JSON(fiber.Map{
"code": http.StatusCreated,
"message": "Success",
"status": true,
})
}
func GetPaymentRequests(c *fiber.Ctx) error {
var data []models.RequestInfo
pid, _ := strconv.Atoi(c.Query("partnerid"))
status, _ := strconv.Atoi(c.Query("status"))
q1 := "select * from paymentrequests where partnerid=? and status=?"
db.DB.Raw(q1, pid, status).Find(&data)
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
"details": data,
})
}

37
controllers/platform.go Normal file
View File

@@ -0,0 +1,37 @@
package controllers
import (
"nearle/domain"
"net/http"
"strconv"
"github.com/gofiber/fiber/v2"
)
func GetModules(c *fiber.Ctx) error {
mid, _ := strconv.Atoi(c.Query("moduleid"))
result := domain.GetModules(mid)
return c.JSON(fiber.Map{
"code": http.StatusCreated,
"message": "Success",
"status": true,
"details": result,
})
}
func GetSmsProvider(c *fiber.Ctx) error {
tid, _ := strconv.Atoi(c.Query("templatetypeid"))
result := domain.GetSmsprovider(tid)
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
"details": result,
})
}

View File

@@ -0,0 +1,868 @@
package controllers
import (
"nearle/db"
"nearle/domain"
"nearle/models"
"nearle/utils"
"net/http"
"strconv"
"strings"
"time"
"github.com/gofiber/fiber/v2"
)
func GetProductInfo(c *fiber.Ctx) error {
pid, _ := strconv.Atoi(c.Query("productid"))
utils.Logger.Debugf("productid: %d", pid)
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
})
}
func GetProducts(c *fiber.Ctx) error {
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
})
}
func GetProductCategory(c *fiber.Ctx) error {
data := domain.GetProductCategory()
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
"details": data,
})
}
func GetProductSubCategory(c *fiber.Ctx) error {
categoryID, _ := strconv.Atoi(c.Query("categoryid"))
tenantID, _ := strconv.Atoi(c.Query("tenantid"))
data := domain.GetProductSubCategory(categoryID, tenantID)
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
"details": data,
})
}
func CreateProductVariant(c *fiber.Ctx) error {
var input models.Productvariant
if err := c.BodyParser(&input); err != nil {
return c.Status(http.StatusBadRequest).JSON(fiber.Map{
"code": http.StatusBadRequest,
"message": "Invalid request body",
"status": false,
})
}
if err := domain.CreateProductVariant(input); err != nil {
return c.JSON(fiber.Map{
"code": http.StatusConflict,
"message": "Failed",
"status": false,
})
}
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
})
}
func CreateProduct(c *fiber.Ctx) error {
var product models.Products
if err := c.BodyParser(&product); err != nil {
return c.Status(http.StatusBadRequest).JSON(fiber.Map{
"code": http.StatusBadRequest,
"message": "Invalid request body",
"status": false,
})
}
if err := domain.CreateProduct(&product); err != nil {
return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
"code": http.StatusInternalServerError,
"message": "Failed to create product",
"status": false,
})
}
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Product created successfully",
"status": true,
})
}
func GetAllProducts(c *fiber.Ctx) error {
categoryID, _ := strconv.Atoi(c.Query("categoryid"))
subcategoryID, _ := strconv.Atoi(c.Query("subcategoryid"))
productID, _ := strconv.Atoi(c.Query("productid"))
applocationID, _ := strconv.Atoi(c.Query("applocationid"))
tenantID, _ := strconv.Atoi(c.Query("tenantid"))
locationID, _ := strconv.Atoi(c.Query("locationid"))
keyword := c.Query("keyword", "")
productStatus := c.Query("productstatus", "")
approve := c.Query("approve", "")
pageno, _ := strconv.Atoi(c.Query("pageno"))
pagesize, _ := strconv.Atoi(c.Query("pagesize"))
details, err := domain.FetchFilteredProducts(
categoryID, subcategoryID, productID, applocationID, tenantID,
locationID, keyword, productStatus, approve, pageno, pagesize,
)
if err != nil {
return c.JSON(fiber.Map{
"code": http.StatusConflict,
"message": "Failed",
"status": false,
})
}
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
"data": details,
})
}
func UpdateProduct(c *fiber.Ctx) error {
var data models.Products
if err := c.BodyParser(&data); err != nil {
return err
}
err := domain.UpdateProduct(data)
if err != nil {
return c.JSON(fiber.Map{
"status": false,
"code": http.StatusConflict,
"message": err,
})
}
return c.JSON(fiber.Map{
"status": true,
"code": http.StatusAccepted,
"message": "Product update successful",
})
}
func DeleteProduct(c *fiber.Ctx) error {
// Get product ID from query
pidStr := c.Query("productid")
pid, err := strconv.Atoi(pidStr)
if err != nil || pid <= 0 {
return c.JSON(fiber.Map{
"code": http.StatusBadRequest,
"message": "Invalid product ID",
"status": false,
})
}
// Start transaction
tx := db.DB.Begin()
if tx.Error != nil {
return c.JSON(fiber.Map{
"code": http.StatusInternalServerError,
"message": "Failed to start transaction",
"status": false,
})
}
// Delete product
if err := tx.Table("products").Where("productid = ?", pid).Delete(&models.Products{}).Error; err != nil {
tx.Rollback()
return c.JSON(fiber.Map{
"code": http.StatusInternalServerError,
"message": "Error deleting product",
"status": false,
})
}
// Commit transaction
if err := tx.Commit().Error; err != nil {
return c.JSON(fiber.Map{
"code": http.StatusInternalServerError,
"message": "Failed to commit transaction",
"status": false,
})
}
// Success response
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
})
}
func GetProductsBySubcategory(c *fiber.Ctx) error {
// log.Println("Handler: GetProductsBySubcategory called")
// Required query param: categoryid
categoryIDStr := c.Query("categoryid")
if categoryIDStr == "" {
utils.Error("Error: categoryid is missing")
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"code": 400,
"status": false,
"message": "categoryid is required",
"data": fiber.Map{},
})
}
categoryID, err := strconv.Atoi(categoryIDStr)
if err != nil {
utils.Logger.Errorf("Error: Invalid categoryid: %s", categoryIDStr)
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"code": 400,
"status": false,
"message": "Invalid categoryid",
"data": fiber.Map{},
})
}
// Optional tenantid
tenantIDStr := c.Query("tenantid")
tenantID := 0
if tenantIDStr != "" {
tenantID, err = strconv.Atoi(tenantIDStr)
if err != nil {
utils.Logger.Errorf("Error: Invalid tenantid: %s", tenantIDStr)
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"code": 400,
"status": false,
"message": "Invalid tenantid",
"data": fiber.Map{},
})
}
}
// Optional query params
applocationIDStr := c.Query("applocationid", "0")
applocationID, _ := strconv.Atoi(applocationIDStr)
productIDStr := c.Query("productid")
keyword := c.Query("keyword")
locationIDStr := c.Query("locationid")
locationID := 0
if locationIDStr != "" {
locationID, _ = strconv.Atoi(locationIDStr)
}
productID := 0
if productIDStr != "" {
productID, err = strconv.Atoi(productIDStr)
if err != nil {
utils.Logger.Errorf("Error: Invalid productid: %s", productIDStr)
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"code": 400,
"status": false,
"message": "Invalid productid",
"data": fiber.Map{},
})
}
}
// Fetch subcategories
var subcategories []models.Subcategory
utils.Logger.Infof("Fetching subcategories for categoryid: %d", categoryID)
if err := db.DB.Table("productsubcategories").
Where("categoryid = ?", categoryID).
Find(&subcategories).Error; err != nil {
utils.Logger.Errorf("Error fetching subcategories: %v", err)
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"code": 500,
"status": false,
"message": "Error fetching subcategories",
"data": fiber.Map{},
})
}
// Build product query
var allProducts []models.Products
query := db.DB.
Table("products a").
Joins("LEFT JOIN productlocations pl ON pl.productid = a.productid").
Where("a.categoryid = ?", categoryID)
if tenantID > 0 {
query = query.Where("a.tenantid = ?", tenantID)
}
if locationID > 0 {
utils.Logger.Infof("Filtering by locationid: %d", locationID)
query = query.Where("pl.locationid = ?", locationID)
} else {
utils.Info("No locationid provided or value is 0 — showing all locations")
}
if applocationID > 0 {
query = query.Where("a.applocationid = ?", applocationID)
}
if productID > 0 {
query = query.Where("a.productid = ?", productID)
}
if keyword != "" {
utils.Info("Applying keyword filter")
like := "%" + strings.ToLower(keyword) + "%"
query = query.Where(
db.DB.Where("LOWER(a.productname) LIKE ?", like).
Or("LOWER(a.unitvalue) LIKE ?", like).
Or("LOWER(CAST(a.productcost AS CHAR)) LIKE ?", like),
)
}
if err := query.Select("a.*").Find(&allProducts).Error; err != nil {
utils.Logger.Errorf("Error fetching products: %v", err)
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"code": 500,
"status": false,
"message": "Error fetching products",
"data": fiber.Map{},
})
}
// Group products under subcategories
var details []models.SubcategoryProductResponse
var uncategorizedProducts []models.Products
for _, subcat := range subcategories {
var subcatProducts []models.Products
for _, prod := range allProducts {
if prod.Subcategoryid != nil && *prod.Subcategoryid == subcat.Subcategoryid {
subcatProducts = append(subcatProducts, prod)
}
}
if len(subcatProducts) > 0 {
details = append(details, models.SubcategoryProductResponse{
SubcategoryID: subcat.Subcategoryid,
SubcategoryName: subcat.Subcategoryname,
Products: subcatProducts,
})
}
}
for _, prod := range allProducts {
if prod.Subcategoryid == nil {
uncategorizedProducts = append(uncategorizedProducts, prod)
}
}
if len(uncategorizedProducts) > 0 {
details = append(details, models.SubcategoryProductResponse{
SubcategoryID: 0,
SubcategoryName: "Uncategorized",
Products: uncategorizedProducts,
})
}
// Tenant info block only if tenantID is passed
if tenantID > 0 {
var tenantInfo = fiber.Map{}
var tenantFound bool
for _, p := range allProducts {
if p.Tenantid != nil {
var tenant struct {
Tenantname string
Address string
Licenseno string
Primaryemail string
Primarycontact string
Locationname string
Pickuplocationid int
Suburb string
City string
Latitude string
Longitude string
Postcode string
}
err := db.DB.Raw(`
SELECT
t.tenantname,
t.address,
t.licenseno,
t.primaryemail,
t.primarycontact,
l.locationid AS pickuplocationid,
l.suburb,
l.city,
l.latitude,
l.longitude,
l.postcode,
a.locationname
FROM tenants t
LEFT JOIN tenantlocations l ON t.tenantid = l.tenantid
LEFT JOIN app_location a ON l.applocationid = a.applocationid
WHERE t.tenantid = ? AND t.applocationid = ?
LIMIT 1
`, *p.Tenantid, applocationID).Scan(&tenant).Error
if err == nil {
tenantInfo = fiber.Map{
"tenantname": tenant.Tenantname,
"address": tenant.Address,
"licenseno": tenant.Licenseno,
"primaryemail": tenant.Primaryemail,
"primarycontact": tenant.Primarycontact,
"locationname": tenant.Locationname,
"pickuplocationid": tenant.Pickuplocationid,
"suburb": tenant.Suburb,
"city": tenant.City,
"pickuplat": tenant.Latitude,
"pickuplong": tenant.Longitude,
"postcode": tenant.Postcode,
"details": details,
}
tenantFound = true
}
break
}
}
if tenantFound {
return c.Status(fiber.StatusOK).JSON(fiber.Map{
"code": 200,
"status": true,
"message": "Success",
"data": tenantInfo,
})
}
}
// Return only details if tenantid is not provided
return c.Status(fiber.StatusOK).JSON(fiber.Map{
"code": 200,
"status": true,
"message": "Success",
"data": fiber.Map{
"details": details,
},
})
}
func GetProductCount(c *fiber.Ctx) error {
tenantID, _ := strconv.Atoi(c.Query("tenantid"))
categoryID, _ := strconv.Atoi(c.Query("categoryid"))
subcategoryID, _ := strconv.Atoi(c.Query("subcategoryid"))
approve := c.Query("approve", "") // New line
result, err := domain.Getproductcount(tenantID, categoryID, subcategoryID, approve)
if err != nil {
return c.JSON(fiber.Map{
"code": http.StatusConflict,
"message": "failed",
"status": false,
})
}
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
"details": result,
})
}
func GetProductByVariant(c *fiber.Ctx) error {
tenantID, _ := strconv.Atoi(c.Query("tenantid"))
variantid, _ := strconv.Atoi(c.Query("variantid"))
result, err := domain.GetproductbyVariant(tenantID, variantid)
if err != nil {
return c.JSON(fiber.Map{
"code": http.StatusConflict,
"message": "failed",
"status": false,
})
}
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
"details": result,
})
}
func GetCatalougeProducts(c *fiber.Ctx) error {
tenantId, _ := strconv.Atoi(c.Query("tenantid"))
locationid, _ := strconv.Atoi(c.Query("locationid"))
subcategoryid, _ := strconv.Atoi(c.Query("subcategoryid"))
keyword := c.Query("keyword")
pageno, _ := strconv.Atoi(c.Query("pageno"))
pagesize, _ := strconv.Atoi(c.Query("pagesize"))
data := domain.GetCatalougeProducts(tenantId, locationid, subcategoryid, pageno, pagesize, keyword)
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
"details": data,
})
}
func GetStockstatement(c *fiber.Ctx) error {
tenantId, _ := strconv.Atoi(c.Query("tenantid"))
locationid, _ := strconv.Atoi(c.Query("locationid"))
subcategoryid, _ := strconv.Atoi(c.Query("subcategoryid"))
pageno, _ := strconv.Atoi(c.Query("pageno"))
pagesize, _ := strconv.Atoi(c.Query("pagesize"))
keyword := c.Query("keyword")
data := domain.GetStockStatement(tenantId, locationid, subcategoryid, pageno, pagesize, keyword)
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
"details": data,
})
}
func GetProductVariants(c *fiber.Ctx) error {
tenantId, _ := strconv.Atoi(c.Query("tenantid"))
subcategoryId, _ := strconv.Atoi(c.Query("subcategoryid"))
data := domain.GetProductVariants(tenantId, subcategoryId)
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
"details": data,
})
}
func CreateProductLocation(c *fiber.Ctx) error {
var data []models.Productlocations
if err := c.BodyParser(&data); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"code": 400,
"message": "Invalid request body",
"status": false,
})
}
err := domain.CreateProductLocation(data)
if err != nil {
return c.JSON(fiber.Map{
"status": false,
"code": http.StatusConflict,
"message": err,
})
}
return c.JSON(fiber.Map{
"status": true,
"code": http.StatusCreated,
"message": "Success",
})
}
func UpdateProductLocation(c *fiber.Ctx) error {
var data models.Productlocations
if err := c.BodyParser(&data); err != nil {
return err
}
err := domain.UpdateProductLocation(data)
if err != nil {
return c.JSON(fiber.Map{
"status": false,
"code": http.StatusConflict,
"message": err,
})
}
return c.JSON(fiber.Map{
"status": true,
"code": http.StatusAccepted,
"message": "Product update successful",
})
}
func CreateProductStock(c *fiber.Ctx) error {
var stocks []models.Productstock
if err := c.BodyParser(&stocks); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"code": 400,
"message": "Invalid request body",
"status": false,
})
}
for i := range stocks {
stocks[i].Stockdate = time.Now()
}
// Insert all stock records
if err := db.DB.Table("productstocks").Create(&stocks).Error; err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"code": 500,
"message": "Failed to create product stocks",
"status": false,
})
}
// Collect and dedupe product IDs to update their status
idMap := make(map[int]struct{})
var productIDs []int
for _, s := range stocks {
if s.Productid <= 0 {
continue
}
if _, ok := idMap[s.Productid]; !ok {
idMap[s.Productid] = struct{}{}
productIDs = append(productIDs, s.Productid)
}
}
// Only update if we have product ids
if len(productIDs) > 0 {
if err := db.DB.Table("products").
Where("productid IN ?", productIDs).
Update("productstatus", "available").Error; err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"code": 500,
"message": "Failed to update product status",
"status": false,
})
}
}
return c.Status(fiber.StatusCreated).JSON(fiber.Map{
"code": 201,
"message": "Product stocks created successfully",
"status": true,
"details": stocks,
})
}
func UpdateProductStock(c *fiber.Ctx) error {
var stock models.Productstock
// Parse body
if err := c.BodyParser(&stock); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"code": 400,
"message": "Invalid request body",
"status": false,
})
}
// Validate required ID
if stock.Productstockid == 0 {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"code": 400,
"message": "Missing productstockid",
"status": false,
})
}
// Attempt update
if err := domain.UpdateProductStock(&stock); err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"code": 500,
"message": "Failed to update product stock",
"status": false,
})
}
return c.Status(fiber.StatusOK).JSON(fiber.Map{
"code": 200,
"message": "Product stock updated successfully",
"status": true,
})
}
func GetProductStocks(c *fiber.Ctx) error {
tenantID := c.Query("tenantid")
locationID := c.Query("locationid")
stocks, err := domain.GetProductStocks(tenantID, locationID)
if err != nil {
return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
"code": 500,
"message": "Failed to fetch product stocks",
"status": false,
})
}
return c.Status(http.StatusOK).JSON(fiber.Map{
"code": 200,
"message": "Product stocks fetched successfully",
"status": true,
"data": stocks,
})
}
func GetLocationProducts(c *fiber.Ctx) error {
tenantid, _ := strconv.Atoi(c.Query("tenantid"))
locationid, _ := strconv.Atoi(c.Query("locationid"))
subcategoryid, _ := strconv.Atoi(c.Query("subcategoryid"))
keyword := c.Query("keyword")
pageno, _ := strconv.Atoi(c.Query("pageno"))
pagesize, _ := strconv.Atoi(c.Query("pagesize"))
result := domain.GetLocationProducts(tenantid, locationid, subcategoryid, pageno, pagesize, keyword)
return c.JSON(fiber.Map{
"status": true,
"code": http.StatusOK,
"message": "Success",
"details": result,
})
}
func GetSubCategoryWiseSummary(c *fiber.Ctx) error {
tenantId, _ := strconv.Atoi(c.Query("tenantid"))
locationid, _ := strconv.Atoi(c.Query("locationid"))
subcategoryid, _ := strconv.Atoi(c.Query("subcategoryid"))
data, err := domain.GetSubCategoryWiseSummary(tenantId, locationid, subcategoryid)
if err != nil {
return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
"code": 500,
"status": false,
"message": "Failed to fetch subcategory-wise summary",
})
}
if data == nil {
data = []models.SubCategorySummary{}
}
return c.Status(http.StatusOK).JSON(fiber.Map{
"code": http.StatusOK,
"message": "Subcategory-wise summary fetched successfully",
"status": true,
"details": data,
})
}
func GetLocationProductSummary(c *fiber.Ctx) error {
tenantid, _ := strconv.Atoi(c.Query("tenantid"))
locationid, _ := strconv.Atoi(c.Query("locationid"))
result := domain.GetLocationProductSummary(tenantid, locationid)
return c.JSON(fiber.Map{
"status": true,
"code": http.StatusOK,
"message": "Success",
"details": result,
})
}
func GetStockStatementSummary(c *fiber.Ctx) error {
tenantId, _ := strconv.Atoi(c.Query("tenantid"))
locationid, _ := strconv.Atoi(c.Query("locationid"))
data := domain.GetStockStatementSummary(tenantId, locationid)
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Success",
"status": true,
"details": data,
})
}
func CreateProductDiscount(c *fiber.Ctx) error {
var data models.ProductDiscount
if err := c.BodyParser(&data); err != nil {
return c.Status(http.StatusBadRequest).JSON(fiber.Map{
"status": false,
"code": http.StatusBadRequest,
"message": "Invalid JSON body",
})
}
if len(data.Locationid) > 0 {
data.LocationidStr = strings.Join(data.Locationid, ",")
}
data.Status = "Active"
if err := domain.CreateProductDiscount(&data); err != nil {
return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
"status": false,
"code": http.StatusInternalServerError,
"message": err.Error(),
})
}
return c.Status(http.StatusCreated).JSON(fiber.Map{
"status": true,
"code": http.StatusCreated,
"message": "Product discount created successfully",
"data": data,
})
}
func GetProductDiscounts(c *fiber.Ctx) error {
tid, _ := strconv.Atoi(c.Query("tenantid"))
lid := c.Query("locationid")
data := domain.GetProductDiscounts(tid, lid)
return c.JSON(fiber.Map{
"status": true,
"code": 200,
"message": "Success",
"details": data,
})
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,17 @@
package controllers
import (
"net/http"
"github.com/gofiber/fiber/v2"
)
func PublishLogs(c *fiber.Ctx) error {
return c.JSON(fiber.Map{
"status": true,
"code": http.StatusConflict,
"message": "Heloo",
})
}

File diff suppressed because it is too large Load Diff

185
db/connect copy.go Normal file
View File

@@ -0,0 +1,185 @@
package db
// import (
// "fmt"
// "log"
// "nearle/utils"
// "time"
// "gorm.io/driver/mysql"
// "gorm.io/gorm"
// )
// var DB *gorm.DB
// var (
// DB_DEV *gorm.DB
// DB_LIVE *gorm.DB
// )
// func DevConnect() {
// var DBname string
// var Username string
// var Password string
// var Host string
// var Port string
// var err error
// Port, DBname, Password, Username, Host, _, _ = utils.DevConfig()
// dsn := Username + ":" + Password + "@tcp" + "(" + Host + ":" + Port + ")/" + DBname + "?" + "parseTime=true&loc=Local"
// DB_DEV, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
// if err != nil {
// log.Fatal("❌ Could not connect to Dev database:", err)
// }
// setupDB(DB_DEV)
// fmt.Println("✅ Connected to Dev Database")
// // var DBname string
// // var Username string
// // var Password string
// // var Host string
// // var Port string
// // Port, DBname, Password, Username, Host, _, _ = utils.DevConfig()
// // dsn := Username + ":" + Password + "@tcp" + "(" + Host + ":" + Port + ")/" + DBname + "?" + "parseTime=true&loc=Local"
// // for i := 0; i < 5; i++ {
// // db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
// // if err == nil {
// // sqlDB, _ := db.DB()
// // sqlDB.SetMaxIdleConns(100)
// // sqlDB.SetMaxOpenConns(1000)
// // sqlDB.SetConnMaxLifetime(time.Hour)
// // err = sqlDB.Ping()
// // if err == nil {
// // log.Println("Successfully connected to the database.")
// // DB = db
// // return
// // }
// // }
// // log.Printf("Failed to connect to the database, retrying... (%d/5)\n", i+1)
// // time.Sleep(2 * time.Second)
// // }
// // // log.Fatal("Could not connect to the database:", err)
// // // database, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
// // // if err != nil {
// // // panic("Could not connect to the database")
// // // }
// }
// func setupDB(database *gorm.DB) {
// sqlDB, err := database.DB()
// if err != nil {
// log.Fatal("❌ Failed to get DB from GORM:", err)
// }
// sqlDB.SetMaxIdleConns(10)
// sqlDB.SetMaxOpenConns(100)
// sqlDB.SetConnMaxLifetime(30 * time.Minute)
// }
// // func LiveConnect() {
// // var DBname string
// // var Username string
// // var Password string
// // var Host string
// // var Port string
// // Port, DBname, Password, Username, Host, _, _ = utils.DevConfig()
// // dsn := Username + ":" + Password + "@tcp" + "(" + Host + ":" + Port + ")/" + DBname + "?" + "parseTime=true&loc=Local"
// // for i := 0; i < 5; i++ {
// // db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
// // if err != nil {
// // log.Printf("Failed to connect to the database, retrying... (%d/5)\n", i+1)
// // log.Println("Error:", err)
// // time.Sleep(2 * time.Second)
// // continue
// // }
// // sqlDB, err := db.DB()
// // if err != nil {
// // log.Println("Failed to get DB from GORM:", err)
// // time.Sleep(2 * time.Second)
// // continue
// // }
// // sqlDB.SetMaxIdleConns(10)
// // sqlDB.SetMaxOpenConns(100)
// // sqlDB.SetConnMaxLifetime(time.Hour)
// // if err = sqlDB.Ping(); err != nil {
// // log.Printf("Failed to ping database, retrying... (%d/5)\n", i+1)
// // log.Println("Error:", err)
// // time.Sleep(2 * time.Second)
// // continue
// // }
// // log.Println("Successfully connected to the database.")
// // DB = db
// // return
// // }
// // log.Fatal("Could not connect to the database after multiple attempts.")
// // }
// func LiveConnect() {
// var DBname string
// var Username string
// var Password string
// var Host string
// var Port string
// Port, DBname, Password, Username, Host, _, _ = utils.LiveConfig()
// // dsn := "zqbuvyrhhf:Package%40%123#@tcp(165.232.178.78:3306)/dbname?parseTime=true"
// dsn := Username + ":" + Password + "@tcp" + "(" + Host + ":" + Port + ")/" + DBname + "?" + "parseTime=true&loc=Local"
// //database, err := sql.Open("mysql", dsn)
// database, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
// if err != nil {
// panic("Could not connect to the database")
// }
// sqlDB, err := database.DB()
// if err != nil {
// log.Println("Failed to get DB from GORM:", err)
// panic("Could not connect to the database")
// }
// sqlDB.SetMaxIdleConns(100)
// sqlDB.SetMaxOpenConns(1000)
// sqlDB.SetConnMaxLifetime(time.Hour)
// if err = sqlDB.Ping(); err != nil {
// log.Println("Error:", err)
// panic("Could not connect to the database")
// }
// fmt.Println("Live Database Connected Successfully")
// DB = database
// }
// func CloseDB() {
// sqlDB, err := DB.DB()
// if err != nil {
// log.Println("Error retrieving sql.DB from GORM:", err)
// return
// }
// fmt.Println("Connection closed Successfully")
// sqlDB.Close() // This will close the connection pool
// }

221
db/connect.go Normal file
View File

@@ -0,0 +1,221 @@
package db
import (
"context"
"database/sql"
"fmt"
"nearle/utils"
"os"
"time"
"github.com/redis/go-redis/v9"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
var (
DB *gorm.DB
)
// --------------------
// DATABASE CONNECTION
// --------------------
func Connect() {
dsn := fmt.Sprintf(
"host=%s user=%s password=%s dbname=%s port=%s sslmode=disable TimeZone=Asia/Kolkata",
mustEnv("DB_HOST"),
mustEnv("DB_USER"),
mustEnv("DB_PASSWORD"),
mustEnv("DB_NAME"),
getEnv("DB_PORT", "5432"),
)
var err error
maxRetries := 10
backoff := 2 * time.Second
for i := 1; i <= maxRetries; i++ {
utils.Logger.Infow("Connecting to database", "attempt", i)
DB, err = gorm.Open(postgres.Open(dsn), &gorm.Config{
Logger: logger.Default.LogMode(logger.Error),
})
if err == nil {
sqlDB, dbErr := DB.DB()
if dbErr == nil {
// 🔥 Ping with timeout (important)
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if pingErr := sqlDB.PingContext(ctx); pingErr == nil {
setupDB(DB)
utils.Logger.Infow("✅ Database connected successfully")
// Start background health check
startDBHealthCheck(sqlDB)
return
} else {
err = pingErr
}
} else {
err = dbErr
}
}
utils.Logger.Errorw("❌ DB connection failed", "attempt", i, "error", err)
time.Sleep(backoff)
backoff *= 2
}
utils.Logger.Fatalw("☢️ CRITICAL: DB connection failed after retries")
}
// --------------------
// CONNECTION POOLING
// --------------------
func setupDB(database *gorm.DB) {
sqlDB, err := database.DB()
if err != nil {
utils.Logger.Errorw("Failed to get sql.DB", "error", err)
return
}
// 🔥 K8s SAFE CONFIG
sqlDB.SetMaxOpenConns(30) // total open connections
sqlDB.SetMaxIdleConns(5) // idle connections
sqlDB.SetConnMaxLifetime(5 * time.Minute) // avoid stale connections
sqlDB.SetConnMaxIdleTime(2 * time.Minute)
stats := sqlDB.Stats()
utils.Logger.Infow("DB Pool configured",
"MaxOpen", stats.MaxOpenConnections,
)
}
// --------------------
// DB HEALTH CHECK
// --------------------
func startDBHealthCheck(sqlDB *sql.DB) {
go func() {
for {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
err := sqlDB.PingContext(ctx)
cancel()
if err != nil {
utils.Logger.Errorw("❌ DB connection lost", "error", err)
}
time.Sleep(30 * time.Second)
}
}()
}
// --------------------
// CLOSE DB
// --------------------
func CloseDB() {
if DB == nil {
return
}
sqlDB, err := DB.DB()
if err != nil {
utils.Logger.Errorw("Error retrieving sql.DB", "error", err)
return
}
utils.Logger.Infow("Closing DB connection")
sqlDB.Close()
}
// --------------------
// ENV HELPERS
// --------------------
func mustEnv(key string) string {
val := os.Getenv(key)
if val == "" {
utils.Logger.Warnw("Missing env variable", "key", key)
}
return val
}
func getEnv(key, fallback string) string {
if val := os.Getenv(key); val != "" {
return val
}
return fallback
}
// --------------------
// REDIS CONNECTION
// --------------------
var Rdb *redis.Client
var Ctx = context.Background()
func InitRedis() {
redisHost := getEnv("REDIS_HOST", "66.116.226.255") // ✅ FIXED IP
redisPort := getEnv("REDIS_PORT", "6379")
addr := fmt.Sprintf("%s:%s", redisHost, redisPort)
Rdb = redis.NewClient(&redis.Options{
Addr: addr,
Username: "default",
Password: "Package@324969#",
DB: 0,
// ✅ TIMEOUTS (VERY IMPORTANT)
DialTimeout: 10 * time.Second,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
// ✅ POOL
PoolSize: 50,
MinIdleConns: 10,
// ✅ RETRIES
MaxRetries: 3,
MinRetryBackoff: 500 * time.Millisecond,
MaxRetryBackoff: 2 * time.Second,
})
maxRetries := 5
backoff := 1 * time.Second
for i := 1; i <= maxRetries; i++ {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
_, err := Rdb.Ping(ctx).Result()
cancel()
if err == nil {
utils.Logger.Infow("✅ Redis connected successfully", "addr", addr)
return
}
utils.Logger.Errorw("❌ Redis connection failed",
"attempt", i,
"addr", addr,
"error", err,
)
time.Sleep(backoff)
backoff *= 2
}
utils.Logger.Fatalw("☢️ CRITICAL: Redis connection failed after retries", "addr", addr)
}

668
domain/customerDomain.go Normal file
View File

@@ -0,0 +1,668 @@
package domain
import (
"nearle/db"
"nearle/models"
"nearle/utils"
"net/http"
"strconv"
"strings"
)
func CreateCustomer(input models.Customers) int {
var custloc models.Customerlocations
var tcust models.Tenantcustomers
tx := db.DB.Begin()
t1 := tx.Create(&input)
if t1.Error != nil {
utils.Error("CreateCustomer t1 error", "error", t1.Error)
tx.Rollback()
}
custloc.Customerid = input.Customerid
custloc.Address = input.Address
custloc.Suburb = input.Suburb
custloc.City = input.City
custloc.State = input.State
custloc.Postcode = input.Postcode
custloc.Latitude = input.Latitude
custloc.Longitude = input.Longitude
custloc.Doorno = input.Doorno
custloc.Landmark = input.Landmark
custloc.Primaryaddress = 1
t2 := tx.Table("customerlocations").Create(&custloc)
if t2.Error != nil {
utils.Error("CreateCustomer t2 error", "error", t2.Error)
tx.Rollback()
}
tcust.Customerid = input.Customerid
tcust.Tenantid = input.Tenantid
t3 := tx.Table("tenantcustomers").Create(&tcust)
if t3.Error != nil {
utils.Error("CreateCustomer t3 error", "error", t3.Error)
tx.Rollback()
}
tx.Commit()
return input.Customerid
}
func CreateCustomerv1(input models.Customers) (int, error) {
var tcust models.Tenantcustomers
tx := db.DB.Begin()
t1 := tx.Create(&input)
if t1.Error != nil {
utils.Error("CreateCustomerv1 t1 error", "error", t1.Error)
tx.Rollback()
return 0, t1.Error
}
tcust.Customerid = input.Customerid
tcust.Tenantid = input.Tenantid
t3 := tx.Table("tenantcustomers").Create(&tcust)
if t3.Error != nil {
utils.Error("CreateCustomerv1 t3 error", "error", t3.Error)
tx.Rollback()
return 0, t3.Error
}
err := tx.Commit().Error
if err != nil {
return 0, err
}
return input.Customerid, nil
}
func CreateCustomerv2(input models.Customers) (*models.CustomersId, error) {
var custloc models.Customerlocations
var tcust models.Tenantcustomers
var cid models.CustomersId
tx := db.DB.Begin()
t1 := tx.Create(&input)
if t1.Error != nil {
utils.Error("CreateCustomerv2 t1 error", "error", t1.Error)
tx.Rollback()
return nil, t1.Error
}
custloc.Customerid = input.Customerid
custloc.Address = input.Address
custloc.Suburb = input.Suburb
custloc.City = input.City
custloc.State = input.State
custloc.Postcode = input.Postcode
custloc.Latitude = input.Latitude
custloc.Longitude = input.Longitude
custloc.Doorno = input.Doorno
custloc.Landmark = input.Landmark
custloc.Primaryaddress = 1
t2 := tx.Table("customerlocations").Create(&custloc)
if t2.Error != nil {
utils.Error("CreateCustomerv2 t2 error", "error", t2.Error)
tx.Rollback()
return nil, t2.Error
}
tcust.Customerid = input.Customerid
tcust.Tenantid = input.Tenantid
t3 := tx.Table("tenantcustomers").Create(&tcust)
if t3.Error != nil {
utils.Error("CreateCustomerv2 t3 error", "error", t3.Error)
tx.Rollback()
return nil, t3.Error
}
cid.Customerid = input.Customerid
cid.Locationid = custloc.Locationid
err := tx.Commit().Error
if err != nil {
return nil, err
}
return &cid, nil
}
func UpdateCustomerv2(input models.Customers) (int, error) {
var custloc models.Customerlocations
var tcust models.Tenantcustomers
var data models.CustomersId
tx := db.DB.Begin()
t1 := tx.Where("customerid=?", input.Customerid).Updates(&input)
if t1.Error != nil {
utils.Error("UpdateCustomerv2 t1 error", "error", t1.Error)
tx.Rollback()
return 0, t1.Error
}
custloc.Customerid = input.Customerid
custloc.Address = input.Address
custloc.Suburb = input.Suburb
custloc.City = input.City
custloc.State = input.State
custloc.Postcode = input.Postcode
custloc.Latitude = input.Latitude
custloc.Longitude = input.Longitude
custloc.Doorno = input.Doorno
custloc.Landmark = input.Landmark
custloc.Primaryaddress = 1
custlocid, err := CheckLocation(input.Customerid)
if err != nil {
tx.Rollback()
return 0, err
}
if custlocid != 0 {
utils.Logger.Infof("entering location update: %d", custlocid)
custloc.Locationid = custlocid
t2 := tx.Table("customerlocations").Where("locationid=?", custlocid).Updates(&custloc)
if t2.Error != nil {
utils.Error("UpdateCustomerv2 t2 update error", "error", t2.Error)
tx.Rollback()
return 0, t2.Error
}
} else {
utils.Logger.Infof("entering location create for customer: %d", input.Customerid)
t2 := tx.Table("customerlocations").Create(&custloc)
if t2.Error != nil {
utils.Error("UpdateCustomerv2 t2 create error", "error", t2.Error)
tx.Rollback()
return 0, t2.Error
}
}
cid := CheckTenantCustomer(input.Customerid, input.Tenantid)
if cid == 0 {
tcust.Customerid = input.Customerid
tcust.Tenantid = input.Tenantid
t3 := tx.Table("tenantcustomers").Create(&tcust)
if t3.Error != nil {
utils.Error("UpdateCustomerv2 t3 error", "error", t3.Error)
tx.Rollback()
return 0, t3.Error
}
}
data.Locationid = custloc.Locationid
utils.Logger.Infof("customerid for the customer is %d", input.Customerid)
utils.Logger.Infof("The created Location for the customer is %d", data.Locationid)
utils.Logger.Infof("the Location for the customer is %d", custloc.Locationid)
err = tx.Commit().Error
if err != nil {
return 0, err
}
return data.Locationid, nil
}
func UpdateCustomerv1(input models.Customers) error {
var tcust models.Tenantcustomers
tx := db.DB.Begin()
t1 := tx.Where("customerid=?", input.Customerid).Updates(&input)
if t1.Error != nil {
utils.Error("UpdateCustomerv1 t1 error", "error", t1.Error)
tx.Rollback()
return t1.Error
}
cid := CheckTenantCustomer(input.Customerid, input.Tenantid)
if cid == 0 {
tcust.Customerid = input.Customerid
tcust.Tenantid = input.Tenantid
t3 := tx.Table("tenantcustomers").Create(&tcust)
if t3.Error != nil {
utils.Error("UpdateCustomerv1 t3 error", "error", t3.Error)
tx.Rollback()
return t3.Error
}
}
err := tx.Commit().Error
if err != nil {
return err
}
return nil
}
func CreateTenantCustomer(input models.Customers) int {
var tcust models.Tenantcustomers
tcust.Customerid = input.Customerid
tcust.Tenantid = input.Tenantid
tx := db.DB.Begin()
t3 := tx.Table("tenantcustomers").Create(&tcust)
if t3.Error != nil {
utils.Error("CreateTenantCustomer t3 error", "error", t3.Error)
tx.Rollback()
}
tx.Commit()
return input.Customerid
}
func UpdateCustomer(input models.Customers) models.Result {
var custloc models.Customerlocations
var result models.Result
tx := db.DB.Begin()
t1 := tx.Where("customerid=?", input.Customerid).Updates(&input)
if t1.Error != nil {
utils.Error("UpdateCustomer t1 error", "error", t1.Error)
tx.Rollback()
}
custloc.Customerid = input.Customerid
custloc.Address = input.Address
custloc.Suburb = input.Suburb
custloc.City = input.City
custloc.State = input.State
custloc.Postcode = input.Postcode
custloc.Latitude = input.Latitude
custloc.Longitude = input.Longitude
custloc.Doorno = input.Doorno
custloc.Landmark = input.Landmark
t2 := tx.Table("customerlocations").Where("customerid=? and primaryaddress=?", input.Customerid, 1).Updates(&custloc)
if t2.Error != nil {
utils.Error("UpdateCustomer t2 error", "error", t2.Error)
tx.Rollback()
}
err := tx.Commit().Error
if err != nil {
result.Code = http.StatusConflict
result.Status = false
result.Message = "Update Customer Failed"
return result
}
result.Code = http.StatusAccepted
result.Status = true
result.Message = "Customer customer successful"
return result
}
func GetCustomer(cid int, cno string) models.CustomerInfo {
var data models.CustomerInfo
var q1 string
if cid != 0 {
// q1 = `select a.customerid,a.authmode,a.configid,a.deviceid,a.devicetype,a.customertoken,a.firstname,a.lastname,
// a.contactno,a.email,a.profileimage,a.address,a.suburb,a.city,a.state,a.landmark,a.doorno,a.postcode,
// a.latitude,a.longitude,a.applocationid,a.status from customers a where a.customerid= ` + strconv.Itoa(cid)
q1 = `SELECT a.customerid,a.firstname,a.lastname,a.contactno,a.email, a.profileimage, a.dialcode, a.deviceid, a.devicetype, a.authmode, a.configid, a.customertoken, a.intro, a.gender, a.dob,
b.locationid as deliverylocationid,b.address,b.suburb,b.city,b.state,b.landmark,b.doorno,b.postcode,
b.latitude,b.longitude,a.applocationid,c.locationid as tenantlocationid, c.tenantid, a.status,d.qrmode,d.latitude as selectedlatitude, d.longitude as selectedlongitude, d.radius, d.applocationid, e.allocationid
from customers a
INNER JOIN customerlocations b ON a.customerid=b.customerid
INNER JOIN tenantcustomers c ON a.customerid=c.customerid
LEFT JOIN app_location d ON a.applocationid=d.applocationid
LEFT JOIN tenants e ON e.tenantid=c.tenantid
WHERE b.primaryaddress=1 and a.customerid= ` + strconv.Itoa(cid) + ` order by customerid desc`
} else {
q1 = `SELECT a.customerid,a.firstname,a.lastname,a.contactno,a.email,a.profileimage, a.dialcode, a.deviceid, a.devicetype, a.authmode, a.configid, a.customertoken, a.intro,a.gender, a.dob,
b.locationid as deliverylocationid,b.address,b.suburb,b.city,b.state,b.landmark,b.doorno,b.postcode,
b.latitude,b.longitude,a.applocationid,c.locationid as tenantlocationid, c.tenantid, a.status, d.qrmode, d.latitude as selectedlatitude, d.longitude as selectedlongitude,d.radius, d.applocationid, e.allocationid
from customers a
INNER JOIN customerlocations b ON a.customerid=b.customerid
INNER JOIN tenantcustomers c ON a.customerid=c.customerid
LEFT JOIN app_location d ON a.applocationid=d.applocationid
LEFT JOIN tenants e ON e.tenantid=c.tenantid
WHERE b.primaryaddress=1 and a.contactno= '` + cno + `' order by customerid desc`
}
utils.Logger.Debugf("Query: %s", q1)
db.DB.Raw(q1).Find(&data)
return data
}
func GetTenantCustomers(tid, lid, aid, pageno, pagesize int, keyword string) []models.CustomerInfo {
var data []models.CustomerInfo
offset := (pageno - 1) * pagesize
var q1 string
var args []interface{}
if lid != 0 {
q1 = `
SELECT a.customerid,a.firstname,a.lastname,a.contactno,
a.email,b.locationid AS deliverylocationid,b.address,b.suburb,b.city,b.state,b.landmark,b.doorno,b.postcode,b.latitude,b.longitude,a.applocationid,c.tenantid,
c.locationid AS tenantlocationid,a.status,1 AS quantity,0.0 AS collectionamt
FROM customers a
LEFT JOIN customerlocations b ON a.customerid = b.customerid
INNER JOIN tenantcustomers c ON a.customerid = c.customerid
WHERE c.locationid = ? AND c.tenantid = ?
`
args = append(args, lid, tid)
if aid != 0 {
q1 += ` AND a.applocationid = ?`
args = append(args, aid)
}
if keyword != "" {
search := "%" + keyword + "%"
q1 += ` AND (a.firstname LIKE ? OR a.contactno LIKE ? OR b.suburb LIKE ?)`
args = append(args, search, search, search)
}
q1 += ` ORDER BY a.customerid DESC LIMIT ? OFFSET ?`
args = append(args, pagesize, offset)
} else {
q1 = `
SELECT a.customerid, a.firstname, a.lastname, a.contactno, a.email, a.address, a.suburb, a.city, a.state, a.landmark, a.doorno, a.postcode, a.latitude,
a.longitude, a.applocationid, c.tenantid, c.locationid AS tenantlocationid, a.status, 1 AS quantity, 0.0 AS collectionamt
FROM customers a
INNER JOIN tenantcustomers c ON a.customerid = c.customerid WHERE c.tenantid = ? `
args = append(args, tid)
if aid != 0 {
q1 += ` AND a.applocationid = ?`
args = append(args, aid)
}
if keyword != "" {
search := "%" + strings.ToLower(keyword) + "%"
q1 += ` AND (LOWER(a.firstname) LIKE ? OR LOWER(a.contactno) LIKE ? OR LOWER(a.suburb) LIKE ?)`
args = append(args, search, search, search)
}
q1 += ` ORDER BY a.customerid DESC LIMIT ? OFFSET ?`
args = append(args, pagesize, offset)
}
// 🔹 Execute query
db.DB.Raw(q1, args...).Scan(&data)
return data
}
func GetCustomerbytenant(tid, lid int) []models.CustomerInfo {
var data []models.CustomerInfo
var q1 string
if lid != 0 {
q1 = `SELECT a.customerid,a.firstname,a.lastname,a.contactno,a.email,
b.locationid as deliverylocationid,b.address,b.suburb,b.city,b.state,b.landmark,b.doorno,b.postcode,
b.latitude,b.longitude,a.applocationid,c.locationid as tenantlocationid,a.status
from customers a
INNER JOIN customerlocations b ON a.customerid=b.customerid
INNER JOIN tenantcustomers c ON a.customerid=c.customerid
WHERE c.locationid > 0 and c.tenantid=? order by customerid desc`
} else {
q1 = `SELECT a.customerid,a.firstname,a.lastname,a.contactno,a.email,
b.locationid as deliverylocationid,b.address,b.suburb,b.city,b.state,b.landmark,b.doorno,b.postcode,
b.latitude,b.longitude,a.applocationid,c.locationid as tenantlocationid,a.status
from customers a
INNER JOIN customerlocations b ON a.customerid=b.customerid
INNER JOIN tenantcustomers c ON a.customerid=c.customerid
WHERE c.tenantid=? and c.locationid = 0 order by customerid desc`
//and c.locationid = 0
}
db.DB.Raw(q1, tid).Find(&data)
return data
}
func GetallCustomers(aid, pageno, pagesize int, keyword string) []models.CustomerInfo {
var data []models.CustomerInfo
offset := (pageno - 1) * pagesize
var q1 string
baseQuery := `SELECT a.customerid,a.firstname,a.lastname,a.contactno,a.email,
b.locationid as deliverylocationid,b.address,b.suburb,b.city,b.state,b.landmark,b.doorno,b.postcode,
b.latitude,b.longitude,a.applocationid,a.status,b.primaryaddress
FROM customers a
INNER JOIN customerlocations b ON a.customerid=b.customerid
WHERE b.primaryaddress=1`
// filter by applocationid
if aid != 0 {
baseQuery += " AND a.applocationid=" + strconv.Itoa(aid)
}
// keyword search filter (case-insensitive)
if keyword != "" {
like := "'%" + strings.ToLower(keyword) + "%'"
baseQuery += " AND (LOWER(a.firstname) LIKE " + like +
" OR LOWER(a.lastname) LIKE " + like +
" OR LOWER(a.contactno) LIKE " + like + ")"
}
// order + pagination
q1 = baseQuery + " ORDER BY a.customerid DESC LIMIT " + strconv.Itoa(pagesize) + " OFFSET " + strconv.Itoa(offset)
db.DB.Raw(q1).Find(&data)
return data
}
func SearchCustomer(str string, tid int) []models.CustomerInfo {
var data []models.CustomerInfo
var q1 string
if tid != 0 {
q1 = `SELECT a.customerid,a.firstname,a.lastname,a.contactno,a.email,
a.address,a.suburb,a.city,a.state,a.landmark,a.doorno,a.postcode,
a.latitude,a.longitude,a.applocationid,c.locationid as tenantlocationid,a.status
from customers a
INNER JOIN tenantcustomers c ON a.customerid=c.customerid
WHERE c.tenantid=` + strconv.Itoa(tid) + ` and lower(a.firstname) like '` + strings.ToLower(str) + `%' or contactno like '` + strings.ToLower(str) + `%'`
} else {
// q1 = `SELECT a.customerid,a.firstname,a.lastname,a.contactno,a.email,
// b.locationid as deliverylocationid,b.address,b.suburb,b.city,b.state,b.landmark,b.doorno,b.postcode,
// b.latitude,b.longitude,a.applocationid,a.status,c.locationid as tenantlocationid
// from customers a
// INNER JOIN customerlocations b ON a.customerid=b.customerid
// INNER JOIN tenantcustomers c ON a.customerid=c.customerid
// WHERE lower(a.firstname) like '` + strings.ToLower(str) + `%' or contactno like '` + strings.ToLower(str) + `%'`
q1 = `SELECT a.customerid,a.firstname,a.lastname,a.contactno,a.email,
a.address,a.suburb,a.city,a.state,a.landmark,a.doorno,a.postcode,
a.latitude,a.longitude,a.applocationid,c.locationid as tenantlocationid,a.status
from customers a
INNER JOIN tenantcustomers c ON a.customerid=c.customerid
WHERE lower(a.firstname) like '` + strings.ToLower(str) + `%' or contactno like '` + strings.ToLower(str) + `%'`
}
db.DB.Raw(q1).Find(&data)
return data
}
func GetCustomerbyApplocation(aid int) []models.CustomerInfo {
var data []models.CustomerInfo
var q1 string
if aid != 0 {
q1 = `SELECT a.customerid,a.firstname,a.lastname,a.contactno,a.email,
b.locationid as deliverylocationid,b.address,b.suburb,b.city,b.state,b.landmark,b.doorno,b.postcode,
b.latitude,b.longitude,a.applocationid,a.status
from customers a
INNER JOIN customerlocations b ON a.customerid=b.customerid
INNER JOIN tenantcustomers c ON a.customerid=c.customerid
WHERE b.primaryaddress=1 and a.applocationid=? order by customerid desc`
}
db.DB.Raw(q1, aid).Find(&data)
return data
}
func CheckCustomer(contactno string) int {
var data models.Customers
q1 := `select a.customerid,a.authmode,a.configid,a.deviceid,a.devicetype,a.customertoken,a.firstname,a.lastname,
a.contactno,a.email,a.profileimage,a.address,a.suburb,a.city,a.state,a.landmark,a.doorno,a.postcode,
a.latitude,a.longitude,a.status from customers a where a.contactno= '` + contactno + `'`
db.DB.Raw(q1).Find(&data)
return data.Customerid
}
func CheckLocation(cid int) (int, error) {
var data int
q1 := `select a.locationid from customerlocations a where a.customerid= ` + strconv.Itoa(cid)
db.DB.Raw(q1).Find(&data)
return data, nil
}
func CheckTenantCustomer(cid, tid int) int {
var data models.Customers
q1 := `select a.customerid from tenantcustomers a where a.customerid=` + strconv.Itoa(cid) + ` and a.tenantid=` + strconv.Itoa(tid)
db.DB.Raw(q1).Find(&data)
return data.Customerid
}
func CreateCustomerLocation(input models.Customerlocations) int {
err := db.DB.Create(&input).Error
if err != nil {
return 0
}
return input.Customerid
}
func GetCustomerLocation(cid int) models.CustomerLocationResult {
var result models.CustomerLocationResult
var data []models.Customerlocations
var q1 string
if cid != 0 {
q1 = `SELECT a.locationid, a.customerid, a.address, a.suburb, a.city, a.state, a.landmark, a.doorno, a.postcode,
a.latitude, a.longitude, a.defaultaddress, a.primaryaddress, a.status
FROM customerlocations a WHERE a.customerid = ` + strconv.Itoa(cid)
}
db.DB.Raw(q1).Find(&data)
result.Code = http.StatusOK
result.Status = true
result.Message = "Successful"
result.Details = data
return result
}

1295
domain/delivery.go Normal file

File diff suppressed because it is too large Load Diff

207
domain/invoice.go Normal file
View File

@@ -0,0 +1,207 @@
package domain
import (
"nearle/db"
"nearle/models"
"nearle/utils"
"strconv"
)
func GetAllInvoice(stat, tid int) []models.Tenantsales {
var q1 string
var data []models.Tenantsales
const (
base = `select a.* from tenantsales a`
)
if stat == 1 {
if tid != 0 {
q1 = base + ` where a.billstatus=0 and a.tenantid=` + strconv.Itoa(tid) + ` and a.duedate::date > CURRENT_DATE order by salesid desc `
} else {
q1 = base + ` where a.billstatus=0 and a.duedate::date > CURRENT_DATE order by salesid desc `
}
} else if stat == 2 {
if tid != 0 {
q1 = base + ` where a.billstatus=0 and a.tenantid=` + strconv.Itoa(tid) + ` and a.duedate::date < CURRENT_DATE order by salesid desc `
} else {
q1 = base + ` where a.billstatus=0 and a.duedate::date < CURRENT_DATE order by salesid desc `
}
} else if stat == 3 {
if tid != 0 {
q1 = base + ` where a.billstatus=2 and a.tenantid=` + strconv.Itoa(tid) + ` order by salesid desc `
} else {
q1 = base + ` where a.billstatus=2 order by salesid desc `
}
} else {
if tid != 0 {
q1 = base + ` where a.tenantid=` + strconv.Itoa(tid) + ` order by salesid desc `
} else {
q1 = base + ` order by salesid desc `
}
}
// print(q1)
db.DB.Raw(q1).Preload("Tenantsalesdetails").Find(&data)
return data
}
func GetInvoiceOrders(tid int, fdate, tdate string) models.InvoiceOrders {
var q1 string
var data models.InvoiceOrders
q1 = `SELECT round(SUM(actualkms),0) AS actualkms,round(SUM(kms),0) AS kms,count(*) as deliveries FROM deliveries
WHERE orderstatus='delivered' and tenantid=` + strconv.Itoa(tid) + ` and date(deliverydate) between '` + fdate + `' and '` + tdate + `'`
utils.Logger.Debugf("Query: %s", q1)
db.DB.Raw(q1).Find(&data)
return data
}
func GetInvoiceInsight(tid int) models.InvoiceInsight {
var q1 string
var data models.InvoiceInsight
if tid != 0 {
q1 = `Select COUNT(*) AS totalcount,
SUM(totalamount) AS total,
SUM(CASE WHEN billstatus=0 and status='pending' AND duedate > CURRENT_DATE THEN 1 ELSE 0 END) AS pendingcount,
SUM(CASE WHEN billstatus IN (0) and status='pending' AND duedate > CURRENT_DATE THEN totalamount ELSE 0 END) AS pending,
(SUM(CASE WHEN billstatus IN (0) and status='pending' AND duedate > CURRENT_DATE THEN totalamount ELSE 0 END) / SUM(totalamount) * 100) AS pendingpercent,
SUM(CASE WHEN billstatus = 1 THEN 1 ELSE 0 END) AS confirmedcount,
SUM(CASE WHEN billstatus = 1 THEN totalamount ELSE 0 END) AS confirmed,
(SUM(CASE WHEN billstatus = 1 THEN totalamount ELSE 0 END) / SUM(totalamount) * 100) AS confrimedpercent,
SUM(CASE WHEN billstatus = 2 THEN 1 ELSE 0 END) AS paidcount,
SUM(CASE WHEN billstatus = 2 THEN totalamount ELSE 0 END) AS paid,
(SUM(CASE WHEN billstatus = 2 THEN totalamount ELSE 0 END) / SUM(totalamount) * 100) AS paidpercent,
SUM(CASE WHEN billstatus IN (0) and status='pending' AND duedate <= CURRENT_DATE THEN 1 ELSE 0 END) AS overduecount,
SUM(CASE WHEN billstatus IN(0) and status='pending' AND duedate <= CURRENT_DATE THEN totalamount ELSE 0 END) AS overdue,
(SUM(CASE WHEN billstatus IN(0) and status='pending' AND duedate <= CURRENT_DATE THEN totalamount ELSE 0 END) / SUM(totalamount) * 100) AS overduepercent
FROM tenantsales where tenantid=` + strconv.Itoa(tid)
} else {
q1 = `Select COUNT(*) AS totalcount,
SUM(totalamount) AS total,
SUM(CASE WHEN billstatus=0 and status='pending' AND duedate > CURRENT_DATE THEN 1 ELSE 0 END) AS pendingcount,
SUM(CASE WHEN billstatus IN (0) and status='pending' AND duedate > CURRENT_DATE THEN totalamount ELSE 0 END) AS pending,
(SUM(CASE WHEN billstatus IN (0) and status='pending' AND duedate > CURRENT_DATE THEN totalamount ELSE 0 END) / SUM(totalamount) * 100) AS pendingpercent,
SUM(CASE WHEN billstatus = 1 THEN 1 ELSE 0 END) AS confirmedcount,
SUM(CASE WHEN billstatus = 1 THEN totalamount ELSE 0 END) AS confirmed,
(SUM(CASE WHEN billstatus = 1 THEN totalamount ELSE 0 END) / SUM(totalamount) * 100) AS confrimedpercent,
SUM(CASE WHEN billstatus = 2 THEN 1 ELSE 0 END) AS paidcount,
SUM(CASE WHEN billstatus = 2 THEN totalamount ELSE 0 END) AS paid,
(SUM(CASE WHEN billstatus = 2 THEN totalamount ELSE 0 END) / SUM(totalamount) * 100) AS paidpercent,
SUM(CASE WHEN billstatus IN (0) and status='pending' AND duedate <= CURRENT_DATE THEN 1 ELSE 0 END) AS overduecount,
SUM(CASE WHEN billstatus IN(0) and status='pending' AND duedate <= CURRENT_DATE THEN totalamount ELSE 0 END) AS overdue,
(SUM(CASE WHEN billstatus IN(0) and status='pending' AND duedate <= CURRENT_DATE THEN totalamount ELSE 0 END) / SUM(totalamount) * 100) AS overduepercent
FROM tenantsales`
}
// print(q1)
db.DB.Raw(q1).Find(&data)
return data
}
func CreateInvoice(data models.Tenantsales) error {
tx := db.DB.Begin()
t1 := tx.Create(&data)
if t1.Error != nil {
utils.Error("CreateInvoice error", "error", t1.Error)
tx.Rollback()
return t1.Error
}
t2 := tx.Table("deliveries").Where("deliverydate>=? and deliverydate<=?", data.Tenantsalesdetails[0].Fromdate, data.Tenantsalesdetails[0].Todate).Update("settlementid", data.Salesid)
if t2.Error != nil {
utils.Error("CreateInvoice deliveries update error", "error", t2.Error)
tx.Rollback()
return t2.Error
}
UpdateSeqno(data.Tenantid, "INV")
err := tx.Commit().Error
if err != nil {
return err
}
return nil
}
func UpdateInvoice(data models.Tenantsales) error {
tx := db.DB.Begin()
t1 := tx.Where("salesid=?", data.Salesid).Updates(&data)
if t1.Error != nil {
utils.Error("UpdateInvoice error", "error", t1.Error)
tx.Rollback()
}
err := tx.Commit().Error
if err != nil {
return err
}
return nil
}
func UpdateInvoiceStatus(data models.InvoiceStatus) error {
tx := db.DB.Begin()
t1 := tx.Table("tenantsales").Where("salesid=?", data.Salesid).Updates(&data)
if t1.Error != nil {
utils.Error("UpdateInvoiceStatus error", "error", t1.Error)
tx.Rollback()
}
err := tx.Commit().Error
if err != nil {
return err
}
return nil
}

1072
domain/order.go Normal file

File diff suppressed because it is too large Load Diff

1388
domain/partner.go Normal file

File diff suppressed because it is too large Load Diff

34
domain/platform.go Normal file
View File

@@ -0,0 +1,34 @@
package domain
import (
"nearle/db"
"nearle/models"
"nearle/utils"
"strconv"
)
func GetModules(mid int) []models.AppModules {
var data []models.AppModules
q1 := `SELECT a.moduleid,a.modulename,a.logourl,
(SELECT COUNT(*) FROM tenants WHERE moduleid=a.moduleid) AS business,
(SELECT COUNT(*) FROM deliveries WHERE moduleid=a.moduleid) as orders from app_module a where a.status='Active' order by sortorder asc`
db.DB.Raw(q1).Find(&data)
return data
}
func GetSmsprovider(tid int) models.Smsproviders {
var data models.Smsproviders
q1 := `select * from smsproviders where status='Active' and templatetypeid=` + strconv.Itoa(tid)
db.DB.Raw(q1).Find(&data)
utils.Logger.Debugf("Query: %s", q1)
return data
}

847
domain/product.go Normal file
View File

@@ -0,0 +1,847 @@
package domain
import (
"errors"
"nearle/db"
"nearle/models"
"nearle/utils"
"strconv"
"strings"
"time"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
func GetProductCategory() []models.ProductCategory {
var data []models.ProductCategory
q1 := `SELECT * FROM productcategories WHERE moduleid = 2 and status = "Active"`
db.DB.Raw(q1).Scan(&data)
return data
}
func GetProductSubCategory(categoryID, tenantID int) []models.ProductSubCategory {
var data []models.ProductSubCategory
var query strings.Builder
var args []interface{}
query.WriteString("SELECT * FROM productsubcategories WHERE 1=1")
if tenantID != 0 {
query.WriteString(" AND tenantid = ?")
args = append(args, tenantID)
}
if categoryID != 0 {
query.WriteString(" AND categoryid = ?")
args = append(args, categoryID)
}
db.DB.Raw(query.String(), args...).Scan(&data)
return data
}
func CreateProduct(product *models.Products) error {
tx := db.DB.Begin()
t1 := tx.Create(&product)
if t1.Error != nil {
utils.Error("CreateProduct error", "error", t1.Error)
tx.Rollback()
return t1.Error
}
err := tx.Commit().Error
if err != nil {
return err
}
return nil
}
func CreateProductVariant(input models.Productvariant) error {
tx := db.DB.Begin()
t1 := tx.Create(&input)
if t1.Error != nil {
utils.Error("CreateProductVariant error", "error", t1.Error)
tx.Rollback()
return t1.Error
}
err := tx.Commit().Error
if err != nil {
return err
}
return nil
}
func FetchFilteredProducts(categoryID, subcategoryID, productID, applocationID, tenantID, locationID int, keyword, productStatus, approve string, pageno, pagesize int) ([]models.Tenantproducts, error) {
offset := (pageno - 1) * pagesize
results := make([]models.Tenantproducts, 0)
if tenantID == 0 {
return results, nil
}
var tenant models.TenantInfo
err := db.DB.Table("tenants").Where("tenantid = ?", tenantID).First(&tenant).Error
if err != nil {
return nil, err
}
var products []models.Products
query := db.DB.
Debug().
Table("products a").
Select(`
a.*,
c.categoryname,
d.subcatname AS subcategoryname,
e.locationid,
COALESCE(
SUM(CASE WHEN e.stocktype = 'in' THEN e.quantity ELSE 0 END) -
SUM(CASE WHEN e.stocktype = 'out' THEN e.quantity ELSE 0 END),
0
) AS quantity
`).
Joins("LEFT JOIN productcategories c ON a.categoryid = c.categoryid").
Joins("LEFT JOIN productsubcategories d ON a.subcategoryid = d.subcatid").
Joins("LEFT JOIN productstocks e ON e.productid = a.productid").
Where("a.tenantid = ?", tenantID).
Group("a.productid"). // Important for SUM
Order("a.productid DESC")
if categoryID != 0 {
query = query.Where("a.categoryid = ?", categoryID)
}
if subcategoryID != 0 {
query = query.Where("a.subcategoryid = ?", subcategoryID)
}
if productID != 0 {
query = query.Where("a.productid = ?", productID)
}
if productStatus != "" {
query = query.Where("a.productstatus = ?", productStatus)
}
if locationID != 0 {
query = query.Where("e.locationid = ?", locationID)
}
if approve != "" {
query = query.Where("a.approve = ?", approve)
}
if keyword != "" {
like := "%" + strings.ToLower(keyword) + "%"
query = query.Where(
db.DB.Where("LOWER(a.productname) LIKE ?", like).
Or("LOWER(a.unitvalue) LIKE ?", like).
Or("LOWER(CAST(a.productcost AS CHAR)) LIKE ?", like),
)
}
if pagesize > 0 && offset >= 0 {
query = query.Limit(pagesize).Offset(offset)
}
err = query.Scan(&products).Error
if err != nil {
return nil, err
}
if products == nil {
products = []models.Products{}
}
results = append(results, models.Tenantproducts{
Tenant: tenant,
Products: products,
})
return results, nil
}
func UpdateProduct(input models.Products) error {
tx := db.DB.Begin()
t1 := tx.Where("productid=?", input.Productid).Updates(&input)
if t1.Error != nil {
tx.Rollback()
return t1.Error
}
err := tx.Commit().Error
if err != nil {
return err
}
return nil
}
func Getproductcount(tenantid, categoryid, subcategory int, approve string) ([]models.Productcount, error) {
var data []models.Productcount
baseQuery := `
SELECT
COUNT(*) AS total,
SUM(CASE WHEN a.productstatus = 'available' THEN 1 ELSE 0 END) AS available,
SUM(CASE WHEN a.productstatus = 'outofstock' THEN 1 ELSE 0 END) AS outofstock
FROM products a
WHERE 1 = 1
`
var conditions []string
var params []interface{}
if tenantid != 0 {
conditions = append(conditions, "a.tenantid = ?")
params = append(params, tenantid)
}
if categoryid != 0 {
conditions = append(conditions, "a.categoryid = ?")
params = append(params, categoryid)
}
if subcategory != 0 {
conditions = append(conditions, "a.subcategoryid = ?")
params = append(params, subcategory)
}
if approve != "" {
conditions = append(conditions, "a.approve = ?")
params = append(params, approve)
}
if len(conditions) > 0 {
baseQuery += " AND " + strings.Join(conditions, " AND ")
}
if err := db.DB.Raw(baseQuery, params...).Scan(&data).Error; err != nil {
return nil, err
}
return data, nil
}
func GetproductbyVariant(tenantid, variantid int) ([]models.Products, error) {
var data []models.Products
err := db.DB.
Table("products p").
Select("p.*, c.categoryname, d.subcatname as subcategoryname").
Joins("LEFT JOIN productcategories c ON p.categoryid = c.categoryid").
Joins("LEFT JOIN productsubcategories d ON p.subcategoryid = d.subcatid").
Where("p.tenantid = ? and p.variants = ?", tenantid, variantid).
Order("p.productid desc").Scan(&data).Error
if err != nil {
return nil, err
}
return data, nil
}
func GetProductVariants(tenantId int, subcategoryId int) []models.Productvariant {
var data []models.Productvariant
var query string
var params []interface{}
query = `
SELECT a.*, b.categoryname
FROM productvariants a
JOIN app_category b ON a.categoryid = b.categoryid
WHERE a.tenantid = ?
`
params = append(params, tenantId)
if subcategoryId != 0 {
query += " AND a.subcategoryid = ?"
params = append(params, subcategoryId)
}
db.DB.Raw(query, params...).Scan(&data)
return data
}
func GetCatalougeProducts(tenantId, locationid, subcategoryid, pageno, pagesize int, keyword string) []models.Products {
var data []models.Products
var query string
if pageno < 1 {
pageno = 1
}
if pagesize < 1 {
pagesize = 10
}
offset := (pageno - 1) * pagesize
params := []interface{}{locationid, tenantId}
query = `SELECT a.* FROM products a
LEFT JOIN productlocations b ON a.productid = b.productid
AND b.locationid =? AND b.tenantid = a.tenantid
WHERE a.approve=1 and a.tenantid = ? AND b.productid IS NULL order by a.productid desc LIMIT ` + strconv.Itoa(pagesize) + ` OFFSET ` + strconv.Itoa(offset)
if subcategoryid != 0 {
query += " AND a.subcategoryid = ?"
params = append(params, subcategoryid)
}
if keyword != "" {
query += " AND LOWER(a.productname) LIKE ?"
params = append(params, "%"+strings.ToLower(keyword)+"%")
}
db.DB.Raw(query, params...).Scan(&data)
utils.Logger.Debugf("Query: %s", query)
return data
}
func GetLocationProducts(tenantid, locationid, subcategoryid, pageno, pagesize int, keyword string) []models.Products {
var data []models.Products
if pageno < 1 {
pageno = 1
}
if pagesize < 1 {
pagesize = 10
}
offset := (pageno - 1) * pagesize
params := []interface{}{tenantid, locationid}
query := `SELECT a.*,
COALESCE(SUM(CASE WHEN UPPER(c.stocktype) = 'IN' THEN c.quantity ELSE 0 END), 0) AS total_in,
COALESCE(SUM(CASE WHEN UPPER(c.stocktype) = 'OUT' THEN c.quantity ELSE 0 END), 0) AS total_out,
COALESCE(SUM(CASE WHEN UPPER(c.stocktype) = 'IN' THEN c.quantity ELSE 0 END) -
SUM(CASE WHEN UPPER(c.stocktype) = 'OUT' THEN c.quantity ELSE 0 END), 0) AS productstock
FROM products a
INNER JOIN productlocations b
ON a.productid = b.productid AND a.tenantid = b.tenantid
LEFT JOIN productstocks c
ON a.productid = c.productid
AND b.locationid = c.locationid
AND a.tenantid = c.tenantid
WHERE a.approve=1 AND a.tenantid = ?
AND b.locationid = ?`
if subcategoryid != 0 {
query += " AND a.subcategoryid = ?"
params = append(params, subcategoryid)
}
if keyword != "" {
query += " AND LOWER(a.productname) LIKE ?"
params = append(params, "%"+strings.ToLower(keyword)+"%")
}
query += ` GROUP BY a.productid, a.productname, a.productimage, a.categoryid, a.subcategoryid,
a.productunit, a.productcost, a.taxpercent, a.taxamount, a.retailprice,
b.tenantid, b.locationid`
query += " ORDER BY a.productid DESC LIMIT ? OFFSET ?"
params = append(params, pagesize, offset)
db.DB.Raw(query, params...).Scan(&data)
return data
}
func GetStockStatement(tenantid, locationid, subcategoryid, pageno, pagesize int, keyword string) []models.Productstockstatement {
data := make([]models.Productstockstatement, 0)
if pageno < 1 {
pageno = 1
}
if pagesize < 1 {
pagesize = 10
}
offset := (pageno - 1) * pagesize
params := []interface{}{tenantid, locationid}
query := `SELECT a.productid,a.productname,a.productimage,a.categoryid,a.subcategoryid,a.productunit,a.unitvalue,a.productcost,a.taxpercent,a.taxamount,a.retailprice,b.tenantid,b.locationid,
COALESCE( SUM(CASE WHEN UPPER(c.stocktype) = 'IN' AND c.stockdate::date <= CURRENT_DATE THEN c.quantity ELSE 0 END) -
SUM(CASE WHEN UPPER(c.stocktype) = 'OUT' AND c.stockdate::date <= CURRENT_DATE THEN c.quantity ELSE 0 END),0 )
AS opening,
COALESCE(SUM(CASE WHEN UPPER(c.stocktype) = 'IN' AND c.stockdate::date = CURRENT_DATE THEN c.quantity ELSE 0 END), 0) AS credit,
COALESCE(SUM(CASE WHEN UPPER(c.stocktype) = 'OUT' AND c.stockdate::date= CURRENT_DATE THEN c.quantity ELSE 0 END), 0) AS debit,
COALESCE(
( SUM(CASE WHEN UPPER(c.stocktype) = 'IN' AND c.stockdate::date < CURRENT_DATE THEN c.quantity ELSE 0 END) -
SUM(CASE WHEN UPPER(c.stocktype) = 'OUT' AND c.stockdate::date < CURRENT_DATE THEN c.quantity ELSE 0 END)
) +
SUM(CASE WHEN UPPER(c.stocktype) = 'IN' AND c.stockdate::date = CURRENT_DATE THEN c.quantity ELSE 0 END) -
SUM(CASE WHEN UPPER(c.stocktype) = 'OUT' AND c.stockdate::date = CURRENT_DATE THEN c.quantity ELSE 0 END),
0
) AS closing
FROM products a
JOIN productlocations b ON a.productid = b.productid AND a.tenantid = b.tenantid
LEFT JOIN productstocks c ON a.productid = c.productid AND b.locationid = c.locationid AND b.tenantid = c.tenantid
WHERE b.tenantid = ? AND b.locationid = ?`
if subcategoryid != 0 {
query += " AND a.subcategoryid = ?"
params = append(params, subcategoryid)
}
if keyword != "" {
query += " AND (CAST(a.productid AS CHAR) LIKE ? OR LOWER(a.productname) LIKE ?)"
likeParam := "%" + strings.ToLower(keyword) + "%"
params = append(params, likeParam, likeParam)
}
query += `
GROUP BY
a.productid, a.productname, a.productimage,
a.categoryid, a.subcategoryid, a.productunit,
a.productcost, a.taxpercent, a.taxamount,
a.retailprice, b.tenantid, b.locationid
ORDER BY a.productid DESC LIMIT ` + strconv.Itoa(pagesize) + ` OFFSET ` + strconv.Itoa(offset)
db.DB.Raw(query, params...).Scan(&data)
utils.Logger.Debugf("Query: %s", query)
return data
}
func CreateProductLocation(input []models.Productlocations) error {
var stk []models.Productstock
tx := db.DB.Begin()
if err := tx.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "tenantid"}, {Name: "locationid"}, {Name: "productid"}},
DoUpdates: clause.AssignmentColumns([]string{"price", "minquantity", "maxquantity"}),
}).Create(&input).Error; err != nil {
tx.Rollback()
return err
}
for _, loc := range input {
if loc.Quantity > 0 {
stk = append(stk, models.Productstock{
Tenantid: loc.Tenantid,
Stockdate: time.Now(),
Locationid: loc.Locationid,
Productid: loc.Productid,
Quantity: loc.Quantity,
Stocktype: loc.Stocktype,
})
}
}
if len(stk) > 0 {
t2 := tx.Create(&stk)
if t2.Error != nil {
tx.Rollback()
return t2.Error
}
}
err := tx.Commit().Error
if err != nil {
return err
}
return nil
}
func UpdateProductLocation(input models.Productlocations) error {
tx := db.DB.Begin()
t1 := tx.Where("productlocationid=?", input.Productlocationid).Updates(&input)
if t1.Error != nil {
tx.Rollback()
return t1.Error
}
err := tx.Commit().Error
if err != nil {
return err
}
return nil
}
func FetchProductsBySubcategory(categoryID, tenantID, applocationID, locationID, productID int, keyword string) (map[string]interface{}, error) {
utils.Logger.Infof("Domain: Fetching products for categoryID=%d, tenantID=%d", categoryID, tenantID)
// Step 1: Fetch subcategories
var subcategories []models.Subcategory
err := db.DB.Table("productsubcategories").
Where("categoryid = ?", categoryID).
Find(&subcategories).Error
if err != nil {
utils.Error("Error fetching subcategories", "error", err)
return nil, err
}
// Step 2: Build product query
var products []models.Products
query := db.DB.Table("products a").
Joins("LEFT JOIN productlocations pl ON pl.productid = a.productid").
Where("a.categoryid = ? AND a.tenantid = ?", categoryID, tenantID)
if locationID > 0 {
query = query.Where("pl.locationid = ?", locationID)
}
if applocationID > 0 {
query = query.Where("a.applocationid = ?", applocationID)
}
if productID > 0 {
query = query.Where("a.productid = ?", productID)
}
if keyword != "" {
like := "%" + strings.ToLower(keyword) + "%"
query = query.Where(
db.DB.Where("LOWER(a.productname) LIKE ?", like).
Or("LOWER(a.unitvalue) LIKE ?", like).
Or("LOWER(CAST(a.productcost AS CHAR)) LIKE ?", like),
)
}
if err := query.Select("a.*").Find(&products).Error; err != nil {
utils.Error("Error fetching products", "error", err)
return nil, err
}
// Step 3: Grouping
var grouped []models.SubcategoryProductResponse
var uncategorized []models.Products
for _, subcat := range subcategories {
var matched []models.Products
for _, prod := range products {
if prod.Subcategoryid != nil && *prod.Subcategoryid == subcat.Subcategoryid {
matched = append(matched, prod)
}
}
if len(matched) > 0 {
grouped = append(grouped, models.SubcategoryProductResponse{
SubcategoryID: subcat.Subcategoryid,
SubcategoryName: subcat.Subcategoryname,
Products: matched,
})
}
}
// Add uncategorized
for _, p := range products {
if p.Subcategoryid == nil {
uncategorized = append(uncategorized, p)
}
}
if len(uncategorized) > 0 {
grouped = append(grouped, models.SubcategoryProductResponse{
SubcategoryID: 0,
SubcategoryName: "Uncategorized",
Products: uncategorized,
})
}
// Step 4: Tenant info
var tenantInfo map[string]interface{}
for _, p := range products {
if p.Tenantid != nil {
tenantInfo, err = fetchTenantDetails(*p.Tenantid, applocationID)
if err != nil {
utils.Error("Error fetching tenant details", "error", err)
}
break
}
}
if tenantInfo == nil {
return map[string]interface{}{}, nil
}
tenantInfo["details"] = grouped
return tenantInfo, nil
}
func fetchTenantDetails(tenantID, applocationID int) (map[string]interface{}, error) {
var tenant struct {
Tenantname string
Address string
Licenseno string
Primaryemail string
Primarycontact string
Locationname string
Pickuplocationid int
Suburb string
City string
Latitude string
Longitude string
Postcode string
}
err := db.DB.Raw(`
SELECT t.tenantname,t.address,t.licenseno,t.primaryemail,t.primarycontact,l.locationid AS pickuplocationid,l.suburb,l.city,l.latitude,l.longitude,l.postcode,a.locationname
FROM tenants t
LEFT JOIN tenantlocations l ON t.tenantid = l.tenantid
LEFT JOIN app_location a ON l.applocationid = a.applocationid
WHERE t.tenantid = ? AND t.applocationid = ?
LIMIT 1
`, tenantID, applocationID).Scan(&tenant).Error
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
return nil, err
}
return map[string]interface{}{
"tenantname": tenant.Tenantname,
"address": tenant.Address,
"licenseno": tenant.Licenseno,
"primaryemail": tenant.Primaryemail,
"primarycontact": tenant.Primarycontact,
"locationname": tenant.Locationname,
"pickuplocationid": tenant.Pickuplocationid,
"suburb": tenant.Suburb,
"city": tenant.City,
"pickuplat": tenant.Latitude,
"pickuplong": tenant.Longitude,
"postcode": tenant.Postcode,
}, nil
}
func UpdateProductStock(stock *models.Productstock) error {
// Ensure the record exists
var existing models.Productstock
if err := db.DB.First(&existing, "productstockid = ?", stock.Productstockid).Error; err != nil {
return err
}
// Update fields
return db.DB.Model(&existing).Updates(models.Productstock{
Tenantid: stock.Tenantid,
Stockdate: stock.Stockdate,
Locationid: stock.Locationid,
Productid: stock.Productid,
Quantity: stock.Quantity,
Stocktype: stock.Stocktype,
Status: stock.Status,
}).Error
}
func GetProductStocks(tenantID, locationID string) ([]models.Productstocks, error) {
var stocks []models.Productstocks
var params []interface{}
var conditions []string
query := `
SELECT
a.productid, a.tenantid, MAX(a.stockdate) AS stockdate, a.locationid, a.stocktype, a.maxquantity, a.minquantity, a.status,
b.applocationid, b.categoryid, b.subcategoryid, b.catalogueid, b.addonid, b.discountid, b.pricingid,
b.productname, b.productimage, b.productdesc, b.productsku, b.brandid, b.productbrand, b.productunit,
b.unitvalue, b.toppicks, b.productcost, b.taxamount, b.taxpercent, b.producttax, b.productstock,
b.productcombo, b.variants, b.retailprice, b.diffprice, b.diffpercent, b.othercost, b.approve,
b.productstatus, b.created, b.updated, c.subcatname AS subcategoryname,
SUM(CASE WHEN a.stocktype = 'in' THEN a.quantity ELSE 0 END) -
SUM(CASE WHEN a.stocktype = 'out' THEN a.quantity ELSE 0 END) AS quantity
FROM productstocks a
JOIN products b ON a.productid = b.productid
INNER JOIN productsubcategories c ON c.subcatid = b.subcategoryid
`
if tenantID != "" {
conditions = append(conditions, "a.tenantid = ?")
params = append(params, tenantID)
}
if locationID != "" {
conditions = append(conditions, "a.locationid = ?")
params = append(params, locationID)
}
if len(conditions) > 0 {
query += " WHERE " + strings.Join(conditions, " AND ")
}
query += " GROUP BY a.productid"
if err := db.DB.Raw(query, params...).Scan(&stocks).Error; err != nil {
return nil, err
}
return stocks, nil
}
func GetSubCategoryWiseSummary(tenantId, locationid, subcategoryid int) ([]models.SubCategorySummary, error) {
var data []models.SubCategorySummary
query := `
SELECT a.subcategoryid AS subcategoryid, c.subcatname AS subcatname, COUNT(a.productid) AS productcount
FROM products a
LEFT JOIN productlocations b ON a.productid = b.productid AND b.locationid = ? AND b.tenantid = a.tenantid
LEFT JOIN productsubcategories c ON a.subcategoryid = c.subcatid
WHERE a.approve = 1 AND a.tenantid = ? AND b.productid IS NULL
`
var params []interface{}
params = append(params, locationid, tenantId)
if subcategoryid > 0 {
query += " AND a.subcategoryid = ?"
params = append(params, subcategoryid)
}
query += `
GROUP BY a.subcategoryid, c.subcatname
ORDER BY a.subcategoryid ASC
`
if err := db.DB.Raw(query, params...).Scan(&data).Error; err != nil {
return nil, err
}
return data, nil
}
func GetLocationProductSummary(tenantid, locationid int) []models.ProductSummary {
data := make([]models.ProductSummary, 0)
params := []interface{}{tenantid, locationid}
query := `
SELECT a.subcatid AS subcategoryid, a.subcatname AS subcategroyname, a.image, COUNT(DISTINCT b.productid) AS productcount
FROM productsubcategories a
LEFT JOIN products b ON a.subcatid = b.subcategoryid AND b.approve = 1 AND b.tenantid = ?
LEFT JOIN productlocations c ON b.productid = c.productid AND b.tenantid = c.tenantid AND c.locationid = ?
WHERE a.categoryid = 2
GROUP BY a.subcatid, a.subcatname
ORDER BY a.subcatid;
`
db.DB.Raw(query, params...).Scan(&data)
total := 0
for _, d := range data {
total += d.Productcount
}
all := models.ProductSummary{
Subcategoryid: 0,
Subcategroyname: "All",
Productcount: total,
}
data = append([]models.ProductSummary{all}, data...)
return data
}
func GetStockStatementSummary(tenantid, locationid int) []models.ProductSummary {
data := make([]models.ProductSummary, 0)
params := []interface{}{tenantid, locationid}
query := `
SELECT a.subcatid AS subcategoryid, a.subcatname AS subcategroyname, a.image, COUNT(DISTINCT b.productid) AS productcount
FROM productsubcategories a
LEFT JOIN products b ON a.subcatid = b.subcategoryid AND b.tenantid = ?
LEFT JOIN productlocations c ON b.productid = c.productid AND b.tenantid = c.tenantid AND c.locationid = ?
WHERE a.categoryid = 2
GROUP BY a.subcatid, a.subcatname
ORDER BY a.subcatid;
`
db.DB.Raw(query, params...).Scan(&data)
utils.Logger.Debugf("Query: %s", query)
// Add "All" row
total := models.ProductSummary{
Subcategoryid: 0,
Subcategroyname: "All",
}
for _, d := range data {
total.Productcount += d.Productcount
}
data = append([]models.ProductSummary{total}, data...)
return data
}
func CreateProductDiscount(discount *models.ProductDiscount) error {
// convert []string to comma-separated string
if len(discount.Locationid) > 0 {
discount.LocationidStr = strings.Join(discount.Locationid, ",")
}
tx := db.DB.Begin()
if err := tx.Table("productdiscounts").Create(discount).Error; err != nil {
tx.Rollback()
return err
}
return tx.Commit().Error
}
func GetProductDiscounts(tid int, lid string) []models.ProductDiscount {
var result []models.ProductDiscount
query := `
SELECT
discountid, discounttypeid, tenantid, productid, moduleid,
locationid, discountname, discountcode,
discountterms, discountvalue, startdate, enddate, status
FROM productdiscounts
WHERE tenantid = ?
AND moduleid = 2
AND FIND_IN_SET(?, locationid)
`
db.DB.Raw(query, tid, lid).Scan(&result)
// convert comma separated location ids to []string
for i := range result {
if result[i].LocationidStr != "" {
result[i].Locationid = strings.Split(result[i].LocationidStr, ",")
} else {
result[i].Locationid = []string{}
}
}
return result
}

591
domain/tenant.go Normal file
View File

@@ -0,0 +1,591 @@
package domain
import (
"errors"
"nearle/db"
"nearle/models"
"nearle/utils"
"strconv"
"strings"
"github.com/jinzhu/copier"
)
func CreateTenantUser(data models.Tenants) (bool, error) {
var seq models.Ordersequences
var user models.User
var cust models.Customers
var custloc models.Customerlocations
var tcust models.Tenantcustomers
tx := db.DB.Begin()
t1 := tx.Create(&data)
if t1.Error != nil {
tx.Rollback()
return false, errors.New("error in tenant creation")
}
seq.Tenantid = data.Tenantid
t2 := tx.Table("ordersequences").Create(&seq)
if t2.Error != nil {
tx.Rollback()
return false, errors.New("error in sequence")
}
if err := copier.Copy(&user, &data); err != nil {
return false, err
}
user.Userfcmtoken = data.Tenanttoken
user.Contactno = data.Primarycontact
user.Email = data.Primaryemail
user.Authname = data.Primaryemail
user.Deviceid = data.Deviceid
user.Tenantid = data.Tenantid
user.Locationid = data.Tenantlocations.Locationid
user.Roleid = 1
t3 := tx.Table("app_users").Create(&user)
if t3.Error != nil {
tx.Rollback()
return false, errors.New("error in user creation")
}
cust.Configid = data.Configid
cust.Firstname = data.Tenantname
cust.Email = data.Primaryemail
cust.Contactno = data.Primarycontact
cust.Deviceid = data.Deviceid
cust.Devicetype = data.Devicetype
cust.Customertoken = data.Tenanttoken
cust.Profileimage = data.Tenantimage
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 = 1
cid := CheckCustomer(data.Primarycontact)
if cid == 0 {
t4 := tx.Table("customers").Create(&cust)
if t4.Error != nil {
tx.Rollback()
return false, errors.New("error in customer creation")
}
if err := copier.Copy(&custloc, &cust); err != nil {
return false, err
}
t5 := tx.Table("customerlocations").Create(&custloc)
if t5.Error != nil {
tx.Rollback()
return false, errors.New("error in customer location")
}
} else {
t1 := tx.Table("customers").Where("customerid=?", cid).Updates(&cust)
if t1.Error != nil {
tx.Rollback()
return false, errors.New("error in customer creation")
}
if err := copier.Copy(&custloc, &cust); err != nil {
return false, err
}
t2 := tx.Table("customerlocations").Where("customerid=?", cid).Updates(&custloc)
if t2.Error != nil {
tx.Rollback()
return false, errors.New("error in customer location")
}
}
tcust.Customerid = cust.Customerid
tcust.Tenantid = data.Tenantid
tcust.Locationid = data.Tenantlocations.Locationid
t6 := tx.Table("tenantcustomers").Create(&tcust)
if t6.Error != nil {
tx.Rollback()
return false, errors.New("error in tenant customer")
}
err := tx.Commit().Error
if err != nil {
return false, errors.New("error in tenant creation")
}
return true, nil
}
func UpdateTenant(input models.Tenants) error {
tx := db.DB.Begin()
t1 := tx.Where("tenantid=?", input.Tenantid).Updates(&input)
if t1.Error != nil {
tx.Rollback()
return t1.Error
}
err := tx.Commit().Error
if err != nil {
return err
}
return nil
}
func UpdateLocation(input models.Tenantlocations) error {
tx := db.DB.Begin()
t1 := tx.Where("locationid=?", input.Locationid).Updates(&input)
if t1.Error != nil {
tx.Rollback()
return t1.Error
}
err := tx.Commit().Error
if err != nil {
return err
}
return nil
}
func CreateLocation(data models.Tenantlocations) error {
var cust models.Customers
var tcust models.Tenantcustomers
var custloc models.Customerlocations
tx := db.DB.Begin()
t1 := tx.Create(&data)
if t1.Error != nil {
tx.Rollback()
return t1.Error
}
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
t2 := tx.Table("customers").Create(&cust)
if t2.Error != nil {
tx.Rollback()
return t2.Error
}
if err := copier.Copy(&custloc, &cust); err != nil {
return err
}
t3 := tx.Table("customerlocations").Create(&custloc)
if t3.Error != nil {
tx.Rollback()
return t3.Error
}
tcust.Customerid = cust.Customerid
tcust.Tenantid = data.Tenantid
tcust.Locationid = data.Locationid
tcust.Moduleid = data.Moduleid
t4 := tx.Table("tenantcustomers").Create(&tcust)
if t4.Error != nil {
tx.Rollback()
return t4.Error
}
err := tx.Commit().Error
if err != nil {
return err
}
return nil
}
func Checktenantbyno(cno string) int {
var id int
q1 := "select tenantid from tenants where primarycontact='" + cno + `'`
db.DB.Raw(q1).Find(&id)
return id
}
func GetTeanantById(tid int) models.Tenantinfo {
var data models.Tenantinfo
// q1 := `SELECT a.*,b.categoryid,b.subcategoryid,c.subcategoryname,b.moduleid,d.locationid,d.locationname FROM
// tenants a
// INNER JOIN tenantsubscriptions b ON a.tenantid=b.tenantid
// INNER JOIN app_subcategory c ON c.subcategoryid=b.subcategoryid
// INNER JOIN tenantlocations d ON d.tenantid=a.tenantid
// where a.tenantid=?`
q1 := `SELECT a.*,b.categoryname,c.locationname as applocation,d.allocationid as allocationmode,e.typename AS allocationtype,e.mapid as allocationid,f.locationid,
f.locationname, g.slab, g.pricingdate, g.baseprice, g.minkm, g.priceperkm, g.maxkm, g.orders, g.othercharges, g.surgecharges
FROM tenants a
INNER JOIN app_category b ON a.categoryid=b.categoryid
INNER JOIN app_location c ON a.applocationid=c.applocationid
LEFT JOIN partnerinfo d ON a.partnerid=d.partnerid
LEFT JOIN app_types e ON d.allocationid=e.apptypeid
LEFT JOIN tenantlocations f ON a.tenantid=f.tenantid
LEFT JOIN tenantpricing g ON a.tenantid=g.tenantid
where a.tenantid=?`
utils.Logger.Debugf("Query: %s", q1)
db.DB.Raw(q1, tid).Find(&data)
return data
}
func GetTeanantPricing(tid, aid int) models.Tenantpricing {
var data models.Tenantpricing
var q1 string
if tid != 0 {
q1 = `SELECT * FROM tenantpricing WHERE pricingdate = (SELECT MAX(pricingdate) FROM tenantpricing where tenantid=` + strconv.Itoa(tid) + `) AND tenantid=? order by tenantpricingid desc`
}
utils.Logger.Debugf("Query: %s", q1)
db.DB.Raw(q1, tid).Find(&data)
return data
}
func GetPricinglist(tid int) []models.Tenantpricing {
var data []models.Tenantpricing
q1 := `SELECT *
FROM tenantpricing
WHERE tenantid=? order by pricingdate desc`
db.DB.Raw(q1, tid).Find(&data)
return data
}
func Getalltenants(pageno, pagesize, aid, moduleid int, status, tenanttype, keyword string) []models.Tenantinfo {
offset := (pageno - 1) * pagesize
var data []models.Tenantinfo
base := `
SELECT a.*, b.categoryname, c.slab, c.pricingdate, c.baseprice, c.minkm,
c.priceperkm, c.maxkm, c.orders,
c.othercharges, c.surgecharges
FROM tenants a
LEFT JOIN app_category b ON a.categoryid = b.categoryid
LEFT JOIN (
SELECT DISTINCT ON (tenantid) *
FROM tenantpricing
ORDER BY tenantid, pricingdate DESC
) c ON a.tenantid = c.tenantid
WHERE 1 = 1
`
var (
conds []string
params []interface{}
)
switch strings.ToLower(status) {
case "active":
conds = append(conds, "a.approved = 1 AND a.status = 'Active'")
case "inactive":
conds = append(conds, "a.approved = 1 AND a.status = 'InActive'")
case "pending":
conds = append(conds, "a.approved = 0")
}
if aid != 0 {
conds = append(conds, "a.applocationid = ?")
params = append(params, aid)
}
if moduleid != 0 {
conds = append(conds, "a.moduleid = ?")
params = append(params, moduleid)
}
if tenanttype != "" {
conds = append(conds, "a.tenanttype = ?")
params = append(params, tenanttype)
}
if keyword != "" {
kw := "%" + strings.ToLower(keyword) + "%"
conds = append(conds,
"(LOWER(a.tenantname) LIKE ? OR LOWER(a.primarycontact) LIKE ?)")
params = append(params, kw, kw)
}
if len(conds) > 0 {
base += " AND " + strings.Join(conds, " AND ")
}
base += " ORDER BY a.tenantid DESC LIMIT ? OFFSET ?"
params = append(params, pagesize, offset)
print(base, params)
db.DB.Raw(base, params...).Find(&data)
return data
}
func GetCustomerLocations(customerID int) models.CustomerTenantResponse {
var customer models.Customers
// get customer
db.DB.Table("customers").
Where("customerid = ?", customerID).
First(&customer)
// get locations
locations := []models.LocationDetails{}
query := `
SELECT
c.locationid,c.locationname,c.tenantid,b.tenantname,c.address,c.email,c.contactno,c.applocationid,c.suburb,c.city,c.latitude,c.longitude,c.postcode
FROM tenantcustomers a
Left join tenants b ON a.tenantid = b.tenantid
LEFT JOIN tenantlocations c ON a.locationid = c.locationid
WHERE a.customerid = ?
`
db.DB.Raw(query, customerID).Scan(&locations)
// print(customer, locations)
return models.CustomerTenantResponse{
Customer: customer,
Tenantlocations: locations,
}
}
func CreateTenantLocation(data models.Tenantlocations) error {
var user models.Tenantuser
tx := db.DB.Begin()
// 🔧 Set status BEFORE insert
data.Status = "InActive"
// Step 1: Insert into tenantlocations
if err := tx.Create(&data).Error; err != nil {
tx.Rollback()
return err
}
// Step 2: Insert into app_users
user.Authname = data.Email
user.Firstname = data.Locationname
user.Email = data.Email
user.Contactno = data.Contactno
user.Address = data.Address
user.Suburb = data.Suburb
user.City = data.City
user.State = data.State
user.Postcode = data.Postcode
user.Partnerid = data.Partnerid
user.Tenantid = data.Tenantid
user.Locationid = data.Locationid
user.Applocationid = data.Applocationid
user.Configid = 1
user.Status = "InActive"
user.Roleid = 0
user.Authmode = 0
user.Password = ""
user.Dialcode = "+91"
if err := tx.Table("app_users").Create(&user).Error; err != nil {
tx.Rollback()
return err
}
// Commit
if err := tx.Commit().Error; err != nil {
return err
}
return nil
}
func UpdateTenantLocation(input models.Tenantlocations) error {
tx := db.DB.Begin()
t1 := tx.Where("locationid=?", input.Locationid).Updates(&input)
if t1.Error != nil {
tx.Rollback()
return t1.Error
}
err := tx.Commit().Error
if err != nil {
return err
}
return nil
}
func FetchLocationSummary(tenantID int) models.LocationSummary {
var summary models.LocationSummary
db.DB.Raw(`
SELECT
SUM(CASE WHEN status = 'Active' THEN 1 ELSE 0 END) AS active_count,
SUM(CASE WHEN status = 'InActive' THEN 1 ELSE 0 END) AS inactive_count,
COUNT(*) AS total_count
FROM tenantlocations
WHERE tenantid = ?
`, tenantID).Scan(&summary)
return summary
}
func FetchTenantStaffSummary(tenantID int) models.TenantUserSummary {
var summary models.TenantUserSummary
query := `
SELECT
SUM(CASE WHEN a.status = 'Active' THEN 1 ELSE 0 END) AS active_count,
SUM(CASE WHEN b.status = 'InActive' THEN 1 ELSE 0 END) AS inactive_count,
COUNT(*) AS total_count
FROM tenantstaffs a
JOIN app_users b ON a.userid = b.userid
WHERE a.tenantid = ? AND b.roleid = 2
`
db.DB.Raw(query, tenantID).Scan(&summary)
return summary
}
func FetchTenantRiderSummary(tenantID int) models.TenantUserSummary {
var summary models.TenantUserSummary
query := `
SELECT
SUM(CASE WHEN a.status = 'Active' THEN 1 ELSE 0 END) AS active_count,
SUM(CASE WHEN a.status = 'InActive' THEN 1 ELSE 0 END) AS inactive_count,
COUNT(*) AS total_count
FROM tenantstaffs a
JOIN app_users b ON a.userid = b.userid
WHERE a.tenantid = ? AND b.roleid = 3
`
db.DB.Raw(query, tenantID).Scan(&summary)
return summary
}
func CreateTenantPromotion(promo *models.Tenantpromotions) error {
// convert []string to comma-separated string
if len(promo.Locationid) > 0 {
promo.LocationidStr = strings.Join(promo.Locationid, ",")
}
tx := db.DB.Begin()
if err := tx.Table("tenantpromotions").Create(promo).Error; err != nil {
tx.Rollback()
return err
}
return tx.Commit().Error
}
func GetTenantPromotions(tid int, lid string) []models.Tenantpromotions {
var result []models.Tenantpromotions
query := `
SELECT
promotionid, promotiontypeid, tenantid,
locationid, applocationid, moduleid, categoryid,
promoname, promocode, description, product, productimage,
promoamount, promovalue, purchasevalue, startdate, enddate
FROM tenantpromotions
WHERE tenantid = ?
AND moduleid = 2
AND FIND_IN_SET(?, locationid)
`
db.DB.Raw(query, tid, lid).Scan(&result)
// Convert location string → slice
for i := range result {
if result[i].LocationidStr != "" {
result[i].Locationid = strings.Split(result[i].LocationidStr, ",")
} else {
result[i].Locationid = []string{}
}
}
return result
}

457
domain/userDomain.go Normal file
View File

@@ -0,0 +1,457 @@
package domain
import (
"nearle/db"
"nearle/models"
"nearle/utils"
"strconv"
"strings"
)
func Getuserbyid(uid int) models.UserInfo {
var user models.UserInfo
q1 := `SELECT a.userid,a.authname,a.email,a.configid,a.roleid,a.authmode,a.contactno,
a.firstname,a.lastname,concat(a.firstname,' ',a.lastname) as fullname,a.password,a.address,a.suburb,a.city,a.state,a.postcode,
a.userfcmtoken,a.pin,a.deviceid,a.devicetype,a.tenantid,a.shiftid,
a.applocationid,b.locationname as applocation,b.latitude as applatitude,b.longitude as applongitude, b.radius as appradius , concat(c.starttime, ' - ', c.endtime) as shiftname
from app_users a
INNER JOIN app_location b on a.applocationid=b.applocationid
LEFT JOIN ridershifts c ON a.shiftid = c.shiftid
WHERE a.userid= ` + strconv.Itoa(uid)
// print(q1)
db.DB.Raw(q1).Find(&user)
return user
}
func GetAllUsers(
roleID, configID, tenantID, pageno, pagesize int,
status, keyword string,
) []models.UserInfo {
var users []models.UserInfo
var params []interface{}
var queryBuilder strings.Builder
offset := (pageno - 1) * pagesize
queryBuilder.WriteString(`
SELECT
a.userid, a.authname, a.email, a.configid, a.roleid, a.authmode, a.contactno,
a.firstname, a.lastname, CONCAT(a.firstname, ' ', a.lastname) AS fullname,
a.address, a.suburb, a.city, a.state, a.postcode,
a.userfcmtoken, a.pin, a.deviceid, a.devicetype,
a.tenantid, a.status, a.shiftid, a.latitude, a.longitude,d.rolename,
STRING_AGG(
CONCAT(
ac.applocationid, '::',
al.locationname, '::',
ac.status
)::text, ','
) AS applocations_raw
FROM app_users a
LEFT JOIN app_locationconfig ac ON ac.userid = a.userid
LEFT JOIN app_location al ON al.applocationid = ac.applocationid
LEFT JOIN app_roles d ON a.roleid = d.roleid
WHERE 1=1
`)
if roleID != 0 {
queryBuilder.WriteString(" AND a.roleid = ?")
params = append(params, roleID)
}
if configID != 0 {
queryBuilder.WriteString(" AND a.configid = ?")
params = append(params, configID)
}
if tenantID != 0 {
queryBuilder.WriteString(" AND a.tenantid = ?")
params = append(params, tenantID)
}
if status != "" {
queryBuilder.WriteString(" AND a.status = ?")
params = append(params, status)
}
if keyword != "" {
queryBuilder.WriteString(`
AND (
LOWER(a.firstname) LIKE ? OR
LOWER(a.contactno) LIKE ? OR
LOWER(a.suburb) LIKE ?
)
`)
search := "%" + strings.ToLower(keyword) + "%"
params = append(params, search, search, search)
}
queryBuilder.WriteString(`
GROUP BY a.userid, d.rolename
ORDER BY a.userid DESC
LIMIT ? OFFSET ?
`)
params = append(params, pagesize, offset)
// ---------- TEMP STRUCT ----------
type tempUser struct {
models.UserInfo
ApplocationsRaw string `gorm:"column:applocations_raw"`
}
var temp []tempUser
db.DB.Raw(queryBuilder.String(), params...).Scan(&temp)
// ---------- MAP RESULT ----------
for _, t := range temp {
t.UserInfo.Applocations = []models.AppLocation{}
if t.ApplocationsRaw != "" {
items := strings.Split(t.ApplocationsRaw, ",")
for _, item := range items {
parts := strings.Split(item, "::")
if len(parts) == 3 {
id, err := strconv.Atoi(parts[0])
if err == nil {
t.UserInfo.Applocations = append(
t.UserInfo.Applocations,
models.AppLocation{
Applocationid: id,
Applocationname: parts[1],
Status: parts[2],
},
)
}
}
}
}
users = append(users, t.UserInfo)
}
return users
}
func GetTenantUserbyId(uid int) models.TenantUserInfo {
var user models.TenantUserInfo
q1 := `SELECT a.userid,a.authname,a.email,a.configid,a.roleid,a.authmode,a.contactno,
a.firstname,a.lastname,concat(a.firstname,' ',a.lastname) as fullname,
a.userfcmtoken,a.pin,a.deviceid,a.devicetype,a.tenantid,a.locationid,a.applocationid,
b.partnerid,b.moduleid,b.categoryid as categoryid,b.subcategoryid as subcategoryid,
b.applocationid,b.tenantname,b.address as tenantaddress,b.state as tenantstate,b.city as tenantcity,
b.postcode as tenantpostcode,b.latitude as tenantlat,b.longitude as tenantlong,c.locationname AS applocation,
c.latitude as applatitude,c.longitude as applongitude,c.radius as appradius, d.categoryname, e.locationname
from app_users a
LEFT JOIN tenants b ON a.tenantid=b.tenantid
INNER JOIN app_location c on c.applocationid=b.applocationid
LEFT JOIN app_category d ON b.categoryid=d.categoryid
LEFT JOIN tenantlocations e ON a.locationid=e.locationid
WHERE a.userid= ` + strconv.Itoa(uid)
// print(q1)
db.DB.Raw(q1).Find(&user)
return user
}
func GetTenantId(uid int, contactno string) int {
var tid int
var q1 string
if contactno != "" {
q1 = `select tenantid from tenants WHERE primarycontact='` + contactno + `'`
} else {
q1 = `select primarycontact from tenants WHERE primarycontact='` + contactno + `'`
}
db.DB.Raw(q1).Find(&tid)
return tid
}
func Getuserbyno(cno string) models.UserInfo {
var user models.UserInfo
q1 := `SELECT a.userid,a.authname,a.email,a.configid,a.roleid,a.authmode,a.contactno,
a.firstname,a.lastname,concat(a.firstname,' ',a.lastname) as fullname,
a.userfcmtoken,a.pin,a.deviceid,a.devicetype,a.tenantid,a.locationid,
b.partnerid,b.moduleid,b.categoryid as categoryid,b.subcategoryid as subcategoryid,
b.applocationid,b.tenantname,b.address as tenantaddress,b.state as tenantstate,b.city as tenantcity,
b.postcode as tenantpostcode,b.latitude as tenantlat,b.longitude as tenantlong
from app_users a
LEFT JOIN tenants b ON a.tenantid=b.tenantid
WHERE a.contactno= '` + cno + `'`
db.DB.Raw(q1).Find(&user)
return user
}
func GetPartnerUserbyid(uid int) models.UserInfo {
var user models.UserInfo
q1 := `SELECT a.userid,a.authname,a.email,a.configid,a.roleid,a.authmode,a.contactno,a.firstname,a.lastname,concat(a.firstname,' ',a.lastname) as fullname,
a.userfcmtoken,a.pin,a.deviceid,a.devicetype,a.tenantid,a.applocationid,a.partnerid,
b.locationname AS applocation,b.latitude AS applatitude,b.longitude AS applongitude,b.radius AS appradius, b.deliveryradius, c.partnername
from app_users a
INNER JOIN app_location b ON a.applocationid=b.applocationid
LEFT JOIN partnerinfo c ON a.partnerid=c.partnerid
WHERE a.userid= ` + strconv.Itoa(uid)
db.DB.Raw(q1).Find(&user)
return user
}
func GetRiderUserbyid(uid int) models.RiderInfo {
var user models.RiderInfo
q1 := `SELECT a.userid,a.authname,a.email,a.configid,a.roleid,a.authmode,a.contactno, a.address,a.state,a.city,a.postcode,a.latitude,a.longitude,
a.firstname,a.lastname,concat(a.firstname,' ',a.lastname) as username,a.userfcmtoken,a.pin,a.deviceid,a.devicetype,a.partnerid,a.applocationid, a.tenantid, a.locationid, a.shiftid,
b.starttime, b.endtime, b.shifthours, b.firstmilecharge, b.fuelcharge, c.logid, d.onduty, e.logseconds, e.deliveryradius
from app_users a
LEFT JOIN ridershifts b ON a.shiftid=b.shiftid
LEFT JOIN riderlogs c ON a.userid=c.userid
LEFT JOIN app_userpools d on a.userid=d.userid
LEFT JOIN app_location e on a.applocationid=e.applocationid
WHERE a.userid= ` + strconv.Itoa(uid)
db.DB.Raw(q1).Find(&user)
utils.Logger.Debugf("Query: %s", q1)
return user
}
func GetAdminUserbyid(uid int) models.User {
var user models.User
q1 := `SELECT a.*,b.rolename from app_users a LEFT JOIN app_roles b ON a.roleid=b.roleid where a.userid= ` + strconv.Itoa(uid)
db.DB.Raw(q1).Find(&user)
return user
}
func UpdatUser(user models.User) {
db.DB.Table("app_users").Where("userid=?", user.Userid).Updates(&user)
if user.Tenantid != 0 {
db.DB.Table("tenants").Where("tenantid=?", user.Tenantid).Update("tenanttoken", user.Userfcmtoken)
}
}
func GetUserIDByContact(contact string, configID int) int {
var uid int
query := `SELECT userid FROM app_users WHERE contactno = ? AND configid = ?`
db.DB.Raw(query, contact, configID).Scan(&uid)
return uid
}
func GetUserIDByAuth(authname string, configID int) int {
var uid int
query := `SELECT userid FROM app_users WHERE authname = ? AND configid = ?`
db.DB.Raw(query, authname, configID).Scan(&uid)
return uid
}
func GetUserStatus(userid int) string {
var status string
db.DB.Raw("SELECT status FROM app_users WHERE userid = ?", userid).Scan(&status)
return status
}
func GetStoredPin(uid int) int {
var pin int
db.DB.Raw(`SELECT COALESCE(pin, 0) FROM app_users WHERE userid = ?`, uid).Scan(&pin)
return pin
}
func GetAuthMode(uid int) int {
var mode int
db.DB.Raw(`SELECT COALESCE(authmode, 1) FROM app_users WHERE userid = ?`, uid).Scan(&mode)
return mode
}
func UpdateUserFcmToken(uid int, token string) error {
query := `UPDATE app_users SET userfcmtoken = ? WHERE userid = ?`
return db.DB.Exec(query, token, uid).Error
}
// Check if device already exists for user
func IsDeviceLinked(userid int, deviceid string) bool {
var count int64
db.DB.Table("user_devices").
Where("userid = ? AND deviceid = ?", userid, deviceid).
Count(&count)
return count > 0
}
func GetStoredDeviceID(uid int) (string, error) {
var deviceID string
query := `SELECT deviceid FROM app_users WHERE userid = ? LIMIT 1`
result := db.DB.Raw(query, uid).Scan(&deviceID)
if result.Error != nil {
utils.Error("Error fetching deviceid", "error", result.Error)
return "", result.Error
}
// If nothing found
if result.RowsAffected == 0 {
return "", nil
}
return deviceID, nil
}
func CheckUserExists(contactno, email string, configid int) (bool, error) {
var count int64
err := db.DB.Table("app_users").
Where("configid = ?", configid).
Where(
db.DB.
Where("contactno = ? AND ? != ''", contactno, contactno).
Or("email = ? AND ? != ''", email, email),
).
Count(&count).Error
if err != nil {
return false, err
}
return count > 0, nil
}
func GetAllUsersv2(roleID, configID, tenantID, pageno, pagesize int, keyword string) []models.UserInfov2 {
var users []models.UserInfov2
var params []interface{}
var queryBuilder strings.Builder
offset := (pageno - 1) * pagesize
queryBuilder.WriteString(`
SELECT a.userid,a.authname,a.email,a.configid,a.roleid,a.authmode,a.contactno,a.firstname,
a.lastname,CONCAT(a.firstname, ' ', a.lastname) AS fullname,a.address,a.suburb,
a.city,a.state,a.postcode,a.userfcmtoken,a.pin,a.deviceid,a.devicetype,a.tenantid,
a.status,a.shiftid,
STRING_AGG(DISTINCT alc.applocationid::text, ',') AS applocationids_raw,
STRING_AGG(DISTINCT d.locationname, ',') AS applocationnames_raw,
CONCAT(c.starttime, ' - ', c.endtime) AS shiftname
FROM app_users a
LEFT JOIN app_locationconfig alc
ON alc.userid = a.userid
AND alc.configid = a.configid
AND alc.status = 'Active'
LEFT JOIN app_location d
ON d.applocationid = alc.applocationid
LEFT JOIN ridershifts c
ON a.shiftid = c.shiftid
WHERE 1=1
`)
if roleID != 0 {
queryBuilder.WriteString(" AND a.roleid = ?")
params = append(params, roleID)
}
if configID != 0 {
queryBuilder.WriteString(" AND a.configid = ?")
params = append(params, configID)
}
if tenantID != 0 {
queryBuilder.WriteString(" AND a.tenantid = ?")
params = append(params, tenantID)
}
if keyword != "" {
queryBuilder.WriteString(`
AND (
LOWER(a.firstname) LIKE ? OR
LOWER(a.contactno) LIKE ? OR
LOWER(a.suburb) LIKE ?
)
`)
search := "%" + strings.ToLower(keyword) + "%"
params = append(params, search, search, search)
}
queryBuilder.WriteString(`
GROUP BY a.userid, c.starttime, c.endtime
ORDER BY a.userid DESC
LIMIT ? OFFSET ?
`)
params = append(params, pagesize, offset)
// 🔹 Execute query
db.DB.Raw(queryBuilder.String(), params...).Scan(&users)
// 🔹 Convert RAW → API arrays
for i := range users {
// ✅ always initialize → [] not null
users[i].Applocationids = []int{}
users[i].Applocationnames = []string{}
// IDs
if users[i].ApplocationidsRaw != "" {
ids := strings.Split(users[i].ApplocationidsRaw, ",")
for _, id := range ids {
if v, err := strconv.Atoi(id); err == nil {
users[i].Applocationids = append(users[i].Applocationids, v)
}
}
}
// Names
if users[i].ApplocationnamesRaw != "" {
names := strings.Split(users[i].ApplocationnamesRaw, ",")
for _, name := range names {
users[i].Applocationnames = append(
users[i].Applocationnames,
strings.TrimSpace(name),
)
}
}
}
return users
}

727
domain/utilsDomain.go Normal file
View File

@@ -0,0 +1,727 @@
package domain
import (
"context"
"errors"
"nearle/db"
"nearle/models"
"nearle/utils"
"net/http"
"strconv"
firebase "firebase.google.com/go"
"firebase.google.com/go/messaging"
"google.golang.org/api/option"
"gorm.io/gorm"
)
var (
firebaseApp *firebase.App
fcmClient *messaging.Client
)
func getFCMClient() (*messaging.Client, error) {
if fcmClient != nil {
return fcmClient, nil
}
opt := option.WithCredentialsFile("nearle-gear-firebase-adminsdk-l9oha-23ca3b3609.json")
app, err := firebase.NewApp(context.Background(), nil, opt)
if err != nil {
return nil, errors.New("error initializing firebase app: " + err.Error())
}
firebaseApp = app
client, err := app.Messaging(context.Background())
if err != nil {
return nil, errors.New("error getting messaging client: " + err.Error())
}
fcmClient = client
return fcmClient, nil
}
func GetApplocations(aid int) []models.Applocations {
var data []models.Applocations
var q1 string
if aid != 0 {
q1 = "Select * from app_location where status='Active' and applocationid=?"
db.DB.Raw(q1, aid).Find(&data)
} else {
q1 = "Select * from app_location where status='Active'"
db.DB.Raw(q1).Find(&data)
}
utils.Logger.Debugf("Query executed for aid: %d", aid)
return data
}
func GetApplocationsv2(userid int) []models.Applocations {
var data []models.Applocations
var q1 string
if userid != 0 {
q1 = `
SELECT b.*
FROM app_locationconfig a
INNER JOIN app_location b
ON a.applocationid = b.applocationid
WHERE b.status = 'Active'
AND a.userid = ?`
db.DB.Raw(q1, userid).Find(&data)
} else {
q1 = `
SELECT *
FROM app_location
WHERE status = 'Active'
`
db.DB.Raw(q1).Find(&data)
}
utils.Logger.Debugf("Query executed for userid: %d", userid)
return data
}
func GetApplocationConfig(aid int) models.Applocations {
var data models.Applocations
var q1, q2 string
if aid != 0 {
q1 = `Select * from app_location where status='Active' and applocationid=` + strconv.Itoa(aid)
q2 = `SELECT distinct a.userid,a.userfcmtoken,b.notify,b.applocationid,c.opentime,c.closetime
FROM app_users a
INNER JOIN app_locationconfig b ON a.userid=b.userid
INNER JOiN app_location c on a.applocationid= c.applocationid
WHERE b.notify='true' AND b.applocationid=` + strconv.Itoa(aid)
} else {
q1 = `Select * from app_location where status='Active'`
}
// print(q1)
// db.DB.Raw(q1).Preload("Applocationadmins").Find(&data)
db.DB.Raw(q1).Preload("Applocationadmins", func(db *gorm.DB) *gorm.DB {
return db.Raw(q2)
}).Find(&data)
return data
}
func GetAppPricing(aid, cid, pid int) []models.Apppricing {
var data []models.Apppricing
var q1 string
if aid != 0 {
q1 = `SELECT a.* FROM app_pricing a
JOIN (
SELECT pricingtypeid, MAX(pricingdate) AS maxpricingdate
FROM app_pricing
WHERE applocationid = ?
GROUP BY pricingtypeid
) AS maxpricing ON a.pricingtypeid = maxpricing.pricingtypeid AND a.pricingdate = maxpricing.maxpricingdate WHERE a.applocationid = ?`
db.DB.Raw(q1, aid, aid).Find(&data)
} else if cid != 0 {
q1 = `SELECT * FROM app_pricing WHERE pricingdate = (SELECT MAX(pricingdate) FROM app_pricing where configid= ?)`
db.DB.Raw(q1, cid).Find(&data)
}
// print(q1)
db.DB.Raw(q1).Find(&data)
return data
}
func CreateAppProcing(input models.Apppricing) bool {
err := db.DB.Table("app_pricing").Create(&input).Error
return err == nil
}
func GetAllAppPricing(aid int) []models.Apppricing {
var data []models.Apppricing
var q1 string
if aid != 0 {
q1 = `SELECT a.*,b.locationname as applocation, d.appname FROM app_pricing a
inner join app_location b on a.applocationid=b.applocationid
Inner Join app_types c on a.pricingtypeid=c.apptypeid
INNER JOIN app_config d ON a.configid=d.configid
where a.applocationid=? ORDER BY b.locationname ASC`
db.DB.Raw(q1, aid).Find(&data)
} else {
q1 = `SELECT a.*,b.locationname as applocation, d.appname FROM app_pricing a
inner join app_location b on a.applocationid=b.applocationid
Inner Join app_types c on a.pricingtypeid=c.apptypeid
INNER JOIN app_config d ON a.configid=d.configid ORDER BY b.locationname ASC`
db.DB.Raw(q1).Find(&data)
}
utils.Logger.Debugf("Query executed for aid: %d", aid)
return data
}
func GetApplocationadmins(aid int) []models.Applocationadmins {
var data []models.Applocationadmins
var q1 string
if aid != 0 {
q1 = `SELECT distinct a.userid,a.userfcmtoken,b.notify,b.applocationid,c.opentime,c.closetime
FROM app_users a
INNER JOIN app_locationconfig b ON a.userid=b.userid
INNER JOiN app_location c on a.applocationid= c.applocationid
WHERE b.notify='true' AND b.applocationid=?`
db.DB.Raw(q1, aid).Find(&data)
}
return data
}
func GetAppconfig(cid int) models.Appconfig {
var data models.Appconfig
var q1 string
if cid != 0 {
q1 = `SELECT a.configid,a.Appname,a.paymentdevkey,a.paymentlivekey,a.fcmkey,a.googleapikey,a.applocationradius,
b.providerid,b.providerapi,b.providerkey
FROM app_config a
LEFT JOIN smsproviders b ON a.smsproviderid=b.providerid
WHERE a.configid=?`
db.DB.Raw(q1, cid).Find(&data)
} else {
q1 = `SELECT a.configid,a.Appname,a.paymentdevkey,a.paymentlivekey,a.fcmkey,a.googleapikey,a.applocationradius,
b.providerid,b.providerapi,b.providerkey FROM app_config a
LEFT JOIN smsproviders b ON a.smsproviderid=b.providerid order by configid asc`
db.DB.Raw(q1).Find(&data)
}
utils.Logger.Debugf("Query executed for cid: %d", cid)
return data
}
func GetAllAppconfig() []models.Appconfig {
var data []models.Appconfig
q1 := `SELECT a.configid,a.Appname,a.paymentdevkey,a.paymentlivekey,a.fcmkey,a.googleapikey,a.applocationradius,
b.providerid,b.providerapi,b.providerkey FROM app_config a
LEFT JOIN smsproviders b ON a.smsproviderid=b.providerid order by configid asc`
db.DB.Raw(q1).Find(&data)
return data
}
func GetAppModule() []models.AppModule {
var data []models.AppModule
q1 := `SELECT * FROM app_module where status='Active'`
db.DB.Raw(q1).Find(&data)
return data
}
func GetApptypes(tag string) []models.Apptypes {
var data []models.Apptypes
q1 := "Select * from app_types where status ='Active' and tag=?"
db.DB.Raw(q1, tag).Find(&data)
return data
}
func GetSubcategories(moduleid int, categoryid int) []models.Appsubcategories {
var data []models.Appsubcategories
query := `
SELECT a.subcategoryid,a.categoryid,a.subcategoryname,b.categoryname,a.status,c.moduleid
FROM app_subcategory a
INNER JOIN app_category b ON a.categoryid = b.categoryid
INNER JOIN app_module c ON a.categoryid = c.categoryid
WHERE 1=1`
var params []interface{}
if moduleid != 0 {
query += " AND c.moduleid = ?"
params = append(params, moduleid)
}
if categoryid != 0 {
query += " AND a.categoryid = ?"
params = append(params, categoryid)
}
db.DB.Raw(query, params...).Scan(&data)
return data
}
func GetCategories(mid int) []models.AppCategory {
var data []models.AppCategory
if mid == 0 {
// No moduleid filter → return all categories
q := `
SELECT a.*, b.moduleid
FROM app_category a
INNER JOIN app_module b ON a.categoryid = b.categoryid
`
db.DB.Raw(q).Scan(&data)
} else {
// Filter by moduleid
q := `
SELECT a.*, b.moduleid
FROM app_category a
INNER JOIN app_module b ON a.categoryid = b.categoryid
WHERE b.moduleid = ?
`
db.DB.Raw(q, mid).Scan(&data)
}
return data
}
func Insertnotification(input models.Data) bool {
db.DB.Table("tenantnotifications").Create(&input)
return true
}
func SendLoginNotification(regid, accessid string, pin int) error {
if regid == "" {
return errors.New("no FCM token provided")
}
client, err := getFCMClient()
if err != nil {
return err
}
// Construct the notification payload
body := "Your passcode to Nearle app is: " + strconv.Itoa(pin) + "."
title := "Nearle Code"
// Prepare FCM message
message := &messaging.Message{
Notification: &messaging.Notification{
Title: title,
Body: body,
},
Token: regid,
Android: &messaging.AndroidConfig{
Priority: "high",
Notification: &messaging.AndroidNotification{
Sound: "ring",
},
},
}
// Send the FCM notification
response, err := client.Send(context.Background(), message)
if err != nil {
utils.Logger.Errorf("FCM send error: %v", err)
return errors.New("failed to send FCM: " + err.Error())
}
utils.Logger.Infof("Successfully sent message: %v", response)
return nil
}
func SendSingleNotification(regid, accessid string, Partner string) bool {
client, err := getFCMClient()
if err != nil {
utils.Logger.Errorf("getFCMClient error: %v", err)
return false
}
title := "Nearle Admin"
body := "Orders had been placed for delivery by " + Partner
message := &messaging.Message{
Notification: &messaging.Notification{
Title: title,
Body: body,
},
Token: regid,
Android: &messaging.AndroidConfig{
Priority: "high",
Notification: &messaging.AndroidNotification{
Sound: "ring",
},
},
}
response, err := client.Send(context.Background(), message)
if err != nil {
utils.Logger.Errorf("Error sending single notification: %v", err)
return false
}
utils.Logger.Infof("Successfully sent single message: %v", response)
return true
}
func NotifyUser(fcm models.NotifyUser) bool {
client, err := getFCMClient()
if err != nil {
utils.Logger.Errorf("getFCMClient error: %v", err)
return false
}
message := &messaging.Message{
Notification: &messaging.Notification{
Title: fcm.Notification.Notify.Title,
Body: fcm.Notification.Notify.Body,
},
Token: fcm.Notification.To,
Android: &messaging.AndroidConfig{
Priority: fcm.Notification.Priority,
Notification: &messaging.AndroidNotification{
Sound: fcm.Notification.Notify.Sound,
},
},
}
response, err := client.Send(context.Background(), message)
if err != nil {
utils.Logger.Errorf("Error notifying user: %v", err)
return false
}
utils.Logger.Infof("Successfully notified user: %v", response)
return true
}
func SendNotifications(fcm models.Notifications) bool {
client, err := getFCMClient()
if err != nil {
utils.Logger.Errorf("getFCMClient error: %v", err)
return false
}
successCount := 0
for _, token := range fcm.Registrationids {
if token == "" {
continue
}
message := &messaging.Message{
Notification: &messaging.Notification{
Title: fcm.Notify.Title,
Body: fcm.Notify.Body,
},
Token: token,
Android: &messaging.AndroidConfig{
Priority: fcm.Priority,
Notification: &messaging.AndroidNotification{
Sound: fcm.Notify.Sound,
},
},
}
_, err := client.Send(context.Background(), message)
if err != nil {
utils.Logger.Errorf("Error sending notification to token %s: %v", token, err)
continue
}
successCount++
}
utils.Logger.Infof("Successfully sent %d notifications out of %d", successCount, len(fcm.Registrationids))
return successCount > 0
}
func SendNotification(fcm models.Notifications, accessid string) models.Result {
var result models.Result
client, err := getFCMClient()
if err != nil {
utils.Logger.Errorf("getFCMClient error: %v", err)
result.Code = http.StatusInternalServerError
result.Message = "Error initializing FCM client"
result.Status = false
return result
}
// Assuming we send to the first registration ID if multiple provided
if len(fcm.Registrationids) == 0 {
result.Code = http.StatusBadRequest
result.Message = "No registration IDs provided"
result.Status = false
return result
}
message := &messaging.Message{
Notification: &messaging.Notification{
Title: fcm.Notify.Title,
Body: fcm.Notify.Body,
},
Token: fcm.Registrationids[0],
Android: &messaging.AndroidConfig{
Priority: fcm.Priority,
Notification: &messaging.AndroidNotification{
Sound: fcm.Notify.Sound,
},
},
}
response, err := client.Send(context.Background(), message)
if err != nil {
utils.Logger.Errorf("Error sending single notification: %v", err)
result.Code = http.StatusInternalServerError
result.Message = "Error sending notification: " + err.Error()
result.Status = false
return result
}
utils.Logger.Infof("Successfully sent notification: %v", response)
status := Insertnotification(fcm.Data)
if !status {
result.Code = http.StatusConflict
result.Message = "Notification sent but Insert UnSuccessfully"
result.Status = false
return result
}
result.Code = http.StatusCreated
result.Message = "Notification Sent and Inserted Successfully"
result.Status = true
return result
}
func Getconfigs(categoryid int) models.Appconfig {
var q1 string
var data models.Appconfig
q1 = `SELECT a.configid,a.appname,a.smsproviderid,COALESCE(a.fcmkey,'') AS fcmkey,COALESCE(a.clientid,'') AS clientid,COALESCE(a.googleapikey,'') AS googleapikey,COALESCE(a.paymentdevkey,'') AS paymentdevkey,COALESCE(a.paymentlivekey,'') AS paymentlivekey,a.applocationradius,COALESCE(b.providername,'') AS providername,COALESCE(b.providerapi,'') AS providerapi,COALESCE(b.providerkey,'') AS providerkey, COALESCE(b.username,'') AS username,COALESCE(b.passcode,'') AS passcode,COALESCE(b.defaultprovider,false) AS defaultprovider
FROM app_config a LEFT OUTER JOIN smsproviders b ON a.smsproviderid = b.providerid AND b.status='Active' WHERE a.configid=?`
db.DB.Raw(q1, categoryid).Find(&data)
return data
}
func UpdateSeqno(tid int, prefix string) error {
var field string
if prefix == "ORD" {
field = "orderseqno"
} else if prefix == "INV" {
field = "invoiceseqno"
} else {
return errors.New("invalid prefix: " + prefix)
}
result := db.DB.
Table("ordersequences").
Where("tenantid = ?", tid).
Update(field, gorm.Expr(field+" + 1"))
if result.Error != nil {
utils.Logger.Errorf("UpdateSeqno failed for tenantid %d, prefix %s: %v", tid, prefix, result.Error)
return result.Error
}
if result.RowsAffected == 0 {
utils.Logger.Infof("No rows updated for tenantid %d with prefix %s", tid, prefix)
return errors.New("no rows updated for tenantid " + strconv.Itoa(tid))
}
return nil
}
func GetSequenceno(tid int, prefix string) string {
type SeqResult struct {
Orderseqno string
}
var q1 string
if prefix == "ORD" {
q1 = `
SELECT COALESCE(CONCAT(tenantid, '-', subprefix, COALESCE(MAX(orderseqno) + 1, 1)), '') AS orderseqno
FROM ordersequences
WHERE tenantid = ?
GROUP BY tenantid, subprefix
`
} else if prefix == "INV" {
q1 = `
SELECT COALESCE(CONCAT(tenantid, '-', subprefix, COALESCE(MAX(invoiceseqno) + 1, 1)), '') AS orderseqno
FROM ordersequences
WHERE tenantid = ?
GROUP BY tenantid, subprefix
`
}
var result SeqResult
db.DB.Raw(q1, tid).Scan(&result)
return result.Orderseqno
}
func GetTenantNotifications(tenantid, locationid, customerid, moduleid, pageno, pagesize int) ([]models.TenantNotification, int) {
var data []models.TenantNotification
var total int
offset := (pageno - 1) * pagesize
baseQuery := db.DB.Table("tenantnotifications").
Select("*").
Where("tenantid = ?", tenantid)
if locationid != 0 {
baseQuery = baseQuery.Where("locationid = ?", locationid)
}
if customerid != 0 {
baseQuery = baseQuery.Where("customerid = ?", customerid)
}
if moduleid != 0 {
baseQuery = baseQuery.Where("moduleid = ?", moduleid)
}
err := baseQuery.
Order("notificationdate DESC").
Limit(pagesize).
Offset(offset).
Find(&data).Error
if err != nil {
utils.Logger.Errorf("DB Error GetTenantNotifications: %v", err)
}
return data, total
}
func GetUserBonusSummary(userid int) (models.Riderinfo, error) {
var user models.Riderinfo
query := `
SELECT COALESCE(SUM(a.bonuspts), 0) AS bonuspts,b.*
FROM deliveries a
LEFT JOIN app_users b ON a.userid = b.userid
WHERE a.userid = ?
GROUP BY b.userid
`
err := db.DB.Raw(query, userid).Scan(&user).Error
if err != nil {
return user, err
}
return user, nil
}
func CreateAppLocationConfig(input models.AppLocationConfigRequest) bool {
if input.Notify == "" {
input.Notify = "true"
}
if input.Status == "" {
input.Status = "Active"
}
for _, locID := range input.Applocationids {
data := models.AppLocationConfig{
Applocationid: locID,
Configid: input.Configid,
Userid: input.Userid,
Partnerid: input.Partnerid,
Notify: input.Notify,
Status: input.Status,
}
if err := db.DB.Table("app_locationconfig").Create(&data).Error; err != nil {
return false
}
}
return true
}
func UpdateAppLocationConfig(input models.AppLocationConfigRequest) bool {
if input.Status == "" {
input.Status = "Active"
}
for _, locID := range input.Applocationids {
if err := db.DB.Table("app_locationconfig").
Where("userid = ? AND applocationid = ?", input.Userid, locID).
Update("status", input.Status).Error; err != nil {
utils.Logger.Errorf("Error updating app_locationconfig: %v", err)
return false
}
}
return true
}
func GetUserRoles() ([]models.UserRoles, error) {
var roles []models.UserRoles
query := `SELECT * FROM app_roles
`
err := db.DB.Raw(query).Scan(&roles).Error
if err != nil {
return roles, err
}
return roles, nil
}

142
go.mod Normal file
View File

@@ -0,0 +1,142 @@
module nearle
go 1.24.0
require (
firebase.google.com/go v3.13.0+incompatible
github.com/apache/arrow/go/v14 v14.0.2
github.com/aws/aws-sdk-go-v2 v1.41.1
github.com/aws/aws-sdk-go-v2/config v1.32.7
github.com/aws/aws-sdk-go-v2/credentials v1.19.7
github.com/aws/aws-sdk-go-v2/service/s3 v1.95.1
github.com/joho/godotenv v1.5.1
github.com/redis/go-redis/v9 v9.16.0
go.uber.org/zap v1.27.1
golang.org/x/oauth2 v0.34.0
google.golang.org/api v0.260.0
gorm.io/gorm v1.31.1
)
require (
cel.dev/expr v0.24.0 // indirect
cloud.google.com/go v0.121.6 // indirect
cloud.google.com/go/auth v0.18.0 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
cloud.google.com/go/compute/metadata v0.9.0 // indirect
cloud.google.com/go/firestore v1.20.0 // indirect
cloud.google.com/go/iam v1.5.3 // indirect
cloud.google.com/go/longrunning v0.7.0 // indirect
cloud.google.com/go/monitoring v1.24.3 // indirect
cloud.google.com/go/storage v1.56.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 // indirect
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c // indirect
github.com/andybalholm/brotli v1.2.0 // indirect
github.com/apache/thrift v0.22.0 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17 // indirect
github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 // indirect
github.com/aws/smithy-go v1.24.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/envoyproxy/go-control-plane/envoy v1.35.0 // indirect
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-jose/go-jose/v4 v4.1.3 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-sql-driver/mysql v1.7.1 // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v1.0.0 // indirect
github.com/google/flatbuffers v25.9.23+incompatible // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.9 // indirect
github.com/googleapis/gax-go/v2 v2.16.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.6.0 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/klauspost/asmfmt v1.3.2 // indirect
github.com/klauspost/compress v1.18.2 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 // indirect
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pierrec/lz4/v4 v4.1.22 // indirect
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/sagikazarmark/locafero v0.3.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.10.0 // indirect
github.com/spf13/cast v1.5.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spiffe/go-spiffe/v2 v2.6.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.51.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
github.com/zeebo/xxh3 v1.0.2 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/contrib/detectors/gcp v1.38.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
go.opentelemetry.io/otel v1.38.0 // indirect
go.opentelemetry.io/otel/metric v1.38.0 // indirect
go.opentelemetry.io/otel/sdk v1.38.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect
go.opentelemetry.io/otel/trace v1.38.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.46.0 // indirect
golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 // indirect
golang.org/x/mod v0.31.0 // indirect
golang.org/x/net v0.48.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/telemetry v0.0.0-20251208220230-2638a1023523 // indirect
golang.org/x/time v0.14.0 // indirect
golang.org/x/tools v0.40.0 // indirect
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20251202230838-ff82c1b0f217 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b // indirect
google.golang.org/grpc v1.78.0 // indirect
google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gorm.io/driver/postgres v1.6.0 // indirect
)
require (
github.com/gofiber/fiber/v2 v2.52.10
github.com/jinzhu/copier v0.4.0
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/spf13/viper v1.17.0
golang.org/x/sys v0.39.0 // indirect
golang.org/x/text v0.32.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gorm.io/driver/mysql v1.5.2
)

772
go.sum Normal file
View File

@@ -0,0 +1,772 @@
cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY=
cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
cloud.google.com/go v0.121.6 h1:waZiuajrI28iAf40cWgycWNgaXPO06dupuS+sgibK6c=
cloud.google.com/go v0.121.6/go.mod h1:coChdst4Ea5vUpiALcYKXEpR1S9ZgXbhEzzMcMR66vI=
cloud.google.com/go/auth v0.18.0 h1:wnqy5hrv7p3k7cShwAU/Br3nzod7fxoqG+k0VZ+/Pk0=
cloud.google.com/go/auth v0.18.0/go.mod h1:wwkPM1AgE1f2u6dG443MiWoD8C3BtOywNsUMcUTVDRo=
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs=
cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/firestore v1.20.0 h1:JLlT12QP0fM2SJirKVyu2spBCO8leElaW0OOtPm6HEo=
cloud.google.com/go/firestore v1.20.0/go.mod h1:jqu4yKdBmDN5srneWzx3HlKrHFWFdlkgjgQ6BKIOFQo=
cloud.google.com/go/iam v1.5.3 h1:+vMINPiDF2ognBJ97ABAYYwRgsaqxPbQDlMnbHMjolc=
cloud.google.com/go/iam v1.5.3/go.mod h1:MR3v9oLkZCTlaqljW6Eb2d3HGDGK5/bDv93jhfISFvU=
cloud.google.com/go/logging v1.13.1 h1:O7LvmO0kGLaHY/gq8cV7T0dyp6zJhYAOtZPX4TF3QtY=
cloud.google.com/go/logging v1.13.1/go.mod h1:XAQkfkMBxQRjQek96WLPNze7vsOmay9H5PqfsNYDqvw=
cloud.google.com/go/longrunning v0.7.0 h1:FV0+SYF1RIj59gyoWDRi45GiYUMM3K1qO51qoboQT1E=
cloud.google.com/go/longrunning v0.7.0/go.mod h1:ySn2yXmjbK9Ba0zsQqunhDkYi0+9rlXIwnoAf+h+TPY=
cloud.google.com/go/monitoring v1.24.3 h1:dde+gMNc0UhPZD1Azu6at2e79bfdztVDS5lvhOdsgaE=
cloud.google.com/go/monitoring v1.24.3/go.mod h1:nYP6W0tm3N9H/bOw8am7t62YTzZY+zUeQ+Bi6+2eonI=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
cloud.google.com/go/storage v1.56.0 h1:iixmq2Fse2tqxMbWhLWC9HfBj1qdxqAmiK8/eqtsLxI=
cloud.google.com/go/storage v1.56.0/go.mod h1:Tpuj6t4NweCLzlNbw9Z9iwxEkrSem20AetIeH/shgVU=
cloud.google.com/go/trace v1.11.7 h1:kDNDX8JkaAG3R2nq1lIdkb7FCSi1rCmsEtKVsty7p+U=
cloud.google.com/go/trace v1.11.7/go.mod h1:TNn9d5V3fQVf6s4SCveVMIBS2LJUqo73GACmq/Tky0s=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
firebase.google.com/go v3.13.0+incompatible h1:3TdYC3DDi6aHn20qoRkxwGqNgdjtblwVAyRLQwGn/+4=
firebase.google.com/go v3.13.0+incompatible/go.mod h1:xlah6XbEyW6tbfSklcfe5FHJIwjt8toICdV5Wh9ptHs=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 h1:sBEjpZlNHzK1voKq9695PJSX2o5NEXl7/OL3coiIY0c=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 h1:owcC2UnmsZycprQ5RfRgjydWhuoxg71LUfyiQdijZuM=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0/go.mod h1:ZPpqegjbE99EPKsu3iUWV22A04wzGPcAY/ziSIQEEgs=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.53.0 h1:4LP6hvB4I5ouTbGgWtixJhgED6xdf67twf9PoY96Tbg=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.53.0/go.mod h1:jUZ5LYlw40WMd07qxcQJD5M40aUxrfwqQX1g7zxYnrQ=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 h1:Ron4zCA/yk6U7WOBXhTJcDpsUBG9npumK6xw2auFltQ=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0/go.mod h1:cSgYe11MCNYunTnRXrKiR/tHc0eoKjICUuWpNZoVCOo=
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c h1:RGWPOewvKIROun94nF7v2cua9qP+thov/7M50KEoeSU=
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk=
github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
github.com/apache/arrow/go/v14 v14.0.2 h1:N8OkaJEOfI3mEZt07BIkvo4sC6XDbL+48MBPWO5IONw=
github.com/apache/arrow/go/v14 v14.0.2/go.mod h1:u3fgh3EdgN/YQ8cVQRguVW3R+seMybFg8QBQ5LU+eBY=
github.com/apache/thrift v0.22.0 h1:r7mTJdj51TMDe6RtcmNdQxgn9XcyfGDOzegMDRg47uc=
github.com/apache/thrift v0.22.0/go.mod h1:1e7J/O1Ae6ZQMTYdy9xa3w9k+XHWPfRvdPyJeynQ+/g=
github.com/aws/aws-sdk-go-v2 v1.41.1 h1:ABlyEARCDLN034NhxlRUSZr4l71mh+T5KAeGh6cerhU=
github.com/aws/aws-sdk-go-v2 v1.41.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4=
github.com/aws/aws-sdk-go-v2/config v1.32.7 h1:vxUyWGUwmkQ2g19n7JY/9YL8MfAIl7bTesIUykECXmY=
github.com/aws/aws-sdk-go-v2/config v1.32.7/go.mod h1:2/Qm5vKUU/r7Y+zUk/Ptt2MDAEKAfUtKc1+3U1Mo3oY=
github.com/aws/aws-sdk-go-v2/credentials v1.19.7 h1:tHK47VqqtJxOymRrNtUXN5SP/zUTvZKeLx4tH6PGQc8=
github.com/aws/aws-sdk-go-v2/credentials v1.19.7/go.mod h1:qOZk8sPDrxhf+4Wf4oT2urYJrYt3RejHSzgAquYeppw=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 h1:I0GyV8wiYrP8XpA70g1HBcQO1JlQxCMTW9npl5UbDHY=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17/go.mod h1:tyw7BOl5bBe/oqvoIeECFJjMdzXoa/dfVz3QQ5lgHGA=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 h1:xOLELNKGp2vsiteLsvLPwxC+mYmO6OZ8PYgiuPJzF8U=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17/go.mod h1:5M5CI3D12dNOtH3/mk6minaRwI2/37ifCURZISxA/IQ=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 h1:WWLqlh79iO48yLkj1v3ISRNiv+3KdQoZ6JWyfcsyQik=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17/go.mod h1:EhG22vHRrvF8oXSTYStZhJc1aUgKtnJe+aOiFEV90cM=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17 h1:JqcdRG//czea7Ppjb+g/n4o8i/R50aTBHkA7vu0lK+k=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17/go.mod h1:CO+WeGmIdj/MlPel2KwID9Gt7CNq4M65HUfBW97liM0=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8 h1:Z5EiPIzXKewUQK0QTMkutjiaPVeVYXX7KIqhXu/0fXs=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8/go.mod h1:FsTpJtvC4U1fyDXk7c71XoDv3HlRm8V3NiYLeYLh5YE=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 h1:RuNSMoozM8oXlgLG/n6WLaFGoea7/CddrCfIiSA+xdY=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17/go.mod h1:F2xxQ9TZz5gDWsclCtPQscGpP0VUOc8RqgFM3vDENmU=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17 h1:bGeHBsGZx0Dvu/eJC0Lh9adJa3M1xREcndxLNZlve2U=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17/go.mod h1:dcW24lbU0CzHusTE8LLHhRLI42ejmINN8Lcr22bwh/g=
github.com/aws/aws-sdk-go-v2/service/s3 v1.95.1 h1:C2dUPSnEpy4voWFIq3JNd8gN0Y5vYGDo44eUE58a/p8=
github.com/aws/aws-sdk-go-v2/service/s3 v1.95.1/go.mod h1:5jggDlZ2CLQhwJBiZJb4vfk4f0GxWdEDruWKEJ1xOdo=
github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 h1:VrhDvQib/i0lxvr3zqlUwLwJP4fpmpyD9wYG1vfSu+Y=
github.com/aws/aws-sdk-go-v2/service/signin v1.0.5/go.mod h1:k029+U8SY30/3/ras4G/Fnv/b88N4mAfliNn08Dem4M=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 h1:v6EiMvhEYBoHABfbGB4alOYmCIrcgyPPiBE1wZAEbqk=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.9/go.mod h1:yifAsgBxgJWn3ggx70A3urX2AN49Y5sJTD1UQFlfqBw=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13 h1:gd84Omyu9JLriJVCbGApcLzVR3XtmC4ZDPcAI6Ftvds=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13/go.mod h1:sTGThjphYE4Ohw8vJiRStAcu3rbjtXRsdNB0TvZ5wwo=
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 h1:5fFjR/ToSOzB2OQ/XqWpZBmNvmP/pJ1jOWYlFDJTjRQ=
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6/go.mod h1:qgFDZQSD/Kys7nJnVqYlWKnh0SSdMjAi0uSwON4wgYQ=
github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk=
github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f h1:Y8xYupdHxryycyPlc9Y+bSQAYZnetRJ70VMVKm5CKI0=
github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f/go.mod h1:HlzOvOjVBOfTGSRXRyY0OiCS/3J1akRGQQpRO/7zyF4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.13.5-0.20251024222203-75eaa193e329 h1:K+fnvUM0VZ7ZFJf0n4L/BRlnsb9pL/GuDG6FqaH+PwM=
github.com/envoyproxy/go-control-plane v0.13.5-0.20251024222203-75eaa193e329/go.mod h1:Alz8LEClvR7xKsrq3qzoc4N0guvVNSS8KmSChGYr9hs=
github.com/envoyproxy/go-control-plane/envoy v1.35.0 h1:ixjkELDE+ru6idPxcHLj8LBVc2bFP7iBytj353BoHUo=
github.com/envoyproxy/go-control-plane/envoy v1.35.0/go.mod h1:09qwbGVuSWWAyN5t/b3iyVfz5+z8QWGrzkoqm/8SbEs=
github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI=
github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8=
github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs=
github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/gofiber/fiber/v2 v2.52.10 h1:jRHROi2BuNti6NYXmZ6gbNSfT3zj/8c0xy94GOU5elY=
github.com/gofiber/fiber/v2 v2.52.10/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/flatbuffers v25.9.23+incompatible h1:rGZKv+wOb6QPzIdkM2KxhBZCDrA0DeN6DNmRDrqIsQU=
github.com/google/flatbuffers v25.9.23+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc=
github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.3.9 h1:TOpi/QG8iDcZlkQlGlFUti/ZtyLkliXvHDcyUIMuFrU=
github.com/googleapis/enterprise-certificate-proxy v0.3.9/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gax-go/v2 v2.16.0 h1:iHbQmKLLZrexmb0OSsNGTeSTS0HO4YvFOG8g5E4Zd0Y=
github.com/googleapis/gax-go/v2 v2.16.0/go.mod h1:o1vfQjjNZn4+dPnRdl/4ZD7S9414Y4xA+a/6Icj6l14=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY=
github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/asmfmt v1.3.2 h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4=
github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE=
github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk=
github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs=
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY=
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI=
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/redis/go-redis/v9 v9.16.0 h1:OotgqgLSRCmzfqChbQyG1PHC3tLNR89DG4jdOERSEP4=
github.com/redis/go-redis/v9 v9.16.0/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9cJvm4SvQ=
github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spf13/afero v1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY=
github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.17.0 h1:I5txKw7MJasPL/BrfkbA0Jyo/oELqVmux4pR/UxOMfI=
github.com/spf13/viper v1.17.0/go.mod h1:BmMMMLQXSbcHK6KAOiFLz0l5JHrU89OdIRHvsk0+yVI=
github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo=
github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/contrib/detectors/gcp v1.38.0 h1:ZoYbqX7OaA/TAikspPl3ozPI6iY6LiIY9I8cUfm+pJs=
go.opentelemetry.io/contrib/detectors/gcp v1.38.0/go.mod h1:SU+iU7nu5ud4oCb3LQOhIZ3nRLj6FNVrKgtflbaf2ts=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 h1:rixTyDGXFxRy1xzhKrotaHy3/KXdPhlWARrCgK+eqUY=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0/go.mod h1:dowW6UsM9MKbJq5JTz2AMVp3/5iW5I/TStsk8S+CfHw=
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 h1:MDfG8Cvcqlt9XXrmEiD4epKn7VJHZO84hejP9Jmp0MM=
golang.org/x/exp v0.0.0-20251209150349-8475f28825e9/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI=
golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/telemetry v0.0.0-20251208220230-2638a1023523 h1:H52Mhyrc44wBgLTGzq6+0cmuVuF3LURCSXsLMOqfFos=
golang.org/x/telemetry v0.0.0-20251208220230-2638a1023523/go.mod h1:ArQvPJS723nJQietgilmZA+shuB3CZxH1n2iXq9VSfs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA=
golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY=
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
google.golang.org/api v0.260.0 h1:XbNi5E6bOVEj/uLXQRlt6TKuEzMD7zvW/6tNwltE4P4=
google.golang.org/api v0.260.0/go.mod h1:Shj1j0Phr/9sloYrKomICzdYgsSDImpTxME8rGLaZ/o=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20251202230838-ff82c1b0f217 h1:GvESR9BIyHUahIb0NcTum6itIWtdoglGX+rnGxm2934=
google.golang.org/genproto v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:yJ2HH4EHEDTd3JiLmhds6NkJ17ITVYOdV3m3VKOnws0=
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 h1:fCvbg86sFXwdrl5LgVcTEvNC+2txB5mgROGmRL5mrls=
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b h1:Mv8VFug0MP9e5vUxfBcE3vUkV6CImK3cMNMIDFjmzxU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.5.2 h1:QC2HRskSE75wBuOxe0+iCkyJZ+RqpudsQtqkp+IMuXs=
gorm.io/driver/mysql v1.5.2/go.mod h1:pQLhh1Ut/WUAySdTHwBpBv6+JKcj+ua4ZFx1QQTBzb8=
gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4=
gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo=
gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls=
gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s=
gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg=
gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

View File

@@ -0,0 +1,156 @@
package backup
import (
"database/sql"
"os"
"time"
"github.com/apache/arrow/go/v14/arrow"
"github.com/apache/arrow/go/v14/arrow/array"
"github.com/apache/arrow/go/v14/arrow/memory"
"github.com/apache/arrow/go/v14/parquet"
"github.com/apache/arrow/go/v14/parquet/compress"
"github.com/apache/arrow/go/v14/parquet/pqarrow"
)
func BackupDeliveryLogs(sqlDB *sql.DB) (string, error) {
rows, err := sqlDB.Query(`
SELECT
logid, logdate, deliveryid, orderheaderid,
tenantid, locationid, userid, partnerid,
orderid, orderstatus, latitude, longitude,
logstatus, created, updated, firstname, lastname
FROM deliverylogs
WHERE logdate >= NOW() - INTERVAL '3 months'
`)
if err != nil {
return "", err
}
defer rows.Close()
// Arrow schema (exact match with MySQL table)
schema := arrow.NewSchema([]arrow.Field{
{Name: "logid", Type: arrow.PrimitiveTypes.Int32},
{Name: "logdate", Type: arrow.FixedWidthTypes.Timestamp_ms, Nullable: true},
{Name: "deliveryid", Type: arrow.PrimitiveTypes.Int32},
{Name: "orderheaderid", Type: arrow.PrimitiveTypes.Int32},
{Name: "tenantid", Type: arrow.PrimitiveTypes.Int32},
{Name: "locationid", Type: arrow.PrimitiveTypes.Int32},
{Name: "userid", Type: arrow.PrimitiveTypes.Int32},
{Name: "partnerid", Type: arrow.PrimitiveTypes.Int32},
{Name: "orderid", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "orderstatus", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "latitude", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "longitude", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "logstatus", Type: arrow.PrimitiveTypes.Int32},
{Name: "created", Type: arrow.FixedWidthTypes.Timestamp_ms},
{Name: "updated", Type: arrow.FixedWidthTypes.Timestamp_ms},
{Name: "firstname", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "lastname", Type: arrow.BinaryTypes.String, Nullable: true},
}, nil)
pool := memory.NewGoAllocator()
builder := array.NewRecordBuilder(pool, schema)
defer builder.Release()
for rows.Next() {
var (
logid, deliveryid, orderheaderid int32
tenantid, locationid, userid int32
partnerid, logstatus int32
logdate, created, updated sql.NullTime
orderid, orderstatus sql.NullString
latitude, longitude sql.NullString
firstname, lastname sql.NullString
)
if err := rows.Scan(
&logid, &logdate, &deliveryid, &orderheaderid,
&tenantid, &locationid, &userid, &partnerid,
&orderid, &orderstatus, &latitude, &longitude,
&logstatus, &created, &updated, &firstname, &lastname,
); err != nil {
return "", err
}
builder.Field(0).(*array.Int32Builder).Append(logid)
if logdate.Valid {
builder.Field(1).(*array.TimestampBuilder).
Append(arrow.Timestamp(logdate.Time.UnixMilli()))
} else {
builder.Field(1).(*array.TimestampBuilder).AppendNull()
}
builder.Field(2).(*array.Int32Builder).Append(deliveryid)
builder.Field(3).(*array.Int32Builder).Append(orderheaderid)
builder.Field(4).(*array.Int32Builder).Append(tenantid)
builder.Field(5).(*array.Int32Builder).Append(locationid)
builder.Field(6).(*array.Int32Builder).Append(userid)
builder.Field(7).(*array.Int32Builder).Append(partnerid)
appendString(builder.Field(8), orderid)
appendString(builder.Field(9), orderstatus)
appendString(builder.Field(10), latitude)
appendString(builder.Field(11), longitude)
builder.Field(12).(*array.Int32Builder).Append(logstatus)
builder.Field(13).(*array.TimestampBuilder).
Append(arrow.Timestamp(created.Time.UnixMilli()))
builder.Field(14).(*array.TimestampBuilder).
Append(arrow.Timestamp(updated.Time.UnixMilli()))
appendString(builder.Field(15), firstname)
appendString(builder.Field(16), lastname)
}
record := builder.NewRecord()
defer record.Release()
_ = os.MkdirAll("backups/parquet/deliverylogs", 0755)
filePath := "backups/parquet/deliverylogs/deliverylogs_last_3_months_" +
time.Now().Format("2006_01_02") + ".parquet"
file, err := os.Create(filePath)
if err != nil {
return "", err
}
defer file.Close()
// ✅ Correct Parquet + Arrow writer props (Arrow v14)
parquetProps := parquet.NewWriterProperties(
parquet.WithCompression(compress.Codecs.Snappy),
)
writer, err := pqarrow.NewFileWriter(
schema,
file,
parquetProps,
pqarrow.ArrowWriterProperties{}, // zero-value is valid
)
if err != nil {
return "", err
}
defer writer.Close()
if err := writer.Write(record); err != nil {
return "", err
}
return filePath, nil
}
// helper for nullable strings
func appendString(b array.Builder, v sql.NullString) {
sb := b.(*array.StringBuilder)
if v.Valid {
sb.Append(v.String)
} else {
sb.AppendNull()
}
}

View File

@@ -0,0 +1,764 @@
package backup
import (
"database/sql"
"os"
"time"
"github.com/apache/arrow/go/v14/arrow"
"github.com/apache/arrow/go/v14/arrow/array"
"github.com/apache/arrow/go/v14/arrow/memory"
"github.com/apache/arrow/go/v14/parquet"
"github.com/apache/arrow/go/v14/parquet/compress"
"github.com/apache/arrow/go/v14/parquet/pqarrow"
)
func BackupDeliveries(sqlDB *sql.DB) (string, error) {
rows, err := sqlDB.Query(`
SELECT DISTINCT a.deliveryid,a.applocationid,f.locationname AS applocation,a.orderheaderid,a.configid,a.tenantid,a.partnerid,a.locationid,a.userid,a.categoryid,a.subcategoryid,a.moduleid,
a.orderid,a.deliverydate,a.orderstatus,a.assigntime,a.starttime,a.arrivaltime,a.pickuptime,a.deliverytime,a.canceltime,a.acceptedtime,
a.customerid,a.pickupcustomer,a.pickupcontactno,a.pickuplocationid,a.pickupaddress,a.pickuplocation,a.pickuplat,a.pickuplon,
a.deliverycustomerid,a.deliverycustomer,a.deliverycontactno,a.deliverylocationid,a.deliveryaddress,a.deliverylocation,
a.droplat,a.droplon,a.deliverylat,a.deliverylong,
a.riderslat,a.riderslon,a.deliveryamt,a.kms,a.actualkms,a.riderkms,a.deliverycharges,a.deliverytype,a.paymenttype,a.smsdelivery,a.quantity,a.collectionamt,a.collectedamt,a.collectionstatus,
a.notes,a.ordernotes,a.step,a.eta,a.previouskms,a.cumulativekms,a.ridertime,b.tenantname,b.primarycontact as tenantcontactno,b.tenanttoken,b.suburb as tenantsuburb,b.city as tenantcity,
b.address AS tenantaddress, CONCAT(c.firstname, ' ', c.lastname) AS ridername,c.userfcmtoken,c.contactno as ridercontact,e.locationname,e.suburb AS locationsuburb,e.contactno AS locationcontactno,e.address AS locationaddress,
h.slab, h.pricingdate, h.baseprice, h.minkm, h.priceperkm, h.maxkm, h.orders, h.othercharges, h.surgecharges
FROM deliveries a
INNER JOIN tenants b ON a.tenantid=b.tenantid
INNER JOIN app_users c ON a.userid=c.userid
INNER JOIN tenantlocations e ON a.locationid=e.locationid
INNER JOIN app_location f ON a.applocationid = f.applocationid
INNER JOIN app_locationconfig g ON f.applocationid = g.applocationid
LEFT JOIN tenantpricing h ON a.tenantid = h.tenantid
WHERE a.deliverydate >= NOW() - INTERVAL '3 months'
`)
if err != nil {
return "", err
}
defer rows.Close()
// ✅ REAL schema (no placeholders)
schema := arrow.NewSchema([]arrow.Field{
{Name: "deliveryid", Type: arrow.PrimitiveTypes.Int32},
{Name: "applocationid", Type: arrow.PrimitiveTypes.Int32, Nullable: true},
{Name: "applocation", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "orderheaderid", Type: arrow.PrimitiveTypes.Int32, Nullable: true},
{Name: "configid", Type: arrow.PrimitiveTypes.Int32, Nullable: true},
{Name: "tenantid", Type: arrow.PrimitiveTypes.Int32, Nullable: true},
{Name: "partnerid", Type: arrow.PrimitiveTypes.Int32, Nullable: true},
{Name: "locationid", Type: arrow.PrimitiveTypes.Int32, Nullable: true},
{Name: "userid", Type: arrow.PrimitiveTypes.Int32, Nullable: true},
{Name: "categoryid", Type: arrow.PrimitiveTypes.Int32, Nullable: true},
{Name: "subcategoryid", Type: arrow.PrimitiveTypes.Int32, Nullable: true},
{Name: "moduleid", Type: arrow.PrimitiveTypes.Int32, Nullable: true},
{Name: "orderid", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "deliverydate", Type: arrow.FixedWidthTypes.Timestamp_ms, Nullable: true},
{Name: "orderstatus", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "assigntime", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "starttime", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "arrivaltime", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "pickuptime", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "deliverytime", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "canceltime", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "acceptedtime", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "customerid", Type: arrow.PrimitiveTypes.Int32, Nullable: true},
{Name: "pickupcustomer", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "pickupcontactno", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "pickuplocationid", Type: arrow.PrimitiveTypes.Int32, Nullable: true},
{Name: "pickupaddress", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "pickuplocation", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "pickuplat", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "pickuplon", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "deliverycustomerid", Type: arrow.PrimitiveTypes.Int32, Nullable: true},
{Name: "deliverycustomer", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "deliverycontactno", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "deliverylocationid", Type: arrow.PrimitiveTypes.Int32, Nullable: true},
{Name: "deliveryaddress", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "deliverylocation", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "droplat", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "droplon", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "deliverylat", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "deliverylong", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "riderslat", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "riderslon", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "deliveryamt", Type: arrow.PrimitiveTypes.Float64, Nullable: true},
{Name: "kms", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "actualkms", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "riderkms", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "deliverycharges", Type: arrow.PrimitiveTypes.Float64, Nullable: true},
{Name: "deliverytype", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "paymenttype", Type: arrow.PrimitiveTypes.Int32, Nullable: true},
{Name: "smsdelivery", Type: arrow.PrimitiveTypes.Int32, Nullable: true},
{Name: "quantity", Type: arrow.PrimitiveTypes.Int32, Nullable: true},
{Name: "collectionamt", Type: arrow.PrimitiveTypes.Float64, Nullable: true},
{Name: "collectedamt", Type: arrow.PrimitiveTypes.Float64, Nullable: true},
{Name: "collectionstatus", Type: arrow.PrimitiveTypes.Int32, Nullable: true},
{Name: "notes", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "ordernotes", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "step", Type: arrow.PrimitiveTypes.Int32, Nullable: true},
{Name: "eta", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "previouskms", Type: arrow.PrimitiveTypes.Int32, Nullable: true},
{Name: "cumulativekms", Type: arrow.PrimitiveTypes.Int32, Nullable: true},
{Name: "ridertime", Type: arrow.PrimitiveTypes.Int32, Nullable: true},
{Name: "tenantname", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "tenantcontactno", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "tenanttoken", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "tenantsuburb", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "tenantcity", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "tenantaddress", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "ridername", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "userfcmtoken", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "ridercontact", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "locationname", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "locationsuburb", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "locationcontactno", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "locationaddress", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "slab", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "pricingdate", Type: arrow.FixedWidthTypes.Timestamp_ms, Nullable: true},
{Name: "baseprice", Type: arrow.PrimitiveTypes.Float64, Nullable: true},
{Name: "minkm", Type: arrow.PrimitiveTypes.Float64, Nullable: true},
{Name: "priceperkm", Type: arrow.PrimitiveTypes.Float64, Nullable: true},
{Name: "maxkm", Type: arrow.PrimitiveTypes.Float64, Nullable: true},
{Name: "orders", Type: arrow.PrimitiveTypes.Int32, Nullable: true},
{Name: "othercharges", Type: arrow.PrimitiveTypes.Float64, Nullable: true},
{Name: "surgecharges", Type: arrow.PrimitiveTypes.Float64, Nullable: true},
}, nil)
pool := memory.NewGoAllocator()
builder := array.NewRecordBuilder(pool, schema)
defer builder.Release()
for rows.Next() {
var (
deliveryid int32
orderheaderid, configid, applocationid sql.NullInt32
tenantid, locationid, partnerid, moduleid, userid sql.NullInt32
categoryid, subcategoryid sql.NullInt32
orderid, orderstatus, assigntime, starttime sql.NullString
arrivaltime, pickuptime, acceptedtime, deliverytime sql.NullString
canceltime sql.NullString
customerid, pickuplocationid sql.NullInt32
pickupcustomer, pickupaddress, pickuplocation sql.NullString
pickupcontactno, pickuplat, pickuplon sql.NullString
deliverycustomerid, deliverylocationid sql.NullInt32
deliverycustomer, deliverycontactno, deliveryaddress sql.NullString
deliverylocation, droplat, droplon sql.NullString
deliverylat, deliverylong, riderslat, riderslon sql.NullString
kms, riderkms, actualkms sql.NullString
deliverycharges, deliveryamt sql.NullFloat64
notes, deliverytype, ordernotes sql.NullString
paymenttype sql.NullInt32
smsdelivery sql.NullInt32
previouskms, cumulativekms, step, quantity sql.NullInt32
collectionamt, collectedamt sql.NullFloat64
collectionstatus sql.NullInt32
eta sql.NullString
ridertime sql.NullInt32
deliverydate sql.NullTime
applocation sql.NullString
tenantname, tenantcontactno, tenanttoken sql.NullString
tenantsuburb, tenantcity, tenantaddress sql.NullString
ridername, userfcmtoken, ridercontact sql.NullString
locationname, locationsuburb sql.NullString
locationcontactno, locationaddress sql.NullString
slab sql.NullString
pricingdate sql.NullTime
baseprice, minkm, priceperkm, maxkm sql.NullFloat64
pricingorders sql.NullInt32
othercharges, surgecharges sql.NullFloat64
)
if err := rows.Scan(
&deliveryid, &applocationid, &applocation,
&orderheaderid, &configid, &tenantid, &partnerid,
&locationid, &userid, &categoryid, &subcategoryid, &moduleid,
&orderid, &deliverydate, &orderstatus,
&assigntime, &starttime, &arrivaltime, &pickuptime,
&deliverytime, &canceltime, &acceptedtime,
&customerid, &pickupcustomer, &pickupcontactno,
&pickuplocationid, &pickupaddress, &pickuplocation,
&pickuplat, &pickuplon,
&deliverycustomerid, &deliverycustomer, &deliverycontactno,
&deliverylocationid, &deliveryaddress, &deliverylocation,
&droplat, &droplon, &deliverylat, &deliverylong,
&riderslat, &riderslon,
&deliveryamt, &kms, &actualkms, &riderkms,
&deliverycharges, &deliverytype, &paymenttype,
&smsdelivery, &quantity, &collectionamt,
&collectedamt, &collectionstatus,
&notes, &ordernotes, &step, &eta,
&previouskms, &cumulativekms, &ridertime,
&tenantname, &tenantcontactno, &tenanttoken,
&tenantsuburb, &tenantcity, &tenantaddress,
&ridername, &userfcmtoken, &ridercontact,
&locationname, &locationsuburb, &locationcontactno, &locationaddress,
&slab, &pricingdate, &baseprice, &minkm,
&priceperkm, &maxkm, &pricingorders,
&othercharges, &surgecharges,
); err != nil {
return "", err
}
// ✅ Append safely
builder.Field(0).(*array.Int32Builder).Append(deliveryid)
if applocationid.Valid {
builder.Field(1).(*array.Int32Builder).Append(applocationid.Int32)
} else {
builder.Field(1).(*array.Int32Builder).AppendNull()
}
if applocation.Valid {
builder.Field(2).(*array.StringBuilder).Append(applocation.String)
} else {
builder.Field(2).(*array.StringBuilder).AppendNull()
}
if orderheaderid.Valid {
builder.Field(3).(*array.Int32Builder).Append(orderheaderid.Int32)
} else {
builder.Field(3).(*array.Int32Builder).AppendNull()
}
if configid.Valid {
builder.Field(4).(*array.Int32Builder).Append(configid.Int32)
} else {
builder.Field(4).(*array.Int32Builder).AppendNull()
}
if tenantid.Valid {
builder.Field(5).(*array.Int32Builder).Append(tenantid.Int32)
} else {
builder.Field(5).(*array.Int32Builder).AppendNull()
}
if partnerid.Valid {
builder.Field(6).(*array.Int32Builder).Append(partnerid.Int32)
} else {
builder.Field(6).(*array.Int32Builder).AppendNull()
}
if locationid.Valid {
builder.Field(7).(*array.Int32Builder).Append(locationid.Int32)
} else {
builder.Field(7).(*array.Int32Builder).AppendNull()
}
if userid.Valid {
builder.Field(8).(*array.Int32Builder).Append(userid.Int32)
} else {
builder.Field(8).(*array.Int32Builder).AppendNull()
}
if categoryid.Valid {
builder.Field(9).(*array.Int32Builder).Append(categoryid.Int32)
} else {
builder.Field(9).(*array.Int32Builder).AppendNull()
}
if subcategoryid.Valid {
builder.Field(10).(*array.Int32Builder).Append(subcategoryid.Int32)
} else {
builder.Field(10).(*array.Int32Builder).AppendNull()
}
if moduleid.Valid {
builder.Field(11).(*array.Int32Builder).Append(moduleid.Int32)
} else {
builder.Field(11).(*array.Int32Builder).AppendNull()
}
if orderid.Valid {
builder.Field(12).(*array.StringBuilder).Append(orderid.String)
} else {
builder.Field(12).(*array.StringBuilder).AppendNull()
}
if deliverydate.Valid {
builder.Field(13).(*array.TimestampBuilder).
Append(arrow.Timestamp(deliverydate.Time.UnixMilli()))
} else {
builder.Field(13).(*array.TimestampBuilder).AppendNull()
}
if orderstatus.Valid {
builder.Field(14).(*array.StringBuilder).Append(orderstatus.String)
} else {
builder.Field(14).(*array.StringBuilder).AppendNull()
}
if assigntime.Valid {
builder.Field(15).(*array.StringBuilder).Append(assigntime.String)
} else {
builder.Field(15).(*array.StringBuilder).AppendNull()
}
if starttime.Valid {
builder.Field(16).(*array.StringBuilder).Append(starttime.String)
} else {
builder.Field(16).(*array.StringBuilder).AppendNull()
}
if arrivaltime.Valid {
builder.Field(17).(*array.StringBuilder).Append(arrivaltime.String)
} else {
builder.Field(17).(*array.StringBuilder).AppendNull()
}
if pickuptime.Valid {
builder.Field(18).(*array.StringBuilder).Append(pickuptime.String)
} else {
builder.Field(18).(*array.StringBuilder).AppendNull()
}
if deliverytime.Valid {
builder.Field(19).(*array.StringBuilder).Append(deliverytime.String)
} else {
builder.Field(19).(*array.StringBuilder).AppendNull()
}
if canceltime.Valid {
builder.Field(20).(*array.StringBuilder).Append(canceltime.String)
} else {
builder.Field(20).(*array.StringBuilder).AppendNull()
}
if acceptedtime.Valid {
builder.Field(21).(*array.StringBuilder).Append(acceptedtime.String)
} else {
builder.Field(21).(*array.StringBuilder).AppendNull()
}
if customerid.Valid {
builder.Field(22).(*array.Int32Builder).Append(customerid.Int32)
} else {
builder.Field(22).(*array.Int32Builder).AppendNull()
}
if pickupcustomer.Valid {
builder.Field(23).(*array.StringBuilder).Append(pickupcustomer.String)
} else {
builder.Field(23).(*array.StringBuilder).AppendNull()
}
if pickupcontactno.Valid {
builder.Field(24).(*array.StringBuilder).Append(pickupcontactno.String)
} else {
builder.Field(24).(*array.StringBuilder).AppendNull()
}
if pickuplocationid.Valid {
builder.Field(25).(*array.Int32Builder).Append(pickuplocationid.Int32)
} else {
builder.Field(25).(*array.Int32Builder).AppendNull()
}
if pickupaddress.Valid {
builder.Field(26).(*array.StringBuilder).Append(pickupaddress.String)
} else {
builder.Field(26).(*array.StringBuilder).AppendNull()
}
if pickuplocation.Valid {
builder.Field(27).(*array.StringBuilder).Append(pickuplocation.String)
} else {
builder.Field(27).(*array.StringBuilder).AppendNull()
}
if pickuplat.Valid {
builder.Field(28).(*array.StringBuilder).Append(pickuplat.String)
} else {
builder.Field(28).(*array.StringBuilder).AppendNull()
}
if pickuplon.Valid {
builder.Field(29).(*array.StringBuilder).Append(pickuplon.String)
} else {
builder.Field(29).(*array.StringBuilder).AppendNull()
}
if deliverycustomerid.Valid {
builder.Field(30).(*array.Int32Builder).Append(deliverycustomerid.Int32)
} else {
builder.Field(30).(*array.Int32Builder).AppendNull()
}
if deliverycustomer.Valid {
builder.Field(31).(*array.StringBuilder).Append(deliverycustomer.String)
} else {
builder.Field(31).(*array.StringBuilder).AppendNull()
}
if deliverycontactno.Valid {
builder.Field(32).(*array.StringBuilder).Append(deliverycontactno.String)
} else {
builder.Field(32).(*array.StringBuilder).AppendNull()
}
if deliverylocationid.Valid {
builder.Field(33).(*array.Int32Builder).Append(deliverylocationid.Int32)
} else {
builder.Field(33).(*array.Int32Builder).AppendNull()
}
if deliveryaddress.Valid {
builder.Field(34).(*array.StringBuilder).Append(deliveryaddress.String)
} else {
builder.Field(34).(*array.StringBuilder).AppendNull()
}
if deliverylocation.Valid {
builder.Field(35).(*array.StringBuilder).Append(deliverylocation.String)
} else {
builder.Field(35).(*array.StringBuilder).AppendNull()
}
if droplat.Valid {
builder.Field(36).(*array.StringBuilder).Append(droplat.String)
} else {
builder.Field(36).(*array.StringBuilder).AppendNull()
}
if droplon.Valid {
builder.Field(37).(*array.StringBuilder).Append(droplon.String)
} else {
builder.Field(37).(*array.StringBuilder).AppendNull()
}
if deliverylat.Valid {
builder.Field(38).(*array.StringBuilder).Append(deliverylat.String)
} else {
builder.Field(38).(*array.StringBuilder).AppendNull()
}
if deliverylong.Valid {
builder.Field(39).(*array.StringBuilder).Append(deliverylong.String)
} else {
builder.Field(39).(*array.StringBuilder).AppendNull()
}
if riderslat.Valid {
builder.Field(40).(*array.StringBuilder).Append(riderslat.String)
} else {
builder.Field(40).(*array.StringBuilder).AppendNull()
}
if riderslon.Valid {
builder.Field(41).(*array.StringBuilder).Append(riderslon.String)
} else {
builder.Field(41).(*array.StringBuilder).AppendNull()
}
if deliveryamt.Valid {
builder.Field(42).(*array.Float64Builder).Append(deliveryamt.Float64)
} else {
builder.Field(42).(*array.Float64Builder).AppendNull()
}
if kms.Valid {
builder.Field(43).(*array.StringBuilder).Append(kms.String)
} else {
builder.Field(43).(*array.StringBuilder).AppendNull()
}
if actualkms.Valid {
builder.Field(44).(*array.StringBuilder).Append(actualkms.String)
} else {
builder.Field(44).(*array.StringBuilder).AppendNull()
}
if riderkms.Valid {
builder.Field(45).(*array.StringBuilder).Append(riderkms.String)
} else {
builder.Field(45).(*array.StringBuilder).AppendNull()
}
if deliverycharges.Valid {
builder.Field(46).(*array.Float64Builder).Append(deliverycharges.Float64)
} else {
builder.Field(46).(*array.Float64Builder).AppendNull()
}
if deliverytype.Valid {
builder.Field(47).(*array.StringBuilder).Append(deliverytype.String)
} else {
builder.Field(47).(*array.StringBuilder).AppendNull()
}
if paymenttype.Valid {
builder.Field(48).(*array.Int32Builder).Append(paymenttype.Int32)
} else {
builder.Field(48).(*array.Int32Builder).AppendNull()
}
if smsdelivery.Valid {
builder.Field(49).(*array.Int32Builder).Append(smsdelivery.Int32)
} else {
builder.Field(49).(*array.Int32Builder).AppendNull()
}
if quantity.Valid {
builder.Field(50).(*array.Int32Builder).Append(quantity.Int32)
} else {
builder.Field(50).(*array.Int32Builder).AppendNull()
}
if collectionamt.Valid {
builder.Field(51).(*array.Float64Builder).Append(collectionamt.Float64)
} else {
builder.Field(51).(*array.Float64Builder).AppendNull()
}
if collectedamt.Valid {
builder.Field(52).(*array.Float64Builder).Append(collectedamt.Float64)
} else {
builder.Field(52).(*array.Float64Builder).AppendNull()
}
if collectionstatus.Valid {
builder.Field(53).(*array.Int32Builder).Append(collectionstatus.Int32)
} else {
builder.Field(53).(*array.Int32Builder).AppendNull()
}
if notes.Valid {
builder.Field(54).(*array.StringBuilder).Append(notes.String)
} else {
builder.Field(54).(*array.StringBuilder).AppendNull()
}
if ordernotes.Valid {
builder.Field(55).(*array.StringBuilder).Append(ordernotes.String)
} else {
builder.Field(55).(*array.StringBuilder).AppendNull()
}
if step.Valid {
builder.Field(56).(*array.Int32Builder).Append(step.Int32)
} else {
builder.Field(56).(*array.Int32Builder).AppendNull()
}
if eta.Valid {
builder.Field(57).(*array.StringBuilder).Append(eta.String)
} else {
builder.Field(57).(*array.StringBuilder).AppendNull()
}
if previouskms.Valid {
builder.Field(58).(*array.Int32Builder).Append(previouskms.Int32)
} else {
builder.Field(58).(*array.Int32Builder).AppendNull()
}
if cumulativekms.Valid {
builder.Field(59).(*array.Int32Builder).Append(cumulativekms.Int32)
} else {
builder.Field(59).(*array.Int32Builder).AppendNull()
}
if ridertime.Valid {
builder.Field(60).(*array.Int32Builder).Append(ridertime.Int32)
} else {
builder.Field(60).(*array.Int32Builder).AppendNull()
}
if tenantname.Valid {
builder.Field(61).(*array.StringBuilder).Append(tenantname.String)
} else {
builder.Field(61).(*array.StringBuilder).AppendNull()
}
if tenantcontactno.Valid {
builder.Field(62).(*array.StringBuilder).Append(tenantcontactno.String)
} else {
builder.Field(62).(*array.StringBuilder).AppendNull()
}
if tenanttoken.Valid {
builder.Field(63).(*array.StringBuilder).Append(tenanttoken.String)
} else {
builder.Field(63).(*array.StringBuilder).AppendNull()
}
if tenantsuburb.Valid {
builder.Field(64).(*array.StringBuilder).Append(tenantsuburb.String)
} else {
builder.Field(64).(*array.StringBuilder).AppendNull()
}
if tenantcity.Valid {
builder.Field(65).(*array.StringBuilder).Append(tenantcity.String)
} else {
builder.Field(65).(*array.StringBuilder).AppendNull()
}
if tenantaddress.Valid {
builder.Field(66).(*array.StringBuilder).Append(tenantaddress.String)
} else {
builder.Field(66).(*array.StringBuilder).AppendNull()
}
if ridername.Valid {
builder.Field(67).(*array.StringBuilder).Append(ridername.String)
} else {
builder.Field(67).(*array.StringBuilder).AppendNull()
}
if userfcmtoken.Valid {
builder.Field(68).(*array.StringBuilder).Append(userfcmtoken.String)
} else {
builder.Field(68).(*array.StringBuilder).AppendNull()
}
if ridercontact.Valid {
builder.Field(69).(*array.StringBuilder).Append(ridercontact.String)
} else {
builder.Field(69).(*array.StringBuilder).AppendNull()
}
if locationname.Valid {
builder.Field(70).(*array.StringBuilder).Append(locationname.String)
} else {
builder.Field(70).(*array.StringBuilder).AppendNull()
}
if locationsuburb.Valid {
builder.Field(71).(*array.StringBuilder).Append(locationsuburb.String)
} else {
builder.Field(71).(*array.StringBuilder).AppendNull()
}
if locationcontactno.Valid {
builder.Field(72).(*array.StringBuilder).Append(locationcontactno.String)
} else {
builder.Field(72).(*array.StringBuilder).AppendNull()
}
if locationaddress.Valid {
builder.Field(73).(*array.StringBuilder).Append(locationaddress.String)
} else {
builder.Field(73).(*array.StringBuilder).AppendNull()
}
if slab.Valid {
builder.Field(74).(*array.StringBuilder).Append(slab.String)
} else {
builder.Field(74).(*array.StringBuilder).AppendNull()
}
if pricingdate.Valid {
builder.Field(75).(*array.TimestampBuilder).
Append(arrow.Timestamp(pricingdate.Time.UnixMilli()))
} else {
builder.Field(75).(*array.TimestampBuilder).AppendNull()
}
if baseprice.Valid {
builder.Field(76).(*array.Float64Builder).Append(baseprice.Float64)
} else {
builder.Field(76).(*array.Float64Builder).AppendNull()
}
if minkm.Valid {
builder.Field(77).(*array.Float64Builder).Append(minkm.Float64)
} else {
builder.Field(77).(*array.Float64Builder).AppendNull()
}
if priceperkm.Valid {
builder.Field(78).(*array.Float64Builder).Append(priceperkm.Float64)
} else {
builder.Field(78).(*array.Float64Builder).AppendNull()
}
if maxkm.Valid {
builder.Field(79).(*array.Float64Builder).Append(maxkm.Float64)
} else {
builder.Field(79).(*array.Float64Builder).AppendNull()
}
if pricingorders.Valid {
builder.Field(80).(*array.Int32Builder).Append(pricingorders.Int32)
} else {
builder.Field(80).(*array.Int32Builder).AppendNull()
}
if othercharges.Valid {
builder.Field(81).(*array.Float64Builder).Append(othercharges.Float64)
} else {
builder.Field(81).(*array.Float64Builder).AppendNull()
}
if surgecharges.Valid {
builder.Field(82).(*array.Float64Builder).Append(surgecharges.Float64)
} else {
builder.Field(82).(*array.Float64Builder).AppendNull()
}
}
record := builder.NewRecord()
defer record.Release()
_ = os.MkdirAll("backups/parquet/deliveries", 0755)
filePath := "backups/parquet/deliveries/deliveries_" +
time.Now().Format("2006_01_02") + ".parquet"
file, err := os.Create(filePath)
if err != nil {
return "", err
}
defer file.Close()
parquetProps := parquet.NewWriterProperties(
parquet.WithCompression(compress.Codecs.Snappy),
)
writer, err := pqarrow.NewFileWriter(
schema,
file,
parquetProps,
pqarrow.ArrowWriterProperties{},
)
if err != nil {
return "", err
}
defer writer.Close()
if err := writer.Write(record); err != nil {
return "", err
}
return filePath, nil
}

View File

@@ -0,0 +1,388 @@
package backup
import (
"database/sql"
"os"
"time"
"github.com/apache/arrow/go/v14/arrow"
"github.com/apache/arrow/go/v14/arrow/array"
"github.com/apache/arrow/go/v14/arrow/memory"
"github.com/apache/arrow/go/v14/parquet"
"github.com/apache/arrow/go/v14/parquet/compress"
"github.com/apache/arrow/go/v14/parquet/pqarrow"
)
func BackupOrders(sqlDB *sql.DB) (string, error) {
rows, err := sqlDB.Query(`
SELECT DISTINCT a.orderheaderid, a.applocationid,
a.tenantid, a.locationid, a.partnerid, a.configid, a.categoryid, a.subcategoryid, a.moduleid,
a.orderid, a.orderstatus, a.orderdate, a.ordernotes, a.itemcount, a.deliverytime AS deliverydate,
a.pending, a.processing, a.ready, a.delivered AS completed, a.cancelled,
a.deliverycharge, a.kms,
a.customerid, a.pickupaddress, a.pickuplat, a.pickuplong,
a.pickupcustomer, a.pickupcontactno, a.pickuplocation as pickupsuburb, a.pickupcity,
a.deliveryid AS deliverycustomerid, a.deliveryaddress, a.deliverylat, a.deliverylong, a.deliverytype,
a.deliverycustomer, a.deliverycontactno, a.deliverylocation as deliverysuburb, a.deliverycity, a.paymenttype, a.smsdelivery, a.orderamount, a.quantity, a.collectionamt,
b.tenantname, b.tenanttoken, b.primarycontact AS tenantcontactno, b.postcode AS tenantpostcode, b.suburb AS tenantsuburb, b.city AS tenantcity, b.address AS tenantaddress,
c.locationname, c.contactno AS locationcontactno, c.postcode AS locationpostcode, c.suburb AS locationsuburb, c.city AS locationcity, c.address AS locationaddress,
d.locationname AS applocation, f.slab, f.pricingdate, f.baseprice, f.minkm, f.priceperkm, f.maxkm, f.orders, f.othercharges, f.surgecharges
FROM orders a
INNER JOIN tenants b ON a.tenantid = b.tenantid
INNER JOIN tenantlocations c ON a.locationid = c.locationid
INNER JOIN app_location d ON a.applocationid = d.applocationid
INNER JOIN app_locationconfig e ON d.applocationid = e.applocationid
LEFT JOIN tenantpricing f ON a.tenantid = f.tenantid
WHERE a.orderdate >= NOW() - INTERVAL '3 months'
`)
if err != nil {
return "", err
}
defer rows.Close()
// ---------- Arrow Schema (aligned with SQL SELECT — 67 columns) ----------
schema := arrow.NewSchema([]arrow.Field{
// core ids
{Name: "orderheaderid", Type: arrow.PrimitiveTypes.Int32},
{Name: "applocationid", Type: arrow.PrimitiveTypes.Int32},
{Name: "tenantid", Type: arrow.PrimitiveTypes.Int32},
{Name: "locationid", Type: arrow.PrimitiveTypes.Int32},
{Name: "partnerid", Type: arrow.PrimitiveTypes.Int32},
{Name: "configid", Type: arrow.PrimitiveTypes.Int32},
{Name: "categoryid", Type: arrow.PrimitiveTypes.Int32},
{Name: "subcategoryid", Type: arrow.PrimitiveTypes.Int32},
{Name: "moduleid", Type: arrow.PrimitiveTypes.Int32},
// order meta
{Name: "orderid", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "orderstatus", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "orderdate", Type: arrow.FixedWidthTypes.Timestamp_ms, Nullable: true},
{Name: "ordernotes", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "itemcount", Type: arrow.PrimitiveTypes.Int32, Nullable: true},
{Name: "deliverydate", Type: arrow.FixedWidthTypes.Timestamp_ms, Nullable: true},
// lifecycle
{Name: "pending", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "processing", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "ready", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "completed", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "cancelled", Type: arrow.BinaryTypes.String, Nullable: true},
// charges & distance
{Name: "deliverycharge", Type: arrow.PrimitiveTypes.Float64, Nullable: true},
{Name: "kms", Type: arrow.BinaryTypes.String, Nullable: true},
// pickup
{Name: "customerid", Type: arrow.PrimitiveTypes.Int32},
{Name: "pickupaddress", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "pickuplat", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "pickuplong", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "pickupcustomer", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "pickupcontactno", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "pickuplocation", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "pickupcity", Type: arrow.BinaryTypes.String, Nullable: true},
// delivery
{Name: "deliverycustomerid", Type: arrow.PrimitiveTypes.Int32},
{Name: "deliveryaddress", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "deliverylat", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "deliverylong", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "deliverytype", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "deliverycustomer", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "deliverycontactno", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "deliverylocation", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "deliverycity", Type: arrow.BinaryTypes.String, Nullable: true},
// payment
{Name: "paymenttype", Type: arrow.PrimitiveTypes.Int32, Nullable: true},
{Name: "smsdelivery", Type: arrow.PrimitiveTypes.Int32, Nullable: true},
{Name: "orderamount", Type: arrow.PrimitiveTypes.Float64, Nullable: true},
{Name: "quantity", Type: arrow.PrimitiveTypes.Int32, Nullable: true},
{Name: "collectionamt", Type: arrow.PrimitiveTypes.Float64, Nullable: true},
// tenant
{Name: "tenantname", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "tenanttoken", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "tenantcontactno", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "tenantpostcode", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "tenantsuburb", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "tenantcity", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "tenantaddress", Type: arrow.BinaryTypes.String, Nullable: true},
// location
{Name: "locationname", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "locationcontactno", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "locationpostcode", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "locationsuburb", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "locationcity", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "locationaddress", Type: arrow.BinaryTypes.String, Nullable: true},
// app location + pricing
{Name: "applocation", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "slab", Type: arrow.BinaryTypes.String, Nullable: true},
{Name: "pricingdate", Type: arrow.FixedWidthTypes.Timestamp_ms, Nullable: true},
{Name: "baseprice", Type: arrow.PrimitiveTypes.Float64, Nullable: true},
{Name: "minkm", Type: arrow.PrimitiveTypes.Float64, Nullable: true},
{Name: "priceperkm", Type: arrow.PrimitiveTypes.Float64, Nullable: true},
{Name: "maxkm", Type: arrow.PrimitiveTypes.Float64, Nullable: true},
{Name: "pricingorders", Type: arrow.PrimitiveTypes.Int32, Nullable: true},
{Name: "othercharges", Type: arrow.PrimitiveTypes.Float64, Nullable: true},
{Name: "surgecharges", Type: arrow.PrimitiveTypes.Float64, Nullable: true},
}, nil)
pool := memory.NewGoAllocator()
builder := array.NewRecordBuilder(pool, schema)
defer builder.Release()
// ---------- Scan & Append ----------
for rows.Next() {
var (
orderheaderid, applocationid, tenantid, locationid, partnerid int32
configid, categoryid, subcategoryid, moduleid int32
orderid, orderstatus, ordernotes sql.NullString
pending, processing, ready, completed, cancelled sql.NullString
pickupaddress, pickuplat, pickuplong sql.NullString
pickupcustomer, pickupcontactno, pickupsuburb, pickupcity sql.NullString
deliveryaddress, deliverylat, deliverylong sql.NullString
deliverytype, deliverycustomer, deliverycontactno sql.NullString
deliverysuburb, deliverycity sql.NullString
kms sql.NullString
itemcount, paymenttype, smsdelivery, quantity sql.NullInt32
customerid, deliverycustomerid int32
orderamount, deliverycharge, collectionamt sql.NullFloat64
orderdate, deliverydate sql.NullTime
tenantname, tenanttoken, tenantcontactno sql.NullString
tenantpostcode, tenantsuburb, tenantcity, tenantaddress sql.NullString
locationname, locationcontactno, locationpostcode sql.NullString
locationsuburb, locationcity, locationaddress sql.NullString
applocation sql.NullString
slab sql.NullString
pricingdate sql.NullTime
baseprice, minkm, priceperkm, maxkm sql.NullFloat64
pricingorders sql.NullInt32
othercharges, surgecharges sql.NullFloat64
)
if err := rows.Scan(
// core ids
&orderheaderid, &applocationid,
&tenantid, &locationid, &partnerid, &configid, &categoryid, &subcategoryid, &moduleid,
// order meta
&orderid, &orderstatus, &orderdate, &ordernotes, &itemcount, &deliverydate,
// lifecycle
&pending, &processing, &ready, &completed, &cancelled,
// charges & distance
&deliverycharge, &kms,
// pickup
&customerid, &pickupaddress, &pickuplat, &pickuplong,
&pickupcustomer, &pickupcontactno, &pickupsuburb, &pickupcity,
// delivery
&deliverycustomerid, &deliveryaddress, &deliverylat, &deliverylong,
&deliverytype, &deliverycustomer, &deliverycontactno,
&deliverysuburb, &deliverycity,
// payment
&paymenttype, &smsdelivery, &orderamount, &quantity, &collectionamt,
// tenant
&tenantname, &tenanttoken, &tenantcontactno,
&tenantpostcode, &tenantsuburb, &tenantcity, &tenantaddress,
// location
&locationname, &locationcontactno, &locationpostcode,
&locationsuburb, &locationcity, &locationaddress,
// app location + pricing
&applocation,
&slab, &pricingdate, &baseprice, &minkm, &priceperkm,
&maxkm, &pricingorders, &othercharges, &surgecharges,
); err != nil {
return "", err
}
// core ids (not null)
builder.Field(0).(*array.Int32Builder).Append(orderheaderid)
builder.Field(1).(*array.Int32Builder).Append(applocationid)
builder.Field(2).(*array.Int32Builder).Append(tenantid)
builder.Field(3).(*array.Int32Builder).Append(locationid)
builder.Field(4).(*array.Int32Builder).Append(partnerid)
builder.Field(5).(*array.Int32Builder).Append(configid)
builder.Field(6).(*array.Int32Builder).Append(categoryid)
builder.Field(7).(*array.Int32Builder).Append(subcategoryid)
builder.Field(8).(*array.Int32Builder).Append(moduleid)
// order meta
appendString(builder.Field(9), orderid)
appendString(builder.Field(10), orderstatus)
if orderdate.Valid {
builder.Field(11).(*array.TimestampBuilder).Append(arrow.Timestamp(orderdate.Time.UnixMilli()))
} else {
builder.Field(11).(*array.TimestampBuilder).AppendNull()
}
appendString(builder.Field(12), ordernotes)
if itemcount.Valid {
builder.Field(13).(*array.Int32Builder).Append(itemcount.Int32)
} else {
builder.Field(13).(*array.Int32Builder).AppendNull()
}
if deliverydate.Valid {
builder.Field(14).(*array.TimestampBuilder).Append(arrow.Timestamp(deliverydate.Time.UnixMilli()))
} else {
builder.Field(14).(*array.TimestampBuilder).AppendNull()
}
// lifecycle
appendString(builder.Field(15), pending)
appendString(builder.Field(16), processing)
appendString(builder.Field(17), ready)
appendString(builder.Field(18), completed)
appendString(builder.Field(19), cancelled)
// charges & distance
if deliverycharge.Valid {
builder.Field(20).(*array.Float64Builder).Append(deliverycharge.Float64)
} else {
builder.Field(20).(*array.Float64Builder).AppendNull()
}
appendString(builder.Field(21), kms)
// pickup
builder.Field(22).(*array.Int32Builder).Append(customerid)
appendString(builder.Field(23), pickupaddress)
appendString(builder.Field(24), pickuplat)
appendString(builder.Field(25), pickuplong)
appendString(builder.Field(26), pickupcustomer)
appendString(builder.Field(27), pickupcontactno)
appendString(builder.Field(28), pickupsuburb)
appendString(builder.Field(29), pickupcity)
// delivery
builder.Field(30).(*array.Int32Builder).Append(deliverycustomerid)
appendString(builder.Field(31), deliveryaddress)
appendString(builder.Field(32), deliverylat)
appendString(builder.Field(33), deliverylong)
appendString(builder.Field(34), deliverytype)
appendString(builder.Field(35), deliverycustomer)
appendString(builder.Field(36), deliverycontactno)
appendString(builder.Field(37), deliverysuburb)
appendString(builder.Field(38), deliverycity)
// payment
if paymenttype.Valid {
builder.Field(39).(*array.Int32Builder).Append(paymenttype.Int32)
} else {
builder.Field(39).(*array.Int32Builder).AppendNull()
}
if smsdelivery.Valid {
builder.Field(40).(*array.Int32Builder).Append(smsdelivery.Int32)
} else {
builder.Field(40).(*array.Int32Builder).AppendNull()
}
if orderamount.Valid {
builder.Field(41).(*array.Float64Builder).Append(orderamount.Float64)
} else {
builder.Field(41).(*array.Float64Builder).AppendNull()
}
if quantity.Valid {
builder.Field(42).(*array.Int32Builder).Append(quantity.Int32)
} else {
builder.Field(42).(*array.Int32Builder).AppendNull()
}
if collectionamt.Valid {
builder.Field(43).(*array.Float64Builder).Append(collectionamt.Float64)
} else {
builder.Field(43).(*array.Float64Builder).AppendNull()
}
// tenant
appendString(builder.Field(44), tenantname)
appendString(builder.Field(45), tenanttoken)
appendString(builder.Field(46), tenantcontactno)
appendString(builder.Field(47), tenantpostcode)
appendString(builder.Field(48), tenantsuburb)
appendString(builder.Field(49), tenantcity)
appendString(builder.Field(50), tenantaddress)
// location
appendString(builder.Field(51), locationname)
appendString(builder.Field(52), locationcontactno)
appendString(builder.Field(53), locationpostcode)
appendString(builder.Field(54), locationsuburb)
appendString(builder.Field(55), locationcity)
appendString(builder.Field(56), locationaddress)
// app location + pricing
appendString(builder.Field(57), applocation)
appendString(builder.Field(58), slab)
if pricingdate.Valid {
builder.Field(59).(*array.TimestampBuilder).Append(arrow.Timestamp(pricingdate.Time.UnixMilli()))
} else {
builder.Field(59).(*array.TimestampBuilder).AppendNull()
}
if baseprice.Valid {
builder.Field(60).(*array.Float64Builder).Append(baseprice.Float64)
} else {
builder.Field(60).(*array.Float64Builder).AppendNull()
}
if minkm.Valid {
builder.Field(61).(*array.Float64Builder).Append(minkm.Float64)
} else {
builder.Field(61).(*array.Float64Builder).AppendNull()
}
if priceperkm.Valid {
builder.Field(62).(*array.Float64Builder).Append(priceperkm.Float64)
} else {
builder.Field(62).(*array.Float64Builder).AppendNull()
}
if maxkm.Valid {
builder.Field(63).(*array.Float64Builder).Append(maxkm.Float64)
} else {
builder.Field(63).(*array.Float64Builder).AppendNull()
}
if pricingorders.Valid {
builder.Field(64).(*array.Int32Builder).Append(pricingorders.Int32)
} else {
builder.Field(64).(*array.Int32Builder).AppendNull()
}
if othercharges.Valid {
builder.Field(65).(*array.Float64Builder).Append(othercharges.Float64)
} else {
builder.Field(65).(*array.Float64Builder).AppendNull()
}
if surgecharges.Valid {
builder.Field(66).(*array.Float64Builder).Append(surgecharges.Float64)
} else {
builder.Field(66).(*array.Float64Builder).AppendNull()
}
}
record := builder.NewRecord()
defer record.Release()
_ = os.MkdirAll("backups/parquet/orders", 0755)
filePath := "backups/parquet/orders/orders_last_3_months_" +
time.Now().Format("2006_01_02") + ".parquet"
file, err := os.Create(filePath)
if err != nil {
return "", err
}
defer file.Close()
parquetProps := parquet.NewWriterProperties(
parquet.WithCompression(compress.Codecs.Snappy),
)
writer, err := pqarrow.NewFileWriter(
schema,
file,
parquetProps,
pqarrow.ArrowWriterProperties{},
)
if err != nil {
return "", err
}
defer writer.Close()
if err := writer.Write(record); err != nil {
return "", err
}
return filePath, nil
}

View File

@@ -0,0 +1,67 @@
package backup
import (
"context"
"fmt"
"os"
"path/filepath"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/service/s3"
)
func UploadParquetToSpaces(localFilePath, objectPath string) (string, error) {
region := os.Getenv("DO_SPACES_REGION")
endpoint := os.Getenv("DO_SPACES_ENDPOINT")
bucket := os.Getenv("DO_SPACES_BUCKET")
accessKey := os.Getenv("DO_SPACES_ACCESS_KEY")
secretKey := os.Getenv("DO_SPACES_SECRET_KEY")
cfg, err := config.LoadDefaultConfig(
context.TODO(),
config.WithRegion(region),
config.WithCredentialsProvider(
credentials.NewStaticCredentialsProvider(accessKey, secretKey, ""),
),
config.WithEndpointResolver(
aws.EndpointResolverFunc(func(service, region string) (aws.Endpoint, error) {
return aws.Endpoint{
URL: "https://" + endpoint,
SigningRegion: region,
}, nil
}),
),
)
if err != nil {
return "", err
}
client := s3.NewFromConfig(cfg)
file, err := os.Open(localFilePath)
if err != nil {
return "", err
}
defer file.Close()
_, err = client.PutObject(context.TODO(), &s3.PutObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(objectPath),
Body: file,
ContentType: aws.String("application/octet-stream"),
ACL: "public-read",
})
if err != nil {
return "", err
}
cdnURL := fmt.Sprintf(
"https://images.nearle.app/%s",
filepath.ToSlash(objectPath),
)
return cdnURL, nil
}

66
main.go Normal file
View File

@@ -0,0 +1,66 @@
package main
import (
"os"
"os/signal"
"syscall"
"time"
"nearle/config"
"nearle/db"
"nearle/middlewares"
"nearle/routes"
"nearle/utils"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cors"
"github.com/joho/godotenv"
)
func main() {
_ = godotenv.Load()
cfg := config.Load()
app := fiber.New()
app.Use(cors.New(cors.Config{
AllowHeaders: "Origin,Content-Type,Accept,Authorization",
AllowOrigins: "http://localhost:3000,http://localhost:3001,http://localhost:3002,http://localhost:3003,http://localhost:3004,http://localhost:3005,https://console.nearlexpress.com,https://app.nearlexpress.com,https://admin.nearlexpress.com,https://developer.nearlexpress.com", // 🔥 simplify (or keep your domains)
AllowCredentials: true,
AllowMethods: "GET,POST,PUT,DELETE,PATCH,OPTIONS",
}))
app.Use(middlewares.ZapLogger())
utils.Info("Connecting to database...")
db.Connect()
db.InitRedis()
utils.Info("All connections established!")
routes.LiveSetup(app)
go func() {
utils.Info("Server starting", "port", cfg.Port)
if err := app.Listen(":" + cfg.Port); err != nil {
utils.Logger.Fatalf("Server failed: %v", err)
}
}()
gracefulShutdown()
}
func gracefulShutdown() {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
<-c
utils.Info("Shutting down...")
db.CloseDB()
time.Sleep(2 * time.Second)
utils.Info("Shutdown complete")
}

57
mainOLD copy.go Normal file
View File

@@ -0,0 +1,57 @@
package main
// import (
// "strings"
// "nearle/db"
// "nearle/routes"
// "github.com/gofiber/fiber/v2"
// "github.com/gofiber/fiber/v2/middleware/cors"
// )
// var (
// router = fiber.New()
// )
// func main() {
// //app := fiber.New()
// router.Use(cors.New(cors.Config{
// AllowHeaders: "Origin,Content-Type,Accept,Content-Length,Accept-Language,Accept-Encoding,Connection,Access-Control-Allow-Origin",
// AllowOrigins: "*",
// AllowCredentials: true,
// AllowMethods: "GET,POST,HEAD,PUT,DELETE,PATCH,OPTIONS",
// }))
// router.Use(handler)
// routes.DevSetup(router)
// routes.LiveSetup(router)
// router.Listen(":1009")
// }
// func handler(c *fiber.Ctx) error {
// path := c.Path()
// result := strings.Split(path, "/")
// var flavour string
// for _ = range result {
// flavour = result[1]
// }
// if flavour == "dev" {
// db.DevConnect()
// } else if flavour == "live" {
// db.LiveConnect()
// defer db.CloseDB()
// }
// return c.Next()
// }

View File

@@ -0,0 +1,43 @@
package middlewares
import (
"time"
"nearle/utils"
"github.com/gofiber/fiber/v2"
)
// ZapLogger is a Fiber middleware that logs HTTP requests using Zap.
func ZapLogger() fiber.Handler {
return func(c *fiber.Ctx) error {
start := time.Now()
// Handle the request
err := c.Next()
latency := time.Since(start).String()
status := c.Response().StatusCode()
method := c.Method()
path := c.Path()
ip := c.IP()
fields := []interface{}{
"status", status,
"method", method,
"path", path,
"ip", ip,
"latency", latency,
}
if err != nil {
fields = append(fields, "error", err.Error())
utils.Logger.Errorw("API Request Failed", fields...)
return err
}
utils.Logger.Infow("API Request Successful", fields...)
return nil
}
}

View File

@@ -0,0 +1,89 @@
package middlewares
import (
"nearle/db"
"nearle/models"
"github.com/gofiber/fiber/v2"
)
type RolePayload struct {
Roleid int `json:"roleid"`
}
func RoleCheckMiddleware(allowedRoles ...int) fiber.Handler {
return func(c *fiber.Ctx) error {
var user models.User
if err := c.BodyParser(&user); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"status": false,
"code": 400,
"message": "Invalid request body",
})
}
var uid, dbRoleId int
var status, dbPassword string
var query string
if user.Authname != "" {
query = `SELECT userid, password, status, roleid FROM app_users WHERE authname = ? AND configid = ?`
db.DB.Raw(query, user.Authname, user.Configid).Row().Scan(&uid, &dbPassword, &status, &dbRoleId)
} else if user.Contactno != "" {
query = `SELECT userid, password, status, roleid FROM app_users WHERE contactno = ? AND configid = ?`
db.DB.Raw(query, user.Contactno, user.Configid).Row().Scan(&uid, &dbPassword, &status, &dbRoleId)
} else {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"status": false,
"code": 400,
"message": "authname or contactno required",
})
}
// No user found
if uid == 0 {
return c.Status(fiber.StatusOK).JSON(fiber.Map{
"status": false,
"code": 409,
"message": "Invalid Email",
"tenantform": true,
})
}
// Inactive user
if status == "InActive" {
return c.Status(fiber.StatusOK).JSON(fiber.Map{
"status": false,
"code": 403,
"message": "Inactive Account. Contact admin.",
})
}
// Check allowed role
allowed := false
for _, r := range allowedRoles {
if dbRoleId == r {
allowed = true
break
}
}
if !allowed {
return c.Status(fiber.StatusOK).JSON(fiber.Map{
"status": false,
"code": 403,
"message": "Unauthorized role",
})
}
// Store user data in context
c.Locals("uid", uid)
c.Locals("password", dbPassword)
return c.Next()
}
}

91
models/common.go Normal file
View File

@@ -0,0 +1,91 @@
package models
type Result struct {
Code int `json:"code"`
Status bool `json:"status"`
Message string `json:"message"`
}
type GroupNotifications struct {
Notifications []NotificationData `json:"notifications"`
Fcmmodel *Notification `json:"fcmmodel"`
}
type Notifications struct {
Priority string `json:"priority"`
Registrationids []string `json:"registration_ids"`
Data Data `json:"data"`
Notify Notify `json:"notification"`
}
type NotifyUser struct {
Sender string `json:"sender"`
Accessid string `json:"accessid"`
Notification Notification `json:"notification"`
}
type Notification struct {
Priority string `json:"priority"`
To string `json:"to"`
Notify Notify `json:"notification"`
}
type LoginNotification struct {
Priority string `json:"priority"`
To string `json:"to"`
Notification Notify `json:"notification"`
}
type Notify struct {
Title string `json:"title"`
Body string `json:"body"`
Sound string `json:"sound"`
}
type FcmNotification struct {
Title string `json:"title"`
Body string `json:"body"`
// Type string `json:"type"`
}
type NotificationResult struct {
StatusCode int `json:"statuscode"`
Success int `json:"success"`
Failure int `json:"failure"`
}
type Data struct {
Notificationid int `json:"notificationid" gorm:"Primary_Key"`
Notificationdate string `json:"notificationdate"`
Title string `json:"title"`
Message string `json:"message"`
Configid int `json:"configid"`
Tenantid int64 `json:"tenantid"`
Orderheaderid int `json:"orderheaderid"`
Orderid string `json:"orderid"`
Success int `json:"success"`
Notifytype int `json:"notifytype"`
Notifyreason string `json:"notifyreason"`
Accessid string `json:"accessid" gorm:"<-:false"`
Customerid int64 `json:"customerid" gorm:"<-:false"`
ClickAction string `json:"clickaction" gorm:"<-:false"`
}
type NotificationData struct {
Notificationid int `json:"notificationid" gorm:"Primary_Key"`
Notificationdate string `json:"notificationdate"`
Title string `json:"title"`
Message string `json:"message"`
Configid int `json:"configid"`
Tenantid int64 `json:"tenantid"`
Orderheaderid int `json:"orderheaderid"`
Orderprocessid int `json:"orderprocessid"`
Orderstatus string `json:"orderstatus" gorm:"<-:false"`
Processing string `json:"processing" gorm:"<-:false"`
Shiftid int64 `json:"shiftid"`
Userid int `json:"userid"`
Orderid string `json:"orderid"`
Notifytype int `json:"notifytype"`
Notifyreason string `json:"notifyreason"`
Success int `json:"success"`
}

189
models/customer.go Normal file
View File

@@ -0,0 +1,189 @@
package models
import "time"
type CustomerResult struct {
Code int `json:"code"`
Status bool `json:"status"`
Message string `json:"message"`
Details Customers `json:"details"`
}
type CustomersResult struct {
Code int `json:"code"`
Status bool `json:"status"`
Message string `json:"message"`
Details []Customers `json:"details"`
}
type CustomerInfo struct {
Customerid int `json:"customerid"`
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
Profileimage string `json:"profileimage"`
Gender string `json:"gender"`
Dob string `json:"dob"`
Dialcode string `json:"dialcode"`
Contactno string `json:"contactno"`
Email string `json:"email"`
Deviceid string `json:"deviceid"`
Devicetype string `json:"devicetype"`
Authmode int `json:"authmode"`
Configid int `json:"configid"`
Customertoken string `json:"customertoken"`
Deliverylocationid int `json:"deliverylocationid"`
Address string `json:"address"`
Suburb string `json:"suburb"`
City string `json:"city"`
State string `json:"state"`
Landmark string `json:"landmark"`
Doorno string `json:"doorno"`
Postcode string `json:"postcode"`
Latitude string `json:"latitude"`
Longitude string `json:"longitude"`
Applocationid int `json:"applocationid"`
Allocationid int `json:"allocationid"`
Primaryaddress int `json:"primaryaddress"`
Tenantlocationid int `json:"tenantlocationid"`
Tenantid int `json:"tenantid"`
Status int `json:"status"`
Intro string `json:"intro"`
Selectedlatitude string `json:"selectedlatitude"`
Selectedlongitude string `json:"selectedlongitude"`
Radius string `json:"radius"`
Qrmode int `json:"qrmode"`
Quantity int `json:"quantity" gorm:"default:1"`
Collectionamt float32 `json:"collectionamt" gorm:"default:0.0"`
}
type Customers struct {
Customerid int `json:"customerid" gorm:"Primary_Key"`
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
Profileimage string `json:"profileimage"`
Gender string `json:"gender"`
Dob string `json:"dob"`
Dialcode string `json:"dialcode"`
Contactno string `json:"contactno"`
Email string `json:"email"`
Deviceid string `json:"deviceid"`
Devicetype string `json:"devicetype"`
Authmode int `json:"authmode"`
Configid int `json:"configid"`
Customertoken string `json:"customertoken"`
Address string `json:"address"`
Suburb string `json:"suburb"`
City string `json:"city"`
State string `json:"state"`
Landmark string `json:"landmark"`
Doorno string `json:"doorno"`
Postcode string `json:"postcode"`
Latitude string `json:"latitude"`
Longitude string `json:"longitude"`
Applocationid int `json:"applocationid"`
Locationid int `json:"locationid,omitempty" gorm:"-"`
Defaultaddress string `json:"defaultaddress,omitempty" gorm:"-"`
Primaryaddress int `json:"primaryaddress,omitempty" gorm:"-"`
Tenantid int `json:"tenantid,omitempty" gorm:"-"`
Status int `json:"status"`
Intro string `json:"intro"`
Qrmode int `json:"qrmode,omitempty" gorm:"-"`
}
type Customer struct {
Customerid int `json:"customerid" gorm:"Primary_Key"`
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
Profileimage string `json:"profileimage"`
Gender string `json:"gender"`
Dob string `json:"dob"`
Dialcode string `json:"dialcode"`
Contactno string `json:"contactno"`
Email string `json:"email"`
Deviceid string `json:"deviceid"`
Devicetype string `json:"devicetype"`
Authmode int `json:"authmode"`
Configid int `json:"configid"`
Customertoken string `json:"customertoken"`
Address string `json:"address"`
Suburb string `json:"suburb"`
City string `json:"city"`
State string `json:"state"`
Landmark string `json:"landmark"`
Doorno string `json:"doorno"`
Postcode string `json:"postcode"`
Latitude string `json:"latitude"`
Longitude string `json:"longitude"`
Applocationid int `json:"applocationid"`
Locationid int `json:"locationid,omitempty"`
Defaultaddress string `json:"defaultaddress,omitempty"`
Primaryaddress int `json:"primaryaddress,omitempty"`
Tenantid int `json:"tenantid,omitempty"`
Status int `json:"status"`
Intro string `json:"intro"`
Qrmode int `json:"qrmode,omitempty"`
}
type Tenantcustomers struct {
Tenantcustomerid int `json:"tenantcustomerid" gorm:"Primary_Key;autoIncrement"`
Tenantid int `json:"tenantid" `
Locationid int `json:"locationid"`
Customerid int `json:"customerid"`
Moduleid int `json:"moduleid"`
Status int `json:"status"`
}
type Tenantcustomer struct {
Tenantcustomerid int `json:"tenantcustomerid" gorm:"Primary_Key"`
// Tenantid int `json:"tenantid" `
Locationid int `json:"locationid"`
Customerid int `json:"customerid"`
Moduleid int `json:"moduleid"`
Status int `json:"status"`
}
type CustomersId struct {
Customerid int `json:"customerid"`
Locationid int `json:"locationsid"`
Pickuplocationid int `json:"pickuplocationid"`
Deliveryid int `json:"deliveryid"`
Droplocationid int `json:"droplocationid"`
}
type CustomerLocationResult struct {
Code int `json:"code"`
Status bool `json:"status"`
Message string `json:"message"`
Details []Customerlocations `json:"details"`
}
type Customerlocations struct {
Locationid int `json:"locationid" gorm:"Primary_Key"`
Customerid int `json:"customerid"`
Address string `json:"address"`
Suburb string `json:"suburb"`
City string `json:"city"`
State string `json:"state"`
Landmark string `json:"landmark"`
Doorno string `json:"doorno"`
Postcode string `json:"postcode"`
Latitude string `json:"latitude"`
Longitude string `json:"longitude"`
Primaryaddress int `json:"primaryaddress"`
Status int `json:"status"`
}
type CustomerRequest struct {
Customerrequestid int `json:"customerrequestid"`
Referencedate time.Time `json:"referencedate"`
Referencetype string `json:"referencetype"`
Customerid int `json:"customerid"`
Tenantid int `json:"tenantid"`
Apptypeid int `json:"apptypeid"`
Locationid int `json:"locationid"`
Subject string `json:"subject"`
Remarks string `json:"remarks"`
Status int `json:"status"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
}

443
models/delivery.go Normal file
View File

@@ -0,0 +1,443 @@
package models
import "gorm.io/gorm"
type Deliveries struct {
Deliveryid int `json:"deliveryid" gorm:"Primary_Key"`
Orderheaderid int `json:"orderheaderid"`
Applocationid int `json:"applocationid"`
Configid int `json:"configid"`
Partnerid int `json:"partnerid"`
Tenantid int `json:"tenantid"`
Moduleid int `json:"moduleid"`
Locationid int `json:"locationid"`
Categoryid int `json:"categoryid"`
Userid int `json:"userid"`
Subcategoryid int `json:"subcategoryid"`
Orderid string `json:"orderid"`
Deliverydate string `json:"deliverydate"`
Orderstatus string `json:"orderstatus"`
Assigntime string `json:"assigntime"`
Starttime string `json:"starttime"`
Arrivaltime string `json:"arrivaltime"`
Pickuptime string `json:"pickuptime"`
Acceptedtime string `json:"acceptedtime"`
Canceltime string `json:"canceltime"`
Itemcount int `json:"itemcount"`
Orderamount float64 `json:"orderamount" gorm:"type:numeric"`
Customerid int `json:"customerid"`
Pickupcustomer string `json:"pickupcustomer"`
Pickupcontactno string `json:"pickupcontactno"`
Pickuplocationid int `json:"pickuplocationid"`
Pickupaddress string `json:"Pickupaddress"`
Pickuplocation string `json:"pickuplocation"`
Pickuplat string `json:"pickuplat"`
Pickuplon string `json:"pickuplon"`
Deliverycustomerid int `json:"deliverycustomerid"`
Deliverylocationid int `json:"deliverylocationid"`
Deliverycustomer string `json:"deliverycustomer"`
Deliverycontactno string `json:"deliverycontactno"`
Deliveryaddress string `json:"deliveryaddress"`
Deliverylocation string `json:"deliverylocation"`
Droplat string `json:"droplat"`
Droplon string `json:"droplon"`
Deliverylat string `json:"deliverylat"`
Deliverylong string `json:"deliverylong"`
Deliverycharges float64 `json:"deliverycharges" gorm:"type:numeric"`
Deliveryamt float64 `json:"deliveryamt" gorm:"type:numeric"`
Deliverytype string `json:"deliverytype"`
Notes string `json:"notes"`
Ordernotes string `json:"ordernotes"`
Riderslat string `json:"riderslat"`
Riderslon string `json:"riderslon"`
Firstmilekm float64 `json:"firstmilekm" gorm:"type:numeric"`
Firstmilecharges float64 `json:"firstmilecharges" gorm:"type:numeric"`
Lastmilecharges float64 `json:"lastmilecharges" gorm:"type:numeric"`
Ridercharges float64 `json:"ridercharges" gorm:"type:numeric"`
Kms string `json:"kms"`
Actualkms string `json:"actualkms"`
Smsdelivery int `json:"smsdelivery"`
Paymenttype int `json:"paymenttype" gorm:"default:0"`
Previouskms int `json:"previouskms" gorm:"default:0"`
Cumulativekms int `json:"cumulativekms" gorm:"default:0"`
Step int `json:"step" gorm:"default:0"`
Eta string `json:"eta" gorm:"type:varchar(100);default:''"`
Quantity int `josn:"quantity"`
Collectionamt float64 `json:"collectionamt" gorm:"type:numeric"`
Collectedamt float64 `json:"collectedamt" gorm:"type:numeric"`
Collectionstatus float64 `json:"collectionstatus" gorm:"type:numeric"`
Ridertime int `json:"ridertime"`
// GPS tracking fields (nullable — old app versions may not send these)
RawLatitude *string `json:"raw_latitude" gorm:"column:raw_latitude"`
RawLongitude *string `json:"raw_longitude" gorm:"column:raw_longitude"`
VelocityLat *string `json:"velocity_lat" gorm:"column:velocity_lat"`
VelocityLng *string `json:"velocity_lng" gorm:"column:velocity_lng"`
Speed *string `json:"speed" gorm:"column:speed"`
Heading *string `json:"heading" gorm:"column:heading"`
Expecteddeliverytime string `json:"expecteddeliverytime"`
Profit float64 `json:"profit"`
Transitminutes float64 `json:"transitminutes" gorm:"type:numeric"`
Calculationdistancekm float64 `json:"calculationdistancekm" gorm:"type:numeric"`
}
type UpdateDeliveryStatus struct {
Deliveryid int `json:"deliveryid"`
Deliverytype string `json:"deliverytype"`
Pickuplocationid int `json:"pickuplocationid"`
Deliverylocationid int `json:"deliverylocationid"`
Orderheaderid int `json:"orderheaderid"`
Userid int `json:"userid"`
Orderstatus string `json:"orderstatus"`
Assigntime string `json:"assigntime"`
Starttime string `json:"starttime"`
Arrivaltime string `json:"arrivaltime"`
Pickuptime string `json:"pickuptime"`
Acceptedtime string `json:"acceptedtime"`
Deliverytime string `json:"deliverytime"`
Canceltime string `json:"canceltime"`
Pickuplat string `json:"pickuplat"`
Pickuplon string `json:"picklon"`
Pickupimage string `json:"pickupimage"`
Riderslat string `json:"riderslat"`
Riderslon string `json:"riderslon"`
Deliverylat string `json:"deliverylat"`
Deliverylong string `json:"deliverylong"`
Dropimage string `json:"dropimage"`
Address string `json:"address" gorm:"<-:false"`
Suburb string `json:"suburb" gorm:"<-:false"`
City string `json:"city" gorm:"<-:false"`
State string `json:"state" gorm:"<-:false"`
Postcode string `json:"postcode" gorm:"<-:false"`
Deliveryamt float64 `json:"deliveryamt" gorm:"type:numeric"`
Kms string `json:"kms"`
// Actualkms string `json:"actualkms"`
Riderkms string `json:"riderkms"`
Ridercharges float64 `json:"ridercharges" gorm:"type:numeric"`
Kmcal string `json:"kmcal"`
Notes string `json:"notes"`
Feedback string `json:"feedback"`
Smsdelivery int `json:"smsdelivery"`
Previouskms int `json:"previouskms" gorm:"default:0"`
Cumulativekms int `json:"cumulativekms" gorm:"default:0"`
Step int `json:"step" gorm:"default:0"`
Eta string `json:"eta"`
Quantity int `josn:"quantity"`
Collectionamt float64 `json:"collectionamt" gorm:"type:numeric"`
Collectedamt float64 `json:"collectedamt" gorm:"type:numeric"`
Collectionstatus int `json:"collectionstatus" gorm:"default:0"`
Ridertime int `json:"ridertime" gorm:"default:0"`
Bonuspts int `json:"bonuspts"`
Skippedtime string `json:"skippedtime"`
Activelat string `json:"activelat"`
Activelon string `json:"activelon"`
// GPS tracking fields (nullable — old app versions may not send these)
RawLatitude *string `json:"raw_latitude" gorm:"column:raw_latitude"`
RawLongitude *string `json:"raw_longitude" gorm:"column:raw_longitude"`
VelocityLat *string `json:"velocity_lat" gorm:"column:velocity_lat"`
VelocityLng *string `json:"velocity_lng" gorm:"column:velocity_lng"`
Speed *string `json:"speed" gorm:"column:speed"`
Heading *string `json:"heading" gorm:"column:heading"`
Expecteddeliverytime string `json:"expecteddeliverytime"`
Profit float64 `json:"profit"`
Transitminutes float64 `json:"transitminutes" gorm:"type:numeric"`
Calculationdistancekm float64 `json:"calculationdistancekm" gorm:"type:numeric"`
}
type Deliveryinfo struct {
Deliveryid int `json:"deliveryid"`
Orderheaderid int `json:"orderheaderid"`
Applocationid int `json:"applocationid"`
Applocation string `json:"applocation"`
Configid int `json:"configid"`
Partnerid int `json:"partnerid"`
Tenantid int `json:"tenantid"`
Moduleid int `json:"moduleid"`
Locationid int `json:"locationid"`
Categoryid int `json:"categoryid"`
Userid int `json:"userid"`
Subcategoryid int `json:"subcategoryid"`
Orderid string `json:"orderid"`
Deliverydate string `json:"deliverydate"`
Orderstatus string `json:"orderstatus"`
Assigntime string `json:"assigntime"`
Starttime string `json:"starttime"`
Arrivaltime string `json:"arrivaltime"`
Pickuptime string `json:"pickuptime"`
Acceptedtime string `json:"acceptedtime"`
Deliverytime string `json:"deliverytime"`
Canceltime string `json:"canceltime"`
Itemcount int `json:"itemcount"`
Orderamount float64 `json:"orderamount" gorm:"type:numeric"`
Customerid int `json:"customerid"`
Pickupcustomer string `json:"pickupcustomer"`
Pickupcontactno string `json:"pickupcontactno"`
Pickuplocationid int `json:"pickuplocationid"`
Pickupaddress string `json:"Pickupaddress"`
Pickuplocation string `json:"pickuplocation"`
Pickuplat string `json:"pickuplat"`
Pickuplon string `json:"pickuplon"`
Deliverycustomerid int `json:"deliverycustomerid"`
Deliverylocationid int `json:"deliverylocationid"`
Deliverycustomer string `json:"deliverycustomer"`
Deliverycontactno string `json:"deliverycontactno"`
Deliveryaddress string `json:"deliveryaddress"`
Deliverylocation string `json:"deliverylocation"`
Droplat string `json:"droplat"`
Droplon string `json:"droplon"`
Deliverylat string `json:"deliverylat"`
Deliverylong string `json:"deliverylong"`
Deliverycharges float64 `json:"deliverycharges" gorm:"type:numeric"`
Deliveryamt float64 `json:"deliveryamt" gorm:"type:numeric"`
Deliverytype string `json:"deliverytype"`
Notes string `json:"notes"`
Ordernotes string `json:"ordernotes"`
Riderslat string `json:"riderslat"`
Riderslon string `json:"riderslon"`
Firstmilekm float64 `json:"firstmilekm" gorm:"type:numeric"`
Firstmilecharges float64 `json:"firstmilecharges" gorm:"type:numeric"`
Lastmilecharges float64 `json:"lastmilecharges" gorm:"type:numeric"`
Ridercharges float64 `json:"ridercharges" gorm:"type:numeric"`
Kms string `json:"kms"`
Actualkms string `json:"actualkms"`
Riderkms string `json:"riderkms"`
Paymenttype int `json:"paymenttype"`
Tenantname string `json:"tenantname"`
Tenantcontactno string `json:"tenantcontactno"`
Tenanttoken string `json:"tenanttoken"`
Tenantsuburb string `json:"tenantsuburb"`
Tenantcity string `json:"tenantcity"`
Tenantaddress string `json:"tenantaddress"`
Locationname string `json:"locationname"`
Locationcontactno string `json:"locationcontactno"`
Locationsuburb string `json:"locationsuburb"`
Locationaddress string `json:"locationaddress"`
Ridername string `json:"ridername"`
Userfcmtoken string `json:"userfcmtoken"`
Queueid int `json:"queueid"`
Smsdelivery int `json:"smsdelivery"`
Customertoken string `json:"customertoken"`
Ridercontact string `json:"ridercontact"`
Previouskms int `json:"previouskms" `
Cumulativekms int `json:"cumulativekms" `
Step int `json:"step" gorm:"default:0"`
Eta string `json:"eta" gorm:"type:varchar(100);default:''"`
Quantity int `josn:"quantity"`
Collectionamt float64 `json:"collectionamt" gorm:"type:numeric"`
Collectedamt float64 `json:"collectedamt" gorm:"type:numeric"`
Collectionstatus float64 `json:"collectionstatus" gorm:"type:numeric"`
Ridertime int `json:"ridertime"`
Slab string `json:"slab"`
Pricingdate string `json:"pricingdate"`
Baseprice float64 `json:"baseprice" gorm:"type:numeric"`
Minkm int `json:"minkm"`
Priceperkm float64 `json:"priceperkm" gorm:"type:numeric"`
Maxkm int `json:"maxkm"`
Orders int `json:"orders"`
Othercharges float64 `json:"othercharges" gorm:"type:numeric"`
Surgecharges float64 `json:"surgecharges" gorm:"type:numeric"`
Expecteddeliverytime string `json:"expecteddeliverytime"`
Profit float64 `json:"profit"`
Transitminutes float64 `json:"transitminutes" gorm:"type:numeric"`
Calculationdistancekm float64 `json:"calculationdistancekm" gorm:"type:numeric"`
}
type Deliveryqueues struct {
Queueid int `json:"queueid" gorm:"Primary_Key"`
Tenantid int `json:"tenantid"`
Locationid int `json:"locationid"`
Orderheaderid int `json:"orderheaderid"`
Deliveryid int `json:"deliveryid"`
Userid int `json:"userid"`
Partnerid int `json:"partnerid"`
Orderid string `json:"orderid"`
Latitude string `json:"latitude"`
Longitude string `json:"longitude"`
Accept int `json:"accept"`
Decline int `json:"decline"`
Queuestatus int `json:"queuestatus"`
}
type Deliverylogs struct {
Logid int `json:"logid" gorm:"Primary_Key"`
Logdate string `json:"logdate"`
Tenantid int `json:"tenantid"`
Locationid int `json:"locationid"`
Orderheaderid int `json:"orderheaderid"`
Deliveryid int `json:"deliveryid"`
Userid int `json:"userid"`
Partnerid int `json:"partnerid"`
Orderid string `json:"orderid"`
Orderstatus string `json:"orderstatus"`
Latitude string `json:"latitude"`
Longitude string `json:"longitude"`
Logstatus *int `json:"logstatus" gorm:"default:0"`
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
// GPS tracking fields (nullable — old app versions may not send these)
RawLatitude *string `json:"raw_latitude" gorm:"column:raw_latitude"`
RawLongitude *string `json:"raw_longitude" gorm:"column:raw_longitude"`
VelocityLat *string `json:"velocity_lat" gorm:"column:velocity_lat"`
VelocityLng *string `json:"velocity_lng" gorm:"column:velocity_lng"`
Speed *string `json:"speed" gorm:"column:speed"`
Heading *string `json:"heading" gorm:"column:heading"`
}
type Deliverydet struct {
Deliveries int `json:"deliveries"`
Delivered int `json:"Delivered"`
Cancelled int `json:"cancelled"`
Kms float64 `json:"kms" gorm:"type:numeric"`
Amount float64 `json:"amount" gorm:"type:numeric"`
}
type DeliverySummary struct {
Total int `json:"total"`
Created int `json:"created"`
Pending int `json:"pending"`
Accepted int `json:"accepted"`
Arrived int `json:"arrived"`
Picked int `json:"picked"`
Active int `json:"active"`
Delivered int `json:"delivered"`
Cancelled int `json:"cancelled"`
Skipped int `json:"skipped"`
}
type DeliveryDetailsCount struct {
Assigned int `json:"assigned"`
Accepted int `json:"accepted"`
Arrived int `json:"Arrived"`
Picked int `json:"picked"`
Active int `json:"active"`
Delivered int `json:"delivered"`
Cancelled int `json:"cancelled"`
}
type ReportSummary struct {
Tenantid int `json:"tenantid"`
Tenantname string `json:"tenantname"`
Locationid int `json:"locationid"`
Locationname string `json:"locationname"`
Totalorders int `json:"totalorders"`
Orderscreated int `json:"orderscreated"`
Orderspending int `json:"Orderspending"`
Orderscompleted int `json:"orderscompleted"`
Orderscancelled int `json:"orderscancelled"`
Deliveriespending int `json:"deliveriespending"`
Deliveriescompleted int `json:"deliveriescompleted"`
Deliveriescancelled int `json:"deliveriescancelled"`
Paylater float64 `json:"paylater" gorm:"type:numeric"`
Payondelivery float64 `json:"payondelivery" gorm:"type:numeric"`
Kms float64 `json:"kms" gorm:"type:numeric"`
Actualkms float64 `json:"actualkms" gorm:"type:numeric"`
Charges float64 `json:"charges" gorm:"type:numeric"`
Previouskms int `json:"previouskms"`
Cumulativekms int `json:"cumulativekms"`
Deliveryamt float64 `json:"deliveryamt" gorm:"type:numeric"`
Riderkms float64 `json:"riderkms" gorm:"type:numeric"`
Quantity int `josn:"quantity"`
Collectionamt float64 `json:"collectionamt" gorm:"type:numeric"`
Collectedamt float64 `json:"collectedamt" gorm:"type:numeric"`
Collectionstatus float64 `json:"collectionstatus" gorm:"type:numeric"`
}
type UserReportSummary struct {
// 🔹 User (Rider) details
Userid int `json:"userid"`
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
Ridercontact string `json:"ridercontact"`
// 🔹 Tenant details
Tenantid int `json:"tenantid"`
Tenantname string `json:"tenantname"`
// 🔹 Location details
Locationid int `json:"locationid"`
Locationname string `json:"locationname"`
// 🔹 Order summary
Totalorders int `json:"totalorders"`
Orderscreated int `json:"orderscreated"`
Orderspending int `json:"orderspending"`
Orderscompleted int `json:"orderscompleted"`
Orderscancelled int `json:"orderscancelled"`
// 🔹 Delivery summary
Deliveriespending int `json:"deliveriespending"`
Deliveriescompleted int `json:"deliveriescompleted"`
Deliveriescancelled int `json:"deliveriescancelled"`
// 🔹 Payment summary
Paylater float64 `json:"paylater"`
Payondelivery float64 `json:"payondelivery"`
// 🔹 Distance summary
Kms float64 `json:"kms"`
Actualkms float64 `json:"actualkms"`
Previouskms float64 `json:"previouskms"`
Cumulativekms float64 `json:"cumulativekms"`
Riderkms float64 `json:"riderkms"`
// 🔹 Amount summary
Charges float64 `json:"charges"`
Deliveryamt float64 `json:"deliveryamt"`
// 🔹 Collection summary
Quantity int `json:"quantity"`
Collectionamt float64 `json:"collectionamt"`
Collectedamt float64 `json:"collectedamt"`
Collectionstatus int `json:"collectionstatus"`
}
type Ridersummary struct {
Userid int `json:"userid"`
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
Ridercontact string `json:"ridercontact"`
Tenantid int `json:"tenantid"`
Tenantname string `json:"tenantname"`
Locationid int `json:"locationid"`
Locationname string `json:"locationname"`
Totalorders int `json:"totalorders"`
Pending int `json:"pending"`
Assigned int `json:"assigned"`
Accepted int `json:"accepted"`
Picked int `json:"picked"`
Arrived int `json:"arrived"`
Active int `json:"active"`
Skipped int `json:"skipped"`
Delivered int `json:"delivered"`
Cancelled int `json:"cancelled"`
Kms float64 `json:"kms" gorm:"type:numeric"`
Actualkms float64 `json:"actualkms" gorm:"type:numeric"`
Previouskms int `json:"previouskms"`
Cumulativekms int `json:"cumulativekms"`
Payondelivery float64 `json:"payondelivery" gorm:"type:numeric"`
Paylater float64 `json:"Paylater" gorm:"type:numeric"`
Deliveryamt float64 `json:"deliveryamt" gorm:"type:numeric"`
Status string `json:"status"`
Quantity int `josn:"quantity"`
Collectionamt float64 `json:"collectionamt" gorm:"type:numeric"`
Collectedamt float64 `json:"collectedamt" gorm:"type:numeric"`
Collectionstatus float64 `json:"collectionstatus" gorm:"type:numeric"`
}
type DeliveryQuery struct {
Tenantid int
Partnerid int
UserID int
Appuserid int
Applocationid int
Locationid int
Configid int
Fromdate string
ToDate string
Status string
Pageno int
Pagesize int
Conn *gorm.DB
Keyword string `json:"keyword"`
}

89
models/invoice.go Normal file
View File

@@ -0,0 +1,89 @@
package models
type Tenantsales struct {
Salesid int `json:"salesid" gorm:"Primary_Key"`
Transactiondate string `json:"transactiondate"`
Duedate string `json:"duedate"`
Applocationid int `json:"applocationid"`
Invoiceid string `json:"invoiceid"`
Invoiceno string `json:"invoiceno"`
Tenantid int `json:"tenantid"`
Pricingtypeid int `json:"pricingtypeid"`
Pricingtype string `json:"pricingtype"`
Tenantname string `json:"tenantname"`
Contactperson string `json:"contactperson"`
Address string `json:"address"`
Suburb string `json:"suburb"`
City string `json:"city"`
State string `json:"state"`
Itemcount int `json:"itemcount"`
Salesamount float32 `json:"salesamount"`
Discountpercent float32 `json:"discountpercent"`
Discountamt float32 `json:"discountamt"`
Taxpercent float32 `json:"taxpercent"`
Taxamount float32 `json:"taxamount"`
Totalamount float32 `json:"totalamount"`
Billstatus int `json:"billstatus"`
Billcancel int `json:"billcancel"`
Remarks string `json:"remarks"`
Referenceno string `json:"referenceno"`
Referencedate string `json:"referencedate" gorm:"default:NULL"`
Paymentremarks string `json:"paymentremarks"`
Status string `json:"status" gorm:"default:pending"`
Tenantsalesdetails []Tenantsalesdetails `json:"tenantsalesdetails" gorm:"ForeignKey:salesid"`
}
type Tenantsalesdetails struct {
Salesdetailid int `json:"salesdetailid" gorm:"Primary_Key"`
Salesid int `json:"salesid" `
Tenantid int `json:"tenantid"`
Particulars string `json:"particulars"`
Fromdate string `json:"fromdate"`
Todate string `json:"todate"`
Pricingtypeid int `json:"pricingtypeid"`
Pricingtype string `json:"pricingtype"`
Baserate float32 `json:"baserate"`
Quantity float32 `json:"quantity"`
Amount float32 `json:"amount"`
Othercharges float32 `json:"othercharges"`
Taxpercent float32 `json:"taxpercent"`
Taxamount float32 `json:"taxamount"`
Totalamount float32 `json:"totalamount"`
Billstatus int `json:"billstatus" gorm:"<-:false"`
Orderheaderid int `json:"orderheaderid" gorm:"<-:false"`
Orderid string `json:"orderid" gorm:"<-:false"`
Orderdate string `json:"orderdate" gorm:"<-:false"`
Pickup string `json:"pickup" gorm:"<-:false"`
Drop string `json:"drop" gorm:"<-:false"`
}
type InvoiceOrders struct {
Deliveries int `json:"deliveries"`
Kms int `json:"kms"`
Actualkms int `json:"actualkms"`
}
type InvoiceInsight struct {
Total float32 `json:"total"`
Totalcount int `json:"totalcount"`
Pending float32 `json:"pending"`
Pendingcount int `json:"pendingcount"`
Pendingpercent float32 `json:"pendingpercent"`
Confirmed float32 `json:"confirmed"`
Confirmedcount int `json:"confirmedcount"`
Confirmedpercent float32 `json:"confirmedpercent"`
Paid float32 `json:"paid"`
Paidcount int `json:"paidcount"`
Paidpercent float32 `json:"paidpercent"`
Overduecount int `json:"overduecount"`
Overdue float32 `json:"overdue"`
Overduepercent float32 `json:"overduepercent"`
}
type InvoiceStatus struct {
Salesid int `json:"salesid" gorm:"Primary_Key"`
Referenceno string `json:"Referenceno"`
Referencedate string `json:"referencedate"`
Billstatus int `json:"billstatus"`
Paymentremarks string `json:"paymentremarks"`
}

460
models/order.go Normal file
View File

@@ -0,0 +1,460 @@
package models
type OrderInfo struct {
Orderheaderid int `json:"orderheaderid"`
Applocationid int `json:"applocationid"`
Applocation string `json:"applocation"`
Tenantid int `json:"tenantid"`
Partnerid int `json:"partnerid"`
Locationid int `json:"locationid"`
Categoryid int `json:"categoryid"`
Subcategoryid int `json:"subcategoryid"`
Moduleid int `json:"moduleid"`
Configid int `json:"configid"`
Orderid string `json:"orderid"`
Orderdate string `json:"orderdate"`
Deliverydate string `json:"deliverydate"`
Orderstatus string `json:"orderstatus"`
Deliverystatus string `json:"deliverystatus"`
Deliveryamt float64 `json:"deliveryamt"`
Itemcount int `json:"itemcount"`
Ordernotes string `json:"ordernotes"`
Kms string `json:"kms"`
Actualkms string `json:"actualkms"`
Pending string `json:"Pending"`
Processing string `json:"processing"`
Ready string `json:"ready"`
Cancelled string `json:"cancelled"`
Delivered string `json:"delivered"`
Assigntime string `json:"assigntime"`
Starttime string `json:"starttime"`
Arrivaltime string `json:"arrivaltime"`
Pickuptime string `json:"pickuptime"`
Deliverytime string `json:"deliverytime"`
Canceltime string `json:"canceltime"`
Deliverycharge float64 `json:"deliverycharge"`
Orderamount float64 `json:"orderamount"`
Customerid int `json:"customerid"`
Pickupcustomer string `json:"pickupcustomer"`
Pickupcontactno string `json:"pickupcontactno"`
Pickuplocationid int `json:"pickuplocationid"`
Pickupaddress string `json:"pickupaddress"`
Pickupsuburb string `json:"pickupsuburb"`
Pickupcity string `json:"pickupcity"`
Pickuplat string `json:"pickuplat"`
Pickuplong string `json:"pickuplong"`
Pickupslot string `json:"pickupslot"`
Deliveryid int `json:"deliveryid"`
Deliverycustomerid int `json:"deliverycustomerid"`
Deliverycustomer string `json:"deliverycustomer"`
Deliverycontactno string `json:"deliverycontactno"`
Deliverylocationid int `json:"deliverylocationid"`
Deliveryaddress string `json:"deliveryaddress"`
Deliverysuburb string `json:"deliverysuburb"`
Droplat string `json:"droplat"`
Droplon string `json:"droplon"`
Deliverylat string `json:"deliverylat"`
Deliverylong string `json:"deliverylong"`
Deliverytype string `json:"deliverytype"`
Paymenttype int `json:"paymenttype"`
Tenantname string `json:"tenantname"`
Tenanttoken string `json:"tenanttoken"`
Tenantsuburb string `json:"tenantsuburb"`
Tenantcity string `json:"tenantcity"`
Tenantcontactno string `json:"tenantcontactno"`
Tenantpostcode string `json:"tenantpostcode"`
Tenantaddress string `json:"tenantaddress"`
Locationname string `json:"locationname"`
Locationsuburb string `json:"locationsuburb"`
Locationcity string `json:"locationcity"`
Locationcontactno string `json:"locationcontactno"`
Locationaddress string `json:"locationaddress"`
Rider string `json:"rider"`
Ridercontactno string `json:"ridercontactno"`
Riderkms string `json:"riderkms"`
Smsdelivery int `json:"smsdelivery"`
Customertoken string `json:"customertoken"`
Ridertoken string `json:"ridertoken"`
Previouskms int `json:"previouskms" gorm:"default:0"`
Cumulativekms int `json:"cumulativekms" gorm:"default:0"`
Step int `json:"step" gorm:"default:0"`
Eta string `json:"eta" gorm:"type:varchar(100);default:''"`
Quantity int `json:"quantity" gorm:"default:0"`
Collectionamt float64 `json:"collectionamt" gorm:"default:0"`
Slab string `json:"slab"`
Pricingdate string `json:"pricingdate"`
Baseprice float64 `json:"baseprice"`
Minkm int `json:"minkm"`
Priceperkm float64 `json:"priceperkm"`
Maxkm int `json:"maxkm"`
Orders int `json:"orders"`
Othercharges float64 `json:"othercharges"`
Surgecharges float64 `json:"surgecharges"`
}
// type TenantOrders struct {
// Orderheaderid int `json:"orderheaderid"`
// Tenantid int `json:"tenantid"`
// Locationid int `json:"locationid"`
// Categoryid int `json:"categoryid"`
// Subcategoryid int `json:"subcategoryid"`
// Moduleid int `json:"moduleid"`
// Configid int `json:"configid"`
// Orderid string `json:"orderid"`
// Customerid int `json:"customerid"`
// Customername string `json:"customername"`
// Contactno string `json:"contactno"`
// Deliverydate string `json:"deliverydate"`
// Orderstatus string `json:"orderstatus"`
// Starttime string `json:"starttime"`
// Arrivaltime string `json:"arrivaltime"`
// Pickuptime string `json:"pickuptime"`
// Deliverytime string `json:"deliverytime"`
// Deliveryaddress string `json:"deliveryaddress"`
// Deliverylat string `json:"deliverylat"`
// Deliverylong string `json:"deliverylong"`
// Pickupaddress string `json:"pickupaddress"`
// Pickuplat string `json:"pickuplat"`
// Pickuplong string `json:"pickuplong"`
// Droplat string `json:"droplat"`
// Droplon string `json:"droplon"`
// Notes string `json:"notes"`
// Ordernotes string `json:"ordernotes"`
// Locationname string `json:"locationname"`
// }
type Ordersequences struct {
Sequenceid int `json:"sequenceid" gorm:"Primary_Key"`
Tenantid int `json:"tenantid"`
Orderprefix string `json:"orderprefix" gorm:"default:ORD"`
Customerprefix string `json:"customerprefix" gorm:"default:CUS"`
Appointmentprefix string `json:"appointmentprefix" gorm:"default:ORD"`
Receiptprefix string `json:"receiptprefix" gorm:"default:REC"`
Paymentprefix string `json:"paymentprefix" gorm:"default:PAY"`
}
type Orders struct {
Orderheaderid int `json:"orderheaderid" gorm:"Primary_Key"`
Tenantid int `json:"tenantid"`
Locationid int `json:"locationid"`
Applocationid int `json:"applocationid"`
Moduleid int `json:"moduleid"`
Partnerid int `json:"partnerid"`
Configid int `json:"configid"`
Categoryid int `json:"categoryid"`
Subcategoryid int `json:"subcategoryid"`
Orderid string `json:"orderid"`
Orderdate string `json:"orderdate,omitempty"`
Deliverytime string `json:"deliverytime"`
Deliverytype string `json:"deliverytype"`
Orderstatus string `json:"orderstatus"`
Pending string `json:"pending"`
Processing string `json:"processing"`
Ready string `json:"ready"`
Delivered string `json:"delivered"`
Cancelled string `json:"cancelled"`
Customerid int `json:"customerid"`
Pickupcustomer string `json:"pickupcustomer"`
Pickupcontactno string `json:"pickupcontactno"`
Pickuplandmark string `json:"pickuplandmark"`
Pickuplocationid int `json:"pickuplocationid"`
Pickupaddress string `json:"pickupaddress"`
Pickuplocation string `json:"pickuplocation"`
Pickupcity string `json:"pickupcity"`
Pickuplat string `json:"pickuplat"`
Pickuplong string `json:"pickuplong"`
Pickupslot string `json:"pickupslot"`
Deliveryid int `json:"deliveryid"`
Deliverylocationid int `json:"deliverylocationid"`
Deliverycustomer string `json:"deliverycustomer"`
Deliverycontactno string `json:"deliverycontactno"`
Deliverylandmark string `json:"deliverylandmark"`
Deliverylocation string `json:"deliverylocation"`
Deliverycity string `json:"deliverycity"`
Deliveryaddress string `json:"deliveryaddress"`
Deliverylat string `json:"deliverylat"`
Deliverylong string `json:"deliverylong"`
Promotionid int `json:"promotionid"`
Promoname string `json:"promoname"`
Promoterms string `json:"promoterms"`
Promovalue int `json:"promovalue"`
Promoamount float64 `json:"promoamount" gorm:"type:numeric"`
Orderamount float64 `json:"orderamount" gorm:"type:numeric"`
Taxamount float64 `json:"taxamount" gorm:"type:numeric"`
Ordercharges float64 `json:"ordercharges" gorm:"type:numeric"`
Ordervalue float64 `json:"ordervalue" gorm:"type:numeric"`
Itemcount int `json:"itemcount"`
Paymenttype int `json:"paymenttype"`
Paymentstatus int `json:"paymentstatus"`
Deliverycharge float64 `json:"deliverycharge" gorm:"type:numeric"`
Ordernotes string `json:"ordernotes"`
Kms string `json:"kms"`
Remarks string `json:"remarks"`
Tenantuserid int `json:"tenantuserid"`
Partneruserid int `json:"partneruserid"`
Smsdelivery int `json:"smsdelivery" gorm:"default:0"`
Quantity int `josn:"quantity"`
Collectionamt float64 `json:"collectionamt" gorm:"type:numeric"`
Items []OrderDetail `json:"items" gorm:"-"`
}
type OrderDetail struct {
Orderdetailid int `json:"orderdetailid" gorm:"primaryKey;autoIncrement"`
Orderheaderid int `json:"orderheaderid"`
Tenantid int `json:"tenantid"`
Locationid int `json:"locationid"`
Productid int `json:"productid"`
Productname string `json:"productname"`
Productdescription string `json:"productdescription"`
Supplyqty float64 `json:"supplyqty"`
Balanceqty float64 `json:"balanceqty"`
Orderqty float64 `json:"orderqty"`
Price float64 `json:"price"`
Unitid int `json:"unitid"`
Unitname string `json:"unitname"`
Productaddonid int `json:"productaddonid"`
Addontypeid int `json:"addontypeid"`
Productmapid int `json:"productmapid"`
Productvariantid int `json:"productvariantid"`
Productaddondescription string `json:"productaddondescription"`
Discountid int `json:"discountid"`
Discountname string `json:"discountname"`
Discountcode string `json:"discountcode"`
Discountterms string `json:"discountterms"`
Discountpercentage float64 `json:"discountpercentage"`
Discountamount float64 `json:"discountamount"`
Landingamount float64 `json:"landingamount"`
Taxpercentage float64 `json:"taxpercentage"`
Taxamount float64 `json:"taxamount"`
Productsumprice float64 `json:"productsumprice"`
Itemstatus string `json:"itemstatus"`
Delivered string `json:"delivered"`
Orderamount float64 `json:"-" gorm:"-"`
Productimage string `json:"productimage" gorm:"-"` // only for JSON
}
// ✅ GORM will now use `orderdetails` instead of `order_details`
func (OrderDetail) TableName() string {
return "orderdetails"
}
type OrderDetails struct {
Orderdetailid int `json:"orderdetailid" gorm:"primaryKey;autoIncrement"`
Orderheaderid int `json:"orderheaderid"`
Tenantid int `json:"tenantid"`
Locationid int `json:"locationid"`
Productid int `json:"productid"`
Productname string `json:"productname"`
Productdescription string `json:"productdescription"`
Supplyqty float64 `json:"supplyqty"`
Balanceqty float64 `json:"balanceqty"`
Orderqty float64 `json:"orderqty"`
Price float64 `json:"price"`
Unitid int `json:"unitid"`
Unitname string `json:"unitname"`
Productaddonid int `json:"productaddonid"`
Addontypeid int `json:"addontypeid"`
Productmapid int `json:"productmapid"`
Productvariantid int `json:"productvariantid"`
Productaddondescription string `json:"productaddondescription"`
Discountid int `json:"discountid"`
Discountname string `json:"discountname"`
Discountcode string `json:"discountcode"`
Discountterms string `json:"discountterms"`
Discountpercentage float64 `json:"discountpercentage"`
Discountamount float64 `json:"discountamount"`
Landingamount float64 `json:"landingamount"`
Taxpercentage float64 `json:"taxpercentage"`
Taxamount float64 `json:"taxamount"`
Totaltaxamount float64 `json:"totaltaxamount"`
Productsumprice float64 `json:"productsumprice"`
Itemstatus string `json:"itemstatus"`
Delivered string `json:"delivered"`
Orderamount float64 `json:"Orderamount"` // 👈 Correct way
Productimage string `json:"productimage"` // only for JSON
}
func (OrderDetails) TableName() string {
return "orderdetails"
}
type Customerorder struct {
Orders Orders `json:"orders"`
Pickup Customers `json:"pickup"`
Drop Customers `json:"drop"`
}
type CustomerorderV2 struct {
Orders Orders `json:"orders"`
}
type Updateorderstatus struct {
Orderheaderid int `json:"Orderheaderid"`
Orderstatus string `json:"Orderstatus"`
Pending string `json:"pending"`
Processing string `json:"processing"`
Cancelled string `json:"cancelled"`
Delivered string `json:"delivered"`
Userid int `json:"userid"`
}
type Ordersummary struct {
Total int `json:"total"`
Created int `json:"created"`
Pending int `json:"pending"`
Processing int `json:"processing"`
Delivered int `json:"delivered"`
Cancelled int `json:"cancelled"`
Locationname string `json:"locationname"`
Applocationid string `json:"applocationid"`
}
type Ordersummarydaily struct {
Total int `json:"total"`
Created int `json:"created"`
Pending int `json:"pending"`
Processing int `json:"processing"`
Delivered int `json:"delivered"`
Cancelled int `json:"cancelled"`
Tenantid int `json:"tenantid"`
Tenantname string `json:"tenantname"`
}
type Ordersummarylocation struct {
Total int `json:"total"`
Created int `json:"created"`
Pending int `json:"pending"`
Processing int `json:"processing"`
Delivered int `json:"delivered"`
Cancelled int `json:"cancelled"`
Locationid int `json:"locationid"`
Locationname string `json:"locationname"`
}
type OrderInsight struct {
Applocationid int `json:"applocationid" gorm:"Primary_Key"`
Locationname string `json:"locationname"`
Ordermonths *Ordermonths `json:"ordermonths" gorm:"-"`
}
type OrderInsightv1 struct {
Locationid int `json:"locationid" gorm:"Primary_Key"`
Locationname string `json:"locationname"`
Ordermonths *Ordermonths `json:"ordermonths" gorm:"-"`
}
type Ordermonths struct {
Jan int `json:"jan"`
Feb int `json:"feb"`
Mar int `json:"mar"`
Apr int `json:"apr"`
May int `json:"may"`
Jun int `json:"jun"`
Jul int `json:"jul"`
Aug int `Json:"aug"`
Sep int `Json:"sep"`
Oct int `Json:"oct"`
Nov int `Json:"nov"`
Dece int `Json:"dece"`
// Applocationid int `json:"applocationid"`
}
type CustomerOrder struct {
Orderheaderid int `json:"orderheaderid" gorm:"Primary_Key"`
Applocationid int `json:"applocationid"`
Tenantid int `json:"tenantid"`
Locationid int `json:"locationid"`
Partnerid int `json:"partnerid"`
Configid int `json:"configid"`
Categoryid int `json:"categoryid"`
Subcategoryid int `json:"subcategoryid"`
Moduleid int `json:"moduleid"`
Orderid string `json:"orderid"`
Orderstatus string `json:"orderstatus"`
Orderdate string `json:"orderdate,omitempty"`
Ordernotes string `json:"ordernotes"`
Itemcount int `json:"itemcount"`
Deliverytime string `json:"deliverytime"` // alias for delivered
Pending string `json:"pending"`
Processing string `json:"processing"`
Ready string `json:"ready"`
Delivered string `json:"delivered"` // original delivered column
Cancelled string `json:"cancelled"`
Deliverycharge float32 `json:"deliverycharge"`
Kms string `json:"kms"`
Customerid int `json:"customerid"`
Pickupaddress string `json:"pickupaddress"`
Pickuplat string `json:"pickuplat"`
Pickuplong string `json:"pickuplong"`
Pickupcustomer string `json:"pickupcustomer"`
Pickupcontactno string `json:"pickupcontactno"`
Pickuplocation string `json:"pickupsuburb"` // alias
Pickupcity string `json:"pickupcity"`
Deliveryid int `json:"deliverycustomerid"` // alias
Deliveryaddress string `json:"deliveryaddress"`
Deliverylat string `json:"deliverylat"`
Deliverylong string `json:"deliverylong"`
Deliverytype string `json:"deliverytype"`
Deliverycustomer string `json:"deliverycustomer"`
Deliverycontactno string `json:"deliverycontactno"`
Deliverylocation string `json:"deliverysuburb"` // alias
Deliverycity string `json:"deliverycity"`
Paymenttype int `json:"paymenttype"`
Smsdelivery int `json:"smsdelivery"`
// Tenant Info
Tenantname string `json:"tenantname"`
Tenanttoken string `json:"tenanttoken"`
Tenantcontactno string `json:"tenantcontactno"`
Tenantpostcode string `json:"tenantpostcode"`
Tenantsuburb string `json:"tenantsuburb"`
Tenantcity string `json:"tenantcity"`
// Location Info
Locationname string `json:"locationname"`
Locationcontactno string `json:"locationcontactno"`
Locationpostcode string `json:"locationpostcode"`
Locationsuburb string `json:"locationsuburb"`
Locationcity string `json:"locationcity"`
// App Location
Applocation string `json:"applocation"`
// Delivery Info (from `deliveries` table)
Deliverystatus string `json:"deliverystatus"`
DeliveryUserID int `json:"deliveryid"` // alias
Assigntime string `json:"assigntime"`
Starttime string `json:"starttime"`
Arrivaltime string `json:"arrivaltime"`
Pickuptime string `json:"pickuptime"`
Finaldeliverytime string `json:"finaldeliverytime"` // alias for f.deliverytime
Canceltime string `json:"canceltime"`
// Actualkms sql.NullFloat64 `json:"actualkms"`
// Riderkms sql.NullFloat64 `json:"riderkms"`
// Deliveryamt sql.NullFloat64 `json:"deliveryamt"`
Droplat string `json:"droplat"`
Droplon string `json:"droplon"`
// Rider
Rider string `json:"rider"`
Orderamount float64 `json:"orderamount"`
Taxamount float64 `json:"taxamount"`
// Items if applicable
OrderDetails []OrderDetails `json:"orderdetails" gorm:"-"`
}
type CustomerOrderLocation struct {
Locationname string `json:"locationname" gorm:"column:locationname"`
Ordercount int `json:"ordercount" gorm:"column:ordercount"`
Contactno string `json:"contactno" gorm:"column:contactno"`
Address string `json:"address" gorm:"column:address"`
Suburb string `json:"suburb" gorm:"column:suburb"`
City string `json:"city" gorm:"column:city"`
State string `json:"state" gorm:"column:state"`
Postcode string `json:"postcode" gorm:"column:postcode"`
Latitude float64 `json:"latitude" gorm:"column:latitude"`
Longitude float64 `json:"longitude" gorm:"column:longitude"`
}

353
models/partner.go Normal file
View File

@@ -0,0 +1,353 @@
package models
import (
"time"
)
type RiderPoolResult struct {
Status bool `json:"status"`
Code int `json:"code"`
Message string `json:"message"`
Details []RiderPool `json:"Details"`
}
type RiderPool struct {
Poolid int `json:"poolid"`
Userid int `json:"userid"`
Partnerid int `json:"partnerid"`
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
Fullname string `json:"fullname"`
Email string `json:"email"`
Contactno string `json:"contactno"`
Userfcmtoken string `json:"userfcmtoken"`
Identificationno string `json:"identificationno"`
Vehicleid int `json:"vehicleid"`
Vehiclename string `json:"vehiclename"`
Registrationno string `json:"registrationno"`
Licenseno string `json:"licenseno"`
Shiftid int `json:"shiftid"`
Starttime string `json:"starttime"`
Endtime string `json:"endtime"`
Shifthours float32 `json:"shifthours"`
Basefare float32 `json:"basefare"`
Fuelcharge float32 `json:"fuelcharge"`
Applocationid int `json:"applocationid"`
Status string `json:"status"`
}
type Partnerinfo struct {
Partnerid int `json:"partnerid" gorm:"Primary_Key"`
Partnertypeid int `json:"partnertypeid"`
Applocationid int `json:"applocationid"`
Partnername string `json:"partnername"`
Registrationno string `json:"registrationno"`
Primarycontact string `json:"primartcontact"`
Primaryemail string `json:"primaryemail"`
Contactno string `json:"contactno"`
Bizcategoryid int `json:"bizcategoryid"`
Bizsubcategoryid int `json:"bizsubcategoryid"`
Adderss string `json:"address"`
Suburb string `json:"suburb"`
State string `json:"state"`
City string `json:"city"`
Postcode string `json:"postcode"`
Partnerinfo string `json:"partnerinfo"`
Partnerimage string `json:"partnerimage"`
}
type AdminToken struct {
Userid int `json:"userid"`
Userfcmtoken string `json:"userfcmtokem"`
Notify string `json:"notify"`
Applocationid int `json:"applocationid"`
Closetime string `json:"closetime"`
Opentime string `json:"opentime"`
Tenantid int `json:"tenantid"`
}
type Rider struct {
Userid int `json:"userid" gorm:"primaryKey"`
Authname string `json:"authname"`
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
Password string `json:"password"`
Email string `json:"email"`
Contactno string `json:"contactno"`
Configid int `json:"configid"`
Authmode int `json:"authmode"`
Roleid int `json:"roleid"`
Pin int `json:"pin"`
Deviceid string `json:"deviceid"`
Devicetype string `json:"devicetype"`
Userfcmtoken string `json:"userfcmtoken"`
Address string `json:"address"`
Suburb string `json:"suburb"`
City string `json:"city"`
State string `json:"state"`
Postcode string `json:"postcode"`
Partnerid int `json:"partnerid"`
Tenantid int `json:"tenantid"`
Locationid int `json:"locationid"`
Applocationid int `json:"applocationid"`
Latitude string `json:"latitude"`
Longitude string `json:"longitude"`
Name string `json:"name"`
Capacity int `json:"capacity"`
Rangekm int `json:"rangekm"`
Batterypercentage int `json:"batterypercentage"`
Type string `json:"type"`
Status string `json:"status" gorm:"column:status;default:InActive"`
Ridersettings Ridersettings `json:"ridersettings" gorm:"-"`
}
type RiderDetails struct {
Userid int `json:"userid"`
Authname string `json:"authname"`
Configid int `json:"configid"`
Authmode int `json:"authmode"`
Roleid int `json:"roleid"`
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
Fullname string `json:"fullname"`
Password string `json:"password"`
Email string `json:"email"`
Contactno string `json:"contactno"`
Address string `json:"address"`
Suburb string `json:"suburb"`
City string `json:"city"`
State string `json:"state"`
Postcode string `json:"postcode"`
Userfcmtoken string `json:"userfcmtoken"`
Pin int `json:"pin"`
Partnerid int `json:"partnerid"`
Riderid int `json:"riderid"`
Identificationno string `json:"identificationno"`
Shiftid int `json:"shiftid"`
Starttime string `json:"starttime"`
Endtime string `json:"endtime"`
Shifthours float32 `json:"shifthours"`
Basefare float32 `json:"basefare"`
Additionalcharges float32 `json:"additionalcharges"`
Additionalkm float32 `json:"additionalkm"`
Orders int `json:"orders"`
Fuelcharge float32 `json:"fuelcharge"`
Accountno string `json:"accountno"`
Accountname string `json:"accountname"`
Accounttypeid int `json:"accounttypeid"`
Accounttype string `json:"accounttype"`
Bankname string `json:"bankname"`
Ifsccode string `json:"ifsccode"`
Branch string `json:"branch"`
Vehicleid int `json:"vehicleid"`
Vehiclename string `json:"vehiclename"`
Vehicleno string `json:"vehicleno"`
Model string `json:"model"`
Color string `json:"color"`
Licenseno string `json:"licenseno"`
Insuranceno string `json:"insuranceno"`
Insurancedate string `json:"insurancedate"`
Applocationid int `json:"applocationid"`
Status string `json:"status"`
}
type Ridersettings struct {
Riderid int `json:"riderid" grom:"Primary_Key"`
Userid int `json:"userid"`
Partnerid int `json:"partnerid"`
Shiftid int `json:"shiftid"`
Identificationno string `json:"identificationno"`
Basefare float32 `json:"basefare"`
Additionalkm float32 `json:"additionalkm"`
Additionalcharges float32 `json:"additionalcharges"`
Accountno string `json:"accountno"`
Accountname string `json:"accountname"`
Accounttypeid int `json:"accounttypeid"`
Accounttype string `json:"accounttype"`
Bankname string `json:"bankname"`
Ifsccode string `json:"ifsccode"`
Branch string `json:"branch"`
Vehicleid int `json:"vehicleid"`
Vehiclename string `json:"vehiclename"`
Vehicleno string `json:"vehicleno"`
Model string `json:"model"`
Color string `json:"color"`
Licenseno string `json:"licenseno"`
Insuranceno string `json:"insuranceno"`
Insurancedate string `json:"insurancedate"`
Status int `json:"status"`
}
type Ridershifts struct {
Shiftid int `json:"shiftid" gorm:"Primary_Key"`
Shiftdate string `json:"shiftdate"`
Starttime string `json:"starttime"`
Endtime string `json:"endtime"`
Shifthours float32 `json:"shifthours"`
Basefare float32 `json:"basefare"`
Additionalkm float32 `json:"additionalkm"`
Additionalcharges float32 `json:"additionalcharges"`
Orders int `json:"orders"`
Fuelcharge float32 `json:"fuelcharge"`
Shiftname string `json:"shiftname" gorm:"<-:false"`
}
type Riderlogs struct {
Logid int `json:"logid" gorm:"Primary_Key"`
Logdate string `json:"logdate"`
Userid int `json:"userid"`
Partnerid int `json:"partnerid"`
Shiftid int `json:"shiftid"`
Shifthours float64 `json:"shifthours" gorm:"type:numeric"`
Login string `json:"login,omitempty" gorm:"column:login;default:NULL"`
Logout string `json:"logout,omitempty" gorm:"column:logout;default:NULL"`
Latitude string `json:"latitude"`
Workhours float64 `json:"workhours" gorm:"type:numeric"`
Shorthours float64 `json:"shorthours" gorm:"type:numeric"`
Logstatus int `json:"logstatus"`
Longitude string `json:"longitude"`
Status string `json:"status"`
Breakhours float32 `json:"breakhours" gorm:"<-:false"`
Onduty int `json:"onduty" gorm:"<-:false"`
Firstname string `json:"firstname" gorm:"<-:false"`
Lastname string `json:"lastname" gorm:"<-:false"`
Username string `json:"username"`
Contactno string `json:"contactno"`
Userfcmtoken string `json:"userfcmtoken"`
Applocationid int `json:"applocationid"`
Tenantid int `json:"tenantid"`
Locationid int `json:"locationid"`
Orderid string `json:"orderid"`
Raw_latitude string `json:"raw_latitude"`
Raw_longitude string `json:"raw_longitude"`
Velocity_lat string `json:"velocity_lat"`
Velocity_long string `json:"velocity_long"`
Speed string `json:"speed"`
Heading string `json:"heading"`
}
type Riderlogsv1 struct {
Logid int `json:"logid" gorm:"Primary_Key"`
Logdate string `json:"logdate"`
Userid int `json:"userid"`
Partnerid int `json:"partnerid"`
Shiftid int `json:"shiftid"`
Shifthours float32 `json:"shifthours"`
Login string `json:"login,omitempty" gorm:"column:login;default:NULL"`
Logout string `json:"logout,omitempty" gorm:"column:logout;default:NULL"`
Latitude string `json:"latitude"`
Workhours float32 `json:"workhours"`
Shorthours float32 `json:"shorthours"`
Logstatus int `json:"logstatus"`
Longitude string `json:"longitude"`
Breakhours float32 `json:"breakhours" `
Onduty int `json:"onduty" `
Status string `json:"status"`
Firstname string `json:"firstname" `
Lastname string `json:"lastname" `
Contactno string `json:"contactno" `
Username string `json:"username" `
Userfcmtoken string `json:"userfcmtoken"`
Applocationid int `json:"applocationid"`
Tenantid int `json:"tenantid"`
Locationid int `json:"locationid"`
Orderid string `json:"orderid"`
}
type Riderbreaks struct {
Breakid int `json:"breakid" gorm:"Primary_Key"`
Logid int `json:"logid"`
Breakdate string `json:"breakdate"`
Userid int `json:"userid"`
Partnerid int `json:"partnerid"`
Shiftid int `json:"shiftid"`
Breakstart string `json:"breakstart,omitempty" gorm:"column:breakstart;default:NULL"`
Breakend string `json:"breakend,omitempty" gorm:"column:breakend;default:NULL"`
Latitude string `json:"latitude"`
Longitude string `json:"longitude"`
Breakhours float32 `json:"breakhours"`
}
type RiderlogDetails struct {
Logid int `json:"logid"`
Logdate string `json:"logdate"`
Userid int `json:"userid"`
Username string `json:"username"`
Partnerid int `json:"partnerid"`
Shiftid int `json:"shiftid"`
Shifthours float32 `json:"shifthours"`
Login string `json:"login"`
Logout string `json:"logout"`
Latitude string `json:"latitude"`
Longitude string `json:"longitude"`
Workhours float32 `json:"workhours"`
Shorthours float32 `json:"shorthours"`
Breakhours float32 `json:"breakhours"`
Logstatus int `json:"logstatus"`
}
type Userpools struct {
Poolid int `json:"poolid" gorm:"primaryKey;autoIncrement"`
Userid int `json:"userid"`
Partnerid int `json:"partnerid"`
Vehicleid int `json:"vehicleid"`
Onduty int `json:"onduty" gorm:"column:onduty;default:0"`
Status string `json:"status" gorm:"column:status;default:idle"`
}
type Locationconfigs struct {
Applocationid int `json:"applocationid"`
Configid int `json:"configid"`
Locationname string `json:"locationname"`
Latitude string `json:"latitude"`
Longitude string `json:"longitude"`
Status string `json:"status"`
}
type DeliveryStats struct {
Today int `json:"today"`
Week int `json:"week"`
Month int `json:"month"`
Total int `json:"total"`
Cancelled int `json:"cancelled"`
}
type RiderPricing struct {
Shiftid int `json:"shiftid"`
Basefare float32 `json:"basefare"`
Additionalcharges float32 `json:"additionalcharges"`
Fuelcharge float32 `json:"fuelcharge"`
Applocationid int `json:"applocationid"`
Locationname string `json:"locationname"`
}
type RiderKms struct {
Day string `json:"day"`
Kms float64 `json:"kms"`
}
type RiderWeeklyKms struct {
Details []RiderKms `json:"details"`
TotalKms float64 `json:"totalkms"`
OverallKms float64 `json:"overallkms"`
}
type RiderSupport struct {
Ridersupportid int `json:"ridersupportid" gorm:"primaryKey;autoIncrement"`
Userid int `json:"userid"`
Category string `json:"category"`
Priority string `json:"priority"`
Subject string `json:"subject"`
Issue string `json:"issue"`
Image string `json:"image"`
Created time.Time `json:"created" gorm:"autoCreateTime"`
Updated time.Time `json:"updated" gorm:"autoUpdateTime"`
}
type RidersSummary struct {
Active int `json:"active"`
Inactive int `json:"inactive"`
Total int `json:"total"`
}

46
models/payments.go Normal file
View File

@@ -0,0 +1,46 @@
package models
type Paymentrequests struct {
Requestid int `json:"requestid" gorm:"Primary_Key"`
Partnerid int `json:"partnerid"`
Requestdate string `json:"requestdate"`
Referenceno string `json:"referenceno"`
Apptypeid int `json:"apptypeid"`
Requesttype int `json:"requestype"`
Reason string `json:"reason"`
Userid int `json:"userid"`
Requestor string `json:"requestor"`
Amount float32 `json:"amount"`
Accountno string `json:"accountno"`
Bankname string `json:"bankname"`
Ifsccode string `json:"ifsccode"`
Status int `json:"status"`
}
type RequestInfo struct {
Requestid int `json:"requestid"`
Requestdate string `json:"requestdate"`
Referenceno string `json:"referenceno"`
Apptypeid int `json:"apptypeid"`
Requesttype int `json:"requestype"`
Reason string `json:"reason"`
Userid int `json:"userid"`
Requestor string `json:"requestor"`
Amount float32 `json:"amount"`
Accountno string `json:"accountno"`
Bankname string `json:"bankname"`
Ifsccode string `json:"ifsccode"`
Paymentref string `json:"paymentref"`
Paymentdate string `json:"paymentdate"`
Status int `json:"status"`
}
type Paymentdetails struct {
Paymentdetailsid int `json:"Paymentdetailsid" gorm:"Primary_Key"`
Requestid int `json:"requestid"`
Userid int `json:"userid"`
Paymentdate string `json:"paymentdate"`
Referenceno string `json:"referenceno"`
Amount float32 `json:"amount"`
Status int `json:"status"`
}

23
models/platform.go Normal file
View File

@@ -0,0 +1,23 @@
package models
type AppModules struct {
Moduleid int `json:"moduleid"`
Modulename string `json:"modulename"`
Logourl string `json:"logourl"`
Business int `json:"business"`
Orders int `json:"orders"`
}
type Smsproviders struct {
Providerid int `json:"providerid"`
Templatetypeid int `json:"templatetypeid"`
Templatename string `json:"templatename"`
Templateid int `json:"templateid"`
Providerapi string `json:"providerapi"`
Content string `json:"content"`
Defaultprovider int `json:"defaultprovider"`
Passkey int `json:"passkey"`
}
// https://msg.lionsms.com/api/smsapi?key=e57f5c9679af26077be1a7eadabb1b2a&route=7&sender=NEARLE&number=&templateid=1107168725266104678&sms=

258
models/product.go Normal file
View File

@@ -0,0 +1,258 @@
package models
import (
"time"
)
type Products struct {
Productid int `json:"productid"`
AppLocationid int `json:"applocationid" gorm:"column:applocationid"`
Tenantid *int `json:"tenantid,omitempty"`
Categoryid int `json:"categoryid"`
Categoryname string `json:"categoryname" gorm:"->"`
Subcategoryid *int `json:"subcategoryid,omitempty"`
Subcategoryname string `json:"Subcategoryname" gorm:"->"`
Catalogueid *int `json:"catalogueid,omitempty"`
Addonid *int `json:"addonid,omitempty"`
Discountid *int `json:"discountid,omitempty"`
Pricingid *int `json:"pricingid,omitempty"`
Productname *string `json:"productname,omitempty"`
Productimage *string `json:"productimage,omitempty"`
Productdesc *string `json:"productdesc,omitempty"`
Productsku *string `json:"productsku,omitempty"`
Brandid *int `json:"brandid,omitempty"`
Productbrand *string `json:"productbrand,omitempty"`
Productunit *string `json:"productunit,omitempty"`
Unitvalue *string `json:"unitvalue,omitempty"`
Toppicks *string `json:"toppicks,omitempty"`
Productcost *float64 `json:"productcost,omitempty"`
Taxamount *float64 `json:"taxamount,omitempty"`
Taxpercent *float64 `json:"taxpercent,omitempty"`
Producttax *int `json:"producttax" gorm:"default:0"`
Productstock *int `json:"productstock" gorm:"default:0"`
Productcombo *int `json:"productcombo" gorm:"default:0"`
Variants int `json:"variants" gorm:"default:0"`
Quantity int `json:"quantity"`
Retailprice float64 `json:"retailprice,omitempty"`
Diffprice float64 `json:"diffprice,omitempty"`
Diffpercent float64 `json:"diffpercent,omitempty"`
Othercost float64 `json:"othercost,omitempty"`
Approve *int `json:"approve" gorm:"default:0"`
Productstatus string `json:"productstatus" gorm:"default:available"`
}
type ProductCategory struct {
Categoryid int `json:"categoryid"`
Moduleid int `json:"moduleid"`
Tenantid *int `json:"tenantid,omitempty"`
Categorytypeid *int `json:"categorytypeid,omitempty"`
Categoryname *string `json:"categoryname,omitempty"`
Image *string `json:"image,omitempty"`
Catalougecategoryid *int `json:"catalougecategoryid,omitempty"`
Sortorder *int `json:"sortorder,omitempty"`
Status string `json:"status"`
Createdby *int `json:"createdby,omitempty"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
}
type Productstockstatement struct {
Productid int `json:"productid"`
Productname string `json:"productname"`
Productimage string `json:"productimage"`
Categoryid int `json:"categoryid"`
Subcategoryid int `json:"subcategoryid"`
Productunit string `json:"productunit"`
Unitvalue string `json:"unitvalue"`
Productcost float32 `json:"productcost"`
Taxpercent float32 `json:"taxpercent"`
Taxamount float32 `json:"taxamount"`
Retailprice float32 `json:"retailprice"`
Tenantid int `json:"tenantid"`
Locationid int `json:"locationid"`
Opening int `json:"opening"`
Credit int `json:"credit"`
Debit int `json:"debit"`
Closing int `json:"closing"`
}
type Productcount struct {
Total int `json:"total"`
Available int `json:"available"`
Outofstock int `json:"outofstock"`
}
type ProductSubCategory struct {
Subcatid int `json:"subcatid"`
Categoryid int `json:"categoryid,omitempty"`
Tenantid int `json:"tenantid,omitempty"`
Subcatname string `json:"subcatname,omitempty"`
Image string `json:"image,omitempty"`
Status string `json:"status,omitempty"`
Sortorder int `json:"sortorder,omitempty"`
Createdby int `json:"createdby,omitempty"`
Created time.Time `json:"created,omitempty"`
Updated time.Time `json:"updated,omitempty"`
}
// Struct to match the `productsubcategories` table
type Subcategory struct {
Subcategoryid int `json:"subcategoryid" gorm:"column:subcatid"`
Subcategoryname string `json:"subcategoryname" gorm:"column:subcatname"`
Categoryid int `json:"categoryid" gorm:"column:categoryid"`
}
// Response format
type SubcategoryProductResponse struct {
SubcategoryID int `json:"subcategoryid"`
SubcategoryName string `json:"subcategoryname"`
Products []Products `json:"products"`
}
type TenantInfo struct {
Tenantid int `json:"tenantid"`
Tenantname string `json:"tenantname"`
Address string `json:"address"`
Licenseno string `json:"licenseno"`
Primaryemail string `json:"primaryemail"`
Primarycontact string `json:"primarycontact"`
Pickuplocationid int `json:"pickuplocationid"`
Applocationid int `json:"applocationid"`
Suburb string `json:"suburb"`
City string `json:"city"`
Latitude string `json:"latitude"`
Longitude string `json:"longitude"`
Postcode string `json:"postcode"`
Tenantimage string `json:"tenantimage"`
Locationid int `json:"locationid"`
Locationname string `json:"locationname"`
Subcategoryid int `json:"subcategoryid"`
Categoryid int `json:"categoryid"`
Registrationno string `json:"registrationno"`
}
type ProductListResponse struct {
Tenantid int `json:"tenantid"`
Tenantname string `json:"tenantname"`
Address string `json:"address"`
Licenseno string `json:"licenseno"`
Primaryemail string `json:"primaryemail"`
Pickupcontactno string `json:"primarycontact"`
Applocationid int `json:"applocationid"`
Pickuplocationid int `json:"pickuplocationid"`
Pickupsuburb string `json:"suburb"`
Pickupcity string `json:"city"`
Pickuplat string `json:"pickuplat"`
Pickuplong string `json:"pickuplong"`
Tenantpostcode string `json:"postcode"`
Locationname string `json:"locationname"`
Categoryname string `json:"categoryname"`
Products []Products `json:"products"`
}
type Tenantproducts struct {
Tenant TenantInfo `json:"tenant"`
Products []Products `json:"products"`
}
type Productvariant struct {
Variantid int `json:"variantid" gorm:"Primary_Key"`
Tenantid int `json:"tenantid"`
Variantname string `json:"variantname"`
Categoryid int `json:"categoryid" gorm:"default:0"`
Categoryname string `json:"categoryname" gorm:"-"`
Subcategoryid int `json:"subcategoryid"`
Status string `json:"status" gorm:"default:active"`
}
type Productlocations struct {
Productlocationid int `json:"productlocationid" gorm:"Primary_Key"`
Tenantid int `json:"tenantid"`
Locationid int `json:"locationid"`
Productid int `json:"productid"`
Catlougeid int `json:"catlougeid"`
Minquantity int `json:"minquantity" gorm:"default:0"`
Maxquantity int `json:"maxquantity" gorm:"default:0"`
Price float32 `json:"price" gorm:"default:0.0"`
Quantity int `json:"quantity" gorm:"<-:false"`
Stocktype string `json:"stocktype" gorm:"<-:false"`
Status string `json:"status"`
}
type Productstock struct {
Productstockid int `json:"productstockid" gorm:"Primary_Key"`
Tenantid int `json:"tenantid"`
Stockdate time.Time `json:"stockdate"`
Locationid int `json:"locationid"`
Productid int `json:"productid"`
Quantity int `json:"quantity"`
Stocktype string `json:"stocktype"`
Status string `json:"status"`
}
type Productstocks struct {
Productstockid int `json:"productstockid" gorm:"Primary_Key"`
Locationid int `json:"locationid"`
Tenantid int `json:"tenantid"`
Stockdate string `json:"stockdate"`
Productid int `json:"productid"`
Quantity int `json:"quantity"`
Stocktype string `json:"stocktype"`
Status string `json:"status"`
AppLocationid int `json:"applocationid"`
Categoryid int `json:"categoryid"`
Categoryname string `json:"categoryname" gorm:"->"`
Subcategoryid int `json:"subcategoryid,omitempty"`
Subcategoryname string `json:"Subcategoryname" `
Productname string `json:"productname,omitempty"`
Productimage string `json:"productimage,omitempty"`
Productdesc *string `json:"productdesc,omitempty"`
Productsku *string `json:"productsku,omitempty"`
Brandid *int `json:"brandid,omitempty"`
Productbrand *string `json:"productbrand,omitempty"`
Productunit *string `json:"productunit,omitempty"`
Unitvalue *string `json:"unitvalue,omitempty"`
Toppicks *string `json:"toppicks,omitempty"`
Productcost *float64 `json:"productcost,omitempty"`
Taxamount *float64 `json:"taxamount,omitempty"`
Taxpercent *float64 `json:"taxpercent,omitempty"`
Producttax *int `json:"producttax,omitempty"`
Productstock *int `json:"productstock,omitempty"`
Productcombo *int `json:"productcombo,omitempty"`
Variants int `json:"variants"`
Retailprice float64 `json:"retailprice,omitempty"`
Diffprice float64 `json:"diffprice,omitempty"`
Diffpercent float64 `json:"diffpercent,omitempty"`
Othercost float64 `json:"othercost,omitempty"`
Approve *int `json:"approve"`
}
type SubCategorySummary struct {
SubCategoryID int `json:"subcategoryid"`
SubCategoryName string `json:"subcatname"`
Image string `json:"image"`
ProductCount int `json:"productcount"`
}
type ProductSummary struct {
Subcategoryid int `json:"subcategoryid"`
Subcategroyname string `json:"subcategroyname"`
Image string `json:"image"`
Productcount int `json:"productcount"`
}
type ProductDiscount struct {
Discountid int `json:"discountid" gorm:"column:discountid;primaryKey"`
Discounttypeid int `json:"discounttypeid" gorm:"column:discounttypeid"`
Tenantid int `json:"tenantid" gorm:"column:tenantid"`
Moduleid int `json:"moduleid" gorm:"column:moduleid"`
Productid int `json:"productid" gorm:"column:productid"`
Locationid []string `json:"locationid" gorm:"-"`
LocationidStr string `json:"-" gorm:"column:locationid"`
Discountname string `json:"discountname" gorm:"column:discountname"`
Discountcode string `json:"discountcode" gorm:"column:discountcode"`
Discountterms string `json:"discountterms" gorm:"column:discountterms"`
Discountvalue float64 `json:"discountvalue" gorm:"column:discountvalue"`
Startdate string `json:"startdate" gorm:"column:startdate"`
Enddate string `json:"enddate" gorm:"column:enddate"`
Status string `json:"status" gorm:"column:status"`
}

410
models/tenant.go Normal file
View File

@@ -0,0 +1,410 @@
package models
import "time"
type TenantResult struct {
Status bool `json:"status"`
Code int `json:"code"`
Message string `json:"message"`
Details Tenants `json:"Details"`
}
type Tenants struct {
Tenantid int `json:"tenantid" gorm:"Primary_Key"`
Tenantname string `json:"tenantname"`
Configid int `json:"configid"`
Partnerid int `json:"partnerid"`
Moduleid int `json:"moduleid"`
Tenanttype string `json:"tenanttype"`
Registrationno string `json:"registrationno"`
Tenanttoken string `json:"tenanttoken"`
Companyname string `json:"companyname"`
Devicetype string `json:"devicetype"`
Deviceid string `json:"deviceid"`
Firstname string `json:"firstname"`
Primaryemail string `json:"primaryemail"`
Primarycontact string `json:"primarycontact"`
Categoryid int `json:"categoryid"`
Subcategoryid int `json:"subcategoryid"`
Address string `json:"address"`
Suburb string `json:"suburb"`
City string `json:"city"`
State string `json:"state"`
Postcode string `json:"postcode"`
Latitude string `json:"latitude"`
Longitude string `json:"longitude"`
Tenantimage string `json:"tenantimage"`
Tenantinfo string `json:"tenantinfo"`
Paymode1 int `json:"paymode1"`
Paymode2 int `json:"paymode2"`
Promotion int `json:"promotion"`
Minorder int `json:"minorder"`
Applocationid int `json:"applocationid"`
Approved *int `json:"approved" gorm:"default:0"`
Status string `json:"status" gorm:"default:Active"`
Partneruserid int `json:"partneruserid"`
Tenantlocations Tenantlocations `json:"tenantlocations" gorm:"ForeignKey:tenantid"`
Tenantsubscriptions Tenantsubscriptions `json:"tenantsubscriptions" gorm:"ForeignKey:tenantid"`
}
type TenantUser struct {
Tenantid int `json:"tenantid" gorm:"Primary_Key"`
Tenantname string `json:"tenantname"`
Tenanttype string `json:"tenanttype"`
Registrationno string `json:"registrationno"`
Tenanttoken string `json:"tenanttoken"`
Companyname string `json:"companyname"`
Primaryperson string `json:"primaryperson"`
Primaryemail string `json:"primaryemail"`
Primarycontact string `json:"primarycontact"`
Bizcategoryid int `json:"Bizcategoryid"`
Bizsubcategoryid int `json:"Bizsubcategoryid"`
Address string `json:"address"`
Suburb string `json:"suburb"`
City string `json:"city"`
State string `json:"state"`
Postcode string `json:"postcode"`
Latitude string `json:"latitude"`
Longitude string `json:"longitude"`
Tenantimage string `json:"tenantimage"`
Tenantinfo string `json:"tenantinfo"`
Paymode1 int `json:"paymode1"`
Paymode2 int `json:"paymode2"`
Promotion int `json:"promotion"`
Partnerid int `json:"partnerid"`
Minorder int `json:"minorder"`
Applocationid int `json:"applocationid"`
Approved int `json:"approved"`
Moduleid int `json:"moduleid"`
Tenantlocations Tenantlocations `json:"tenantlocations" gorm:"ForeignKey:tenantid"`
Tenantsubscriptions Tenantsubscriptions `json:"tenantsubscriptions" gorm:"ForeignKey:tenantid"`
}
type Tenantinfo struct {
Tenantid int `json:"tenantid" gorm:"Primary_Key"`
Locationid int `json:"locationid"`
Tenantname string `json:"tenantname"`
Tenanttype string `json:"tenanttype"`
Registrationno string `json:"registrationno"`
Tenanttoken string `json:"tenanttoken"`
Companyname string `json:"companyname"`
Primaryemail string `json:"primaryemail"`
Primarycontact string `json:"primarycontact"`
Categoryid int `json:"categoryid"`
Subcategoryid int `json:"subcategoryid"`
Address string `json:"address"`
Suburb string `json:"suburb"`
City string `json:"city"`
State string `json:"state"`
Postcode string `json:"postcode"`
Latitude string `json:"latitude"`
Longitude string `json:"longitude"`
Tenantimage string `json:"tenantimage"`
Tenantinfo string `json:"tenantinfo"`
Paymenttype int `json:"paymenttype"`
Paymode1 int `json:"paymode1"`
Paymode2 int `json:"paymode2"`
Promotion int `json:"promotion"`
Partnerid int `json:"partnerid"`
Minorder int `json:"minorder"`
Applocationid int `json:"applolcationid"`
Applocation string `json:"applocation"`
Approved int `json:"approved"`
Moduleid int `json:"moduleid"`
Categoryname string `json:"categoryname"`
Subcategoryname string `json:"subcategoryname"`
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
Accountname string `json:"Accountname"`
Status string `json:"status"`
Allocationid int `json:"allocationid"`
Allocationtype string `json:"allocationtype"`
Allocationmode int `json:"allocationmode"`
Slab string `json:"slab"`
Pricingdate string `json:"pricingdate"`
Baseprice float32 `json:"baseprice"`
Minkm int `json:"minkm"`
Priceperkm float32 `json:"priceperkm"`
Maxkm int `json:"maxkm"`
Orders int `json:"orders"`
Othercharges float32 `json:"othercharges"`
Surgecharges float32 `json:"surgecharges"`
}
type Tenantsubscriptions struct {
Subscriptionid int `json:"subscriptionid" gorm:"Primary_Key"`
Tenantid int `json:"tenantid"`
Transactiondate string `json:"transactiondate"`
Moduleid int `json:"moduleid"`
Applocationid int `json:"applocationid"`
Promoid int `json:"promoid"`
Categoryid int `json:"categoryid"`
Subcategoryid int `json:"subcategoryid"`
Promoprice float32 `json:"float32"`
Subscriptionprice float32 `json:"subscriptionprice"`
Quantity int `json:"quantity"`
Taxpercent int `json:"taxpercent"`
Taxamount float32 `json:"taxamount"`
Totalamount float32 `json:"totalamount"`
Validitydate string `json:"validitydate"`
}
type Tenantlocationinfo struct {
Locationid int `json:"locationid" gorm:"Primary_Key"`
Tenantid int `json:"tenantid"`
Moduleid int `json:"moduleid"`
Locationname string `json:"locationname"`
Locationemail string `json:"locationemail" gorm:"column:email"`
Locationcontact string `json:"locationcontact" gorm:"column:contactno"`
Locationlatitude string `json:"locationlatitude" gorm:"column:latitude"`
Locationlong string `json:"locationlong" gorm:"column:longitude"`
Locationaddress string `json:"locationaddress" gorm:"column:address"`
Locationsuburb string `json:"locationsuburb" gorm:"column:suburb"`
Locationstate string `json:"locationstate" gorm:"column:state"`
Locationcity string `json:"locationcity" gorm:"column:city"`
Locationpostcode string `json:"locationpostcode" gorm:"column:postcode"`
Opentime string `json:"opentime"`
Closetime string `json:"closetime"`
Partnerid int `json:"partnerid"`
Deliveryradius int `json:"deliveryradius"`
Deliverymins int `json:"deliverymins"`
Cancelsecs int `json:"cancelsecs"`
Applocationid int `json:"applocationid"`
Slot1 string `json:"slot1"`
Slot2 string `json:"slot2"`
Slot3 string `json:"slot3"`
Status string `json:"status"`
Roleid int `json:"roleid"`
}
func (Tenantlocationinfo) TableName() string {
return "tenantlocations"
}
type Tenantslot struct {
// Slotid int `json:"slotid" gorm:"Primary_Key"`
Slot1 string `json:"slot1"`
Slot2 string `json:"slot2"`
Slot3 string `json:"slot3"`
}
type TenantLocationSummary struct {
Locationid int `json:"locationid"`
Locationname string `json:"locationname"`
Locationsuburb string `json:"locationsuburb"`
Total int `json:"total"`
Created int `json:"created"`
Pending int `json:"pending"`
Delivered int `json:"delivered"`
Cancelled int `json:"cancelled"`
}
type Tenantlocations struct {
Locationid int `json:"locationid" gorm:"Primary_Key"`
Tenantid int `json:"tenantid"`
Applocationid int `json:"applocationid"`
Moduleid int `json:"moduleid"`
Locationname string `json:"locationname"`
Email string `json:"email"`
Contactno string `json:"contactno"`
Latitude string `json:"latitude"`
Longitude string `json:"longitude"`
Address string `json:"address"`
Suburb string `json:"suburb"`
City string `json:"city"`
State string `json:"state"`
Postcode string `json:"postcode"`
Opentime string `json:"opentime"`
Closetime string `json:"closetime"`
Partnerid int `json:"partnerid"`
Deliveryradius int `json:"deliveryradius"`
Deliverymins int `json:"deliverymins"`
Cancelsecs int `json:"cancelsecs"`
Slot1 string `json:"slot1"`
Slot2 string `json:"slot2"`
Slot3 string `json:"slot3"`
Slot4 string `json:"slot4"`
Slot5 string `json:"slot5"`
Status string `json:"status" gorm:"default:Active"`
}
type Tenantlocation struct {
Locationid int `json:"locationid" gorm:"Primary_Key"`
Tenantid int `json:"tenantid"`
Applocationid int `json:"applocationid"`
Moduleid int `json:"moduleid"`
Locationname string `json:"locationname"`
Email string `json:"email"`
Contactno string `json:"contactno"`
Latitude string `json:"latitude"`
Longitude string `json:"longitude"`
Address string `json:"address"`
Suburb string `json:"suburb"`
City string `json:"city"`
State string `json:"state"`
Postcode string `json:"postcode"`
Opentime string `json:"opentime"`
Closetime string `json:"closetime"`
Partnerid int `json:"partnerid"`
Deliveryradius int `json:"deliveryradius"`
Deliverymins int `json:"deliverymins"`
Cancelsecs int `json:"cancelsecs"`
Status string `json:"status" gorm:"default:Active"`
}
type Tenantpricing struct {
Tenantpricingid int `json:"tenantpricingid" gorm:"Primary_Key"`
Pricingid int `json:"pricingid"`
Tenantid int `json:"tenantid"`
Applocationid int `json:"applocationid"`
Pricingtypeid int `json:"pricingtypeid"`
Slab string `json:"slab"`
Configid int `json:"configid"`
Pricingdate string `json:"pricingdate"`
Baseprice float32 `json:"baseprice"`
Priceperkm float32 `json:"priceperkm"`
Minkm int `json:"minkm"`
Maxkm int `json:"maxkm"`
Orders int `json:"orders"`
Othercharges float32 `json:"othercharges"`
Surgecharges float32 `json:"surgecharges"`
}
type TenantCustomer struct {
TenantCustomerID int `json:"tenantcustomerid" gorm:"primaryKey;column:tenantcustomerid"`
ModuleID int `json:"moduleid" gorm:"column:moduleid"`
TenantID int `json:"tenantid" gorm:"column:tenantid"`
LocationID int `json:"locationid" gorm:"column:locationid"`
CustomerID int `json:"customerid" gorm:"column:customerid"`
CustomerLocationID int `json:"customerlocationid" gorm:"column:customerlocationid"`
Status int `json:"status" gorm:"column:status"`
Created time.Time `json:"created" gorm:"column:created;autoCreateTime"`
Updated time.Time `json:"updated" gorm:"column:updated;autoUpdateTime"`
}
// If needed, define the table name explicitly
func (TenantCustomer) TableName() string {
return "tenantcustomers"
}
type CreateTenantCustomerRequest struct {
ModuleID int `json:"moduleid"`
TenantID int `json:"tenantid"`
LocationID int `json:"locationid"`
CustomerID int `json:"customerid"`
CustomerLocationID int `json:"customerlocationid"`
Status int `json:"status"`
}
// type CustomerInfo struct {
// Customerid int `json:"customerid"`
// Customername string `json:"customername"`
// Contactno string `json:"contactno"`
// }
// type TenantInfo struct {
// Tenantid int `json:"tenantid"`
// Tenantname string `json:"tenantname"`
// }
type CustomerTenantResponse struct {
Customer Customers `json:"customer"`
// Tenants []TenantInfo `json:"tenants"`
Tenantlocations []LocationDetails `json:"locations"`
}
type Tenantuser struct {
Userid int `json:"userid" gorm:"Primary_Key"`
Authname string `json:"authname"`
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
Password string `json:"password"`
Email string `json:"email"`
Dialcode string `json:"dialcode"`
Contactno string `json:"contactno"`
Configid int `json:"configid"`
Authmode int `json:"authmode"`
Roleid int `json:"roleid"`
Pin int `json:"pin"`
Deviceid string `json:"deviceid"`
Devicetype string `json:"devicetype"`
Userfcmtoken string `json:"userfcmtoken"`
Address string `json:"address"`
Suburb string `json:"suburb"`
City string `json:"city"`
State string `json:"state"`
Postcode string `json:"postcode"`
Partnerid int `json:"partnerid"`
Tenantid int `json:"tenantid"`
Locationid int `json:"locationid"`
Applocationid int `json:"applocationid"`
Status string `json:"status"`
}
type LocationSummary struct {
ActiveCount int `json:"active"`
InactiveCount int `json:"inactive"`
TotalCount int `json:"total"`
}
type TenantUserSummary struct {
ActiveCount int `json:"active"`
InactiveCount int `json:"inactive"`
TotalCount int `json:"total"`
}
type TenantRequest struct {
Requestid int `json:"requestid"`
Requestdate time.Time `json:"requestdate"`
Requesttype int `json:"requesttype"`
Subject string `json:"subject"`
Apptypeid int `json:"apptypeid"`
Userid int `json:"userid"`
Tenantid int `json:"tenantid"`
Referenceid int `json:"referenceid"`
Referencetype string `json:"referencetype"`
Remarks string `json:"remarks"`
Resolution string `json:"resolution"`
Orderheaderid int `json:"orderheaderid"`
Eventname string `json:"eventname"`
Status int `json:"status"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
}
type LocationDetails struct {
Locationid int `json:"locationid"`
Locationname string `json:"locationname"`
Tenantid int `json:"tenantid"`
Tenantname string `json:"tenantname"`
Address string `json:"address"`
Email string `json:"email"`
Contactno string `json:"contactno"`
Applocationid int `json:"applocationid"`
Suburb string `json:"suburb"`
City string `json:"city"`
Latitude string `json:"latitude"`
Longitude string `json:"longitude"`
Postcode string `json:"postcode"`
}
type Tenantpromotions struct {
Promotionid int `json:"promotionid" gorm:"primaryKey"`
Promotiontypeid int `json:"promotiontypeid"`
Tenantid int `json:"tenantid"`
Locationid []string `json:"locationid" gorm:"-"`
LocationidStr string `json:"-" gorm:"column:locationid"`
Applocationid int `json:"applocationid"`
Moduleid int `json:"moduleid"`
Categoryid int `json:"categoryid"`
Promoname string `json:"promoname"`
Promocode string `json:"promocode"`
Description string `json:"description"`
Product string `json:"product"`
Productimage string `json:"productimage"`
Promoamount float32 `json:"promoamount"`
Promovalue float32 `json:"promovalue"`
Purchasevalue float32 `json:"purchasevalue"`
Startdate string `json:"startdate"`
Enddate string `json:"enddate"`
}

333
models/user.go Normal file
View File

@@ -0,0 +1,333 @@
package models
type User struct {
Userid int `json:"userid" gorm:"Primary_Key"`
Authname string `json:"authname"`
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
Password string `json:"password"`
Email string `json:"email"`
Dialcode string `json:"dialcode"`
Contactno string `json:"contactno"`
Configid int `json:"configid"`
Authmode int `json:"authmode"`
Roleid int `json:"roleid"`
Rolename string `json:"rolename"`
Pin int `json:"pin"`
Deviceid string `json:"deviceid"`
Devicetype string `json:"devicetype"`
Userfcmtoken string `json:"userfcmtoken"`
Address string `json:"address"`
Suburb string `json:"suburb"`
City string `json:"city"`
State string `json:"state"`
Postcode string `json:"postcode"`
Partnerid int `json:"partnerid"`
Tenantid int `json:"tenantid"`
Locationid int `json:"locationid"`
Applocationid int `json:"applocationid"`
Status string `json:"status"`
Shiftid int `json:"shiftid"`
Bonuspts int `json:"bonuspts" gorm:"-"`
Hashsalt string `json:"hashsalt" gorm:"-"`
}
type Users struct {
Userid int `json:"userid" gorm:"Primary_Key"`
Email string `json:"email"`
Username string `json:"username"`
Contactno string `json:"contactno"`
Roleid int `json:"roleid"`
Configid int `json:"configid"`
Password string `json:"password"`
}
type AppLocation struct {
Applocationid int `json:"applocationid"`
Applocationname string `json:"applocationname"`
Status string `json:"status"`
}
type UserInfo struct {
Userid int `json:"userid"`
Authname string `json:"authname"`
Configid int `json:"configid"`
Authmode int `json:"authmode"`
Roleid int `json:"roleid"`
Rolename string `json:"rolename"`
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
Fullname string `json:"fullname"`
Email string `json:"email"`
Contactno string `json:"contactno"`
Address string `json:"address"`
Suburb string `json:"suburb"`
City string `json:"city"`
State string `json:"state"`
Postcode string `json:"postcode"`
Userfcmtoken string `json:"userfcmtoken"`
Shiftid int `json:"shiftid"`
Shiftname string `json:"shiftname"`
Pin int `json:"pin"`
Tenantid int `json:"tenantid"`
Status string `json:"status"`
Latitude string `json:"latitude"`
Longitude string `json:"longitude"`
Applocations []AppLocation `json:"applocations" gorm:"-"`
}
type UserInfov2 struct {
Userid int `json:"userid"`
Authname string `json:"authname"`
Configid int `json:"configid"`
Authmode int `json:"authmode"`
Roleid int `json:"roleid"`
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
Fullname string `json:"fullname"`
Email string `json:"email"`
Contactno string `json:"contactno"`
Address string `json:"address"`
Suburb string `json:"suburb"`
City string `json:"city"`
State string `json:"state"`
Postcode string `json:"postcode"`
Userfcmtoken string `json:"userfcmtoken"`
Shiftid int `json:"shiftid"`
Shiftname string `json:"shiftname"`
Pin int `json:"pin"`
Tenantid int `json:"tenantid"`
ApplocationidsRaw string `json:"-"`
ApplocationnamesRaw string `json:"-"`
Applocationids []int `json:"applocationids"`
Applocationnames []string `json:"applocationnames"`
Status string `json:"status"`
}
type TenantUserInfo struct {
Userid int `json:"userid"`
Authname string `json:"authname"`
Configid int `json:"configid"`
Authmode int `json:"authmode"`
Roleid int `json:"roleid"`
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
Fullname string `json:"fullname"`
Password string `json:"password"`
Email string `json:"email"`
Contactno string `json:"contactno"`
Address string `json:"address"`
Suburb string `json:"suburb"`
City string `json:"city"`
State string `json:"state"`
Postcode string `json:"postcode"`
Userfcmtoken string `json:"userfcmtoken"`
Pin int `json:"pin"`
Partnerid int `json:"partnerid"`
Locationid int `json:"locationid"`
Applocationid int `json:"applocationid"`
Tenantid int `json:"tenantid"`
Tenantname string `json:"tenantname"`
Tenantaddress string `json:"tenantaddress"`
Tenantcity string `json:"tenantcity"`
Tenantpostcode string `json:"tenantpostcode"`
Tenantlat string `json:"tenantlat"`
Tenantlong string `json:"tenantlong"`
Locationname string `json:"locationname"`
Applocation string `json:"applocation"`
Applatitude string `json:"applatitude"`
Applongitude string `json:"applongitude"`
Appradius int `json:"appradius"`
Moduleid int `json:"moduleid"`
Categoryid int `json:"categoryid"`
Categoryname string `json:"categoryname"`
Subcategoryid int `json:"subcategoryid"`
}
type StaffInfo struct {
Userid int `json:"userid"`
Authname string `json:"authname"`
Configid int `json:"configid"`
Authmode int `json:"authmode"`
Roleid int `json:"roleid"`
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
Fullname string `json:"fullname"`
Password string `json:"password"`
Email string `json:"email"`
Contactno string `json:"contactno"`
Address string `json:"address"`
Suburb string `json:"suburb"`
City string `json:"city"`
State string `json:"state"`
Postcode string `json:"postcode"`
Userfcmtoken string `json:"userfcmtoken"`
Pin int `json:"pin"`
Applocationid int `json:"applocationid"`
Partnerid int `json:"partnerid"`
Tenantid int `json:"tenantid"`
Locationid int `json:"locationid"`
Locationname string `json:"locationname"`
}
type RiderInfo struct {
Userid int `json:"userid"`
Authname string `json:"authname"`
Configid int `json:"configid"`
Authmode int `json:"authmode"`
Roleid int `json:"roleid"`
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
Username string `json:"username"`
Password string `json:"password"`
Email string `json:"email"`
Contactno string `json:"contactno"`
Address string `json:"address"`
Suburb string `json:"suburb"`
City string `json:"city"`
State string `json:"state"`
Postcode string `json:"postcode"`
Userfcmtoken string `json:"userfcmtoken"`
Pin int `json:"pin"`
Partnerid int `json:"partnerid"`
Identificationno string `json:"identificationno"`
Vehiclename string `json:"vehiclename"`
Vehicleno string `json:"vehicleno"`
Licenseno string `json:"licenseno"`
Insuranceno string `json:"insoranceno"`
Insurancedate string `json:"insurancedate"`
Shiftid int `json:"shiftid"`
Firstmilecharge float32 `json:"firstmilecharge"`
Starttime string `json:"starttime"`
Endtime string `json:"endtime"`
Shifthours float32 `json:"shifthours"`
Basefare float32 `json:"basefare"`
Additionalcharges float32 `json:"additionalcharges"`
Orders int `json:"orders"`
Fuelcharge float32 `json:"fuelcharge"`
Logdate string `json:"logdate"`
Applocationid int `json:"applocationid"`
Applocation string `json:"applocation"`
Logseconds int `json:"logseconds"`
Deliveryradius int `json:"deliveryradius"`
Riderid int `json:"riderid"`
Status string `json:"status"`
Tenantid int `json:"tenantid"`
Locationid int `json:"locationid"`
Logid int `json:"logid"`
Onduty int `json:"onduty"`
Latitude string `json:"latitude"`
Longitude string `json:"longitude"`
Bonuspts int `json:"bonuspts"`
Name string `json:"name"`
Capacity int `json:"capacity"`
Rangekm int `json:"rangekm"`
Batterypercentage int `json:"batterypercentage"`
Type string `json:"type"`
}
type AppUserpools struct {
Poolid int `json:"poolid" gorm:"Primary_key"`
Userid int `json:"userid"`
Partnerid int `json:"partnerid"`
Vehicleid int `json:"vehicleid"`
Onduty int `json:"onduty"`
Latitude string `json:"latitude"`
Longitude string `json:"longitude"`
Status string `json:"status"`
}
type Tenantstaffs struct {
Tenantstaffid int `json:"tenantstaffid" gorm:"Primary_key"`
Tenantid int `json:"tenantid"`
Moduleid int `json:"moduleid"`
Locationid int `json:"locationid"`
Userid int `json:"userid"`
Status string `json:"status"`
}
type Riderinfo struct {
Userid int `json:"userid" gorm:"Primary_Key"`
Authname string `json:"authname"`
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
Password string `json:"password"`
Email string `json:"email"`
Dialcode string `json:"dialcode"`
Contactno string `json:"contactno"`
Configid int `json:"configid"`
Authmode int `json:"authmode"`
Roleid int `json:"roleid"`
Pin int `json:"pin"`
Deviceid string `json:"deviceid"`
Devicetype string `json:"devicetype"`
Userfcmtoken string `json:"userfcmtoken"`
Address string `json:"address"`
Suburb string `json:"suburb"`
City string `json:"city"`
State string `json:"state"`
Postcode string `json:"postcode"`
Partnerid int `json:"partnerid"`
Tenantid int `json:"tenantid"`
Locationid int `json:"locationid"`
Applocationid int `json:"applocationid"`
Status string `json:"status"`
Shiftid int `json:"shiftid"`
Bonuspts int `json:"bonuspts"`
Hashsalt string `json:"hashsalt" gorm:"-"`
}
type AppLocationConfig struct {
Applocationconfigid int `gorm:"primaryKey"`
Applocationid int
Configid int
Userid int
Partnerid int
Notify string
Status string
}
type ConsoleUser struct {
Userid int `json:"userid" gorm:"Primary_Key"`
Authname string `json:"authname"`
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
Password string `json:"password"`
Email string `json:"email"`
Dialcode string `json:"dialcode"`
Contactno string `json:"contactno"`
Configid int `json:"configid"`
Authmode int `json:"authmode"`
Roleid int `json:"roleid"`
Pin int `json:"pin"`
Deviceid string `json:"deviceid"`
Devicetype string `json:"devicetype"`
Userfcmtoken string `json:"userfcmtoken"`
Address string `json:"address"`
Suburb string `json:"suburb"`
City string `json:"city"`
State string `json:"state"`
Postcode string `json:"postcode"`
Partnerid int `json:"partnerid"`
Tenantid int `json:"tenantid"`
Locationid int `json:"locationid"`
Applocationid int `json:"applocationid"`
Status string `json:"status"`
Shiftid int `json:"shiftid"`
Bonuspts int `json:"bonuspts" gorm:"-"`
Hashsalt string `json:"hashsalt" gorm:"-"`
// Applocationids []int `json:"applocationids" gorm:"-"`
}
type AppLocationConfigRequest struct {
Userid int `json:"userid"`
Configid int `json:"configid"`
Partnerid int `json:"partnerid"`
Applocationids []int `json:"applocationids"`
Notify string `json:"notify"`
Status string `json:"status"`
}

156
models/utils.go Normal file
View File

@@ -0,0 +1,156 @@
package models
import "time"
type Applocations struct {
Applocationid int `json:"applocationid" gorm:"Primary_Key"`
Locationname string `json:"locationname"`
Image string `json:"image"`
City string `json:"city"`
State string `json:"state"`
Postcode string `json:"postcode"`
Latitude string `json:"latitude"`
Longitude string `json:"longitude"`
Opentime string `json:"opentime"`
Closetime string `json:"closetime"`
Radius int `json:"radius"`
Applocationadmins []Applocationadmins `json:"applocationadmins" gorm:"ForeignKey:applocationid"`
}
type Applocationadmins struct {
Applocationconfigid int `json:"applocationconfigid" gorm:"Primary_Key"`
Applocationid int `json:"applocationid"`
Userid int `json:"userid"`
Userfcmtoken string `json:"userfcmtokem"`
Notify string `json:"notify"`
}
type ApplocationsResult struct {
Code int `json:"code"`
Status bool `json:"status"`
Message string `json:"message"`
Details []Applocations `json:"details"`
}
type Apppricing struct {
Pricingid int `json:"pricingid"`
Pricingdate string `json:"pricingdate"`
Pricingtypeid int `json:"pricingtypeid"`
Applocationid int `json:"applocationid"`
Configid int `json:"configid"`
Slab string `json:"slab"`
Baseprice float32 `json:"baseprice"`
Minkm int `json:"minkm"`
Priceperkm float32 `json:"priceperkm"`
Maxkm int `json:"maxkm"`
Minorder int `json:"minorder"`
Status int `json:"status" gorm:"default:0"`
Applocation string `json:"applocation" gorm:"<-:false"`
Appname string `json:"appname" gorm:"<-:false"`
}
type Appconfig struct {
Configid int `json:"configid"`
Appname string `json:"appname"`
Paymentdevkey string `json:"paymentdevkey"`
Paymentlivekey string `json:"paymentlivekey"`
Fcmkey string `json:"fcmkey"`
Googleapikey string `json:"googleapikey"`
Applocationradius int `json:"applocationradius"`
Smsproviderid int `json:"smsproviderid"`
Providerapi string `json:"providerapi"`
Providerkey string `json:"providerkey"`
Sender string `json:"sender"`
Templateid string `json:"templateid"`
Defaultprovider int `json:"defaultprovider"`
}
type Apptypes struct {
Apptypeid int `json:"apptypeid"`
Typename string `json:"typename"`
Mapid int `json:"mapid"`
Tag string `json:"tag"`
Status string `json:"status"`
}
type Appsubcategories struct {
Subcategoryid int `json:"subcategoryid"`
Categoryid int `json:"categoryid"`
Subcategoryname string `json:"subcategoryname"`
Categoryname string `json:"catgeoryname"`
Moduleid int `json:"moduleid"`
Status string `json:"status"`
}
type AppCategory struct {
Categoryid int `json:"categoryid"`
Categoryname string `json:"categoryname"`
Categorytype string `json:"categorytype"`
Moduleid int `json:"moduleid"`
Sortorder int `json:"sortorder"`
Imageurl string `json:"imageurl"`
Iconurl string `json:"iconurl"`
Profileurl string `json:"profileurl"`
Crossaxis int `json:"crossaxis"`
Mainaxis int `json:"mainaxis"`
Status string `json:"status"`
}
type AppModule struct {
Moduleid int `json:"moduleid"`
Modulename string `json:"modulename"`
Categoryid int `json:"categoryid"`
Baseprice float32 `json:"baseprice"`
Taxpercent float32 `json:"taxpercent"`
Taxamount float32 `json:"taxamount"`
Amount float32 `json:"amount"`
Commisiontype string `json:"commisiontype"`
Commisionvalue float32 `json:"commisionvalue"`
Content string `json:"content"`
Logourl string `json:"logourl"`
Iconurl string `json:"iconurl"`
Sortorder int `json:"sortorder"`
Status string `json:"status"`
Createdby int `json:"createdby"`
}
type TenantNotification struct {
Notificationid int `json:"notificationid"`
Title string `json:"title"`
Message string `json:"message"`
Tenantid int `json:"tenantid"`
Moduleid int `json:"moduleid"`
Locationid int `json:"locationid"`
Customerid int `json:"customerid"`
Notificationdate time.Time `json:"notificationdate"`
Successcode int `json:"successcode"`
}
type UserRoles struct {
Roleid int `json:"roleid"`
Rolename string `json:"rolename"`
Configid int `json:"configid"`
}
type RiderLog struct {
UserID int `json:"userid"`
Username string `json:"username"`
LogDate string `json:"logdate"`
Latitude string `json:"latitude"`
Longitude string `json:"longitude"`
Speed string `json:"speed"`
Heading string `json:"heading"`
Accuracy string `json:"accuracy"`
Status string `json:"status"`
OrderID string `json:"orderid"`
Battery string `json:"battery"`
IsCharging bool `json:"is_charging"`
Connection string `json:"connection"`
LocationService string `json:"location_service"`
IsBackground bool `json:"is_background"`
}
type RiderStatus struct {
UserID int `json:"userid"`
Status string `json:"status"`
}

View File

@@ -0,0 +1,13 @@
{
"type": "service_account",
"project_id": "nearle-gear",
"private_key_id": "23ca3b3609076b93b29a730f63e1da76d68e4baa",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDfsSE/Otsp0LTJ\nrTBUoOcdd0MF3rRZtcL4/WCekyEUh8tTh0YtSqaaDoO2lpg2Ym9jS031z1U0UOqg\n83L9IwyQD0UV0rYFkOm9LWNU60ZvL/KjE8YcRf0j8nj/Sv6S9rrrQmQKKDXINs2t\noXyBi7R4WTGxJmRzyAr9jTgS/aghGpvo57z7aln2veYXUVxw1kVDEou9dFEu2eHC\nPY4Bb6ACDFvxtGNAClwHy3pYHv+6QirF5O2z+JPjGuYJXSOqiT6SOhLHnv9P7W4y\nUY5/wFiRpvK6iYjRFEnpw3c950UH3y19njiPyZN+pS6tCqyE6w0tQPIaxX7c39dg\nmq9esOGbAgMBAAECggEAVzfIP9Ah/fbbVrtJWeX21x1WK6a+6S+emtioYIv7XPbp\nh2L6MNSniu/X2Ux0gtf0mGGXPx2dGi3mneTuU9bjohPiGvUydY8gI9vbnBO0PcwT\nLhSarRF49xgmp1vFUOYU0X/sY61z8uGzZlzNn/Ep57bXUjwm9KHt7xit4XG3qVfs\n84+hYWGl6vy15LfgmRb5MzTWexYMfQnaxk0we0mUzSIXmOCvI/OrkQwKenkgkR2F\n7r/0LZQBbVhZ/kB9avWBNnsj89nDNld9MtuKHqjcwFfHFgBzSz+3Qy2LolCVtN5Z\nMEjJ3/t1cocDAnKRBJeA9B3Hj2ud1BCxSQceTnb22QKBgQD3tOa/KWQbgmfoFh/w\nni2EJM0KDKvibxJfIC+p6z4/EiXENmJDQx32yqURCO75mwtBX/VYxGSLb1wLTfIn\nGVRu5KWs5oLV8FqyAQPYh5Urz6DVqg6CQRQadCz0emMMbjRk2XDE2j7f18VOB4DV\nZCxpx1Bv1wiU2ITNxczlteH6zwKBgQDnLmXTw1jfZ1DS69idby5L8PpcnP3GWV4t\nxAHH6QJhqUrMo5/eFKOL6aaSR4cIg47NdtP4yKo71TyaFl68xo4VWyoy2xJffdyd\niGf1kG2prNmHAtcU6W9QdgK4qgHpYVpqZufAn2XW/KMrsyhd4jwVR/UFNogswLI5\nXXy8Tx7vdQKBgGRHHL64n+kvEqd3BXkgX+bGCyeNV6w0MOjHm+Qa8rkPvLBBH+iA\n7ElzYf2Sc0QjCxxtH2LPJrD35PhClsxTScYW1Cc5ri+zvNOg65Cl2rLAvCijTnpW\npC/NZkGWpjBrENTe3fMjMx7lN9/N088PXZd488xC7htrx9+RutAnoJMrAoGAd8Px\nvONXB2Xe2WaVsfoHYhBVo+UxE7D4uXzx7z8nnLC3r4yVJdhLYhCJ2v5zVlXRhWAq\nMJjEmHrACpPMQMAcm7O/CNm1iwMJaBNiyDUqmtyRVQCDrLHCmUyJ3GE23FEzJixp\no8DwYZBAeEM4hmrN9bhxl2HI6mZp7o4gMO5MeIECgYAuqqv/hq9t57qnJhk2S5mi\nSmDMk+Zz/pVFYfpUlRL33k/t+8c/8+qTdSruRZzLzSAtdZY6XE85lidt2zwdCgqO\nEuviAb474iF8UOY0hf4mQkrIHmlojd2nZmUQbPjPTR+kiUvhJGvQuaJywbX54+wR\n+8tH+pbwRbkrENWHqJHxhg==\n-----END PRIVATE KEY-----\n",
"client_email": "firebase-adminsdk-l9oha@nearle-gear.iam.gserviceaccount.com",
"client_id": "118373484295110637143",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-l9oha%40nearle-gear.iam.gserviceaccount.com",
"universe_domain": "googleapis.com"
}

376
routes/routes.go Normal file
View File

@@ -0,0 +1,376 @@
package routes
import (
"nearle/controllers"
"nearle/middlewares"
"net/http"
"github.com/gofiber/fiber/v2"
)
func DevSetup(app *fiber.App) {
app.Get("/", func(c *fiber.Ctx) error {
return c.JSON(fiber.Map{
"code": http.StatusOK,
"message": "Welcome to Nearle",
"status": true,
})
})
dev := app.Group("/dev/api")
customer := dev.Group("/v1/customers")
customer.Post("/login", controllers.CustomerLogin)
customer.Post("/create", controllers.CreateCustomer)
util := dev.Group("/v1/utils")
util.Get("/getapplocations", controllers.GetApplocations)
util.Get("/getappconfig", controllers.GetAppConfig)
}
func LiveSetup(app *fiber.App) {
live := app.Group("/live/api")
users := live.Group("/v1/users")
users.Post("/login", controllers.Login)
users.Post("/tenant/login", controllers.TenantLogin)
users.Post("/partner/login", controllers.Partnerlogin)
users.Post("/rider/login", controllers.Riderlogin)
users.Post("/admin/login", controllers.AdminLogin)
users.Post("/console/login", controllers.AdminConsoleLogin)
users.Post("/tenant/weblogin", controllers.TenantWebLogin)
users.Post("/applogin", controllers.AppLogin)
users.Post("/create", controllers.CreateUser)
users.Post("/createconsoleuser", controllers.CreateConsoleUser)
users.Put("/update", controllers.UpdateStaff)
users.Delete("/delete", controllers.DeleteUser)
users.Get("/getusers", controllers.GetUserInfo)
users.Get("/getallusers", controllers.GetAllUsers)
users = live.Group("/v2/users")
users.Post("/applogin", middlewares.RoleCheckMiddleware(0), controllers.TenantWebLoginv2)
users.Post("/tenant/weblogin", middlewares.RoleCheckMiddleware(1), controllers.TenantWebLoginv2)
users.Post("/create", controllers.CreateUserV2)
users.Put("/update", controllers.UpdateUserV2)
users.Post("/rider/login", controllers.Riderloginv2)
users.Get("/getallusers", controllers.GetAllUsersv2)
customer := live.Group("/v1/customers")
customer.Get("/", controllers.BasicRoute)
customer.Post("/login", controllers.CustomerLogin)
customer.Post("/create", controllers.CreateCustomer)
customer.Put("/update", controllers.UpdateCustomer)
customer.Get("/getbyid", controllers.GetCustomer)
customer.Get("/getbyno", controllers.GetCustomer)
customer.Get("/getbytid", controllers.GetCustomersbytenent)
customer.Get("/gettenantcustomers", controllers.GetTenantCustomers)
customer.Get("/getcustomerlocation", controllers.GetCustomerLocations)
customer.Post("/createlocations", controllers.CreateCustomerLocation)
customer.Get("/getcustomersbyapplocation", controllers.GetCustomersbyapplocation)
customer.Get("/getallcustomers", controllers.GetallCustomers)
customer.Get("getcustomersummary", controllers.GetCustomerSummary)
customer.Get("/search", controllers.SearchCustomer)
customer.Delete("/delete", controllers.DeleteCustomer)
customer.Post("/createcustomerrequest", controllers.CreateCustomerRequest)
customer.Get("/getcustomerrequests", controllers.GetCustomerRequests)
util := live.Group("/v1/utils")
util.Get("/getapplocations", controllers.GetApplocations)
util.Get("/getappconfig", controllers.GetAppConfig)
util.Get("/getallappconfig", controllers.GetAllAppConfig)
util.Get("/getapptypes", controllers.GetApptypes)
util.Get("/getappmodule", controllers.GetAppModule)
util.Get("/getsubcategories", controllers.GetSubcategories)
util.Get("/getcategories", controllers.GetCategories)
util.Post("/notifyuser", controllers.NotifyUser)
util.Post("/sendnotifications", controllers.NotifyUsers)
util.Get("/getapppricing", controllers.GetAppPricing)
util.Get("/getallpricing", controllers.GetAllAppPricing)
util.Get("/getallpricing", controllers.GetAllAppPricing)
util.Post("/createapppricing", controllers.CreateAppPricing)
util.Get("/getapplocationconfig", controllers.GetApplocationConfig)
util.Post("/notifyadmin", controllers.NotifyAdmin)
util.Post("/notifytenant", controllers.NotifyTenant)
util.Get("/gettenantnotifications", controllers.GetTenantNotifications)
util.Post("/webhooks", controllers.WebhookHandler)
util.Post("/register-webhook", controllers.RegisterWebhookHandler)
util.Post("/createwebhook", controllers.Createwebhook)
util.Post("/webhooksreceiver", controllers.WebhookReceiver)
util.Get("/getshopfrontorders", controllers.GetShopfrontOrders)
util.Post("/webhooks/inventory", controllers.RegisterInventoryWebhook)
util.Get("/getuserbonussummary", controllers.GetUserBonusSummary)
util.Post("/createapplocationconfig", controllers.CreateAppLocationConfig)
util.Put("/updateapplocationconfig", controllers.UpdateAppLocationConfig)
util.Get("/getuserroles", controllers.GetUserRoles)
util.Post("/createuserredis", controllers.CreateUserRedis)
util.Get("/getuserredis", controllers.GetUserRedis)
util.Post("/createriderperiodiclog", controllers.CreateRiderPeriodicLog)
util.Get("/getriderperiodiclogs", controllers.GetRiderPeriodicLogs)
util.Post("/createriderstatus", controllers.CreateRiderStatus)
util.Get("/getriderstatus", controllers.GetRiderStatus)
util = live.Group("/v2/utils")
util.Get("/getapplocations", controllers.GetApplocationsv2)
partner := live.Group("/v1/partners")
partner.Get("/getriders", controllers.GetActiveRiders)
partner.Get("/getactiveriderssummary", controllers.GetActiveRidersSummary)
partner.Get("/getridershifts", controllers.GetRiderShifts)
partner.Get("/getriderpricing", controllers.GetRiderPricing)
partner.Get("/getriderpool", controllers.GetRiderPool)
partner.Get("/getriderinfo", controllers.GetRiderInfo)
partner.Get("/getriderdetail", controllers.GetRiderDetails)
partner.Get("/getallriders", controllers.GetAllRiders)
partner.Get("/getpartners", controllers.GetPartners)
partner.Get("/getlocations", controllers.GetLocationConfig)
partner.Get("/getpartnerusers", controllers.GetPartnerusers)
partner.Get("/getallorderbystatus", controllers.GetOrders)
partner.Get("/getadmintoken", controllers.GetAdminToken)
partner.Post("/createshift", controllers.CreateRiderShift)
partner.Post("/createrider", controllers.CreateRider)
partner.Put("/updateridersettings", controllers.UpdateRiderSettings)
partner.Put("/updaterider", controllers.UpdateRiderInfo)
partner.Post("/createriderlog", controllers.CreateRiderLog)
partner.Put("/updateriderlog", controllers.UpdateRiderLog)
partner.Get("/getriderlog", controllers.GetRiderLog)
partner.Get("/getriderlogs", controllers.GetRiderLogs)
partner.Get("/getridercount", controllers.GetRiderOrderCount)
partner.Post("/createbreaklog", controllers.CreateBreakLog)
partner.Put("/updatebreaklog", controllers.UpdateBreakLog)
partner.Get("/getriderweeklykms", controllers.GetRiderWeeklyKms)
partner.Post("/createridersupport", controllers.CreateRiderSupport)
partner.Get("/getridersupport", controllers.GetRiderSupport)
partner.Get("/getallridersummary", controllers.GetAllRidersSummary)
partner.Get("/getuserlocationsummary", controllers.GetUserLocationSummary)
partner.Get("/getriderpricing", controllers.GetRiderPricing)
partner = live.Group("/v2/partners")
partner.Get("/getriderinfo", controllers.GetRiderInfov2)
partner.Get("/getriders", controllers.GetActiveRidersv2)
partner.Post("/createbreaklog", controllers.CreateBreakLogv1)
partner.Put("/updatebreaklog", controllers.UpdateBreakLogv1)
partner.Get("/getdeliverystats", controllers.GetDeliveryStats)
partner.Post("/createriderlog", controllers.CreateRiderLogv1)
partner.Put("/updateriderlog", controllers.UpdateRiderLogv1)
partner.Get("/getriderlogs", controllers.GetRiderLogsv1)
partner.Delete("/deleteriderlog", controllers.DeleteRiderLogs)
invoice := live.Group("/v1/invoice")
invoice.Get("/getseqno", controllers.InvoiceSeqno)
invoice.Get("/getinvoiceorders", controllers.GetInvoiceOrders)
invoice.Post("/create", controllers.CreateInvoice)
invoice.Get("/getallinvoice", controllers.GetallInvoice)
invoice.Get("/getinvoiceinsight", controllers.GetInvoiceInsight)
invoice.Put("/update", controllers.UpdateInvoice)
invoice.Put("/updatestatus", controllers.UpdateInvoiceStatus)
tenant := live.Group("/v1/tenants")
tenant.Post("/create", controllers.Createtenant)
tenant.Post("/createlocation", controllers.CreateLocation)
tenant.Post("/createtenantuser", controllers.CreatetenantUser)
tenant.Put("/update", controllers.UpdateTenant)
tenant.Put("/updatelocation", controllers.UpdateLocation)
tenant.Put("/createpartneruser", controllers.UpdateTenant)
tenant.Get("/gettenantinfo", controllers.GetTenantInfo)
tenant.Get("/search", controllers.SearchTenant)
tenant.Post("/createtenantcustomer", controllers.Createtenantcustomer)
tenant.Post("/createstaff", controllers.CreateStaff)
tenant.Put("/updatestaff", controllers.UpdateStaff)
tenant.Get("/getstaffs", controllers.GetStaffs)
tenant.Get("/gettenants", controllers.GetTenants)
tenant.Get("/getalltenants", controllers.GetAllTenants)
tenant.Get("/gettenantsummary", controllers.GetTenantSummary)
tenant.Get("/getcloudstore", controllers.GetCloudStore)
tenant.Get("/gettenantlocations", controllers.GetTenantLocations)
tenant.Get("/gettenantslots", controllers.GetTenantSlot)
tenant.Get("/gettenantlocation", controllers.GetTenantLocation)
tenant.Post("/createpricing", controllers.CreatePricing)
tenant.Get("/gettenantpricing", controllers.GetTenantPricing)
tenant.Post("/createtenantrequest", controllers.CreateTenantRequest)
tenant.Get("/gettenantrequests", controllers.GetTenantRequests)
tenant.Get("/getpricinglist", controllers.GetPricingList)
tenant.Post("/createtenantpromotions", controllers.CreateTenantPromotion)
tenant.Get("/gettenantpromotions", controllers.GetTenantPromotions)
tenant = live.Group("/v2/tenants")
tenant.Post("/createtenantlocation", controllers.CreateTenantLocation)
tenant.Put("/updatetenantlocation", controllers.UpdateTenantLocation)
tenant.Get("/getlocationsummary", controllers.GetLocationSummary)
tenant.Get("/gettenantstaffsummary", controllers.GetTenantStaffSummary)
tenant.Get("/gettenantridersummary", controllers.GetTenantRiderSummary)
tenant.Get("/getcustomertenants", controllers.GetCustomerTenants)
products := live.Group("v1/products")
products.Get("/getallproducts", controllers.GetAllProducts)
products.Get("/getproductinfo", controllers.GetProductInfo)
products.Get("/getproductcategories", controllers.GetProductCategory)
products.Get("/getproductsubcategories", controllers.GetProductSubCategory)
products.Post("/create", controllers.CreateProduct)
products.Put("/update", controllers.UpdateProduct)
products.Delete("/delete", controllers.DeleteProduct)
products.Get("/getproductsbysubcategory", controllers.GetProductsBySubcategory)
products.Get("/getproductscount", controllers.GetProductCount)
products.Get("/getproductbyvariant", controllers.GetProductByVariant)
products.Post("/createproductvariant", controllers.CreateProductVariant)
products.Get("/getproductvariants", controllers.GetProductVariants)
products.Post("/createproductdiscount", controllers.CreateProductDiscount)
products.Get("/getproductdiscounts", controllers.GetProductDiscounts)
products = live.Group("v2/products")
products.Get("/getcatalougeproducts", controllers.GetCatalougeProducts)
products.Get("/getlocationproducts", controllers.GetLocationProducts)
products.Get("/getlocationproductsummary", controllers.GetLocationProductSummary)
products.Get("/getstockstatement", controllers.GetStockstatement)
products.Post("/createproductlocation", controllers.CreateProductLocation)
products.Put("/updateproductlocation", controllers.UpdateProductLocation)
products.Post("/createproductstock", controllers.CreateProductStock)
products.Put("/updateproductstock", controllers.UpdateProductStock)
products.Get("/getproductstocks", controllers.GetProductStocks)
products.Get("/getproductcategorywisesummary", controllers.GetSubCategoryWiseSummary)
products.Get("/getstockstatementsummary", controllers.GetStockStatementSummary)
orders := live.Group("/v1/orders")
orders.Get("partner/getorders", controllers.GetOrders)
orders.Get("tenant/getorders", controllers.GetOrders)
orders.Get("customer/getorders", controllers.GetOrders)
orders.Get("/getorders", controllers.GetOrders)
orders.Get("tenant/getlocationsummary", controllers.GetTenantLocationSummary)
orders.Get("/getordersummary", controllers.GetOrderSummary)
orders.Get("/getlocationsummary", controllers.GetlocationOrderSummary)
orders.Get("/getorderinsight", controllers.GetOrderInsight)
orders.Get("/getorderdetails", controllers.GetOrderDetails)
orders.Post("/createorder", controllers.CreateOrder)
orders.Post("/createorders", controllers.CreateOrders)
orders.Put("/updateorder", controllers.UpdateOrder)
orders.Put("/updatemultipleorders", controllers.UpdateMultipleOrders)
orders.Get("/getorderbylocations", controllers.GetCustomerOrderByLocation)
ordersv2 := live.Group("/v2/orders")
ordersv2.Post("/createorder", controllers.CreateCustomerOrderv2)
ordersv2.Get("/getorders", controllers.GetOrdersv2)
ordersv2.Get("/getorderinsight", controllers.GetOrderInsightDaily)
ordersv2.Get("/getordersummary", controllers.GetOrderSummaryDaily)
ordersv2.Get("/getlocationsummary", controllers.GetLocationOrderSummaryDaily)
ordersv3 := live.Group("/v3/orders")
ordersv3.Post("/createorder", controllers.CreateOrderv3)
ordersv3.Get("getcustomerorders", controllers.GetCustomerOrders)
deliveries := live.Group("/v1/deliveries")
deliveries.Post("/createdelivery", controllers.CreateDelivery)
deliveries.Post("/createdeliveries", controllers.CreateDeliveries)
deliveries.Post("/createdeliverylog", controllers.PublishLog)
deliveries.Get("/getdeliverylogs", controllers.GetDeliverylogs)
deliveries.Get("deliverysummary", controllers.GetDeliverySummary)
deliveries.Get("/getlocationsummary", controllers.GetlocationdeliverySummary)
deliveries.Get("/getdeliveries", controllers.GetDeliveriesV2)
deliveries.Get("/getdeliveryqueues", controllers.GetDeliveryQueues)
deliveries.Get("/getdeliveryqueuespicked", controllers.GetDeliveryQueuesPicked)
deliveries.Put("/Updatedelivery", controllers.UpdateDelivery)
deliveries.Get("/getdeliveryinsight", controllers.GetDeliveryInsight)
deliveries.Get("/getreportsummary", controllers.GetReportSummary)
deliveries.Get("/getreportlocationsummary", controllers.GetReportLocationSummary)
deliveries.Get("/getriderlocationreportsummary", controllers.GetRiderLocationReportSummary)
deliveries.Get("/getridersummary", controllers.GetRiderSummary)
deliveries.Get("/getriderlocationsummary", controllers.GetRiderLocationSummary)
deliveries.Get("/getriderbydelivery", controllers.GetRiderByDelivery)
deliveries.Get("/getlastdeliverybycontact", controllers.GetLastDeliveryByContact)
deliveries.Get("/getuserreportsummary", controllers.GetUserReportSummary)
deliveries.Get("/getuserdeliverylogs", controllers.GetUserDeliveryLogs)
deliveriesv2 := live.Group("/v2/deliveries")
deliveriesv2.Post("/createdeliveries", controllers.CreateDeliveriesV2)
deliveriesv2.Get("/getdeliveries", controllers.GetDeliveriesV2)
deliveriesv2.Get("/getlocationsummary", controllers.GetlocationdeliverySummaryDaily)
deliveriesv2.Get("/getdeliveryinsight", controllers.GetDeliveryInsightDaily)
deliveriesv2.Post("/createdeliverylog", controllers.PublishLogv1)
deliveriesv2.Get("/getdeliverylogs", controllers.GetDeliverylogsv1)
deliveriesv2.Get("/getdeliveryqueues", controllers.GetDeliveryQueuesV1)
deliveriesv3 := live.Group("/v3/deliveries")
deliveriesv3.Get("/getdeliveries", controllers.GetDeliveriesV3)
deliveriesv3.Get("/getdeliverylogs", controllers.GetDeliveryLogsv1)
payments := live.Group("/v1/payments")
payments.Get("requests/getpaymentrequest", controllers.GetPaymentRequests)
payments.Post("requests/create", controllers.CreatePaymentRequest)
admin := live.Group("/v1/admin")
admin.Post("/login", controllers.CustomerLogin)
admin.Get("/orders/getorders", controllers.GetOrders)
platform := live.Group("/v1/platform")
platform.Get("/getmodules", controllers.GetModules)
platform.Get("/getsmsprovider", controllers.GetSmsProvider)
}
func LiveWebSetup(app *fiber.App) {
liveweb := app.Group("/live/api/web")
users := liveweb.Group("/v1/users")
users.Post("/create", controllers.CreateUserV2)
users.Get("/getallusers", controllers.GetAllUsers)
users.Put("/update", controllers.UpdateUserV2)
tenantweb := liveweb.Group("/v1/tenants")
tenantweb.Put("/update", controllers.UpdateTenant)
tenantweb.Get("/gettenantpricing", controllers.GetTenantPricing)
tenantweb.Get("/gettenantinfo", controllers.GetTenantInfo)
tenantweb.Get("/gettenantlocations", controllers.GetTenantLocations)
tenantweb.Put("/updatetenantlocation", controllers.UpdateTenantLocation)
ordersweb := liveweb.Group("/v1/orders")
ordersweb.Get("tenant/getorders", controllers.GetOrders)
ordersweb.Get("/getordersummary", controllers.GetOrderSummary)
ordersweb.Get("customer/getorders", controllers.GetOrders)
ordersweb.Get("tenant/getorders", controllers.GetOrders)
utilweb := liveweb.Group("/v1/utils")
utilweb.Get("/getsubcategories", controllers.GetSubcategories)
utilweb.Get("/getapplocations", controllers.GetApplocations)
utilweb.Get("/getapplocationconfig", controllers.GetApplocationConfig)
utilweb.Get("/getapptypes", controllers.GetApptypes)
customerweb := liveweb.Group("/v1/customers")
customerweb.Get("/gettenantcustomers", controllers.GetTenantCustomers)
partnerweb := liveweb.Group("/v1/partners")
partnerweb.Get("/getpartners", controllers.GetPartners)
partnerweb.Get("/getlocations", controllers.GetLocationConfig)
partnerweb.Get("/getridershifts", controllers.GetRiderShifts)
partnerweb.Get("/getriderpricing", controllers.GetRiderPricing)
productsweb := liveweb.Group("v1/products")
productsweb.Post("/create", controllers.CreateProduct)
productsweb.Post("/createproductlocation", controllers.CreateProductLocation)
productsweb.Put("/updateproductstock", controllers.UpdateProductStock)
productsweb.Get("/getallproducts", controllers.GetAllProducts)
productsweb.Get("/getproductcategories", controllers.GetProductCategory)
productsweb.Get("/getproductsubcategories", controllers.GetProductSubCategory)
productsweb.Get("/getproductscount", controllers.GetProductCount)
productsweb.Get("/getproductvariants", controllers.GetProductVariants)
deliveries := liveweb.Group("/v1/deliveries")
deliveries.Get("/getdeliveries", controllers.GetDeliveriesV2)
invoice := liveweb.Group("/v1/invoice")
invoice.Get("/getinvoiceinsight", controllers.GetInvoiceInsight)
invoice.Get("/getallinvoice", controllers.GetallInvoice)
}

41
tmp/check_schema.go Normal file
View File

@@ -0,0 +1,41 @@
package main
import (
"fmt"
"nearle/db"
"github.com/joho/godotenv"
)
func main() {
_ = godotenv.Load()
db.Connect()
if db.DB == nil {
fmt.Println("❌ Failed to connect to DB")
return
}
tables := []string{"deliveries", "deliveryqueues", "deliverylogs"}
for _, table := range tables {
fmt.Printf("\n--- Schema for %s ---\n", table)
var results []struct {
ColumnName string `gorm:"column:column_name"`
DataType string `gorm:"column:data_type"`
IsNullable string `gorm:"column:is_nullable"`
ColumnDefault *string `gorm:"column:column_default"`
}
db.DB.Raw(`
SELECT column_name, data_type, is_nullable, column_default
FROM information_schema.columns
WHERE table_name = ?
AND column_name LIKE '%id'
`, table).Scan(&results)
for _, r := range results {
def := "NULL"
if r.ColumnDefault != nil {
def = *r.ColumnDefault
}
fmt.Printf("Col: %-15s | Type: %-10s | Null: %-3s | Def: %s\n", r.ColumnName, r.DataType, r.IsNullable, def)
}
}
}

46
utils/config.go Normal file
View File

@@ -0,0 +1,46 @@
package utils
import (
"github.com/spf13/viper"
)
func DevConfig() (Port, DBname, Password, Username, Host, key, secret string) {
viper.SetConfigName("config") // config file name without extension
viper.SetConfigType("yaml")
viper.AddConfigPath(".")
err := viper.ReadInConfig()
if err != nil {
Logger.Fatalf("fatal error config file: default \n %v", err)
}
dbname := viper.GetString("DEV.DATABASE_NAME")
dbpassword := viper.GetString("DEV.DATABASE_PASSWORD")
dbusername := viper.GetString("DEV.DATABASE_USERNAME")
dbport := viper.GetString("DEV.DATABASE_PORT")
dbhost := viper.GetString("DEV.DATABASE_SERVER_HOST")
contextkey := viper.GetString("DEV.USER_CONTEXT_KEY")
jwtkey := viper.GetString("DEV.JWT_SECRET_KEY")
return dbport, dbname, dbpassword, dbusername, dbhost, contextkey, jwtkey
}
func LiveConfig() (Port, DBname, Password, Username, Host, key, secret string) {
viper.SetConfigName("config") // config file name without extension
viper.SetConfigType("yaml")
viper.AddConfigPath(".")
err := viper.ReadInConfig()
if err != nil {
Logger.Fatalf("fatal error config file: default \n %v", err)
}
dbname := viper.GetString("APP.DATABASE_NAME")
dbpassword := viper.GetString("APP.DATABASE_PASSWORD")
dbusername := viper.GetString("APP.DATABASE_USERNAME")
dbport := viper.GetString("APP.DATABASE_PORT")
dbhost := viper.GetString("APP.DATABASE_SERVER_HOST")
contextkey := viper.GetString("APP.USER_CONTEXT_KEY")
jwtkey := viper.GetString("APP.JWT_SECRET_KEY")
return dbport, dbname, dbpassword, dbusername, dbhost, contextkey, jwtkey
}

42
utils/logger.go Normal file
View File

@@ -0,0 +1,42 @@
package utils
import (
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
var Logger *zap.SugaredLogger
func init() {
config := zap.NewProductionConfig()
config.EncoderConfig.TimeKey = "time"
config.EncoderConfig.EncodeTime = zapcore.RFC3339TimeEncoder
config.EncoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
l, err := config.Build()
if err != nil {
// Fallback to basic logger if zap fails
l, _ = zap.NewDevelopment()
}
Logger = l.Sugar()
}
// Info logs messages at level info
func Info(msg string, keysAndValues ...interface{}) {
Logger.Infow(msg, keysAndValues...)
}
// Error logs messages at level error
func Error(msg string, keysAndValues ...interface{}) {
Logger.Errorw(msg, keysAndValues...)
}
// Debug logs messages at level debug
func Debug(msg string, keysAndValues ...interface{}) {
Logger.Debugw(msg, keysAndValues...)
}
// Warn logs messages at level warn
func Warn(msg string, keysAndValues ...interface{}) {
Logger.Warnw(msg, keysAndValues...)
}