feat(product): Create (+ workflow), delete, restore (#4459)

* Feat: create product with product module

* feat: create product wip

* feat: create product wip

* feat: update product relation and generate image migration

* lint

* conitnue implementation

* continue implementation and add integration tests for produceService.create

* Add integration tests for product creation at the module level for the complete flow

* only use persist since write operations are always wrapped in a transaction which will be committed and flushed

* simplify the transaction wrapper to make future changes easier

* feat: move some utils to the utils package to simplify its usage

* tests: fix unit tests

* feat: create variants along side the product

* Add more integration tests an update migrations

* chore: Update actions workflow to include packages integration tests

* small types and utils cleanup

* chore: Add support for database debug option

* chore: Add missing types in package.json from types and util, validate that all the models are sync with medusa

* expose retrieve method

* fix types issues

* fix unit tests and move integration tests workflow with the plugins integration tests

* chore: remove migration function export from the definition to prevent them to be ran by the medusa cli just in case

* fix package.json script

* chore: workflows

* feat: start creating the create product workflow

* feat: add empty step for prices and sales channel

* tests: update scripts and action envs

* fix imports

* feat: Add proper soft deleted support + add product deletion service public api

* chore: update migrations

* chore: update migrations

* chore: update todo

* feat: Add product deletion to the create-product workflow as compensation

* chore: cleanup product utils

* feat: Add support for cascade soft-remove

* feat: refactor repository to take into account withDeleted

* fix integration tests

* Add support for force delete -> delete, cleanup repositories and improvements

* Add support for restoring a product and add integration tests

* cleaup + tests

* types

* fix integration tests

* remove unnecessary comments

* move specific mikro orm usage to the DAL

* Cleanup workflow functions

* Make deleted_at optional at the property level and add url index for the images

* address feedback + cleanup

* fix export

* merge migrations into one

* feat(product, types): added missing product variant methods (#4475)

* chore: added missing product variant methods

* chore: address PR feedback

* chore: catch undefined case for retrieve + specs for variant service

* chore: align TEntity + add changeset

* chore: revert changeset, TEntity to ProductVariant

* chore: write tests for pagination, unskip the test

* Create chilled-mice-deliver.md

* update integration fixtuers

* update pipeline node version

* rename github action

* fix pipeline

* feat(medusa, types): added missing category tests and service methods (#4499)

* chore: added missing category tests and service methods

* chore: added type changes to module service

* chore: address pr feedback

* update repositories manager usage and serialisation from the write public API

* move serializisation to the DAL

* rename template args

* chore: added collection methods for module and collection service (#4505)

* chore: added collection methods for module and collection service

* Create fresh-islands-teach.md

* chore: move retrieve entity to utils package

* chore: make products optional in DTO type

---------

Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com>

* feat(product): Apply transaction decorators to the services (#4512)

---------

Co-authored-by: Riqwan Thamir <rmthamir@gmail.com>
Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com>
Co-authored-by: Carlos R. L. Rodrigues <37986729+carlos-r-l-rodrigues@users.noreply.github.com>
This commit is contained in:
Adrien de Peretti
2023-07-16 20:19:23 +02:00
committed by GitHub
co-authored by Oliver Windall Juhl Riqwan Thamir Carlos R. L. Rodrigues
parent 5b91a3503a
commit befc2f1c80
98 changed files with 5444 additions and 688 deletions
@@ -1,14 +1,9 @@
import { FindOptions, RepositoryService } from "@medusajs/types"
import { BaseRepository } from "../../src/repositories/base"
class CustomRepository implements RepositoryService {
constructor() {}
find(options?: FindOptions): Promise<any[]> {
throw new Error("Method not implemented.")
}
findAndCount(options?: FindOptions): Promise<[any[], number]> {
throw new Error("Method not implemented.")
class CustomRepository extends BaseRepository {
constructor({ manager }) {
// @ts-ignore
super(...arguments)
}
}
@@ -0,0 +1,80 @@
import { ProductTypes } from "@medusajs/types"
import faker from "faker"
import { Image } from "@models"
export const buildProductOnlyData = ({
title,
description,
subtitle,
is_giftcard,
discountable,
thumbnail,
images,
status,
}: {
title?: string
description?: string
subtitle?: string
is_giftcard?: boolean
discountable?: boolean
thumbnail?: string
images?: { id?: string; url: string }[]
status?: ProductTypes.ProductStatus
} = {}) => {
return {
title: title ?? faker.commerce.productName(),
description: description ?? faker.commerce.productName(),
subtitle: subtitle ?? faker.commerce.productName(),
is_giftcard: is_giftcard ?? false,
discountable: discountable ?? true,
thumbnail: thumbnail as string,
status: status ?? ProductTypes.ProductStatus.PUBLISHED,
images: (images ?? []) as Image[],
}
}
export const buildProductAndRelationsData = ({
title,
description,
subtitle,
is_giftcard,
discountable,
thumbnail,
images,
status,
type,
tags,
options,
variants,
}: Partial<ProductTypes.CreateProductDTO>) => {
const defaultOptionTitle = faker.commerce.productName()
return {
title: title ?? faker.commerce.productName(),
description: description ?? faker.commerce.productName(),
subtitle: subtitle ?? faker.commerce.productName(),
is_giftcard: is_giftcard ?? false,
discountable: discountable ?? true,
thumbnail: thumbnail as string,
status: status ?? ProductTypes.ProductStatus.PUBLISHED,
images: (images ?? []) as Image[],
type: type ? { value: type } : { value: faker.commerce.productName() },
tags: tags ?? [{ value: "tag-1" }],
options: options ?? [
{
title: defaultOptionTitle,
},
],
variants: variants ?? [
{
title: faker.commerce.productName(),
sku: faker.commerce.productName(),
options: [
{
value: defaultOptionTitle + faker.commerce.productName(),
},
],
},
],
// TODO: add categories, must be created first
}
}
@@ -1,5 +1,7 @@
import { ProductTypes } from "@medusajs/types"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import {
Image,
Product,
ProductCategory,
ProductCollection,
@@ -7,9 +9,16 @@ import {
} from "@models"
import ProductOption from "../../../src/models/product-option"
export * from "./data/create-product"
export async function createProductAndTags(
manager: SqlEntityManager,
data: any[]
data: {
id?: string
title: string
status: ProductTypes.ProductStatus
tags?: { id: string; value: string }[]
}[]
) {
const products: any[] = data.map((productData) => {
return manager.create(Product, productData)
@@ -35,7 +44,11 @@ export async function createProductVariants(
export async function createCollections(
manager: SqlEntityManager,
collectionData: any[]
collectionData: {
id?: string
title: string
handle?: string
}[]
) {
const collections: any[] = collectionData.map((collectionData) => {
return manager.create(ProductCollection, collectionData)
@@ -48,10 +61,21 @@ export async function createCollections(
export async function createOptions(
manager: SqlEntityManager,
optionsData: any[]
optionsData: {
id?: string
product: { id: string }
title: string
value?: string
values?: {
id?: string
value: string
variant?: { id: string } & any
}[]
variant?: { id: string } & any
}[]
) {
const options: any[] = optionsData.map((o) => {
return manager.create(ProductOption, o)
const options: any[] = optionsData.map((option) => {
return manager.create(ProductOption, option)
})
await manager.persistAndFlush(options)
@@ -59,6 +83,19 @@ export async function createOptions(
return options
}
export async function createImages(
manager: SqlEntityManager,
imagesData: string[]
) {
const images: any[] = imagesData.map((img) => {
return manager.create(Image, { url: img })
})
await manager.persistAndFlush(images)
return images
}
export async function assignCategoriesToProduct(
manager: SqlEntityManager,
product: Product,
@@ -0,0 +1,44 @@
import { ProductTypes } from "@medusajs/types"
import faker from "faker"
export const buildProductVariantOnlyData = ({
title,
sku,
barcode,
ean,
upc,
allow_backorder,
inventory_quantity,
manage_inventory,
hs_code,
origin_country,
mid_code,
material,
weight,
length,
height,
width,
options,
metadata,
}: Partial<ProductTypes.CreateProductVariantOnlyDTO>) => {
return {
title: title ?? faker.commerce.productName(),
sku: sku ?? faker.commerce.productName(),
barcode,
ean,
upc,
allow_backorder,
inventory_quantity,
manage_inventory,
hs_code,
origin_country,
mid_code,
material,
weight,
length,
height,
width,
options,
metadata,
}
}
@@ -0,0 +1 @@
export * from "./data/create-variant"