diff --git a/.adonisjs/client/data.d.ts b/.adonisjs/client/data.d.ts index 3568d52..ee014a4 100644 --- a/.adonisjs/client/data.d.ts +++ b/.adonisjs/client/data.d.ts @@ -1,3 +1,8 @@ +/** + * This file is automatically generated. + * DO NOT EDIT manually + */ + /// import type { InferData, InferVariants } from '@adonisjs/core/types/transformers' import type UserTransformer from '#transformers/user_transformer' diff --git a/.adonisjs/client/manifest.d.ts b/.adonisjs/client/manifest.d.ts index 5845626..158e306 100644 --- a/.adonisjs/client/manifest.d.ts +++ b/.adonisjs/client/manifest.d.ts @@ -1,4 +1,10 @@ +/** + * This file is automatically generated. + * DO NOT EDIT manually + */ + /// /// /// +/// /// diff --git a/.adonisjs/server/controllers.ts b/.adonisjs/server/controllers.ts index f7f61b6..9abefc8 100644 --- a/.adonisjs/server/controllers.ts +++ b/.adonisjs/server/controllers.ts @@ -1,5 +1,23 @@ +/** + * This file is automatically generated. + * DO NOT EDIT manually + */ + export const controllers = { AccessToken: () => import('#controllers/access_token_controller'), + Categories: () => import('#controllers/categories_controller'), + FastPasses: () => import('#controllers/fast_passes_controller'), + Furnitures: () => import('#controllers/furnitures_controller'), + Goods: () => import('#controllers/goods_controller'), + Logs: () => import('#controllers/logs_controller'), + Members: () => import('#controllers/members_controller'), NewAccount: () => import('#controllers/new_account_controller'), + Permissions: () => import('#controllers/permissions_controller'), + Products: () => import('#controllers/products_controller'), Profile: () => import('#controllers/profile_controller'), + Restocks: () => import('#controllers/restocks_controller'), + Roles: () => import('#controllers/roles_controller'), + StockBatches: () => import('#controllers/stock_batches_controller'), + StockMovements: () => import('#controllers/stock_movements_controller'), + Suppliers: () => import('#controllers/suppliers_controller'), } diff --git a/.adonisjs/server/events.ts b/.adonisjs/server/events.ts index a7ab473..a74e59b 100644 --- a/.adonisjs/server/events.ts +++ b/.adonisjs/server/events.ts @@ -1 +1,6 @@ +/** + * This file is automatically generated. + * DO NOT EDIT manually + */ + export const events = {} diff --git a/.adonisjs/server/listeners.ts b/.adonisjs/server/listeners.ts index 28cbf66..05f35f8 100644 --- a/.adonisjs/server/listeners.ts +++ b/.adonisjs/server/listeners.ts @@ -1 +1,6 @@ +/** + * This file is automatically generated. + * DO NOT EDIT manually + */ + export const listeners = {} diff --git a/app/controllers/categories_controller.ts b/app/controllers/categories_controller.ts new file mode 100644 index 0000000..dd94e08 --- /dev/null +++ b/app/controllers/categories_controller.ts @@ -0,0 +1,44 @@ +import type { HttpContext } from '@adonisjs/core/http' +import Category from '#models/category' + +export default class CategoriesController { + /** + * Display a list of resource + */ + async index({}: HttpContext) { + return Category.all() + } + + /** + * Handle form submission for the create action + */ + async store({ request }: HttpContext) { + const data = request.all() + return Category.create(data) + } + + /** + * Show individual record + */ + async show({ params }: HttpContext) { + return Category.findOrFail(params.id) + } + + /** + * Handle form submission for the edit action + */ + async update({ params, request }: HttpContext) { + const category = await Category.findOrFail(params.id) + const data = request.all() + category.merge(data) + return category.save() + } + + /** + * Delete record + */ + async destroy({ params }: HttpContext) { + const category = await Category.findOrFail(params.id) + return category.delete() + } +} diff --git a/app/controllers/fast_passes_controller.ts b/app/controllers/fast_passes_controller.ts new file mode 100644 index 0000000..9ec8b47 --- /dev/null +++ b/app/controllers/fast_passes_controller.ts @@ -0,0 +1,54 @@ +import type { HttpContext } from '@adonisjs/core/http' +import FastPass from '#models/fast_pass' + +export default class FastPassesController { + /** + * Display a list of resource + */ + async index({}: HttpContext) { + return FastPass.query() + } + + /** + * Handle form submission for the create action + */ + async store({ request }: HttpContext) { + const { price, duration, description, label } = request.all() + const fastPass = new FastPass() + fastPass.price = price + fastPass.duration = duration + fastPass.description = description + fastPass.label = label + await fastPass.save() + return fastPass + } + + /** + * Show individual record + */ + async show({ params }: HttpContext) { + return FastPass.query().where('id', params.id).firstOrFail() + } + + /** + * Handle form submission for the edit action + */ + async update({ params, request }: HttpContext) { + const fastPass = await FastPass.query().where('id', params.id).firstOrFail() // We get our fast pass by id + const { price, duration, description, label } = request.all() // We transfer the new data from the request to constants + fastPass.price = price // Assigning the data + fastPass.duration = duration + fastPass.description = description + fastPass.label = label + await fastPass.save() // We save the fast pass to the database + return fastPass + } + + /** + * Delete record + */ + async destroy({ params }: HttpContext) { + const fastPass = await FastPass.query().where('id', params.id).firstOrFail() + await fastPass.delete() + } +} diff --git a/app/controllers/furnitures_controller.ts b/app/controllers/furnitures_controller.ts new file mode 100644 index 0000000..76a68c6 --- /dev/null +++ b/app/controllers/furnitures_controller.ts @@ -0,0 +1,44 @@ +import type { HttpContext } from '@adonisjs/core/http' +import Furniture from '#models/furniture' + +export default class FurnituresController { + /** + * Display a list of resource + */ + async index({}: HttpContext) { + return Furniture.all() + } + + /** + * Handle form submission for the create action + */ + async store({ request }: HttpContext) { + const { name, quantity, price } = request.all() + return Furniture.create({ name, quantity, price }) + } + + /** + * Show individual record + */ + async show({ params }: HttpContext) { + return Furniture.findOrFail(params.id) + } + + /** + * Handle form submission for the edit action + */ + async update({ params, request }: HttpContext) { + const furniture = await Furniture.findOrFail(params.id) + const { name, quantity, price } = request.all() + furniture.merge({ name, quantity, price }) + return furniture.save() + } + + /** + * Delete record + */ + async destroy({ params }: HttpContext) { + const furniture = await Furniture.findOrFail(params.id) + return furniture.delete() + } +} diff --git a/app/controllers/goods_controller.ts b/app/controllers/goods_controller.ts new file mode 100644 index 0000000..e8cff66 --- /dev/null +++ b/app/controllers/goods_controller.ts @@ -0,0 +1,69 @@ +import type { HttpContext } from '@adonisjs/core/http' +import Good from '#models/good' + +export default class GoodsController { + /** + * Display a list of resource + */ + async index({}: HttpContext) { + return Good.query().preload('products').preload('category').preload('suppliers') + } + + /** + * Handle form submission for the create action + */ + async store({ request }: HttpContext) { + const { name, unit, brand, categoryId } = request.all() + const good = new Good() + good.name = name + good.unit = unit + good.brand = brand + good.categoryId = categoryId + await good.save() + return good + } + + /** + * Show individual record + */ + async show({ params }: HttpContext) { + return await Good.query() + .preload('products') + .preload('category') + .preload('suppliers') + .where('id', params.id) + .firstOrFail() + } + + /** + * Handle form submission for the edit action + */ + async update({ params, request }: HttpContext) { + const good = await Good.query() + .preload('products') + .preload('category') + .preload('suppliers') + .where('id', params.id) + .firstOrFail() // We get our good by id + const { name, unit, brand, categoryId } = request.all() + good.name = name + good.unit = unit + good.brand = brand + good.categoryId = categoryId + await good.save() + return good + } + + /** + * Delete record + */ + async destroy({ params }: HttpContext) { + const good = await Good.query() + .preload('products') + .preload('category') + .preload('suppliers') + .where('id', params.id) + .firstOrFail() + await good.delete() + } +} diff --git a/app/controllers/logs_controller.ts b/app/controllers/logs_controller.ts new file mode 100644 index 0000000..232e372 --- /dev/null +++ b/app/controllers/logs_controller.ts @@ -0,0 +1,62 @@ +import type { HttpContext } from '@adonisjs/core/http' +import Log from '#models/log' + +export default class LogsController { + /** + * Display a list of resource + */ + async index({}: HttpContext) { + const logs = await Log.query().preload('user') + return logs + } + + /** + * Handle form submission for the create action + */ + async store({ request }: HttpContext) { + const { level, message, method, url, ip, meta, userId } = request.all() + const log = await Log.create({ + level, + message, + method, + url, + ip, + meta, + userId, + }) + return log + } + + /** + * Show individual record + */ + async show({ params }: HttpContext) { + const log = await Log.query().where('id', params.id).preload('user').firstOrFail() + return log + } + + /** + * Handle form submission for the edit action + */ + async update({ params, request }: HttpContext) { + const log = await Log.query().where('id', params.id).firstOrFail() + const { level, message, method, url, ip, meta, userId } = request.all() + log.level = level + log.message = message + log.method = method + log.url = url + log.ip = ip + log.meta = meta + log.userId = userId + await log.save() + return log + } + + /** + * Delete record + */ + async destroy({ params }: HttpContext) { + const log = await Log.query().where('id', params.id).preload('user').firstOrFail() + await log.delete() + } +} diff --git a/app/controllers/members_controller.ts b/app/controllers/members_controller.ts new file mode 100644 index 0000000..246b0bd --- /dev/null +++ b/app/controllers/members_controller.ts @@ -0,0 +1,61 @@ +import type { HttpContext } from '@adonisjs/core/http' +import Member from '#models/member' + +export default class MembersController { + /** + * Display a list of resource + */ + async index({}: HttpContext) { + const members = await Member.query().preload('role') + return members + } + + /** + * Handle form submission for the create action + */ + async store({ request }: HttpContext) { + const { firstName, lastName } = request.all() + const member = new Member() + member.firstName = firstName + member.lastName = lastName + await member.save() + return member + } + + /** + * Show individual record + */ + async show({ params }: HttpContext) { + const member = await Member.query().preload('role').where('id', params.id).first() + if (!member) { + throw new Error('Member not found') + } + return member + } + + /** + * Handle form submission for the edit action + */ + async update({ params, request }: HttpContext) { + const member = await Member.query().preload('role').where('id', params.id).first() + if (!member) { + throw new Error('Member not found') + } + const { firstName, lastName } = request.all() + member.firstName = firstName + member.lastName = lastName + await member.save() + return member + } + + /** + * Delete record + */ + async destroy({ params }: HttpContext) { + const member = await Member.query().preload('role').where('id', params.id).first() + if (!member) { + throw new Error('Member not found') + } + await member.delete() + } +} diff --git a/app/controllers/permissions_controller.ts b/app/controllers/permissions_controller.ts new file mode 100644 index 0000000..6dc1aad --- /dev/null +++ b/app/controllers/permissions_controller.ts @@ -0,0 +1,49 @@ +import type { HttpContext } from '@adonisjs/core/http' +import Permission from '#models/permission' + +export default class PermissionsController { + /** + * Display a list of resource + */ + async index({}: HttpContext) { + const permissions = await Permission.all() + return permissions + } + + /** + * Handle form submission for the create action + */ + async store({ request }: HttpContext) { + const { permission } = request.all() + const newPermission = await Permission.create({ permission }) + return newPermission + } + + /** + * Show individual record + */ + async show({ params }: HttpContext) { + const permission = await Permission.findOrFail(params.id) + return permission + } + + /** + * Handle form submission for the edit action + */ + async update({ params, request }: HttpContext) { + const permission = await Permission.findOrFail(params.id) + const { permission: newPermission } = request.all() + permission.permission = newPermission + await permission.save() + return permission + } + + /** + * Delete record + */ + async destroy({ params }: HttpContext) { + const permission = await Permission.findOrFail(params.id) + await permission.delete() + return { message: 'Permission deleted successfully' } + } +} diff --git a/app/controllers/products_controller.ts b/app/controllers/products_controller.ts new file mode 100644 index 0000000..215c49e --- /dev/null +++ b/app/controllers/products_controller.ts @@ -0,0 +1,66 @@ +import type { HttpContext } from '@adonisjs/core/http' +import Product from '#models/product' + +export default class ProductsController { + /** + * Display a list of resource + */ + async index({}: HttpContext) { + return Product.query().preload('furnitures').preload('goods') + } + + /** + * Handle form submission for the create action + */ + async store({ request }: HttpContext) { + const { name, isVegetarian, description, recipe } = request.all() + const product = new Product() + product.name = name + product.isVegetarian = isVegetarian + product.description = description + product.recipe = recipe + await product.save() + return product + } + + /** + * Show individual record + */ + async show({ params }: HttpContext) { + return await Product.query() + .preload('furnitures') + .preload('goods') + .where('id', params.id) + .firstOrFail() + } + + /** + * Handle form submission for the edit action + */ + async update({ params, request }: HttpContext) { + const product = await Product.query() + .preload('furnitures') + .preload('goods') + .where('id', params.id) + .firstOrFail() // We get our product by id + const { name, isVegetarian, description, recipe } = request.all() // We transfer the new data from the request to constants + product.name = name // Assigning the data + product.isVegetarian = isVegetarian // Assigning the data + product.description = description // Assigning the data + product.recipe = recipe // Assigning the data + await product.save() // We save the product to the database + return product + } + + /** + * Delete record + */ + async destroy({ params }: HttpContext) { + const product = await Product.query() + .preload('furnitures') + .preload('goods') + .where('id', params.id) + .firstOrFail() // Get the product by id + await product.delete() + } +} diff --git a/app/controllers/restocks_controller.ts b/app/controllers/restocks_controller.ts new file mode 100644 index 0000000..cc6c6f1 --- /dev/null +++ b/app/controllers/restocks_controller.ts @@ -0,0 +1,72 @@ +import type { HttpContext } from '@adonisjs/core/http' +import Restock from '#models/restock' + +export default class RestocksController { + /** + * Display a list of resource + */ + async index({}: HttpContext) { + const restocks = await Restock.query() + .preload('member') + .preload('supplier') + .preload('stockBatches') + return restocks + } + + /** + * Handle form submission for the create action + */ + async store({ request }: HttpContext) { + const { memberId, supplierId, totalPrice } = request.all() + const restock = new Restock() + restock.memberId = memberId + restock.supplierId = supplierId + restock.totalPrice = totalPrice + await restock.save() + return restock + } + + /** + * Show individual record + */ + async show({ params }: HttpContext) { + const restock = await Restock.query() + .preload('member') + .preload('supplier') + .preload('stockBatches') + .where('id', params.id) + .firstOrFail() + return restock + } + + /** + * Handle form submission for the edit action + */ + async update({ params, request }: HttpContext) { + const restock = await Restock.query() + .preload('member') + .preload('supplier') + .preload('stockBatches') + .where('id', params.id) + .firstOrFail() + const { memberId, supplierId, totalPrice } = request.all() + restock.memberId = memberId + restock.supplierId = supplierId + restock.totalPrice = totalPrice + await restock.save() + return restock + } + + /** + * Delete record + */ + async destroy({ params }: HttpContext) { + const restock = await Restock.query() + .preload('member') + .preload('supplier') + .preload('stockBatches') + .where('id', params.id) + .firstOrFail() + await restock.delete() + } +} diff --git a/app/controllers/roles_controller.ts b/app/controllers/roles_controller.ts new file mode 100644 index 0000000..a7c9659 --- /dev/null +++ b/app/controllers/roles_controller.ts @@ -0,0 +1,54 @@ +import type { HttpContext } from '@adonisjs/core/http' +import Role from '#models/role' + +export default class RolesController { + /** + * Display a list of resource + */ + async index({}: HttpContext) { + const roles = await Role.query() + return roles + } + + /** + * Handle form submission for the create action + */ + async store({ request }: HttpContext) { + const { name } = request.all() + const role = await Role.create({ name }) + return role + } + + /** + * Show individual record + */ + async show({ params }: HttpContext) { + const role = await Role.findOrFail(params.id) + return role + } + + /** + * Handle form submission for the edit action + */ + async update({ params, request }: HttpContext) { + const { name } = request.body() + const role = await Role.find(params.id) + if (!role) { + throw new Error('Role not found') + } + role.name = name + await role.save() + return role + } + + /** + * Delete record + */ + async destroy({ params }: HttpContext) { + const role = await Role.find(params.id) + if (!role) { + throw new Error('Role not found') + } + await role.delete() + } +} diff --git a/app/controllers/stock_batches_controller.ts b/app/controllers/stock_batches_controller.ts new file mode 100644 index 0000000..1576bdb --- /dev/null +++ b/app/controllers/stock_batches_controller.ts @@ -0,0 +1,73 @@ +import type { HttpContext } from '@adonisjs/core/http' +import StockBatch from '#models/stock_batch' + +export default class StockBatchesController { + /** + * Display a list of resource + */ + async index({}: HttpContext) { + const stockBatches = await StockBatch.query().preload('good').preload('restock') + return stockBatches + } + + /** + * Handle form submission for the create action + */ + async store({ request }: HttpContext) { + const { expirationDate, label, quantity, restockId, goodId } = request.all() + const stockBatch = await StockBatch.create({ + expirationDate, + label, + quantity, + restockId, + goodId, + }) + return stockBatch + } + + /** + * Show individual record + */ + async show({ params }: HttpContext) { + const stockBatch = await StockBatch.query() + .where('id', params.id) + .preload('good') + .preload('restock') + .firstOrFail() + return stockBatch + } + + /** + * Handle form submission for the edit action + */ + async update({ params, request }: HttpContext) { + const stockBatch = await StockBatch.query() + .where('id', params.id) + .preload('good') + .preload('restock') + .firstOrFail() + const { expirationDate, label, quantity, restockId, goodId } = request.all() + await stockBatch + .merge({ + expirationDate, + label, + quantity, + restockId, + goodId, + }) + .save() + return stockBatch + } + + /** + * Delete record + */ + async destroy({ params }: HttpContext) { + const stockBatch = await StockBatch.query() + .where('id', params.id) + .preload('good') + .preload('restock') + .firstOrFail() + await stockBatch.delete() + } +} diff --git a/app/controllers/stock_movements_controller.ts b/app/controllers/stock_movements_controller.ts new file mode 100644 index 0000000..3683a2a --- /dev/null +++ b/app/controllers/stock_movements_controller.ts @@ -0,0 +1,71 @@ +import type { HttpContext } from '@adonisjs/core/http' +import StockMovement from '#models/stock_movement' + +export default class StockMovementsController { + /** + * Display a list of resource + */ + async index({}: HttpContext) { + const stockMovements = await StockMovement.query().preload('good').preload('stockBatch') + return stockMovements + } + + /** + * Handle form submission for the create action + */ + async store({ request }: HttpContext) { + const { quantity, movementType, goodId, stockBatchId } = request.all() + const stockMovement = await StockMovement.create({ + quantity, + movementType, + goodId, + stockBatchId, + }) + return stockMovement + } + + /** + * Show individual record + */ + async show({ params }: HttpContext) { + const stockMovement = await StockMovement.query() + .where('id', params.id) + .preload('good') + .preload('stockBatch') + .firstOrFail() + + return stockMovement + } + + /** + * Handle form submission for the edit action + */ + async update({ params, request }: HttpContext) { + const stockMovement = await StockMovement.query() + .where('id', params.id) + .preload('good') + .preload('stockBatch') + .firstOrFail() + const { quantity, movementType, goodId, stockBatchId } = request.all() + + stockMovement.quantity = quantity + stockMovement.movementType = movementType + stockMovement.goodId = goodId + stockMovement.stockBatchId = stockBatchId + + await stockMovement.save() + return stockMovement + } + + /** + * Delete record + */ + async destroy({ params }: HttpContext) { + const stockMovement = await StockMovement.query() + .where('id', params.id) + .preload('good') + .preload('stockBatch') + .firstOrFail() + await stockMovement.delete() + } +} diff --git a/app/controllers/suppliers_controller.ts b/app/controllers/suppliers_controller.ts new file mode 100644 index 0000000..5b3f3e7 --- /dev/null +++ b/app/controllers/suppliers_controller.ts @@ -0,0 +1,60 @@ +import type { HttpContext } from '@adonisjs/core/http' +import Supplier from '#models/supplier' + +export default class SuppliersController { + /** + * Display a list of resource + */ + async index({}: HttpContext) { + return Supplier.query().preload('goods').preload('restocks') + } + + /** + * Handle form submission for the create action + */ + async store({ request }: HttpContext) { + const { name } = request.all() + const supplier = new Supplier() + supplier.name = name + await supplier.save() + return supplier + } + + /** + * Show individual record + */ + async show({ params }: HttpContext) { + return await Supplier.query() + .preload('goods') + .preload('restocks') + .where('id', params.id) + .firstOrFail() + } + + /** + * Handle form submission for the edit action + */ + async update({ params, request }: HttpContext) { + const supplier = await Supplier.query() + .preload('goods') + .preload('restocks') + .where('id', params.id) + .firstOrFail() // We get our supplier by id + const { name } = request.all() // We transfer the new data from the request to constants + supplier.name = name // Assigning the data + await supplier.save() // We save the supplier to the database + return supplier + } + + /** + * Delete record + */ + async destroy({ params }: HttpContext) { + const supplier = await Supplier.query() + .preload('goods') + .preload('restocks') + .where('id', params.id) + .firstOrFail() // Get the supplier by id + await supplier.delete() + } +} diff --git a/app/models/fast_pass.ts b/app/models/fast_pass.ts index 96dc7ae..e30557d 100644 --- a/app/models/fast_pass.ts +++ b/app/models/fast_pass.ts @@ -1,9 +1,9 @@ import { FastPassSchema } from '#database/schema' -import { belongsTo } from '@adonisjs/lucid/orm' +import { manyToMany } from '@adonisjs/lucid/orm' import User from '#models/user' -import type { BelongsTo } from '@adonisjs/lucid/types/relations' +import type { ManyToMany } from '@adonisjs/lucid/types/relations' export default class FastPass extends FastPassSchema { - @belongsTo(() => User) - declare user: BelongsTo + @manyToMany(() => User) + declare user: ManyToMany } diff --git a/app/models/member.ts b/app/models/member.ts index 61f5c9a..99c86d2 100644 --- a/app/models/member.ts +++ b/app/models/member.ts @@ -10,7 +10,9 @@ import Restock from '#models/restock' import Role from '#models/role' export default class Member extends MemberSchema { - @belongsTo(() => User) + public static selfAssignPrimaryKey = true + + @belongsTo(() => User, { foreignKey: 'id' }) declare user: BelongsTo @hasMany(() => Order) diff --git a/app/models/permission.ts b/app/models/permission.ts index 5a8a820..a12f3bd 100644 --- a/app/models/permission.ts +++ b/app/models/permission.ts @@ -4,8 +4,19 @@ import Role from '#models/role' import type { ManyToMany } from '@adonisjs/lucid/types/relations' export default class Permission extends PermissionSchema { + public static primaryKey = 'permission' + public static selfAssignPrimaryKey = true + @manyToMany(() => Role, { pivotTable: 'roles_permissions', + pivotForeignKey: 'permission_id', + pivotRelatedForeignKey: 'role_id', + localKey: 'permission', + relatedKey: 'id', + pivotTimestamps: { + createdAt: 'created_at', + updatedAt: false, + }, }) declare roles: ManyToMany } diff --git a/app/models/role.ts b/app/models/role.ts index 72549b4..5541888 100644 --- a/app/models/role.ts +++ b/app/models/role.ts @@ -7,6 +7,14 @@ import Member from '#models/member' export default class Role extends RoleSchema { @manyToMany(() => Permission, { pivotTable: 'roles_permissions', + pivotForeignKey: 'role_id', + pivotRelatedForeignKey: 'permission_id', + localKey: 'id', + relatedKey: 'permission', + pivotTimestamps: { + createdAt: 'created_at', + updatedAt: false, + }, }) declare permissions: ManyToMany diff --git a/app/models/user.ts b/app/models/user.ts index f47980f..65c55da 100644 --- a/app/models/user.ts +++ b/app/models/user.ts @@ -19,10 +19,14 @@ export default class User extends compose(UserSchema, withAuthFinder(hash)) { @manyToMany(() => FastPass, { pivotTable: 'subscriptions', + pivotForeignKey: 'user_id', + pivotRelatedForeignKey: 'fast_pass_id', + pivotColumns: ['subscribed_at'], + pivotTimestamps: true, }) declare fastPasses: ManyToMany - @hasOne(() => Member) + @hasOne(() => Member, { foreignKey: 'id', localKey: 'id' }) declare member: HasOne @hasMany(() => PreOrder) diff --git a/database/factories/category_factory.ts b/database/factories/category_factory.ts new file mode 100644 index 0000000..e0f1e4d --- /dev/null +++ b/database/factories/category_factory.ts @@ -0,0 +1,10 @@ +import factory from '@adonisjs/lucid/factories' +import Category from '#models/category' + +export const CategoryFactory = factory + .define(Category, async ({ faker }) => { + return { + name: faker.commerce.department(), + } + }) + .build() diff --git a/database/factories/event_factory.ts b/database/factories/event_factory.ts new file mode 100644 index 0000000..6e3f100 --- /dev/null +++ b/database/factories/event_factory.ts @@ -0,0 +1,14 @@ +import factory from '@adonisjs/lucid/factories' +import Event from '#models/event' +import { DateTime } from 'luxon' + +export const EventFactory = factory + .define(Event, async ({ faker }) => { + return { + name: faker.company.catchPhrase(), + description: faker.lorem.paragraph(), + date: DateTime.fromJSDate(faker.date.future()), + status: faker.helpers.arrayElement(['scheduled', 'ongoing', 'completed']), + } + }) + .build() diff --git a/database/factories/fast_pass_factory.ts b/database/factories/fast_pass_factory.ts new file mode 100644 index 0000000..a81c624 --- /dev/null +++ b/database/factories/fast_pass_factory.ts @@ -0,0 +1,13 @@ +import factory from '@adonisjs/lucid/factories' +import FastPass from '#models/fast_pass' + +export const FastPassFactory = factory + .define(FastPass, async ({ faker }) => { + return { + label: faker.helpers.arrayElement(['1 year', '2 year', '3 year']), + description: faker.lorem.sentence(), + price: faker.number.int({ min: 10, max: 100 }), + duration: faker.number.int({ min: 1, max: 12 }), + } + }) + .build() diff --git a/database/factories/furniture_factory.ts b/database/factories/furniture_factory.ts new file mode 100644 index 0000000..7636c13 --- /dev/null +++ b/database/factories/furniture_factory.ts @@ -0,0 +1,12 @@ +import factory from '@adonisjs/lucid/factories' +import Furniture from '#models/furniture' + +export const FurnitureFactory = factory + .define(Furniture, async ({ faker }) => { + return { + name: faker.commerce.productName(), + quantity: faker.number.int({ min: 1, max: 100 }), + price: faker.commerce.price(), + } + }) + .build() diff --git a/database/factories/good_factory.ts b/database/factories/good_factory.ts new file mode 100644 index 0000000..c8ebcd0 --- /dev/null +++ b/database/factories/good_factory.ts @@ -0,0 +1,15 @@ +import factory from '@adonisjs/lucid/factories' +import Good from '#models/good' +import { CategoryFactory } from './category_factory.js' + +export const GoodFactory = factory + .define(Good, async ({ faker }) => { + return { + name: faker.commerce.productName(), + unit: faker.helpers.arrayElement(['pcs', 'kg', 'liter']), + brand: faker.company.name(), + categoryId: null, // Will be set by relation + } + }) + .relation('category', () => CategoryFactory) + .build() diff --git a/database/factories/job_factory.ts b/database/factories/job_factory.ts new file mode 100644 index 0000000..30f82cb --- /dev/null +++ b/database/factories/job_factory.ts @@ -0,0 +1,11 @@ +import factory from '@adonisjs/lucid/factories' +import Job from '#models/job' + +export const JobFactory = factory + .define(Job, async ({ faker }) => { + return { + name: faker.person.jobTitle(), + description: faker.lorem.paragraph(), + } + }) + .build() diff --git a/database/factories/log_factory.ts b/database/factories/log_factory.ts new file mode 100644 index 0000000..8a0d407 --- /dev/null +++ b/database/factories/log_factory.ts @@ -0,0 +1,21 @@ +import factory from '@adonisjs/lucid/factories' +import Log from '#models/log' +import { UserFactory } from './user_factory.ts' + +export const LogFactory = factory + .define(Log, async ({ faker }) => { + return { + level: faker.helpers.arrayElement(['info', 'warning', 'error']), + message: faker.lorem.sentence(), + method: faker.helpers.arrayElement(['GET', 'POST', 'PUT', 'DELETE']), + url: faker.internet.url(), + ip: faker.internet.ip(), + meta: { + userAgent: faker.internet.userAgent(), + referrer: faker.internet.url(), + }, + userId: null, // Will be set by relation if needed + } + }) + .relation('user', () => UserFactory) + .build() diff --git a/database/factories/member_event_assigned_job_factory.ts b/database/factories/member_event_assigned_job_factory.ts new file mode 100644 index 0000000..111892f --- /dev/null +++ b/database/factories/member_event_assigned_job_factory.ts @@ -0,0 +1,14 @@ +import factory from '@adonisjs/lucid/factories' +import MemberEventAssignedJob from '#models/member_event_assigned_job' +import { MemberFactory } from '#database/factories/members_factory' +import { EventFactory } from '#database/factories/event_factory' +import { JobFactory } from '#database/factories/job_factory' + +export const MemberEventAssignedJobFactory = factory + .define(MemberEventAssignedJob, async () => { + return {} + }) + .relation('member', () => MemberFactory) + .relation('event', () => EventFactory) + .relation('job', () => JobFactory) + .build() diff --git a/database/factories/members_factory.ts b/database/factories/members_factory.ts new file mode 100644 index 0000000..74d662e --- /dev/null +++ b/database/factories/members_factory.ts @@ -0,0 +1,32 @@ +import factory from '@adonisjs/lucid/factories' +import Member from '#models/member' +import { UserFactory } from '#database/factories/user_factory' +import { RoleFactory } from '#database/factories/role_factory' + +export const MemberFactory = factory + .define(Member, async ({ faker }) => { + return { + firstName: faker.person.firstName(), + lastName: faker.person.lastName(), + roleId: null, + } + }) + .before('create', async (builder, member, ctx) => { + const requestedBelongsTo = (builder as any).withBelongsToRelations as + | undefined + | Array<{ name: string }> + const willCreateUserViaRelation = requestedBelongsTo?.some( + (relation) => relation.name === 'user' + ) + + if (willCreateUserViaRelation) { + return + } + + const user = await UserFactory.useCtx(ctx).create() + member.id = user.id + member.$setRelated('user', user) + }) + .relation('user', () => UserFactory) + .relation('role', () => RoleFactory) + .build() diff --git a/database/factories/order_factory.ts b/database/factories/order_factory.ts new file mode 100644 index 0000000..1cb7237 --- /dev/null +++ b/database/factories/order_factory.ts @@ -0,0 +1,16 @@ +import factory from '@adonisjs/lucid/factories' +import Order from '#models/order' +import { MemberFactory } from '#database/factories/members_factory' +import { EventFactory } from '#database/factories/event_factory' +import { TransactionFactory } from '#database/factories/transaction_factory' + +export const OrderFactory = factory + .define(Order, async ({ faker }) => { + return { + status: faker.helpers.arrayElement(['pending', 'completed', 'cancelled']), + } + }) + .relation('takenBy', () => MemberFactory) + .relation('event', () => EventFactory) + .relation('transaction', () => TransactionFactory) + .build() diff --git a/database/factories/permission_factory.ts b/database/factories/permission_factory.ts new file mode 100644 index 0000000..0bf7611 --- /dev/null +++ b/database/factories/permission_factory.ts @@ -0,0 +1,37 @@ +import factory from '@adonisjs/lucid/factories' +import Permission from '#models/permission' + +const permissions = [ + 'presence:write', + 'presence:read', + 'stock:read', + 'stock:update', + 'stock:create', + 'stock:delete', + 'product:read', + 'product:update', + 'product:create', + 'product:delete', + 'supplier:read', + 'supplier:update', + 'supplier:create', + 'supplier:delete', + 'restock:read', + 'restock:update', + 'restock:create', + 'restock:delete', +] + +let permissionIndex = 0 + +export const PermissionFactory = factory + .define(Permission, async () => { + if (permissionIndex >= permissions.length) { + throw new Error('Plus de permissions disponibles (unicité garantie)') + } + + return { + permission: permissions[permissionIndex++], + } + }) + .build() diff --git a/database/factories/pre_order_factory.ts b/database/factories/pre_order_factory.ts new file mode 100644 index 0000000..4cf873a --- /dev/null +++ b/database/factories/pre_order_factory.ts @@ -0,0 +1,14 @@ +import factory from '@adonisjs/lucid/factories' +import PreOrder from '#models/pre_order' +import { UserFactory } from '#database/factories/user_factory' +import { EventFactory } from '#database/factories/event_factory' +import { TransactionFactory } from '#database/factories/transaction_factory' + +export const PreOrderFactory = factory + .define(PreOrder, async () => { + return {} + }) + .relation('user', () => UserFactory) + .relation('event', () => EventFactory) + .relation('transaction', () => TransactionFactory) + .build() diff --git a/database/factories/product_factory.ts b/database/factories/product_factory.ts new file mode 100644 index 0000000..248285b --- /dev/null +++ b/database/factories/product_factory.ts @@ -0,0 +1,13 @@ +import factory from '@adonisjs/lucid/factories' +import Product from '#models/product' + +export const ProductFactory = factory + .define(Product, async ({ faker }) => { + return { + name: faker.commerce.productName(), + isVegetarian: faker.datatype.boolean(), + description: faker.commerce.productDescription(), + recipe: faker.lorem.paragraph(), + } + }) + .build() diff --git a/database/factories/restock_factory.ts b/database/factories/restock_factory.ts new file mode 100644 index 0000000..8e083e6 --- /dev/null +++ b/database/factories/restock_factory.ts @@ -0,0 +1,16 @@ +import factory from '@adonisjs/lucid/factories' +import Restock from '#models/restock' +import { SupplierFactory } from './supplier_factory.ts' +import { MemberFactory } from './members_factory.ts' + +export const RestockFactory = factory + .define(Restock, async ({ faker }) => { + return { + totalPrice: faker.commerce.price(), + memberId: null, // Will be set by relation + supplierId: null, // Will be set by relation + } + }) + .relation('member', () => MemberFactory) + .relation('supplier', () => SupplierFactory) + .build() diff --git a/database/factories/role_factory.ts b/database/factories/role_factory.ts new file mode 100644 index 0000000..0661138 --- /dev/null +++ b/database/factories/role_factory.ts @@ -0,0 +1,17 @@ +import factory from '@adonisjs/lucid/factories' +import Role from '#models/role' + +export const RoleFactory = factory + .define(Role, async ({ faker }) => { + return { + name: faker.helpers.arrayElement([ + 'President', + 'Service', + 'Assembly', + 'Logistics', + 'Finance', + 'HR', + ]), + } + }) + .build() diff --git a/database/factories/stock_batch_factory.ts b/database/factories/stock_batch_factory.ts new file mode 100644 index 0000000..5adabb8 --- /dev/null +++ b/database/factories/stock_batch_factory.ts @@ -0,0 +1,19 @@ +import factory from '@adonisjs/lucid/factories' +import StockBatch from '#models/stock_batch' +import { RestockFactory } from './restock_factory.ts' +import { GoodFactory } from './good_factory.ts' +import { DateTime } from 'luxon' + +export const StockBatchFactory = factory + .define(StockBatch, async ({ faker }) => { + return { + expirationDate: DateTime.fromJSDate(faker.date.future()), + label: faker.commerce.productName(), + quantity: faker.number.int({ min: 1, max: 100 }).toString(), + restockId: null, // Will be set by relation + goodId: null, // Will be set by relation + } + }) + .relation('restock', () => RestockFactory) + .relation('good', () => GoodFactory) + .build() diff --git a/database/factories/stock_movement_factory.ts b/database/factories/stock_movement_factory.ts new file mode 100644 index 0000000..c02af18 --- /dev/null +++ b/database/factories/stock_movement_factory.ts @@ -0,0 +1,17 @@ +import factory from '@adonisjs/lucid/factories' +import StockMovement from '#models/stock_movement' +import { GoodFactory } from './good_factory.ts' +import { StockBatchFactory } from './stock_batch_factory.ts' + +export const StockMovementFactory = factory + .define(StockMovement, async ({ faker }) => { + return { + quantity: faker.number.int({ min: 1, max: 100 }).toString(), + movementType: faker.helpers.arrayElement(['in', 'out']), + goodId: undefined, + stockBatchId: undefined, + } + }) + .relation('good', () => GoodFactory) + .relation('stockBatch', () => StockBatchFactory) + .build() diff --git a/database/factories/supplier_factory.ts b/database/factories/supplier_factory.ts new file mode 100644 index 0000000..258d390 --- /dev/null +++ b/database/factories/supplier_factory.ts @@ -0,0 +1,10 @@ +import factory from '@adonisjs/lucid/factories' +import Supplier from '#models/supplier' + +export const SupplierFactory = factory + .define(Supplier, async ({ faker }) => { + return { + name: faker.company.name(), + } + }) + .build() diff --git a/database/factories/transaction_factory.ts b/database/factories/transaction_factory.ts new file mode 100644 index 0000000..7e6e719 --- /dev/null +++ b/database/factories/transaction_factory.ts @@ -0,0 +1,11 @@ +import factory from '@adonisjs/lucid/factories' +import Transaction from '#models/transaction' + +export const TransactionFactory = factory + .define(Transaction, async ({ faker }) => { + return { + amount: faker.finance.amount(), + type: faker.helpers.arrayElement(['credit', 'debit', 'refund']), + } + }) + .build() diff --git a/database/factories/user_factory.ts b/database/factories/user_factory.ts new file mode 100644 index 0000000..862f56f --- /dev/null +++ b/database/factories/user_factory.ts @@ -0,0 +1,12 @@ +import factory from '@adonisjs/lucid/factories' +import User from '#models/user' + +export const UserFactory = factory + .define(User, async ({ faker }) => { + return { + email: faker.internet.email(), + password: faker.internet.password(), + casId: faker.string.uuid(), + } + }) + .build() diff --git a/database/migrations/1761885935168_create_users_table.ts b/database/migrations/1761885935168_create_users_table.ts index 93770f5..2f8d0e0 100644 --- a/database/migrations/1761885935168_create_users_table.ts +++ b/database/migrations/1761885935168_create_users_table.ts @@ -5,7 +5,7 @@ export default class extends BaseSchema { async up() { this.schema.createTable(this.tableName, (table) => { - table.increments('id').notNullable() + table.increments('id') table.string('cas_id').unique().notNullable() table.string('email', 254).notNullable().unique() table.string('password').notNullable() diff --git a/database/migrations/1773828511747_create_members_table.ts b/database/migrations/1773828511747_create_members_table.ts index 10da26b..a3b5803 100644 --- a/database/migrations/1773828511747_create_members_table.ts +++ b/database/migrations/1773828511747_create_members_table.ts @@ -5,7 +5,13 @@ export default class extends BaseSchema { async up() { this.schema.createTable(this.tableName, (table) => { - table.integer('id').references('id').inTable('users').onDelete('CASCADE').primary() + table + .integer('id') + .primary() + .notNullable() + .references('id') + .inTable('users') + .onDelete('CASCADE') table.string('first_name').notNullable() table.string('last_name').notNullable() diff --git a/database/schema.ts b/database/schema.ts index 688c00c..d0a5e46 100644 --- a/database/schema.ts +++ b/database/schema.ts @@ -160,13 +160,15 @@ export class FurnitureSchema extends BaseModel { } export class GoodSupplierSchema extends BaseModel { - static $columns = ['createdAt', 'goodId', 'supplierId', 'updatedAt'] as const + static $columns = ['createdAt', 'goodId', 'price', 'supplierId', 'updatedAt'] as const $columns = GoodSupplierSchema.$columns @column.dateTime({ autoCreate: true }) declare createdAt: DateTime | null @column() declare goodId: number @column() + declare price: string + @column() declare supplierId: number @column.dateTime({ autoCreate: true, autoUpdate: true }) declare updatedAt: DateTime | null @@ -390,21 +392,33 @@ export class PreOrderSchema extends BaseModel { } export class ProductFurnitureSchema extends BaseModel { - static $columns = ['furnitureId', 'productId'] as const + static $columns = ['createdAt', 'furnitureId', 'productId', 'quantity', 'updatedAt'] as const $columns = ProductFurnitureSchema.$columns + @column.dateTime({ autoCreate: true }) + declare createdAt: DateTime @column() declare furnitureId: number @column({ isPrimary: true }) declare productId: number + @column() + declare quantity: number + @column.dateTime({ autoCreate: true, autoUpdate: true }) + declare updatedAt: DateTime | null } export class ProductGoodSchema extends BaseModel { - static $columns = ['goodId', 'productId'] as const + static $columns = ['createdAt', 'goodId', 'productId', 'quantity', 'updatedAt'] as const $columns = ProductGoodSchema.$columns + @column.dateTime({ autoCreate: true }) + declare createdAt: DateTime @column() declare goodId: number @column({ isPrimary: true }) declare productId: number + @column() + declare quantity: number + @column.dateTime({ autoCreate: true, autoUpdate: true }) + declare updatedAt: DateTime | null } export class ProductSchema extends BaseModel { @@ -580,8 +594,10 @@ export class TransactionSchema extends BaseModel { } export class UserSchema extends BaseModel { - static $columns = ['createdAt', 'email', 'id', 'password', 'updatedAt'] as const + static $columns = ['casId', 'createdAt', 'email', 'id', 'password', 'updatedAt'] as const $columns = UserSchema.$columns + @column() + declare casId: string @column.dateTime({ autoCreate: true }) declare createdAt: DateTime @column() diff --git a/database/seeders/category_seeder.ts b/database/seeders/category_seeder.ts new file mode 100644 index 0000000..9a33a46 --- /dev/null +++ b/database/seeders/category_seeder.ts @@ -0,0 +1,8 @@ +import { BaseSeeder } from '@adonisjs/lucid/seeders' +import { CategoryFactory } from '#database/factories/category_factory' + +export default class extends BaseSeeder { + async run() { + await CategoryFactory.createMany(10) + } +} diff --git a/database/seeders/event_seeder.ts b/database/seeders/event_seeder.ts new file mode 100644 index 0000000..bac1669 --- /dev/null +++ b/database/seeders/event_seeder.ts @@ -0,0 +1,8 @@ +import { BaseSeeder } from '@adonisjs/lucid/seeders' +import { EventFactory } from '#database/factories/event_factory' + +export default class extends BaseSeeder { + async run() { + await EventFactory.createMany(10) + } +} diff --git a/database/seeders/fast_pass_seeder.ts b/database/seeders/fast_pass_seeder.ts new file mode 100644 index 0000000..dd42730 --- /dev/null +++ b/database/seeders/fast_pass_seeder.ts @@ -0,0 +1,8 @@ +import { BaseSeeder } from '@adonisjs/lucid/seeders' +import { FastPassFactory } from '#database/factories/fast_pass_factory' + +export default class extends BaseSeeder { + async run() { + await FastPassFactory.createMany(5) + } +} diff --git a/database/seeders/furniture_seeder.ts b/database/seeders/furniture_seeder.ts new file mode 100644 index 0000000..d5777a5 --- /dev/null +++ b/database/seeders/furniture_seeder.ts @@ -0,0 +1,9 @@ +import { FurnitureFactory } from '#database/factories/furniture_factory' +import { BaseSeeder } from '@adonisjs/lucid/seeders' + +export default class extends BaseSeeder { + async run() { + // Write your database queries inside the run method + await FurnitureFactory.createMany(10) + } +} diff --git a/database/seeders/good_seeder.ts b/database/seeders/good_seeder.ts new file mode 100644 index 0000000..74ed770 --- /dev/null +++ b/database/seeders/good_seeder.ts @@ -0,0 +1,17 @@ +import { BaseSeeder } from '@adonisjs/lucid/seeders' +import { GoodFactory } from '#database/factories/good_factory' +import { CategoryFactory } from '#database/factories/category_factory' + +export default class extends BaseSeeder { + public async run() { + // 1. Créer des catégories + const categories = await CategoryFactory.createMany(3) + + // 2. Créer des goods liés aux catégories + await GoodFactory.merge( + Array.from({ length: 10 }, (_, index) => ({ + categoryId: categories[index % categories.length].id, + })) + ).createMany(10) + } +} diff --git a/database/seeders/good_supplier_seeder.ts b/database/seeders/good_supplier_seeder.ts new file mode 100644 index 0000000..0ab76a9 --- /dev/null +++ b/database/seeders/good_supplier_seeder.ts @@ -0,0 +1,40 @@ +import { BaseSeeder } from '@adonisjs/lucid/seeders' +import Good from '#models/good' +import Supplier from '#models/supplier' + +export default class extends BaseSeeder { + async run() { + // Write your database queries inside the run method + const goods = await Good.all() + const suppliers = await Supplier.all() + + console.log(`Found ${goods.length} goods and ${suppliers.length} suppliers`) + + if (goods.length < 2) { + throw new Error('Not enough goods in database. Run good_seeder first!') + } + + if (suppliers.length === 0) { + throw new Error('Not enough suppliers in database. Run supplier_seeder first!') + } + + // Pour chaque supplier, attacher plusieurs goods avec des prices + for (const supplier of suppliers) { + // Sélectionner 2-3 goods aléatoires pour chaque supplier + const randomGoodsCount = Math.floor(Math.random() * 2) + 2 // 2 ou 3 goods + const selectedGoods = goods + .sort(() => 0.5 - Math.random()) // Mélanger + .slice(0, randomGoodsCount) + + const pivotData: Record = {} + + for (const good of selectedGoods) { + pivotData[good.id] = { + price: Math.floor(Math.random() * 1000) + 10, // prix entre 10 et 1000 + } + } + + await supplier.related('goods').sync(pivotData) + } + } +} diff --git a/database/seeders/job_seeder.ts b/database/seeders/job_seeder.ts new file mode 100644 index 0000000..fc230ea --- /dev/null +++ b/database/seeders/job_seeder.ts @@ -0,0 +1,8 @@ +import { BaseSeeder } from '@adonisjs/lucid/seeders' +import { JobFactory } from '#database/factories/job_factory' + +export default class extends BaseSeeder { + async run() { + await JobFactory.createMany(8) + } +} diff --git a/database/seeders/log_seeder.ts b/database/seeders/log_seeder.ts new file mode 100644 index 0000000..68b53c2 --- /dev/null +++ b/database/seeders/log_seeder.ts @@ -0,0 +1,21 @@ +import { BaseSeeder } from '@adonisjs/lucid/seeders' +import User from '#models/user' +import { LogFactory } from '#database/factories/log_factory' + +export default class extends BaseSeeder { + async run() { + const users = await User.query().select('id') + + if (users.length === 0) { + throw new Error('LogSeeder: no users found. Run UserSeeder first.') + } + + const pickUserId = () => users[Math.floor(Math.random() * users.length)].id + + await LogFactory.merge( + Array.from({ length: 50 }, () => ({ + userId: pickUserId(), + })) + ).createMany(50) + } +} diff --git a/database/seeders/main_seeder.ts b/database/seeders/main_seeder.ts new file mode 100644 index 0000000..8f4fd3d --- /dev/null +++ b/database/seeders/main_seeder.ts @@ -0,0 +1,60 @@ +import { BaseSeeder } from '@adonisjs/lucid/seeders' +import GoodSeeder from './good_seeder.js' +import FurnitureSeeder from './furniture_seeder.js' +import ProductSeeder from './product_seeder.js' +import ProductGoodSeeder from './product_good_seeder.js' +import ProductFurnitureSeeder from './product_furniture_seeder.js' +import SupplierSeeder from './supplier_seeder.js' +import GoodSupplierSeeder from './good_supplier_seeder.js' +import MemberSeeder from './member_seeder.js' +import RestockSeeder from './restock_seeder.js' +import StockBatchSeeder from './stock_batch_seeder.js' +import StockMovementSeeder from './stock_movement_seeder.js' +import LogSeeder from './log_seeder.js' +import RoleSeeder from './role_seeder.js' +import PermissionSeeder from './permission_seeder.js' +import RolePermissionSeeder from './role_permission_seeder.js' +import EventSeeder from './event_seeder.js' +import JobSeeder from './job_seeder.js' +import TransactionSeeder from './transaction_seeder.js' +import FastPassSeeder from './fast_pass_seeder.js' +import SubscriptionSeeder from './subscription_seeder.js' + +export default class extends BaseSeeder { + private async runSeeder(Seeder: typeof BaseSeeder) { + await new Seeder(this.client).run() + } + + public async run() { + // 1. Seeders seuls (no dependencies) + await this.runSeeder(RoleSeeder) + await this.runSeeder(PermissionSeeder) + await this.runSeeder(JobSeeder) + await this.runSeeder(TransactionSeeder) + + // 2. Seeders dépendants (depends on step 1) + await this.runSeeder(RolePermissionSeeder) + await this.runSeeder(MemberSeeder) + await this.runSeeder(GoodSeeder) + await this.runSeeder(FurnitureSeeder) + await this.runSeeder(SupplierSeeder) + await this.runSeeder(EventSeeder) + await this.runSeeder(FastPassSeeder) + + // 3. Seeders dépendants des seeders précédents + await this.runSeeder(ProductSeeder) + await this.runSeeder(RestockSeeder) + await this.runSeeder(LogSeeder) + await this.runSeeder(FastPassSeeder) + + // 4. Seeders dépendants des seeders précédents + await this.runSeeder(SubscriptionSeeder) + await this.runSeeder(ProductGoodSeeder) + await this.runSeeder(ProductFurnitureSeeder) + await this.runSeeder(GoodSupplierSeeder) + await this.runSeeder(StockBatchSeeder) + + // 5. Seeders dépendants des seeders précédents + await this.runSeeder(StockMovementSeeder) + } +} diff --git a/database/seeders/member_seeder.ts b/database/seeders/member_seeder.ts new file mode 100644 index 0000000..02adfcf --- /dev/null +++ b/database/seeders/member_seeder.ts @@ -0,0 +1,23 @@ +import { BaseSeeder } from '@adonisjs/lucid/seeders' +import { MemberFactory } from '#database/factories/members_factory' +import Role from '#models/role' + +export default class MemberSeeder extends BaseSeeder { + async run() { + const roles = await Role.query().select('id') + + if (roles.length === 0) { + throw new Error('MemberSeeder: no roles found. Run RoleSeeder first.') + } + + const pickRoleId = () => roles[Math.floor(Math.random() * roles.length)].id + + await MemberFactory.with('user') + .merge( + Array.from({ length: 10 }, () => ({ + roleId: pickRoleId(), + })) + ) + .createMany(10) + } +} diff --git a/database/seeders/permission_seeder.ts b/database/seeders/permission_seeder.ts new file mode 100644 index 0000000..f3e2a57 --- /dev/null +++ b/database/seeders/permission_seeder.ts @@ -0,0 +1,32 @@ +import { BaseSeeder } from '@adonisjs/lucid/seeders' +import Permission from '#models/permission' + +const permissions = [ + 'presence:write', + 'presence:read', + 'stock:read', + 'stock:update', + 'stock:create', + 'stock:delete', + 'product:read', + 'product:update', + 'product:create', + 'product:delete', + 'supplier:read', + 'supplier:update', + 'supplier:create', + 'supplier:delete', + 'restock:read', + 'restock:update', + 'restock:create', + 'restock:delete', +] + +export default class extends BaseSeeder { + async run() { + await Permission.fetchOrCreateMany( + 'permission', + permissions.map((permission) => ({ permission })) + ) + } +} diff --git a/database/seeders/product_furniture_seeder.ts b/database/seeders/product_furniture_seeder.ts new file mode 100644 index 0000000..33d0de3 --- /dev/null +++ b/database/seeders/product_furniture_seeder.ts @@ -0,0 +1,18 @@ +import Furniture from '#models/furniture' +import Product from '#models/product' +import { BaseSeeder } from '@adonisjs/lucid/seeders' + +export default class extends BaseSeeder { + async run() { + // Write your database queries inside the run method. + const products = await Product.all() + const funrnitures = await Furniture.all() + + for (const product of products) { + await product.related('furnitures').sync({ + [funrnitures[0].id]: { quantity: 2 }, + [funrnitures[1].id]: { quantity: 5 }, + }) + } + } +} diff --git a/database/seeders/product_good_seeder.ts b/database/seeders/product_good_seeder.ts new file mode 100644 index 0000000..cfb66c6 --- /dev/null +++ b/database/seeders/product_good_seeder.ts @@ -0,0 +1,39 @@ +import Good from '#models/good' +import Product from '#models/product' +import { BaseSeeder } from '@adonisjs/lucid/seeders' + +export default class extends BaseSeeder { + async run() { + const goods = await Good.all() + const products = await Product.all() + + console.log(`Found ${goods.length} goods and ${products.length} products`) + + if (goods.length < 2) { + throw new Error('Not enough goods in database. Run good_seeder first!') + } + + if (products.length === 0) { + throw new Error('Not enough products in database. Run product_seeder first!') + } + + // Pour chaque product, attacher plusieurs goods avec des quantités + for (const product of products) { + // Sélectionner 2-3 goods aléatoires pour chaque product + const randomGoodsCount = Math.floor(Math.random() * 2) + 2 // 2 ou 3 goods + const selectedGoods = goods + .sort(() => 0.5 - Math.random()) // Mélanger + .slice(0, randomGoodsCount) + + const pivotData: Record = {} + + for (const good of selectedGoods) { + pivotData[good.id] = { + quantity: Math.floor(Math.random() * 10) + 1, // quantité entre 1 et 10 + } + } + + await product.related('goods').sync(pivotData) + } + } +} diff --git a/database/seeders/product_seeder.ts b/database/seeders/product_seeder.ts new file mode 100644 index 0000000..f823e45 --- /dev/null +++ b/database/seeders/product_seeder.ts @@ -0,0 +1,9 @@ +import { BaseSeeder } from '@adonisjs/lucid/seeders' +import { ProductFactory } from '#database/factories/product_factory' + +export default class extends BaseSeeder { + async run() { + // Write your database queries inside the run method + await ProductFactory.createMany(10) + } +} diff --git a/database/seeders/restock_seeder.ts b/database/seeders/restock_seeder.ts new file mode 100644 index 0000000..c2bd7ea --- /dev/null +++ b/database/seeders/restock_seeder.ts @@ -0,0 +1,19 @@ +import { SupplierFactory } from '#database/factories/supplier_factory' +import { BaseSeeder } from '@adonisjs/lucid/seeders' +import { RestockFactory } from '#database/factories/restock_factory' +import { MemberFactory } from '#database/factories/members_factory' + +export default class extends BaseSeeder { + async run() { + // Write your database queries inside the run method + const suppliers = await SupplierFactory.createMany(5) + const members = await MemberFactory.createMany(5) + + await RestockFactory.merge( + Array.from({ length: 10 }, (_, index) => ({ + supplierId: suppliers[index % suppliers.length].id, + memberId: members[index % members.length].id, + })) + ).createMany(10) + } +} diff --git a/database/seeders/role_permission_seeder.ts b/database/seeders/role_permission_seeder.ts new file mode 100644 index 0000000..7640f57 --- /dev/null +++ b/database/seeders/role_permission_seeder.ts @@ -0,0 +1,73 @@ +import { BaseSeeder } from '@adonisjs/lucid/seeders' +import Role from '#models/role' +import Permission from '#models/permission' + +export default class extends BaseSeeder { + async run() { + // Fetch all roles and permissions + const roles = await Role.all() + const permissions = await Permission.all() + + // Define permission mapping for different roles + const rolePermissionMap: Record = { + President: [ + 'presence:write', + 'presence:read', + 'stock:read', + 'stock:update', + 'stock:create', + 'stock:delete', + 'product:read', + 'product:update', + 'product:create', + 'product:delete', + 'supplier:read', + 'supplier:update', + 'supplier:create', + 'supplier:delete', + 'restock:read', + 'restock:update', + 'restock:create', + 'restock:delete', + ], + Service: [ + 'presence:read', + 'stock:read', + 'product:read', + 'supplier:read', + 'restock:read', + 'restock:create', + ], + Assembly: ['presence:read', 'stock:read', 'product:read'], + Logistics: [ + 'stock:read', + 'stock:update', + 'stock:create', + 'product:read', + 'supplier:read', + 'supplier:update', + 'restock:read', + 'restock:update', + 'restock:create', + ], + Finance: [ + 'supplier:read', + 'supplier:update', + 'restock:read', + 'restock:update', + 'product:read', + ], + HR: ['presence:write', 'presence:read'], + } + + // Assign permissions to roles + for (const role of roles) { + const permissionNames = rolePermissionMap[role.name] || [] + const rolePermissions = permissions.filter((p) => permissionNames.includes(p.permission)) + + if (rolePermissions.length > 0) { + await role.related('permissions').attach(rolePermissions.map((p) => p.permission)) + } + } + } +} diff --git a/database/seeders/role_seeder.ts b/database/seeders/role_seeder.ts new file mode 100644 index 0000000..b582eee --- /dev/null +++ b/database/seeders/role_seeder.ts @@ -0,0 +1,9 @@ +import { BaseSeeder } from '@adonisjs/lucid/seeders' +import { RoleFactory } from '#database/factories/role_factory' + +export default class extends BaseSeeder { + async run() { + // Write your database queries inside the run method + await RoleFactory.createMany(5) + } +} diff --git a/database/seeders/stock_batch_seeder.ts b/database/seeders/stock_batch_seeder.ts new file mode 100644 index 0000000..b249dab --- /dev/null +++ b/database/seeders/stock_batch_seeder.ts @@ -0,0 +1,26 @@ +import { BaseSeeder } from '@adonisjs/lucid/seeders' +import { StockBatchFactory } from '#database/factories/stock_batch_factory' +import Good from '#models/good' +import Restock from '#models/restock' + +export default class extends BaseSeeder { + async run() { + const goods = await Good.query().select('id') + const restocks = await Restock.query().select('id') + + if (goods.length === 0) { + throw new Error('StockBatchSeeder: no goods found. Run GoodSeeder first.') + } + + if (restocks.length === 0) { + throw new Error('StockBatchSeeder: no restocks found. Run RestockSeeder first.') + } + + await StockBatchFactory.merge( + Array.from({ length: 10 }, (_, index) => ({ + goodId: goods[index % goods.length].id, + restockId: restocks[index % restocks.length].id, + })) + ).createMany(10) + } +} diff --git a/database/seeders/stock_movement_seeder.ts b/database/seeders/stock_movement_seeder.ts new file mode 100644 index 0000000..706cc54 --- /dev/null +++ b/database/seeders/stock_movement_seeder.ts @@ -0,0 +1,44 @@ +import { BaseSeeder } from '@adonisjs/lucid/seeders' +import Good from '#models/good' +import StockBatch from '#models/stock_batch' +import { StockMovementFactory } from '#database/factories/stock_movement_factory' + +export default class extends BaseSeeder { + async run() { + // Write your database queries inside the run method + const goods = await Good.query().select('id') + const stockBatches = await StockBatch.query().select('id') + + if (goods.length === 0) { + throw new Error('StockMovementSeeder: no goods found. Run GoodSeeder first.') + } + + if (stockBatches.length === 0) { + throw new Error('StockMovementSeeder: no stock batches found. Run StockBatchSeeder first.') + } + + console.log( + `Seeding stock movements with ${goods.length} goods and ${stockBatches.length} stock batches...` + ) + + const pickId = (rows: Array<{ id: number }>) => rows[Math.floor(Math.random() * rows.length)].id + + await StockMovementFactory.merge( + Array.from({ length: 20 }, () => { + const goodId = pickId(goods) + + let stockBatchId = pickId(stockBatches) + if (stockBatches.length > 1) { + while (stockBatchId === goodId) { + stockBatchId = pickId(stockBatches) + } + } + + return { + goodId, + stockBatchId, + } + }) + ).createMany(20) + } +} diff --git a/database/seeders/subscription_seeder.ts b/database/seeders/subscription_seeder.ts new file mode 100644 index 0000000..0e3d5e3 --- /dev/null +++ b/database/seeders/subscription_seeder.ts @@ -0,0 +1,22 @@ +import { BaseSeeder } from '@adonisjs/lucid/seeders' +import User from '#models/user' +import FastPass from '#models/fast_pass' +import { DateTime } from 'luxon' + +export default class extends BaseSeeder { + async run() { + const users = await User.all() + const fastPasses = await FastPass.all() + + if (users.length === 0 || fastPasses.length < 2) { + return + } + + for (const user of users) { + await user.related('fastPasses').sync({ + [fastPasses[0].id]: { subscribed_at: DateTime.now() }, + [fastPasses[1].id]: { subscribed_at: DateTime.now() }, + }) + } + } +} diff --git a/database/seeders/supplier_seeder.ts b/database/seeders/supplier_seeder.ts new file mode 100644 index 0000000..c73ff64 --- /dev/null +++ b/database/seeders/supplier_seeder.ts @@ -0,0 +1,9 @@ +import { BaseSeeder } from '@adonisjs/lucid/seeders' +import { SupplierFactory } from '#database/factories/supplier_factory' + +export default class extends BaseSeeder { + async run() { + // Write your database queries inside the run method + await SupplierFactory.createMany(10) + } +} diff --git a/database/seeders/transaction_seeder.ts b/database/seeders/transaction_seeder.ts new file mode 100644 index 0000000..fcfeb86 --- /dev/null +++ b/database/seeders/transaction_seeder.ts @@ -0,0 +1,8 @@ +import { BaseSeeder } from '@adonisjs/lucid/seeders' +import { TransactionFactory } from '#database/factories/transaction_factory' + +export default class extends BaseSeeder { + async run() { + await TransactionFactory.createMany(15) + } +} diff --git a/start/routes.ts b/start/routes.ts index 720a100..b1b8c4c 100644 --- a/start/routes.ts +++ b/start/routes.ts @@ -14,3 +14,28 @@ router.get('/', () => { }) router.group(() => {}).prefix('/v1') + +router + .group(() => { + router.resource('members', () => import('#controllers/members_controller')).apiOnly() + router.resource('categories', () => import('#controllers/categories_controller')).apiOnly() + router.resource('furnitures', () => import('#controllers/furnitures_controller')).apiOnly() + router.resource('products', () => import('#controllers/products_controller')).apiOnly() + router.resource('goods', () => import('#controllers/goods_controller')).apiOnly() + router.resource('suppliers', () => import('#controllers/suppliers_controller')).apiOnly() + router.resource('restocks', () => import('#controllers/restocks_controller')).apiOnly() + router + .resource('stock-batches', () => import('#controllers/stock_batches_controller')) + .apiOnly() + router + .resource('stock-movements', () => import('#controllers/stock_movements_controller')) + .apiOnly() + router.resource('logs', () => import('#controllers/logs_controller')).apiOnly() + router.resource('roles', () => import('#controllers/roles_controller')).apiOnly() + router.resource('permissions', () => import('#controllers/permissions_controller')).apiOnly() + }) + .prefix('/v1') + +router.get('/test', async () => { + return { message: 'ok' } +})