Add product price history model and database schema: Implement associations for ProductPriceHistory with ProductType and RegionData. Update FalukantService to utilize active character for user-related operations. Ensure product price history table exists in the database with appropriate structure and indexing.
This commit is contained in:
@@ -421,6 +421,13 @@ export default function setupAssociations() {
|
||||
DaySell.belongsTo(FalukantUser, { foreignKey: 'sellerId', as: 'user' });
|
||||
FalukantUser.hasMany(DaySell, { foreignKey: 'sellerId', as: 'daySells' });
|
||||
|
||||
// Produkt-Preishistorie (Zeitreihe für Preiskurven)
|
||||
ProductPriceHistory.belongsTo(ProductType, { foreignKey: 'productId', as: 'productType' });
|
||||
ProductType.hasMany(ProductPriceHistory, { foreignKey: 'productId', as: 'priceHistory' });
|
||||
|
||||
ProductPriceHistory.belongsTo(RegionData, { foreignKey: 'regionId', as: 'region' });
|
||||
RegionData.hasMany(ProductPriceHistory, { foreignKey: 'regionId', as: 'productPriceHistory' });
|
||||
|
||||
Notification.belongsTo(FalukantUser, { foreignKey: 'userId', as: 'user' });
|
||||
FalukantUser.hasMany(Notification, { foreignKey: 'userId', as: 'notifications' });
|
||||
|
||||
|
||||
44
backend/models/falukant/log/product_price_history.js
Normal file
44
backend/models/falukant/log/product_price_history.js
Normal file
@@ -0,0 +1,44 @@
|
||||
import { Model, DataTypes } from 'sequelize';
|
||||
import { sequelize } from '../../../utils/sequelize.js';
|
||||
|
||||
/**
|
||||
* Preishistorie pro Produkt und Region (Zeitreihe für Preis-Graphen).
|
||||
* Aktuell wird diese Tabelle noch nicht befüllt; sie dient nur als Grundlage.
|
||||
*/
|
||||
class ProductPriceHistory extends Model { }
|
||||
|
||||
ProductPriceHistory.init({
|
||||
productId: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false
|
||||
},
|
||||
regionId: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false
|
||||
},
|
||||
price: {
|
||||
type: DataTypes.DECIMAL(12, 2),
|
||||
allowNull: false
|
||||
},
|
||||
recordedAt: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false,
|
||||
defaultValue: sequelize.literal('CURRENT_TIMESTAMP')
|
||||
}
|
||||
}, {
|
||||
sequelize,
|
||||
modelName: 'ProductPriceHistory',
|
||||
tableName: 'product_price_history',
|
||||
schema: 'falukant_log',
|
||||
timestamps: false,
|
||||
underscored: true,
|
||||
indexes: [
|
||||
{
|
||||
name: 'product_price_history_product_region_recorded_idx',
|
||||
fields: ['product_id', 'region_id', 'recorded_at']
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
export default ProductPriceHistory;
|
||||
|
||||
@@ -89,6 +89,7 @@ import Learning from './falukant/data/learning.js';
|
||||
import Credit from './falukant/data/credit.js';
|
||||
import DebtorsPrism from './falukant/data/debtors_prism.js';
|
||||
import HealthActivity from './falukant/log/health_activity.js';
|
||||
import ProductPriceHistory from './falukant/log/product_price_history.js';
|
||||
|
||||
// — Match3 Minigame —
|
||||
import Match3Campaign from './match3/campaign.js';
|
||||
@@ -239,6 +240,7 @@ const models = {
|
||||
Credit,
|
||||
DebtorsPrism,
|
||||
HealthActivity,
|
||||
ProductPriceHistory,
|
||||
RegionDistance,
|
||||
VehicleType,
|
||||
Vehicle,
|
||||
|
||||
@@ -2901,9 +2901,9 @@ class FalukantService extends BaseService {
|
||||
}
|
||||
|
||||
async getGifts(hashedUserId) {
|
||||
// 1) Mein User & Character
|
||||
// 1) Mein aktiver Falukant-User & dessen aktueller Charakter
|
||||
const user = await this.getFalukantUserByHashedId(hashedUserId);
|
||||
const myChar = await FalukantCharacter.findOne({ where: { userId: user.id } });
|
||||
const myChar = user.character;
|
||||
if (!myChar) throw new Error('Character not found');
|
||||
|
||||
// 2) Beziehung finden und „anderen“ Character bestimmen
|
||||
@@ -3520,12 +3520,10 @@ class FalukantService extends BaseService {
|
||||
|
||||
async baptise(hashedUserId, childId, firstName) {
|
||||
try {
|
||||
const falukantUser = await getFalukantUserOrFail(hashedUserId);
|
||||
const parentCharacter = await FalukantCharacter.findOne({
|
||||
where: {
|
||||
userId: falukantUser.id,
|
||||
},
|
||||
});
|
||||
// Nutze den aktuell aktiven Charakter (wie in getFalukantUserByHashedId definiert),
|
||||
// statt „irgendeinen“ Charakter des Users per userId zu suchen.
|
||||
const falukantUser = await this.getFalukantUserByHashedId(hashedUserId);
|
||||
const parentCharacter = falukantUser.character;
|
||||
if (!parentCharacter) {
|
||||
throw new Error('Parent character not found');
|
||||
}
|
||||
|
||||
@@ -539,6 +539,27 @@ const syncDatabase = async () => {
|
||||
console.warn('⚠️ relationship_change_log/Trigger konnten nicht sichergestellt werden:', e?.message || e);
|
||||
}
|
||||
|
||||
// Preishistorie für Produkte (Zeitreihe) – nur Schema/Struktur, noch ohne Logik
|
||||
console.log("Ensuring falukant_log.product_price_history exists...");
|
||||
try {
|
||||
await sequelize.query(`
|
||||
CREATE TABLE IF NOT EXISTS falukant_log.product_price_history (
|
||||
id serial PRIMARY KEY,
|
||||
product_id integer NOT NULL,
|
||||
region_id integer NOT NULL,
|
||||
price numeric(12,2) NOT NULL,
|
||||
recorded_at timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
`);
|
||||
await sequelize.query(`
|
||||
CREATE INDEX IF NOT EXISTS product_price_history_product_region_recorded_idx
|
||||
ON falukant_log.product_price_history (product_id, region_id, recorded_at);
|
||||
`);
|
||||
console.log("✅ product_price_history ist vorhanden.");
|
||||
} catch (e) {
|
||||
console.warn('⚠️ product_price_history konnte nicht sichergestellt werden:', e?.message || e);
|
||||
}
|
||||
|
||||
// Vorab: Stelle kritische Spalten sicher, damit Index-Erstellung nicht fehlschlägt
|
||||
console.log("Pre-ensure Taxi columns (traffic_light) ...");
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user