Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 2 additions & 0 deletions apps/backend/src/config/typeorm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { RemoveMultipleVolunteerTypes1764811878152 } from '../migrations/1764811
import { RemoveUnusedStatuses1764816885341 } from '../migrations/1764816885341-RemoveUnusedStatuses';
import { UpdatePantryFields1763762628431 } from '../migrations/1763762628431-UpdatePantryFields';
import { PopulateDummyData1768501812134 } from '../migrations/1768501812134-populateDummyData';
import { AddDonationRecurrenceFields1770080947285 } from '../migrations/1770080947285-AddDonationRecurrenceFields';

const config = {
type: 'postgres',
Expand Down Expand Up @@ -67,6 +68,7 @@ const config = {
RemoveMultipleVolunteerTypes1764811878152,
RemoveUnusedStatuses1764816885341,
PopulateDummyData1768501812134,
AddDonationRecurrenceFields1770080947285,
],
};

Expand Down
32 changes: 31 additions & 1 deletion apps/backend/src/donations/donations.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
import { ApiBody } from '@nestjs/swagger';
import { Donation } from './donations.entity';
import { DonationService } from './donations.service';
import { DonationStatus } from './types';
import { DonationStatus, RecurrenceEnum } from './types';

@Controller('donations')
export class DonationsController {
Expand Down Expand Up @@ -54,6 +54,20 @@ export class DonationsController {
totalItems: { type: 'integer', example: 100 },
totalOz: { type: 'integer', example: 500 },
totalEstimatedValue: { type: 'integer', example: 1000 },
recurrence: {
type: 'string',
enum: Object.values(RecurrenceEnum),
example: RecurrenceEnum.ONCE,
nullable: true,
},
recurrenceFreq: { type: 'integer', example: 1, nullable: true },
nextDonationDates: {
type: 'array',
items: { type: 'string', format: 'date-time' },
example: ['2024-07-01T00:00:00Z', '2024-08-01T00:00:00Z'],
nullable: true,
},
occurences: { type: 'integer', example: 2, nullable: true },
},
},
})
Expand All @@ -66,6 +80,10 @@ export class DonationsController {
totalItems: number;
totalOz: number;
totalEstimatedValue: number;
recurrence: RecurrenceEnum;
recurrenceFreq?: number;
nextDonationDates?: Date[];
occurences?: number;
},
): Promise<Donation> {
if (
Expand All @@ -74,13 +92,25 @@ export class DonationsController {
) {
throw new BadRequestException('Invalid status');
}
// If we got a recurrence, we should have all of these values
// The next donation dates should be a list of dates we will get from the frontend accordingly
if (
body.recurrence != RecurrenceEnum.ONCE &&
(!body.recurrenceFreq || !body.nextDonationDates || !body.occurences)
) {
throw new BadRequestException('recurrence details are incomplete');
}
return this.donationService.create(
body.foodManufacturerId,
body.dateDonated,
body.status ?? DonationStatus.AVAILABLE,
body.totalItems,
body.totalOz,
body.totalEstimatedValue,
body.recurrence,
body.recurrenceFreq ?? null,
body.nextDonationDates ?? null,
body.occurences ?? null,
);
}

Expand Down
25 changes: 24 additions & 1 deletion apps/backend/src/donations/donations.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
ManyToOne,
} from 'typeorm';
import { FoodManufacturer } from '../foodManufacturers/manufacturer.entity';
import { DonationStatus } from './types';
import { DonationStatus, RecurrenceEnum } from './types';

@Entity('donations')
export class Donation {
Expand Down Expand Up @@ -44,4 +44,27 @@ export class Donation {

@Column({ name: 'total_estimated_value', type: 'int', nullable: true })
totalEstimatedValue: number;

@Column({
name: 'recurrence',
type: 'enum',
enum: RecurrenceEnum,
enumName: 'donation_recurrence_enum',
default: RecurrenceEnum.ONCE,
})
recurrence: RecurrenceEnum;

@Column({ name: 'recurrence_freq', type: 'int', nullable: true })
recurrenceFreq: number;

@Column({
name: 'next_donation_dates',
type: 'timestamptz',
array: true,
nullable: true,
})
nextDonationDates: Date[];

@Column({ name: 'occurences', type: 'int', nullable: true })
occurences: number;
}
12 changes: 10 additions & 2 deletions apps/backend/src/donations/donations.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Repository } from 'typeorm';
import { Donation } from './donations.entity';
import { validateId } from '../utils/validation.utils';
import { FoodManufacturer } from '../foodManufacturers/manufacturer.entity';
import { DonationStatus } from './types';
import { DonationStatus, RecurrenceEnum } from './types';

@Injectable()
export class DonationService {
Expand Down Expand Up @@ -45,7 +45,11 @@ export class DonationService {
totalItems: number,
totalOz: number,
totalEstimatedValue: number,
) {
recurrence: RecurrenceEnum,
recurrenceFreq: number,
nextDonationDates: Date[] | null,
occurences: number | null,
): Promise<Donation> {
validateId(foodManufacturerId, 'Food Manufacturer');
const manufacturer = await this.manufacturerRepo.findOne({
where: { foodManufacturerId },
Expand All @@ -63,6 +67,10 @@ export class DonationService {
totalItems,
totalOz,
totalEstimatedValue,
recurrence,
recurrenceFreq,
nextDonationDates,
occurences,
});

return this.repo.save(donation);
Expand Down
7 changes: 7 additions & 0 deletions apps/backend/src/donations/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,10 @@ export enum DonationStatus {
FULFILLED = 'fulfilled',
MATCHING = 'matching',
}

export enum RecurrenceEnum {
ONCE = 'once',
WEEKLY = 'weekly',
MONTHLY = 'monthly',
YEARLY = 'yearly',
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { MigrationInterface, QueryRunner } from 'typeorm';

export class AddDonationRecurrenceFields1770080947285
implements MigrationInterface
{
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
CREATE TYPE donation_recurrence_enum AS ENUM (
'once',
'weekly',
'monthly',
'yearly'
);
`);

await queryRunner.query(`
ALTER TABLE donations
ADD COLUMN recurrence donation_recurrence_enum NOT NULL DEFAULT 'once',
ADD COLUMN recurrence_freq INTEGER,
ADD COLUMN next_donation_dates TIMESTAMP WITH TIME ZONE[],
ADD COLUMN occurences INTEGER;
`);

await queryRunner.query(`
ALTER TABLE donations
ADD CONSTRAINT recurrence_fields_not_null CHECK (
(recurrence = 'once'
AND recurrence_freq IS NULL
AND next_donation_dates IS NULL
AND occurences IS NULL)
OR
(recurrence != 'once'
AND recurrence_freq IS NOT NULL
AND next_donation_dates IS NOT NULL
AND occurences IS NOT NULL)
);
`);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE donations
DROP CONSTRAINT recurrence_fields_not_null,
DROP COLUMN recurrence,
DROP COLUMN recurrence_freq,
DROP COLUMN next_donation_dates,
DROP COLUMN occurences;

DROP TYPE donation_recurrence_enum;
`);
}
}
7 changes: 7 additions & 0 deletions apps/frontend/src/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,13 @@ export enum DonationStatus {
MATCHING = 'matching',
}

export enum RecurrenceEnum {
ONCE = 'once',
WEEKLY = 'weekly',
MONTHLY = 'monthly',
YEARLY = 'yearly',
}

export interface Donation {
donationId: number;
dateDonated: string;
Expand Down
Loading