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:
@@ -1,17 +1,17 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
|
||||
import {
|
||||
calculateAcquisitionCostBasis,
|
||||
createAcquisition,
|
||||
} from '../../src/modules/acquisitions/domain/acquisition.js';
|
||||
} from "../../src/modules/acquisitions/domain/acquisition.js";
|
||||
import {
|
||||
calculateMedianPriceMinor,
|
||||
createPricingObservation,
|
||||
identifyOutlierPrices,
|
||||
} from '../../src/modules/pricing/domain/pricing-observation.js';
|
||||
} from "../../src/modules/pricing/domain/pricing-observation.js";
|
||||
|
||||
test('calculates acquisition cost basis from all cost components', () => {
|
||||
test("calculates acquisition cost basis from all cost components", () => {
|
||||
const total = calculateAcquisitionCostBasis({
|
||||
costMinor: 1000,
|
||||
shippingMinor: 150,
|
||||
@@ -23,43 +23,48 @@ test('calculates acquisition cost basis from all cost components', () => {
|
||||
assert.equal(total, 1075);
|
||||
});
|
||||
|
||||
test('rejects negative acquisition values and missing identity fields', () => {
|
||||
test("rejects negative acquisition values and missing identity fields", () => {
|
||||
assert.throws(
|
||||
() => createAcquisition({
|
||||
inventoryItemId: 'inventory-item-id',
|
||||
method: 'PURCHASE',
|
||||
costMinor: -1,
|
||||
}),
|
||||
() =>
|
||||
createAcquisition({
|
||||
inventoryItemId: "inventory-item-id",
|
||||
method: "PURCHASE",
|
||||
costMinor: -1,
|
||||
}),
|
||||
/must be a non-negative integer minor unit/,
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
() => createAcquisition({
|
||||
inventoryItemId: '',
|
||||
method: 'PURCHASE',
|
||||
costMinor: 1000,
|
||||
}),
|
||||
() =>
|
||||
createAcquisition({
|
||||
inventoryItemId: "",
|
||||
method: "PURCHASE",
|
||||
costMinor: 1000,
|
||||
}),
|
||||
/Inventory item ID is required/,
|
||||
);
|
||||
});
|
||||
|
||||
test('creates pricing observations and calculates a median observed price', () => {
|
||||
test("creates pricing observations and calculates a median observed price", () => {
|
||||
const observation = createPricingObservation({
|
||||
productId: 'product-id',
|
||||
inventoryItemId: 'inventory-item-id',
|
||||
providerId: 'ebay',
|
||||
productId: "product-id",
|
||||
inventoryItemId: "inventory-item-id",
|
||||
providerId: "ebay",
|
||||
priceMinor: 2499,
|
||||
currency: 'USD',
|
||||
sourceIdentifier: 'listing-1',
|
||||
conditionId: 'condition-id',
|
||||
currency: "USD",
|
||||
sourceIdentifier: "listing-1",
|
||||
conditionId: "condition-id",
|
||||
});
|
||||
|
||||
assert.equal(observation.currency, 'USD');
|
||||
assert.equal(observation.currency, "USD");
|
||||
assert.equal(observation.priceMinor, 2499);
|
||||
assert.equal(calculateMedianPriceMinor([1199, 2499, 2000]), 2000);
|
||||
});
|
||||
|
||||
test('identifies extreme pricing observations without discarding normal values', () => {
|
||||
assert.deepEqual([...identifyOutlierPrices([1000, 1050, 1100, 5000])], [5000]);
|
||||
test("identifies extreme pricing observations without discarding normal values", () => {
|
||||
assert.deepEqual(
|
||||
[...identifyOutlierPrices([1000, 1050, 1100, 5000])],
|
||||
[5000],
|
||||
);
|
||||
assert.equal(identifyOutlierPrices([1000, 1050, 1100]).size, 0);
|
||||
});
|
||||
|
||||
@@ -1,76 +1,83 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
|
||||
import {
|
||||
calculateNetSaleProceeds,
|
||||
createSale,
|
||||
createSaleItem,
|
||||
} from '../../src/modules/sales/domain/sale.js';
|
||||
} from "../../src/modules/sales/domain/sale.js";
|
||||
|
||||
test('creates a valid sale record and calculates net proceeds after fees', () => {
|
||||
test("creates a valid sale record and calculates net proceeds after fees", () => {
|
||||
const sale = createSale({
|
||||
sellerId: 'seller-id',
|
||||
saleDate: '2026-09-08',
|
||||
saleLocation: 'eBay',
|
||||
sellerId: "seller-id",
|
||||
saleDate: "2026-09-08",
|
||||
saleLocation: "eBay",
|
||||
soldPriceMinor: 4999,
|
||||
currency: 'USD',
|
||||
currency: "USD",
|
||||
platformFeesMinor: 300,
|
||||
paymentProcessingFeesMinor: 120,
|
||||
shippingCostMinor: 50,
|
||||
taxesMinor: 90,
|
||||
otherFeesMinor: 40,
|
||||
buyerName: 'Alex',
|
||||
buyerContact: 'alex@example.com',
|
||||
buyerName: "Alex",
|
||||
buyerContact: "alex@example.com",
|
||||
});
|
||||
|
||||
assert.equal(sale.soldPriceMinor, 4999);
|
||||
assert.equal(sale.currency, 'USD');
|
||||
assert.equal(calculateNetSaleProceeds({
|
||||
soldPriceMinor: 4999,
|
||||
platformFeesMinor: 300,
|
||||
paymentProcessingFeesMinor: 120,
|
||||
shippingCostMinor: 50,
|
||||
taxesMinor: 90,
|
||||
otherFeesMinor: 40,
|
||||
}), 4399);
|
||||
assert.equal(sale.currency, "USD");
|
||||
assert.equal(
|
||||
calculateNetSaleProceeds({
|
||||
soldPriceMinor: 4999,
|
||||
platformFeesMinor: 300,
|
||||
paymentProcessingFeesMinor: 120,
|
||||
shippingCostMinor: 50,
|
||||
taxesMinor: 90,
|
||||
otherFeesMinor: 40,
|
||||
}),
|
||||
4399,
|
||||
);
|
||||
});
|
||||
|
||||
test('rejects invalid sales and negative fee values', () => {
|
||||
test("rejects invalid sales and negative fee values", () => {
|
||||
assert.throws(
|
||||
() => createSale({
|
||||
sellerId: 'seller-id',
|
||||
saleDate: '2026-09-08',
|
||||
soldPriceMinor: 0,
|
||||
}),
|
||||
() =>
|
||||
createSale({
|
||||
sellerId: "seller-id",
|
||||
saleDate: "2026-09-08",
|
||||
soldPriceMinor: 0,
|
||||
}),
|
||||
/must be a positive integer minor unit/,
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
() => createSaleItem({
|
||||
saleId: 'sale-id',
|
||||
inventoryItemId: 'inventory-item-id',
|
||||
soldPriceMinor: 2000,
|
||||
costBasisMinor: -1,
|
||||
}),
|
||||
() =>
|
||||
createSaleItem({
|
||||
saleId: "sale-id",
|
||||
inventoryItemId: "inventory-item-id",
|
||||
soldPriceMinor: 2000,
|
||||
costBasisMinor: -1,
|
||||
}),
|
||||
/must be a non-negative integer minor unit/,
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
() => createSale({
|
||||
sellerId: 'seller-id',
|
||||
saleDate: '2026-02-30',
|
||||
soldPriceMinor: 2000,
|
||||
}),
|
||||
() =>
|
||||
createSale({
|
||||
sellerId: "seller-id",
|
||||
saleDate: "2026-02-30",
|
||||
soldPriceMinor: 2000,
|
||||
}),
|
||||
/must be a valid ISO date/,
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
() => createSale({
|
||||
sellerId: 'seller-id',
|
||||
saleDate: '2026-09-08',
|
||||
soldPriceMinor: 2000,
|
||||
currency: 'US dollars',
|
||||
}),
|
||||
() =>
|
||||
createSale({
|
||||
sellerId: "seller-id",
|
||||
saleDate: "2026-09-08",
|
||||
soldPriceMinor: 2000,
|
||||
currency: "US dollars",
|
||||
}),
|
||||
/must be a three-letter ISO currency code/,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
|
||||
import {
|
||||
buildSearchFilters,
|
||||
createSearchQuery,
|
||||
normalizeSearchQuery,
|
||||
} from '../../src/modules/search/domain/search-query.js';
|
||||
} from "../../src/modules/search/domain/search-query.js";
|
||||
|
||||
test('normalizes a public search query and keeps filter values within bounds', () => {
|
||||
test("normalizes a public search query and keeps filter values within bounds", () => {
|
||||
const query = createSearchQuery({
|
||||
query: ' Charizard ex ',
|
||||
category: 'Cards',
|
||||
query: " Charizard ex ",
|
||||
category: "Cards",
|
||||
minPriceMinor: 1000,
|
||||
maxPriceMinor: 5000,
|
||||
page: 1,
|
||||
@@ -18,8 +18,8 @@ test('normalizes a public search query and keeps filter values within bounds', (
|
||||
includeSold: false,
|
||||
});
|
||||
|
||||
assert.equal(query.text, 'charizard ex');
|
||||
assert.equal(query.category, 'Cards');
|
||||
assert.equal(query.text, "charizard ex");
|
||||
assert.equal(query.category, "Cards");
|
||||
assert.equal(query.minPriceMinor, 1000);
|
||||
assert.equal(query.maxPriceMinor, 5000);
|
||||
assert.equal(query.page, 1);
|
||||
@@ -27,25 +27,45 @@ test('normalizes a public search query and keeps filter values within bounds', (
|
||||
assert.equal(query.includeSold, false);
|
||||
});
|
||||
|
||||
test('rejects invalid pagination and price boundaries', () => {
|
||||
assert.throws(() => createSearchQuery({ query: 'abc', page: 0, limit: 20 }), /page must be >= 1/);
|
||||
assert.throws(() => createSearchQuery({ query: 'abc', minPriceMinor: 5000, maxPriceMinor: 1000 }), /minPriceMinor must be <= maxPriceMinor/);
|
||||
assert.throws(() => createSearchQuery({ query: 'abc', limit: 0 }), /limit must be between 1 and 100/);
|
||||
test("rejects invalid pagination and price boundaries", () => {
|
||||
assert.throws(
|
||||
() => createSearchQuery({ query: "abc", page: 0, limit: 20 }),
|
||||
/page must be >= 1/,
|
||||
);
|
||||
assert.throws(
|
||||
() =>
|
||||
createSearchQuery({
|
||||
query: "abc",
|
||||
minPriceMinor: 5000,
|
||||
maxPriceMinor: 1000,
|
||||
}),
|
||||
/minPriceMinor must be <= maxPriceMinor/,
|
||||
);
|
||||
assert.throws(
|
||||
() => createSearchQuery({ query: "abc", limit: 0 }),
|
||||
/limit must be between 1 and 100/,
|
||||
);
|
||||
});
|
||||
|
||||
test('builds a public query filter set that hides sold items by default', () => {
|
||||
test("builds a public query filter set that hides sold items by default", () => {
|
||||
const filters = buildSearchFilters({ includeSold: false });
|
||||
|
||||
assert.equal(filters.status, 'AVAILABLE');
|
||||
assert.equal(filters.status, "AVAILABLE");
|
||||
assert.equal(filters.includeSold, false);
|
||||
assert.deepEqual(filters.sort, ['recently_added']);
|
||||
assert.deepEqual(filters.sort, ["recently_added"]);
|
||||
});
|
||||
|
||||
test('accepts only the supported public search sort values', () => {
|
||||
assert.equal(createSearchQuery({ sort: 'price_low' }).sort, 'price_low');
|
||||
assert.throws(() => createSearchQuery({ sort: 'random' }), /sort must be recent/);
|
||||
test("accepts only the supported public search sort values", () => {
|
||||
assert.equal(createSearchQuery({ sort: "price_low" }).sort, "price_low");
|
||||
assert.throws(
|
||||
() => createSearchQuery({ sort: "random" }),
|
||||
/sort must be recent/,
|
||||
);
|
||||
});
|
||||
|
||||
test('normalizes whitespace and punctuation in free-text search terms', () => {
|
||||
assert.equal(normalizeSearchQuery(' Pikachu #199 / holo '), 'pikachu 199 holo');
|
||||
test("normalizes whitespace and punctuation in free-text search terms", () => {
|
||||
assert.equal(
|
||||
normalizeSearchQuery(" Pikachu #199 / holo "),
|
||||
"pikachu 199 holo",
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user