Offer Feed Criteria¶
This page describes the requirements and validation rules that iUsed applies to Refurbisher Offer Feeds during import. It is intended for the iUsed team and Flooris developers involved in onboarding or troubleshooting Refurbisher integrations.
Partner-facing documentation
The full technical specification for Refurbisher partners is published at the iUsed Partner Documentation portal:
How the import works¶
The IRP polls each active Refurbisher's offer feed approximately every 5 minutes via ImportRefurbisherOffersJob. The
job:
- Fetches all offers from the Refurbisher's endpoint (HTTP or sFTP)
- Maps the raw feed fields to IRP fields using the Refurbisher's connector config
- Upserts each offer using
(refurbisher_id, sku, ean)as the identity key - Validates each offer via
RefurbisherOfferValidationService - Sets
stock_available = 0on any offer not present in the current feed
Identity key¶
Each RefurbisherOffer record is uniquely identified by the combination:
refurbisher_id + sku + ean
EAN is part of the identity
If a Refurbisher submits a different EAN for an existing SKU, the IRP creates a new separate offer record — it does
not update the existing one. The old offer will have its stock set to 0. The new offer is immediately flagged as *
rejected* and requires manual review.
This is intentional: an EAN change may indicate a product substitution, re-packaging, or supplier error — all of which require human judgement before the product goes live.
Field requirements¶
| Field | DB column | Type | Max length | Required | Notes |
|---|---|---|---|---|---|
sku |
sku |
varchar(255) |
255 | Yes | Unique per Refurbisher |
ean |
ean |
varchar(25) |
25 | No | Part of identity key |
name |
name |
string |
— | Yes | Product name |
stock_available |
stock_available |
integer |
— | Yes | 0 = out of stock |
price_purchase_amount |
price_purchase_amount |
integer (cents) |
— | Yes | Stored after VAT/margin deduction |
price_consumer_amount |
price_consumer_amount |
integer (cents) |
— | Yes | Consumer-facing price |
tax_percentage |
tax_percentage |
decimal |
— | No | Fallback from connector config |
currency_iso |
currency_iso |
varchar(3) |
— | No | Defaults to EUR |
Validation rules¶
The RefurbisherOfferValidationService runs after every create or update. Validation is applied to the raw feed data
** (before database write) for length checks, and to the persisted model** for duplicate checks.
| Rule | Checked against | Trigger |
|---|---|---|
| SKU exceeds 255 characters | Raw feed value | Rejected |
| EAN exceeds 25 characters | Raw feed value | Rejected |
| Duplicate SKU with different EAN | Persisted DB records | Rejected |
Why raw feed data for length checks?
MySQL silently truncates strings that exceed the column length. Checking strlen() on the already-saved model would
always pass (the value is already truncated). Validation therefore runs against the unmapped feed value before any DB
write.
Rejected offers:
- Have
validation_status = 'rejected' - Have
validation_message(JSON array) with one or more human-readable reasons - Are visible on the Refurbisher Offer index page and filterable by validation status
- Are not pushed to Shopware until the issue is resolved or the offer is manually approved
Viewing validation results¶
In the IRP:
- Navigate to Refurbisher Offers — filter by Validation status: Rejected
- Open any rejected offer to see the specific rejection reason(s)
In the reporting cache:
Each import run produces a report at:
/reporting/refurbisher_offers/{refurbisher_id}/{import_uuid}
The report includes a rejected_offers count and detailed event log.
Common issues¶
Duplicate SKU with changed EAN¶
Symptom: An offer appears as rejected with the message "Duplicate SKU: another offer exists for this SKU with a
different EAN code."
Cause: The Refurbisher has changed the EAN associated with a SKU that already exists in the IRP.
Resolution:
- Confirm with the Refurbisher whether the EAN change is intentional.
- If intentional: soft-delete the old offer (if not linked to a ProductVariant) and approve the new offer.
- If the old offer is linked to a ProductVariant: re-link the ProductVariant to the new offer, then soft-delete the old offer.
- If the EAN change is an error: ask the Refurbisher to correct the feed and revert to the original EAN.
SKU or EAN too long¶
Symptom: An offer is rejected with "SKU exceeds maximum length" or "EAN exceeds maximum length".
Cause: The Refurbisher's feed contains a value that is longer than the database column allows.
Resolution: Contact the Refurbisher and request a shorter identifier. The IRP cannot truncate values automatically because that would corrupt the identity key.
Offers not disappearing after stock runs out¶
Cause: The Refurbisher is submitting a partial feed (only changed offers) instead of the full catalogue.
Resolution: The IRP requires a complete feed on every poll. Ask the Refurbisher to always include all products,
with stock_available: 0 for out-of-stock items.
Database cleanup after EAN-truncation bug¶
Prior to the varchar(25) column expansion (migration 2026_07_04_192053), the ean column was varchar(15). EAN
codes longer than 15 characters were silently truncated, causing duplicate offer records to be created on every import
run.
SQL instructions for identifying and cleaning up these duplicates are in:
docs/refurbisher-offer-cleanup.md in the IRP repository.