feat: reconcile application vertical slices
Backfill the completed acquisitions, sales, dashboard, pricing, search, public detail, worker, migration, contracts, validation, tests, and implementation-status changes into one verified application slice.
This commit is contained in:
@@ -21,4 +21,4 @@ export function toAdminAcquisitionDto(acquisition) {
|
||||
createdAt: toIsoString(acquisition.createdAt),
|
||||
updatedAt: toIsoString(acquisition.updatedAt),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,24 @@ export function toAdminDashboardDto(dashboard) {
|
||||
return {
|
||||
counts: dashboard.counts,
|
||||
financials: dashboard.financials,
|
||||
recentSales: dashboard.recentSales.map(({ sale, saleItem, inventoryItem, productName, netProceedsMinor, profitMinor }) => ({
|
||||
id: sale.id,
|
||||
productName: productName ?? inventoryItem.id,
|
||||
saleDate: sale.saleDate,
|
||||
soldPriceMinor: sale.soldPriceMinor,
|
||||
netProceedsMinor,
|
||||
profitMinor,
|
||||
inventoryItemId: saleItem.inventoryItemId,
|
||||
})),
|
||||
recentSales: dashboard.recentSales.map(
|
||||
({
|
||||
sale,
|
||||
saleItem,
|
||||
inventoryItem,
|
||||
productName,
|
||||
netProceedsMinor,
|
||||
profitMinor,
|
||||
}) => ({
|
||||
id: sale.id,
|
||||
productName: productName ?? inventoryItem.id,
|
||||
saleDate: sale.saleDate,
|
||||
soldPriceMinor: sale.soldPriceMinor,
|
||||
netProceedsMinor,
|
||||
profitMinor,
|
||||
inventoryItemId: saleItem.inventoryItemId,
|
||||
}),
|
||||
),
|
||||
recentAcquisitions: dashboard.recentAcquisitions.map((acquisition) => ({
|
||||
id: acquisition.id,
|
||||
inventoryItemId: acquisition.inventoryItemId,
|
||||
@@ -18,4 +27,4 @@ export function toAdminDashboardDto(dashboard) {
|
||||
costBasisMinor: acquisition.costBasisMinor ?? null,
|
||||
})),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
"./public-listing": "./public-listing.js",
|
||||
"./public-inventory": "./public-inventory.js",
|
||||
"./public-product": "./public-product.js",
|
||||
"./public-seller": "./public-seller.js"
|
||||
,"./pricing": "./pricing.js",
|
||||
"./public-seller": "./public-seller.js",
|
||||
"./pricing": "./pricing.js",
|
||||
"./provider-mapping": "./provider-mapping.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
function toIsoString(value) { return value instanceof Date ? value.toISOString() : value; }
|
||||
function toIsoString(value) {
|
||||
return value instanceof Date ? value.toISOString() : value;
|
||||
}
|
||||
|
||||
export function toAdminPricingObservationDto(observation) {
|
||||
return {
|
||||
@@ -28,7 +30,9 @@ export function toAdminMarketValuationDto({ valuation, observations }) {
|
||||
confidence: valuation.confidence,
|
||||
sourceCount: valuation.sourceCount,
|
||||
calculatedAt: toIsoString(valuation.calculatedAt),
|
||||
stale: Date.now() - new Date(valuation.calculatedAt).getTime() > 7 * 24 * 60 * 60 * 1000,
|
||||
stale:
|
||||
Date.now() - new Date(valuation.calculatedAt).getTime() >
|
||||
7 * 24 * 60 * 60 * 1000,
|
||||
observations: observations.map(toAdminPricingObservationDto),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,13 @@ export function toAdminProviderMappingDto(mapping) {
|
||||
sourceUrl: mapping.sourceUrl ?? null,
|
||||
status: mapping.status,
|
||||
metadata: mapping.metadata ?? {},
|
||||
createdAt: mapping.createdAt instanceof Date ? mapping.createdAt.toISOString() : mapping.createdAt,
|
||||
updatedAt: mapping.updatedAt instanceof Date ? mapping.updatedAt.toISOString() : mapping.updatedAt,
|
||||
createdAt:
|
||||
mapping.createdAt instanceof Date
|
||||
? mapping.createdAt.toISOString()
|
||||
: mapping.createdAt,
|
||||
updatedAt:
|
||||
mapping.updatedAt instanceof Date
|
||||
? mapping.updatedAt.toISOString()
|
||||
: mapping.updatedAt,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -19,4 +19,4 @@ export function toPublicListingDto(listing) {
|
||||
createdAt: toIsoString(listing.createdAt),
|
||||
updatedAt: toIsoString(listing.updatedAt),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,16 @@ function toIsoString(value) {
|
||||
return value instanceof Date ? value.toISOString() : value;
|
||||
}
|
||||
|
||||
export function toAdminSaleDto({ sale, saleItem, inventoryItem, saleItems = [saleItem], inventoryItems = [inventoryItem], netProceedsMinor, profitMinor, productName }) {
|
||||
export function toAdminSaleDto({
|
||||
sale,
|
||||
saleItem,
|
||||
inventoryItem,
|
||||
saleItems = [saleItem],
|
||||
inventoryItems = [inventoryItem],
|
||||
netProceedsMinor,
|
||||
profitMinor,
|
||||
productName,
|
||||
}) {
|
||||
return {
|
||||
id: sale.id,
|
||||
sellerId: sale.sellerId,
|
||||
@@ -40,8 +49,11 @@ export function toAdminSaleDto({ sale, saleItem, inventoryItem, saleItems = [sal
|
||||
id: inventoryItem.id,
|
||||
status: inventoryItem.status,
|
||||
},
|
||||
inventoryItems: inventoryItems.map((item) => ({ id: item.id, status: item.status })),
|
||||
inventoryItems: inventoryItems.map((item) => ({
|
||||
id: item.id,
|
||||
status: item.status,
|
||||
})),
|
||||
createdAt: toIsoString(sale.createdAt),
|
||||
updatedAt: toIsoString(sale.updatedAt),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
import { z } from 'zod';
|
||||
import { z } from "zod";
|
||||
|
||||
export const createAcquisitionSchema = z.object({
|
||||
inventoryItemId: z.uuid(),
|
||||
method: z.string().trim().min(1).max(100),
|
||||
costMinor: z.int().nonnegative(),
|
||||
currency: z.string().trim().regex(/^[A-Za-z]{3}$/).optional(),
|
||||
date: z.string().trim().max(10).optional(),
|
||||
source: z.string().trim().max(255).optional(),
|
||||
location: z.string().trim().max(255).optional(),
|
||||
shippingMinor: z.int().nonnegative().optional(),
|
||||
taxMinor: z.int().nonnegative().optional(),
|
||||
otherFeesMinor: z.int().nonnegative().optional(),
|
||||
estimatedTradeValueMinor: z.int().nonnegative().optional(),
|
||||
notes: z.string().trim().max(10000).optional(),
|
||||
}).strict();
|
||||
export const createAcquisitionSchema = z
|
||||
.object({
|
||||
inventoryItemId: z.uuid(),
|
||||
method: z.string().trim().min(1).max(100),
|
||||
costMinor: z.int().nonnegative(),
|
||||
currency: z
|
||||
.string()
|
||||
.trim()
|
||||
.regex(/^[A-Za-z]{3}$/)
|
||||
.optional(),
|
||||
date: z.string().trim().max(10).optional(),
|
||||
source: z.string().trim().max(255).optional(),
|
||||
location: z.string().trim().max(255).optional(),
|
||||
shippingMinor: z.int().nonnegative().optional(),
|
||||
taxMinor: z.int().nonnegative().optional(),
|
||||
otherFeesMinor: z.int().nonnegative().optional(),
|
||||
estimatedTradeValueMinor: z.int().nonnegative().optional(),
|
||||
notes: z.string().trim().max(10000).optional(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
"./image": "./image.js",
|
||||
"./listing": "./listing.js",
|
||||
"./sale": "./sale.js",
|
||||
"./product": "./product.js"
|
||||
,"./pricing": "./pricing.js",
|
||||
"./product": "./product.js",
|
||||
"./pricing": "./pricing.js",
|
||||
"./provider-mapping": "./provider-mapping.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"zod": "^4.1.8"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,31 @@
|
||||
import { z } from 'zod';
|
||||
import { z } from "zod";
|
||||
|
||||
export const createPricingObservationSchema = z.object({
|
||||
productId: z.uuid(),
|
||||
inventoryItemId: z.uuid(),
|
||||
providerId: z.string().trim().min(1).max(100),
|
||||
priceMinor: z.int().positive(),
|
||||
currency: z.string().trim().regex(/^[A-Za-z]{3}$/).optional(),
|
||||
sourceIdentifier: z.string().trim().min(1).max(255),
|
||||
conditionId: z.uuid(),
|
||||
sourceUrl: z.string().trim().url().optional(),
|
||||
qualityScore: z.int().min(0).max(100).optional(),
|
||||
}).strict();
|
||||
export const createPricingObservationSchema = z
|
||||
.object({
|
||||
productId: z.uuid(),
|
||||
inventoryItemId: z.uuid(),
|
||||
providerId: z.string().trim().min(1).max(100),
|
||||
priceMinor: z.int().positive(),
|
||||
currency: z
|
||||
.string()
|
||||
.trim()
|
||||
.regex(/^[A-Za-z]{3}$/)
|
||||
.optional(),
|
||||
sourceIdentifier: z.string().trim().min(1).max(255),
|
||||
conditionId: z.uuid(),
|
||||
sourceUrl: z.string().trim().url().optional(),
|
||||
qualityScore: z.int().min(0).max(100).optional(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
export const createMarketValueOverrideSchema = z.object({
|
||||
valueMinor: z.int().nonnegative(),
|
||||
currency: z.string().trim().regex(/^[A-Za-z]{3}$/).optional(),
|
||||
reason: z.string().trim().min(3).max(1000),
|
||||
}).strict();
|
||||
export const createMarketValueOverrideSchema = z
|
||||
.object({
|
||||
valueMinor: z.int().nonnegative(),
|
||||
currency: z
|
||||
.string()
|
||||
.trim()
|
||||
.regex(/^[A-Za-z]{3}$/)
|
||||
.optional(),
|
||||
reason: z.string().trim().min(3).max(1000),
|
||||
})
|
||||
.strict();
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { z } from 'zod';
|
||||
import { z } from "zod";
|
||||
|
||||
export const createProviderMappingSchema = z.object({
|
||||
providerId: z.string().trim().min(1).max(100),
|
||||
mappingType: z.enum(['PRODUCT', 'SEARCH']),
|
||||
externalIdentifier: z.string().trim().max(255).optional(),
|
||||
searchQuery: z.string().trim().max(1000).optional(),
|
||||
sourceUrl: z.string().trim().url().optional(),
|
||||
metadata: z.record(z.string(), z.unknown()).optional(),
|
||||
}).strict();
|
||||
export const createProviderMappingSchema = z
|
||||
.object({
|
||||
providerId: z.string().trim().min(1).max(100),
|
||||
mappingType: z.enum(["PRODUCT", "SEARCH"]),
|
||||
externalIdentifier: z.string().trim().max(255).optional(),
|
||||
searchQuery: z.string().trim().max(1000).optional(),
|
||||
sourceUrl: z.string().trim().url().optional(),
|
||||
metadata: z.record(z.string(), z.unknown()).optional(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
+40
-34
@@ -1,4 +1,4 @@
|
||||
import { z } from 'zod';
|
||||
import { z } from "zod";
|
||||
|
||||
const isoDate = /^\d{4}-\d{2}-\d{2}$/;
|
||||
const currencyCode = /^[A-Za-z]{3}$/;
|
||||
@@ -8,38 +8,44 @@ const saleItemSchema = z.object({
|
||||
costBasisMinor: z.int().nonnegative(),
|
||||
});
|
||||
|
||||
export const createSaleSchema = z.object({
|
||||
inventoryItemId: z.uuid(),
|
||||
costBasisMinor: z.int().nonnegative(),
|
||||
saleDate: z.string().trim().regex(isoDate),
|
||||
saleLocation: z.string().trim().max(255).optional(),
|
||||
soldPriceMinor: z.int().positive(),
|
||||
currency: z.string().trim().regex(currencyCode).optional(),
|
||||
platformFeesMinor: z.int().nonnegative().optional(),
|
||||
paymentProcessingFeesMinor: z.int().nonnegative().optional(),
|
||||
shippingCostMinor: z.int().nonnegative().optional(),
|
||||
taxesMinor: z.int().nonnegative().optional(),
|
||||
otherFeesMinor: z.int().nonnegative().optional(),
|
||||
buyerName: z.string().trim().max(255).optional(),
|
||||
buyerContact: z.string().trim().max(255).optional(),
|
||||
notes: z.string().trim().max(10000).optional(),
|
||||
}).strict();
|
||||
export const createSaleSchema = z
|
||||
.object({
|
||||
inventoryItemId: z.uuid(),
|
||||
costBasisMinor: z.int().nonnegative(),
|
||||
saleDate: z.string().trim().regex(isoDate),
|
||||
saleLocation: z.string().trim().max(255).optional(),
|
||||
soldPriceMinor: z.int().positive(),
|
||||
currency: z.string().trim().regex(currencyCode).optional(),
|
||||
platformFeesMinor: z.int().nonnegative().optional(),
|
||||
paymentProcessingFeesMinor: z.int().nonnegative().optional(),
|
||||
shippingCostMinor: z.int().nonnegative().optional(),
|
||||
taxesMinor: z.int().nonnegative().optional(),
|
||||
otherFeesMinor: z.int().nonnegative().optional(),
|
||||
buyerName: z.string().trim().max(255).optional(),
|
||||
buyerContact: z.string().trim().max(255).optional(),
|
||||
notes: z.string().trim().max(10000).optional(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
export const createMultiItemSaleSchema = z.object({
|
||||
items: z.array(saleItemSchema).min(2),
|
||||
saleDate: z.string().trim().regex(isoDate),
|
||||
saleLocation: z.string().trim().max(255).optional(),
|
||||
currency: z.string().trim().regex(currencyCode).optional(),
|
||||
platformFeesMinor: z.int().nonnegative().optional(),
|
||||
paymentProcessingFeesMinor: z.int().nonnegative().optional(),
|
||||
shippingCostMinor: z.int().nonnegative().optional(),
|
||||
taxesMinor: z.int().nonnegative().optional(),
|
||||
otherFeesMinor: z.int().nonnegative().optional(),
|
||||
buyerName: z.string().trim().max(255).optional(),
|
||||
buyerContact: z.string().trim().max(255).optional(),
|
||||
notes: z.string().trim().max(10000).optional(),
|
||||
}).strict();
|
||||
export const createMultiItemSaleSchema = z
|
||||
.object({
|
||||
items: z.array(saleItemSchema).min(2),
|
||||
saleDate: z.string().trim().regex(isoDate),
|
||||
saleLocation: z.string().trim().max(255).optional(),
|
||||
currency: z.string().trim().regex(currencyCode).optional(),
|
||||
platformFeesMinor: z.int().nonnegative().optional(),
|
||||
paymentProcessingFeesMinor: z.int().nonnegative().optional(),
|
||||
shippingCostMinor: z.int().nonnegative().optional(),
|
||||
taxesMinor: z.int().nonnegative().optional(),
|
||||
otherFeesMinor: z.int().nonnegative().optional(),
|
||||
buyerName: z.string().trim().max(255).optional(),
|
||||
buyerContact: z.string().trim().max(255).optional(),
|
||||
notes: z.string().trim().max(10000).optional(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
export const voidSaleSchema = z.object({
|
||||
reason: z.string().trim().min(3).max(1000),
|
||||
}).strict();
|
||||
export const voidSaleSchema = z
|
||||
.object({
|
||||
reason: z.string().trim().min(3).max(1000),
|
||||
})
|
||||
.strict();
|
||||
|
||||
Reference in New Issue
Block a user