From 95f6d954bc10af8e037b3fddc40d212a7ae914bc Mon Sep 17 00:00:00 2001 From: Jamal Soueidan Date: Fri, 15 Dec 2023 00:43:43 +0300 Subject: [PATCH 1/4] fix(get-lineitem.spec.ts): fix typo in import statement fix(get-lineitem.spec.ts): add missing import statements fix(get-lineitem.spec.ts): add missing variable declarations fix(get-lineitem.spec.ts): fix typo in variable name fix(get-lineitem.spec.ts): fix typo in variable name fix(get-lineitem.spec.ts): fix typo in variable name fix(get-lineitem.spec.ts): fix typo in variable name fix(get-lineitem.spec.ts): fix typo in variable name fix(get-lineitem.spec.ts): fix typo in variable name fix(get-lineitem.spec.ts): fix typo in variable name fix(get-lineitem.spec.ts): fix typo in variable name fix(get-lineitem.spec.ts): fix typo in variable name fix(get-lineitem.spec.ts): fix typo in variable name fix(get-lineitem.spec.ts): fix typo in variable name fix(get-lineitem.spec.ts): fix typo in variable name fix(get-line --- .../services/order/get-lineitem.spec.ts | 13 +- .../customer/services/order/get-lineitem.ts | 261 ++++++++++++------ src/functions/customer/services/order/get.ts | 41 ++- .../customer/services/order/list.spec.ts | 3 + ...data-ordre-with-fullfilment-and-refunds.ts | 2 +- 5 files changed, 234 insertions(+), 86 deletions(-) diff --git a/src/functions/customer/services/order/get-lineitem.spec.ts b/src/functions/customer/services/order/get-lineitem.spec.ts index 7e865ed7..d9883191 100644 --- a/src/functions/customer/services/order/get-lineitem.spec.ts +++ b/src/functions/customer/services/order/get-lineitem.spec.ts @@ -1,25 +1,34 @@ import { OrderModel } from "~/functions/order/order.models"; import { Order } from "~/functions/order/order.types"; import { orderWithfulfillmentAndRefunds } from "~/functions/webhook/data-ordre-with-fullfilment-and-refunds"; +import { createUser } from "~/library/jest/helpers"; +import { createLocation } from "~/library/jest/helpers/location"; import { CustomerOrderServiceGetLineItem } from "./get-lineitem"; require("~/library/jest/mongoose/mongodb.jest"); describe("CustomerOrderServiceGetLineItem", () => { it("should return order by line-item for customer", async () => { + const customerId = 7106990342471; + + const user = await createUser({ customerId }); + const location = await createLocation({ customerId }); const dumbData = Order.parse(orderWithfulfillmentAndRefunds); + dumbData.line_items[0].properties!.locationId = location._id.toString(); const response = await OrderModel.create(dumbData); const lineItemId = response.line_items[0].id; // both the beauty professional and customer can see the order const ownerCustomerId = response.customer.id; - const customerId = response.line_items[0].properties?.customerId || 0; + const beautyCustomerId = response.line_items[0].properties?.customerId || 0; let order = await CustomerOrderServiceGetLineItem({ - customerId, + customerId: beautyCustomerId, lineItemId, }); + console.log(order.line_items); + expect(order.line_items.user).toBeDefined(); expect(order.line_items.id).toEqual(lineItemId); expect(order.fulfillments.length).toBe(1); expect(order.refunds.length).toBe(1); diff --git a/src/functions/customer/services/order/get-lineitem.ts b/src/functions/customer/services/order/get-lineitem.ts index 5f404499..0a51b0a8 100644 --- a/src/functions/customer/services/order/get-lineitem.ts +++ b/src/functions/customer/services/order/get-lineitem.ts @@ -1,6 +1,28 @@ import { OrderModel } from "~/functions/order/order.models"; +import { + Order, + OrderFulfillment, + OrderLineItem, + OrderRefund, + OrderRefundLineItem, +} from "~/functions/order/order.types"; +import { User } from "~/functions/user"; import { NotFoundError } from "~/library/handler"; -import { CustomerOrderServiceListAggregate } from "./list"; + +export type CustomerOrderServiceGetLineItemAggregate = Omit< + Order, + "line_items" | "refunds" | "fulfillments" +> & { + line_items: OrderLineItem & { + user: Pick; + }; + fulfillments: Array>; + refunds: Array< + Omit & { + refund_line_items: Array>; + } + >; +}; export type CustomerOrderServiceGetLineItemProps = { customerId: number; @@ -11,78 +33,158 @@ export const CustomerOrderServiceGetLineItem = async ({ customerId, lineItemId, }: CustomerOrderServiceGetLineItemProps) => { - const orders = await OrderModel.aggregate([ - { - $match: { - $and: [ - { - $or: [ - { - "line_items.properties.customerId": customerId, + const orders = + await OrderModel.aggregate([ + { + $match: { + $and: [ + { + $or: [ + { + "line_items.properties.customerId": customerId, + }, + { + "customer.id": customerId, + }, + ], + }, + { + line_items: { + $elemMatch: { id: lineItemId }, }, - { - "customer.id": customerId, + }, + ], + }, + }, + { $unwind: "$line_items" }, + { + $match: { + $and: [ + { + $or: [ + { + "line_items.properties.customerId": customerId, + }, + { + "customer.id": customerId, + }, + ], + }, + { + "line_items.id": lineItemId, + }, + ], + }, + }, + { + $lookup: { + from: "User", + let: { customerId: "$customerId" }, + pipeline: [ + { + $match: { + $expr: { + $and: [ + { + $eq: [ + "$line_items.properties._customerId", + "$$customerId", + ], + }, + ], + }, }, - ], - }, - { - line_items: { - $elemMatch: { id: lineItemId }, }, - }, - ], + { + $project: { + customerId: 1, + username: 1, + createdAt: 1, + fullname: 1, + shortDescription: 1, + "images.profile": "$images.profile", + }, + }, + ], + as: "line_items.user", + }, + }, + { + $unwind: { + path: "$user", + preserveNullAndEmptyArrays: true, // Set to false if you always expect a match + }, }, - }, - { $unwind: "$line_items" }, - { - $match: { - $and: [ - { - $or: [ - { - "line_items.properties.customerId": customerId, + { + $lookup: { + from: "Location", + let: { locationId: "$_id" }, + pipeline: [ + { + $match: { + $expr: { + $and: [ + { + $eq: [ + { $toObjectId: "$line_items.properties.locationId" }, + "$$locationId", + ], + }, + ], + }, }, - { - "customer.id": customerId, + }, + { + $project: { + name: 1, + fullAddress: 1, + customerId: 1, }, - ], - }, - { - "line_items.id": lineItemId, - }, - ], + }, + ], + as: "line_items.location", + }, + }, + { + $unwind: { + path: "$line_items.location", + preserveNullAndEmptyArrays: true, // Set to false if you always expect a match + }, }, - }, - { - $addFields: { - refunds: { - $filter: { - input: "$refunds", - as: "refund", - cond: { - $anyElementTrue: { - $map: { - input: "$$refund.refund_line_items", - as: "refund_line_item", - in: { - $eq: ["$$refund_line_item.line_item_id", "$line_items.id"], + { + $addFields: { + refunds: { + $filter: { + input: "$refunds", + as: "refund", + cond: { + $anyElementTrue: { + $map: { + input: "$$refund.refund_line_items", + as: "refund_line_item", + in: { + $eq: [ + "$$refund_line_item.line_item_id", + "$line_items.id", + ], + }, }, }, }, }, }, - }, - fulfillments: { - $filter: { - input: "$fulfillments", - as: "fulfillment", - cond: { - $anyElementTrue: { - $map: { - input: "$$fulfillment.line_items", - as: "fulfillment_line_item", - in: { - $eq: ["$$fulfillment_line_item.id", "$line_items.id"], + fulfillments: { + $filter: { + input: "$fulfillments", + as: "fulfillment", + cond: { + $anyElementTrue: { + $map: { + input: "$$fulfillment.line_items", + as: "fulfillment_line_item", + in: { + $eq: ["$$fulfillment_line_item.id", "$line_items.id"], + }, }, }, }, @@ -90,26 +192,25 @@ export const CustomerOrderServiceGetLineItem = async ({ }, }, }, - }, - { - $project: { - id: 1, - line_items: 1, - customer: 1, - order_number: 1, - fulfillment_status: 1, - financial_status: 1, - created_at: 1, - updated_at: 1, - cancel_reason: 1, - cancelled_at: 1, - note: 1, - note_attributes: 1, - fulfillments: 1, - refunds: 1, + { + $project: { + id: 1, + line_items: 1, + customer: 1, + order_number: 1, + fulfillment_status: 1, + financial_status: 1, + created_at: 1, + updated_at: 1, + cancel_reason: 1, + cancelled_at: 1, + note: 1, + note_attributes: 1, + fulfillments: 1, + refunds: 1, + }, }, - }, - ]); + ]); if (orders.length === 0) { throw new NotFoundError([ diff --git a/src/functions/customer/services/order/get.ts b/src/functions/customer/services/order/get.ts index 0f3df212..6b46574c 100644 --- a/src/functions/customer/services/order/get.ts +++ b/src/functions/customer/services/order/get.ts @@ -1,7 +1,8 @@ import { OrderModel } from "~/functions/order/order.models"; import { OrderLineItem } from "~/functions/order/order.types"; +import { User } from "~/functions/user"; import { NotFoundError } from "~/library/handler"; -import { CustomerOrderServiceListAggregate } from "./list"; +import { CustomerOrderServiceGetLineItemAggregate } from "./get-lineitem"; export type CustomerOrderServiceGetProps = { customerId: number; @@ -13,8 +14,12 @@ export const CustomerOrderServiceGet = async ({ orderId, }: CustomerOrderServiceGetProps) => { const orders = await OrderModel.aggregate< - Omit & { - line_items: OrderLineItem[]; + Omit & { + line_items: Array< + OrderLineItem & { + user: Pick; + } + >; } >([ { @@ -37,6 +42,36 @@ export const CustomerOrderServiceGet = async ({ }, }, { $unwind: "$line_items" }, + { + $lookup: { + from: "User", + let: { customerId: "$customerId" }, + pipeline: [ + { + $match: { + $expr: { + $and: [ + { + $eq: ["$line_items.properties._customerId", "$$customerId"], + }, + ], + }, + }, + }, + { + $project: { + customerId: 1, + username: 1, + createdAt: 1, + fullname: 1, + shortDescription: 1, + "images.profile": "$images.profile", + }, + }, + ], + as: "line_items.user", + }, + }, { $addFields: { refunds: { diff --git a/src/functions/customer/services/order/list.spec.ts b/src/functions/customer/services/order/list.spec.ts index 852fb3bb..0c3ff762 100644 --- a/src/functions/customer/services/order/list.spec.ts +++ b/src/functions/customer/services/order/list.spec.ts @@ -1,11 +1,14 @@ import { OrderModel } from "~/functions/order/order.models"; import { Order } from "~/functions/order/order.types"; import { orderWithfulfillmentAndRefunds } from "~/functions/webhook/data-ordre-with-fullfilment-and-refunds"; +import { createUser } from "~/library/jest/helpers"; import { CustomerOrderServiceList } from "./list"; require("~/library/jest/mongoose/mongodb.jest"); describe("CustomerOrderServiceList", () => { it("should return orders for customer on range of start/end", async () => { + await createUser({ customerId: 7106990342471 }); + const dumbData = Order.parse(orderWithfulfillmentAndRefunds); const response = await OrderModel.create(dumbData); diff --git a/src/functions/webhook/data-ordre-with-fullfilment-and-refunds.ts b/src/functions/webhook/data-ordre-with-fullfilment-and-refunds.ts index b693c5bb..f08a5239 100644 --- a/src/functions/webhook/data-ordre-with-fullfilment-and-refunds.ts +++ b/src/functions/webhook/data-ordre-with-fullfilment-and-refunds.ts @@ -266,7 +266,7 @@ export const orderWithfulfillmentAndRefunds = { { name: "_from", value: "2023-12-18T07:00:00.000Z" }, { name: "_to", value: "2023-12-18T08:15:00.000Z" }, { name: "_customerId", value: "7106990342471" }, - { name: "Skønhedsekspert", value: "hana nielsen" }, + { name: "_locationId", value: "" }, { name: "Tid", value: "mandag, 18. december 10:00" }, { name: "Varighed", value: "1 time(r)" }, ], From 3bdba76bc98d38b7fc34675922fa1e0f189a4c46 Mon Sep 17 00:00:00 2001 From: Jamal Soueidan Date: Fri, 15 Dec 2023 08:12:27 +0300 Subject: [PATCH 2/4] feat(get-lineitem.ts): refactor CustomerOrderServiceGetLineItem to use lookup for product, location, and shipping information feat(get-lineitem.ts): add selectedOptions field to line_items in CustomerOrderServiceGetLineItemAggregate type feat(get-lineitem.ts): add ScheduleProduct type import to CustomerOrderServiceGetLineItemProps feat(get-lineitem.ts): add Schedule lookup in CustomerOrderServiceGetLineItem pipeline feat(get-lineitem.ts): add selectedOptions field to line_items in CustomerOrderServiceGetLineItem pipeline feat(get.spec.ts): add test case for CustomerOrderServiceGet function feat(customer): refactor order service get and list functions - In `get.ts`, refactor the types and interfaces to use more descriptive names and improve readability. - In `list.ts`, refactor the types and interfaces to use more descriptive names and improve readability. feat(order): refactor order types - In `order.types.ts`, remove unnecessary type annotations and improve code readability. feat(jest): add shipping helper function - Add a new helper function `createShipping` in `shipping.ts` to create a shipping object for testing purposes. --- .../controllers/order/get-lineitem.ts | 33 +---- .../customer/services/order/_types.ts | 138 ++++++++++++++++++ .../services/order/get-lineitem.spec.ts | 29 +++- .../customer/services/order/get-lineitem.ts | 95 ++++-------- .../customer/services/order/get.spec.ts | 11 +- src/functions/customer/services/order/get.ts | 56 ++----- src/functions/customer/services/order/list.ts | 19 +-- src/functions/order/order.types.ts | 2 +- src/library/jest/helpers/shipping.ts | 49 +++++++ 9 files changed, 266 insertions(+), 166 deletions(-) create mode 100644 src/functions/customer/services/order/_types.ts create mode 100644 src/library/jest/helpers/shipping.ts diff --git a/src/functions/customer/controllers/order/get-lineitem.ts b/src/functions/customer/controllers/order/get-lineitem.ts index 9c30a469..92ae3d96 100644 --- a/src/functions/customer/controllers/order/get-lineitem.ts +++ b/src/functions/customer/controllers/order/get-lineitem.ts @@ -1,10 +1,7 @@ import { z } from "zod"; -import { ShippingServiceGet } from "~/functions/shipping/services/get"; import { _ } from "~/library/handler"; import { NumberOrStringType } from "~/library/zod"; -import { CustomerLocationServiceGetOne } from "../../services/location"; import { CustomerOrderServiceGetLineItem } from "../../services/order/get-lineitem"; -import { CustomerProductServiceGet } from "../../services/product"; export type CustomerOrderControllerGetLineItemRequest = { query: z.infer; @@ -22,34 +19,6 @@ export type CustomerOrderControllerGetLineItemResponse = Awaited< export const CustomerOrderControllerGetLineItem = _( async ({ query }: CustomerOrderControllerGetLineItemRequest) => { const validateData = CustomerOrderControllerGetLineItemSchema.parse(query); - - // Should we use lookup to get product,location,shippingId? - const order = await CustomerOrderServiceGetLineItem(validateData); - - const product = await CustomerProductServiceGet({ - productId: order.line_items.product_id, - customerId: order.line_items.properties?.customerId!, - }); - - const location = await CustomerLocationServiceGetOne({ - customerId: order.line_items.properties?.customerId!, - locationId: order.line_items.properties?.locationId, - }); - - const shippingId = order.line_items.properties?.shippingId; - const shipping = shippingId - ? await ShippingServiceGet({ - shippingId: shippingId, - }) - : null; - - return { - order, - product: { - selectedOptions: product.selectedOptions, - }, - location, - shipping, - }; + return CustomerOrderServiceGetLineItem(validateData); } ); diff --git a/src/functions/customer/services/order/_types.ts b/src/functions/customer/services/order/_types.ts new file mode 100644 index 00000000..9740993f --- /dev/null +++ b/src/functions/customer/services/order/_types.ts @@ -0,0 +1,138 @@ +import { Location } from "~/functions/location"; +import { + Order, + OrderFulfillment, + OrderLineItem, + OrderRefund, + OrderRefundLineItem, +} from "~/functions/order/order.types"; +import { Shipping } from "~/functions/shipping/shipping.types"; +import { User } from "~/functions/user"; + +export type OrderLineItemsAggreate = OrderLineItem & { + user: Pick< + User, + "customerId" | "username" | "fullname" | "images" | "shortDescription" + >; + location: Pick< + Location, + "name" | "fullAddress" | "locationType" | "originType" + >; + shipping?: Pick; +}; + +export type OrderAggregate = Omit< + Order, + "line_items" | "refunds" | "fulfillments" +> & { + line_items: OrderLineItemsAggreate; + fulfillments: Array>; + refunds: Array< + Omit & { + refund_line_items: Array>; + } + >; +}; + +export const OrderLookupProperties = [ + { + $lookup: { + from: "User", + let: { customerId: "$line_items.properties.customerId" }, + pipeline: [ + { + $match: { + $expr: { + $eq: ["$customerId", "$$customerId"], + }, + }, + }, + { + $project: { + customerId: 1, + username: 1, + createdAt: 1, + fullname: 1, + shortDescription: 1, + "images.profile": "$images.profile", + }, + }, + ], + as: "line_items.user", + }, + }, + { + $unwind: { + path: "$line_items.user", + preserveNullAndEmptyArrays: true, // Set to false if you always expect a match + }, + }, + { + $lookup: { + from: "Location", + let: { locationId: "$line_items.properties.locationId" }, + pipeline: [ + { + $match: { + $expr: { + $and: [ + { + $eq: ["$_id", { $toObjectId: "$$locationId" }], + }, + ], + }, + }, + }, + { + $project: { + name: 1, + fullAddress: 1, + originType: 1, + locationType: 1, + }, + }, + ], + as: "line_items.location", + }, + }, + { + $unwind: { + path: "$line_items.location", + preserveNullAndEmptyArrays: true, // Set to false if you always expect a match + }, + }, + { + $lookup: { + from: "Shipping", + let: { shippingId: "$line_items.properties.shippingId" }, + pipeline: [ + { + $match: { + $expr: { + $and: [ + { + $eq: ["$_id", { $toObjectId: "$$shippingId" }], + }, + ], + }, + }, + }, + { + $project: { + destination: 1, + duration: 1, + distance: 1, + cost: 1, + }, + }, + ], + as: "line_items.shipping", + }, + }, + { + $unwind: { + path: "$line_items.shipping", + preserveNullAndEmptyArrays: true, + }, + }, +]; diff --git a/src/functions/customer/services/order/get-lineitem.spec.ts b/src/functions/customer/services/order/get-lineitem.spec.ts index d9883191..e7e48b11 100644 --- a/src/functions/customer/services/order/get-lineitem.spec.ts +++ b/src/functions/customer/services/order/get-lineitem.spec.ts @@ -1,24 +1,43 @@ +import { LocationTypes } from "~/functions/location"; import { OrderModel } from "~/functions/order/order.models"; import { Order } from "~/functions/order/order.types"; import { orderWithfulfillmentAndRefunds } from "~/functions/webhook/data-ordre-with-fullfilment-and-refunds"; import { createUser } from "~/library/jest/helpers"; import { createLocation } from "~/library/jest/helpers/location"; +import { createSchedule } from "~/library/jest/helpers/schedule"; +import { createShipping } from "~/library/jest/helpers/shipping"; import { CustomerOrderServiceGetLineItem } from "./get-lineitem"; require("~/library/jest/mongoose/mongodb.jest"); describe("CustomerOrderServiceGetLineItem", () => { it("should return order by line-item for customer", async () => { const customerId = 7106990342471; - const user = await createUser({ customerId }); const location = await createLocation({ customerId }); + const shipping = await createShipping({}); + + const schedule = await createSchedule( + { customerId }, + { + days: ["monday", "tuesday"], + totalProducts: 2, + locations: [ + { location: location._id, locationType: LocationTypes.ORIGIN }, + ], + } + ); + const dumbData = Order.parse(orderWithfulfillmentAndRefunds); + dumbData.line_items[0].properties!.customerId = customerId; dumbData.line_items[0].properties!.locationId = location._id.toString(); + dumbData.line_items[0].properties!.shippingId = shipping._id.toString(); + dumbData.line_items[0].product_id = schedule.products[0].productId; + dumbData.line_items[0].variant_id = schedule.products[0].variantId; + const response = await OrderModel.create(dumbData); const lineItemId = response.line_items[0].id; - // both the beauty professional and customer can see the order const ownerCustomerId = response.customer.id; const beautyCustomerId = response.line_items[0].properties?.customerId || 0; @@ -27,8 +46,10 @@ describe("CustomerOrderServiceGetLineItem", () => { lineItemId, }); - console.log(order.line_items); - expect(order.line_items.user).toBeDefined(); + expect(order.line_items.selectedOptions).toBeDefined(); + expect(order.line_items.location).toBeDefined(); + expect(order.line_items.shipping).toBeDefined(); + expect(order.line_items.user.customerId).toBe(user.customerId); expect(order.line_items.id).toEqual(lineItemId); expect(order.fulfillments.length).toBe(1); expect(order.refunds.length).toBe(1); diff --git a/src/functions/customer/services/order/get-lineitem.ts b/src/functions/customer/services/order/get-lineitem.ts index 0a51b0a8..b38027ef 100644 --- a/src/functions/customer/services/order/get-lineitem.ts +++ b/src/functions/customer/services/order/get-lineitem.ts @@ -1,27 +1,17 @@ import { OrderModel } from "~/functions/order/order.models"; -import { - Order, - OrderFulfillment, - OrderLineItem, - OrderRefund, - OrderRefundLineItem, -} from "~/functions/order/order.types"; -import { User } from "~/functions/user"; +import { ScheduleProduct } from "~/functions/schedule"; import { NotFoundError } from "~/library/handler"; +import { + OrderAggregate, + OrderLineItemsAggreate, + OrderLookupProperties, +} from "./_types"; export type CustomerOrderServiceGetLineItemAggregate = Omit< - Order, - "line_items" | "refunds" | "fulfillments" + OrderAggregate, + "line_items" > & { - line_items: OrderLineItem & { - user: Pick; - }; - fulfillments: Array>; - refunds: Array< - Omit & { - refund_line_items: Array>; - } - >; + line_items: OrderLineItemsAggreate & Pick; }; export type CustomerOrderServiceGetLineItemProps = { @@ -76,79 +66,44 @@ export const CustomerOrderServiceGetLineItem = async ({ ], }, }, + ...OrderLookupProperties, + { $lookup: { - from: "User", - let: { customerId: "$customerId" }, + from: "Schedule", + let: { + productId: "$line_items.product_id", + variantId: "$line_items.variant_id", + }, pipeline: [ { - $match: { - $expr: { - $and: [ - { - $eq: [ - "$line_items.properties._customerId", - "$$customerId", - ], - }, - ], - }, - }, - }, - { - $project: { - customerId: 1, - username: 1, - createdAt: 1, - fullname: 1, - shortDescription: 1, - "images.profile": "$images.profile", - }, + $unwind: "$products", }, - ], - as: "line_items.user", - }, - }, - { - $unwind: { - path: "$user", - preserveNullAndEmptyArrays: true, // Set to false if you always expect a match - }, - }, - { - $lookup: { - from: "Location", - let: { locationId: "$_id" }, - pipeline: [ { $match: { $expr: { $and: [ - { - $eq: [ - { $toObjectId: "$line_items.properties.locationId" }, - "$$locationId", - ], - }, + { $eq: ["$products.productId", "$$productId"] }, + { $eq: ["$products.variantId", "$$variantId"] }, ], }, }, }, { $project: { - name: 1, - fullAddress: 1, - customerId: 1, + name: "$products.selectedOptions.name", + value: "$products.selectedOptions.value", + _id: 0, }, }, ], - as: "line_items.location", + as: "line_items.selectedOptions", }, }, { $unwind: { - path: "$line_items.location", - preserveNullAndEmptyArrays: true, // Set to false if you always expect a match + path: "$line_items.selectedOptions", + preserveNullAndEmptyArrays: true, }, }, { diff --git a/src/functions/customer/services/order/get.spec.ts b/src/functions/customer/services/order/get.spec.ts index f7fc564c..5548bf06 100644 --- a/src/functions/customer/services/order/get.spec.ts +++ b/src/functions/customer/services/order/get.spec.ts @@ -1,19 +1,26 @@ import { OrderModel } from "~/functions/order/order.models"; import { Order } from "~/functions/order/order.types"; import { orderWithfulfillmentAndRefunds } from "~/functions/webhook/data-ordre-with-fullfilment-and-refunds"; +import { createUser } from "~/library/jest/helpers"; +import { createLocation } from "~/library/jest/helpers/location"; import { CustomerOrderServiceGet } from "./get"; require("~/library/jest/mongoose/mongodb.jest"); describe("CustomerOrderServiceGet", () => { it("should return order by line-item for customer", async () => { + const customerId = 7106990342471; + const user = await createUser({ customerId }); + const location = await createLocation({ customerId }); const dumbData = Order.parse(orderWithfulfillmentAndRefunds); + dumbData.line_items[0].properties!.customerId = customerId; + dumbData.line_items[0].properties!.locationId = location._id.toString(); const response = await OrderModel.create(dumbData); const orderId = response.id; - const customerId = response.customer.id; + const ownerCustomerId = response.customer.id; const order = await CustomerOrderServiceGet({ - customerId, + customerId: ownerCustomerId, orderId, }); diff --git a/src/functions/customer/services/order/get.ts b/src/functions/customer/services/order/get.ts index 6b46574c..9700edb5 100644 --- a/src/functions/customer/services/order/get.ts +++ b/src/functions/customer/services/order/get.ts @@ -1,8 +1,17 @@ import { OrderModel } from "~/functions/order/order.models"; -import { OrderLineItem } from "~/functions/order/order.types"; -import { User } from "~/functions/user"; import { NotFoundError } from "~/library/handler"; -import { CustomerOrderServiceGetLineItemAggregate } from "./get-lineitem"; +import { + OrderAggregate, + OrderLineItemsAggreate, + OrderLookupProperties, +} from "./_types"; + +export type CustomerOrderServiceGetAggregate = Omit< + OrderAggregate, + "line_items" +> & { + line_items: Array; +}; export type CustomerOrderServiceGetProps = { customerId: number; @@ -13,15 +22,7 @@ export const CustomerOrderServiceGet = async ({ customerId, orderId, }: CustomerOrderServiceGetProps) => { - const orders = await OrderModel.aggregate< - Omit & { - line_items: Array< - OrderLineItem & { - user: Pick; - } - >; - } - >([ + const orders = await OrderModel.aggregate([ { $match: { $and: [ @@ -42,36 +43,7 @@ export const CustomerOrderServiceGet = async ({ }, }, { $unwind: "$line_items" }, - { - $lookup: { - from: "User", - let: { customerId: "$customerId" }, - pipeline: [ - { - $match: { - $expr: { - $and: [ - { - $eq: ["$line_items.properties._customerId", "$$customerId"], - }, - ], - }, - }, - }, - { - $project: { - customerId: 1, - username: 1, - createdAt: 1, - fullname: 1, - shortDescription: 1, - "images.profile": "$images.profile", - }, - }, - ], - as: "line_items.user", - }, - }, + ...OrderLookupProperties, { $addFields: { refunds: { diff --git a/src/functions/customer/services/order/list.ts b/src/functions/customer/services/order/list.ts index 2e13dd49..169dab56 100644 --- a/src/functions/customer/services/order/list.ts +++ b/src/functions/customer/services/order/list.ts @@ -1,11 +1,6 @@ import { OrderModel } from "~/functions/order/order.models"; -import { - Order, - OrderFulfillment, - OrderLineItem, - OrderRefund, - OrderRefundLineItem, -} from "~/functions/order/order.types"; +import { OrderLineItem } from "~/functions/order/order.types"; +import { OrderAggregate } from "./_types"; export type CustomerOrderServiceListProps = { customerId: number; @@ -14,19 +9,13 @@ export type CustomerOrderServiceListProps = { }; export type CustomerOrderServiceListAggregate = Omit< - Order, - "line_items" | "refunds" | "fulfillments" + OrderAggregate, + "line_items" > & { start: Date; end: Date; title: Date; line_items: OrderLineItem; - fulfillments: Array>; - refunds: Array< - Omit & { - refund_line_items: Array>; - } - >; }; export const CustomerOrderServiceList = async ({ diff --git a/src/functions/order/order.types.ts b/src/functions/order/order.types.ts index 28335d0d..58e1600c 100644 --- a/src/functions/order/order.types.ts +++ b/src/functions/order/order.types.ts @@ -97,7 +97,7 @@ interface Properties { } const propertiesSchema = z.array(propertySchema).transform((properties) => { - return properties.reduce((acc: Properties, property) => { + return properties.reduce((acc, property) => { const keyWithoutUnderscore = property.name.replace( /^_/, "" diff --git a/src/library/jest/helpers/shipping.ts b/src/library/jest/helpers/shipping.ts new file mode 100644 index 00000000..28a206ec --- /dev/null +++ b/src/library/jest/helpers/shipping.ts @@ -0,0 +1,49 @@ +import { faker } from "@faker-js/faker"; +import mongoose from "mongoose"; +import { + Location, + LocationOriginTypes, + LocationTypes, +} from "~/functions/location/location.types"; +import { ShippingModel } from "~/functions/shipping/shipping.model"; +import { Shipping } from "~/functions/shipping/shipping.types"; + +export const DEFAULT_GROUP = "all"; + +const getOriginObject = (props: Partial = {}): Location => ({ + name: faker.person.firstName(), + customerId: faker.number.int({ min: 1, max: 100000 }), + locationType: LocationTypes.ORIGIN, + originType: LocationOriginTypes.COMMERCIAL, + fullAddress: faker.location.streetAddress(), + distanceHourlyRate: faker.number.int({ min: 1, max: 5 }), + fixedRatePerKm: faker.number.int({ min: 1, max: 5 }), + distanceForFree: faker.number.int({ min: 1, max: 5 }), + maxDriveDistance: 500, + minDriveDistance: 0, + startFee: 0, + ...props, +}); + +export const createShipping = (filter: Partial) => { + const shipping = new ShippingModel(); + shipping.location = new mongoose.Types.ObjectId(); + shipping.origin = getOriginObject({}); + shipping.destination = { + name: faker.word.sample(), + fullAddress: faker.word.conjunction(), + }; + shipping.duration = { + text: "123 km", + value: 1, + }; + shipping.distance = { + text: "123 km", + value: 1, + }; + shipping.cost = { + currency: "DKK", + value: 123, + }; + return shipping.save(); +}; From d5b2b220ebeb4f19f27f96cb3c18d1907b87d2d3 Mon Sep 17 00:00:00 2001 From: Jamal Soueidan Date: Fri, 15 Dec 2023 08:31:38 +0300 Subject: [PATCH 3/4] feat(openapi): add base-location.yaml for customer location types fix(openapi): update location.yaml to include base-location.yaml fix(openapi): remove discount.yaml from order types feat(openapi): add line-item-with-lookup.yaml for order line items with user and location fix(openapi): update line-item.yaml to include variant_id property feat(openapi): add user.yaml for order user information fix(openapi): update get-line-item.yaml to include line-items property with line-item-with-lookup.yaml feat(openapi): add get.yaml for order get response with line items feat(openapi): add list.yaml for order list response with line items feat(openapi): add cost-destination.yaml for shipping cost and destination fix(openapi): update shipping.yaml to include cost-destination.yaml --- .../location/_types/base-location.yaml | 22 +++++ .../customer/location/_types/location.yaml | 91 ++++++++----------- .../paths/customer/order/_types/discount.yaml | 12 --- .../order/_types/line-item-with-lookup.yaml | 15 +++ .../customer/order/_types/line-item.yaml | 2 +- openapi/paths/customer/order/_types/user.yaml | 29 ++++++ .../order/get-line-item/get-line-item.yaml | 30 +++--- .../get.yaml} | 5 +- .../paths/customer/order/get/response.yaml | 2 +- .../list.yaml} | 2 +- .../paths/customer/order/list/response.yaml | 2 +- .../shipping/_types/cost-destination.yaml | 25 +++++ openapi/paths/shipping/_types/shipping.yaml | 23 +---- 13 files changed, 150 insertions(+), 110 deletions(-) create mode 100644 openapi/paths/customer/location/_types/base-location.yaml delete mode 100644 openapi/paths/customer/order/_types/discount.yaml create mode 100644 openapi/paths/customer/order/_types/line-item-with-lookup.yaml create mode 100644 openapi/paths/customer/order/_types/user.yaml rename openapi/paths/customer/order/{_types/order-array-line-items.yaml => get/get.yaml} (59%) rename openapi/paths/customer/order/{_types/order-single-line-item.yaml => list/list.yaml} (79%) create mode 100644 openapi/paths/shipping/_types/cost-destination.yaml diff --git a/openapi/paths/customer/location/_types/base-location.yaml b/openapi/paths/customer/location/_types/base-location.yaml new file mode 100644 index 00000000..c060f885 --- /dev/null +++ b/openapi/paths/customer/location/_types/base-location.yaml @@ -0,0 +1,22 @@ +type: object +properties: + locationType: + type: string + enum: [origin, destination] + customerId: + type: string + format: gid + originType: + type: string + enum: [home, commercial] + name: + type: string + fullAddress: + type: string + +required: + - locationType + - originType + - customerId + - name + - fullAddress diff --git a/openapi/paths/customer/location/_types/location.yaml b/openapi/paths/customer/location/_types/location.yaml index b1a5cad9..806560da 100644 --- a/openapi/paths/customer/location/_types/location.yaml +++ b/openapi/paths/customer/location/_types/location.yaml @@ -1,57 +1,42 @@ type: object -properties: - _id: - type: string - locationType: - type: string - enum: [origin, destination] - customerId: - type: string - format: gid - originType: - type: string - enum: [home, commercial] - name: - type: string - fullAddress: - type: string - geoLocation: - type: object - required: - - type - - coordinates +allOf: + - $ref: ./location.yaml + - type: object properties: - type: + _id: type: string - enum: ["Point"] - coordinates: - type: array - items: - type: number - distanceForFree: - type: number - distanceHourlyRate: - type: number - fixedRatePerKm: - type: number - minDriveDistance: - type: number - maxDriveDistance: - type: number - startFee: - type: number + geoLocation: + type: object + required: + - type + - coordinates + properties: + type: + type: string + enum: ["Point"] + coordinates: + type: array + items: + type: number + distanceForFree: + type: number + distanceHourlyRate: + type: number + fixedRatePerKm: + type: number + minDriveDistance: + type: number + maxDriveDistance: + type: number + startFee: + type: number -required: - - _id - - locationType - - originType - - customerId - - name - - fullAddress - - geoLocation - - distanceForFree - - distanceHourlyRate - - fixedRatePerKm - - minDriveDistance - - maxDriveDistance - - startFee + required: + - _id + - geoLocation + - distanceForFree + - distanceHourlyRate + - fixedRatePerKm + - minDriveDistance + - maxDriveDistance + - startFee diff --git a/openapi/paths/customer/order/_types/discount.yaml b/openapi/paths/customer/order/_types/discount.yaml deleted file mode 100644 index 9be0a3ff..00000000 --- a/openapi/paths/customer/order/_types/discount.yaml +++ /dev/null @@ -1,12 +0,0 @@ -type: object -properties: - code: - type: string - amount: - type: string - type: - type: string -required: - - code - - amount - - type diff --git a/openapi/paths/customer/order/_types/line-item-with-lookup.yaml b/openapi/paths/customer/order/_types/line-item-with-lookup.yaml new file mode 100644 index 00000000..127ef6a9 --- /dev/null +++ b/openapi/paths/customer/order/_types/line-item-with-lookup.yaml @@ -0,0 +1,15 @@ +allOf: + - $ref: line-item.yaml + - type: object + properties: + user: + $ref: ../_types/user.yaml + location: + $ref: ../../location/_types/base-location.yaml + shipping: + allOf: + - $ref: ../../../location/_types/travel-time.yaml + - $ref: ../../../shipping/_types/cost-destination.yaml + required: + - user + - location diff --git a/openapi/paths/customer/order/_types/line-item.yaml b/openapi/paths/customer/order/_types/line-item.yaml index 3bcedcee..9cea2254 100644 --- a/openapi/paths/customer/order/_types/line-item.yaml +++ b/openapi/paths/customer/order/_types/line-item.yaml @@ -44,7 +44,6 @@ properties: $ref: money.yaml variant_id: type: number - nullable: true variant_inventory_management: type: string nullable: true @@ -67,6 +66,7 @@ required: - price_set - product_exists - product_id + - variant_id - quantity - requires_shipping - taxable diff --git a/openapi/paths/customer/order/_types/user.yaml b/openapi/paths/customer/order/_types/user.yaml new file mode 100644 index 00000000..78a43e71 --- /dev/null +++ b/openapi/paths/customer/order/_types/user.yaml @@ -0,0 +1,29 @@ +type: object +properties: + customerId: + type: number + fullname: + type: string + username: + type: string + shortDescription: + type: string + images: + type: object + properties: + profile: + type: object + properties: + url: + type: string + format: uri + width: + type: integer + height: + type: integer +required: + - customerId + - fullname + - username + - shortDescription + - images diff --git a/openapi/paths/customer/order/get-line-item/get-line-item.yaml b/openapi/paths/customer/order/get-line-item/get-line-item.yaml index fa285329..87cdbf4a 100644 --- a/openapi/paths/customer/order/get-line-item/get-line-item.yaml +++ b/openapi/paths/customer/order/get-line-item/get-line-item.yaml @@ -1,19 +1,15 @@ -type: object -properties: - order: - $ref: "../_types/order-single-line-item.yaml" - product: - type: object +allOf: + - $ref: "../_types/order.yaml" + - type: object properties: - selectedOptions: - $ref: ../../schedule/_types/product-selected-options.yaml + line_items: + allOf: + - $ref: ../_types/line-item-with-lookup.yaml + - type: object + properties: + selectedOptions: + $ref: ../_types/user.yaml + required: + - selectedOptions required: - - selectedOptions - location: - $ref: ../../location/_types/location-is-default.yaml - shipping: - $ref: ../../../shipping/_types/shipping.yaml -required: - - order - - product - - location + - line_items diff --git a/openapi/paths/customer/order/_types/order-array-line-items.yaml b/openapi/paths/customer/order/get/get.yaml similarity index 59% rename from openapi/paths/customer/order/_types/order-array-line-items.yaml rename to openapi/paths/customer/order/get/get.yaml index f255d355..cf3d051e 100644 --- a/openapi/paths/customer/order/_types/order-array-line-items.yaml +++ b/openapi/paths/customer/order/get/get.yaml @@ -1,10 +1,11 @@ allOf: - - $ref: "./order.yaml" + - $ref: "../_types/order.yaml" - type: object properties: line_items: type: array items: - $ref: ../_types/line-item.yaml + $ref: ../_types/line-item-with-lookup.yaml + required: - line_items diff --git a/openapi/paths/customer/order/get/response.yaml b/openapi/paths/customer/order/get/response.yaml index 5df41990..cf57f2b7 100644 --- a/openapi/paths/customer/order/get/response.yaml +++ b/openapi/paths/customer/order/get/response.yaml @@ -4,7 +4,7 @@ properties: type: boolean example: true payload: - $ref: "../_types/order-array-line-items.yaml" + $ref: get.yaml required: - success - payload diff --git a/openapi/paths/customer/order/_types/order-single-line-item.yaml b/openapi/paths/customer/order/list/list.yaml similarity index 79% rename from openapi/paths/customer/order/_types/order-single-line-item.yaml rename to openapi/paths/customer/order/list/list.yaml index 051de835..78e3a0a2 100644 --- a/openapi/paths/customer/order/_types/order-single-line-item.yaml +++ b/openapi/paths/customer/order/list/list.yaml @@ -1,5 +1,5 @@ allOf: - - $ref: "./order.yaml" + - $ref: "../_types/order.yaml" - type: object properties: line_items: diff --git a/openapi/paths/customer/order/list/response.yaml b/openapi/paths/customer/order/list/response.yaml index 4db269c7..eb232183 100644 --- a/openapi/paths/customer/order/list/response.yaml +++ b/openapi/paths/customer/order/list/response.yaml @@ -6,7 +6,7 @@ properties: payload: type: array items: - $ref: "../_types/order-single-line-item.yaml" + $ref: list.yaml required: - success - payload diff --git a/openapi/paths/shipping/_types/cost-destination.yaml b/openapi/paths/shipping/_types/cost-destination.yaml new file mode 100644 index 00000000..f102ac6b --- /dev/null +++ b/openapi/paths/shipping/_types/cost-destination.yaml @@ -0,0 +1,25 @@ +type: object +properties: + destination: + type: object + properties: + name: + type: string + fullAddress: + type: string + required: + - name + - fullAddress + cost: + type: object + properties: + currency: + type: string + value: + type: integer + required: + - currency + - value +required: + - destination + - cost diff --git a/openapi/paths/shipping/_types/shipping.yaml b/openapi/paths/shipping/_types/shipping.yaml index ba3ccf51..eb67f7e2 100644 --- a/openapi/paths/shipping/_types/shipping.yaml +++ b/openapi/paths/shipping/_types/shipping.yaml @@ -1,6 +1,7 @@ type: object allOf: - $ref: ../../location/_types/travel-time.yaml + - $ref: cost-destination.yaml - type: object properties: _id: @@ -9,29 +10,7 @@ allOf: type: string origin: $ref: ../../customer/location/_types/location.yaml - destination: - type: object - properties: - name: - type: string - fullAddress: - type: string - required: - - name - - fullAddress - cost: - type: object - properties: - currency: - type: string - value: - type: integer - required: - - currency - - value required: - _id - location - origin - - destination - - cost From be93d453d21a5aff79715fbf1844f550df214cfa Mon Sep 17 00:00:00 2001 From: Jamal Soueidan Date: Fri, 15 Dec 2023 08:31:53 +0300 Subject: [PATCH 4/4] update openapi --- openapi/openapi.yaml | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index 36f3f318..385314a9 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -106,18 +106,12 @@ components: # Order CustomerOrder: $ref: paths/customer/order/_types/order.yaml - CustomerOrderArrayLineItems: - $ref: paths/customer/order/_types/order-array-line-items.yaml - CustomerOrderSingleLineItem: - $ref: paths/customer/order/_types/order-single-line-item.yaml CustomerOrderMoney: $ref: paths/customer/order/_types/money.yaml CustomerOrderAddress: $ref: paths/customer/order/_types/address.yaml CustomerOrderClient: $ref: paths/customer/order/_types/client.yaml - CustomerOrderDiscount: - $ref: paths/customer/order/_types/discount.yaml CustomerOrderLineItemProperties: $ref: paths/customer/order/_types/properties.yaml CustomerOrderSimpleLineItem: @@ -126,6 +120,8 @@ components: $ref: paths/customer/order/_types/customer.yaml CustomerOrderLineItem: $ref: paths/customer/order/_types/line-item.yaml + CustomerOrderLineItemLookup: + $ref: paths/customer/order/_types/line-item-with-lookup.yaml CustomerOrderRefund: $ref: paths/customer/order/_types/refund.yaml CustomerOrderShipping: @@ -136,8 +132,12 @@ components: $ref: paths/customer/order/get-line-item/get-line-item.yaml CustomerOrderGetLineItemResponse: $ref: paths/customer/order/get-line-item/response.yaml + CustomerOrderGet: + $ref: paths/customer/order/get/get.yaml CustomerOrderGetResponse: $ref: paths/customer/order/get/response.yaml + CustomerOrderList: + $ref: paths/customer/order/list/list.yaml CustomerOrderListResponse: $ref: paths/customer/order/list/response.yaml @@ -165,6 +165,8 @@ components: CustomerProductListResponse: $ref: paths/customer/product/list/response.yaml + CustomerLocationBase: + $ref: paths/customer/location/_types/base-location.yaml CustomerLocation: $ref: paths/customer/location/_types/location.yaml CustomerLocationIsDefault: @@ -255,6 +257,8 @@ components: # Shipping Shipping: $ref: paths/shipping/_types/shipping.yaml + ShippingCostDestination: + $ref: paths/shipping/_types/cost-destination.yaml ShippingBody: $ref: paths/shipping/_types/body.yaml ShippingCreateResponse: