Skip to content
Merged
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
21 changes: 19 additions & 2 deletions src/services/generalItemRequestService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from "@/types/api/donorOffer.types";
import { Filters } from "@/types/api/filter.types";
import { buildQueryWithPagination, buildWhereFromFilters } from "@/util/table";
import { WishlistService } from "./wishlistService";

export class GeneralItemRequestService {
static async getById(id: number) {
Expand Down Expand Up @@ -250,6 +251,22 @@ export class GeneralItemRequestService {
)
);

// After persisting final quantities, auto-populate wishlists for any
// requests that were not fully fulfilled (finalQuantity < quantity).
const unfulfilledUpdates = updates.filter(({ requestId, finalQuantity }) => {
const request = requests.find(r => r.id === requestId);
return request && finalQuantity < request.quantity;
});

if (unfulfilledUpdates.length > 0) {
try {
await WishlistService.createUnfulfilledWishlistEntries(unfulfilledUpdates);
} catch (error) {
// Log but don't fail the bulk update if wishlist creation errors
console.error("Failed to create unfulfilled wishlist entries:", error);
}
}
Comment thread
greptile-apps[bot] marked this conversation as resolved.
Outdated

return results;
}

Expand Down Expand Up @@ -279,7 +296,7 @@ export class GeneralItemRequestService {

const previousGeneralItemId = existingRequest.generalItem.id;

const targetGeneralItem = await tx.generalItem.findUnique({
const targetGeneralItem = await tx.generalItem.findFirst({
Comment thread
greptile-apps[bot] marked this conversation as resolved.
Outdated
where: { id: targetGeneralItemId },
select: {
id: true,
Expand Down Expand Up @@ -537,4 +554,4 @@ export class GeneralItemRequestService {
total,
};
}
}
}
90 changes: 89 additions & 1 deletion src/services/wishlistService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { Prisma } from "@prisma/client";
import { PrismaClientKnownRequestError } from "@prisma/client/runtime/library";
import { MatchingService } from "./matchingService";

const AUTO_GENERATED_COMMENT = "Automatically generated due to unfulfilled request";

export class WishlistService {
static async createWishlist(data: CreateWishlistData) {
const partner = await db.user.findUnique({
Expand Down Expand Up @@ -42,6 +44,92 @@ export class WishlistService {
return wishlist;
}

/**
* For each request where finalQuantity < quantity, automatically creates or
* updates a wishlist entry for the partner with the unfulfilled quantity.
* If an entry with the same name already exists for the partner, the
* unfulfilled quantity is added to it.
*/
Comment on lines +47 to +52

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

JSDoc comment contradicts actual implementation

The doc says "the unfulfilled quantity is added to it", but line 83 does data: { quantity: unfulfilledQuantity } which replaces the existing quantity rather than incrementing it. The PR description also describes the additive behavior. The comment should be corrected to match the code's actual semantics:

 * If an entry with the same name already exists for the partner, its
 * quantity is replaced with the new unfulfilled quantity.

static async createUnfulfilledWishlistEntries(
requests: Array<{
requestId: number;
finalQuantity: number;
}>
): Promise<void> {
if (requests.length === 0) return;

const requestIds = requests.map((r) => r.requestId);

const fullRequests = await db.generalItemRequest.findMany({
where: { id: { in: requestIds } },
include: {
generalItem: {
select: { title: true },
},
partner: {
select: { id: true, enabled: true, pending: true },
},
},
});

for (const update of requests) {
const request = fullRequests.find((r) => r.id === update.requestId);
if (!request) continue;

// Skip inactive partners
if (!request.partner.enabled || request.partner.pending) continue;

const unfulfilledQuantity = request.quantity - update.finalQuantity;
if (unfulfilledQuantity <= 0) continue;

const itemName = request.generalItem.title;
const partnerId = request.partner.id;
const priority = request.priority ?? "LOW";

// Check if a wishlist entry with the same name already exists
const existing = await db.wishlist.findFirst({
where: {
partnerId,
name: itemName,
generalItemId: null, // only unfulfilled wishlist entries
},
});

if (existing) {
// Add quantities together
await db.wishlist.update({
where: { id: existing.id },
data: {
quantity: (existing.quantity ?? 0) + unfulfilledQuantity,
},
});
Comment thread
greptile-apps[bot] marked this conversation as resolved.
Outdated
} else {
// Create a new wishlist entry
const wishlist = await db.wishlist.create({
data: {
name: itemName,
quantity: unfulfilledQuantity,
priority,
comments: AUTO_GENERATED_COMMENT,
partnerId,
},
});

try {
await MatchingService.add({
wishlistId: wishlist.id,
title: wishlist.name,
});
} catch (error) {
console.warn(
"Failed to generate embedding for auto-created wishlist entry:",
error
);
}
}
}
Comment thread
greptile-apps[bot] marked this conversation as resolved.
Outdated
}

/**
* Automatically updates lastUpdated
*/
Expand Down Expand Up @@ -247,4 +335,4 @@ export class WishlistService {
}
}
}
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Missing newline at end of file

Both wishlistService.ts and generalItemRequestService.ts now end without a trailing newline (the diff shows \ No newline at end of file). Most linters (e.g., ESLint's eol-last rule) treat this as a warning or error. Please restore the trailing newline to keep the linter happy and avoid noisy future diffs.

The same issue exists at the end of src/services/generalItemRequestService.ts.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Loading