Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adicionar serviço agendado para remover itens(supplies) abaixo de urgente e registrar logs #157

Open
wants to merge 10 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"@nestjs/passport": "^10.0.3",
"@nestjs/platform-express": "^10.0.0",
"@nestjs/platform-fastify": "^10.3.8",
"@nestjs/schedule": "^4.0.2",
"@nestjs/swagger": "^7.3.1",
"@prisma/client": "^5.13.0",
"bcrypt": "^5.1.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
-- CreateTable
CREATE TABLE "supply_auto_remove_logs" (
"id" TEXT NOT NULL,
"supply_id" TEXT NOT NULL,
"shelter_id" TEXT NOT NULL,
"created_at" VARCHAR(32) NOT NULL,
rodrigooler marked this conversation as resolved.
Show resolved Hide resolved

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

-- AddForeignKey
ALTER TABLE "supply_auto_remove_logs" ADD CONSTRAINT "supply_auto_remove_logs_shelter_id_fkey" FOREIGN KEY ("shelter_id") REFERENCES "shelters"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "supply_auto_remove_logs" ADD CONSTRAINT "supply_auto_remove_logs_supply_id_fkey" FOREIGN KEY ("supply_id") REFERENCES "supplies"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
Warnings:

- You are about to drop the column `created_at` on the `supply_auto_remove_logs` table. All the data in the column will be lost.
- Added the required column `removed_at` to the `supply_auto_remove_logs` table without a default value. This is not possible if the table is not empty.

*/
-- AlterTable
ALTER TABLE "supply_auto_remove_logs" DROP COLUMN "created_at",
ADD COLUMN "removed_at" VARCHAR(32) NOT NULL;
17 changes: 17 additions & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ model Supply {

supplyCategory SupplyCategory @relation(fields: [supplyCategoryId], references: [id])
shelterSupplies ShelterSupply[]
supplyAutoRemoveLogs SupplyAutoRemoveLog[]

@@map("supplies")
}
Expand Down Expand Up @@ -114,6 +115,7 @@ model Shelter {

shelterManagers ShelterManagers[]
shelterSupplies ShelterSupply[]
supplyAutoRemoveLogs SupplyAutoRemoveLog[]

@@map("shelters")
}
Expand Down Expand Up @@ -151,3 +153,18 @@ model Supporters {

@@map("supporters")
}


model SupplyAutoRemoveLog {
id String @id @default(uuid())
supplyId String @map("supply_id")
shelterId String @map("shelter_id")
removedAt String @map("removed_at") @db.VarChar(32)



shelter Shelter @relation(fields: [shelterId], references: [id])
supply Supply @relation(fields: [supplyId], references: [id])

@@map("supply_auto_remove_logs")
}
5 changes: 5 additions & 0 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import { ShelterManagersModule } from './shelter-managers/shelter-managers.modul
import { ShelterSupplyModule } from './shelter-supply/shelter-supply.module';
import { PartnersModule } from './partners/partners.module';
import { SupportersModule } from './supporters/supporters.module';
import { ScheduleModule } from '@nestjs/schedule';
import { ItemCleanupService } from './schedule/item-cleanup.service';


@Module({
imports: [
Expand All @@ -26,13 +29,15 @@ import { SupportersModule } from './supporters/supporters.module';
ShelterSupplyModule,
PartnersModule,
SupportersModule,
ScheduleModule.forRoot(),
],
controllers: [],
providers: [
{
provide: APP_INTERCEPTOR,
useClass: ServerResponseInterceptor,
},
ItemCleanupService
],
})
export class AppModule implements NestModule {
Expand Down
113 changes: 113 additions & 0 deletions src/schedule/item-cleanup.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { Injectable, Logger } from '@nestjs/common';
import { Cron } from '@nestjs/schedule';
import { PrismaService } from 'src/prisma/prisma.service';
import { SupplyPriority } from 'src/supply/types';

@Injectable()
export class ItemCleanupService {
private logger = new Logger('ItemCleanupService');
constructor(private readonly prismaService: PrismaService) {}

@Cron('0 0 */2 * *')
async handleCron() {
const shelters = await this.prismaService.shelter.findMany({
rodrigooler marked this conversation as resolved.
Show resolved Hide resolved
include: {
shelterSupplies: {
include: {
supply: true,
},
},
},
});

for (const shelter of shelters) {
this.logger.log(
`Verificando necessidade de exclusão de itens no abrigo ${shelter.name}`,
);
for (const shelterSupply of shelter.shelterSupplies) {
const supply = shelterSupply.supply;
if (
this.canRemoveSupply(
supply.createdAt,
supply.updatedAt,
shelterSupply.priority,
)
) {
this.removeSupply(supply.id, shelter.id, supply.name);
}
}
}
}

private hasPassed48Hours(
rodrigooler marked this conversation as resolved.
Show resolved Hide resolved
createdAt: string | null,
updatedAt: string | null,
): boolean {
if (updatedAt !== null) {
const updatedAtTime = new Date(updatedAt).getTime();
const now = new Date().getTime();
const difference = now - updatedAtTime;
const hours = Math.floor(difference / (1000 * 60 * 60));
return hours >= 48;
} else {
const createdAtTime =
createdAt !== null ? new Date(createdAt).getTime() : 0;
const now = new Date().getTime();
const difference = now - createdAtTime;
const hours = Math.floor(difference / (1000 * 60 * 60));
return hours >= 48;
}
}

private async removeSupply(
supplyId: string,
shelterId: string,
supplyName: string,
) {
this.logger.log(
`Suprimento ${supplyName} já está há 48 horas com baixa movimentação e prioridade 0. Removendo do abrigo ${shelterId}`,
);

try {
await this.prismaService.shelterSupply.deleteMany({
rodrigooler marked this conversation as resolved.
Show resolved Hide resolved
where: {
supplyId,
shelterId,
},
});

await this.prismaService.supplyAutoRemoveLog.create({
data: {
supply: {
connect: {
id: supplyId,
},
},
shelter: {
connect: {
id: shelterId,
},
},
removedAt: new Date().toISOString(),
},
});
} catch (error) {
this.logger.error(
`Erro ao tentar remover o suprimento ${supplyId} do abrigo ${shelterId}`,
(error as Error).stack,
);
}
}

private canRemoveSupply(
createdAt: string | null,
updatedAt: string | null,
priority: SupplyPriority,
): boolean {
const hasPassedTime = this.hasPassed48Hours(createdAt, updatedAt);

const isNotUrgent = priority !== SupplyPriority.Urgent;

return isNotUrgent && hasPassedTime;
}
}
9 changes: 9 additions & 0 deletions src/schedule/schedule.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Module } from '@nestjs/common';
import { ItemCleanupService } from './item-cleanup.service';
import { PrismaService } from 'src/prisma/prisma.service';

@Module({
providers: [ItemCleanupService, PrismaService],
exports: [ItemCleanupService],
})
export class ScheduleModule {}
rodrigooler marked this conversation as resolved.
Show resolved Hide resolved
18 changes: 18 additions & 0 deletions src/schedule/schedule.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { ScheduleService } from './item-cleanup.service';

describe('ScheduleService', () => {
let service: ScheduleService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [ScheduleService],
}).compile();

service = module.get<ScheduleService>(ScheduleService);
});

it('should be defined', () => {
expect(service).toBeDefined();
});
});