Skip to content

Commit

Permalink
add inventorie feature (#105)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexrobaina authored Jun 5, 2024
1 parent f9c952f commit 9f2f89e
Show file tree
Hide file tree
Showing 22 changed files with 562 additions and 159 deletions.
Binary file modified .DS_Store
Binary file not shown.
2 changes: 0 additions & 2 deletions .idea/.gitignore

This file was deleted.

5 changes: 0 additions & 5 deletions .idea/codeStyles/codeStyleConfig.xml

This file was deleted.

6 changes: 0 additions & 6 deletions .idea/eslintPlugin.xml

This file was deleted.

6 changes: 0 additions & 6 deletions .idea/misc.xml

This file was deleted.

8 changes: 0 additions & 8 deletions .idea/modules.xml

This file was deleted.

8 changes: 0 additions & 8 deletions .idea/petsLoveBackendTypescript.iml

This file was deleted.

6 changes: 0 additions & 6 deletions .idea/vcs.xml

This file was deleted.

14 changes: 0 additions & 14 deletions .idea/webResources.xml

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
-- CreateEnum
CREATE TYPE "ExpenseType" AS ENUM ('INCOME', 'EXPENSE');

-- CreateEnum
CREATE TYPE "InventoryType" AS ENUM ('MEDICINE', 'FOOD', 'TOYS', 'ACCESSORIES', 'HEALTH_WELLNESS', 'HOUSING', 'LITTER_WASTE_MANAGEMENT', 'APPAREL', 'FEEDING_SUPPLIES', 'TRAVEL_OUTDOOR', 'TRAINING_BEHAVIOR');

-- CreateTable
CREATE TABLE "Inventory" (
"id" TEXT NOT NULL,
"name" TEXT NOT NULL,
"type" "InventoryType" NOT NULL,
"description" TEXT,
"quantity" INTEGER NOT NULL,
"price" DOUBLE PRECISION NOT NULL,
"images" TEXT[],
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"userId" TEXT NOT NULL,

CONSTRAINT "Inventory_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "Expense" (
"id" TEXT NOT NULL,
"amount" DOUBLE PRECISION NOT NULL,
"date" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"type" "ExpenseType" NOT NULL,
"category" TEXT NOT NULL,
"description" TEXT,
"userId" TEXT NOT NULL,
"inventoryId" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,

CONSTRAINT "Expense_pkey" PRIMARY KEY ("id")
);

-- AddForeignKey
ALTER TABLE "Inventory" ADD CONSTRAINT "Inventory_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "Expense" ADD CONSTRAINT "Expense_inventoryId_fkey" FOREIGN KEY ("inventoryId") REFERENCES "Inventory"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "Expense" ADD CONSTRAINT "Expense_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
52 changes: 51 additions & 1 deletion src/database/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

generator client {
provider = "prisma-client-js"
seed = "ts-node --loader ts-node/esm src/database/prisma/seed.ts "
}

datasource db {
Expand Down Expand Up @@ -33,6 +32,8 @@ model User {
Appointment Appointment[]
Team Team[]
TeamMembership TeamMembership[]
Inventory Inventory[]
Expense Expense[]
}

model Location {
Expand Down Expand Up @@ -206,6 +207,41 @@ model TeamMembership {
@@id([teamId, userId])
}

model Inventory {
id String @id @default(uuid())
name String
type InventoryType
description String?
quantity Int
price Float
images String[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
userId String
user User @relation(fields: [userId], references: [id])
Expense Expense[]
}

model Expense {
id String @id @default(uuid())
amount Float
date DateTime @default(now())
type ExpenseType
category String
description String?
userId String
inventoryId String
inventory Inventory @relation(fields: [inventoryId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id])
}

enum ExpenseType {
INCOME
EXPENSE
}

enum TeamRole {
MEMBER
ADMIN
Expand All @@ -217,3 +253,17 @@ enum RecurrenceType {
MONTHLY
YEARLY
}

enum InventoryType {
MEDICINE
FOOD
TOYS
ACCESSORIES
HEALTH_WELLNESS
HOUSING
LITTER_WASTE_MANAGEMENT
APPAREL
FEEDING_SUPPLIES
TRAVEL_OUTDOOR
TRAINING_BEHAVIOR
}
52 changes: 28 additions & 24 deletions src/middlewares/utils/saveToLocal.ts
Original file line number Diff line number Diff line change
@@ -1,70 +1,74 @@
import path from 'path'
import { promises as fs } from 'fs'
import { handleError } from './handleError'
import path from 'path';
import { promises as fs } from 'fs';
import { handleError } from './handleError';

declare global {
namespace Express {
interface Response {
locals: {
file?: {
url?: string
urls?: string[]
}
}
url?: string;
urls?: string[];
};
};
}
}
}

const bucketRoute = (originalUrl: string) => {
console.log(originalUrl);
if (originalUrl.includes('/api/v1/pets')) {
return 'pets';
} else if (originalUrl.includes('/api/v1/user')) {
return 'users/avatar'; // Assuming you want to maintain this more specific path for users
} else if (originalUrl.includes('/api/v1/vaccines/petVaccine/')) {
return 'vaccines'; // Assuming you want to maintain this more specific path for users
} else if (originalUrl.includes('/api/v1/inventory')) {
return 'inventory'; // Assuming you want to maintain this more specific path for users
} else if (originalUrl.includes('qrCode')) {
return 'qrCode';
}
return '';
}
};

export const saveToLocal = async ({
req,
res,
fieldName,
}: {
req: any
res: any
fieldName: string
req: any;
res: any;
fieldName: string;
}) => {
const uploadsDir = process.env.DEV === 'true' ? path.join(__dirname, '../..', `uploads/${bucketRoute(req.originalUrl)}`) : `${process.env.UPLOAD_DIR}/${bucketRoute(req.originalUrl)}` || 'uploads'
const uploadsDir =
process.env.DEV === 'true'
? path.join(__dirname, '../..', `uploads/${bucketRoute(req.originalUrl)}`)
: `${process.env.UPLOAD_DIR}/${bucketRoute(req.originalUrl)}` || 'uploads';

try {
await fs.access(uploadsDir)
await fs.access(uploadsDir);
} catch {
await fs.mkdir(uploadsDir, { recursive: true })
await fs.mkdir(uploadsDir, { recursive: true });
}

const urls: string[] = []
const urls: string[] = [];
for (const file of req.files) {
const uniqueName = `${Date.now()}-pets-love`
const localFilePath = path.join(uploadsDir, uniqueName)
const uniqueName = `${Date.now()}-pets-love`;
const localFilePath = path.join(uploadsDir, uniqueName);

try {
await fs.writeFile(localFilePath, file.buffer)
urls.push(uniqueName)
await fs.writeFile(localFilePath, file.buffer);
urls.push(uniqueName);
} catch (error: any) {
handleError({
res,
error,
status: 500,
message: 'Failed to save the image locally.',
})
});
}
}

res.locals.file =
urls.length === 1
? { [fieldName]: { url: urls[0] } }
: { [fieldName]: { urls } }
}
urls.length === 1 ? { [fieldName]: { url: urls[0] } } : { [fieldName]: { urls } };
};
2 changes: 2 additions & 0 deletions src/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import vaccineRoutes from './vaccine'
import appointmentsRoutes from './appointment'
import teamRoutes from './team'
import petAnalyticsRoutes from './petAnalytics'
import inventoryRoutes from './inventory'

const router = routerx()

Expand All @@ -18,6 +19,7 @@ router.use(
teamRoutes,
productRoutes,
vaccineRoutes,
inventoryRoutes,
petAnalyticsRoutes,
appointmentsRoutes,
)
Expand Down
36 changes: 36 additions & 0 deletions src/routes/inventory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import {
createInventory,
updateInventory,
getInventories,
getInventory,
deleteInventory,
} from '../useCases/inventoryCase/inventory.controller'
import express from 'express'

import { verifyToken } from '../middlewares/auth'
import { createCloudUploader } from '../middlewares/cloudUploader'

const uploadImagesInventory = createCloudUploader('newImages')

const router = express.Router()

// CREATE INVENTORY ITEM
router.post('/inventory', [verifyToken, uploadImagesInventory], createInventory)

// UPDATE INVENTORY ITEM
router.put(
'/inventory/:inventoryId',
[verifyToken, uploadImagesInventory],
updateInventory,
)

// GET ALL INVENTORY ITEMS
router.get('/inventory', [verifyToken], getInventories)

// GET INVENTORY ITEM BY ID
router.get('/inventory/:inventoryId', [verifyToken], getInventory)

// DELETE INVENTORY ITEM BY ID
router.delete('/inventory/:inventoryId', [verifyToken], deleteInventory)

export default router
Loading

0 comments on commit 9f2f89e

Please sign in to comment.