This commit is contained in:
@@ -143,6 +143,7 @@ async function startServer() {
|
||||
listingService: createListingService({ listingRepository, inventoryImageRepository }),
|
||||
saleService: createSaleService({ saleRepository }),
|
||||
acquisitionService: createAcquisitionService({ acquisitionRepository }),
|
||||
pricingRepository,
|
||||
}),
|
||||
pricingService: createPricingService({ pricingRepository, pricingRefreshJobRepository, providerMappingRepository, pricingProviderRegistry: pricingProviders }),
|
||||
providerMappingService: createProviderMappingService({ providerMappingRepository }),
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
export function createDashboardService({ productService, inventoryItemService, listingService, saleService, acquisitionService }) {
|
||||
export function createDashboardService({ productService, inventoryItemService, listingService, saleService, acquisitionService, pricingRepository }) {
|
||||
return {
|
||||
async get({ sellerId }) {
|
||||
const [products, inventory, listings, sales, acquisitions] = await Promise.all([
|
||||
const [products, inventory, listings, sales, acquisitions, valuations] = await Promise.all([
|
||||
productService.listBySellerId(sellerId),
|
||||
inventoryItemService.listBySellerId(sellerId),
|
||||
listingService.list({ sellerId }),
|
||||
saleService.list({ sellerId }),
|
||||
acquisitionService.list({ sellerId }),
|
||||
pricingRepository?.listLatestValuationsForSeller(sellerId) ?? [],
|
||||
]);
|
||||
|
||||
const activeListings = listings.filter(({ status }) => ['AVAILABLE', 'PENDING'].includes(status));
|
||||
const completedSales = sales.filter(({ status }) => status !== 'VOIDED');
|
||||
const valuationByItem = new Map(valuations.map((valuation) => [valuation.inventoryItemId, valuation]));
|
||||
const staleThreshold = 7 * 24 * 60 * 60 * 1000;
|
||||
const total = (values, field) => values.reduce((sum, value) => sum + (value[field] ?? 0), 0);
|
||||
|
||||
return {
|
||||
@@ -23,12 +26,15 @@ export function createDashboardService({ productService, inventoryItemService, l
|
||||
sales: completedSales.length,
|
||||
acquisitions: acquisitions.length,
|
||||
missingImages: listings.filter(({ imageCount }) => imageCount < 1).length,
|
||||
missingPricing: inventory.filter(({ id }) => !valuationByItem.has(id)).length,
|
||||
stalePricing: valuations.filter(({ calculatedAt }) => Date.now() - new Date(calculatedAt).getTime() > staleThreshold).length,
|
||||
},
|
||||
financials: {
|
||||
totalAcquisitionCostMinor: total(acquisitions, 'costBasisMinor'),
|
||||
totalAskingValueMinor: total(activeListings, 'askingPriceMinor'),
|
||||
totalNetSaleProceedsMinor: total(completedSales, 'netProceedsMinor'),
|
||||
totalProfitMinor: total(completedSales, 'profitMinor'),
|
||||
totalMarketValueMinor: total([...valuationByItem.values()], 'valueMinor'),
|
||||
},
|
||||
recentSales: completedSales.slice(0, 5),
|
||||
recentAcquisitions: acquisitions.slice(0, 5),
|
||||
|
||||
@@ -41,6 +41,20 @@ export function createPricingRepository(db) {
|
||||
return { status: 'CALCULATED', valuation, observations };
|
||||
},
|
||||
|
||||
async listLatestValuationsForSeller(sellerId) {
|
||||
const rows = await db.select({ valuation: marketValuations, inventoryItemId: inventoryItems.id })
|
||||
.from(marketValuations)
|
||||
.innerJoin(inventoryItems, eq(inventoryItems.id, marketValuations.inventoryItemId))
|
||||
.innerJoin(products, eq(products.id, inventoryItems.productId))
|
||||
.where(eq(products.sellerId, sellerId))
|
||||
.orderBy(desc(marketValuations.calculatedAt));
|
||||
const latest = new Map();
|
||||
for (const row of rows) {
|
||||
if (!latest.has(row.inventoryItemId)) latest.set(row.inventoryItemId, row.valuation);
|
||||
}
|
||||
return [...latest.values()];
|
||||
},
|
||||
|
||||
async markOutliersForSeller({ inventoryItemId, sellerId }) {
|
||||
const [ownedItem] = await db.select({ id: inventoryItems.id }).from(inventoryItems)
|
||||
.innerJoin(products, eq(products.id, inventoryItems.productId))
|
||||
|
||||
Reference in New Issue
Block a user