feat: add Amazon seller and buy box share metrics to product analysis
- Introduced `amazonIsSeller` and `amazonBuyboxSharePct90d` fields in KeepaData type. - Updated database schema and queries to store Amazon seller status and buy box share percentage. - Enhanced product analysis results with new metrics from Keepa API. - Modified frontend components to display Amazon seller status and buy box share percentage. - Implemented reanalysis functionality for products to refresh Amazon-related metrics.
This commit is contained in:
@@ -36,6 +36,8 @@ function createProductAnalysisResultsTable(database: Database): void {
|
||||
sales_rank INTEGER,
|
||||
sales_rank_avg_90d INTEGER,
|
||||
seller_count INTEGER,
|
||||
amazon_is_seller INTEGER,
|
||||
amazon_buybox_share_pct_90d REAL,
|
||||
monthly_sold INTEGER,
|
||||
rank_drops_30d INTEGER,
|
||||
rank_drops_90d INTEGER,
|
||||
@@ -92,7 +94,9 @@ function ensureProductAnalysisResultsTable(database: Database): void {
|
||||
asin, run_id, name, brand, category, unit_cost,
|
||||
current_price, avg_price_90d, avg_price_90d_sheet,
|
||||
selling_price_sheet, sales_rank, sales_rank_avg_90d,
|
||||
seller_count, monthly_sold, rank_drops_30d, rank_drops_90d,
|
||||
seller_count, NULL AS amazon_is_seller,
|
||||
NULL AS amazon_buybox_share_pct_90d,
|
||||
monthly_sold, rank_drops_30d, rank_drops_90d,
|
||||
fba_fee, fbm_fee, referral_percent, can_sell,
|
||||
sellability_status, sellability_reason,
|
||||
verdict, confidence, reasoning, fetched_at,
|
||||
@@ -106,7 +110,8 @@ function ensureProductAnalysisResultsTable(database: Database): void {
|
||||
asin, run_id, name, brand, category, unit_cost,
|
||||
current_price, avg_price_90d, avg_price_90d_sheet,
|
||||
selling_price_sheet, sales_rank, sales_rank_avg_90d,
|
||||
seller_count, monthly_sold, rank_drops_30d, rank_drops_90d,
|
||||
seller_count, amazon_is_seller, amazon_buybox_share_pct_90d,
|
||||
monthly_sold, rank_drops_30d, rank_drops_90d,
|
||||
fba_fee, fbm_fee, referral_percent, can_sell,
|
||||
sellability_status, sellability_reason,
|
||||
verdict, confidence, reasoning, fetched_at
|
||||
@@ -115,7 +120,8 @@ function ensureProductAnalysisResultsTable(database: Database): void {
|
||||
asin, run_id, name, brand, category, unit_cost,
|
||||
current_price, avg_price_90d, avg_price_90d_sheet,
|
||||
selling_price_sheet, sales_rank, sales_rank_avg_90d,
|
||||
seller_count, monthly_sold, rank_drops_30d, rank_drops_90d,
|
||||
seller_count, amazon_is_seller, amazon_buybox_share_pct_90d,
|
||||
monthly_sold, rank_drops_30d, rank_drops_90d,
|
||||
fba_fee, fbm_fee, referral_percent, can_sell,
|
||||
sellability_status, sellability_reason,
|
||||
verdict, confidence, reasoning, fetched_at
|
||||
@@ -126,6 +132,30 @@ function ensureProductAnalysisResultsTable(database: Database): void {
|
||||
}
|
||||
}
|
||||
|
||||
function ensureProductAnalysisResultsColumns(database: Database): void {
|
||||
const tableInfo = database
|
||||
.query("PRAGMA table_info(product_analysis_results)")
|
||||
.all() as Array<{ name: string }>;
|
||||
|
||||
if (tableInfo.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const existingColumns = new Set(tableInfo.map((col) => col.name));
|
||||
const requiredColumns: Array<{ name: string; type: string }> = [
|
||||
{ name: "amazon_is_seller", type: "INTEGER" },
|
||||
{ name: "amazon_buybox_share_pct_90d", type: "REAL" },
|
||||
];
|
||||
|
||||
for (const column of requiredColumns) {
|
||||
if (!existingColumns.has(column.name)) {
|
||||
database.run(
|
||||
`ALTER TABLE product_analysis_results ADD COLUMN ${column.name} ${column.type}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ensureResultsTableColumns(database: Database): void {
|
||||
const tableInfo = database
|
||||
.query("PRAGMA table_info(results)")
|
||||
@@ -151,6 +181,8 @@ function ensureResultsTableColumns(database: Database): void {
|
||||
{ name: "promo_coupon_code", type: "TEXT" },
|
||||
{ name: "notes", type: "TEXT" },
|
||||
{ name: "lead_date", type: "TEXT" },
|
||||
{ name: "amazon_is_seller", type: "INTEGER" },
|
||||
{ name: "amazon_buybox_share_pct_90d", type: "REAL" },
|
||||
];
|
||||
|
||||
for (const column of requiredColumns) {
|
||||
@@ -192,6 +224,8 @@ export function initDb(dbPath: string): void {
|
||||
sales_rank INTEGER,
|
||||
rank_avg_90d INTEGER,
|
||||
sellers INTEGER,
|
||||
amazon_is_seller INTEGER,
|
||||
amazon_buybox_share_pct_90d REAL,
|
||||
monthly_sold INTEGER,
|
||||
rank_drops_30d INTEGER,
|
||||
rank_drops_90d INTEGER,
|
||||
@@ -239,6 +273,7 @@ export function initDb(dbPath: string): void {
|
||||
);
|
||||
`);
|
||||
ensureProductAnalysisResultsTable(database);
|
||||
ensureProductAnalysisResultsColumns(database);
|
||||
|
||||
database.run(
|
||||
`CREATE INDEX IF NOT EXISTS idx_runs_timestamp ON runs(timestamp DESC);`,
|
||||
|
||||
Reference in New Issue
Block a user