BERTUS

Calcutta Records Vendor Tool
{{ bertusStatus.configured ? '● API Connected' : '○ API Not Configured' }} Last import: {{ formatDate(stats.lastImport.import_date) }}
{{ stats.total }}
Total
{{ stats.inStock }}
In Stock
{{ stats.outOfStock }}
Out of Stock
{{ stats.synced }}
Synced
{{ stats.pendingSync }}
Pending Sync
{{ stats.stockChanged }}
Stock Changed

Step 1: Select Export File

Bertus API not configured — check backend/.env
{{ exportsError }}
Loading available exports from Bertus...
{{ exp.FileName }}
{{ exp.SizeInBytes ? (exp.SizeInBytes / 1024 / 1024).toFixed(1) + ' MB' : 'size unknown' }}
No exports found. Create one on my.bertus.com first.
Selected: {{ selectedExport.FileName }}

Step 2: Check Out-of-Stock

Run after all partial imports are done

Finds every in-stock product not seen in any import today, then verifies each one via the Bertus API before marking it out-of-stock. Run this after all your partial imports are done.

{{ oosCheckCandidates }} products not seen in any import today
This can take a while for large catalogs — one Bertus API call per candidate.
{{ oosCheckResult.checked }}
Candidates Checked
{{ oosCheckResult.outOfStock }}
Marked Out-of-Stock
{{ oosCheckResult.keptInStock }}
Kept In-Stock (API)
{{ item.art_id }} — {{ item.artist }} - {{ item.title }} {{ item.media }}
{{ oosCheckError }}

Verify Stock via API Deprecated

This feature has been replaced by the Stock tab which uses the bulk API and updates WooCommerce automatically.

Import Results

{{ importResult.totalBeforeFilter || importResult.total }}
CSV Total
{{ importResult.skippedNotInStock || 0 }}
Skipped (No Stock)
{{ importResult.new }}
New
{{ importResult.updated }}
Updated
{{ importResult.backInStock }}
Back In Stock
{{ item.art_id }} — {{ item.artist }} - {{ item.title }} {{ item.media }}
{{ item.art_id }} — {{ item.artist }} - {{ item.title }} {{ item.media }}

{{ importError }}

{{ pagination.total }} results
Art.Id Artist Title Media € Price ₹ WC Price Genre Stock Synced Enriched WC Actions
♫
{{ p.art_id }} {{ p.artist }} {{ p.title }} {{ p.media }} €{{ p.customer_price?.toFixed(2) }} ₹{{ calcWcPrice(p.customer_price, p.media === 'CD' || p.media === 'CD-S') }} {{ genreLabel(p.genre) }} {{ p.stock_status==='instock' ? 'In Stock' : 'OOS' }} {{ p.synced_to_woocommerce ? 'Yes' : 'No' }} Yes — ↗ —
No products. Import from Bertus API first.
Page {{ filters.page }} / {{ pagination.pages }}
{{ enrichStats.enriched || 0 }}
Enriched
{{ enrichStats.pending || 0 }}
Pending
{{ enrichStats.withImages || 0 }}
With Covers
{{ enrichStats.noMatch || 0 }}
Not Found
{{ enrichStats.imageMissing || 0 }}
No Images

Bertus API Enrichment

Fetches cover images, description, and genre from the Bertus article API.
Rate: ~50 req/min. {{ enrichStats.pending || 0 }} pending. Est: {{ enrichEstimate }}.

{{ enrichStats.bertusApiConfigured ? '✓' : '✗' }} Bertus API {{ enrichStats.aiDescConfigured ? '✓' : '⚠' }} AI Desc
{{ enrichProgress.message }} {{ enrichProgress.completed || 0 }}/{{ enrichProgress.total || 0 }}
{{ enrichProgress.success || 0 }} enriched
{{ enrichProgress.withCovers || 0 }} covers
{{ enrichProgress.noMatch || 0 }} not found

Log

{{ e.message }}

WooCommerce Sync

{{ stats.pendingSync }} new products pending · {{ stats.stockChanged }} stock changes · {{ stats.restockCandidates || '—' }} restock candidates

{{ syncProgress.message }} {{ syncProgress.completed }}/{{ syncProgress.total }}
{{ (syncMode === 'force-update' || syncMode === 'force-update-v2') ? (syncProgress.updated || 0) : syncProgress.created }} {{ (syncMode === 'force-update' || syncMode === 'force-update-v2') ? 'updated' : 'created' }}
{{ syncProgress.stockUpdated || 0 }} stock
{{ syncProgress.restocked || 0 }} restocked
{{ syncProgress.errors || 0 }} errors

Sync Log

{{ e.message }}

Bulk Stock Check

Checks all synced WooCommerce products against the Bertus articlesStockAndPrice bulk API. Out-of-stock items are set to quantity 0 on the store; items back in stock are restocked with updated prices.

Bertus API not configured WooCommerce not configured
{{ stockCheckProgress.message }} {{ stockCheckProgress.completed || 0 }}/{{ stockCheckProgress.total || 0 }}
{{ stockCheckProgress.total || 0 }}
Total
{{ stockCheckProgress.checked || 0 }}
Checked
{{ stockCheckProgress.confirmedInStock || 0 }}
Confirmed
{{ stockCheckProgress.markedOutOfStock || 0 }}
Marked Out
{{ stockCheckProgress.restocked || 0 }}
Restocked
{{ stockCheckProgress.wcUpdated || 0 }}
WC Updated
{{ stockCheckProgress.errors || 0 }}
Errors

Changes ({{ stockCheckProgress.changes.length }})

Article Artist — Title Action Reason
{{ c.art_id }} {{ c.artist }} — {{ c.title }} ↑ Restocked ↓ Out of Stock ⚠ Error {{ c.reason }} {{ c.price }}
No changes matching filter.
📦

Run a stock check to compare your synced products against Bertus live stock.

Uses bulk articlesStockAndPrice API in batches of 20. Items with Stock > 0 = in stock, Stock = 0 = out of stock.

{{ priceCheckProgress.message }} {{ priceCheckProgress.checked || 0 }}/{{ priceCheckProgress.total || 0 }}
{{ priceCheckProgress.total || 0 }}
Total
{{ priceCheckProgress.checked || 0 }}
Checked
{{ priceCheckProgress.matched || 0 }}
Matched
{{ priceCheckProgress.updated || 0 }}
Updated in WC
{{ priceCheckProgress.errors || 0 }}
Errors

Price Changes ({{ filteredPriceChanges.length }})

Article Artist — Title Old Price New Price Bertus Source
{{ c.art_id }} {{ c.artist }} — {{ c.title }} {{ c.old_price || '—' }} {{ c.new_price || '—' }} ✓ Updated ⚠ {{ c.reason }}
No changes matching filter.
💰

Run a price check to revalidate all in-stock product prices against Bertus live data and your current config.

Fetches current Bertus NettPrice, applies your EUR→INR rate and markup, and updates WooCommerce where prices differ.

Configuration

1 EUR = {{ config.eur_to_inr }} INR

Up to (EUR)
Multiplier
catch-all (€{{ priceTiers[i-1] ? priceTiers[i-1].max : '0' }}+)

EUR cost < max → that multiplier applies · last row is catch-all · price rounded to ₹X99

Preview at EUR→INR {{ config.eur_to_inr }}: €{{ pts.eur }}→₹{{ pts.inr }}

Media
Categories (Ctrl/Cmd+click for multiple)
🎵 Vinyl
LP / 12"
{{ vinylCategoryIds.length }} selected
💿 CD
CD / CD-S
{{ cdCategoryIds.length }} selected

Refresh categories first · Ctrl/Cmd+click to select multiple · Save Config to apply.

✓ Saved
{{ bertusStatus.configured ? '✓ Bertus API' : '✗ Bertus API not configured' }} ({{ bertusStatus.accountId }})
{{ wcOk ? '✓ WooCommerce' : '✗ WC not configured' }} {{ wcUrl }}

Price Preview

€{{ s }} → ₹{{ previewPrice(s) }}

Danger Zone

Clear all products & logs. Config preserved.

Date Source Total New Updated OOS Back
{{ fmtDate(l.import_date) }} {{ l.filename }} {{ l.total_records }} +{{ l.new_records }} {{ l.updated_records }} {{ l.out_of_stock_records }} {{ l.back_in_stock_records }}
No imports yet.
This is a preview. Loading the Revolver Club catalog does not change calcuttarecords.com. Their feed prices are before GST. The price we tally against is that amount plus {{ trcGstLabel }} GST. The suggested sale is ₹100 below that site price, and only when the lower price is still at or above our no-loss floor. Otherwise the row stays unchanged.

The Revolver Club

{{ competitorStatus.offers.toLocaleString('en-IN') }} in-stock EANs stored · updated {{ fmtDate(competitorStatus.fetchedAt) }}

No local catalog yet.

Downloading page {{ competitorStatus.fetch.page }} · {{ competitorStatus.fetch.fetched }} products so far. The previous catalog stays in place until this finishes.

{{ competitorError }}

{{ competitorSummary.matched }}
Matched on our site
{{ competitorSummary.safe }}
Would go on sale
₹{{ competitorSummary.totalSavings.toLocaleString('en-IN') }}
Combined reduction
{{ competitorSummary.blocked }}
Blocked by floor
Floor = Bertus € × {{ competitorFormula.eurToInr }} × (1 + {{ competitorFormula.customs }}) × (1 + {{ competitorFormula.gst }}) + ₹{{ competitorFormula.shipping }} shipping + ₹{{ competitorFormula.ads }} ads + ₹{{ competitorFormula.profit }} profit. TRC benchmark = feed price × {{ (1 + competitorFormula.trcGst).toFixed(2) }}.
Title CRC price List price Floor TRC ex-GST TRC incl. GST Suggested sale Effect if applied
♫
{{ row.artist }}
{{ row.title }}
{{ row.ean }}
₹{{ Number(row.paysNow).toLocaleString('en-IN') }} ₹{{ Number(row.listPrice).toLocaleString('en-IN') }} ₹{{ Number(row.floor).toLocaleString('en-IN') }} ₹{{ Number(row.trcRaw).toLocaleString('en-IN', { maximumFractionDigits: 2 }) }} ₹{{ Number(row.trcFinal).toLocaleString('en-IN', { maximumFractionDigits: 2 }) }} {{ row.suggestedSale ? '₹' + Number(row.suggestedSale).toLocaleString('en-IN') : '—' }} {{ row.effect }}
No rows for this filter. Load the catalog if you have not yet.
Page {{ competitorPage }} of {{ competitorPages }}

{{ competitorApplyMessage }}