Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
142 lines
3.7 KiB
Go
142 lines
3.7 KiB
Go
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
|
|
}
|