Files
backend_fiesta/repositories/tenantRepository.go
2026-05-25 11:52:26 +05:30

738 lines
20 KiB
Go

package repositories
import (
"errors"
"fmt"
"nearle/models"
"strconv"
"strings"
"github.com/jinzhu/copier"
"gorm.io/gorm"
)
type TenantRepository interface {
SearchTenant(status, searchstr string) ([]models.Tenantinfo, error)
GetAllTenants(pageno, pagesize, aid int, status, tenanttype, keyword string) ([]models.Tenantinfo, error)
GetTenantLocations(tid int) ([]models.Tenantlocations, error)
GetTenantSlot() (models.Tenantslot, error)
CreateTenantCustomer(customer models.Tenantcustomer) (*models.Tenantcustomer, error)
GetCustomerTenants(customerID int, categoryID int, tenantFlag int) ([]models.TenantInfo, error)
GetTenantPricing(tid, aid int) (*models.Tenantpricing, error)
UpdateLocation(input models.Tenantlocations) error
CreateLocation(data models.Tenantlocations) error
GetStaffs(tid int) ([]models.StaffInfo, error)
CreateStaff(user models.User) error
UpdateStaff(user models.User) error
CreateTenantLocation(data models.Tenantlocations) error
UpdateTenantLocation(data models.Tenantlocations) error
CheckTenantByNo(cno string) int
CreateTenantUser(data models.Tenants) (bool, error)
GetUserByNo(cno string) models.UserInfo
GetTenantByID(tid int, locationid int) (models.Tenantinfo, error)
GetTenantByKeyword(keyword string) ([]models.TenantSearch, error)
}
type tenantRepository struct {
db *gorm.DB
}
func NewTenantRepository(db *gorm.DB) TenantRepository {
return &tenantRepository{db: db}
}
func (r *tenantRepository) SearchTenant(status, keyword string) ([]models.Tenantinfo, error) {
var data []models.Tenantinfo
var query string
searchStr := strings.ToLower(keyword)
if strings.ToLower(status) != "pending" {
query = `
SELECT a.*, b.subcategoryname, c.firstname, c.lastname,
CONCAT(c.firstname, ' ', c.lastname) AS accountname
FROM tenants a
INNER JOIN app_subcategory b ON a.subcategoryid = b.subcategoryid
LEFT JOIN app_users c ON c.userid = a.partneruserid
WHERE a.approved = 1
AND LOWER(a.status) = ?
AND LOWER(a.tenantname) LIKE ?
`
r.db.Raw(query, strings.ToLower(status), searchStr+"%").Scan(&data)
} else {
query = `
SELECT a.*, b.subcategoryname, c.firstname, c.lastname,
CONCAT(c.firstname, ' ', c.lastname) AS accountname
FROM tenants a
INNER JOIN app_subcategory b ON a.subcategoryid = b.subcategoryid
LEFT JOIN app_users c ON c.userid = a.partneruserid
WHERE a.approved = 0
AND LOWER(a.tenantname) LIKE ?
`
r.db.Raw(query, searchStr+"%").Scan(&data)
}
return data, nil
}
func (r *tenantRepository) GetAllTenants(pageno, pagesize, aid int, status, tenanttype, keyword string) ([]models.Tenantinfo, error) {
offset := (pageno - 1) * pagesize
var data []models.Tenantinfo
base := `SELECT * FROM tenants a 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 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)
err := r.db.Raw(base, params...).Scan(&data).Error
if err != nil {
return nil, err
}
return data, nil
}
func (r *tenantRepository) GetTenantLocations(tid int) ([]models.Tenantlocations, error) {
var data []models.Tenantlocations
q1 := `SELECT a.*, b.roleid FROM tenantlocations a
LEFT JOIN app_users b ON a.locationid = b.locationid
AND a.tenantid = b.tenantid
WHERE a.tenantid = ?`
if err := r.db.Raw(q1, tid).Find(&data).Error; err != nil {
return nil, err
}
print(q1)
return data, nil
}
func (r *tenantRepository) GetTenantSlot() (models.Tenantslot, error) {
var data models.Tenantslot
err := r.db.Raw(`SELECT * FROM tenantslot`).Find(&data).Error
if err != nil {
return models.Tenantslot{}, err
}
return data, nil
}
func (r *tenantRepository) CreateTenantCustomer(customer models.Tenantcustomer) (*models.Tenantcustomer, error) {
var existing models.Tenantcustomer
// 🔍 Step 1: Check if a record already exists with same customerid and locationid
err := r.db.
Where("customerid = ? AND locationid = ?", customer.CustomerID, customer.LocationID).
First(&existing).Error
// If record found, prevent insertion
if err == nil {
return nil, fmt.Errorf("customer already exists for this location")
}
// If error other than record not found, return it
if !errors.Is(err, gorm.ErrRecordNotFound) {
return nil, err
}
// ✅ Step 2: Insert new record if no duplicate found
if err := r.db.Create(&customer).Error; err != nil {
return nil, err
}
return &customer, nil
}
func (r *tenantRepository) GetCustomerTenants(customerID int, categoryID int, tenantFlag int) ([]models.TenantInfo, error) {
var tenants []models.TenantInfo
query := `
SELECT a.customerid, a.locationid, b.tenantid,b.tenantname,b.address,b.licenseno,
b.primaryemail,b.primarycontact,b.applocationid,b.suburb,b.city,
b.latitude,b.longitude,b.postcode,b.tenantimage,b.subcategoryid,
b.categoryid,b.registrationno,d.userfcmtoken,c.locationname,
COALESCE(o.orderscount, 0) AS orderscount
FROM tenantcustomers a
LEFT JOIN tenants b ON a.tenantid = b.tenantid
INNER JOIN tenantlocations c ON a.locationid = c.locationid
LEFT JOIN (
SELECT tenantid, customerid, COUNT(*) AS orderscount
FROM orders
GROUP BY tenantid, customerid
) o ON b.tenantid = o.tenantid AND o.customerid = a.customerid
LEFT JOIN (
SELECT locationid,
MAX(userfcmtoken) AS userfcmtoken
FROM app_users
GROUP BY locationid
) d ON d.locationid = a.locationid
WHERE a.customerid = ?
AND b.tenantid IS NOT NULL
`
args := []interface{}{customerID}
if categoryID != 0 {
query += " AND b.categoryid = ?"
args = append(args, categoryID)
}
if tenantFlag == 1 {
query += " AND COALESCE(o.orderscount,0) > 0"
}
if err := r.db.Raw(query, args...).Scan(&tenants).Error; err != nil {
return nil, err
}
if tenants == nil {
return []models.TenantInfo{}, nil
}
// Attach top 5 subcategories
if len(tenants) > 0 {
var subcategories []models.ProductSubcategory
if err := r.db.Table("productsubcategories").
Order("subcatid ASC").
Limit(5).
Find(&subcategories).Error; err != nil {
return nil, err
}
for i := range tenants {
tenants[i].ProductSubcategory = subcategories
}
}
print(tenants)
return tenants, nil
}
func (r *tenantRepository) GetTenantPricing(tid, aid int) (*models.Tenantpricing, error) {
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`
}
if err := r.db.Raw(q1, tid).Find(&data).Error; err != nil {
return nil, err
}
return &data, nil
}
func (r *tenantRepository) UpdateLocation(input models.Tenantlocations) error {
tx := r.db.Begin()
if err := tx.Where("locationid=?", input.Locationid).Updates(&input).Error; err != nil {
tx.Rollback()
return err
}
if err := tx.Commit().Error; err != nil {
return err
}
return nil
}
func (r *tenantRepository) CreateLocation(data models.Tenantlocations) error {
var cust models.Customers
var tcust models.Tenantcustomers
var custloc models.Customerlocations
tx := r.db.Begin()
if err := tx.Create(&data).Error; err != nil {
tx.Rollback()
return err
}
cust.Firstname = data.Locationname
cust.Email = data.Email
cust.Contactno = data.Contactno
cust.Address = data.Address
cust.Suburb = data.Suburb
cust.City = data.City
cust.State = data.State
cust.Postcode = data.Postcode
cust.Applocationid = data.Applocationid
cust.Latitude = data.Latitude
cust.Longitude = data.Longitude
cust.Primaryaddress = 0
if err := tx.Table("customers").Create(&cust).Error; err != nil {
tx.Rollback()
return err
}
if err := copier.Copy(&custloc, &cust); err != nil {
tx.Rollback()
return err
}
if err := tx.Table("customerlocations").Create(&custloc).Error; err != nil {
tx.Rollback()
return err
}
tcust.Customerid = cust.Customerid
tcust.Tenantid = data.Tenantid
tcust.Locationid = data.Locationid
tcust.Moduleid = data.Moduleid
if err := tx.Table("tenantcustomers").Create(&tcust).Error; err != nil {
tx.Rollback()
return err
}
if err := tx.Commit().Error; err != nil {
return err
}
return nil
}
func (r *tenantRepository) GetStaffs(tid int) ([]models.StaffInfo, error) {
var data []models.StaffInfo
q1 := `SELECT a.userid,a.firstname,a.lastname,
CONCAT(a.firstname,' ',a.lastname) AS fullname,
a.email,a.contactno,a.address,a.suburb,a.city,
a.state,a.postcode,a.userfcmtoken,a.pin,a.applocationid,
a.roleid,a.partnerid,a.tenantid,a.locationid,
b.locationname
FROM app_users a
INNER JOIN tenantlocations b ON a.locationid = b.locationid
WHERE a.tenantid = ?`
if err := r.db.Raw(q1, tid).Scan(&data).Error; err != nil {
return nil, err
}
return data, nil
}
func (r *tenantRepository) CreateStaff(user models.User) error {
if err := r.db.Table("app_users").Create(&user).Error; err != nil {
return err
}
return nil
}
func (r *tenantRepository) UpdateStaff(user models.User) error {
if err := r.db.Table("app_users").Where("userid = ?", user.Userid).Updates(&user).Error; err != nil {
return err
}
return nil
}
func (r *tenantRepository) CreateTenantLocation(data models.Tenantlocations) error {
var user models.Tenantuser
tx := r.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 (r *tenantRepository) UpdateTenantLocation(input models.Tenantlocations) error {
tx := r.db.Begin()
// ✅ Step 1: Prepare map for tenantlocations update
locationUpdate := make(map[string]interface{})
if input.Locationname != "" {
locationUpdate["locationname"] = input.Locationname
}
if input.Email != "" {
locationUpdate["email"] = input.Email
}
if input.Contactno != "" {
locationUpdate["contactno"] = input.Contactno
}
if input.Address != "" {
locationUpdate["address"] = input.Address
}
if input.Suburb != "" {
locationUpdate["suburb"] = input.Suburb
}
if input.City != "" {
locationUpdate["city"] = input.City
}
if input.State != "" {
locationUpdate["state"] = input.State
}
if input.Postcode != "" {
locationUpdate["postcode"] = input.Postcode
}
if input.Partnerid != 0 {
locationUpdate["partnerid"] = input.Partnerid
}
if input.Tenantid != 0 {
locationUpdate["tenantid"] = input.Tenantid
}
if input.Applocationid != 0 {
locationUpdate["applocationid"] = input.Applocationid
}
if input.Status != "" {
locationUpdate["status"] = input.Status
}
// ✅ Step 2: Update tenantlocations (only provided fields)
if len(locationUpdate) > 0 {
if err := tx.Table("tenantlocations").
Where("locationid = ?", input.Locationid).
Updates(locationUpdate).Error; err != nil {
tx.Rollback()
return err
}
}
// ✅ Step 3: Prepare map for app_users update (only matching fields)
userUpdate := make(map[string]interface{})
if input.Locationname != "" {
userUpdate["firstname"] = input.Locationname
}
if input.Email != "" {
userUpdate["email"] = input.Email
}
if input.Contactno != "" {
userUpdate["contactno"] = input.Contactno
}
if input.Address != "" {
userUpdate["address"] = input.Address
}
if input.Suburb != "" {
userUpdate["suburb"] = input.Suburb
}
if input.City != "" {
userUpdate["city"] = input.City
}
if input.State != "" {
userUpdate["state"] = input.State
}
if input.Postcode != "" {
userUpdate["postcode"] = input.Postcode
}
if input.Tenantid != 0 {
userUpdate["tenantid"] = input.Tenantid
}
if input.Partnerid != 0 {
userUpdate["partnerid"] = input.Partnerid
}
if input.Applocationid != 0 {
userUpdate["applocationid"] = input.Applocationid
}
if input.Status != "" {
userUpdate["status"] = input.Status
}
// ✅ Step 4: Update app_users (only provided fields)
if len(userUpdate) > 0 {
if err := tx.Table("app_users").
Where("locationid = ?", input.Locationid).
Updates(userUpdate).Error; err != nil {
tx.Rollback()
return err
}
}
// ✅ Commit transaction
if err := tx.Commit().Error; err != nil {
return err
}
return nil
}
// ✅ Check if tenant exists
func (r *tenantRepository) CheckTenantByNo(cno string) int {
var id int
q1 := "SELECT tenantid FROM tenants WHERE primarycontact = '" + cno + `'`
r.db.Raw(q1).Find(&id)
return id
}
// ✅ Create tenant + user + customer records
func (r *tenantRepository) 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 := r.db.Begin()
// Step 1: Insert into tenants
if err := tx.Create(&data).Error; err != nil {
tx.Rollback()
return false, errors.New("error in tenant creation")
}
// Step 2: Create order sequence
seq.Tenantid = data.Tenantid
if err := tx.Table("ordersequences").Create(&seq).Error; err != nil {
tx.Rollback()
return false, errors.New("error in sequence")
}
// Step 3: Create app_user
if err := copier.Copy(&user, &data); err != nil {
tx.Rollback()
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
if err := tx.Table("app_users").Create(&user).Error; err != nil {
tx.Rollback()
return false, errors.New("error in user creation")
}
// Step 4: Create / Update customers
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 := r.CheckCustomer(data.Primarycontact)
if cid == 0 {
if err := tx.Table("customers").Create(&cust).Error; err != nil {
tx.Rollback()
return false, errors.New("error in customer creation")
}
if err := copier.Copy(&custloc, &cust); err != nil {
tx.Rollback()
return false, err
}
if err := tx.Table("customerlocations").Create(&custloc).Error; err != nil {
tx.Rollback()
return false, errors.New("error in customer location")
}
} else {
if err := tx.Table("customers").Where("customerid=?", cid).Updates(&cust).Error; err != nil {
tx.Rollback()
return false, errors.New("error updating customer")
}
if err := copier.Copy(&custloc, &cust); err != nil {
tx.Rollback()
return false, err
}
if err := tx.Table("customerlocations").Where("customerid=?", cid).Updates(&custloc).Error; err != nil {
tx.Rollback()
return false, errors.New("error updating customer location")
}
}
// Step 5: Create tenant-customer link
tcust.Customerid = cust.Customerid
tcust.Tenantid = data.Tenantid
tcust.Locationid = data.Tenantlocations.Locationid
if err := tx.Table("tenantcustomers").Create(&tcust).Error; err != nil {
tx.Rollback()
return false, errors.New("error in tenant customer")
}
// ✅ Commit transaction
if err := tx.Commit().Error; err != nil {
return false, errors.New("error in tenant creation")
}
return true, nil
}
// ✅ Check if customer exists
func (r *tenantRepository) CheckCustomer(cno string) int {
var id int
q := "SELECT customerid FROM customers WHERE contactno = '" + cno + `'`
r.db.Raw(q).Find(&id)
return id
}
// ✅ Get user by contact number
func (r *tenantRepository) 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,b.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 + `'`
r.db.Raw(q1).Find(&user)
return user
}
func (r *tenantRepository) GetTenantByID(tid int, locationid int) (models.Tenantinfo, error) {
var data models.Tenantinfo
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, f.contactno as locationcontact
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
WHERE a.tenantid = ?
`
var args []interface{}
args = append(args, tid)
if locationid != 0 {
q1 += " AND f.locationid = ?"
args = append(args, locationid)
}
if err := r.db.Raw(q1, args...).Find(&data).Error; err != nil {
return data, err
}
return data, nil
}
func (r *tenantRepository) GetTenantByKeyword(keyword string) ([]models.TenantSearch, error) {
var data []models.TenantSearch
kw := "%" + strings.ToLower(keyword) + "%"
query := `
SELECT a.tenantname, b.productname, c.subcatname
FROM tenants a
LEFT JOIN products b ON a.tenantid = b.tenantid
LEFT JOIN productsubcategories c ON b.subcategoryid = c.subcatid
WHERE c.categoryid = 2
AND (LOWER(a.tenantname) LIKE ? OR LOWER(b.productname) LIKE ? OR LOWER(c.subcatname) LIKE ?)
`
if err := r.db.Raw(query, kw, kw, kw).Scan(&data).Error; err != nil {
return nil, err
}
return data, nil
}