feat: robust ML publish with pre-flight, preview, validation, async

- Add /inventory-check endpoint for local pre-flight validation
- Add /listings/validate endpoint using ML /items/validate API
- Add /categories/<id>/attributes endpoint for required attrs
- Add /listings/async + polling for background publishing via Celery
- Editable preview: title (0/60 counter), price, stock per item
- Pre-flight checks: image, stock, price, duplicate detection
- Image upload directly from publish modal (uses existing /items/<id>/image)
- Dynamic required attributes form based on selected ML category
- Frontend: validate button, async polling with progress, detailed error display
- Backend: build_item_payload supports custom_title, extra_attributes
This commit is contained in:
2026-05-26 04:37:05 +00:00
parent 4866823ba9
commit b314a781a1
8 changed files with 706 additions and 108 deletions

View File

@@ -1333,6 +1333,73 @@
/* History table inside modal */
.inv-modal .data-table { width: 100%; }
/* ─── MercadoLibre Publish Modal Enhancements ────────────────────────── */
.meli-preview-card {
display: grid;
grid-template-columns: 56px 1fr auto auto auto;
gap: var(--space-3);
align-items: center;
padding: var(--space-3);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
margin-bottom: var(--space-2);
background: var(--color-surface-1);
}
.meli-preview-card img {
width: 56px; height: 56px; object-fit: cover; border-radius: var(--radius-sm);
background: var(--color-surface-2);
}
.meli-preview-card .meli-title-input {
width: 100%;
background: var(--color-surface-2);
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
color: var(--color-text-primary);
padding: 4px 8px;
font-size: var(--text-caption);
}
.meli-preview-card .meli-num-input {
width: 80px;
background: var(--color-surface-2);
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
color: var(--color-text-primary);
padding: 4px 8px;
font-size: var(--text-caption);
text-align: right;
}
.meli-check { font-size: var(--text-caption); display: flex; align-items: center; gap: 4px; }
.meli-check.ok { color: var(--color-success); }
.meli-check.fail { color: var(--color-error); }
.meli-checks-row {
display: flex; gap: var(--space-3); flex-wrap: wrap; margin-top: var(--space-1);
}
.meli-attrs-section {
margin-top: var(--space-3);
padding: var(--space-3);
border: 1px dashed var(--color-border);
border-radius: var(--radius-md);
background: var(--color-surface-1);
}
.meli-attrs-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: var(--space-3);
margin-top: var(--space-2);
}
.meli-img-upload {
border: 2px dashed var(--color-border);
border-radius: var(--radius-md);
padding: var(--space-3);
text-align: center;
color: var(--color-text-muted);
font-size: var(--text-caption);
cursor: pointer;
transition: border-color var(--transition-fast);
}
.meli-img-upload:hover { border-color: var(--color-primary); }
.meli-img-upload input { display: none; }
/* ─── MercadoLibre Category Autocomplete ─────────────────────────────── */
.meli-cat-dropdown {
position: absolute;