feat(medusa, core-workflows, product): slightly improve create cart workflow (#5725)

This commit is contained in:
Adrien de Peretti
2023-12-07 17:05:23 +01:00
committed by GitHub
parent 946db51a9b
commit 85cda7ce37
14 changed files with 136 additions and 43 deletions
+6
View File
@@ -0,0 +1,6 @@
---
"@medusajs/medusa": patch
"@medusajs/core-flows": patch
---
slightly improve create cart workflow
@@ -5,7 +5,9 @@ import { WorkflowArguments } from "@medusajs/workflows-sdk"
type AddressesDTO = { type AddressesDTO = {
shipping_address_id?: string shipping_address_id?: string
shipping_address?: AddressDTO
billing_address_id?: string billing_address_id?: string
billing_address?: AddressDTO
} }
type HandlerInputData = { type HandlerInputData = {
@@ -48,6 +50,7 @@ export async function findOrCreateAddresses({
country_code: regionCountries[0], country_code: regionCountries[0],
}) })
addressesDTO.shipping_address = shippingAddress
addressesDTO.shipping_address_id = shippingAddress?.id addressesDTO.shipping_address_id = shippingAddress?.id
} }
} else { } else {
@@ -75,6 +78,7 @@ export async function findOrCreateAddresses({
) )
} }
addressesDTO.shipping_address = address
addressesDTO.shipping_address_id = address.id addressesDTO.shipping_address_id = address.id
} }
} }
@@ -103,6 +107,7 @@ export async function findOrCreateAddresses({
) )
} }
addressesDTO.billing_address = address
addressesDTO.billing_address_id = billingAddressId addressesDTO.billing_address_id = billingAddressId
} }
@@ -1,4 +1,4 @@
import { CartDTO } from "@medusajs/types" import { AddressDTO, CartDTO, CustomerDTO, RegionDTO } from "@medusajs/types"
import { WorkflowArguments } from "@medusajs/workflows-sdk" import { WorkflowArguments } from "@medusajs/workflows-sdk"
enum Aliases { enum Aliases {
@@ -14,14 +14,18 @@ type HandlerInputData = {
sales_channel_id?: string sales_channel_id?: string
} }
addresses: { addresses: {
shipping_address?: AddressDTO
shipping_address_id: string shipping_address_id: string
billing_address?: AddressDTO
billing_address_id: string billing_address_id: string
} }
customer: { customer: {
customer?: CustomerDTO
customer_id?: string customer_id?: string
email?: string email?: string
} }
region: { region: {
region?: RegionDTO
region_id: string region_id: string
} }
context: { context: {
@@ -1,8 +1,10 @@
import { validateEmail } from "@medusajs/utils" import { validateEmail } from "@medusajs/utils"
import { WorkflowArguments } from "@medusajs/workflows-sdk" import { WorkflowArguments } from "@medusajs/workflows-sdk"
import { CustomerTypes } from "@medusajs/types"
type CustomerDTO = { type CustomerResultDTO = {
customer?: CustomerTypes.CustomerDTO
customer_id?: string customer_id?: string
email?: string email?: string
} }
@@ -22,12 +24,12 @@ export async function findOrCreateCustomer({
container, container,
context, context,
data, data,
}: WorkflowArguments<HandlerInputData>): Promise<CustomerDTO> { }: WorkflowArguments<HandlerInputData>): Promise<CustomerResultDTO> {
const { manager } = context const { manager } = context
const customerService = container.resolve("customerService") const customerService = container.resolve("customerService")
const customerDTO: CustomerDTO = {} const customerDataDTO: CustomerResultDTO = {}
const customerId = data[Aliases.Customer].customer_id const customerId = data[Aliases.Customer].customer_id
const customerServiceTx = customerService.withTransaction(manager) const customerServiceTx = customerService.withTransaction(manager)
@@ -36,8 +38,9 @@ export async function findOrCreateCustomer({
.retrieve(customerId) .retrieve(customerId)
.catch(() => undefined) .catch(() => undefined)
customerDTO.customer_id = customer?.id customerDataDTO.customer = customer
customerDTO.email = customer?.email customerDataDTO.customer_id = customer?.id
customerDataDTO.email = customer?.email
} }
const customerEmail = data[Aliases.Customer].email const customerEmail = data[Aliases.Customer].email
@@ -53,11 +56,12 @@ export async function findOrCreateCustomer({
customer = await customerServiceTx.create({ email: validatedEmail }) customer = await customerServiceTx.create({ email: validatedEmail })
} }
customerDTO.customer_id = customer.id customerDataDTO.customer = customer
customerDTO.email = customer.email customerDataDTO.customer_id = customer.id
customerDataDTO.email = customer.email
} }
return customerDTO return customerDataDTO
} }
findOrCreateCustomer.aliases = Aliases findOrCreateCustomer.aliases = Aliases
@@ -1,10 +1,12 @@
import { MedusaError } from "@medusajs/utils" import { MedusaError } from "@medusajs/utils"
import { RegionTypes } from "@medusajs/types"
import { isDefined } from "medusa-core-utils" import { isDefined } from "medusa-core-utils"
import { WorkflowArguments } from "@medusajs/workflows-sdk" import { WorkflowArguments } from "@medusajs/workflows-sdk"
type RegionDTO = { type RegionResultDTO = {
region_id?: string region_id?: string
region?: RegionTypes.RegionDTO
} }
type HandlerInputData = { type HandlerInputData = {
@@ -20,16 +22,24 @@ enum Aliases {
export async function findRegion({ export async function findRegion({
container, container,
data, data,
}: WorkflowArguments<HandlerInputData>): Promise<RegionDTO> { }: WorkflowArguments<HandlerInputData>): Promise<RegionResultDTO> {
const regionService = container.resolve("regionService") const regionService = container.resolve("regionService")
let regionId: string let regionId: string
const regionDTO: RegionDTO = {} const regionDTO: RegionResultDTO = {}
if (isDefined(data[Aliases.Region].region_id)) { if (isDefined(data[Aliases.Region].region_id)) {
regionId = data[Aliases.Region].region_id regionDTO.region_id = data[Aliases.Region].region_id
regionDTO.region = await regionService.retrieve(regionDTO.region_id, {
relations: ["countries"],
})
} else { } else {
const regions = await regionService.list({}, {}) const regions = await regionService.list(
{},
{
relations: ["countries"],
}
)
if (!regions?.length) { if (!regions?.length) {
throw new MedusaError( throw new MedusaError(
@@ -38,11 +48,10 @@ export async function findRegion({
) )
} }
regionId = regions[0].id regionDTO.region_id = regions[0].id
regionDTO.region = regions[0]
} }
regionDTO.region_id = regionId
return regionDTO return regionDTO
} }
+9 -5
View File
@@ -364,11 +364,15 @@ class CartService extends TransactionBaseService {
).id ).id
} }
if (data.customer_id) { if (data.customer_id || data.customer) {
const customer = await this.customerService_ const customer =
.withTransaction(transactionManager) (data.customer ??
.retrieve(data.customer_id) (data.customer_id &&
.catch(() => undefined) (await this.customerService_
.withTransaction(transactionManager)
.retrieve(data.customer_id)
.catch(() => undefined)))) as Customer
rawCart.customer = customer rawCart.customer = customer
rawCart.customer_id = customer?.id rawCart.customer_id = customer?.id
rawCart.email = customer?.email rawCart.email = customer?.email
+2
View File
@@ -8,6 +8,7 @@ import { Cart, CartType } from "../models/cart"
import { IsType } from "../utils/validators/is-type" import { IsType } from "../utils/validators/is-type"
import { Region } from "../models" import { Region } from "../models"
import { ValidateNested } from "class-validator" import { ValidateNested } from "class-validator"
import { CustomerTypes } from "@medusajs/types"
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
export function isCart(object: any): object is Cart { export function isCart(object: any): object is Cart {
@@ -60,6 +61,7 @@ export type CartCreateProps = {
shipping_address?: Partial<AddressPayload> shipping_address?: Partial<AddressPayload>
gift_cards?: GiftCard[] gift_cards?: GiftCard[]
discounts?: Discount[] discounts?: Discount[]
customer?: CustomerTypes.CustomerDTO
customer_id?: string customer_id?: string
type?: CartType type?: CartType
context?: object context?: object
@@ -1,5 +1,9 @@
import { MedusaModule } from "@medusajs/modules-sdk" import { MedusaModule } from "@medusajs/modules-sdk"
import { IProductModuleService, ProductTypes } from "@medusajs/types" import {
IProductModuleService,
ProductTypes,
UpdateProductDTO,
} from "@medusajs/types"
import { kebabCase } from "@medusajs/utils" import { kebabCase } from "@medusajs/utils"
import { import {
Product, Product,
@@ -172,16 +176,30 @@ describe("ProductModuleService products", function () {
const variantTitle = data.variants[0].title const variantTitle = data.variants[0].title
const updateData = { const productBefore = (await module.retrieve(productOne.id, {
...data, relations: [
id: productOne.id, "images",
title: "updated title", "variants",
} "options",
"options.values",
"variants.options",
"tags",
"type",
],
})) as unknown as UpdateProductDTO
const updatedProducts = await module.update([updateData]) productBefore.title = "updated title"
productBefore.variants = [...productBefore.variants!, ...data.variants]
productBefore.type = { value: "new-type" }
productBefore.options = data.options
productBefore.images = data.images
productBefore.thumbnail = data.thumbnail
productBefore.tags = data.tags
const updatedProducts = await module.update([productBefore])
expect(updatedProducts).toHaveLength(1) expect(updatedProducts).toHaveLength(1)
const product = await module.retrieve(updateData.id, { const product = await module.retrieve(productBefore.id, {
relations: [ relations: [
"images", "images",
"variants", "variants",
@@ -195,7 +213,7 @@ describe("ProductModuleService products", function () {
const createdVariant = product.variants.find( const createdVariant = product.variants.find(
(v) => v.title === variantTitle (v) => v.title === variantTitle
) )!
expect(product.images).toHaveLength(1) expect(product.images).toHaveLength(1)
expect(createdVariant?.options).toHaveLength(1) expect(createdVariant?.options).toHaveLength(1)
@@ -206,12 +224,12 @@ describe("ProductModuleService products", function () {
expect.objectContaining({ expect.objectContaining({
id: expect.any(String), id: expect.any(String),
title: "updated title", title: "updated title",
description: updateData.description, description: productBefore.description,
subtitle: updateData.subtitle, subtitle: productBefore.subtitle,
is_giftcard: updateData.is_giftcard, is_giftcard: productBefore.is_giftcard,
discountable: updateData.discountable, discountable: productBefore.discountable,
thumbnail: images[0], thumbnail: images[0],
status: updateData.status, status: productBefore.status,
images: expect.arrayContaining([ images: expect.arrayContaining([
expect.objectContaining({ expect.objectContaining({
id: expect.any(String), id: expect.any(String),
@@ -221,11 +239,11 @@ describe("ProductModuleService products", function () {
options: expect.arrayContaining([ options: expect.arrayContaining([
expect.objectContaining({ expect.objectContaining({
id: expect.any(String), id: expect.any(String),
title: updateData.options[0].title, title: productBefore.options?.[0].title,
values: expect.arrayContaining([ values: expect.arrayContaining([
expect.objectContaining({ expect.objectContaining({
id: expect.any(String), id: expect.any(String),
value: updateData.variants[0].options?.[0].value, value: createdVariant.options?.[0].value,
}), }),
]), ]),
}), }),
@@ -233,18 +251,18 @@ describe("ProductModuleService products", function () {
tags: expect.arrayContaining([ tags: expect.arrayContaining([
expect.objectContaining({ expect.objectContaining({
id: expect.any(String), id: expect.any(String),
value: updateData.tags[0].value, value: productBefore.tags?.[0].value,
}), }),
]), ]),
type: expect.objectContaining({ type: expect.objectContaining({
id: expect.any(String), id: expect.any(String),
value: updateData.type.value, value: productBefore.type!.value,
}), }),
variants: expect.arrayContaining([ variants: expect.arrayContaining([
expect.objectContaining({ expect.objectContaining({
id: expect.any(String), id: expect.any(String),
title: updateData.variants[0].title, title: createdVariant.title,
sku: updateData.variants[0].sku, sku: createdVariant.sku,
allow_backorder: false, allow_backorder: false,
manage_inventory: true, manage_inventory: true,
inventory_quantity: "100", inventory_quantity: "100",
@@ -252,7 +270,7 @@ describe("ProductModuleService products", function () {
options: expect.arrayContaining([ options: expect.arrayContaining([
expect.objectContaining({ expect.objectContaining({
id: expect.any(String), id: expect.any(String),
value: updateData.variants[0].options?.[0].value, value: createdVariant.options?.[0].value,
}), }),
]), ]),
}), }),
+2
View File
@@ -1,5 +1,6 @@
export * as CacheTypes from "./cache" export * as CacheTypes from "./cache"
export * as CommonTypes from "./common" export * as CommonTypes from "./common"
export * as CustomerTypes from "./customer"
export * as DAL from "./dal" export * as DAL from "./dal"
export * as EventBusTypes from "./event-bus" export * as EventBusTypes from "./event-bus"
export * as FeatureFlagTypes from "./feature-flag" export * as FeatureFlagTypes from "./feature-flag"
@@ -8,6 +9,7 @@ export * as LoggerTypes from "./logger"
export * as ModulesSdkTypes from "./modules-sdk" export * as ModulesSdkTypes from "./modules-sdk"
export * as PricingTypes from "./pricing" export * as PricingTypes from "./pricing"
export * as ProductTypes from "./product" export * as ProductTypes from "./product"
export * as RegionTypes from "./region"
export * as SalesChannelTypes from "./sales-channel" export * as SalesChannelTypes from "./sales-channel"
export * as SearchTypes from "./search" export * as SearchTypes from "./search"
export * as StockLocationTypes from "./stock-location" export * as StockLocationTypes from "./stock-location"
+24
View File
@@ -0,0 +1,24 @@
import { AddressDTO } from "../address"
export interface CustomerDTO {
id: string
email: string
billing_address_id?: string | null
shipping_address_id?: string | null
first_name?: string | null
last_name?: string | null
billing_address?: AddressDTO
shipping_address?: AddressDTO
phone?: string | null
has_account: boolean
groups?: {
id: string
}[]
orders: {
id: string
}[]
metadata?: Record<string, unknown>
deleted_at?: Date | string
created_at?: Date | string
updated_at?: Date | string
}
+1
View File
@@ -0,0 +1 @@
export * from "./common"
+2
View File
@@ -3,6 +3,7 @@ export * from "./bundles"
export * from "./cache" export * from "./cache"
export * from "./cart" export * from "./cart"
export * from "./common" export * from "./common"
export * from "./customer"
export * from "./dal" export * from "./dal"
export * from "./event-bus" export * from "./event-bus"
export * from "./feature-flag" export * from "./feature-flag"
@@ -15,6 +16,7 @@ export * from "./modules-sdk"
export * from "./pricing" export * from "./pricing"
export * from "./product" export * from "./product"
export * from "./product-category" export * from "./product-category"
export * from "./region"
export * from "./sales-channel" export * from "./sales-channel"
export * from "./search" export * from "./search"
export * from "./shared-context" export * from "./shared-context"
+11
View File
@@ -0,0 +1,11 @@
export type RegionDTO = {
name: string
currency_code: string
tax_rate?: number
tax_code?: string | null
gift_cards_taxable?: boolean
automatic_taxes?: boolean
tax_provider_id?: string | null
metadata?: Record<string, unknown>
includes_tax?: boolean
}
+1
View File
@@ -0,0 +1 @@
export * from "./common"