Initial commit (unpacked platform)
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
import {
|
||||
boolean,
|
||||
date,
|
||||
doublePrecision,
|
||||
index,
|
||||
pgTable,
|
||||
text,
|
||||
uuid,
|
||||
integer,
|
||||
} from "drizzle-orm/pg-core";
|
||||
import { createdAt, unitEnum } from "./_shared.js";
|
||||
import { households } from "./households.js";
|
||||
import { canonicalIngredients } from "./ingredients.js";
|
||||
import { products } from "./products.js";
|
||||
|
||||
/** Kvitton (spec §12): lager + budget + prishistorik + matsvinnsvärde. */
|
||||
export const receipts = pgTable(
|
||||
"receipts",
|
||||
{
|
||||
id: uuid("id").primaryKey().defaultRandom(),
|
||||
householdId: uuid("household_id")
|
||||
.notNull()
|
||||
.references(() => households.id, { onDelete: "cascade" }),
|
||||
storeName: text("store_name"),
|
||||
purchaseDate: date("purchase_date"),
|
||||
totalMinor: integer("total_minor"),
|
||||
discountMinor: integer("discount_minor"),
|
||||
imageUrl: text("image_url"),
|
||||
scanJobId: uuid("scan_job_id"),
|
||||
status: text("status").notNull().default("pending"),
|
||||
createdAt: createdAt(),
|
||||
},
|
||||
(t) => [index("receipts_household_idx").on(t.householdId, t.purchaseDate)],
|
||||
);
|
||||
|
||||
export const receiptLines = pgTable(
|
||||
"receipt_lines",
|
||||
{
|
||||
id: uuid("id").primaryKey().defaultRandom(),
|
||||
receiptId: uuid("receipt_id")
|
||||
.notNull()
|
||||
.references(() => receipts.id, { onDelete: "cascade" }),
|
||||
rawText: text("raw_text").notNull(),
|
||||
normalizedName: text("normalized_name"),
|
||||
canonicalIngredientId: text("canonical_ingredient_id").references(
|
||||
() => canonicalIngredients.id,
|
||||
),
|
||||
productId: uuid("product_id").references(() => products.id),
|
||||
quantity: doublePrecision("quantity"),
|
||||
unit: unitEnum("unit"),
|
||||
unitPriceMinor: integer("unit_price_minor"),
|
||||
totalPriceMinor: integer("total_price_minor"),
|
||||
confidence: doublePrecision("confidence").notNull().default(0),
|
||||
verifiedByUser: boolean("verified_by_user").notNull().default(false),
|
||||
addedToInventory: boolean("added_to_inventory").notNull().default(false),
|
||||
},
|
||||
(t) => [index("receipt_lines_receipt_idx").on(t.receiptId)],
|
||||
);
|
||||
|
||||
/** Prishistorik per ingrediens/produkt – grund för budget och prognoser (spec §12, §26). */
|
||||
export const priceObservations = pgTable(
|
||||
"price_observations",
|
||||
{
|
||||
id: uuid("id").primaryKey().defaultRandom(),
|
||||
canonicalIngredientId: text("canonical_ingredient_id").references(
|
||||
() => canonicalIngredients.id,
|
||||
),
|
||||
productId: uuid("product_id").references(() => products.id),
|
||||
storeName: text("store_name"),
|
||||
priceMinor: integer("price_minor").notNull(),
|
||||
quantity: doublePrecision("quantity"),
|
||||
unit: unitEnum("unit"),
|
||||
pricePerKgMinor: integer("price_per_kg_minor"),
|
||||
observedAt: date("observed_at").notNull(),
|
||||
source: text("source").notNull().default("receipt"),
|
||||
createdAt: createdAt(),
|
||||
},
|
||||
(t) => [index("price_observations_ingredient_idx").on(t.canonicalIngredientId, t.observedAt)],
|
||||
);
|
||||
Reference in New Issue
Block a user