Files
nick-doc/02 - Data Models/SellerOffer.md

4.6 KiB

title, tags, aliases
title tags aliases
SellerOffer
data-model
mongoose
Seller Offer
Bid
ISellerOffer

SellerOffer

Last updated: 2026-05-31 — added TRY pricing support for oracle/depeg quoting.

A seller's bid against a PurchaseRequest. Stores the proposed price, the delivery time commitment, optional notes/attachments, and a small status machine (pending / accepted / rejected / withdrawn). The parent PurchaseRequest keeps the array of offer ids in offers[] and the chosen one in selectedOfferId.

[!note] Source backend/src/models/SellerOffer.ts:24 — schema definition backend/src/models/SellerOffer.ts:100 — model export

Schema

Field Type Required Default Validation Index Description
sellerId ObjectId → User yes yes Seller submitting the bid.
purchaseRequestId ObjectId → PurchaseRequest yes yes Parent request.
title String yes trim, maxlength 200 Offer headline.
description String yes trim, maxlength 1000 Pitch and details.
price.amount Number yes min 0 Quoted amount.
price.currency String yes USDT enum: USD / EUR / IRR / TRY / USDT / USDC Quote currency. TRY is supported by the oracle/depeg path through the off-chain FX provider.
deliveryTime.amount Number yes min 1 Numeric ETA.
deliveryTime.unit String yes enum: hours / days / weeks ETA unit.
status String no pending enum: pending / accepted / rejected / withdrawn / active yes Offer status.
attachments[] String[] no URLs of supporting files.
notes String no trim Internal/private notes.
validUntil Date no Expiration.
requireAmlCheck Boolean no If true, AML screening must pass before the offer is presented to the buyer.
amlBlockOnFailure Boolean no If true and AML screening fails, the offer is blocked. Otherwise it is flagged for manual review.
createdAt Date auto yes (desc) Mongoose timestamp.
updatedAt Date auto Mongoose timestamp.

Status enum note: active is accepted by the current backend schema for marketplace/listing flows, in addition to the negotiation statuses pending | accepted | rejected | withdrawn.

Virtuals

None defined.

Indexes

Defined at backend/src/models/SellerOffer.ts:95-98:

  • { sellerId: 1 }
  • { purchaseRequestId: 1 }
  • { status: 1 }
  • { createdAt: -1 }

Pre/Post Hooks

None declared.

Instance Methods

None defined.

Static Methods

None defined.

Service notes

createOffer — eligible parent request statuses

createOffer in SellerOfferService permits offers against a PurchaseRequest whose status is pending, received_offers, or active. Attempts against any other status are rejected.

withdrawOffer() — frontend action available

SellerOfferService.withdrawOffer() is not a dedicated HTTP route. The correct API path is PUT /api/marketplace/offers/:id/status with { status: 'withdrawn' }.

The frontend exposes this via the withdrawOffer(offerId) action in src/actions/marketplace.ts (added commit 240a668). It is called from:

  • step-2-waiting-for-payment.tsx (edit/cancel controls while requestDetails.status === 'received_offers')
  • frontend/src/app/dashboard/seller/marketplace/offers/page.tsx (Offer Management page, bulk view)

Relationships

State Transitions

stateDiagram-v2
    [*] --> pending
    pending --> accepted : buyer accepts
    pending --> rejected : buyer rejects
    pending --> withdrawn : seller cancels
    accepted --> [*]
    rejected --> [*]
    withdrawn --> [*]

Common Queries

// Offers for a request
SellerOffer.find({ purchaseRequestId }).sort({ createdAt: -1 });

// Seller's active offers
SellerOffer.find({ sellerId, status: 'pending' });

// Reject siblings on accept
SellerOffer.updateMany(
  { purchaseRequestId, _id: { $ne: acceptedId }, status: 'pending' },
  { status: 'rejected' }
);

// Cleanup expired offers
SellerOffer.find({ validUntil: { $lt: new Date() }, status: 'pending' });

Related: PurchaseRequest, Payment, User.