diff --git a/packages/cart/src/models/address.ts b/packages/cart/src/models/address.ts new file mode 100644 index 0000000000000..a603018efad1e --- /dev/null +++ b/packages/cart/src/models/address.ts @@ -0,0 +1,82 @@ +import { DAL } from "@medusajs/types" +import { generateEntityId } from "@medusajs/utils" +import { + BeforeCreate, + Entity, + OnInit, + OptionalProps, + PrimaryKey, + Property +} from "@mikro-orm/core" + + +type OptionalAddressProps = DAL.EntityDateColumns // TODO: To be revisited when more clear + +@Entity({ tableName: "cart_address" }) +export default class Address { + [OptionalProps]: OptionalAddressProps + + @PrimaryKey({ columnType: "text" }) + id!: string + + @Property({ columnType: "text", nullable: true }) + customer_id?: string | null + + @Property({ columnType: "text", nullable: true }) + company?: string | null + + @Property({ columnType: "text", nullable: true }) + first_name?: string | null + + @Property({ columnType: "text", nullable: true }) + last_name?: string | null + + @Property({ columnType: "text", nullable: true }) + address_1?: string | null + + @Property({ columnType: "text", nullable: true }) + address_2?: string | null + + @Property({ columnType: "text", nullable: true }) + city?: string | null + + @Property({ columnType: "text", nullable: true }) + country_code?: string | null + + @Property({ columnType: "text", nullable: true }) + province?: string | null + + @Property({ columnType: "text", nullable: true }) + postal_code?: string | null + + @Property({ columnType: "text", nullable: true }) + phone?: string | null + + @Property({ columnType: "jsonb", nullable: true }) + metadata?: Record | null + + @Property({ + onCreate: () => new Date(), + columnType: "timestamptz", + defaultRaw: "now()", + }) + created_at: Date + + @Property({ + onCreate: () => new Date(), + onUpdate: () => new Date(), + columnType: "timestamptz", + defaultRaw: "now()", + }) + updated_at: Date + + @BeforeCreate() + onCreate() { + this.id = generateEntityId(this.id, "caaddr") + } + + @OnInit() + onInit() { + this.id = generateEntityId(this.id, "caaddr") + } +} diff --git a/packages/cart/src/models/adjustment-line.ts b/packages/cart/src/models/adjustment-line.ts new file mode 100644 index 0000000000000..4b714542a7237 --- /dev/null +++ b/packages/cart/src/models/adjustment-line.ts @@ -0,0 +1,45 @@ +import { DAL } from "@medusajs/types" +import { OptionalProps, PrimaryKey, Property } from "@mikro-orm/core" + +type OptionalAdjustmentLineProps = DAL.EntityDateColumns // TODO: To be revisited when more clear + +/** + * As per the Mikro ORM docs, superclasses should use the abstract class definition + * Source: https://mikro-orm.io/docs/inheritance-mapping + */ +export default abstract class AdjustmentLine { + [OptionalProps]: OptionalAdjustmentLineProps + + @PrimaryKey({ columnType: "text" }) + id: string + + @Property({ columnType: "text", nullable: true }) + description?: string | null + + @Property({ columnType: "text", nullable: true }) + promotion_id?: string | null + + @Property({ columnType: "text" }) + code: string + + @Property({ columnType: "numeric" }) + amount: number + + @Property({ columnType: "text", nullable: true }) + provider_id?: string | null + + @Property({ + onCreate: () => new Date(), + columnType: "timestamptz", + defaultRaw: "now()", + }) + created_at: Date + + @Property({ + onCreate: () => new Date(), + onUpdate: () => new Date(), + columnType: "timestamptz", + defaultRaw: "now()", + }) + updated_at: Date +} diff --git a/packages/cart/src/models/cart.ts b/packages/cart/src/models/cart.ts index 50e2c12dc7ef0..2e816919a4b8a 100644 --- a/packages/cart/src/models/cart.ts +++ b/packages/cart/src/models/cart.ts @@ -1,10 +1,126 @@ +import { DAL } from "@medusajs/types" import { generateEntityId } from "@medusajs/utils" -import { BeforeCreate, Entity, OnInit, PrimaryKey } from "@mikro-orm/core" +import { + BeforeCreate, + Cascade, + Collection, + Entity, + OnInit, + OneToMany, + OneToOne, + PrimaryKey, + Property, +} from "@mikro-orm/core" +import Address from "./address" +import LineItem from "./line-item" +import ShippingMethod from "./shipping-method" -@Entity() +type OptionalCartProps = + | "shipping_address" + | "billing_address" + | DAL.EntityDateColumns // TODO: To be revisited when more clear + +@Entity({ tableName: "cart" }) export default class Cart { @PrimaryKey({ columnType: "text" }) - id!: string + id: string + + @Property({ columnType: "text", nullable: true }) + region_id?: string | null + + @Property({ + columnType: "text", + nullable: true, + index: "IDX_cart_customer_id", + }) + customer_id?: string | null + + @Property({ columnType: "text", nullable: true }) + sales_channel_id?: string | null + + @Property({ columnType: "text", nullable: true }) + email?: string | null + + @Property({ columnType: "text" }) + currency_code: string + + @OneToOne({ + entity: () => Address, + joinColumn: "shipping_address_id", + cascade: [Cascade.REMOVE], + nullable: true, + }) + shipping_address?: Address | null + + @OneToOne({ + entity: () => Address, + joinColumn: "billing_address_id", + cascade: [Cascade.REMOVE], + nullable: true, + }) + billing_address?: Address | null + + @Property({ columnType: "jsonb", nullable: true }) + metadata?: Record | null + + @OneToMany(() => LineItem, (lineItem) => lineItem.cart, { + orphanRemoval: true, + }) + items = new Collection(this) + + @OneToMany(() => ShippingMethod, (shippingMethod) => shippingMethod.cart, { + orphanRemoval: true, + }) + shipping_methods = new Collection(this) + + /** COMPUTED PROPERTIES - START */ + + // compare_at_item_total?: number + // compare_at_item_subtotal?: number + // compare_at_item_tax_total?: number + + // original_item_total: number + // original_item_subtotal: number + // original_item_tax_total: number + + // item_total: number + // item_subtotal: number + // item_tax_total: number + + // original_total: number + // original_subtotal: number + // original_tax_total: number + + // total: number + // subtotal: number + // tax_total: number + // discount_total: number + // discount_tax_total: number + + // shipping_total: number + // shipping_subtotal: number + // shipping_tax_total: number + + // original_shipping_total: number + // original_shipping_subtotal: number + // original_shipping_tax_total: number + + /** COMPUTED PROPERTIES - END */ + + @Property({ + onCreate: () => new Date(), + columnType: "timestamptz", + defaultRaw: "now()", + }) + created_at: Date + + @Property({ + onCreate: () => new Date(), + onUpdate: () => new Date(), + columnType: "timestamptz", + defaultRaw: "now()", + }) + updated_at: Date @BeforeCreate() onCreate() { diff --git a/packages/cart/src/models/index.ts b/packages/cart/src/models/index.ts index 434874897e1bb..d83594ffc2857 100644 --- a/packages/cart/src/models/index.ts +++ b/packages/cart/src/models/index.ts @@ -1,2 +1,11 @@ -export { default as Cart } from "./cart"; +export { default as Address } from "./address" +export { default as AdjustmentLine } from "./adjustment-line" +export { default as Cart } from "./cart" +export { default as LineItem } from "./line-item" +export { default as LineItemAdjustmentLine } from "./line-item-adjustment-line" +export { default as LineItemTaxLine } from "./line-item-tax-line" +export { default as ShippingMethod } from "./shipping-method" +export { default as ShippingMethodAdjustmentLine } from "./shipping-method-adjustment-line" +export { default as ShippingMethodTaxLine } from "./shipping-method-tax-line" +export { default as TaxLine } from "./tax-line" diff --git a/packages/cart/src/models/line-item-adjustment-line.ts b/packages/cart/src/models/line-item-adjustment-line.ts new file mode 100644 index 0000000000000..b26250fdd47a6 --- /dev/null +++ b/packages/cart/src/models/line-item-adjustment-line.ts @@ -0,0 +1,28 @@ +import { generateEntityId } from "@medusajs/utils" +import { + BeforeCreate, + Entity, + ManyToOne, + OnInit +} from "@mikro-orm/core" +import AdjustmentLine from "./adjustment-line" +import LineItem from "./line-item" + +@Entity({ tableName: "cart_line_item_adjustment_line" }) +export default class LineItemAdjustmentLine extends AdjustmentLine { + @ManyToOne(() => LineItem, { + joinColumn: "line_item", + fieldName: "line_item_id", + }) + line_item: LineItem + + @BeforeCreate() + onCreate() { + this.id = generateEntityId(this.id, "caliadj") + } + + @OnInit() + onInit() { + this.id = generateEntityId(this.id, "caliadj") + } +} diff --git a/packages/cart/src/models/line-item-tax-line.ts b/packages/cart/src/models/line-item-tax-line.ts new file mode 100644 index 0000000000000..7fa461d87c204 --- /dev/null +++ b/packages/cart/src/models/line-item-tax-line.ts @@ -0,0 +1,23 @@ +import { generateEntityId } from "@medusajs/utils" +import { BeforeCreate, Entity, ManyToOne, OnInit } from "@mikro-orm/core" +import LineItem from "./line-item" +import TaxLine from "./tax-line" + +@Entity({ tableName: "cart_line_item_tax_line" }) +export default class LineItemTaxLine extends TaxLine { + @ManyToOne(() => LineItem, { + joinColumn: "line_item", + fieldName: "line_item_id", + }) + line_item: LineItem + + @BeforeCreate() + onCreate() { + this.id = generateEntityId(this.id, "calitxl") + } + + @OnInit() + onInit() { + this.id = generateEntityId(this.id, "calitxl") + } +} diff --git a/packages/cart/src/models/line-item.ts b/packages/cart/src/models/line-item.ts new file mode 100644 index 0000000000000..de5f50b2571b1 --- /dev/null +++ b/packages/cart/src/models/line-item.ts @@ -0,0 +1,169 @@ +import { DAL } from "@medusajs/types" +import { generateEntityId } from "@medusajs/utils" +import { + BeforeCreate, + Cascade, + Check, + Collection, + Entity, + ManyToOne, + OnInit, + OneToMany, + OptionalProps, + PrimaryKey, + Property +} from "@mikro-orm/core" +import Cart from "./cart" +import LineItemAdjustmentLine from "./line-item-adjustment-line" +import LineItemTaxLine from "./line-item-tax-line" + +type OptionalLineItemProps = + | "is_discoutable" + | "is_tax_inclusive" + | "compare_at_unit_price" + | "requires_shipping" + | DAL.EntityDateColumns + +@Entity({ tableName: "cart_line_item" }) +export default class LineItem { + [OptionalProps]?: OptionalLineItemProps + + @PrimaryKey({ columnType: "text" }) + id: string + + @ManyToOne(() => Cart, { + onDelete: "cascade", + index: "IDX_line_item_cart_id", + fieldName: "cart_id", + }) + cart!: Cart + + @Property({ columnType: "text" }) + title: string + + @Property({ columnType: "text", nullable: true }) + subtitle: string | null + + @Property({ columnType: "text", nullable: true }) + thumbnail?: string | null + + @Property({ columnType: "text" }) + quantity: number + + @Property({ + columnType: "text", + nullable: true, + index: "IDX_line_item_variant_id", + }) + variant_id?: string | null + + @Property({ columnType: "text", nullable: true }) + product_id?: string | null + + @Property({ columnType: "text", nullable: true }) + product_title?: string | null + + @Property({ columnType: "text", nullable: true }) + product_description?: string | null + + @Property({ columnType: "text", nullable: true }) + product_subtitle?: string | null + + @Property({ columnType: "text", nullable: true }) + product_type?: string | null + + @Property({ columnType: "text", nullable: true }) + product_collection?: string | null + + @Property({ columnType: "text", nullable: true }) + product_handle?: string | null + + @Property({ columnType: "text", nullable: true }) + variant_sku?: string | null + + @Property({ columnType: "text", nullable: true }) + variant_barcode?: string | null + + @Property({ columnType: "text", nullable: true }) + variant_title?: string | null + + @Property({ columnType: "jsonb", nullable: true }) + variant_option_values?: Record | null + + @Property({ columnType: "boolean" }) + requires_shipping = true + + @Property({ columnType: "boolean" }) + is_discountable = true + + @Property({ columnType: "boolean" }) + is_tax_inclusive = false + + @Property({ columnType: "numeric", nullable: true }) + compare_at_unit_price?: number + + @Property({ columnType: "numeric", serializer: Number }) + @Check({ expression: "unit_price >= 0" }) // TODO: Validate that numeric types work with the expression + unit_price: number + + @OneToMany(() => LineItemTaxLine, (taxLine) => taxLine.line_item, { + cascade: [Cascade.REMOVE], + }) + tax_lines = new Collection(this) + + @OneToMany( + () => LineItemAdjustmentLine, + (adjustment) => adjustment.line_item, + { + cascade: [Cascade.REMOVE], + } + ) + adjustments = new Collection(this) + + /** COMPUTED PROPERTIES - START */ + + // compare_at_total?: number + // compare_at_subtotal?: number + // compare_at_tax_total?: number + + // original_total: number + // original_subtotal: number + // original_tax_total: number + + // item_total: number + // item_subtotal: number + // item_tax_total: number + + // total: number + // subtotal: number + // tax_total: number + // discount_total: number + // discount_tax_total: number + + /** COMPUTED PROPERTIES - END */ + + @Property({ + onCreate: () => new Date(), + columnType: "timestamptz", + defaultRaw: "now()", + }) + created_at: Date + + @Property({ + onCreate: () => new Date(), + onUpdate: () => new Date(), + columnType: "timestamptz", + defaultRaw: "now()", + }) + updated_at: Date + + @BeforeCreate() + onCreate() { + this.id = generateEntityId(this.id, "cali") + } + + @OnInit() + onInit() { + this.id = generateEntityId(this.id, "cali") + } +} diff --git a/packages/cart/src/models/shipping-method-adjustment-line.ts b/packages/cart/src/models/shipping-method-adjustment-line.ts new file mode 100644 index 0000000000000..e56e82313ab1d --- /dev/null +++ b/packages/cart/src/models/shipping-method-adjustment-line.ts @@ -0,0 +1,23 @@ +import { generateEntityId } from "@medusajs/utils" +import { BeforeCreate, Entity, ManyToOne, OnInit } from "@mikro-orm/core" +import AdjustmentLine from "./adjustment-line" +import ShippingMethod from "./shipping-method" + +@Entity({ tableName: "cart_shipping_method_adjustment_line" }) +export default class ShippingMethodAdjustmentLine extends AdjustmentLine { + @ManyToOne(() => ShippingMethod, { + joinColumn: "shipping_method", + fieldName: "shipping_method_id", + }) + shipping_method: ShippingMethod + + @BeforeCreate() + onCreate() { + this.id = generateEntityId(this.id, "casmadj") + } + + @OnInit() + onInit() { + this.id = generateEntityId(this.id, "casmadj") + } +} diff --git a/packages/cart/src/models/shipping-method-tax-line.ts b/packages/cart/src/models/shipping-method-tax-line.ts new file mode 100644 index 0000000000000..5d726936500ba --- /dev/null +++ b/packages/cart/src/models/shipping-method-tax-line.ts @@ -0,0 +1,23 @@ +import { generateEntityId } from "@medusajs/utils" +import { BeforeCreate, Entity, ManyToOne, OnInit } from "@mikro-orm/core" +import ShippingMethod from "./shipping-method" +import TaxLine from "./tax-line" + +@Entity({ tableName: "cart_shipping_method_tax_line" }) +export default class ShippingMethodTaxLine extends TaxLine { + @ManyToOne(() => ShippingMethod, { + joinColumn: "shipping_method", + fieldName: "shipping_method_id", + }) + shipping_method: ShippingMethod + + @BeforeCreate() + onCreate() { + this.id = generateEntityId(this.id, "casmtxl") + } + + @OnInit() + onInit() { + this.id = generateEntityId(this.id, "casmtxl") + } +} diff --git a/packages/cart/src/models/shipping-method.ts b/packages/cart/src/models/shipping-method.ts new file mode 100644 index 0000000000000..084bec89a666c --- /dev/null +++ b/packages/cart/src/models/shipping-method.ts @@ -0,0 +1,108 @@ +import { generateEntityId } from "@medusajs/utils" +import { + BeforeCreate, + Cascade, + Check, + Collection, + Entity, + ManyToOne, + OnInit, + OneToMany, + PrimaryKey, + Property, +} from "@mikro-orm/core" +import Cart from "./cart" +import ShippingMethodAdjustmentLine from "./shipping-method-adjustment-line" +import ShippingMethodTaxLine from "./shipping-method-tax-line" + +@Entity({ tableName: "cart_shipping_method" }) +export default class ShippingMethod { + @PrimaryKey({ columnType: "text" }) + id: string + + @ManyToOne(() => Cart, { + onDelete: "cascade", + index: "IDX_shipping_method_cart_id", + fieldName: "cart_id", + }) + cart: Cart + + @Property({ columnType: "text" }) + title: string + + @Property({ columnType: "jsonb", nullable: true }) + description?: string | null + + @Property({ columnType: "numeric", serializer: Number }) + @Check({ expression: "amount >= 0" }) // TODO: Validate that numeric types work with the expression + amount: number + + @Property({ columnType: "boolean" }) + tax_inclusive = false + + @Property({ columnType: "text", nullable: true }) + shipping_option_id?: string | null + + @Property({ columnType: "jsonb", nullable: true }) + data?: Record | null + + @Property({ columnType: "jsonb", nullable: true }) + metadata?: Record | null + + @OneToMany( + () => ShippingMethodTaxLine, + (taxLine) => taxLine.shipping_method, + { + cascade: [Cascade.REMOVE], + } + ) + tax_lines = new Collection(this) + + @OneToMany( + () => ShippingMethodAdjustmentLine, + (adjustment) => adjustment.shipping_method, + { + cascade: [Cascade.REMOVE], + } + ) + adjustments = new Collection(this) + + /** COMPUTED PROPERTIES - START */ + + // original_total: number + // original_subtotal: number + // original_tax_total: number + + // total: number + // subtotal: number + // tax_total: number + // discount_total: number + // discount_tax_total: number + + /** COMPUTED PROPERTIES - END */ + + @Property({ + onCreate: () => new Date(), + columnType: "timestamptz", + defaultRaw: "now()", + }) + created_at: Date + + @Property({ + onCreate: () => new Date(), + onUpdate: () => new Date(), + columnType: "timestamptz", + defaultRaw: "now()", + }) + updated_at: Date + + @BeforeCreate() + onCreate() { + this.id = generateEntityId(this.id, "casm") + } + + @OnInit() + onInit() { + this.id = generateEntityId(this.id, "casm") + } +} diff --git a/packages/cart/src/models/tax-line.ts b/packages/cart/src/models/tax-line.ts new file mode 100644 index 0000000000000..7a55a930c7bdb --- /dev/null +++ b/packages/cart/src/models/tax-line.ts @@ -0,0 +1,40 @@ +import { PrimaryKey, Property } from "@mikro-orm/core" + +/** + * As per the Mikro ORM docs, superclasses should use the abstract class definition + * Source: https://mikro-orm.io/docs/inheritance-mapping + */ +export default abstract class TaxLine { + @PrimaryKey({ columnType: "text" }) + id: string + + @Property({ columnType: "text", nullable: true }) + description?: string | null + + @Property({ columnType: "text", nullable: true }) + tax_rate_id?: string | null + + @Property({ columnType: "text" }) + code: string + + @Property({ columnType: "numeric" }) + rate: number + + @Property({ columnType: "text", nullable: true }) + provider_id?: string | null + + @Property({ + onCreate: () => new Date(), + columnType: "timestamptz", + defaultRaw: "now()", + }) + created_at: Date + + @Property({ + onCreate: () => new Date(), + onUpdate: () => new Date(), + columnType: "timestamptz", + defaultRaw: "now()", + }) + updated_at: Date +}