diff --git a/backend/database/seeders/benefitsProducts.ts b/backend/database/seeders/benefitsProducts.ts new file mode 100644 index 00000000..7dbbcef7 --- /dev/null +++ b/backend/database/seeders/benefitsProducts.ts @@ -0,0 +1,40 @@ +import db from '../../src/schemas'; +import { BenefitProduct } from '../../src/schemas/benefitProducts'; + +const list = [ + { + productsId: 5, + benefitsId: 1, + amount: 2 + }, + { + productsId: 6, + benefitsId: 2, + amount: 2 + }, + { + productsId: 7, + benefitsId: 2, + amount: 2 + }, + { + productsId: 8, + benefitsId: 2, + amount: 2 + } +] as BenefitProduct[]; + +/** + * Seed the benefits table + */ +const seed = async () => { + const alreadyCreated = await db.benefitProducts.findAll(); + if (alreadyCreated.length < list.length) { + await db.benefitProducts.bulkCreate(list); + console.log(`[seed] Benefits: Seeded successfully - ${list.length} new created`); + } else { + console.log(`[seed] Benefits: Nothing to seed`); + } +}; + +export default { seed, groupList: list }; diff --git a/backend/database/seeders/index.ts b/backend/database/seeders/index.ts index ee9c3ea2..7997e335 100644 --- a/backend/database/seeders/index.ts +++ b/backend/database/seeders/index.ts @@ -9,6 +9,7 @@ import families from './families'; import consumptions from './consumptions'; import dependents from './dependents'; import products from './products'; +import benefitsProducts from './benefitsProducts'; /** * Seed all tables @@ -26,6 +27,7 @@ const seedAll = async () => { await dependents.seed(); await consumptions.seed(); await products.seed(); + await benefitsProducts.seed(); } else { // Production seed - one city and admin user await cities.seed(); diff --git a/backend/src/models/benefitProducts.ts b/backend/src/models/benefitProducts.ts index d1e55db5..8ceb8f51 100644 --- a/backend/src/models/benefitProducts.ts +++ b/backend/src/models/benefitProducts.ts @@ -14,6 +14,22 @@ export const getAll = (): Promise => { }); }; +/** + * Get all products associated to benefit + * @param benefitsId unique ID of the desired benefit + * @returns Promise + */ +export const getAllProductsByBenefitId = ( + benefitsId: NonNullable +): Promise => { + return db.benefitProducts.findAll({ + where: { + benefitsId + }, + include: [{ model: db.products, as: 'products' }] + }); +}; + /** * Get a single item using the unique ID * @param id unique ID of the desired item diff --git a/backend/src/models/benefits.ts b/backend/src/models/benefits.ts index f45a2e42..e17ed369 100644 --- a/backend/src/models/benefits.ts +++ b/backend/src/models/benefits.ts @@ -11,6 +11,20 @@ export const getAll = (cityId: NonNullable): Promise + */ +export const getAllWithProduct = (cityId: NonNullable): Promise => { + return db.benefits.findAll({ + include: [ + { model: db.institutions, as: 'institution', where: { cityId } }, + { model: db.benefitProducts, as: 'benefitProduct', include: [{ model: db.products, as: 'products' }] } + ] + }); +}; + /** * Get a single item using the unique ID * @param id unique ID of the desired item @@ -30,6 +44,25 @@ export const create = (values: Benefit | SequelizeBenefit): Promise + */ +export const createWithProduct = async (values: Benefit | SequelizeBenefit): Promise => { + const created = await db.benefits.create(values); + + if (values.products && created) { + const productList = values.products.map((i) => { + i.benefitsId = created.id as number; + return i; + }); + db.benefitProducts.bulkCreate(productList); + } + + return created; +}; + /** * Function to update a row on the table by the unique ID * @param id unique ID of the desired item @@ -52,6 +85,50 @@ export const updateById = async ( return null; }; +/** + * Function to update a row on the table by the unique ID + * @param id unique ID of the desired item + * @param values object with the new data + * @param cityId logged user city ID + * @returns Promise + */ +export const updateWithProduct = async ( + id: NonNullable, + values: Benefit | SequelizeBenefit, + cityId: NonNullable +): Promise => { + // Trying to get item on the city + const cityItem = await getById(id, cityId); + if (cityItem) { + // The update return an array [count, item[]], so I'm destructuring to get the updated benefit + const [, [updated]] = await db.benefits.update(values, { where: { id }, returning: true }); + const updatedProducts = await db.benefitProducts.findAll({ where: { benefitsId: updated.id as number } }); + + if (values.products) { + const list = values.products.map((i) => { + i.benefitsId = updated.id as number; + return i; + }); + const productToUpdate = list.filter((f) => f.id); + const productToAdd = list.filter((f) => !f.id); + const productToRemove = updatedProducts.filter((a) => { + const index = productToUpdate.find((f) => f.id === a.id); + if (!index) return a; + }); + + await db.benefitProducts.bulkCreate(productToAdd); + + productToRemove.map(async (dt) => { + await db.benefitProducts.destroy({ where: { id: dt.id } }); + }); + productToUpdate.map(async (up) => { + await db.benefitProducts.update({ amount: up.amount }, { where: { id: up.id } }); + }); + } + } + return null; +}; + /** * Function to delete a row on the table by the unique ID * @param id unique ID of the desired item diff --git a/backend/src/routes/benefits.ts b/backend/src/routes/benefits.ts index 0adac76c..8a0febed 100644 --- a/backend/src/routes/benefits.ts +++ b/backend/src/routes/benefits.ts @@ -10,7 +10,7 @@ const router = express.Router({ mergeParams: true }); router.get('/', async (req, res) => { try { if (!req.user?.cityId) throw Error('User without selected city'); - const items = await benefitModel.getAll(req.user.cityId); + const items = await benefitModel.getAllWithProduct(req.user.cityId); res.send(items); } catch (error) { logging.error(error); @@ -41,7 +41,9 @@ router.get('/:id', async (req, res) => { router.post('/', async (req, res) => { try { if (!req.user?.cityId) throw Error('User without selected city'); - const item = await benefitModel.create(req.body); + let item; + if (req.body.value) item = await benefitModel.create(req.body); + else item = await benefitModel.createWithProduct(req.body); res.send(item); } catch (error) { logging.error(error); @@ -55,7 +57,9 @@ router.post('/', async (req, res) => { router.put('/:id', async (req, res) => { try { if (!req.user?.cityId) throw Error('User without selected city'); - const item = await benefitModel.updateById(req.params.id, req.body, req.user.cityId); + let item; + if (req.body.value) item = await benefitModel.updateById(req.params.id, req.body, req.user.cityId); + else item = await benefitModel.updateWithProduct(req.params.id, req.body, req.user.cityId); res.send(item); } catch (error) { logging.error(error); diff --git a/backend/src/schemas/benefitProducts.ts b/backend/src/schemas/benefitProducts.ts index 6ad965b1..60b66e40 100644 --- a/backend/src/schemas/benefitProducts.ts +++ b/backend/src/schemas/benefitProducts.ts @@ -3,8 +3,8 @@ import { Sequelize, Model, DataTypes, BuildOptions, ModelCtor } from 'sequelize' // Simple item type export interface BenefitProduct { readonly id?: number | string; - productId: number | string; - benefitId: number | string; + productsId: number | string; + benefitsId: number | string; amount: number; createdAt?: number | Date | null; updatedAt?: number | Date | null; @@ -49,7 +49,7 @@ export const attributes = { } }; -const tableName = 'Benefits'; +const tableName = 'BenefitProducts'; /** * Sequelize model initializer function diff --git a/backend/src/schemas/benefits.ts b/backend/src/schemas/benefits.ts index b0493adf..2f48223f 100644 --- a/backend/src/schemas/benefits.ts +++ b/backend/src/schemas/benefits.ts @@ -1,4 +1,5 @@ import { Sequelize, Model, DataTypes, BuildOptions, ModelCtor } from 'sequelize'; +import { BenefitProduct } from './benefitProducts'; // Simple item type export interface Benefit { @@ -8,6 +9,7 @@ export interface Benefit { title: string; month: number; year: number; + products?: BenefitProduct[]; value?: number; createdAt?: number | Date | null; updatedAt?: number | Date | null; @@ -76,6 +78,10 @@ export const initBenefitSchema = (sequelize: Sequelize): SequelizeBenefitModel = foreignKey: 'institutionId', as: 'institution' }); + Schema.hasMany(models.benefitProducts, { + foreignKey: 'benefitsId', + as: 'benefitProduct' + }); }; return Schema; diff --git a/backend/src/schemas/products.ts b/backend/src/schemas/products.ts index 63364cba..b2ab6502 100644 --- a/backend/src/schemas/products.ts +++ b/backend/src/schemas/products.ts @@ -62,5 +62,13 @@ export const initProductSchema = (sequelize: Sequelize): SequelizeProductModel = // Sequelize relations // Schema.associate = (models): void => {}; + Schema.associate = (models): void => { + // Sequelize relations + Schema.hasMany(models.benefitProducts, { + foreignKey: 'productsId', + as: 'benefitProduct' + }); + }; + return Schema; };