Initial commit of Descrybe v2 without local scratch artifacts.
Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
package catalog
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5"
|
||||
)
|
||||
|
||||
const maxResetProductIDs = 5000
|
||||
|
||||
// ResetProductsToUnprocessed resets selected products so they reappear as unprocessed raw items.
|
||||
// kind "raw" updates raw_products by id; kind "processed" (default) deletes processed rows and
|
||||
// resets linked raw rows (by raw_product_id and shared product_id/gtin), matching legacy behavior.
|
||||
func (s *Service) ResetProductsToUnprocessed(ctx context.Context, companyID uuid.UUID, productIDs []uuid.UUID, kind string) (map[string]any, error) {
|
||||
if len(productIDs) == 0 {
|
||||
return nil, ClientMsg("product_ids is required")
|
||||
}
|
||||
if len(productIDs) > maxResetProductIDs {
|
||||
return nil, ClientMsg(fmt.Sprintf("at most %d product_ids allowed", maxResetProductIDs))
|
||||
}
|
||||
|
||||
tx, err := s.Pool.Begin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer tx.Rollback(ctx)
|
||||
|
||||
var resetCount int64
|
||||
switch kind {
|
||||
case "raw":
|
||||
resetCount, err = resetRawProducts(ctx, tx, companyID, productIDs)
|
||||
default:
|
||||
resetCount, err = resetProcessedProducts(ctx, tx, companyID, productIDs)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := tx.Commit(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return map[string]any{
|
||||
"success": true,
|
||||
"reset_count": resetCount,
|
||||
"message": fmt.Sprintf("%d product(s) returned to unprocessed state", resetCount),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func resetRawProducts(ctx context.Context, tx pgx.Tx, companyID uuid.UUID, ids []uuid.UUID) (int64, error) {
|
||||
ct, err := tx.Exec(ctx, `
|
||||
UPDATE raw_products
|
||||
SET is_processed = false,
|
||||
processing_status = 'unprocessed',
|
||||
updated_at = now()
|
||||
WHERE company_id = $1 AND id = ANY($2::uuid[])`, companyID, ids)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
_, err = tx.Exec(ctx, `
|
||||
DELETE FROM processed_products
|
||||
WHERE company_id = $1 AND raw_product_id = ANY($2::uuid[])`, companyID, ids)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return ct.RowsAffected(), nil
|
||||
}
|
||||
|
||||
func resetProcessedProducts(ctx context.Context, tx pgx.Tx, companyID uuid.UUID, ids []uuid.UUID) (int64, error) {
|
||||
rows, err := tx.Query(ctx, `
|
||||
SELECT id, raw_product_id, product_id
|
||||
FROM processed_products
|
||||
WHERE company_id = $1 AND id = ANY($2::uuid[])`, companyID, ids)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
processedIDs := make([]uuid.UUID, 0, len(ids))
|
||||
rawIDs := make([]uuid.UUID, 0)
|
||||
gtins := make([]string, 0)
|
||||
seenGTIN := map[string]struct{}{}
|
||||
for rows.Next() {
|
||||
var id uuid.UUID
|
||||
var rawID *uuid.UUID
|
||||
var productID *string
|
||||
if err := rows.Scan(&id, &rawID, &productID); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
processedIDs = append(processedIDs, id)
|
||||
if rawID != nil {
|
||||
rawIDs = append(rawIDs, *rawID)
|
||||
}
|
||||
if productID != nil {
|
||||
g := *productID
|
||||
if g != "" {
|
||||
if _, ok := seenGTIN[g]; !ok {
|
||||
seenGTIN[g] = struct{}{}
|
||||
gtins = append(gtins, g)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if len(processedIDs) == 0 {
|
||||
return 0, ClientMsg("no products found to return to unprocessed state")
|
||||
}
|
||||
|
||||
if len(gtins) > 0 {
|
||||
_, err = tx.Exec(ctx, `
|
||||
UPDATE raw_products
|
||||
SET is_processed = false,
|
||||
processing_status = 'unprocessed',
|
||||
updated_at = now()
|
||||
WHERE company_id = $1 AND gtin = ANY($2::text[])`, companyID, gtins)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
if len(rawIDs) > 0 {
|
||||
_, err = tx.Exec(ctx, `
|
||||
UPDATE raw_products
|
||||
SET is_processed = false,
|
||||
processing_status = 'unprocessed',
|
||||
updated_at = now()
|
||||
WHERE company_id = $1 AND id = ANY($2::uuid[])`, companyID, rawIDs)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
ct, err := tx.Exec(ctx, `
|
||||
DELETE FROM processed_products
|
||||
WHERE company_id = $1 AND id = ANY($2::uuid[])`, companyID, processedIDs)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return ct.RowsAffected(), nil
|
||||
}
|
||||
Reference in New Issue
Block a user