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/migrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { RemoveUnusedStatuses1764816885341 } from '../migrations/1764816885341-R
import { UpdatePantryFields1763762628431 } from '../migrations/1763762628431-UpdatePantryFields';
import { PopulateDummyData1768501812134 } from '../migrations/1768501812134-populateDummyData';
import { RemovePantryFromOrders1769316004958 } from '../migrations/1769316004958-RemovePantryFromOrders';
import { AddDonationRecurrenceFields1770080947285 } from '../migrations/1770080947285-AddDonationRecurrenceFields';
import { UpdateManufacturerEntity1768680807820 } from '../migrations/1768680807820-UpdateManufacturerEntity';
import { AddUserPoolId1769189327767 } from '../migrations/1769189327767-AddUserPoolId';
import { UpdateOrderEntity1769990652833 } from '../migrations/1769990652833-UpdateOrderEntity';
Expand Down Expand Up @@ -57,6 +58,7 @@ const schemaMigrations = [
RemoveUnusedStatuses1764816885341,
PopulateDummyData1768501812134,
RemovePantryFromOrders1769316004958,
AddDonationRecurrenceFields1770080947285,
UpdateManufacturerEntity1768680807820,
AddUserPoolId1769189327767,
UpdateOrderEntity1769990652833,
Expand Down
40 changes: 17 additions & 23 deletions apps/backend/src/donations/donations.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ 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';
import { CreateDonationDto } from './dtos/create-donation.dto';

@Controller('donations')
export class DonationsController {
Expand Down Expand Up @@ -54,34 +55,27 @@ 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.NONE,
},
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,
},
occurrencesRemaining: { type: 'integer', example: 2, nullable: true },
},
},
})
async createDonation(
@Body()
body: {
foodManufacturerId: number;
dateDonated: Date;
status: DonationStatus;
totalItems: number;
totalOz: number;
totalEstimatedValue: number;
},
body: CreateDonationDto,
): Promise<Donation> {
if (
body.status &&
!Object.values(DonationStatus).includes(body.status as DonationStatus)
) {
throw new BadRequestException('Invalid status');
}
return this.donationService.create(
body.foodManufacturerId,
body.dateDonated,
body.status ?? DonationStatus.AVAILABLE,
body.totalItems,
body.totalOz,
body.totalEstimatedValue,
);
return this.donationService.create(body);
}

@Patch('/:donationId/fulfill')
Expand Down
39 changes: 31 additions & 8 deletions apps/backend/src/donations/donations.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,26 @@ import {
JoinColumn,
ManyToOne,
} from 'typeorm';
import { DonationStatus, RecurrenceEnum } from './types';
import { FoodManufacturer } from '../foodManufacturers/manufacturers.entity';
import { DonationStatus } from './types';

@Entity('donations')
export class Donation {
@PrimaryGeneratedColumn({ name: 'donation_id' })
donationId: number;
donationId!: number;

@ManyToOne(() => FoodManufacturer, (manufacturer) => manufacturer.donations, {
nullable: false,
})
@JoinColumn({ name: 'food_manufacturer_id' })
foodManufacturer: FoodManufacturer;
foodManufacturer!: FoodManufacturer;

@CreateDateColumn({
name: 'date_donated',
type: 'timestamp',
default: () => 'NOW()',
})
dateDonated: Date;
dateDonated!: Date;

@Column({
name: 'status',
Expand All @@ -34,14 +34,37 @@ export class Donation {
enumName: 'donations_status_enum',
default: DonationStatus.AVAILABLE,
})
status: DonationStatus;
status!: DonationStatus;

@Column({ name: 'total_items', type: 'int', nullable: true })
totalItems: number;
totalItems?: number;

@Column({ name: 'total_oz', type: 'int', nullable: true })
totalOz: number;
totalOz?: number;

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

@Column({
name: 'recurrence',
type: 'enum',
enum: RecurrenceEnum,
enumName: 'donation_recurrence_enum',
default: RecurrenceEnum.NONE,
})
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: 'occurrences_remaining', type: 'int', nullable: true })
occurrencesRemaining?: number;
}
32 changes: 15 additions & 17 deletions apps/backend/src/donations/donations.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Donation } from './donations.entity';
import { validateId } from '../utils/validation.utils';
import { FoodManufacturer } from '../foodManufacturers/manufacturers.entity';
import { DonationStatus } from './types';
import { CreateDonationDto } from './dtos/create-donation.dto';
import { FoodManufacturer } from '../foodManufacturers/manufacturers.entity';

@Injectable()
export class DonationService {
Expand Down Expand Up @@ -38,31 +39,28 @@ export class DonationService {
return this.repo.count();
}

async create(
foodManufacturerId: number,
dateDonated: Date,
status: DonationStatus,
totalItems: number,
totalOz: number,
totalEstimatedValue: number,
) {
validateId(foodManufacturerId, 'Food Manufacturer');
async create(donationData: CreateDonationDto): Promise<Donation> {
validateId(donationData.foodManufacturerId, 'Food Manufacturer');
const manufacturer = await this.manufacturerRepo.findOne({
where: { foodManufacturerId },
where: { foodManufacturerId: donationData.foodManufacturerId },
});

if (!manufacturer) {
throw new NotFoundException(
`Food Manufacturer ${foodManufacturerId} not found`,
`Food Manufacturer ${donationData.foodManufacturerId} not found`,
);
}
const donation = this.repo.create({
foodManufacturer: manufacturer,
dateDonated,
status,
totalItems,
totalOz,
totalEstimatedValue,
dateDonated: donationData.dateDonated,
status: donationData.status,
totalItems: donationData.totalItems,
totalOz: donationData.totalOz,
totalEstimatedValue: donationData.totalEstimatedValue,
recurrence: donationData.recurrence,
recurrenceFreq: donationData.recurrenceFreq,
nextDonationDates: donationData.nextDonationDates,
occurrencesRemaining: donationData.occurrencesRemaining,
});

return this.repo.save(donation);
Expand Down
64 changes: 64 additions & 0 deletions apps/backend/src/donations/dtos/create-donation.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import {
ArrayNotEmpty,
IsArray,
IsDate,
IsEnum,
IsNotEmpty,
IsNumber,
IsOptional,
Min,
ValidateIf,
} from 'class-validator';
import { DonationStatus, RecurrenceEnum } from '../types';
import { Type } from 'class-transformer';

export class CreateDonationDto {
@IsNumber()
@Min(1)
foodManufacturerId!: number;

@Type(() => Date)
@IsDate()
@IsNotEmpty()
dateDonated!: Date;

@IsNotEmpty()
@IsEnum(DonationStatus)
status!: DonationStatus;

@IsNumber()
@Min(1)
@IsOptional()
totalItems?: number;

@IsNumber({ maxDecimalPlaces: 2 })
@Min(0.01)
@IsOptional()
totalOz?: number;

@IsNumber({ maxDecimalPlaces: 2 })
@Min(0.01)
@IsOptional()
totalEstimatedValue?: number;

@IsNotEmpty()
@IsEnum(RecurrenceEnum)
recurrence!: RecurrenceEnum;

@IsNumber()
@ValidateIf((o) => o.recurrence !== RecurrenceEnum.NONE)
@Min(1)
recurrenceFreq?: number;

@Type(() => Date)
@IsArray()
@ArrayNotEmpty()
@IsDate({ each: true })
@ValidateIf((o) => o.recurrence !== RecurrenceEnum.NONE)
nextDonationDates?: Date[];

@IsNumber()
@ValidateIf((o) => o.recurrence !== RecurrenceEnum.NONE)
@Min(1)
occurrencesRemaining?: number;
}
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 {
NONE = 'none',
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 (
'none',
'weekly',
'monthly',
'yearly'
);
`);

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

await queryRunner.query(`
ALTER TABLE donations
ADD CONSTRAINT recurrence_fields_not_null CHECK (
(recurrence = 'none'
AND recurrence_freq IS NULL
AND next_donation_dates IS NULL
AND occurrences_remaining IS NULL)
OR
(recurrence != 'none'
AND recurrence_freq IS NOT NULL
AND next_donation_dates IS NOT NULL
AND occurrences_remaining 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 occurrences_remaining;

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

export enum RecurrenceEnum {
NONE = 'none',
WEEKLY = 'weekly',
MONTHLY = 'monthly',
YEARLY = 'yearly',
}

export interface Donation {
donationId: number;
dateDonated: string;
Expand All @@ -110,6 +117,10 @@ export interface Donation {
totalOz: number;
totalEstimatedValue: number;
foodManufacturer?: FoodManufacturer;
recurrence: RecurrenceEnum;
recurrenceFreq?: number;
nextDonationDates?: string[];
occurrencesRemaining?: number;
}

export interface DonationItem {
Expand Down