Skip to content

Comments

[SSF-125] Move Food Request Fields#100

Open
Tarun-Nagesh wants to merge 16 commits intomainfrom
TN/SSF-125-move-food-request-fields
Open

[SSF-125] Move Food Request Fields#100
Tarun-Nagesh wants to merge 16 commits intomainfrom
TN/SSF-125-move-food-request-fields

Conversation

@Tarun-Nagesh
Copy link

ℹ️ Issue

Closes SSF-125

📝 Description

Moved delivery confirmation fields from Food Requests to Orders and implemented request status logic. This change reflects where delivery details are specific to individual orders instead of the entire request.

Backend Changes:

  1. Created TypeORM migration to move dateReceived, feedback, and photos fields from food_requests table to orders table
  2. Added status field to FoodRequest entity with enum values ACTIVE and CLOSED
  3. Moved confirm delivery endpoint from requests to orders: POST /api/orders/:orderId/confirm-delivery (previously POST /api/requests/:requestId/confirm-delivery)
  4. Implemented automatic request status updates - request closes when all its orders are delivered
  5. Fixed TypeScript compilation by defining local MulterFile interface in aws-s3.service.ts (could be changed later with tsconfig fix instead)

✔️ Verification

  1. Ran migration with yarn typeorm:migrate
  2. Tested confirm delivery endpoint via PowerShell
  3. All tests passing (added new tests for confirm delivery logic)

Copy link

@dburkhart07 dburkhart07 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some initial comments. Good first pass though! 🥇

})
deliveredAt: Date | null;

@Column({ name: 'date_received', type: 'timestamp', nullable: true })

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are trying to enforce strict type, so we need to give everything a ! for required fields, and ? for optional. So let's add 3 ?s here.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unresolving this.

Copy link

@dburkhart07 dburkhart07 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

few more small things. looks great so far!!

@maxn990 maxn990 requested a review from dburkhart07 February 23, 2026 18:50
Copy link

@dburkhart07 dburkhart07 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

few more things, and just some questions that i wanted your opinions on. looking beautiful so far ⛱️

@maxn990 maxn990 requested a review from dburkhart07 February 24, 2026 01:47
Copy link

@dburkhart07 dburkhart07 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One more thing, but looks good.

})
deliveredAt: Date | null;

@Column({ name: 'date_received', type: 'timestamp', nullable: true })

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unresolving this.

feedback?: string | null;

@Column({ name: 'photos', type: 'text', array: true, nullable: true })
photos?: string[];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add | null here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another thing tarun had put and dalton asked to be removed, i agree with dalton here as ? implies the value can be undefined so | null isn't necessary, it also wouldn't be consistent with how the rest of the code base handles nullable fields

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Justin's strict mode PR, we're adding | null to entity fields corresponding to nullable database fields because we realized that TypeORM actually returns null, not undefined, for a null database entry. (The undefined option should only be used if you want to call a repo function with a subset of the entity fields)

@@ -0,0 +1,4 @@
export class ConfirmDeliveryDto {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use class-validator to validate the fields in this DTO, as we have for other endpoint body DTOs?

dateReceived: {
type: 'string',
format: 'date-time',
nullable: true,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pending confirmation from Priya, but assuming the date received is required as it is in the DTO, this should not be nullable here

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can assume this for now as it may need to change later based on client updates

@@ -1,5 +1,6 @@
import { Injectable } from '@nestjs/common';
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import 'multer';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary since there were no other changes to this file?


async confirmDelivery(
orderId: number,
dto: ConfirmDeliveryDto,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we pass in the individual fields rather than the DTO to limit the DTO to the controller layer?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is how Tarun originally had it, Dalton said in his review that this is not how ssf does it. I agree with you that it would generally be the case that you would want to limit the DTO to the controller layer, but overall looking at the repository it seems like DTOs are almost always passed into the service (according to Dalton this is true, I briefly looked through most of the controllers and this tends to be true). I think we should just be consistent with how this is done on the project and leave it as is

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with that for consistency, I think that started with service functions that would need to take in an impractical number of parameters (e.g., for pantry applications) and ended up spreading to almost all of our DTOs

{ dateReceived: new Date().toISOString(), feedback: 'test' },
[],
),
).rejects.toThrow(`Order ${invalidOrderId} not found`);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we check this is a NotFoundException?

{ dateReceived: 'invalid-date', feedback: 'test feedback' },
[],
),
).rejects.toThrow('Invalid date format for dateReceived');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we check this is a BadRequestException?

it('should throw BadRequestException when order is not shipped', async () => {
const orderRepo = testDataSource.getRepository(Order);

const pendingOrder = await orderRepo.findOne({
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also check that we can't re-confirm a delivered order?

const orderRepo = testDataSource.getRepository(Order);
const requestRepo = testDataSource.getRepository(FoodRequest);

const shippedOrder = await orderRepo.findOne({
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we get a specific order here? this implies that any shipped order will work for this test, which is not true since we're checking that the request is being closed

expect(updatedRequest.status).toBe(FoodRequestStatus.ACTIVE);
});

it('should set request status to CLOSED when all orders are delivered', async () => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not quite sure what the difference is in what we're checking in these two tests compared to the two previous tests?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah looks like 1 and 3 are pretty much the same, 2 is different because it is a case where there are more orders in the request

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't 4 ("should set request status to ACTIVE when not all orders are delivered") also checking essentially the same thing as 2?

@maxn990 maxn990 self-assigned this Feb 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants