Posted on 08/01/2025 14:51:15
Hi Aki
You should always use a priceprovider for the price.
But you can do make an architecture where you fetch the information frrom the ERP from some kind of home grown service, and then let the price provider ask for the actual price information from that service and have other logic in other places also get its information inside that service.
So describing you problem to ChatGPT with some thoughts this is what comes out:
Below is a conceptual example in pseudo code of how you might architect your price provider, backed by an ERP-service call and a caching mechanism, so that you can:
- Ask for the main (final) price for Dynamicweb (returned via a PriceRaw instance).
- Cache all additional ERP pricing data (e.g. daily price, discount info, etc.) in memory or another store.
- Make that additional data available later to other functionality that needs it (e.g. to display daily price in the UI).
High-Level Overview
-
PriceProvider
- Implementation of Dynamicweb’s PriceProvider that must return a PriceRaw.
- It calls into a PriceService to retrieve the required information for a given product, user, and rental period.
- Once it gets the price data, it converts or selects the final price for Dynamicweb into a PriceRaw object.
-
PriceService
- Handles logic around either fetching data from cache or requesting it from the ERP.
- Responsible for storing the full ERP results in a cache (so that subsequent uses do not need to call the ERP again).
-
ERP Client
- Encapsulates calling the ERP’s API.
- Returns a complex object that includes daily prices, discount tiers, etc.
-
Caching
- Either in-memory (e.g.,
MemoryCache
) or a distributed cache.
- Keyed by a combination of product + user + rental period (the most important factors).
- Returns a data object that holds the entire set of ERP data (not just the final price).
-
Consumers of the Additional Data
- Code or UI parts that need the extra data (daily price, discount details) can pull from the same PriceService or from a specialized “RentalInfoService” that wraps the same cache.
- They do not call the ERP again; they just read from the already cached object.
Pseudo Code
1. The Data Structures
// 1) Represents the full data retrieved from the ERP
// (not just the final price used by Dynamicweb)
public class ErpPriceData
{
public decimal FinalPrice { get; set; } // e.g. total for rental period
public decimal DailyPrice { get; set; } // e.g. price per day
public decimal DiscountAmount { get; set; }
public DateTime RentalStart { get; set; }
public DateTime RentalEnd { get; set; }
// Add more fields as needed from the ERP response
}
// 2) A simple cache key for the combination of product, user, and rental period
public class PriceCacheKey
{
public string ProductId { get; }
public string UserId { get; }
public DateTime StartDate { get; }
public DateTime EndDate { get; }
public PriceCacheKey(string productId, string userId, DateTime startDate, DateTime endDate)
{
ProductId = productId;
UserId = userId;
StartDate = startDate;
EndDate = endDate;
}
// Implement Equals and GetHashCode properly so that the cache can match keys
public override bool Equals(object obj)
{
// Pseudo code for equality check
// ...
}
public override int GetHashCode()
{
// Pseudo code for generating a hash
// ...
}
}
2. The Caching Layer
// Could be a static class, a service, or use built-in .NET MemoryCache.
// Here is a simplified approach:
public static class PriceCache
{
private static readonly Dictionary<PriceCacheKey, ErpPriceData> _cache
= new Dictionary<PriceCacheKey, ErpPriceData>();
public static ErpPriceData GetOrAdd(PriceCacheKey key, Func<ErpPriceData> fetchFromErp)
{
if (_cache.TryGetValue(key, out var cachedResult))
{
return cachedResult;
}
// If not in cache, fetch from ERP
var erpData = fetchFromErp();
// Store in cache
_cache[key] = erpData;
return erpData;
}
}
3. The ERP Client
public class ErpClient
{
public ErpPriceData FetchPriceData(string productId, string userId, DateTime startDate, DateTime endDate)
{
// Pseudo code to call out to your ERP, e.g. via HTTP/REST, SOAP, etc.
// For example:
/*
var request = new ErpRequest
{
ProductId = productId,
UserId = userId,
RentalStart = startDate,
RentalEnd = endDate
};
var response = HttpClient.Post("http://myerp/pricing", request);
*/
// Then parse response:
// Convert the ERP response to ErpPriceData
var data = new ErpPriceData
{
FinalPrice = /* parse from response */,
DailyPrice = /* parse from response */,
DiscountAmount = /* parse from response */,
RentalStart = startDate,
RentalEnd = endDate
};
return data;
}
}
4. The PriceService (Orchestration Logic)
public class PriceService
{
private readonly ErpClient _erpClient;
public PriceService()
{
_erpClient = new ErpClient();
}
public ErpPriceData GetFullPriceData(string productId, string userId, DateTime startDate, DateTime endDate)
{
// Build our cache key
var cacheKey = new PriceCacheKey(productId, userId, startDate, endDate);
// Retrieve from cache or do ERP call
var erpPriceData = PriceCache.GetOrAdd(cacheKey, () => {
return _erpClient.FetchPriceData(productId, userId, startDate, endDate);
});
return erpPriceData;
}
}
5. The PriceProvider (Dynamicweb Integration)
// This class extends or implements the relevant PriceProvider interface in Dynamicweb
public class RentalPriceProvider // : Dynamicweb.eCommerce.Prices.PriceProvider (example)
{
private readonly PriceService _priceService = new PriceService();
// This is the method that Dynamicweb will call to get the final price
public PriceRaw GetPrice(PriceProviderContext context)
{
// 1) Extract needed info from the context
var productId = context.ProductId;
var userId = context.UserId;
var rentalStart = context.GetCustomField<DateTime>("RentalStart"); // example
var rentalEnd = context.GetCustomField<DateTime>("RentalEnd"); // example
// 2) Retrieve full ERP data from our PriceService
var erpData = _priceService.GetFullPriceData(productId, userId, rentalStart, rentalEnd);
// 3) Convert the final price from ERP to a PriceRaw (the only thing DW sees)
var priceRaw = new PriceRaw
{
Price = erpData.FinalPrice,
// Possibly set other standard fields from erpData if relevant
};
// 4) Return the price
return priceRaw;
}
}
6. Using the Cached Data Elsewhere
// Example: Some UI or a different piece of code wants to display daily price
public class SomeRentalUI
{
private readonly PriceService _priceService = new PriceService();
public void ShowRentalPrice(string productId, string userId, DateTime startDate, DateTime endDate)
{
// We fetch data from the same PriceService which uses the same cache.
var erpData = _priceService.GetFullPriceData(productId, userId, startDate, endDate);
// Now we have daily price, discount, etc.
Console.WriteLine("Daily price is " + erpData.DailyPrice);
}
}
Summary
-
PriceProvider (Dynamicweb integration layer)
- Returns PriceRaw to Dynamicweb.
- Delegates fetching logic to PriceService.
-
PriceService
- Orchestrates the retrieval of ERP data.
- Uses a PriceCache to avoid repeated calls.
-
PriceCache
- A dictionary or MemoryCache that stores ErpPriceData objects indexed by a composite key (Product + User + RentalPeriod).
-
ERP Client
- Knows how to call and parse the ERP response into an ErpPriceData.
-
Extra Data Consumption
- Other parts of the code that need additional ERP-derived info can call the PriceService and get an already cached ErpPriceData. This avoids calling the ERP a second time.
With this approach, you ensure that:
- You only call the ERP once per (product, user, date range) combination.
- You store all relevant ERP pricing data in a single object.
- The PriceProvider remains simple and only returns a
PriceRaw
object to Dynamicweb.
- The rest of the code can reuse the same data (daily price, discount info, etc.) from the cache without refetching from the ERP.