Skip to content
7 changes: 6 additions & 1 deletion apps/backend/src/allocations/allocations.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,20 @@ import {
JoinColumn,
} from 'typeorm';
import { DonationItem } from '../donationItems/donationItems.entity';
import { Order } from '../orders/order.entity';

@Entity('allocations')
export class Allocation {
@PrimaryGeneratedColumn({ name: 'allocation_id' })
allocationId: number;

@Column({ name: 'order_id', type: 'int' })
@Column({ name: 'order_id', type: 'int', nullable: false })
orderId: number;

@ManyToOne(() => Order, (order) => order.allocations)
@JoinColumn({ name: 'order_id' })
order: Order;

@Column({ name: 'item_id', type: 'int', nullable: false })
itemId: number;

Expand Down
15 changes: 15 additions & 0 deletions apps/backend/src/foodRequests/dtos/order-details.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { FoodType } from '../../donationItems/types';
import { OrderStatus } from '../../orders/types';

export class OrderItemDetailsDto {
name: string;
quantity: number;
foodType: FoodType;
}

export class OrderDetailsDto {
orderId: number;
status: OrderStatus;
foodManufacturerName: string;
items: OrderItemDetailsDto[];
}
60 changes: 56 additions & 4 deletions apps/backend/src/foodRequests/request.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { Readable } from 'stream';
import { FoodRequest } from './request.entity';
import { RequestSize } from './types';
import { OrderStatus } from '../orders/types';
import { FoodType } from '../donationItems/types';
import { OrderDetailsDto } from './dtos/order-details.dto';

const mockRequestsService = mock<RequestsService>();
const mockOrdersService = mock<OrdersService>();
Expand All @@ -26,6 +28,7 @@ describe('RequestsController', () => {
mockRequestsService.find.mockReset();
mockRequestsService.create.mockReset();
mockRequestsService.updateDeliveryDetails?.mockReset();
mockRequestsService.getOrderDetails.mockReset();
mockAWSS3Service.upload.mockReset();
mockOrdersService.updateStatus.mockReset();

Expand Down Expand Up @@ -91,6 +94,55 @@ describe('RequestsController', () => {
});
});

describe('GET /all-order-details/:requestId', () => {
it('should call requestsService.getOrderDetails and return all associated orders and their details', async () => {
const mockOrderDetails: OrderDetailsDto[] = [
{
orderId: 10,
status: OrderStatus.DELIVERED,
foodManufacturerName: 'Test Manufacturer',
items: [
{
name: 'Rice',
quantity: 5,
foodType: FoodType.GRANOLA,
},
{
name: 'Beans',
quantity: 3,
foodType: FoodType.DRIED_BEANS,
},
],
},
{
orderId: 11,
status: OrderStatus.PENDING,
foodManufacturerName: 'Another Manufacturer',
items: [
{
name: 'Milk',
quantity: 2,
foodType: FoodType.DAIRY_FREE_ALTERNATIVES,
},
],
},
];

const requestId = 1;

mockRequestsService.getOrderDetails.mockResolvedValueOnce(
mockOrderDetails as OrderDetailsDto[],
);

const result = await controller.getAllOrderDetailsFromRequest(requestId);

expect(result).toEqual(mockOrderDetails);
expect(mockRequestsService.getOrderDetails).toHaveBeenCalledWith(
requestId,
);
});
});

describe('POST /create', () => {
it('should call requestsService.create and return the created food request', async () => {
const createBody: Partial<FoodRequest> = {
Expand All @@ -107,7 +159,7 @@ describe('RequestsController', () => {
requestId: 1,
...createBody,
requestedAt: new Date(),
order: null,
orders: null,
};

mockRequestsService.create.mockResolvedValueOnce(
Expand Down Expand Up @@ -181,7 +233,7 @@ describe('RequestsController', () => {
mockRequestsService.findOne.mockResolvedValue({
requestId,
pantryId: 1,
order: { orderId: 99 },
orders: [{ orderId: 99 }],
} as FoodRequest);

mockOrdersService.updateStatus.mockResolvedValue();
Expand Down Expand Up @@ -230,7 +282,7 @@ describe('RequestsController', () => {
mockRequestsService.findOne.mockResolvedValue({
requestId,
pantryId: 1,
order: { orderId: 100 },
orders: [{ orderId: 100 }],
} as FoodRequest);

mockOrdersService.updateStatus.mockResolvedValue();
Expand Down Expand Up @@ -275,7 +327,7 @@ describe('RequestsController', () => {
mockRequestsService.findOne.mockResolvedValue({
requestId,
pantryId: 1,
order: { orderId: 101 },
orders: [{ orderId: 101 }],
} as FoodRequest);

mockOrdersService.updateStatus.mockResolvedValue();
Expand Down
38 changes: 30 additions & 8 deletions apps/backend/src/foodRequests/request.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import {
UploadedFiles,
UseInterceptors,
BadRequestException,
NotFoundException,
ConflictException,
} from '@nestjs/common';
import { ApiBody } from '@nestjs/swagger';
import { RequestsService } from './request.service';
Expand All @@ -16,9 +18,9 @@ import { AWSS3Service } from '../aws/aws-s3.service';
import { FilesInterceptor } from '@nestjs/platform-express';
import * as multer from 'multer';
import { OrdersService } from '../orders/order.service';
import { Order } from '../orders/order.entity';
import { RequestSize } from './types';
import { OrderStatus } from '../orders/types';
import { OrderDetailsDto } from './dtos/order-details.dto';

@Controller('requests')
// @UseInterceptors()
Expand All @@ -43,6 +45,13 @@ export class RequestsController {
return this.requestsService.find(pantryId);
}

@Get('/all-order-details/:requestId')
async getAllOrderDetailsFromRequest(
@Param('requestId', ParseIntPipe) requestId: number,
): Promise<OrderDetailsDto[]> {
return this.requestsService.getOrderDetails(requestId);
}

@Post('/create')
@ApiBody({
description: 'Details for creating a food request',
Expand Down Expand Up @@ -109,6 +118,7 @@ export class RequestsController {
);
}

//TODO: delete endpoint, here temporarily as a logic reference for order status impl.
@Post('/:requestId/confirm-delivery')
@ApiBody({
description: 'Details for a confirmation form',
Expand Down Expand Up @@ -157,17 +167,29 @@ export class RequestsController {
photos?.length,
);

const request = await this.requestsService.findOne(requestId);
await this.ordersService.updateStatus(
request.order.orderId,
OrderStatus.DELIVERED,
);

return this.requestsService.updateDeliveryDetails(
const updatedRequest = await this.requestsService.updateDeliveryDetails(
requestId,
formattedDate,
body.feedback,
uploadedPhotoUrls,
);

if (!updatedRequest) {
throw new NotFoundException('Invalid request ID');
}

if (!updatedRequest.orders || updatedRequest.orders.length == 0) {
throw new ConflictException(
'No associated orders found for this request',
);
}

await Promise.all(
updatedRequest.orders.map((order) =>
this.ordersService.updateStatus(order.orderId, OrderStatus.DELIVERED),
),
);

return updatedRequest;
}
}
2 changes: 1 addition & 1 deletion apps/backend/src/foodRequests/request.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,5 @@ export class FoodRequest {
photos: string[];

@OneToMany(() => Order, (order) => order.request, { nullable: true })
order: Order;
orders: Order[];
}
Loading
Loading