Closed 420coupe closed 3 weeks ago
it looks like the sdk.store.cart.complete() is not returning the complete order only the order.id see response to console.log('cartRes: ', cartRes)
below.
cartRes: {
type: 'order',
order: { id: 'order_01JBG1P59HK2BX2VDG1ER21FWK' },
digital_product_order: {
id: '01JBG1P89414WC8V01QMR6PZFW',
status: 'pending',
products: [ [Object] ],
created_at: '2024-10-31T01:05:27.333Z',
updated_at: '2024-10-31T01:05:27.333Z'
}
}
any update/feedback on this?
i've tried the following adding it as part of the complete query using +shipping_address,*shipping_address,shipping_address
and none of these returned anything. Was there a change to the cart complete API that no longer returns the StoreOrder and only the order.id?
src/lib/data/cart.ts
export async function placeOrder(cartId?: string) {
const currentCartId = cartId || getCartId()
if (!currentCartId) {
throw new Error("No existing cart found when placing an order")
}
const cartRes = await sdk.store.cart
.complete(currentCartId, { fields: "shipping_address" }, getAuthHeaders())
.then((cartRes) => {
revalidateTag("cart")
return cartRes
})
.catch(medusaError)
if (cartRes?.type === "order") {
console.log("cartRes: ", cartRes)
const countryCode =
cartRes.order.shipping_address?.country_code?.toLowerCase()
removeCartId()
redirect(`/${countryCode}/order/confirmed/${cartRes?.order.id}`)
}
return cartRes.cart
}
ok think i have pin pointed the issue, i forgot i had the default endpoint overrode with the digital products recipe endpoint. It's the completeCartWorkflow is only returning the order.id when it used to return the entire order.
import {
createWorkflow,
transform,
when,
WorkflowResponse,
} from "@medusajs/framework/workflows-sdk";
import {
completeCartWorkflow,
useRemoteQueryStep,
createRemoteLinkStep,
createOrderFulfillmentWorkflow,
emitEventStep,
} from "@medusajs/medusa/core-flows";
import { Modules } from "@medusajs/framework/utils";
import createDigitalProductOrderStep from "./steps/create-digital-product-order";
import { DIGITAL_PRODUCT_MODULE } from "../../modules/digital-product";
type WorkflowInput = {
cart_id: string;
};
const createDigitalProductOrderWorkflow = createWorkflow(
"create-digital-product-order",
(input: WorkflowInput) => {
const order = completeCartWorkflow.runAsStep({
input: {
id: input.cart_id,
},
});
const { items } = useRemoteQueryStep({
entry_point: "order",
fields: [
"*",
"items.*",
"items.variant.*",
"items.variant.digital_product.*",
],
variables: {
filters: {
id: order.id,
},
},
throw_if_key_not_found: true,
list: false,
});
const itemsWithDigitalProducts = transform(
{
items,
},
(data) => {
return data.items.filter(
(item) => item.variant.digital_product !== undefined
);
}
);
const digital_product_order = when(
itemsWithDigitalProducts,
(itemsWithDigitalProducts) => {
return itemsWithDigitalProducts.length;
}
).then(() => {
const { digital_product_order } = createDigitalProductOrderStep({
items,
});
createRemoteLinkStep([
{
[DIGITAL_PRODUCT_MODULE]: {
digital_product_order_id: digital_product_order.id,
},
[Modules.ORDER]: {
order_id: order.id,
},
},
]);
createOrderFulfillmentWorkflow.runAsStep({
input: {
order_id: order.id,
items: transform(
{
itemsWithDigitalProducts,
},
(data) => {
return data.itemsWithDigitalProducts.map((item) => ({
id: item.id,
quantity: item.quantity,
}));
}
),
},
});
emitEventStep({
eventName: "digital_product_order.created",
data: {
id: digital_product_order.id,
},
});
return digital_product_order;
});
return new WorkflowResponse({
order,
digital_product_order,
});
}
);
export default createDigitalProductOrderWorkflow;
looks like commit below changed the response for completeCartWorkflow. is there a way to pass a custom query to the completeCartWorkflow to get the order.shipping_address returned
@420coupe this is intentional, as the HTTP layer can then refetch the order and also do the field selection, among other things, see https://github.com/medusajs/medusa/blob/develop/packages/medusa/src/api/store/carts/%5Bid%5D/complete/route.ts
I think you can just do the same in your HTTP route handler. I'll close this as the behavior is intended, but let me know if something doesn't work as expected.
@420coupe this is intentional, as the HTTP layer can then refetch the order and also do the field selection, among other things, see https://github.com/medusajs/medusa/blob/develop/packages/medusa/src/api/store/carts/%5Bid%5D/complete/route.ts
I think you can just do the same in your HTTP route handler. I'll close this as the behavior is intended, but let me know if something doesn't work as expected.
So how would this be resolved for the digital product recipe to get it to return the complete order instead of just the order.id?
src/workflows/create-digital-product-order/index.ts
import {
createWorkflow,
transform,
when,
WorkflowResponse,
} from "@medusajs/framework/workflows-sdk";
import {
completeCartWorkflow,
useRemoteQueryStep,
createRemoteLinkStep,
createOrderFulfillmentWorkflow,
emitEventStep,
} from "@medusajs/medusa/core-flows";
import { Modules } from "@medusajs/framework/utils";
import createDigitalProductOrderStep from "./steps/create-digital-product-order";
import { DIGITAL_PRODUCT_MODULE } from "../../modules/digital-product";
type WorkflowInput = {
cart_id: string;
};
const createDigitalProductOrderWorkflow = createWorkflow(
"create-digital-product-order",
(input: WorkflowInput) => {
const order = completeCartWorkflow.runAsStep({
input: {
id: input.cart_id,
},
});
const { items } = useRemoteQueryStep({
entry_point: "order",
fields: [
"*",
"items.*",
"items.variant.*",
"items.variant.digital_product.*",
],
variables: {
filters: {
id: order.id,
},
},
throw_if_key_not_found: true,
list: false,
});
const itemsWithDigitalProducts = transform(
{
items,
},
(data) => {
return data.items.filter(
(item) => item.variant.digital_product !== undefined
);
}
);
const digital_product_order = when(
itemsWithDigitalProducts,
(itemsWithDigitalProducts) => {
return itemsWithDigitalProducts.length;
}
).then(() => {
const { digital_product_order } = createDigitalProductOrderStep({
items,
});
createRemoteLinkStep([
{
[DIGITAL_PRODUCT_MODULE]: {
digital_product_order_id: digital_product_order.id,
},
[Modules.ORDER]: {
order_id: order.id,
},
},
]);
createOrderFulfillmentWorkflow.runAsStep({
input: {
order_id: order.id,
items: transform(
{
itemsWithDigitalProducts,
},
(data) => {
return data.itemsWithDigitalProducts.map((item) => ({
id: item.id,
quantity: item.quantity,
}));
}
),
},
});
emitEventStep({
eventName: "digital_product_order.created",
data: {
id: digital_product_order.id,
},
});
return digital_product_order;
});
return new WorkflowResponse({
order,
digital_product_order,
});
}
);
export default createDigitalProductOrderWorkflow;
src/api/store/carts/[id]/complete/route.ts
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http";
import createDigitalProductOrderWorkflow from "../../../../../workflows/create-digital-product-order";
export const POST = async (req: MedusaRequest, res: MedusaResponse) => {
const { result } = await createDigitalProductOrderWorkflow(req.scope).run({
input: {
cart_id: req.params.id,
},
});
res.json({
type: "order",
...result,
});
};
You are returning the order
in the workflow, so before res.json
you would do
const { data } = await query.graph({
entity: "order",
fields: req.remoteQueryConfig.fields,
filters: { id: result.order.id }, // or result.digital_product_order.id, depending what you want to return
})
res.json({
type: "order",
order: data,
});
but let me know if I am missing something here.
You are returning the
order
in the workflow, so beforeres.json
you would doconst { data } = await query.graph({ entity: "order", fields: req.remoteQueryConfig.fields, filters: { id: result.order.id }, // or result.digital_product_order.id, depending what you want to return }) res.json({ type: "order", order: data, });
but let me know if I am missing something here.
i was trying to avoid another query and have it return in the same original query how it did prior.
This is a common pattern we follow for most endpoints, and since it's an ID-based query it is indexed and very performant, so I wouldn't worry too much about the additional request. Eg. in this case if you have 10k orders per month, it equates to 10k additional DB queries, which is insignificant, and it doesn't make sense to prematurely optimize
Bug report
Describe the bug
When trying to complete an order and the reroute from placeOrder() the country_code is coming back undefined, but it is defined in the database entry. This is because completeCartWorkflow is only returning the order.id when it used to return the entire order.
System information
Medusa version (including plugins):
Node.js version:
v21.7.1
Database:Supabase (postgres) Operating system:
Ubuntu 22.04.4 LTS`` Browser (if relevant):Steps to reproduce the behavior
Expected behavior
When you complete the checkout it should redirect to the order/confirmed page, however it redirects to undefined/order/confrimed/[id]
Screenshots
Code snippets