Get product Offers
The getProductPaginatedOffers
function retrieves a paginated list of offers (pricing and availability information) for a specific product. This function is essential for displaying pricing options from multiple suppliers, enabling users to compare prices, availability, and terms before making purchasing decisions.
Product offers contain comprehensive pricing information including unit prices, bulk pricing tiers, supplier details, availability status, and delivery terms. The function supports pagination to efficiently handle products with numerous offer options from different suppliers, ensuring optimal performance even for products with extensive pricing catalogs.
This function is particularly crucial for B2B e-commerce scenarios where price comparison, supplier selection, and bulk purchasing decisions are key factors in the procurement process.
Process Flow
sequenceDiagram participant User as User participant Component as Vue Component participant useProduct as useProduct participant SDK as Djust SDK participant API as API Server participant Auth as Auth Service User->>Component: Request Product Offers Component->>useProduct: getProductPaginatedOffers(params) useProduct->>useProduct: Validate Parameters useProduct->>SDK: useFetch('/api/product/{id}/offers') SDK->>Auth: Verify Authentication Token Auth-->>SDK: Token Valid SDK->>API: GET /api/product/{productId}/offers alt Success Response API-->>SDK: 200 - Offers List SDK-->>useProduct: GetProductOffersResponse useProduct->>useProduct: Process Pagination useProduct-->>Component: Paginated Offers Component-->>User: Display Pricing Options else No Offers Found API-->>SDK: 404 - No Offers SDK-->>useProduct: Empty Response useProduct->>useProduct: Log No Offers useProduct-->>Component: Empty Offers List Component-->>User: "No pricing available" else Authentication Error Auth-->>SDK: 401 - Unauthorized SDK-->>useProduct: Auth Error useProduct-->>Component: Authentication Error Component-->>User: Redirect to Login else Permission Error API-->>SDK: 403 - Pricing Access Denied SDK-->>useProduct: Permission Error useProduct-->>Component: Access Denied Component-->>User: "Pricing not accessible" else Server Error API-->>SDK: 500 - Internal Error SDK-->>useProduct: Server Error useProduct->>useProduct: Log Server Error useProduct-->>Component: Error Response Component-->>User: "Unable to load pricing" end
Call Parameters
The function accepts a GetProductOffersRequest
object with the following structure:
GetProductOffersRequest Interface (from SDK)
interface GetProductOffersRequest {
productIdentifier: string;
productIdType?: ProductIdType;
currency?: string;
locale?: string;
withoutPrices?: boolean;
pageable?: Pageable;
}
type ProductIdType = "EXTERNAL_ID" | "SKU" | "ID";
interface Pageable {
page?: number;
size?: number;
sort?: string[];
}
Parameter Details
Parameter | Type | Required | Default | Example | Business Impact |
---|---|---|---|---|---|
productIdentifier | string | ✅ Yes | - | "LAPTOP-001" | Critical: Product identifier for offer lookup |
productIdType | ProductIdType | ❌ Optional | "EXTERNAL_ID" | "SKU" , "ID" | Important: Determines lookup strategy |
currency | string | ❌ Optional | Runtime config | "EUR" , "USD" | Pricing: Currency for price display |
locale | string | ❌ Optional | Runtime config | "en-GB" , "fr-FR" | Localization: Affects supplier names and terms |
withoutPrices | boolean | ❌ Optional | false | true , false | Access Control: Hide pricing for restricted users |
pageable.page | number | ❌ Optional | 0 | 0 , 1 , 2 | Performance: Controls result pagination |
pageable.size | number | ❌ Optional | Runtime config | 10 , 20 , 50 | Performance: Limits offers per request |
Complete Example Call
const offersParams: GetProductOffersRequest = {
productIdentifier: "LAPTOP-DELL-001",
productIdType: "SKU",
currency: "EUR",
locale: "en-GB",
withoutPrices: false,
pageable: {
page: 0,
size: 20,
},
};
const response = await getProductPaginatedOffers(offersParams);
Returns from Composable
The function returns a GetProductOffersResponse
object with the following structure:
GetProductOffersResponse Interface (from SDK)
interface GetProductOffersResponse {
success: boolean;
offers: ProductOfferPage;
}
interface ProductOfferPage {
content: ProductOffer[];
pageable: Pageable;
totalElements: number;
totalPages: number;
size: number;
number: number;
first: boolean;
last: boolean;
empty?: boolean;
}
interface ProductOffer {
id: string;
productSku: string;
supplierId: string;
supplierName: string;
price: ProductPrice;
availability: ProductAvailability;
terms: OfferTerms;
validFrom: string;
validTo?: string;
minimumQuantity: number;
packageSize: number;
leadTime: number;
deliveryOptions: DeliveryOption[];
}
interface ProductPrice {
unitPrice: number;
currency: string;
taxIncluded: boolean;
discounts: PriceDiscount[];
bulkPricing: BulkPrice[];
}
interface ProductAvailability {
inStock: boolean;
quantity?: number;
stockLocation: string;
availableFrom?: string;
estimatedDelivery?: string;
}
Realistic Example JSON Response
{
"success": true,
"offers": {
"content": [
{
"id": "offer-001",
"productSku": "LAPTOP-DELL-001",
"supplierId": "supplier-tech-pro",
"supplierName": "TechPro Distribution",
"price": {
"unitPrice": 899.99,
"currency": "EUR",
"taxIncluded": false,
"discounts": [
{
"type": "VOLUME_DISCOUNT",
"minQuantity": 10,
"percentage": 5.0,
"description": "5% discount for orders of 10+ units"
}
],
"bulkPricing": [
{
"minQuantity": 1,
"maxQuantity": 9,
"unitPrice": 899.99
},
{
"minQuantity": 10,
"maxQuantity": 49,
"unitPrice": 854.99
},
{
"minQuantity": 50,
"maxQuantity": null,
"unitPrice": 809.99
}
]
},
"availability": {
"inStock": true,
"quantity": 150,
"stockLocation": "Warehouse Paris",
"estimatedDelivery": "2024-01-25T10:00:00Z"
},
"terms": {
"paymentTerms": "NET30",
"warranty": "24 months",
"returnPolicy": "30 days",
"shippingTerms": "FOB destination"
},
"validFrom": "2024-01-01T00:00:00Z",
"validTo": "2024-03-31T23:59:59Z",
"minimumQuantity": 1,
"packageSize": 1,
"leadTime": 2,
"deliveryOptions": [
{
"method": "EXPRESS",
"cost": 15.99,
"estimatedDays": 1
},
{
"method": "STANDARD",
"cost": 5.99,
"estimatedDays": 3
}
]
},
{
"id": "offer-002",
"productSku": "LAPTOP-DELL-001",
"supplierId": "supplier-global-tech",
"supplierName": "Global Tech Solutions",
"price": {
"unitPrice": 925.0,
"currency": "EUR",
"taxIncluded": false,
"discounts": [
{
"type": "EARLY_PAYMENT",
"percentage": 2.0,
"description": "2% discount for payment within 10 days"
}
],
"bulkPricing": [
{
"minQuantity": 1,
"maxQuantity": 19,
"unitPrice": 925.0
},
{
"minQuantity": 20,
"maxQuantity": null,
"unitPrice": 888.0
}
]
},
"availability": {
"inStock": true,
"quantity": 75,
"stockLocation": "Warehouse Amsterdam",
"estimatedDelivery": "2024-01-26T14:00:00Z"
},
"terms": {
"paymentTerms": "NET15",
"warranty": "36 months",
"returnPolicy": "14 days",
"shippingTerms": "CIF"
},
"validFrom": "2024-01-01T00:00:00Z",
"minimumQuantity": 1,
"packageSize": 1,
"leadTime": 3,
"deliveryOptions": [
{
"method": "PREMIUM",
"cost": 25.99,
"estimatedDays": 1
},
{
"method": "STANDARD",
"cost": 9.99,
"estimatedDays": 4
}
]
}
],
"pageable": {
"page": 0,
"size": 20
},
"totalElements": 8,
"totalPages": 1,
"size": 20,
"number": 0,
"first": true,
"last": true,
"empty": false
}
}
Error Management
HTTP Error Codes and Handling
Error Code | Cause | System Action | User Message | Return Format |
---|---|---|---|---|
400 | Invalid product identifier or parameters | Log validation error, return null | "Invalid product information" | null |
401 | Authentication token missing/invalid | Trigger re-authentication flow | "Please log in to view pricing" | Authentication redirect |
403 | User lacks pricing permissions | Log access attempt, return null | "Pricing information not accessible" | null |
404 | No offers found for product | Log not found, return empty list | "No pricing available for this product" | { success: true, offers: { content: [] } } |
412 | Precondition failed (business rules) | Log business rule violation | "Pricing access restricted for your account" | null |
500 | Internal server error | Log server error, return null | "Unable to load pricing information" | null |
Error Handling Example Code
// Global error handling in composable
const getProductPaginatedOffers = async ({
productIdentifier,
productIdType,
currency,
locale,
withoutPrices = false,
pageable,
}: GetProductOffersRequest): Promise<GetProductOffersResponse | null> => {
try {
// Parameter validation
if (!productIdentifier?.trim()) {
console.error("Product identifier is required for offers lookup");
return null;
}
const { data, error } = await useFetch<GetProductOffersResponse>(
`/api/product/${productIdentifier}/offers`,
{
method: "GET",
params: {
productIdType,
currency,
locale,
withoutPrices,
page: pageable?.page,
size: pageable?.size,
},
}
);
if (error.value) {
console.error("Failed to fetch product paginated offers:", {
productIdentifier,
currency,
error: error.value,
});
return null;
}
return data.value || null;
} catch (err) {
console.error(
"Unexpected error while fetching product paginated offers:",
err
);
return null;
}
};
// Component-level error handling
const handleOffersFetch = async (productId: string) => {
try {
const response = await getProductPaginatedOffers({
productIdentifier: productId,
currency: userCurrency.value,
pageable: { page: 0, size: 20 },
});
if (!response?.success || !response.offers) {
throw new Error("Offers not available");
}
// Process successful response
productOffers.value = response.offers.content;
totalOffers.value = response.offers.totalElements;
} catch (error) {
// User notification
useToast().add({
title: "Pricing Error",
description: "Unable to load pricing information",
color: "yellow",
});
// Fallback to empty state
productOffers.value = [];
totalOffers.value = 0;
}
};
Use Cases
1. Price Comparison Display
Show all available offers for a product to enable price and terms comparison across suppliers.
Scenario: User views product detail page and wants to compare pricing options from different suppliers.
Parameters: { productIdentifier: product.sku, currency: userCurrency, pageable: { page: 0, size: 10 } }
Expected Outcome: Comprehensive pricing table with supplier comparison, bulk pricing tiers, and delivery options.
2. Bulk Purchase Planning
Retrieve pricing information with bulk discounts for procurement planning and budget estimation.
Scenario: Purchasing manager evaluates bulk pricing options for large quantity orders.
Parameters: { productIdentifier: "ITEM-001", currency: "EUR", withoutPrices: false }
Expected Outcome: Detailed bulk pricing tiers, minimum quantities, and volume discounts displayed.
3. Supplier Selection
Compare supplier terms, delivery options, and availability for informed supplier selection.
Scenario: User needs to select optimal supplier based on delivery time, payment terms, and pricing.
Parameters: { productIdentifier: product.externalId, locale: userLocale.value }
Expected Outcome: Supplier comparison matrix with terms, availability, and delivery options.
4. Progressive Offers Loading
Load offers in batches for products with many suppliers to optimize page performance.
Scenario: Popular product with 50+ suppliers needs progressive loading for better user experience.
Parameters: { productIdentifier: "POPULAR-001", pageable: { page: currentPage, size: 15 } }
Expected Outcome: Paginated offers loading with smooth pagination controls and performance optimization.
Important Points
Performance Considerations
- Pagination Strategy: Use appropriate page sizes to balance information completeness and load times
- Currency Caching: Cache offers by currency to reduce redundant API calls for multi-currency scenarios
- Lazy Loading: Load offers progressively as users scroll through large supplier lists
- Price Formatting: Format prices client-side to reduce server processing overhead
Security Aspects
- Pricing Permissions: Strict validation of user permissions to view pricing information
- Supplier Filtering: Backend filters offers based on user's approved supplier list
- Data Privacy: Sensitive pricing information protected based on user role and agreements
- Rate Limiting: API calls limited to prevent pricing scraping or abuse
Flexibility Features
- Multi-Currency Support: Automatic currency conversion and display based on user preferences
- Configurable Pagination: Adaptive page sizing based on screen size and user preferences
- Price Without Display: Support for showing availability without pricing for restricted users
- Supplier Preferences: Integration with user's preferred supplier settings and contracts
Integration Capabilities
- Cart Integration: Seamless integration with cart system for adding selected offers
- Quote Integration: Direct connection to quote generation system for bulk requests
- Analytics Integration: Track pricing views and supplier selection patterns
- Procurement Workflows: Integration with approval workflows for enterprise purchasing
Technical Implementation
Composable Function with Complete JSDoc
/**
* Retrieves paginated offers for a specific product
*
* @param params - Product offers request parameters
* @param params.productIdentifier - Product identifier (SKU, ID, External ID)
* @param params.productIdType - Type of identifier used for lookup
* @param params.currency - Currency for pricing display
* @param params.locale - Locale for internationalized content
* @param params.withoutPrices - Whether to hide pricing information
* @param params.pageable - Pagination configuration
* @returns Promise resolving to paginated offers response or null
*
* @example
* ```typescript
* const { getProductPaginatedOffers } = useProduct();
*
* const response = await getProductPaginatedOffers({
* productIdentifier: "LAPTOP-001",
* currency: "EUR",
* pageable: { page: 0, size: 20 }
* });
*
* if (response?.success) {
* console.log('Offers found:', response.offers.totalElements);
* response.offers.content.forEach(offer => {
* console.log(`${offer.supplierName}: €${offer.price.unitPrice}`);
* });
* }
* ```
*
* @throws {Error} When network request fails or invalid parameters provided
* @since 1.0.0
*/
const getProductPaginatedOffers = async ({
productIdentifier,
productIdType,
currency,
locale,
withoutPrices = false,
pageable,
}: GetProductOffersRequest): Promise<GetProductOffersResponse | null> => {
try {
// Parameter validation
if (!productIdentifier?.trim()) {
throw new Error("Product identifier is required for offers lookup");
}
// Runtime configuration for defaults
const runtimeConfig = useRuntimeConfig();
const defaultCurrency = currency || runtimeConfig.public.currency;
const defaultLocale = locale || runtimeConfig.public.locale;
const defaultPageSize =
pageable?.size ||
Number(runtimeConfig.public.defaultPaginationSize) ||
20;
const { data, error } = await useFetch<GetProductOffersResponse>(
`/api/product/${productIdentifier}/offers`,
{
method: "GET",
params: {
productIdType: productIdType || "EXTERNAL_ID",
currency: defaultCurrency,
locale: defaultLocale,
withoutPrices,
page: pageable?.page || 0,
size: defaultPageSize,
},
// Enable caching with unique key
key: `product-offers-${productIdentifier}-${defaultCurrency}-${
pageable?.page || 0
}-${defaultPageSize}`,
// Default response structure
default: () => ({
success: false,
offers: null,
}),
}
);
if (error.value) {
console.error("Failed to fetch product paginated offers:", {
productIdentifier,
currency: defaultCurrency,
withoutPrices,
error: error.value,
});
return null;
}
return data.value || null;
} catch (err) {
console.error(
"Unexpected error while fetching product paginated offers:",
err
);
return null;
}
};
Execution Flow
Step-by-Step Process
-
Parameter Validation
// Validate required product identifier if (!productIdentifier?.trim()) { throw new Error("Product identifier is required for offers lookup"); }
-
Configuration Setup
// Apply runtime defaults for optional parameters const runtimeConfig = useRuntimeConfig(); const effectiveCurrency = currency || runtimeConfig.public.currency; const effectiveLocale = locale || runtimeConfig.public.locale;
-
Permission Check
// Verify user has pricing access permissions const userStore = useUserStore(); const canViewPricing = userStore.account?.permissions?.canViewPricing;
-
Request Construction
// Build API request with all parameters const requestUrl = `/api/product/${productIdentifier}/offers`; const requestParams = { productIdType: productIdType || "EXTERNAL_ID", currency: effectiveCurrency, locale: effectiveLocale, withoutPrices: withoutPrices || !canViewPricing, page: pageable?.page || 0, size: pageable?.size || defaultPageSize, };
-
Network Request Execution
// Execute paginated fetch with caching const { data, error } = await useFetch<GetProductOffersResponse>( requestUrl, { method: "GET", params: requestParams, } );
-
Response Processing
// Handle response and errors if (error.value) { logError("Failed to fetch offers", { productIdentifier, error: error.value, }); return null; }
-
Data Validation
// Validate response structure if (!data.value?.offers?.content) { console.warn("No offers content in response"); return { success: true, offers: { content: [], totalElements: 0 } }; }
-
Return Processed Response
// Return structured offers data return { success: true, offers: data.value.offers, };
Updated about 2 months ago