Bridge global catalogue DB to per-store product catalogue
Adds a separate CatalogueDB (pgvector) connection alongside the main nearledb, plus a new catalogue module (repository/service/controller/ routes) to browse it by brand, category, and keyword, with brand optional so the whole ~237-product catalogue can be browsed unfiltered. Adds the actual bridge: importing a catalogue product snapshots it into the tenant's own products table (keyed on brand+catalogueid, since a catalogue row's bare id is only unique within its own brand table), then links it via the existing productlocations upsert. Re-importing tops up stock and refreshes price instead of duplicating. Also adds an imported-refs endpoint so the frontend can badge already-imported items without diffing full product lists, and wires the new AWS S3 image store used to resolve catalogue product photos. Bumps Go/Docker to 1.24 for the AWS SDK dependency this needs. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -36,6 +37,10 @@ type ProductRepository interface {
|
||||
CreateProductLocation(input []models.Productlocations) error
|
||||
CreateProductVariant(input models.Productvariant) error
|
||||
DeleteProductLocation(tenantid, locationid, productid int) error
|
||||
FindTenantProductByCatalogueRef(tenantid int, brand string, catalogueid int64) (*models.Products, error)
|
||||
CreateProductReturningID(product models.Products) (int, error)
|
||||
GetImportedCatalogueRefs(tenantid int, brand string) ([]models.ImportedCatalogueRef, error)
|
||||
UpdateProductPricing(productid int, retailprice, productcost, taxpercent float64) error
|
||||
}
|
||||
|
||||
type productRepository struct {
|
||||
@@ -753,3 +758,60 @@ func (r *productRepository) DeleteProductLocation(tenantid, locationid, producti
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindTenantProductByCatalogueRef looks up the tenant's existing snapshot of
|
||||
// a catalogue product, keyed on (tenantid, brand, catalogueid) since a
|
||||
// catalogue row's bare id is only unique within its own brand table.
|
||||
func (r *productRepository) FindTenantProductByCatalogueRef(tenantid int, brand string, catalogueid int64) (*models.Products, error) {
|
||||
var product models.Products
|
||||
result := r.db.Table("products").
|
||||
Where("tenantid = ? AND productbrand = ? AND catalogueid = ?", tenantid, brand, catalogueid).
|
||||
First(&product)
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, result.Error
|
||||
}
|
||||
return &product, nil
|
||||
}
|
||||
|
||||
// CreateProductReturningID inserts a new product snapshot and returns its
|
||||
// generated productid. Kept separate from CreateProduct so existing callers
|
||||
// of CreateProduct are unaffected.
|
||||
func (r *productRepository) CreateProductReturningID(product models.Products) (int, error) {
|
||||
if err := r.db.Create(&product).Error; err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return product.Productid, nil
|
||||
}
|
||||
|
||||
// GetImportedCatalogueRefs returns the (brand, catalogueid) pairs this
|
||||
// tenant has already imported, so a catalogue browse screen can mark items
|
||||
// as already-imported without diffing full product lists client-side. Brand
|
||||
// is optional: omitted, it covers every brand at once — needed because the
|
||||
// all-brands browse view mixes products whose bare catalogueid can collide
|
||||
// across brand tables, so brand must travel with every id.
|
||||
func (r *productRepository) GetImportedCatalogueRefs(tenantid int, brand string) ([]models.ImportedCatalogueRef, error) {
|
||||
refs := make([]models.ImportedCatalogueRef, 0)
|
||||
query := r.db.Table("products").
|
||||
Select("productbrand AS brand, catalogueid").
|
||||
Where("tenantid = ? AND catalogueid IS NOT NULL AND catalogueid != 0", tenantid)
|
||||
if brand != "" {
|
||||
query = query.Where("productbrand = ?", brand)
|
||||
}
|
||||
err := query.Scan(&refs).Error
|
||||
return refs, err
|
||||
}
|
||||
|
||||
// UpdateProductPricing updates only the pricing fields on a product
|
||||
// snapshot, used when a catalogue product is re-imported with new pricing.
|
||||
func (r *productRepository) UpdateProductPricing(productid int, retailprice, productcost, taxpercent float64) error {
|
||||
return r.db.Table("products").
|
||||
Where("productid = ?", productid).
|
||||
Updates(map[string]interface{}{
|
||||
"retailprice": retailprice,
|
||||
"productcost": productcost,
|
||||
"taxpercent": taxpercent,
|
||||
}).Error
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user