This commit is contained in:
@@ -19,12 +19,19 @@ type Product struct {
|
|||||||
func (Product) TableName() string { return "products" }
|
func (Product) TableName() string { return "products" }
|
||||||
|
|
||||||
type ProductPrice struct {
|
type ProductPrice struct {
|
||||||
ID int `json:"id" gorm:"primaryKey;autoIncrement"`
|
ID int `json:"id" gorm:"primaryKey;autoIncrement"`
|
||||||
ProductID int `json:"product_id" gorm:"column:product_id;index"`
|
ProductID int `json:"product_id" gorm:"column:product_id;index"`
|
||||||
Quantity float64 `json:"quantity" gorm:"column:quantity" binding:"required"`
|
Quantity float64 `json:"quantity" gorm:"column:quantity" binding:"required"`
|
||||||
Price float64 `json:"price" gorm:"column:price" binding:"required"`
|
Price float64 `json:"price" gorm:"column:price" binding:"required"`
|
||||||
CreatedAt time.Time `json:"created_at" gorm:"autoCreateTime"`
|
CreatedAt time.Time `json:"created_at" gorm:"autoCreateTime"`
|
||||||
ActivePrice bool `json:"active_price" gorm:"column:active_price;default:true"`
|
// Pas de tag gorm "default:true" ici : GORM omet de l'INSERT tout champ
|
||||||
|
// dont la valeur Go est la valeur zéro (false) s'il porte un tag
|
||||||
|
// "default", laissant Postgres appliquer sa propre valeur par défaut
|
||||||
|
// (TRUE) à la place — un prix explicitement désactivé (false) revenait
|
||||||
|
// donc toujours actif après un Create(). La colonne a déjà son défaut
|
||||||
|
// TRUE posé au niveau SQL (db_init.go), ce tag Go était redondant et
|
||||||
|
// seulement source du bug.
|
||||||
|
ActivePrice bool `json:"active_price" gorm:"column:active_price"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ProductPrice) TableName() string { return "product_prices" }
|
func (ProductPrice) TableName() string { return "product_prices" }
|
||||||
|
|||||||
@@ -278,6 +278,55 @@ func TestUpdateProduct_UpdatesStockWhenProvided(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// productPriceActiveFlags relit active_price par palier de quantité pour un
|
||||||
|
// produit, directement en base.
|
||||||
|
func productPriceActiveFlags(t *testing.T, productID int) map[float64]bool {
|
||||||
|
t.Helper()
|
||||||
|
var rows []struct {
|
||||||
|
Quantity float64 `gorm:"column:quantity"`
|
||||||
|
ActivePrice bool `gorm:"column:active_price"`
|
||||||
|
}
|
||||||
|
if err := testDB.GDB.Raw(
|
||||||
|
`SELECT quantity, active_price FROM product_prices WHERE product_id = ?`, productID,
|
||||||
|
).Scan(&rows).Error; err != nil {
|
||||||
|
t.Fatalf("lecture active_price: %v", err)
|
||||||
|
}
|
||||||
|
out := make(map[float64]bool, len(rows))
|
||||||
|
for _, r := range rows {
|
||||||
|
out[r.Quantity] = r.ActivePrice
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// Un prix explicitement désactivé (active_price=false) doit rester désactivé
|
||||||
|
// après UpdateProduct — piège classique de GORM : un champ bool à sa valeur
|
||||||
|
// zéro (false) avec un tag gorm "default" est omis de l'INSERT, laissant la
|
||||||
|
// base appliquer son propre défaut (TRUE) à la place. Voir le commentaire sur
|
||||||
|
// ProductPrice.ActivePrice dans models/product.go.
|
||||||
|
func TestUpdateProduct_PersistsInactivePriceFlag(t *testing.T) {
|
||||||
|
cleanupStockTestData(t)
|
||||||
|
cat := newTestCategory(t, "CatInactive")
|
||||||
|
productID := newTestProduct(t, "UPInactive", 5)
|
||||||
|
|
||||||
|
body := []byte(fmt.Sprintf(
|
||||||
|
`{"name":"UPInactive","category":%q,"description":"d2","unit":"g","stock":10,"prices":[{"quantity":1,"price":5,"active_price":false},{"quantity":5,"price":20,"active_price":true}]}`,
|
||||||
|
cat,
|
||||||
|
))
|
||||||
|
c, rec := updateProductJSONContext("admin", body, productID)
|
||||||
|
handlers.UpdateProduct(c)
|
||||||
|
if rec.Code != http.StatusOK {
|
||||||
|
t.Fatalf("UpdateProduct valide doit réussir: got=%d body=%s", rec.Code, rec.Body.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
flags := productPriceActiveFlags(t, productID)
|
||||||
|
if flags[1] != false {
|
||||||
|
t.Errorf("palier qty=1 doit rester désactivé après UpdateProduct: got active_price=%v", flags[1])
|
||||||
|
}
|
||||||
|
if flags[5] != true {
|
||||||
|
t.Errorf("palier qty=5 doit rester actif après UpdateProduct: got active_price=%v", flags[5])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ── DeleteProduct ────────────────────────────────────────────────────────
|
// ── DeleteProduct ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
func TestDeleteProduct_RemovesProductWithoutMedia(t *testing.T) {
|
func TestDeleteProduct_RemovesProductWithoutMedia(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user