export type ColumnType = "uuid" | "string" | "longtext" | "bool" | "double" | "int" | "datetime"; export type Column = { name: string; type: ColumnType; nullable: boolean; hasDefault: boolean; max?: number; }; export type TableSpec = { name: string; columns: Column[]; }; function col( name: string, type: ColumnType, extra?: Partial>, ): Column { return { name, type, nullable: extra?.nullable ?? false, hasDefault: extra?.hasDefault ?? false, max: extra?.max, }; } function tail(): Column[] { return [ col("updated_at", "datetime"), col("deleted_at", "datetime", { nullable: true, hasDefault: true }), col("is_dirty", "bool", { hasDefault: true }), ]; } const id = () => col("id", "uuid"); const text = (name: string, max: number, hasDefault = false) => col(name, "string", { max, hasDefault }); const ref = (name: string, nullable = false) => col(name, "uuid", { nullable }); export const SYNC_TABLES: Record = { staff_members: { name: "staff_members", columns: [ id(), text("name", 255), text("pin_hash", 255), text("role", 64), col("active", "bool", { hasDefault: true }), ...tail(), ], }, shop_settings: { name: "shop_settings", columns: [ id(), text("name", 255), text("address", 4000, true), text("phone", 64, true), text("gstin", 64, true), col("tax_percent", "double", { hasDefault: true }), text("sms_bill_template", 4000), text("sms_status_template", 4000), // v1 does not allocate invoice numbers. next_invoice_number is last-write-wins. // Two tablets incrementing it will clash. col("next_invoice_number", "int", { hasDefault: true }), text("expected_open", 16, true), text("expected_close", 16, true), col("late_grace_minutes", "int", { hasDefault: true }), text("public_base_url", 512), ...tail(), ], }, work_days: { name: "work_days", columns: [ id(), text("day_key", 32), col("started_at", "datetime"), col("ended_at", "datetime", { nullable: true }), ref("started_by_staff_id"), ...tail(), ], }, attendance_records: { name: "attendance_records", columns: [ id(), ref("work_day_id"), ref("staff_id"), col("check_in_at", "datetime", { nullable: true }), col("check_out_at", "datetime", { nullable: true }), text("notes", 4000, true), ...tail(), ], }, short_leaves: { name: "short_leaves", columns: [ id(), ref("work_day_id"), ref("staff_id"), col("from_at", "datetime"), col("to_at", "datetime"), col("minutes", "int"), text("reason", 4000, true), ...tail(), ], }, overtime_logs: { name: "overtime_logs", columns: [ id(), ref("work_day_id"), ref("staff_id"), col("from_at", "datetime", { nullable: true }), col("to_at", "datetime", { nullable: true }), col("minutes", "int"), text("reason", 4000, true), ...tail(), ], }, customers: { name: "customers", columns: [ id(), text("phone", 64), text("name", 255), col("created_at", "datetime", { hasDefault: true }), ...tail(), ], }, vehicles: { name: "vehicles", columns: [ id(), ref("customer_id"), text("registration", 64), text("vin", 64, true), text("make", 255, true), text("model_name", 255, true), col("year", "int", { nullable: true }), col("engine_capacity", "int", { nullable: true }), ref("bike_model_id", true), col("created_at", "datetime", { hasDefault: true }), ...tail(), ], }, job_cards: { name: "job_cards", columns: [ id(), ref("vehicle_id"), ref("customer_id"), ref("brought_by_customer_id", true), text("complaint", 4000), text("stage", 64), text("engineer_notes", 4000, true), col("created_at", "datetime", { hasDefault: true }), ...tail(), ], }, odo_readings: { name: "odo_readings", columns: [id(), col("read_at", "datetime"), ref("vehicle_id"), col("reading_km", "int"), ...tail()], }, job_card_events: { name: "job_card_events", columns: [ id(), ref("job_card_id"), text("stage", 64), text("note", 4000, true), col("at", "datetime"), ...tail(), ], }, part_types: { name: "part_types", columns: [id(), text("name", 255), ...tail()], }, bike_models: { name: "bike_models", columns: [id(), text("name", 255), text("brand", 255, true), ...tail()], }, bike_groups: { name: "bike_groups", columns: [ id(), text("name", 255), ref("part_type_id", true), text("code", 64, true), text("notes", 4000, true), ...tail(), ], }, bike_group_members: { name: "bike_group_members", columns: [id(), ref("group_id"), ref("bike_model_id"), ...tail()], }, catalog_parts: { name: "catalog_parts", columns: [ id(), ref("part_type_id"), ref("bike_model_id", true), ref("group_id", true), col("is_universal", "bool", { hasDefault: true }), ...tail(), ], }, catalog_part_models: { name: "catalog_part_models", columns: [id(), ref("catalog_part_id"), ref("bike_model_id"), ...tail()], }, part_variants: { name: "part_variants", columns: [ id(), ref("catalog_part_id"), text("grade", 64), text("brand", 255, true), text("sku", 128, true), col("cost", "double", { hasDefault: true }), col("sale_price", "double"), col("qty_on_hand", "double", { hasDefault: true }), ...tail(), ], }, job_line_items: { name: "job_line_items", columns: [ id(), ref("job_card_id"), text("kind", 64), ref("variant_id", true), text("description", 4000), col("qty", "double"), col("unit_price", "double"), ...tail(), ], }, invoices: { name: "invoices", columns: [ id(), text("number", 64), ref("public_token"), ref("job_card_id", true), ref("customer_id", true), text("kind", 64), col("subtotal", "double"), col("tax_percent", "double"), col("tax_amount", "double"), col("total", "double"), col("snapshot_json", "longtext"), text("publish_status", 64), col("created_at", "datetime"), ...tail(), ], }, invoice_lines: { name: "invoice_lines", columns: [ id(), ref("invoice_id"), text("description", 4000), col("qty", "double"), col("unit_price", "double"), col("line_total", "double"), ...tail(), ], }, payments: { name: "payments", columns: [ id(), ref("invoice_id"), text("method", 64), col("amount", "double"), col("at", "datetime"), ...tail(), ], }, demand_logs: { name: "demand_logs", columns: [ id(), ref("part_type_id"), ref("bike_model_id"), ref("variant_id", true), col("qty", "double"), text("reason", 4000, true), col("created_at", "datetime"), ...tail(), ], }, sms_outbox: { name: "sms_outbox", columns: [ id(), text("to_phone", 64), text("body", 4000), text("status", 64), text("error", 4000, true), ref("invoice_id", true), ref("job_card_id", true), col("created_at", "datetime"), ...tail(), ], }, publish_outbox: { name: "publish_outbox", columns: [ id(), ref("invoice_id"), ref("public_token"), col("payload_json", "longtext"), text("status", 64), text("error", 4000, true), col("created_at", "datetime"), ...tail(), ], }, }; export const SYNC_TABLE_NAMES = Object.keys(SYNC_TABLES);