Initial commit: backend, storefront, vendor-panel added
This commit is contained in:
44
backend/packages/framework/package.json
Normal file
44
backend/packages/framework/package.json
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "@mercurjs/framework",
|
||||
"version": "1.0.0",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist",
|
||||
"!dist/**/__tests__",
|
||||
"!dist/**/__mocks__",
|
||||
"!dist/**/__fixtures__"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "rimraf dist && tsc --build",
|
||||
"migration:initial": " MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:create --initial",
|
||||
"migration:create": " MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:create",
|
||||
"migration:up": " MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:up",
|
||||
"orm:cache:clear": " MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm cache:clear"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@medusajs/framework": "2.8.6",
|
||||
"@medusajs/test-utils": "2.8.6",
|
||||
"@mikro-orm/cli": "6.4.3",
|
||||
"@mikro-orm/core": "6.4.3",
|
||||
"@mikro-orm/migrations": "6.4.3",
|
||||
"@mikro-orm/postgresql": "6.4.3",
|
||||
"@swc/core": "^1.7.28",
|
||||
"@swc/jest": "^0.2.36",
|
||||
"jest": "^29.7.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"tsc-alias": "^1.8.6",
|
||||
"typescript": "^5.6.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@medusajs/framework": "2.8.6",
|
||||
"@mikro-orm/core": "6.4.3",
|
||||
"@mikro-orm/migrations": "6.4.3",
|
||||
"@mikro-orm/postgresql": "6.4.3",
|
||||
"awilix": "^8.0.1"
|
||||
}
|
||||
}
|
||||
2
backend/packages/framework/src/index.ts
Normal file
2
backend/packages/framework/src/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./types";
|
||||
export * from "./utils";
|
||||
@@ -0,0 +1,4 @@
|
||||
import { AlgoliaProduct } from './algolia-product'
|
||||
import { AlgoliaReview } from './algolia-review'
|
||||
|
||||
export type AlgoliaEntity = AlgoliaProduct | AlgoliaReview
|
||||
128
backend/packages/framework/src/types/algolia/algolia-product.ts
Normal file
128
backend/packages/framework/src/types/algolia/algolia-product.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
import { z } from "zod";
|
||||
import { StoreStatus } from "../seller";
|
||||
|
||||
export type AlgoliaProduct = z.infer<typeof AlgoliaProductValidator>;
|
||||
export const AlgoliaProductValidator = z.object({
|
||||
id: z.string(),
|
||||
title: z.string(),
|
||||
handle: z.string(),
|
||||
subtitle: z.string().nullable(),
|
||||
description: z.string().nullable(),
|
||||
thumbnail: z.string().nullable(),
|
||||
average_rating: z.coerce.number().nullable().default(null),
|
||||
supported_countries: z.array(z.string()).nullable().default([]),
|
||||
options: z.array(z.record(z.string())).nullable().default(null),
|
||||
images: z
|
||||
.array(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
url: z.string(),
|
||||
rank: z.number(),
|
||||
})
|
||||
)
|
||||
.nullable()
|
||||
.optional(),
|
||||
collection: z
|
||||
.object({
|
||||
title: z.string(),
|
||||
})
|
||||
.nullable()
|
||||
.optional(),
|
||||
type: z
|
||||
.object({
|
||||
value: z.string(),
|
||||
})
|
||||
.nullable()
|
||||
.optional(),
|
||||
tags: z
|
||||
.array(
|
||||
z.object({
|
||||
value: z.string(),
|
||||
})
|
||||
)
|
||||
.optional(),
|
||||
categories: z
|
||||
.array(
|
||||
z.object({
|
||||
name: z.string(),
|
||||
id: z.string(),
|
||||
})
|
||||
)
|
||||
.optional(),
|
||||
variants: z.any().nullable().default(null),
|
||||
brand: z
|
||||
.object({
|
||||
name: z.string(),
|
||||
})
|
||||
.optional(),
|
||||
attribute_values: z
|
||||
.array(
|
||||
z.object({
|
||||
name: z.string(),
|
||||
value: z.string(),
|
||||
is_filterable: z.boolean(),
|
||||
ui_component: z.string(),
|
||||
})
|
||||
)
|
||||
.optional(),
|
||||
sku: z.string().nullable().optional(),
|
||||
ean: z.string().nullable().optional(),
|
||||
upc: z.string().nullable().optional(),
|
||||
barcode: z.string().nullable().optional(),
|
||||
hs_code: z.string().nullable().optional(),
|
||||
mid_code: z.string().nullable().optional(),
|
||||
weight: z.coerce.number().nullable().optional(),
|
||||
length: z.coerce.number().nullable().optional(),
|
||||
height: z.coerce.number().nullable().optional(),
|
||||
width: z.coerce.number().nullable().optional(),
|
||||
origin_country: z.string().nullable().optional(),
|
||||
material: z.string().nullable().optional(),
|
||||
seller: z
|
||||
.object({
|
||||
id: z.string(),
|
||||
handle: z.string().nullish(),
|
||||
store_status: z.nativeEnum(StoreStatus).nullish(),
|
||||
})
|
||||
.nullable(),
|
||||
});
|
||||
|
||||
export const AlgoliaVariantValidator = z.object({
|
||||
id: z.string(),
|
||||
title: z.string().nullish(),
|
||||
sku: z.string().nullish(),
|
||||
barcode: z.string().nullish(),
|
||||
ean: z.string().nullish(),
|
||||
ups: z.string().nullish(),
|
||||
allow_backorder: z.boolean(),
|
||||
manage_inventory: z.boolean(),
|
||||
hs_code: z.string().nullish(),
|
||||
origin_country: z.string().nullish(),
|
||||
mid_code: z.string().nullish(),
|
||||
material: z.string().nullish(),
|
||||
weight: z.number().nullish(),
|
||||
length: z.number().nullish(),
|
||||
height: z.number().nullish(),
|
||||
wifth: z.number().nullish(),
|
||||
variant_rank: z.number().nullish(),
|
||||
options: z.array(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
value: z.string(),
|
||||
option: z.object({
|
||||
id: z.string(),
|
||||
title: z.string(),
|
||||
}),
|
||||
})
|
||||
),
|
||||
prices: z.array(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
title: z.string().nullish(),
|
||||
currency_code: z.string(),
|
||||
min_quantity: z.number().nullish(),
|
||||
max_quantity: z.number().nullish(),
|
||||
rules_count: z.number(),
|
||||
amount: z.number(),
|
||||
})
|
||||
),
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
import { z } from 'zod'
|
||||
|
||||
export type AlgoliaReview = z.infer<typeof AlgoliaReviewValidator>
|
||||
export const AlgoliaReviewValidator = z.object({
|
||||
id: z.string(),
|
||||
reference: z.string(),
|
||||
reference_id: z.string(),
|
||||
rating: z.coerce.number(),
|
||||
customer_note: z.string().nullable(),
|
||||
seller_note: z.string().nullable()
|
||||
})
|
||||
13
backend/packages/framework/src/types/algolia/events.ts
Normal file
13
backend/packages/framework/src/types/algolia/events.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
export enum AlgoliaEvents {
|
||||
PRODUCTS_CHANGED = 'algolia.products.changed',
|
||||
PRODUCTS_DELETED = 'algolia.products.deleted',
|
||||
REVIEW_CHANGED = 'algolia.reviews.changed'
|
||||
}
|
||||
|
||||
export enum IntermediateEvents {
|
||||
FULFULLMENT_SET_CHANGED = 'algolia.intermediate.fulfillment_set.changed',
|
||||
SERVICE_ZONE_CHANGED = 'algolia.intermediate.service_zone.changed',
|
||||
SHIPPING_OPTION_CHANGED = 'algolia.intermediate.shipping_option.changed',
|
||||
STOCK_LOCATION_CHANGED = 'algolia.intermediate.stock_location.changed',
|
||||
INVENTORY_ITEM_CHANGED = 'algolia.intermediate.inventory_item.changed'
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export enum IndexType {
|
||||
PRODUCT = 'products',
|
||||
REVIEW = 'reviews'
|
||||
}
|
||||
5
backend/packages/framework/src/types/algolia/index.ts
Normal file
5
backend/packages/framework/src/types/algolia/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export * from './index-types'
|
||||
export * from './algolia-entity'
|
||||
export * from './algolia-product'
|
||||
export * from './algolia-review'
|
||||
export * from './events'
|
||||
40
backend/packages/framework/src/types/attribute/common.ts
Normal file
40
backend/packages/framework/src/types/attribute/common.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
export enum AttributeUIComponent {
|
||||
SELECT = "select",
|
||||
MULTIVALUE = "multivalue",
|
||||
UNIT = "unit",
|
||||
TOGGLE = "toggle",
|
||||
TEXTAREA = "text_area",
|
||||
COLOR_PICKER = "color_picker",
|
||||
}
|
||||
|
||||
export interface ProductAttributeValueDTO {
|
||||
value: string;
|
||||
attribute_id: string;
|
||||
}
|
||||
|
||||
export interface AttributePossibleValueDTO {
|
||||
id: string;
|
||||
value: string;
|
||||
rank: number;
|
||||
created_at: string;
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface AttributeDTO {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
handle: string;
|
||||
is_filterable: boolean;
|
||||
ui_component: AttributeUIComponent;
|
||||
metadata?: Record<string, unknown>;
|
||||
possible_values?: AttributePossibleValueDTO[];
|
||||
values?: Array<{
|
||||
id: string;
|
||||
value: string;
|
||||
}>;
|
||||
product_categories?: Array<{
|
||||
id: string;
|
||||
name: string;
|
||||
}>;
|
||||
}
|
||||
2
backend/packages/framework/src/types/attribute/index.ts
Normal file
2
backend/packages/framework/src/types/attribute/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './mutations'
|
||||
export * from './common'
|
||||
51
backend/packages/framework/src/types/attribute/mutations.ts
Normal file
51
backend/packages/framework/src/types/attribute/mutations.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { AttributeUIComponent } from './common'
|
||||
|
||||
export interface CreateAttributeValueDTO {
|
||||
value: string
|
||||
rank: number
|
||||
attribute_id: string
|
||||
metadata?: Record<string, unknown>
|
||||
}
|
||||
|
||||
export interface UpdateAttributeDTO {
|
||||
id: string
|
||||
name?: string
|
||||
description?: string
|
||||
handle?: string
|
||||
is_filterable?: boolean
|
||||
metadata?: Record<string, unknown>
|
||||
possible_values?: UpsertAttributeValueDTO[]
|
||||
product_category_ids?: { id: string }[]
|
||||
}
|
||||
|
||||
export interface UpsertAttributeValueDTO {
|
||||
id?: string
|
||||
value?: string
|
||||
rank?: number
|
||||
metadata?: Record<string, unknown>
|
||||
attribute_id?: string
|
||||
}
|
||||
|
||||
export interface CreateAttributeDTO {
|
||||
name: string
|
||||
description?: string
|
||||
handle?: string
|
||||
is_filterable?: boolean
|
||||
metadata?: Record<string, unknown>
|
||||
ui_component: AttributeUIComponent
|
||||
possible_values?: Omit<CreateAttributeValueDTO, 'attribute_id'>[]
|
||||
product_category_ids?: string[]
|
||||
}
|
||||
|
||||
export interface UpdateAttributeValueDTO {
|
||||
id: string
|
||||
value?: string
|
||||
rank?: number
|
||||
metadata?: Record<string, unknown> | null
|
||||
}
|
||||
|
||||
export type CreateProductAttributeValueDTO = {
|
||||
attribute_id: string
|
||||
product_id: string
|
||||
value: string
|
||||
}
|
||||
1
backend/packages/framework/src/types/brand/index.ts
Normal file
1
backend/packages/framework/src/types/brand/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./mutations";
|
||||
3
backend/packages/framework/src/types/brand/mutations.ts
Normal file
3
backend/packages/framework/src/types/brand/mutations.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export type CreateBrandDTO = {
|
||||
brand_name: string
|
||||
}
|
||||
60
backend/packages/framework/src/types/commission/common.ts
Normal file
60
backend/packages/framework/src/types/commission/common.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { BigNumberValue } from '@medusajs/framework/types'
|
||||
|
||||
export type CommissionRateDTO = {
|
||||
id: string
|
||||
created_at: Date
|
||||
updated_at: Date
|
||||
type: string
|
||||
percentage_rate: number | null
|
||||
include_tax: boolean
|
||||
price_set_id: string | null
|
||||
max_price_set_id: string | null
|
||||
min_price_set_id: string | null
|
||||
}
|
||||
|
||||
export type CommissionRuleDTO = {
|
||||
id: string
|
||||
created_at: Date
|
||||
updated_at: Date
|
||||
name: string
|
||||
reference: string
|
||||
reference_id: string
|
||||
rate: CommissionRateDTO
|
||||
}
|
||||
|
||||
export type CommissionLineDTO = {
|
||||
id: string
|
||||
item_line_id: string
|
||||
rule_id: string
|
||||
currency_code: string
|
||||
value: BigNumberValue
|
||||
created_at: Date
|
||||
updated_at: Date
|
||||
}
|
||||
|
||||
export type CommissionCalculationContext = {
|
||||
product_type_id: string
|
||||
product_category_id: string
|
||||
seller_id: string
|
||||
}
|
||||
|
||||
type Price = { amount: number; currency_code: string }
|
||||
|
||||
export type AdminCommissionAggregate = {
|
||||
id: string
|
||||
name: string
|
||||
type: string
|
||||
reference: string
|
||||
reference_id: string
|
||||
include_tax: boolean
|
||||
is_active: boolean
|
||||
ref_value: string
|
||||
price_set_id: string | null
|
||||
price_set: Price[]
|
||||
min_price_set_id: string | null
|
||||
min_price_set: Price[]
|
||||
max_price_set_id: string | null
|
||||
max_price_set: Price[]
|
||||
percentage_rate: number | null
|
||||
fee_value: string
|
||||
}
|
||||
2
backend/packages/framework/src/types/commission/index.ts
Normal file
2
backend/packages/framework/src/types/commission/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './common'
|
||||
export * from './mutations'
|
||||
36
backend/packages/framework/src/types/commission/mutations.ts
Normal file
36
backend/packages/framework/src/types/commission/mutations.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { CommissionLineDTO } from './common'
|
||||
|
||||
export type Price = {
|
||||
amount: number
|
||||
currency_code: string
|
||||
}
|
||||
|
||||
export type CreateCommissionRateDTO = {
|
||||
type: string
|
||||
percentage_rate?: number
|
||||
include_tax: boolean
|
||||
price_set?: Price[]
|
||||
min_price_set?: Price[]
|
||||
max_price_set?: Price[]
|
||||
}
|
||||
|
||||
export type CreateCommissionRuleDTO = {
|
||||
name: string
|
||||
reference: string
|
||||
reference_id: string
|
||||
is_active: boolean
|
||||
rate: CreateCommissionRateDTO
|
||||
}
|
||||
|
||||
export type CreateCommissionLineDTO = Omit<
|
||||
CommissionLineDTO,
|
||||
'id' | 'created_at' | 'updated_at'
|
||||
>
|
||||
|
||||
export type UpdateCommissionRateDTO = Partial<CreateCommissionRateDTO> & {
|
||||
id: string
|
||||
}
|
||||
|
||||
export type UpdateCommissionRuleDTO = Partial<CreateCommissionRuleDTO> & {
|
||||
id: string
|
||||
}
|
||||
14
backend/packages/framework/src/types/configuration/common.ts
Normal file
14
backend/packages/framework/src/types/configuration/common.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export enum ConfigurationRuleType {
|
||||
GLOBAL_PRODUCT_CATALOG = 'global_product_catalog',
|
||||
REQUIRE_PRODUCT_APPROVAL = 'require_product_approval',
|
||||
PRODUCT_REQUEST_ENABLED = 'product_request_enabled',
|
||||
PRODUCT_IMPORT_ENABLED = 'product_import_enabled'
|
||||
}
|
||||
|
||||
export type ConfigurationRule = {
|
||||
id: string
|
||||
rule_type: ConfigurationRuleType
|
||||
is_enabled: boolean
|
||||
created_at: Date
|
||||
updated_at: Date
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './common'
|
||||
export * from './mutations'
|
||||
@@ -0,0 +1,11 @@
|
||||
import { ConfigurationRuleType } from './common'
|
||||
|
||||
export interface CreateConfigurationRuleDTO {
|
||||
rule_type: ConfigurationRuleType
|
||||
is_enabled: boolean
|
||||
}
|
||||
|
||||
export interface UpdateConfigurationRuleDTO {
|
||||
id: string
|
||||
is_enabled: boolean
|
||||
}
|
||||
14
backend/packages/framework/src/types/index.ts
Normal file
14
backend/packages/framework/src/types/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export * from "./configuration";
|
||||
export * from "./seller";
|
||||
export * from "./reviews";
|
||||
export * from "./payout";
|
||||
export * from "./marketplace";
|
||||
export * from "./brand";
|
||||
export * from "./commission";
|
||||
export * from "./wishlist";
|
||||
export * from "./attribute";
|
||||
export * from "./order-return-request";
|
||||
export * from "./requests";
|
||||
export * from "./split-order-payment";
|
||||
export * from "./algolia";
|
||||
export * from "./payment-stripe-connect";
|
||||
45
backend/packages/framework/src/types/marketplace/common.ts
Normal file
45
backend/packages/framework/src/types/marketplace/common.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import {
|
||||
BigNumberInput,
|
||||
CartDTO,
|
||||
CustomerDTO,
|
||||
FulfillmentStatus,
|
||||
OrderDTO,
|
||||
OrderDetailDTO,
|
||||
OrderStatus,
|
||||
PaymentCollectionDTO,
|
||||
PaymentCollectionStatus,
|
||||
SalesChannelDTO
|
||||
} from '@medusajs/framework/types'
|
||||
|
||||
export type OrderSetDTO = {
|
||||
id: string
|
||||
created_at: Date
|
||||
updated_at: Date
|
||||
display_id: number
|
||||
customer_id?: string
|
||||
customer?: CustomerDTO
|
||||
cart_id: string
|
||||
cart?: CartDTO
|
||||
|
||||
sales_channel_id?: string
|
||||
sales_channel?: SalesChannelDTO
|
||||
|
||||
payment_collection_id?: string
|
||||
payment_collection?: PaymentCollectionDTO
|
||||
}
|
||||
|
||||
export type OrderSetWithOrdersDTO = OrderSetDTO & {
|
||||
orders: (OrderDTO & OrderDetailDTO)[]
|
||||
}
|
||||
|
||||
export type FormattedOrderSetDTO = OrderSetDTO & {
|
||||
status: OrderStatus
|
||||
payment_status: PaymentCollectionStatus
|
||||
fulfillment_status: FulfillmentStatus
|
||||
|
||||
total: BigNumberInput
|
||||
tax_total: BigNumberInput
|
||||
subtotal: BigNumberInput
|
||||
shipping_total: BigNumberInput
|
||||
shipping_tax_total: BigNumberInput
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export enum OrderSetWorkflowEvents {
|
||||
PLACED = 'order_set.placed'
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from './events'
|
||||
export * from './common'
|
||||
export * from './mutations'
|
||||
@@ -0,0 +1,6 @@
|
||||
export type CreateOrderSetDTO = {
|
||||
cart_id: string
|
||||
customer_id: string
|
||||
payment_collection_id: string
|
||||
sales_channel_id: string
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
export type OrderReturnRequestLineItemDTO = {
|
||||
id: string
|
||||
line_item_id: string
|
||||
quantity: number
|
||||
}
|
||||
|
||||
export type OrderReturnRequestDTO = {
|
||||
id: string
|
||||
line_items: OrderReturnRequestLineItemDTO[]
|
||||
customer_id: string
|
||||
customer_note: string
|
||||
shipping_option_id: string | null
|
||||
vendor_reviewer_id: string | null
|
||||
vendor_reviewer_note: string | null
|
||||
vendor_review_date: Date | null
|
||||
admin_reviewer_id: string | null
|
||||
admin_reviewer_note: string | null
|
||||
admin_review_date: Date | null
|
||||
status: string
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './common'
|
||||
export * from './mutations'
|
||||
@@ -0,0 +1,32 @@
|
||||
export type CreateOrderReturnRequestDTO = {
|
||||
order_id: string;
|
||||
shipping_option_id?: string;
|
||||
line_items: { line_item_id: string; quantity: number; reason_id?: string }[];
|
||||
customer_id: string;
|
||||
customer_note: string;
|
||||
};
|
||||
|
||||
export type OrderReturnRequestStatus =
|
||||
| "pending"
|
||||
| "refunded"
|
||||
| "withdrawn"
|
||||
| "escalated"
|
||||
| "canceled";
|
||||
|
||||
export type VendorUpdateOrderReturnRequestDTO = {
|
||||
id: string;
|
||||
vendor_reviewer_id: string;
|
||||
vendor_reviewer_note: string;
|
||||
vendor_review_date: Date;
|
||||
status: OrderReturnRequestStatus;
|
||||
location_id?: string;
|
||||
};
|
||||
|
||||
export type AdminUpdateOrderReturnRequestDTO = {
|
||||
id: string;
|
||||
admin_reviewer_id: string;
|
||||
admin_reviewer_note: string;
|
||||
admin_review_date: Date;
|
||||
status: OrderReturnRequestStatus;
|
||||
location_id?: string;
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
import Stripe from 'stripe'
|
||||
|
||||
export const PaymentProviderKeys = {
|
||||
CARD: 'card'
|
||||
}
|
||||
|
||||
export type PaymentIntentOptions = Omit<
|
||||
Stripe.PaymentIntentCreateParams,
|
||||
'amount' | 'currency' | 'metadata' | 'transfer_group'
|
||||
>
|
||||
|
||||
export const ErrorCodes = {
|
||||
PAYMENT_INTENT_UNEXPECTED_STATE: 'payment_intent_unexpected_state'
|
||||
}
|
||||
|
||||
export const ErrorIntentStatus = {
|
||||
SUCCEEDED: 'succeeded',
|
||||
CANCELED: 'canceled'
|
||||
}
|
||||
38
backend/packages/framework/src/types/payout/common.ts
Normal file
38
backend/packages/framework/src/types/payout/common.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
/* Payment Account */
|
||||
import { BigNumberInput } from '@medusajs/framework/types'
|
||||
|
||||
export enum PayoutAccountStatus {
|
||||
PENDING = 'pending',
|
||||
ACTIVE = 'active',
|
||||
DISABLED = 'disabled'
|
||||
}
|
||||
|
||||
export type PayoutAccountDTO = {
|
||||
id: string
|
||||
created_at: Date
|
||||
updated_at: Date
|
||||
reference_id: string
|
||||
data: Record<string, unknown>
|
||||
status: PayoutAccountStatus
|
||||
}
|
||||
|
||||
/* Onboarding */
|
||||
|
||||
export type OnboardingDTO = {
|
||||
id: string
|
||||
created_at: Date
|
||||
updated_at: Date
|
||||
data: Record<string, unknown>
|
||||
context: Record<string, unknown>
|
||||
}
|
||||
|
||||
/* Payout */
|
||||
|
||||
export type PayoutDTO = {
|
||||
id: string
|
||||
created_at: Date
|
||||
updated_at: Date
|
||||
data: Record<string, unknown> | null
|
||||
amount: BigNumberInput
|
||||
currency_code: string
|
||||
}
|
||||
19
backend/packages/framework/src/types/payout/events.ts
Normal file
19
backend/packages/framework/src/types/payout/events.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
export enum PayoutWorkflowEvents {
|
||||
FAILED = "payout.failed",
|
||||
SUCCEEDED = "payout.succeeded",
|
||||
RECEIVED = "payout.received",
|
||||
}
|
||||
|
||||
export enum PayoutWebhookEvents {
|
||||
ACCOUNT_WEBHOOK_RECEIVED = "payout_account.webhook_received",
|
||||
}
|
||||
|
||||
export enum PayoutWebhookAction {
|
||||
ACCOUNT_AUTHORIZED = "account_authorized",
|
||||
ACCOUNT_DEAUTHORIZED = "account_deauthorized",
|
||||
ACCOUNT_REQUIRES_ACTION = "account_requires_action",
|
||||
}
|
||||
|
||||
export enum PayoutSummaryEvents {
|
||||
NOTIFICATION_SENT = "payout.notification_sent",
|
||||
}
|
||||
4
backend/packages/framework/src/types/payout/index.ts
Normal file
4
backend/packages/framework/src/types/payout/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from './events'
|
||||
export * from './common'
|
||||
export * from './mutations'
|
||||
export * from './provider'
|
||||
35
backend/packages/framework/src/types/payout/mutations.ts
Normal file
35
backend/packages/framework/src/types/payout/mutations.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { BigNumberInput } from '@medusajs/framework/types'
|
||||
|
||||
import { OnboardingDTO, PayoutAccountDTO } from './common'
|
||||
|
||||
export interface CreatePayoutAccountDTO {
|
||||
context: Record<string, unknown>
|
||||
}
|
||||
|
||||
export interface UpdatePayoutAccountDTO
|
||||
extends Omit<Partial<PayoutAccountDTO>, 'id' | 'created_at' | 'updated_at'> {
|
||||
id: string
|
||||
}
|
||||
|
||||
export interface CreateOnboardingDTO
|
||||
extends Omit<
|
||||
Partial<OnboardingDTO>,
|
||||
'id' | 'created_at' | 'updated_at' | 'data'
|
||||
> {
|
||||
payout_account_id: string
|
||||
context: Record<string, unknown>
|
||||
}
|
||||
|
||||
export type CreatePayoutDTO = {
|
||||
amount: BigNumberInput
|
||||
currency_code: string
|
||||
account_id: string
|
||||
transaction_id: string
|
||||
source_transaction: string
|
||||
}
|
||||
|
||||
export type CreatePayoutReversalDTO = {
|
||||
payout_id: string
|
||||
amount: BigNumberInput
|
||||
currency_code: string
|
||||
}
|
||||
69
backend/packages/framework/src/types/payout/provider.ts
Normal file
69
backend/packages/framework/src/types/payout/provider.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import Stripe from 'stripe'
|
||||
|
||||
import { BigNumberInput } from '@medusajs/framework/types'
|
||||
|
||||
import { PayoutWebhookAction } from './events'
|
||||
|
||||
export type ProcessPayoutInput = {
|
||||
amount: BigNumberInput
|
||||
currency: string
|
||||
account_reference_id: string
|
||||
transaction_id: string
|
||||
source_transaction: string
|
||||
}
|
||||
|
||||
export type ReversePayoutInput = {
|
||||
transfer_id: string
|
||||
amount: BigNumberInput
|
||||
currency: string
|
||||
}
|
||||
|
||||
export type ProcessPayoutResponse = {
|
||||
data: Record<string, unknown>
|
||||
}
|
||||
|
||||
export type CreatePayoutAccountInput = {
|
||||
context: Record<string, unknown>
|
||||
account_id: string
|
||||
}
|
||||
|
||||
export type CreatePayoutAccountResponse = {
|
||||
data: Record<string, unknown>
|
||||
id: string
|
||||
}
|
||||
|
||||
export type PayoutWebhookActionPayload = {
|
||||
data: Record<string, unknown>
|
||||
rawData: string | Buffer
|
||||
headers: Record<string, unknown>
|
||||
}
|
||||
|
||||
export type PayoutWebhookActionAndDataResponse = {
|
||||
action: PayoutWebhookAction
|
||||
data: {
|
||||
account_id: string
|
||||
}
|
||||
}
|
||||
|
||||
export type InitializeOnboardingResponse = {
|
||||
data: Record<string, unknown>
|
||||
}
|
||||
|
||||
export interface IPayoutProvider {
|
||||
createPayout(input: ProcessPayoutInput): Promise<ProcessPayoutResponse>
|
||||
createPayoutAccount(
|
||||
input: CreatePayoutAccountInput
|
||||
): Promise<CreatePayoutAccountResponse>
|
||||
reversePayout(input: ReversePayoutInput): Promise<Stripe.TransferReversal>
|
||||
/**
|
||||
* Initialize the onboarding process for a payout account.
|
||||
*/
|
||||
initializeOnboarding(
|
||||
accountId: string,
|
||||
context: Record<string, unknown>
|
||||
): Promise<InitializeOnboardingResponse>
|
||||
getAccount(accountId: string): Promise<Stripe.Account>
|
||||
getWebhookActionAndData(
|
||||
payload: PayoutWebhookActionPayload
|
||||
): Promise<PayoutWebhookActionAndDataResponse>
|
||||
}
|
||||
11
backend/packages/framework/src/types/requests/common.ts
Normal file
11
backend/packages/framework/src/types/requests/common.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export type RequestDTO = {
|
||||
id: string
|
||||
type: string
|
||||
data: Record<string, unknown>
|
||||
submitter_id: string
|
||||
reviewer_id: string
|
||||
reviewer_note: string
|
||||
status: 'pending' | 'accepted' | 'rejected'
|
||||
created_at: Date
|
||||
updated_at: Date
|
||||
}
|
||||
48
backend/packages/framework/src/types/requests/events.ts
Normal file
48
backend/packages/framework/src/types/requests/events.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
export enum SellerAccountRequestUpdatedEvent {
|
||||
ACCEPTED = "requests.seller.accepted",
|
||||
REJECTED = "requests.seller.rejected",
|
||||
}
|
||||
|
||||
export enum SellerRequest {
|
||||
CREATED = "requests.seller.created",
|
||||
}
|
||||
|
||||
export enum RequestUpdated {
|
||||
CREATED = "requests.*.created",
|
||||
}
|
||||
|
||||
export enum ProductCategoryRequestUpdatedEvent {
|
||||
ACCEPTED = "requests.product_category.accepted",
|
||||
REJECTED = "requests.product_category.rejected",
|
||||
}
|
||||
|
||||
export enum ProductCollectionRequestUpdatedEvent {
|
||||
ACCEPTED = "requests.product_collection.accepted",
|
||||
REJECTED = "requests.product_collection.rejected",
|
||||
}
|
||||
|
||||
export enum ProductRequestUpdatedEvent {
|
||||
CREATED = "requests.product.created",
|
||||
ACCEPTED = "requests.product.accepted",
|
||||
REJECTED = "requests.product.rejected",
|
||||
}
|
||||
|
||||
export enum ProductUpdateRequestUpdatedEvent {
|
||||
CREATED = "requests.product_update.created",
|
||||
ACCEPTED = "requests.product_update.accepted",
|
||||
REJECTED = "requests.product_update.rejected",
|
||||
}
|
||||
|
||||
export enum SellerTeamInviteEvent {
|
||||
CREATED = "seller.team.invite.created",
|
||||
}
|
||||
|
||||
export enum ProductTypeRequestUpdatedEvent {
|
||||
ACCEPTED = "requests.product_type.accepted",
|
||||
REJECTED = "requests.product_type.rejected",
|
||||
}
|
||||
|
||||
export enum ProductTagRequestUpdatedEvent {
|
||||
ACCEPTED = "requests.product_tag.accepted",
|
||||
REJECTED = "requests.product_tag.rejected",
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
export const HumanizeTypes = {
|
||||
product_collection: "Product Collection",
|
||||
product_category: "Product Category",
|
||||
product_update: "Product Update",
|
||||
product: "Product",
|
||||
seller: "Seller",
|
||||
review_remove: "Review Remove",
|
||||
product_type: "Product Type",
|
||||
product_tag: "Product Tag",
|
||||
};
|
||||
4
backend/packages/framework/src/types/requests/index.ts
Normal file
4
backend/packages/framework/src/types/requests/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from "./mutations";
|
||||
export * from "./common";
|
||||
export * from "./events";
|
||||
export * from "./humanize_types";
|
||||
31
backend/packages/framework/src/types/requests/mutations.ts
Normal file
31
backend/packages/framework/src/types/requests/mutations.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
export type RequestStatus = 'pending' | 'accepted' | 'rejected' | 'draft'
|
||||
|
||||
export type CreateRequestDTO = {
|
||||
type: string
|
||||
data: any
|
||||
submitter_id: string
|
||||
reviewer_id?: string
|
||||
reviewer_note?: string
|
||||
status?: RequestStatus
|
||||
}
|
||||
|
||||
export type UpdateRequestDTO = {
|
||||
id: string
|
||||
reviewer_id?: string
|
||||
reviewer_note?: string
|
||||
status: RequestStatus
|
||||
}
|
||||
|
||||
export type UpdateRequestDataDTO = {
|
||||
id: string
|
||||
type: string
|
||||
data: any
|
||||
}
|
||||
|
||||
export type AcceptRequestDTO = {
|
||||
id: string
|
||||
reviewer_id: string
|
||||
reviewer_note: string
|
||||
data: any
|
||||
status: RequestStatus
|
||||
}
|
||||
10
backend/packages/framework/src/types/reviews/common.ts
Normal file
10
backend/packages/framework/src/types/reviews/common.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export type ReviewDTO = {
|
||||
id: string
|
||||
reference: 'product' | 'seller'
|
||||
rating: number
|
||||
customer_note: string | null
|
||||
customer_id: string
|
||||
seller_note: string | null
|
||||
created_at: Date
|
||||
updated_at: Date | null
|
||||
}
|
||||
2
backend/packages/framework/src/types/reviews/index.ts
Normal file
2
backend/packages/framework/src/types/reviews/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './common'
|
||||
export * from './mutatations'
|
||||
15
backend/packages/framework/src/types/reviews/mutatations.ts
Normal file
15
backend/packages/framework/src/types/reviews/mutatations.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
export type CreateReviewDTO = {
|
||||
order_id: string
|
||||
reference: 'product' | 'seller'
|
||||
reference_id: string
|
||||
rating: number
|
||||
customer_note: string | null
|
||||
customer_id: string
|
||||
}
|
||||
|
||||
export type UpdateReviewDTO = {
|
||||
id: string
|
||||
rating?: number
|
||||
customer_note?: string
|
||||
seller_note?: string
|
||||
}
|
||||
67
backend/packages/framework/src/types/seller/common.ts
Normal file
67
backend/packages/framework/src/types/seller/common.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
export enum StoreStatus {
|
||||
ACTIVE = "ACTIVE",
|
||||
INACTIVE = "INACTIVE",
|
||||
SUSPENDED = "SUSPENDED",
|
||||
}
|
||||
|
||||
export type SellerDTO = {
|
||||
id: string;
|
||||
store_status: StoreStatus;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
name: string;
|
||||
email: string | null;
|
||||
phone: string | null;
|
||||
description: string | null;
|
||||
address_line: string | null;
|
||||
city: string | null;
|
||||
state: string | null;
|
||||
postal_code: string | null;
|
||||
country_code: string | null;
|
||||
tax_id: string | null;
|
||||
handle: string;
|
||||
photo: string | null;
|
||||
members?: Partial<MemberDTO>[];
|
||||
};
|
||||
|
||||
export type SellerWithPayoutAccountDTO = SellerDTO & {
|
||||
payout_account: {
|
||||
id: string;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
reference_id: string;
|
||||
data: Record<string, unknown>;
|
||||
status: string;
|
||||
};
|
||||
};
|
||||
|
||||
export enum MemberRole {
|
||||
OWNER = "owner",
|
||||
ADMIN = "admin",
|
||||
MEMBER = "member",
|
||||
}
|
||||
|
||||
export type MemberDTO = {
|
||||
id: string;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
role: MemberRole;
|
||||
email: string | null;
|
||||
name: string | null;
|
||||
bio: string | null;
|
||||
photo: string | null;
|
||||
phone: string | null;
|
||||
seller?: Partial<SellerDTO>;
|
||||
};
|
||||
|
||||
export type MemberInviteDTO = {
|
||||
id: string;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
email: string;
|
||||
role: MemberRole;
|
||||
seller?: Partial<SellerDTO>;
|
||||
token: string;
|
||||
expires_at: Date;
|
||||
accepted: boolean;
|
||||
};
|
||||
3
backend/packages/framework/src/types/seller/events.ts
Normal file
3
backend/packages/framework/src/types/seller/events.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export enum SellerEvents {
|
||||
STORE_STATUS_CHANGED = 'seller.store_status_changed'
|
||||
}
|
||||
3
backend/packages/framework/src/types/seller/index.ts
Normal file
3
backend/packages/framework/src/types/seller/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from "./common";
|
||||
export * from "./mutations";
|
||||
export * from "./events";
|
||||
68
backend/packages/framework/src/types/seller/mutations.ts
Normal file
68
backend/packages/framework/src/types/seller/mutations.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { MemberInviteDTO, MemberRole, SellerDTO, StoreStatus } from './common'
|
||||
|
||||
export interface CreateSellerDTO
|
||||
extends Omit<
|
||||
Partial<SellerDTO>,
|
||||
'id' | 'created_at' | 'updated_at' | 'members'
|
||||
> {
|
||||
name: string
|
||||
}
|
||||
|
||||
export interface UpdateSellerDTO {
|
||||
id: string
|
||||
name?: string
|
||||
email?: string
|
||||
phone?: string
|
||||
description?: string
|
||||
address_line?: string
|
||||
city?: string
|
||||
state?: string
|
||||
postal_code?: string
|
||||
country_code?: string
|
||||
tax_id?: string
|
||||
handle?: string
|
||||
photo?: string
|
||||
store_status?: StoreStatus
|
||||
}
|
||||
|
||||
export interface CreateMemberDTO {
|
||||
seller_id: string
|
||||
role?: MemberRole
|
||||
name: string
|
||||
email: string
|
||||
bio?: string
|
||||
photo?: string
|
||||
phone?: string
|
||||
}
|
||||
|
||||
export interface UpdateMemberDTO {
|
||||
id: string
|
||||
role?: MemberRole
|
||||
name?: string
|
||||
email?: string
|
||||
bio?: string
|
||||
photo?: string
|
||||
phone?: string
|
||||
}
|
||||
|
||||
export interface CreateMemberInviteDTO
|
||||
extends Omit<
|
||||
MemberInviteDTO,
|
||||
'id' | 'created_at' | 'updated_at' | 'accepted' | 'expires_at' | 'token'
|
||||
> {
|
||||
seller_id: string
|
||||
}
|
||||
|
||||
export interface AcceptMemberInviteDTO {
|
||||
token: string
|
||||
name: string
|
||||
}
|
||||
|
||||
export interface UpdateMemberInviteDTO extends Partial<MemberInviteDTO> {
|
||||
id: string
|
||||
}
|
||||
|
||||
export interface CreateSellerInvitationDTO {
|
||||
email: string
|
||||
registration_url: string
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
export type SplitOrderPaymentDTO = {
|
||||
id: string
|
||||
status: string
|
||||
currency_code: string
|
||||
authorized_amount: number
|
||||
captured_amount: number
|
||||
refunded_amount: number
|
||||
payment_collection_id: string
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './mutations'
|
||||
export * from './common'
|
||||
@@ -0,0 +1,20 @@
|
||||
export type CreateSplitOrderPaymentsDTO = {
|
||||
order_id: string
|
||||
status: string
|
||||
currency_code: string
|
||||
authorized_amount: number
|
||||
payment_collection_id: string
|
||||
}
|
||||
|
||||
export type UpdateSplitOrderPaymentsDTO = {
|
||||
id: string
|
||||
status?: string
|
||||
authorized_amount?: number
|
||||
captured_amount?: number
|
||||
refunded_amount?: number
|
||||
}
|
||||
|
||||
export type RefundSplitOrderPaymentsDTO = {
|
||||
id: string
|
||||
amount: number
|
||||
}
|
||||
25
backend/packages/framework/src/types/wishlist/common.ts
Normal file
25
backend/packages/framework/src/types/wishlist/common.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import {
|
||||
PriceDTO,
|
||||
ProductDTO,
|
||||
ProductVariantDTO
|
||||
} from '@medusajs/framework/types'
|
||||
|
||||
export interface WishlistProductVariantDTO extends ProductVariantDTO {
|
||||
prices: PriceDTO[]
|
||||
}
|
||||
|
||||
export interface WishlistProduct extends ProductDTO {
|
||||
variants: WishlistProductVariantDTO[]
|
||||
}
|
||||
|
||||
export type Wishlist = {
|
||||
id: string
|
||||
products: WishlistProduct[]
|
||||
}
|
||||
|
||||
export type WishlistItem = {
|
||||
wishlist_id: string
|
||||
wishlist: Wishlist
|
||||
}
|
||||
|
||||
export type WishlistResponse = WishlistItem[]
|
||||
2
backend/packages/framework/src/types/wishlist/index.ts
Normal file
2
backend/packages/framework/src/types/wishlist/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./common";
|
||||
export * from "./mutations";
|
||||
10
backend/packages/framework/src/types/wishlist/mutations.ts
Normal file
10
backend/packages/framework/src/types/wishlist/mutations.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export type CreateWishlistDTO = {
|
||||
reference: 'product'
|
||||
reference_id: string
|
||||
customer_id: string
|
||||
}
|
||||
|
||||
export type DeleteWishlistDTO = {
|
||||
id: string
|
||||
reference_id: string
|
||||
}
|
||||
1
backend/packages/framework/src/utils/index.ts
Normal file
1
backend/packages/framework/src/utils/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './money'
|
||||
79
backend/packages/framework/src/utils/money.ts
Normal file
79
backend/packages/framework/src/utils/money.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { BigNumberInput } from '@medusajs/framework/types'
|
||||
import { BigNumber, MathBN } from '@medusajs/framework/utils'
|
||||
|
||||
function getCurrencyMultiplier(currency) {
|
||||
const currencyMultipliers = {
|
||||
0: [
|
||||
'BIF',
|
||||
'CLP',
|
||||
'DJF',
|
||||
'GNF',
|
||||
'JPY',
|
||||
'KMF',
|
||||
'KRW',
|
||||
'MGA',
|
||||
'PYG',
|
||||
'RWF',
|
||||
'UGX',
|
||||
'VND',
|
||||
'VUV',
|
||||
'XAF',
|
||||
'XOF',
|
||||
'XPF'
|
||||
],
|
||||
3: ['BHD', 'IQD', 'JOD', 'KWD', 'OMR', 'TND']
|
||||
}
|
||||
|
||||
currency = currency.toUpperCase()
|
||||
let power = 2
|
||||
for (const [key, value] of Object.entries(currencyMultipliers)) {
|
||||
if (value.includes(currency)) {
|
||||
power = parseInt(key, 10)
|
||||
break
|
||||
}
|
||||
}
|
||||
return Math.pow(10, power)
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an amount to the format required by Stripe based on currency.
|
||||
* https://docs.stripe.com/currencies
|
||||
* @param {BigNumberInput} amount - The amount to be converted.
|
||||
* @param {string} currency - The currency code (e.g., 'USD', 'JOD').
|
||||
* @returns {number} - The converted amount in the smallest currency unit.
|
||||
*/
|
||||
export function getSmallestUnit(
|
||||
amount: BigNumberInput,
|
||||
currency: string
|
||||
): number {
|
||||
const multiplier = getCurrencyMultiplier(currency)
|
||||
|
||||
const amount_ =
|
||||
Math.round(new BigNumber(MathBN.mult(amount, multiplier)).numeric) /
|
||||
multiplier
|
||||
|
||||
const smallestAmount = new BigNumber(MathBN.mult(amount_, multiplier))
|
||||
|
||||
let numeric = smallestAmount.numeric
|
||||
// Check if the currency requires rounding to the nearest ten
|
||||
if (multiplier === 1e3) {
|
||||
numeric = Math.ceil(numeric / 10) * 10
|
||||
}
|
||||
|
||||
return parseInt(numeric.toString().split('.').shift()!, 10)
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an amount from the smallest currency unit to the standard unit based on currency.
|
||||
* @param {BigNumberInput} amount - The amount in the smallest currency unit.
|
||||
* @param {string} currency - The currency code (e.g., 'USD', 'JOD').
|
||||
* @returns {number} - The converted amount in the standard currency unit.
|
||||
*/
|
||||
export function getAmountFromSmallestUnit(
|
||||
amount: BigNumberInput,
|
||||
currency: string
|
||||
): number {
|
||||
const multiplier = getCurrencyMultiplier(currency)
|
||||
const standardAmount = new BigNumber(MathBN.div(amount, multiplier))
|
||||
return standardAmount.numeric
|
||||
}
|
||||
27
backend/packages/framework/tsconfig.json
Normal file
27
backend/packages/framework/tsconfig.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["ES2021"],
|
||||
"target": "ES2021",
|
||||
"outDir": "${configDir}/dist",
|
||||
"esModuleInterop": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"noUnusedLocals": true,
|
||||
"module": "node16",
|
||||
"moduleResolution": "node16",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"sourceMap": true,
|
||||
"noImplicitReturns": true,
|
||||
"resolveJsonModule": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"noImplicitThis": true,
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"incremental": false
|
||||
},
|
||||
"include": ["${configDir}/src"],
|
||||
"exclude": ["${configDir}/dist", "${configDir}/node_modules"]
|
||||
}
|
||||
45
backend/packages/modules/algolia/package.json
Normal file
45
backend/packages/modules/algolia/package.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "@mercurjs/algolia",
|
||||
"version": "1.0.0",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist",
|
||||
"!dist/**/__tests__",
|
||||
"!dist/**/__mocks__",
|
||||
"!dist/**/__fixtures__"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "rimraf dist && tsc --build",
|
||||
"migration:initial": " MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:create --initial",
|
||||
"migration:create": " MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:create",
|
||||
"migration:up": " MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:up",
|
||||
"orm:cache:clear": " MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm cache:clear"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@medusajs/framework": "2.8.6",
|
||||
"@medusajs/test-utils": "2.8.6",
|
||||
"@mercurjs/framework": "*",
|
||||
"@mikro-orm/cli": "6.4.3",
|
||||
"@mikro-orm/core": "6.4.3",
|
||||
"@mikro-orm/migrations": "6.4.3",
|
||||
"@mikro-orm/postgresql": "6.4.3",
|
||||
"@swc/core": "^1.7.28",
|
||||
"@swc/jest": "^0.2.36",
|
||||
"jest": "^29.7.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"tsc-alias": "^1.8.6",
|
||||
"typescript": "^5.6.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@medusajs/framework": "2.8.6",
|
||||
"@mikro-orm/core": "6.4.3",
|
||||
"@mikro-orm/migrations": "6.4.3",
|
||||
"@mikro-orm/postgresql": "6.4.3",
|
||||
"awilix": "^8.0.1"
|
||||
}
|
||||
}
|
||||
11
backend/packages/modules/algolia/src/index.ts
Normal file
11
backend/packages/modules/algolia/src/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { Module } from "@medusajs/framework/utils";
|
||||
|
||||
import AlgoliaModuleService from "./service";
|
||||
|
||||
export const ALGOLIA_MODULE = "algolia";
|
||||
export { AlgoliaModuleService };
|
||||
export { defaultProductSettings, defaultReviewSettings } from "./service";
|
||||
|
||||
export default Module(ALGOLIA_MODULE, {
|
||||
service: AlgoliaModuleService,
|
||||
});
|
||||
142
backend/packages/modules/algolia/src/service.ts
Normal file
142
backend/packages/modules/algolia/src/service.ts
Normal file
@@ -0,0 +1,142 @@
|
||||
import {
|
||||
Action,
|
||||
Algoliasearch,
|
||||
BatchRequest,
|
||||
IndexSettings,
|
||||
algoliasearch,
|
||||
} from "algoliasearch";
|
||||
import { IndexType, AlgoliaEntity } from "@mercurjs/framework";
|
||||
|
||||
type ModuleOptions = {
|
||||
appId: string;
|
||||
apiKey: string;
|
||||
};
|
||||
|
||||
export const defaultProductSettings: IndexSettings = {
|
||||
searchableAttributes: [
|
||||
"title",
|
||||
"subtitle",
|
||||
"brand.name",
|
||||
"tags.value",
|
||||
"type.value",
|
||||
"categories.name",
|
||||
"collection.title",
|
||||
"variants.title",
|
||||
],
|
||||
};
|
||||
|
||||
export const defaultReviewSettings: IndexSettings = {
|
||||
attributesForFaceting: ["filterOnly(reference_id)", "filterOnly(reference)"],
|
||||
};
|
||||
|
||||
class AlgoliaModuleService {
|
||||
private options_: ModuleOptions;
|
||||
private algolia_: Algoliasearch;
|
||||
|
||||
constructor(_, options: ModuleOptions) {
|
||||
this.options_ = options;
|
||||
this.algolia_ = algoliasearch(this.options_.appId, this.options_.apiKey);
|
||||
}
|
||||
|
||||
getAppId() {
|
||||
return this.options_.appId;
|
||||
}
|
||||
|
||||
checkIndex(index: IndexType) {
|
||||
return this.algolia_.indexExists({
|
||||
indexName: index,
|
||||
});
|
||||
}
|
||||
|
||||
updateSettings(index: IndexType, settings: IndexSettings) {
|
||||
return this.algolia_.setSettings({
|
||||
indexName: index,
|
||||
indexSettings: settings,
|
||||
});
|
||||
}
|
||||
|
||||
batch(type: IndexType, toAdd: AlgoliaEntity[], toDelete: string[]) {
|
||||
const requests: BatchRequest[] = toAdd.map((entity) => {
|
||||
return {
|
||||
action: "addObject" as Action,
|
||||
objectID: entity.id,
|
||||
body: entity,
|
||||
};
|
||||
});
|
||||
|
||||
requests.concat(
|
||||
toDelete.map((id) => {
|
||||
return {
|
||||
action: "deleteObject" as Action,
|
||||
objectID: id,
|
||||
body: {},
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
return this.algolia_.batch({
|
||||
indexName: type,
|
||||
batchWriteParams: {
|
||||
requests,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
batchUpsert(type: IndexType, entities: AlgoliaEntity[]) {
|
||||
return this.algolia_.batch({
|
||||
indexName: type,
|
||||
batchWriteParams: {
|
||||
requests: entities.map((entity) => {
|
||||
return {
|
||||
action: "addObject",
|
||||
objectID: entity.id,
|
||||
body: entity,
|
||||
};
|
||||
}),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
batchDelete(type: IndexType, ids: string[]) {
|
||||
return this.algolia_.batch({
|
||||
indexName: type,
|
||||
batchWriteParams: {
|
||||
requests: ids.map((id) => {
|
||||
return {
|
||||
action: "deleteObject",
|
||||
objectID: id,
|
||||
body: {},
|
||||
};
|
||||
}),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
upsert(type: IndexType, entity: AlgoliaEntity) {
|
||||
return this.algolia_.addOrUpdateObject({
|
||||
indexName: type,
|
||||
objectID: entity.id,
|
||||
body: entity,
|
||||
});
|
||||
}
|
||||
|
||||
delete(type: IndexType, id: string) {
|
||||
return this.algolia_.deleteObject({
|
||||
indexName: type,
|
||||
objectID: id,
|
||||
});
|
||||
}
|
||||
|
||||
partialUpdate(
|
||||
type: IndexType,
|
||||
entity: Partial<AlgoliaEntity> & { id: string }
|
||||
) {
|
||||
return this.algolia_.partialUpdateObject({
|
||||
indexName: type,
|
||||
objectID: entity.id,
|
||||
attributesToUpdate: { ...entity },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default AlgoliaModuleService;
|
||||
27
backend/packages/modules/algolia/tsconfig.json
Normal file
27
backend/packages/modules/algolia/tsconfig.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["ES2021"],
|
||||
"target": "ES2021",
|
||||
"outDir": "${configDir}/dist",
|
||||
"esModuleInterop": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"noUnusedLocals": true,
|
||||
"module": "node16",
|
||||
"moduleResolution": "node16",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"sourceMap": true,
|
||||
"noImplicitReturns": true,
|
||||
"resolveJsonModule": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"noImplicitThis": true,
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"incremental": false
|
||||
},
|
||||
"include": ["${configDir}/src"],
|
||||
"exclude": ["${configDir}/dist", "${configDir}/node_modules"]
|
||||
}
|
||||
45
backend/packages/modules/attribute/package.json
Normal file
45
backend/packages/modules/attribute/package.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "@mercurjs/attribute",
|
||||
"version": "1.0.0",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist",
|
||||
"!dist/**/__tests__",
|
||||
"!dist/**/__mocks__",
|
||||
"!dist/**/__fixtures__"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "rimraf dist && tsc --build",
|
||||
"migration:initial": " MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:create --initial",
|
||||
"migration:create": " MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:create",
|
||||
"migration:up": " MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:up",
|
||||
"orm:cache:clear": " MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm cache:clear"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@medusajs/framework": "2.8.6",
|
||||
"@medusajs/test-utils": "2.8.6",
|
||||
"@mercurjs/framework": "*",
|
||||
"@mikro-orm/cli": "6.4.3",
|
||||
"@mikro-orm/core": "6.4.3",
|
||||
"@mikro-orm/migrations": "6.4.3",
|
||||
"@mikro-orm/postgresql": "6.4.3",
|
||||
"@swc/core": "^1.7.28",
|
||||
"@swc/jest": "^0.2.36",
|
||||
"jest": "^29.7.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"tsc-alias": "^1.8.6",
|
||||
"typescript": "^5.6.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@medusajs/framework": "2.8.6",
|
||||
"@mikro-orm/core": "6.4.3",
|
||||
"@mikro-orm/migrations": "6.4.3",
|
||||
"@mikro-orm/postgresql": "6.4.3",
|
||||
"awilix": "^8.0.1"
|
||||
}
|
||||
}
|
||||
10
backend/packages/modules/attribute/src/index.ts
Normal file
10
backend/packages/modules/attribute/src/index.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Module } from "@medusajs/framework/utils";
|
||||
|
||||
import AttributeModuleService from "./service";
|
||||
|
||||
export const ATTRIBUTE_MODULE = "attribute";
|
||||
export { AttributeModuleService };
|
||||
|
||||
export default Module(ATTRIBUTE_MODULE, {
|
||||
service: AttributeModuleService,
|
||||
});
|
||||
@@ -0,0 +1,422 @@
|
||||
{
|
||||
"namespaces": [
|
||||
"public"
|
||||
],
|
||||
"name": "public",
|
||||
"tables": [
|
||||
{
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"description": {
|
||||
"name": "description",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"is_filterable": {
|
||||
"name": "is_filterable",
|
||||
"type": "boolean",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"default": "true",
|
||||
"mappedType": "boolean"
|
||||
},
|
||||
"handle": {
|
||||
"name": "handle",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"metadata": {
|
||||
"name": "metadata",
|
||||
"type": "jsonb",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"mappedType": "json"
|
||||
},
|
||||
"ui_component": {
|
||||
"name": "ui_component",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"default": "'select'",
|
||||
"enumItems": [
|
||||
"select",
|
||||
"multivalue",
|
||||
"unit",
|
||||
"toggle",
|
||||
"text_area",
|
||||
"color_picker"
|
||||
],
|
||||
"mappedType": "enum"
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"length": 6,
|
||||
"default": "now()",
|
||||
"mappedType": "datetime"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"length": 6,
|
||||
"default": "now()",
|
||||
"mappedType": "datetime"
|
||||
},
|
||||
"deleted_at": {
|
||||
"name": "deleted_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"length": 6,
|
||||
"mappedType": "datetime"
|
||||
}
|
||||
},
|
||||
"name": "attribute",
|
||||
"schema": "public",
|
||||
"indexes": [
|
||||
{
|
||||
"keyName": "IDX_attribute_handle_unique",
|
||||
"columnNames": [],
|
||||
"composite": false,
|
||||
"constraint": false,
|
||||
"primary": false,
|
||||
"unique": false,
|
||||
"expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_attribute_handle_unique\" ON \"attribute\" (handle) WHERE deleted_at IS NULL"
|
||||
},
|
||||
{
|
||||
"keyName": "IDX_attribute_deleted_at",
|
||||
"columnNames": [],
|
||||
"composite": false,
|
||||
"constraint": false,
|
||||
"primary": false,
|
||||
"unique": false,
|
||||
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_attribute_deleted_at\" ON \"attribute\" (deleted_at) WHERE deleted_at IS NULL"
|
||||
},
|
||||
{
|
||||
"keyName": "attribute_pkey",
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"composite": false,
|
||||
"constraint": true,
|
||||
"primary": true,
|
||||
"unique": true
|
||||
}
|
||||
],
|
||||
"checks": [],
|
||||
"foreignKeys": {},
|
||||
"nativeEnums": {}
|
||||
},
|
||||
{
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"value": {
|
||||
"name": "value",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"rank": {
|
||||
"name": "rank",
|
||||
"type": "integer",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "integer"
|
||||
},
|
||||
"metadata": {
|
||||
"name": "metadata",
|
||||
"type": "jsonb",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"mappedType": "json"
|
||||
},
|
||||
"attribute_id": {
|
||||
"name": "attribute_id",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"length": 6,
|
||||
"default": "now()",
|
||||
"mappedType": "datetime"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"length": 6,
|
||||
"default": "now()",
|
||||
"mappedType": "datetime"
|
||||
},
|
||||
"deleted_at": {
|
||||
"name": "deleted_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"length": 6,
|
||||
"mappedType": "datetime"
|
||||
}
|
||||
},
|
||||
"name": "attribute_possible_value",
|
||||
"schema": "public",
|
||||
"indexes": [
|
||||
{
|
||||
"keyName": "IDX_attribute_possible_value_attribute_id",
|
||||
"columnNames": [],
|
||||
"composite": false,
|
||||
"constraint": false,
|
||||
"primary": false,
|
||||
"unique": false,
|
||||
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_attribute_possible_value_attribute_id\" ON \"attribute_possible_value\" (attribute_id) WHERE deleted_at IS NULL"
|
||||
},
|
||||
{
|
||||
"keyName": "IDX_attribute_possible_value_deleted_at",
|
||||
"columnNames": [],
|
||||
"composite": false,
|
||||
"constraint": false,
|
||||
"primary": false,
|
||||
"unique": false,
|
||||
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_attribute_possible_value_deleted_at\" ON \"attribute_possible_value\" (deleted_at) WHERE deleted_at IS NULL"
|
||||
},
|
||||
{
|
||||
"keyName": "UQ_attribute_id_value",
|
||||
"columnNames": [],
|
||||
"composite": false,
|
||||
"constraint": false,
|
||||
"primary": false,
|
||||
"unique": false,
|
||||
"expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"UQ_attribute_id_value\" ON \"attribute_possible_value\" (attribute_id, value) WHERE deleted_at IS NULL"
|
||||
},
|
||||
{
|
||||
"keyName": "attribute_possible_value_pkey",
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"composite": false,
|
||||
"constraint": true,
|
||||
"primary": true,
|
||||
"unique": true
|
||||
}
|
||||
],
|
||||
"checks": [],
|
||||
"foreignKeys": {
|
||||
"attribute_possible_value_attribute_id_foreign": {
|
||||
"constraintName": "attribute_possible_value_attribute_id_foreign",
|
||||
"columnNames": [
|
||||
"attribute_id"
|
||||
],
|
||||
"localTableName": "public.attribute_possible_value",
|
||||
"referencedColumnNames": [
|
||||
"id"
|
||||
],
|
||||
"referencedTableName": "public.attribute",
|
||||
"deleteRule": "cascade",
|
||||
"updateRule": "cascade"
|
||||
}
|
||||
},
|
||||
"nativeEnums": {}
|
||||
},
|
||||
{
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"value": {
|
||||
"name": "value",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"rank": {
|
||||
"name": "rank",
|
||||
"type": "integer",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "integer"
|
||||
},
|
||||
"metadata": {
|
||||
"name": "metadata",
|
||||
"type": "jsonb",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"mappedType": "json"
|
||||
},
|
||||
"attribute_id": {
|
||||
"name": "attribute_id",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"length": 6,
|
||||
"default": "now()",
|
||||
"mappedType": "datetime"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"length": 6,
|
||||
"default": "now()",
|
||||
"mappedType": "datetime"
|
||||
},
|
||||
"deleted_at": {
|
||||
"name": "deleted_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"length": 6,
|
||||
"mappedType": "datetime"
|
||||
}
|
||||
},
|
||||
"name": "attribute_value",
|
||||
"schema": "public",
|
||||
"indexes": [
|
||||
{
|
||||
"keyName": "IDX_attribute_value_attribute_id",
|
||||
"columnNames": [],
|
||||
"composite": false,
|
||||
"constraint": false,
|
||||
"primary": false,
|
||||
"unique": false,
|
||||
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_attribute_value_attribute_id\" ON \"attribute_value\" (attribute_id) WHERE deleted_at IS NULL"
|
||||
},
|
||||
{
|
||||
"keyName": "IDX_attribute_value_deleted_at",
|
||||
"columnNames": [],
|
||||
"composite": false,
|
||||
"constraint": false,
|
||||
"primary": false,
|
||||
"unique": false,
|
||||
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_attribute_value_deleted_at\" ON \"attribute_value\" (deleted_at) WHERE deleted_at IS NULL"
|
||||
},
|
||||
{
|
||||
"keyName": "attribute_value_pkey",
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"composite": false,
|
||||
"constraint": true,
|
||||
"primary": true,
|
||||
"unique": true
|
||||
}
|
||||
],
|
||||
"checks": [],
|
||||
"foreignKeys": {
|
||||
"attribute_value_attribute_id_foreign": {
|
||||
"constraintName": "attribute_value_attribute_id_foreign",
|
||||
"columnNames": [
|
||||
"attribute_id"
|
||||
],
|
||||
"localTableName": "public.attribute_value",
|
||||
"referencedColumnNames": [
|
||||
"id"
|
||||
],
|
||||
"referencedTableName": "public.attribute",
|
||||
"deleteRule": "cascade",
|
||||
"updateRule": "cascade"
|
||||
}
|
||||
},
|
||||
"nativeEnums": {}
|
||||
}
|
||||
],
|
||||
"nativeEnums": {}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { Migration } from '@mikro-orm/migrations';
|
||||
|
||||
export class Migration20250617080244 extends Migration {
|
||||
|
||||
override async up(): Promise<void> {
|
||||
this.addSql(`alter table if exists "attribute" drop constraint if exists "attribute_handle_unique";`);
|
||||
this.addSql(`create table if not exists "attribute" ("id" text not null, "name" text not null, "description" text null, "handle" text not null, "metadata" jsonb null, "ui_component" text check ("ui_component" in ('select', 'multivalue', 'unit', 'toggle', 'text_area', 'color_picker')) not null default 'select', "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "attribute_pkey" primary key ("id"));`);
|
||||
this.addSql(`CREATE UNIQUE INDEX IF NOT EXISTS "IDX_attribute_handle_unique" ON "attribute" (handle) WHERE deleted_at IS NULL;`);
|
||||
this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_attribute_deleted_at" ON "attribute" (deleted_at) WHERE deleted_at IS NULL;`);
|
||||
|
||||
this.addSql(`create table if not exists "attribute_possible_value" ("id" text not null, "value" text not null, "rank" integer not null, "metadata" jsonb null, "attribute_id" text not null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "attribute_possible_value_pkey" primary key ("id"));`);
|
||||
this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_attribute_possible_value_attribute_id" ON "attribute_possible_value" (attribute_id) WHERE deleted_at IS NULL;`);
|
||||
this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_attribute_possible_value_deleted_at" ON "attribute_possible_value" (deleted_at) WHERE deleted_at IS NULL;`);
|
||||
this.addSql(`CREATE UNIQUE INDEX IF NOT EXISTS "UQ_attribute_id_value" ON "attribute_possible_value" (attribute_id, value) WHERE deleted_at IS NULL;`);
|
||||
|
||||
this.addSql(`create table if not exists "attribute_value" ("id" text not null, "value" text not null, "rank" integer not null, "metadata" jsonb null, "attribute_id" text not null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "attribute_value_pkey" primary key ("id"));`);
|
||||
this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_attribute_value_attribute_id" ON "attribute_value" (attribute_id) WHERE deleted_at IS NULL;`);
|
||||
this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_attribute_value_deleted_at" ON "attribute_value" (deleted_at) WHERE deleted_at IS NULL;`);
|
||||
|
||||
this.addSql(`alter table if exists "attribute_possible_value" add constraint "attribute_possible_value_attribute_id_foreign" foreign key ("attribute_id") references "attribute" ("id") on update cascade on delete cascade;`);
|
||||
|
||||
this.addSql(`alter table if exists "attribute_value" add constraint "attribute_value_attribute_id_foreign" foreign key ("attribute_id") references "attribute" ("id") on update cascade on delete cascade;`);
|
||||
}
|
||||
|
||||
override async down(): Promise<void> {
|
||||
this.addSql(`alter table if exists "attribute_possible_value" drop constraint if exists "attribute_possible_value_attribute_id_foreign";`);
|
||||
|
||||
this.addSql(`alter table if exists "attribute_value" drop constraint if exists "attribute_value_attribute_id_foreign";`);
|
||||
|
||||
this.addSql(`drop table if exists "attribute" cascade;`);
|
||||
|
||||
this.addSql(`drop table if exists "attribute_possible_value" cascade;`);
|
||||
|
||||
this.addSql(`drop table if exists "attribute_value" cascade;`);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { Migration } from '@mikro-orm/migrations';
|
||||
|
||||
export class Migration20250620110849 extends Migration {
|
||||
|
||||
override async up(): Promise<void> {
|
||||
this.addSql(`alter table if exists "attribute" add column if not exists "is_filterable" boolean not null default true;`);
|
||||
}
|
||||
|
||||
override async down(): Promise<void> {
|
||||
this.addSql(`alter table if exists "attribute" drop column if exists "is_filterable";`);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { model } from '@medusajs/framework/utils'
|
||||
|
||||
import Attribute from './attribute'
|
||||
|
||||
const AttributePossibleValue = model
|
||||
.define('attribute_possible_value', {
|
||||
id: model.id({ prefix: 'attr_pos_val' }).primaryKey(),
|
||||
value: model.text(),
|
||||
rank: model.number(),
|
||||
metadata: model.json().nullable(),
|
||||
attribute: model.belongsTo(() => Attribute, {
|
||||
mappedBy: 'possible_values'
|
||||
})
|
||||
})
|
||||
.indexes([
|
||||
{
|
||||
on: ['attribute_id', 'value'],
|
||||
name: 'UQ_attribute_id_value',
|
||||
unique: true
|
||||
}
|
||||
])
|
||||
|
||||
export default AttributePossibleValue
|
||||
@@ -0,0 +1,15 @@
|
||||
import { model } from '@medusajs/framework/utils'
|
||||
|
||||
import Attribute from './attribute'
|
||||
|
||||
const AttributeValue = model.define('attribute_value', {
|
||||
id: model.id({ prefix: 'attr_val' }).primaryKey(),
|
||||
value: model.text(),
|
||||
rank: model.number(),
|
||||
metadata: model.json().nullable(),
|
||||
attribute: model.belongsTo(() => Attribute, {
|
||||
mappedBy: 'values'
|
||||
})
|
||||
})
|
||||
|
||||
export default AttributeValue
|
||||
25
backend/packages/modules/attribute/src/models/attribute.ts
Normal file
25
backend/packages/modules/attribute/src/models/attribute.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { model } from "@medusajs/framework/utils";
|
||||
|
||||
import { AttributeUIComponent } from "@mercurjs/framework";
|
||||
import AttributePossibleValue from "./attribute-possible-value";
|
||||
import AttributeValue from "./attribute-value";
|
||||
|
||||
const Attribute = model
|
||||
.define("attribute", {
|
||||
id: model.id({ prefix: "attr" }).primaryKey(),
|
||||
name: model.text().searchable(),
|
||||
description: model.text().nullable(),
|
||||
is_filterable: model.boolean().default(true),
|
||||
handle: model.text().unique(),
|
||||
metadata: model.json().nullable(),
|
||||
ui_component: model
|
||||
.enum(Object.values(AttributeUIComponent))
|
||||
.default(AttributeUIComponent.SELECT),
|
||||
values: model.hasMany(() => AttributeValue),
|
||||
possible_values: model.hasMany(() => AttributePossibleValue),
|
||||
})
|
||||
.cascades({
|
||||
delete: ["values", "possible_values"],
|
||||
});
|
||||
|
||||
export default Attribute;
|
||||
93
backend/packages/modules/attribute/src/service.ts
Normal file
93
backend/packages/modules/attribute/src/service.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import { EntityManager } from "@mikro-orm/knex";
|
||||
import { UpdateAttributeDTO } from "@mercurjs/framework";
|
||||
import { Context, DAL, InferTypeOf } from "@medusajs/framework/types";
|
||||
import {
|
||||
InjectManager,
|
||||
InjectTransactionManager,
|
||||
MedusaContext,
|
||||
MedusaService,
|
||||
} from "@medusajs/framework/utils";
|
||||
|
||||
import Attribute from "./models/attribute";
|
||||
import AttributePossibleValue from "./models/attribute-possible-value";
|
||||
import AttributeValue from "./models/attribute-value";
|
||||
|
||||
type Attribute = InferTypeOf<typeof Attribute>;
|
||||
type AttributePossibleValue = InferTypeOf<typeof AttributePossibleValue>;
|
||||
|
||||
type InjectedDependencies = {
|
||||
attributeRepository: DAL.RepositoryService<Attribute>;
|
||||
attributePossibleValueRepository: DAL.RepositoryService<AttributePossibleValue>;
|
||||
};
|
||||
|
||||
class AttributeModuleService extends MedusaService({
|
||||
Attribute,
|
||||
AttributeValue,
|
||||
AttributePossibleValue,
|
||||
}) {
|
||||
protected attributeRepository_: DAL.RepositoryService<Attribute>;
|
||||
protected attributePossibleValueRepository_: DAL.RepositoryService<AttributePossibleValue>;
|
||||
|
||||
constructor({
|
||||
attributeRepository,
|
||||
attributePossibleValueRepository,
|
||||
}: InjectedDependencies) {
|
||||
super(...arguments);
|
||||
this.attributeRepository_ = attributeRepository;
|
||||
this.attributePossibleValueRepository_ = attributePossibleValueRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param input
|
||||
* @param sharedContext
|
||||
*
|
||||
* Useful to update attribute, allowing to upsert possible_values in the same operation. If "id"
|
||||
* is not provided for "possible_values" entries, it will lookup the DB by attributePossibleValue.value,
|
||||
* to update or create accordingly.
|
||||
*
|
||||
* Assumes caller will eventually refetch entities, for now, to reduce complexity of this
|
||||
* method and concentrate on upserting like ProductOption - ProductOptionValue from Medusa
|
||||
*/
|
||||
@InjectManager()
|
||||
async updateAttributeWithUpsertOrReplacePossibleValues(
|
||||
input: UpdateAttributeDTO | UpdateAttributeDTO[],
|
||||
@MedusaContext() sharedContext?: Context<EntityManager>
|
||||
) {
|
||||
const normalizedInput = Array.isArray(input) ? input : [input];
|
||||
|
||||
return this.updateAttributeWithUpsertOrReplacePossibleValues_(
|
||||
normalizedInput,
|
||||
sharedContext
|
||||
);
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async updateAttributeWithUpsertOrReplacePossibleValues_(
|
||||
input: UpdateAttributeDTO[],
|
||||
@MedusaContext() sharedContext?: Context<EntityManager>
|
||||
) {
|
||||
const upsertedValues = await this.attributePossibleValueRepository_.upsert(
|
||||
input.flatMap((element) => element.possible_values),
|
||||
sharedContext
|
||||
);
|
||||
|
||||
const attributesInput = input.map((toUpdate) => {
|
||||
const { ...attribute } = toUpdate;
|
||||
return {
|
||||
...attribute,
|
||||
possible_values: upsertedValues
|
||||
.filter((val) => val.attribute_id === attribute.id)
|
||||
.map((upserted) => ({ id: upserted.id })),
|
||||
};
|
||||
});
|
||||
|
||||
return this.attributeRepository_.upsertWithReplace(
|
||||
attributesInput,
|
||||
{ relations: ["possible_values"] },
|
||||
sharedContext
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default AttributeModuleService;
|
||||
27
backend/packages/modules/attribute/tsconfig.json
Normal file
27
backend/packages/modules/attribute/tsconfig.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["ES2021"],
|
||||
"target": "ES2021",
|
||||
"outDir": "${configDir}/dist",
|
||||
"esModuleInterop": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"noUnusedLocals": true,
|
||||
"module": "node16",
|
||||
"moduleResolution": "node16",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"sourceMap": true,
|
||||
"noImplicitReturns": true,
|
||||
"resolveJsonModule": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"noImplicitThis": true,
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"incremental": false
|
||||
},
|
||||
"include": ["${configDir}/src"],
|
||||
"exclude": ["${configDir}/dist", "${configDir}/node_modules"]
|
||||
}
|
||||
45
backend/packages/modules/brand/package.json
Normal file
45
backend/packages/modules/brand/package.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "@mercurjs/brand",
|
||||
"version": "1.0.0",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist",
|
||||
"!dist/**/__tests__",
|
||||
"!dist/**/__mocks__",
|
||||
"!dist/**/__fixtures__"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "rimraf dist && tsc --build",
|
||||
"migration:initial": " MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:create --initial",
|
||||
"migration:create": " MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:create",
|
||||
"migration:up": " MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:up",
|
||||
"orm:cache:clear": " MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm cache:clear"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@medusajs/framework": "2.8.6",
|
||||
"@medusajs/test-utils": "2.8.6",
|
||||
"@mercurjs/framework": "*",
|
||||
"@mikro-orm/cli": "6.4.3",
|
||||
"@mikro-orm/core": "6.4.3",
|
||||
"@mikro-orm/migrations": "6.4.3",
|
||||
"@mikro-orm/postgresql": "6.4.3",
|
||||
"@swc/core": "^1.7.28",
|
||||
"@swc/jest": "^0.2.36",
|
||||
"jest": "^29.7.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"tsc-alias": "^1.8.6",
|
||||
"typescript": "^5.6.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@medusajs/framework": "2.8.6",
|
||||
"@mikro-orm/core": "6.4.3",
|
||||
"@mikro-orm/migrations": "6.4.3",
|
||||
"@mikro-orm/postgresql": "6.4.3",
|
||||
"awilix": "^8.0.1"
|
||||
}
|
||||
}
|
||||
10
backend/packages/modules/brand/src/index.ts
Normal file
10
backend/packages/modules/brand/src/index.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Module } from "@medusajs/framework/utils";
|
||||
|
||||
import BrandModuleService from "./service";
|
||||
|
||||
export const BRAND_MODULE = "brand";
|
||||
export { BrandModuleService };
|
||||
|
||||
export default Module(BRAND_MODULE, {
|
||||
service: BrandModuleService,
|
||||
});
|
||||
@@ -0,0 +1,85 @@
|
||||
{
|
||||
"namespaces": [
|
||||
"public"
|
||||
],
|
||||
"name": "public",
|
||||
"tables": [
|
||||
{
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"length": 6,
|
||||
"default": "now()",
|
||||
"mappedType": "datetime"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"length": 6,
|
||||
"default": "now()",
|
||||
"mappedType": "datetime"
|
||||
},
|
||||
"deleted_at": {
|
||||
"name": "deleted_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"length": 6,
|
||||
"mappedType": "datetime"
|
||||
}
|
||||
},
|
||||
"name": "brand",
|
||||
"schema": "public",
|
||||
"indexes": [
|
||||
{
|
||||
"keyName": "IDX_brand_deleted_at",
|
||||
"columnNames": [],
|
||||
"composite": false,
|
||||
"primary": false,
|
||||
"unique": false,
|
||||
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_brand_deleted_at\" ON \"brand\" (deleted_at) WHERE deleted_at IS NULL"
|
||||
},
|
||||
{
|
||||
"keyName": "brand_pkey",
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"composite": false,
|
||||
"primary": true,
|
||||
"unique": true
|
||||
}
|
||||
],
|
||||
"checks": [],
|
||||
"foreignKeys": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Migration } from '@mikro-orm/migrations';
|
||||
|
||||
export class Migration20250218113025 extends Migration {
|
||||
|
||||
async up(): Promise<void> {
|
||||
this.addSql('create table if not exists "brand" ("id" text not null, "name" text not null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "brand_pkey" primary key ("id"));');
|
||||
this.addSql('CREATE INDEX IF NOT EXISTS "IDX_brand_deleted_at" ON "brand" (deleted_at) WHERE deleted_at IS NULL;');
|
||||
}
|
||||
|
||||
async down(): Promise<void> {
|
||||
this.addSql('drop table if exists "brand" cascade;');
|
||||
}
|
||||
|
||||
}
|
||||
6
backend/packages/modules/brand/src/models/brand.ts
Normal file
6
backend/packages/modules/brand/src/models/brand.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { model } from '@medusajs/framework/utils'
|
||||
|
||||
export const Brand = model.define('brand', {
|
||||
id: model.id().primaryKey(),
|
||||
name: model.text()
|
||||
})
|
||||
9
backend/packages/modules/brand/src/service.ts
Normal file
9
backend/packages/modules/brand/src/service.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { MedusaService } from '@medusajs/framework/utils'
|
||||
|
||||
import { Brand } from './models/brand'
|
||||
|
||||
class BrandModuleService extends MedusaService({
|
||||
Brand
|
||||
}) {}
|
||||
|
||||
export default BrandModuleService
|
||||
27
backend/packages/modules/brand/tsconfig.json
Normal file
27
backend/packages/modules/brand/tsconfig.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["ES2021"],
|
||||
"target": "ES2021",
|
||||
"outDir": "${configDir}/dist",
|
||||
"esModuleInterop": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"noUnusedLocals": true,
|
||||
"module": "node16",
|
||||
"moduleResolution": "node16",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"sourceMap": true,
|
||||
"noImplicitReturns": true,
|
||||
"resolveJsonModule": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"noImplicitThis": true,
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"incremental": false
|
||||
},
|
||||
"include": ["${configDir}/src"],
|
||||
"exclude": ["${configDir}/dist", "${configDir}/node_modules"]
|
||||
}
|
||||
45
backend/packages/modules/commission/package.json
Normal file
45
backend/packages/modules/commission/package.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "@mercurjs/commission",
|
||||
"version": "1.0.0",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist",
|
||||
"!dist/**/__tests__",
|
||||
"!dist/**/__mocks__",
|
||||
"!dist/**/__fixtures__"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "rimraf dist && tsc --build",
|
||||
"migration:initial": " MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:create --initial",
|
||||
"migration:create": " MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:create",
|
||||
"migration:up": " MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:up",
|
||||
"orm:cache:clear": " MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm cache:clear"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@medusajs/framework": "2.8.6",
|
||||
"@medusajs/test-utils": "2.8.6",
|
||||
"@mercurjs/framework": "*",
|
||||
"@mikro-orm/cli": "6.4.3",
|
||||
"@mikro-orm/core": "6.4.3",
|
||||
"@mikro-orm/migrations": "6.4.3",
|
||||
"@mikro-orm/postgresql": "6.4.3",
|
||||
"@swc/core": "^1.7.28",
|
||||
"@swc/jest": "^0.2.36",
|
||||
"jest": "^29.7.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"tsc-alias": "^1.8.6",
|
||||
"typescript": "^5.6.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@medusajs/framework": "2.8.6",
|
||||
"@mikro-orm/core": "6.4.3",
|
||||
"@mikro-orm/migrations": "6.4.3",
|
||||
"@mikro-orm/postgresql": "6.4.3",
|
||||
"awilix": "^8.0.1"
|
||||
}
|
||||
}
|
||||
10
backend/packages/modules/commission/src/index.ts
Normal file
10
backend/packages/modules/commission/src/index.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Module } from "@medusajs/framework/utils";
|
||||
|
||||
import CommissionModuleService from "./service";
|
||||
|
||||
export const COMMISSION_MODULE = "commission";
|
||||
export { CommissionModuleService };
|
||||
|
||||
export default Module(COMMISSION_MODULE, {
|
||||
service: CommissionModuleService,
|
||||
});
|
||||
@@ -0,0 +1,388 @@
|
||||
{
|
||||
"namespaces": [
|
||||
"public"
|
||||
],
|
||||
"name": "public",
|
||||
"tables": [
|
||||
{
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"item_line_id": {
|
||||
"name": "item_line_id",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"rule_id": {
|
||||
"name": "rule_id",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"currency_code": {
|
||||
"name": "currency_code",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"value": {
|
||||
"name": "value",
|
||||
"type": "numeric",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "decimal"
|
||||
},
|
||||
"raw_value": {
|
||||
"name": "raw_value",
|
||||
"type": "jsonb",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "json"
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"length": 6,
|
||||
"default": "now()",
|
||||
"mappedType": "datetime"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"length": 6,
|
||||
"default": "now()",
|
||||
"mappedType": "datetime"
|
||||
},
|
||||
"deleted_at": {
|
||||
"name": "deleted_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"length": 6,
|
||||
"mappedType": "datetime"
|
||||
}
|
||||
},
|
||||
"name": "commission_line",
|
||||
"schema": "public",
|
||||
"indexes": [
|
||||
{
|
||||
"keyName": "IDX_commission_line_deleted_at",
|
||||
"columnNames": [],
|
||||
"composite": false,
|
||||
"primary": false,
|
||||
"unique": false,
|
||||
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_commission_line_deleted_at\" ON \"commission_line\" (deleted_at) WHERE deleted_at IS NULL"
|
||||
},
|
||||
{
|
||||
"keyName": "commission_line_pkey",
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"composite": false,
|
||||
"primary": true,
|
||||
"unique": true
|
||||
}
|
||||
],
|
||||
"checks": [],
|
||||
"foreignKeys": {}
|
||||
},
|
||||
{
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"reference": {
|
||||
"name": "reference",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"reference_id": {
|
||||
"name": "reference_id",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"is_active": {
|
||||
"name": "is_active",
|
||||
"type": "boolean",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"default": "true",
|
||||
"mappedType": "boolean"
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"length": 6,
|
||||
"default": "now()",
|
||||
"mappedType": "datetime"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"length": 6,
|
||||
"default": "now()",
|
||||
"mappedType": "datetime"
|
||||
},
|
||||
"deleted_at": {
|
||||
"name": "deleted_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"length": 6,
|
||||
"mappedType": "datetime"
|
||||
}
|
||||
},
|
||||
"name": "commission_rule",
|
||||
"schema": "public",
|
||||
"indexes": [
|
||||
{
|
||||
"keyName": "IDX_commission_rule_deleted_at",
|
||||
"columnNames": [],
|
||||
"composite": false,
|
||||
"primary": false,
|
||||
"unique": false,
|
||||
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_commission_rule_deleted_at\" ON \"commission_rule\" (deleted_at) WHERE deleted_at IS NULL"
|
||||
},
|
||||
{
|
||||
"keyName": "commission_rule_pkey",
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"composite": false,
|
||||
"primary": true,
|
||||
"unique": true
|
||||
}
|
||||
],
|
||||
"checks": [],
|
||||
"foreignKeys": {}
|
||||
},
|
||||
{
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"type": {
|
||||
"name": "type",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"percentage_rate": {
|
||||
"name": "percentage_rate",
|
||||
"type": "integer",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"mappedType": "integer"
|
||||
},
|
||||
"include_tax": {
|
||||
"name": "include_tax",
|
||||
"type": "boolean",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "boolean"
|
||||
},
|
||||
"price_set_id": {
|
||||
"name": "price_set_id",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"max_price_set_id": {
|
||||
"name": "max_price_set_id",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"min_price_set_id": {
|
||||
"name": "min_price_set_id",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"rule_id": {
|
||||
"name": "rule_id",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"length": 6,
|
||||
"default": "now()",
|
||||
"mappedType": "datetime"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"length": 6,
|
||||
"default": "now()",
|
||||
"mappedType": "datetime"
|
||||
},
|
||||
"deleted_at": {
|
||||
"name": "deleted_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"length": 6,
|
||||
"mappedType": "datetime"
|
||||
}
|
||||
},
|
||||
"name": "commission_rate",
|
||||
"schema": "public",
|
||||
"indexes": [
|
||||
{
|
||||
"columnNames": [
|
||||
"rule_id"
|
||||
],
|
||||
"composite": false,
|
||||
"keyName": "commission_rate_rule_id_unique",
|
||||
"primary": false,
|
||||
"unique": true
|
||||
},
|
||||
{
|
||||
"keyName": "IDX_commission_rate_rule_id",
|
||||
"columnNames": [],
|
||||
"composite": false,
|
||||
"primary": false,
|
||||
"unique": false,
|
||||
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_commission_rate_rule_id\" ON \"commission_rate\" (rule_id) WHERE deleted_at IS NULL"
|
||||
},
|
||||
{
|
||||
"keyName": "IDX_commission_rate_deleted_at",
|
||||
"columnNames": [],
|
||||
"composite": false,
|
||||
"primary": false,
|
||||
"unique": false,
|
||||
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_commission_rate_deleted_at\" ON \"commission_rate\" (deleted_at) WHERE deleted_at IS NULL"
|
||||
},
|
||||
{
|
||||
"keyName": "commission_rate_pkey",
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"composite": false,
|
||||
"primary": true,
|
||||
"unique": true
|
||||
}
|
||||
],
|
||||
"checks": [],
|
||||
"foreignKeys": {
|
||||
"commission_rate_rule_id_foreign": {
|
||||
"constraintName": "commission_rate_rule_id_foreign",
|
||||
"columnNames": [
|
||||
"rule_id"
|
||||
],
|
||||
"localTableName": "public.commission_rate",
|
||||
"referencedColumnNames": [
|
||||
"id"
|
||||
],
|
||||
"referencedTableName": "public.commission_rule",
|
||||
"deleteRule": "set null",
|
||||
"updateRule": "cascade"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { Migration } from '@mikro-orm/migrations';
|
||||
|
||||
export class Migration20250124152358 extends Migration {
|
||||
|
||||
async up(): Promise<void> {
|
||||
this.addSql('create table if not exists "commission_line" ("id" text not null, "item_line_id" text not null, "rule_id" text not null, "currency_code" text not null, "value" numeric not null, "raw_value" jsonb not null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "commission_line_pkey" primary key ("id"));');
|
||||
this.addSql('CREATE INDEX IF NOT EXISTS "IDX_commission_line_deleted_at" ON "commission_line" (deleted_at) WHERE deleted_at IS NULL;');
|
||||
|
||||
this.addSql('create table if not exists "commission_rule" ("id" text not null, "name" text not null, "reference" text not null, "reference_id" text not null, "is_active" boolean not null default true, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "commission_rule_pkey" primary key ("id"));');
|
||||
this.addSql('CREATE INDEX IF NOT EXISTS "IDX_commission_rule_deleted_at" ON "commission_rule" (deleted_at) WHERE deleted_at IS NULL;');
|
||||
|
||||
this.addSql('create table if not exists "commission_rate" ("id" text not null, "type" text not null, "percentage_rate" integer not null, "include_tax" boolean not null, "price_set_id" text not null, "max_price_set_id" text not null, "min_price_set_id" text not null, "rule_id" text null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "commission_rate_pkey" primary key ("id"));');
|
||||
this.addSql('alter table if exists "commission_rate" add constraint "commission_rate_rule_id_unique" unique ("rule_id");');
|
||||
this.addSql('CREATE INDEX IF NOT EXISTS "IDX_commission_rate_rule_id" ON "commission_rate" (rule_id) WHERE deleted_at IS NULL;');
|
||||
this.addSql('CREATE INDEX IF NOT EXISTS "IDX_commission_rate_deleted_at" ON "commission_rate" (deleted_at) WHERE deleted_at IS NULL;');
|
||||
|
||||
this.addSql('alter table if exists "commission_rate" add constraint "commission_rate_rule_id_foreign" foreign key ("rule_id") references "commission_rule" ("id") on update cascade on delete set null;');
|
||||
}
|
||||
|
||||
async down(): Promise<void> {
|
||||
this.addSql('alter table if exists "commission_rate" drop constraint if exists "commission_rate_rule_id_foreign";');
|
||||
|
||||
this.addSql('drop table if exists "commission_line" cascade;');
|
||||
|
||||
this.addSql('drop table if exists "commission_rule" cascade;');
|
||||
|
||||
this.addSql('drop table if exists "commission_rate" cascade;');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import { Migration } from '@mikro-orm/migrations'
|
||||
|
||||
export class Migration20250127073504 extends Migration {
|
||||
async up(): Promise<void> {
|
||||
this.addSql(
|
||||
'alter table if exists "commission_rate" alter column "percentage_rate" type integer using ("percentage_rate"::integer);'
|
||||
)
|
||||
this.addSql(
|
||||
'alter table if exists "commission_rate" alter column "percentage_rate" drop not null;'
|
||||
)
|
||||
this.addSql(
|
||||
'alter table if exists "commission_rate" alter column "price_set_id" type text using ("price_set_id"::text);'
|
||||
)
|
||||
this.addSql(
|
||||
'alter table if exists "commission_rate" alter column "price_set_id" drop not null;'
|
||||
)
|
||||
this.addSql(
|
||||
'alter table if exists "commission_rate" alter column "max_price_set_id" type text using ("max_price_set_id"::text);'
|
||||
)
|
||||
this.addSql(
|
||||
'alter table if exists "commission_rate" alter column "max_price_set_id" drop not null;'
|
||||
)
|
||||
this.addSql(
|
||||
'alter table if exists "commission_rate" alter column "min_price_set_id" type text using ("min_price_set_id"::text);'
|
||||
)
|
||||
this.addSql(
|
||||
'alter table if exists "commission_rate" alter column "min_price_set_id" drop not null;'
|
||||
)
|
||||
}
|
||||
|
||||
async down(): Promise<void> {
|
||||
this.addSql(
|
||||
'alter table if exists "commission_rate" alter column "percentage_rate" type integer using ("percentage_rate"::integer);'
|
||||
)
|
||||
this.addSql(
|
||||
'alter table if exists "commission_rate" alter column "percentage_rate" set not null;'
|
||||
)
|
||||
this.addSql(
|
||||
'alter table if exists "commission_rate" alter column "price_set_id" type text using ("price_set_id"::text);'
|
||||
)
|
||||
this.addSql(
|
||||
'alter table if exists "commission_rate" alter column "price_set_id" set not null;'
|
||||
)
|
||||
this.addSql(
|
||||
'alter table if exists "commission_rate" alter column "max_price_set_id" type text using ("max_price_set_id"::text);'
|
||||
)
|
||||
this.addSql(
|
||||
'alter table if exists "commission_rate" alter column "max_price_set_id" set not null;'
|
||||
)
|
||||
this.addSql(
|
||||
'alter table if exists "commission_rate" alter column "min_price_set_id" type text using ("min_price_set_id"::text);'
|
||||
)
|
||||
this.addSql(
|
||||
'alter table if exists "commission_rate" alter column "min_price_set_id" set not null;'
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { model } from '@medusajs/framework/utils'
|
||||
|
||||
export const CommissionLine = model.define('commission_line', {
|
||||
id: model.id({ prefix: 'com_line' }).primaryKey(),
|
||||
item_line_id: model.text(),
|
||||
rule_id: model.text(),
|
||||
currency_code: model.text(),
|
||||
value: model.bigNumber()
|
||||
})
|
||||
@@ -0,0 +1,18 @@
|
||||
import { model } from '@medusajs/framework/utils'
|
||||
|
||||
import { CommissionRule } from './commission_rule'
|
||||
|
||||
export const CommissionRate = model.define('commission_rate', {
|
||||
id: model.id({ prefix: 'com_rate' }).primaryKey(),
|
||||
type: model.text(),
|
||||
percentage_rate: model.number().nullable(),
|
||||
include_tax: model.boolean(),
|
||||
price_set_id: model.text().nullable(),
|
||||
max_price_set_id: model.text().nullable(),
|
||||
min_price_set_id: model.text().nullable(),
|
||||
rule: model
|
||||
.belongsTo(() => CommissionRule, {
|
||||
mappedBy: 'rate'
|
||||
})
|
||||
.nullable()
|
||||
})
|
||||
@@ -0,0 +1,14 @@
|
||||
import { model } from '@medusajs/framework/utils'
|
||||
|
||||
import { CommissionRate } from './commission_rate'
|
||||
|
||||
export const CommissionRule = model.define('commission_rule', {
|
||||
id: model.id({ prefix: 'com_rule' }).primaryKey(),
|
||||
name: model.text().searchable(),
|
||||
reference: model.text().searchable(),
|
||||
reference_id: model.text(),
|
||||
is_active: model.boolean().default(true),
|
||||
rate: model.hasOne(() => CommissionRate, {
|
||||
mappedBy: 'rule'
|
||||
})
|
||||
})
|
||||
3
backend/packages/modules/commission/src/models/index.ts
Normal file
3
backend/packages/modules/commission/src/models/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from './commission_rate'
|
||||
export * from './commission_rule'
|
||||
export * from './commission_line'
|
||||
58
backend/packages/modules/commission/src/service.ts
Normal file
58
backend/packages/modules/commission/src/service.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import { MedusaService } from "@medusajs/framework/utils";
|
||||
|
||||
import { CommissionRate, CommissionRule } from "./models";
|
||||
import { CommissionLine } from "./models/commission_line";
|
||||
import {
|
||||
CommissionCalculationContext,
|
||||
CommissionRuleDTO,
|
||||
} from "@mercurjs/framework";
|
||||
|
||||
class CommissionModuleService extends MedusaService({
|
||||
CommissionRate,
|
||||
CommissionRule,
|
||||
CommissionLine,
|
||||
}) {
|
||||
private async selectCommissionRule(reference: string, reference_id: string) {
|
||||
const [rule] = await this.listCommissionRules(
|
||||
{ reference, reference_id, is_active: true, deleted_at: null },
|
||||
{ relations: ["rate"] }
|
||||
);
|
||||
|
||||
return rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for first applicable CommissionRule for given context. The queries are executed in assumed priority order.
|
||||
* @param ctx Calculation context
|
||||
* @returns CommissionRule applicable for given context or null
|
||||
*/
|
||||
async selectCommissionForProductLine(
|
||||
ctx: CommissionCalculationContext
|
||||
): Promise<CommissionRuleDTO | null> {
|
||||
const ruleQueries = [
|
||||
{
|
||||
reference: "seller+product_type",
|
||||
reference_id: `${ctx.seller_id}+${ctx.product_type_id}`,
|
||||
},
|
||||
{
|
||||
reference: "seller+product_category",
|
||||
reference_id: `${ctx.seller_id}+${ctx.product_category_id}`,
|
||||
},
|
||||
{ reference: "seller", reference_id: ctx.seller_id },
|
||||
{ reference: "product_type", reference_id: ctx.product_type_id },
|
||||
{ reference: "product_category", reference_id: ctx.product_category_id },
|
||||
{ reference: "site", reference_id: "" },
|
||||
];
|
||||
|
||||
for (const { reference, reference_id } of ruleQueries) {
|
||||
const rule = await this.selectCommissionRule(reference, reference_id);
|
||||
if (rule) {
|
||||
return rule;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export default CommissionModuleService;
|
||||
27
backend/packages/modules/commission/tsconfig.json
Normal file
27
backend/packages/modules/commission/tsconfig.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["ES2021"],
|
||||
"target": "ES2021",
|
||||
"outDir": "${configDir}/dist",
|
||||
"esModuleInterop": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"noUnusedLocals": true,
|
||||
"module": "node16",
|
||||
"moduleResolution": "node16",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"sourceMap": true,
|
||||
"noImplicitReturns": true,
|
||||
"resolveJsonModule": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"noImplicitThis": true,
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"incremental": false
|
||||
},
|
||||
"include": ["${configDir}/src"],
|
||||
"exclude": ["${configDir}/dist", "${configDir}/node_modules"]
|
||||
}
|
||||
45
backend/packages/modules/configuration/package.json
Normal file
45
backend/packages/modules/configuration/package.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "@mercurjs/configuration",
|
||||
"version": "1.0.0",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist",
|
||||
"!dist/**/__tests__",
|
||||
"!dist/**/__mocks__",
|
||||
"!dist/**/__fixtures__"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "rimraf dist && tsc --build",
|
||||
"migration:initial": " MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:create --initial",
|
||||
"migration:create": " MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:create",
|
||||
"migration:up": " MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:up",
|
||||
"orm:cache:clear": " MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm cache:clear"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@medusajs/framework": "2.8.6",
|
||||
"@medusajs/test-utils": "2.8.6",
|
||||
"@mercurjs/framework": "*",
|
||||
"@mikro-orm/cli": "6.4.3",
|
||||
"@mikro-orm/core": "6.4.3",
|
||||
"@mikro-orm/migrations": "6.4.3",
|
||||
"@mikro-orm/postgresql": "6.4.3",
|
||||
"@swc/core": "^1.7.28",
|
||||
"@swc/jest": "^0.2.36",
|
||||
"jest": "^29.7.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"tsc-alias": "^1.8.6",
|
||||
"typescript": "^5.6.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@medusajs/framework": "2.8.6",
|
||||
"@mikro-orm/core": "6.4.3",
|
||||
"@mikro-orm/migrations": "6.4.3",
|
||||
"@mikro-orm/postgresql": "6.4.3",
|
||||
"awilix": "^8.0.1"
|
||||
}
|
||||
}
|
||||
12
backend/packages/modules/configuration/src/index.ts
Normal file
12
backend/packages/modules/configuration/src/index.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Module } from "@medusajs/framework/utils";
|
||||
|
||||
import ConfigurationModuleService, {
|
||||
ConfigurationRuleDefaults,
|
||||
} from "./service";
|
||||
|
||||
export const CONFIGURATION_MODULE = "configuration";
|
||||
export { ConfigurationModuleService, ConfigurationRuleDefaults };
|
||||
|
||||
export default Module(CONFIGURATION_MODULE, {
|
||||
service: ConfigurationModuleService,
|
||||
});
|
||||
@@ -0,0 +1,113 @@
|
||||
{
|
||||
"namespaces": [
|
||||
"public"
|
||||
],
|
||||
"name": "public",
|
||||
"tables": [
|
||||
{
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"rule_type": {
|
||||
"name": "rule_type",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"enumItems": [
|
||||
"global_product_catalog",
|
||||
"require_product_approval",
|
||||
"product_request_enabled",
|
||||
"product_import_enabled"
|
||||
],
|
||||
"mappedType": "enum"
|
||||
},
|
||||
"is_enabled": {
|
||||
"name": "is_enabled",
|
||||
"type": "boolean",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "boolean"
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"length": 6,
|
||||
"default": "now()",
|
||||
"mappedType": "datetime"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"length": 6,
|
||||
"default": "now()",
|
||||
"mappedType": "datetime"
|
||||
},
|
||||
"deleted_at": {
|
||||
"name": "deleted_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"length": 6,
|
||||
"mappedType": "datetime"
|
||||
}
|
||||
},
|
||||
"name": "configuration_rule",
|
||||
"schema": "public",
|
||||
"indexes": [
|
||||
{
|
||||
"keyName": "IDX_configuration_rule_rule_type_unique",
|
||||
"columnNames": [],
|
||||
"composite": false,
|
||||
"constraint": false,
|
||||
"primary": false,
|
||||
"unique": false,
|
||||
"expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_configuration_rule_rule_type_unique\" ON \"configuration_rule\" (rule_type) WHERE deleted_at IS NULL"
|
||||
},
|
||||
{
|
||||
"keyName": "IDX_configuration_rule_deleted_at",
|
||||
"columnNames": [],
|
||||
"composite": false,
|
||||
"constraint": false,
|
||||
"primary": false,
|
||||
"unique": false,
|
||||
"expression": "CREATE INDEX IF NOT EXISTS \"IDX_configuration_rule_deleted_at\" ON \"configuration_rule\" (deleted_at) WHERE deleted_at IS NULL"
|
||||
},
|
||||
{
|
||||
"keyName": "configuration_rule_pkey",
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"composite": false,
|
||||
"constraint": true,
|
||||
"primary": true,
|
||||
"unique": true
|
||||
}
|
||||
],
|
||||
"checks": [],
|
||||
"foreignKeys": {},
|
||||
"nativeEnums": {}
|
||||
}
|
||||
],
|
||||
"nativeEnums": {}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Migration } from '@mikro-orm/migrations';
|
||||
|
||||
export class Migration20250114063624 extends Migration {
|
||||
|
||||
async up(): Promise<void> {
|
||||
this.addSql('create table if not exists "configuration_rule" ("id" text not null, "rule_type" text check ("rule_type" in (\'global_product_catalog\', \'require_product_approval\', \'product_request_enabled\')) not null, "is_enabled" boolean not null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "configuration_rule_pkey" primary key ("id"));');
|
||||
this.addSql('CREATE UNIQUE INDEX IF NOT EXISTS "IDX_configuration_rule_rule_type_unique" ON "configuration_rule" (rule_type) WHERE deleted_at IS NULL;');
|
||||
this.addSql('CREATE INDEX IF NOT EXISTS "IDX_configuration_rule_deleted_at" ON "configuration_rule" (deleted_at) WHERE deleted_at IS NULL;');
|
||||
}
|
||||
|
||||
async down(): Promise<void> {
|
||||
this.addSql('drop table if exists "configuration_rule" cascade;');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { Migration } from '@mikro-orm/migrations';
|
||||
|
||||
export class Migration20250324131111 extends Migration {
|
||||
|
||||
override async up(): Promise<void> {
|
||||
this.addSql(`alter table if exists "configuration_rule" drop constraint if exists "configuration_rule_rule_type_check";`);
|
||||
|
||||
this.addSql(`alter table if exists "configuration_rule" add constraint "configuration_rule_rule_type_check" check("rule_type" in ('global_product_catalog', 'require_product_approval', 'product_request_enabled', 'product_import_enabled'));`);
|
||||
}
|
||||
|
||||
override async down(): Promise<void> {
|
||||
this.addSql(`alter table if exists "configuration_rule" drop constraint if exists "configuration_rule_rule_type_check";`);
|
||||
|
||||
this.addSql(`alter table if exists "configuration_rule" add constraint "configuration_rule_rule_type_check" check("rule_type" in ('global_product_catalog', 'require_product_approval', 'product_request_enabled'));`);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { model } from "@medusajs/framework/utils";
|
||||
|
||||
export const ConfigurationRule = model.define("configuration_rule", {
|
||||
id: model.id({ prefix: "conf" }).primaryKey(),
|
||||
rule_type: model
|
||||
.enum([
|
||||
"global_product_catalog",
|
||||
"require_product_approval",
|
||||
"product_request_enabled",
|
||||
"product_import_enabled",
|
||||
])
|
||||
.unique(),
|
||||
is_enabled: model.boolean(),
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
export * from './configuration-rule'
|
||||
27
backend/packages/modules/configuration/src/service.ts
Normal file
27
backend/packages/modules/configuration/src/service.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { MedusaService } from "@medusajs/framework/utils";
|
||||
|
||||
import { ConfigurationRule } from "./models";
|
||||
import { ConfigurationRuleType } from "@mercurjs/framework";
|
||||
|
||||
export const ConfigurationRuleDefaults = new Map<
|
||||
ConfigurationRuleType,
|
||||
boolean
|
||||
>([
|
||||
[ConfigurationRuleType.GLOBAL_PRODUCT_CATALOG, false],
|
||||
[ConfigurationRuleType.PRODUCT_REQUEST_ENABLED, true],
|
||||
[ConfigurationRuleType.REQUIRE_PRODUCT_APPROVAL, false],
|
||||
[ConfigurationRuleType.PRODUCT_IMPORT_ENABLED, true],
|
||||
]);
|
||||
|
||||
class ConfigurationModuleService extends MedusaService({
|
||||
ConfigurationRule,
|
||||
}) {
|
||||
async isRuleEnabled(type: ConfigurationRuleType): Promise<boolean> {
|
||||
const [rule] = await this.listConfigurationRules({
|
||||
rule_type: type,
|
||||
});
|
||||
return rule ? rule.is_enabled : ConfigurationRuleDefaults.get(type)!;
|
||||
}
|
||||
}
|
||||
|
||||
export default ConfigurationModuleService;
|
||||
27
backend/packages/modules/configuration/tsconfig.json
Normal file
27
backend/packages/modules/configuration/tsconfig.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["ES2021"],
|
||||
"target": "ES2021",
|
||||
"outDir": "${configDir}/dist",
|
||||
"esModuleInterop": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"noUnusedLocals": true,
|
||||
"module": "node16",
|
||||
"moduleResolution": "node16",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"sourceMap": true,
|
||||
"noImplicitReturns": true,
|
||||
"resolveJsonModule": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"noImplicitThis": true,
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"incremental": false
|
||||
},
|
||||
"include": ["${configDir}/src"],
|
||||
"exclude": ["${configDir}/dist", "${configDir}/node_modules"]
|
||||
}
|
||||
44
backend/packages/modules/marketplace/package.json
Normal file
44
backend/packages/modules/marketplace/package.json
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "@mercurjs/marketplace",
|
||||
"version": "1.0.0",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist",
|
||||
"!dist/**/__tests__",
|
||||
"!dist/**/__mocks__",
|
||||
"!dist/**/__fixtures__"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "rimraf dist && tsc --build",
|
||||
"migration:initial": " MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:create --initial",
|
||||
"migration:create": " MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:create",
|
||||
"migration:up": " MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:up",
|
||||
"orm:cache:clear": " MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm cache:clear"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@medusajs/framework": "2.8.6",
|
||||
"@medusajs/test-utils": "2.8.6",
|
||||
"@mikro-orm/cli": "6.4.3",
|
||||
"@mikro-orm/core": "6.4.3",
|
||||
"@mikro-orm/migrations": "6.4.3",
|
||||
"@mikro-orm/postgresql": "6.4.3",
|
||||
"@swc/core": "^1.7.28",
|
||||
"@swc/jest": "^0.2.36",
|
||||
"jest": "^29.7.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"tsc-alias": "^1.8.6",
|
||||
"typescript": "^5.6.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@medusajs/framework": "2.8.6",
|
||||
"@mikro-orm/core": "6.4.3",
|
||||
"@mikro-orm/migrations": "6.4.3",
|
||||
"@mikro-orm/postgresql": "6.4.3",
|
||||
"awilix": "^8.0.1"
|
||||
}
|
||||
}
|
||||
10
backend/packages/modules/marketplace/src/index.ts
Normal file
10
backend/packages/modules/marketplace/src/index.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Module } from "@medusajs/framework/utils";
|
||||
|
||||
import MarketplaceModuleService from "./service";
|
||||
|
||||
export const MARKETPLACE_MODULE = "marketplace";
|
||||
export { MarketplaceModuleService };
|
||||
|
||||
export default Module(MARKETPLACE_MODULE, {
|
||||
service: MarketplaceModuleService,
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
import { Migration } from '@mikro-orm/migrations'
|
||||
|
||||
export class Migration20241207151814 extends Migration {
|
||||
async up(): Promise<void> {
|
||||
this.addSql(
|
||||
'create table if not exists "order_set" ("id" text not null, "display_id" serial, "sales_channel_id" text not null, "cart_id" text not null, "customer_id" text null, "payment_collection_id" text not null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "order_set_pkey" primary key ("id"));'
|
||||
)
|
||||
this.addSql(
|
||||
'CREATE INDEX IF NOT EXISTS "IDX_order_set_deleted_at" ON "order_set" (deleted_at) WHERE deleted_at IS NULL;'
|
||||
)
|
||||
}
|
||||
|
||||
async down(): Promise<void> {
|
||||
this.addSql('drop table if exists "order_set" cascade;')
|
||||
}
|
||||
}
|
||||
1
backend/packages/modules/marketplace/src/models/index.ts
Normal file
1
backend/packages/modules/marketplace/src/models/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './order-set'
|
||||
10
backend/packages/modules/marketplace/src/models/order-set.ts
Normal file
10
backend/packages/modules/marketplace/src/models/order-set.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { model } from '@medusajs/framework/utils'
|
||||
|
||||
export const OrderSet = model.define('order_set', {
|
||||
id: model.id({ prefix: 'ordset' }).primaryKey(),
|
||||
display_id: model.number().nullable(),
|
||||
sales_channel_id: model.text(),
|
||||
cart_id: model.text(),
|
||||
customer_id: model.text().nullable(),
|
||||
payment_collection_id: model.text()
|
||||
})
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user