mirror of
https://github.com/R0m1k3/Priceflow.git
synced 2026-10-22 22:58:11 +02:00
corretion
This commit is contained in:
1 parent
1893988bb1
commit
f7059da02a
5 files changed
+73
-42
No files matched your search
+22
-3
@@ -39,7 +39,7 @@ def update_item_category(item_id: int, category: str | None = None, db: Session
|
|||||||
item = db.query(models.Item).filter(models.Item.id == item_id).first()
|
item = db.query(models.Item).filter(models.Item.id == item_id).first()
|
||||||
if not item:
|
if not item:
|
||||||
raise HTTPException(status_code=404, detail="Item not found")
|
raise HTTPException(status_code=404, detail="Item not found")
|
||||||
|
|
||||||
# Treat empty string as None
|
# Treat empty string as None
|
||||||
item.category = category if category and category.strip() else None
|
item.category = category if category and category.strip() else None
|
||||||
db.commit()
|
db.commit()
|
||||||
@@ -77,7 +77,7 @@ def get_price_history(item_id: int, db: Session = Depends(database.get_db)):
|
|||||||
item = db.query(models.Item).filter(models.Item.id == item_id).first()
|
item = db.query(models.Item).filter(models.Item.id == item_id).first()
|
||||||
if not item:
|
if not item:
|
||||||
raise HTTPException(status_code=404, detail="Item not found")
|
raise HTTPException(status_code=404, detail="Item not found")
|
||||||
|
|
||||||
# Get price history sorted by timestamp descending (most recent first)
|
# Get price history sorted by timestamp descending (most recent first)
|
||||||
price_history = (
|
price_history = (
|
||||||
db.query(models.PriceHistory)
|
db.query(models.PriceHistory)
|
||||||
@@ -85,5 +85,24 @@ def get_price_history(item_id: int, db: Session = Depends(database.get_db)):
|
|||||||
.order_by(models.PriceHistory.timestamp.desc())
|
.order_by(models.PriceHistory.timestamp.desc())
|
||||||
.all()
|
.all()
|
||||||
)
|
)
|
||||||
|
|
||||||
return price_history
|
return price_history
|
||||||
|
|
||||||
|
|
||||||
|
@router.patch("/{item_id}/availability")
|
||||||
|
def update_item_availability(item_id: int, available: bool = True, db: Session = Depends(database.get_db)):
|
||||||
|
"""Mark an item as available or unavailable manually"""
|
||||||
|
item = db.query(models.Item).filter(models.Item.id == item_id).first()
|
||||||
|
if not item:
|
||||||
|
raise HTTPException(status_code=404, detail="Item not found")
|
||||||
|
|
||||||
|
item.is_available = available
|
||||||
|
# Also clear the error if marking as available
|
||||||
|
if available and item.last_error and "indisponible" in item.last_error.lower():
|
||||||
|
item.last_error = None
|
||||||
|
db.commit()
|
||||||
|
db.refresh(item)
|
||||||
|
return {
|
||||||
|
"message": f"Item marked as {'available' if available else 'unavailable'}",
|
||||||
|
"is_available": item.is_available,
|
||||||
|
}
|
||||||
@@ -57,6 +57,12 @@ def _update_db_result(
|
|||||||
item.current_price = price
|
item.current_price = price
|
||||||
item.current_price_confidence = p_conf
|
item.current_price_confidence = p_conf
|
||||||
|
|
||||||
|
# Auto-reset availability if price was successfully extracted
|
||||||
|
# A valid price proves the product is still available
|
||||||
|
if item.is_available is False:
|
||||||
|
item.is_available = True
|
||||||
|
logger.info(f"Item {item_id} marked as available again (price found: {price})")
|
||||||
|
|
||||||
session.add(
|
session.add(
|
||||||
models.PriceHistory(
|
models.PriceHistory(
|
||||||
item_id=item.id,
|
item_id=item.id,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { Label } from '@/components/ui/label';
|
|||||||
import { Marquee } from '@/components/ui/marquee';
|
import { Marquee } from '@/components/ui/marquee';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
export function ItemCard({ item, onEdit, onDelete, onCheck, onZoom, onCategoryUpdate, categories, onViewHistory }) {
|
export function ItemCard({ item, onEdit, onDelete, onCheck, onZoom, onCategoryUpdate, categories, onViewHistory, onMarkAvailable }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [showCategorySelect, setShowCategorySelect] = useState(false);
|
const [showCategorySelect, setShowCategorySelect] = useState(false);
|
||||||
const [showNewCategoryDialog, setShowNewCategoryDialog] = useState(false);
|
const [showNewCategoryDialog, setShowNewCategoryDialog] = useState(false);
|
||||||
@@ -73,11 +73,24 @@ export function ItemCard({ item, onEdit, onDelete, onCheck, onZoom, onCategoryUp
|
|||||||
{/* Product Unavailable Overlay */}
|
{/* Product Unavailable Overlay */}
|
||||||
{isProductUnavailable && (
|
{isProductUnavailable && (
|
||||||
<div className="absolute inset-0 z-10 flex items-center justify-center bg-black/60">
|
<div className="absolute inset-0 z-10 flex items-center justify-center bg-black/60">
|
||||||
<div className="flex flex-col items-center gap-2 text-center px-4">
|
<div className="flex flex-col items-center gap-3 text-center px-4">
|
||||||
<AlertTriangle className="h-8 w-8 text-orange-500" />
|
<AlertTriangle className="h-8 w-8 text-orange-500" />
|
||||||
<span className="text-sm font-semibold text-white">
|
<span className="text-sm font-semibold text-white">
|
||||||
Produit retiré du site
|
Produit retiré du site
|
||||||
</span>
|
</span>
|
||||||
|
{onMarkAvailable && (
|
||||||
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
size="sm"
|
||||||
|
className="mt-1"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
onMarkAvailable(item.id);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Marquer comme disponible
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -102,6 +102,17 @@ export default function Dashboard() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleMarkAvailable = async (itemId) => {
|
||||||
|
try {
|
||||||
|
await axios.patch(`${API_URL}/items/${itemId}/availability?available=true`);
|
||||||
|
toast.success('Produit marqué comme disponible');
|
||||||
|
refreshItems();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error marking item as available:', error);
|
||||||
|
toast.error('Erreur lors de la mise à jour');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const filteredItems = items.filter(item => {
|
const filteredItems = items.filter(item => {
|
||||||
const term = searchTerm.toLowerCase();
|
const term = searchTerm.toLowerCase();
|
||||||
const matchesSearch = (
|
const matchesSearch = (
|
||||||
@@ -170,6 +181,7 @@ export default function Dashboard() {
|
|||||||
onZoom={setZoomedImage}
|
onZoom={setZoomedImage}
|
||||||
onCategoryUpdate={handleCategoryUpdate}
|
onCategoryUpdate={handleCategoryUpdate}
|
||||||
onViewHistory={setHistoryItem}
|
onViewHistory={setHistoryItem}
|
||||||
|
onMarkAvailable={handleMarkAvailable}
|
||||||
categories={categories}
|
categories={categories}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -1,43 +1,24 @@
|
|||||||
# Task Board: Catalog Image Fix
|
# Correction Statut Disponibilité Produit B&M
|
||||||
|
|
||||||
## 🚀 Current Focus
|
## Contexte
|
||||||
|
|
||||||
- [ ] Investigate Comparator Price Extraction (User reported false prices)
|
Le produit "Lot de 24 bougies blanches" sur bmstores.fr est affiché comme "Produit retiré du site" dans Priceflow alors qu'il est bien disponible sur le site (0,88€).
|
||||||
- [x] Fix Catalog Images (Generic/Missing icons)
|
|
||||||
- [/] **Amazon Login Wall Fix** (Redirected by User)
|
|
||||||
|
|
||||||
## 📋 Master Plan
|
## Master Plan
|
||||||
|
|
||||||
- [x] Analyze `verify_extraction_logic.py`, `ai_service.py`, `ai_schema.py`, `tracking_scraper_service.py`.
|
- [x] Correction automatique du statut lors d'un refresh réussi
|
||||||
- [x] Proposal Phase: Vision Priority accepted.
|
- [x] Modifier `_update_db_result` dans `scheduler_service.py` pour remettre `is_available = True` quand un prix est détecté
|
||||||
- [x] Implementation Phase:
|
- [x] Endpoint API pour correction manuelle
|
||||||
- [x] Update `ai_schema.py`.
|
- [x] Ajouter un endpoint `PATCH /{item_id}/availability` dans `items.py` router
|
||||||
- [x] Fix `scheduler_service.py`.
|
- [x] Permettre de modifier `is_available` via l'API
|
||||||
- [x] Verification Phase: Verified with `verify_vision_priority.py`.
|
- [x] Interface utilisateur
|
||||||
- [x] **Catalog Retrieval Fix**:
|
- [x] Ajouter `onMarkAvailable` prop dans `ItemCard.jsx`
|
||||||
- [x] Reproduce failure (Confirmed Browserless issue).
|
- [x] Ajouter le handler `handleMarkAvailable` dans `Dashboard.jsx`
|
||||||
- [x] Fix `cataloguemate_scraper.py` with HTTP fallback.
|
- [x] Afficher un bouton "Marquer comme disponible" dans l'overlay des produits indisponibles
|
||||||
- [x] Cleanup debug files.
|
|
||||||
- [x] **Catalog Image Fix**:
|
|
||||||
- [x] Analyze page HTML for correct image selectors (Found Thumbor URL).
|
|
||||||
- [x] **Check PDF availability** (Browser Task).
|
|
||||||
- [x] **Refine Scraper Logic**:
|
|
||||||
- [x] Update `cataloguemate_scraper.py` to grab `src` and prioritize Thumbor.
|
|
||||||
- [x] Update `routers/catalogues.py` to clean up bad images.
|
|
||||||
- [x] **Cleanup Bad Data**:
|
|
||||||
- [x] Run cleanup endpoint.
|
|
||||||
- [x] Verify fix with new scrape.
|
|
||||||
- [/] **Comparator Price Fix**:
|
|
||||||
- [ ] Reproduce "False Price" issue with script.
|
|
||||||
- [ ] Audit `improved_search_service.py` extraction logic (Lowest Price vs AI).
|
|
||||||
- [ ] Implement robust price validation/filtering.
|
|
||||||
- [ ] Verify fix.
|
|
||||||
|
|
||||||
## 📝 Progress Log
|
## Progress Log
|
||||||
|
|
||||||
- **2025-12-22**: Vision Priority implemented and verified.
|
- Diagnostic effectué : produit B&M bien disponible (0,88€) mais marqué indisponible dans la DB
|
||||||
- **2025-12-22**: Fixed Catalog Retrieval using HTTP fallback.
|
- Modifié `scheduler_service.py` : reset auto de `is_available` quand prix détecté
|
||||||
- **2025-12-22**: Investigating generic icon issue. Found images are served via Thumbor.
|
- Ajouté endpoint API `PATCH /api/items/{id}/availability`
|
||||||
- **2025-12-22**: **FIXED**: Scraper now targets Thumbor images. Wiped bad catalogs.
|
- Ajouté bouton dans l'overlay frontend pour correction manuelle
|
||||||
- **2025-12-24**: User prioritized Amazon Login Wall fix.
|
|
||||||
- **2025-12-24**: Reproduction script `test_amazon_scraper.py` patched to use local browser. Verifying issue.
|
|
||||||
Reference in new issue
Block a user