Files
b2b/app/repos/productsRepo/productsRepo.go
2026-04-15 13:19:28 +02:00

301 lines
8.8 KiB
Go

package productsRepo
import (
"encoding/json"
"git.ma-al.com/goc_daniel/b2b/app/config"
"git.ma-al.com/goc_daniel/b2b/app/db"
"git.ma-al.com/goc_daniel/b2b/app/model"
"git.ma-al.com/goc_daniel/b2b/app/model/dbmodel"
"git.ma-al.com/goc_daniel/b2b/app/utils/query/filters"
"git.ma-al.com/goc_daniel/b2b/app/utils/query/find"
"git.ma-al.com/goc_daniel/b2b/app/view"
"git.ma-al.com/goc_marek/gormcol"
"github.com/WinterYukky/gorm-extra-clause-plugin/exclause"
)
type UIProductsRepo interface {
// GetJSON(p_id_product, p_id_shop, p_id_lang, p_id_customer, b2b_id_country, p_quantity int) (*json.RawMessage, error)
Find(id_lang uint, userID uint, p find.Paging, filt *filters.FiltersList) (*find.Found[model.ProductInList], error)
GetProductVariants(langID uint, productID uint, shopID uint, customerID uint, countryID uint, quantity uint) ([]view.ProductAttribute, error)
GetBase(p_id_product, p_id_shop, p_id_lang, p_id_customer uint) (view.Product, error)
GetPrice(p_id_product uint, productAttributeID *uint, p_id_shop uint, p_id_customer uint, p_id_country uint, p_quantity uint) (view.Price, error)
GetVariants(p_id_product, p_id_shop, p_id_lang, p_id_customer, p_id_country, p_quantity uint) ([]view.ProductAttribute, error)
AddToFavorites(userID uint, productID uint) error
RemoveFromFavorites(userID uint, productID uint) error
ExistsInFavorites(userID uint, productID uint) (bool, error)
ProductInDatabase(productID uint) (bool, error)
}
type ProductsRepo struct{}
func New() UIProductsRepo {
return &ProductsRepo{}
}
func (repo *ProductsRepo) GetBase(p_id_product, p_id_shop, p_id_lang, p_id_customer uint) (view.Product, error) {
var result view.Product
err := db.DB.Raw(`CALL get_product_base(?,?,?,?)`,
p_id_product, p_id_shop, p_id_lang, p_id_customer).
Scan(&result).Error
return result, err
}
func (repo *ProductsRepo) GetPrice(
p_id_product uint, productAttributeID *uint, p_id_shop uint, p_id_customer uint, p_id_country uint, p_quantity uint,
) (view.Price, error) {
type row struct {
Price json.RawMessage `gorm:"column:price"`
}
var r row
err := db.DB.Raw(`
SELECT fn_product_price(?,?,?,?,?,?) AS price`,
p_id_product, p_id_shop, p_id_customer, p_id_country, p_quantity, productAttributeID).
Scan(&r).Error
if err != nil {
return view.Price{}, err
}
var temp struct {
Base json.Number `json:"base"`
FinalTaxExcl json.Number `json:"final_tax_excl"`
FinalTaxIncl json.Number `json:"final_tax_incl"`
TaxRate json.Number `json:"tax_rate"`
Priority json.Number `json:"priority"`
}
if err := json.Unmarshal(r.Price, &temp); err != nil {
return view.Price{}, err
}
price := view.Price{
Base: mustParseFloat(temp.Base),
FinalTaxExcl: mustParseFloat(temp.FinalTaxExcl),
FinalTaxIncl: mustParseFloat(temp.FinalTaxIncl),
TaxRate: mustParseFloat(temp.TaxRate),
Priority: mustParseInt(temp.Priority),
}
return price, nil
}
func mustParseFloat(n json.Number) float64 {
f, _ := n.Float64()
return f
}
func mustParseInt(n json.Number) int {
i, _ := n.Int64()
return int(i)
}
func (repo *ProductsRepo) GetVariants(p_id_product, p_id_shop, p_id_lang, p_id_customer, p_id_country, p_quantity uint) ([]view.ProductAttribute, error) {
var results []view.ProductAttribute
err := db.DB.Raw(`
CALL get_product_variants(?,?,?,?,?,?)`,
p_id_product, p_id_shop, p_id_lang, p_id_customer, p_id_country, p_quantity).
Scan(&results).Error
return results, err
}
func (repo *ProductsRepo) Find(langID uint, userID uint, p find.Paging, filt *filters.FiltersList) (*find.Found[model.ProductInList], error) {
query := db.DB.
Table("base_products AS bp").
Clauses(exclause.With{
CTEs: []exclause.CTE{
{
Name: "favorites",
Subquery: exclause.Subquery{
DB: db.DB.
Table("b2b_favorites").
Select(`
product_id AS product_id,
COUNT(*) > 0 AS is_favorite
`).
Where("user_id = ?", userID).
Group("product_id"),
},
},
{
Name: "oems",
Subquery: exclause.Subquery{
DB: db.DB.
Table("b2b_oems").
Select(`
product_id AS product_id,
COUNT(*) > 0 AS is_customers_oem
`).
Where("user_id = ?", userID).
Group("product_id"),
},
},
{
Name: "new_product_days",
Subquery: exclause.Subquery{
DB: db.DB.
Table("ps_configuration").
Select("CAST(value AS SIGNED) AS days").
Where("name = ?", "PS_NB_DAYS_NEW_PRODUCT"),
},
},
{
Name: "variants",
Subquery: exclause.Subquery{
DB: db.DB.
Table("ps_product_attribute_shop").
Select("id_product, COUNT(*) AS variants_number").
Group("id_product"),
},
},
{
Name: "base_products",
Subquery: exclause.Subquery{
DB: db.DB.
Table(gormcol.Field.Tab(dbmodel.PsProductShopCols.Active)+" AS ps").
Select(`
ps.id_product AS product_id,
pl.name AS name,
ps.id_category_default AS category_id,
p.reference AS reference,
p.is_oem AS is_oem,
sa.quantity AS quantity,
COALESCE(f.is_favorite, 0) AS is_favorite,
CASE
WHEN ps.date_add >= DATE_SUB(
NOW(),
INTERVAL COALESCE(npd.days, 20) DAY
) AND ps.active = 1
THEN 1
ELSE 0
END AS is_new
`).
Joins("JOIN "+dbmodel.PsProductCols.IDProduct.Tab()+" p ON p.id_product = ps.id_product").
Joins("JOIN ps_product_lang pl ON pl.id_product = ps.id_product AND pl.id_lang = ?", langID).
Joins("LEFT JOIN favorites f ON f.product_id = ps.id_product").
Joins("LEFT JOIN ps_stock_available sa ON sa.id_product = ps.id_product AND sa.id_product_attribute = 0").
Joins("LEFT JOIN new_product_days npd ON 1 = 1").
Joins("LEFT JOIN oems ON oems.product_id = ps.id_product").
Where("ps.active = ?", 1).
Where("(p.is_oem = 0 OR oems.is_customers_oem > 0)").
Group("ps.id_product"),
},
},
},
}).
Select(`
bp.product_id AS product_id,
bp.name AS name,
pl.link_rewrite AS link_rewrite,
CONCAT(?, '/', ims.id_image, '-small_default/', pl.link_rewrite, '.webp') AS image_link,
cl.name AS category_name,
bp.reference AS reference,
COALESCE(v.variants_number, 0) AS variants_number,
bp.quantity AS quantity,
bp.is_favorite AS is_favorite,
bp.is_new AS is_new,
bp.is_oem AS is_oem
`, config.Get().Image.ImagePrefix).
Joins("JOIN ps_product_lang pl ON pl.id_product = bp.product_id AND pl.id_lang = ?", langID).
Joins("JOIN ps_image_shop ims ON ims.id_product = bp.product_id AND ims.cover = 1").
Joins("JOIN ps_category_lang cl ON cl.id_category = bp.category_id AND cl.id_lang = ?", langID).
Joins("LEFT JOIN variants v ON v.id_product = bp.product_id").
Order("bp.product_id DESC")
query = query.Scopes(filt.All()...)
list, err := find.Paginate[model.ProductInList](langID, p, query)
if err != nil {
return nil, err
}
return &list, nil
}
func (repo *ProductsRepo) GetProductVariants(langID uint, productID uint, shopID uint, customerID uint, countryID uint, quantity uint) ([]view.ProductAttribute, error) {
var result []view.ProductAttribute
err := db.DB.
Raw(`
CALL get_product_attributes_with_price(?, ?, ?, ?, ?, ?)
`,
langID,
productID,
shopID,
customerID,
countryID,
quantity,
).
Scan(&result).Error
if err != nil {
return nil, err
}
return result, nil
}
func (repo *ProductsRepo) PopulateProductPrice(product *model.ProductInList, targetCustomer *model.Customer, quantity int, shopID uint) error {
row := db.Get().Raw(
"CALL get_product_price(?, ?, ?, ?, ?)",
product.ProductID,
shopID,
targetCustomer.ID,
targetCustomer.CountryID,
quantity,
).Row()
var (
id uint
base float64
excl float64
incl float64
tax float64
)
err := row.Scan(&id, &base, &excl, &incl, &tax)
if err != nil {
return err
}
product.PriceTaxExcl = excl
product.PriceTaxIncl = incl
return nil
}
func (repo *ProductsRepo) AddToFavorites(userID uint, productID uint) error {
fav := model.B2bFavorite{
UserID: userID,
ProductID: productID,
}
return db.Get().Create(&fav).Error
}
func (repo *ProductsRepo) RemoveFromFavorites(userID uint, productID uint) error {
return db.Get().
Where("user_id = ? AND product_id = ?", userID, productID).
Delete(&model.B2bFavorite{}).Error
}
func (repo *ProductsRepo) ExistsInFavorites(userID uint, productID uint) (bool, error) {
var count int64
err := db.Get().
Table("b2b_favorites").
Where("user_id = ? AND product_id = ?", userID, productID).
Count(&count).Error
return count >= 1, err
}
func (repo *ProductsRepo) ProductInDatabase(productID uint) (bool, error) {
var count int64
err := db.Get().
Table(dbmodel.TableNamePsProduct).
Where(dbmodel.PsProductCols.IDProduct.Col()+" = ?", productID).
Count(&count).Error
return count >= 1, err
}