feat: order editing data model (#2184)
**What** - add order editing entities - add repositories - add a feature flag for the order editing feature - add the migrations file RESOLVES CORE-490
This commit is contained in:
10
packages/medusa/src/loaders/feature-flags/order-editing.ts
Normal file
10
packages/medusa/src/loaders/feature-flags/order-editing.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { FlagSettings } from "../../types/feature-flags"
|
||||
|
||||
const OrderEditingFeatureFlag: FlagSettings = {
|
||||
key: "order_editing",
|
||||
default_val: false,
|
||||
env_key: "MEDUSA_FF_ORDER_EDITING",
|
||||
description: "[WIP] Enable the order editing feature",
|
||||
}
|
||||
|
||||
export default OrderEditingFeatureFlag
|
||||
@@ -0,0 +1,53 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm"
|
||||
|
||||
import OrderEditingFeatureFlag from "../loaders/feature-flags/order-editing"
|
||||
|
||||
export const featureFlag = OrderEditingFeatureFlag.key
|
||||
|
||||
export class orderEditing1663059812399 implements MigrationInterface {
|
||||
name = "orderEditing1663059812399"
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`CREATE TYPE "order_item_change_type_enum" AS ENUM('item_add', 'item_remove', 'item_update')`
|
||||
)
|
||||
await queryRunner.query(
|
||||
`CREATE TABLE "order_item_change" ("id" character varying NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deleted_at" TIMESTAMP WITH TIME ZONE, "type" "order_item_change_type_enum" NOT NULL, "order_edit_id" character varying NOT NULL, "original_line_item_id" character varying, "line_item_id" character varying, CONSTRAINT "UQ_da93cee3ca0dd50a5246268c2e9" UNIQUE ("order_edit_id", "line_item_id"), CONSTRAINT "UQ_5b7a99181e4db2ea821be0b6196" UNIQUE ("order_edit_id", "original_line_item_id"), CONSTRAINT "REL_5f9688929761f7df108b630e64" UNIQUE ("line_item_id"), CONSTRAINT "PK_d6eb138f77ffdee83567b85af0c" PRIMARY KEY ("id"))`
|
||||
)
|
||||
await queryRunner.query(
|
||||
`CREATE TABLE "order_edit" ("id" character varying NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deleted_at" TIMESTAMP WITH TIME ZONE, "order_id" character varying NOT NULL, "internal_note" character varying, "created_by" character varying NOT NULL, "requested_by" character varying, "requested_at" TIMESTAMP WITH TIME ZONE, "confirmed_by" character varying, "confirmed_at" TIMESTAMP WITH TIME ZONE, "declined_by" character varying, "declined_reason" character varying, "declined_at" TIMESTAMP WITH TIME ZONE, "canceled_by" character varying, "canceled_at" TIMESTAMP WITH TIME ZONE, CONSTRAINT "PK_58ab6acf2e84b4e827f5f846f7a" PRIMARY KEY ("id"))`
|
||||
)
|
||||
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "order_item_change" ADD CONSTRAINT "FK_44feeebb258bf4cfa4cc4202281" FOREIGN KEY ("order_edit_id") REFERENCES "order_edit"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`
|
||||
)
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "order_item_change" ADD CONSTRAINT "FK_b4d53b8d03c9f5e7d4317e818d9" FOREIGN KEY ("original_line_item_id") REFERENCES "line_item"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`
|
||||
)
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "order_item_change" ADD CONSTRAINT "FK_5f9688929761f7df108b630e64a" FOREIGN KEY ("line_item_id") REFERENCES "line_item"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`
|
||||
)
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "order_edit" ADD CONSTRAINT "FK_1f3a251488a91510f57e1bf93cd" FOREIGN KEY ("order_id") REFERENCES "order"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`
|
||||
)
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "order_edit" DROP CONSTRAINT "FK_1f3a251488a91510f57e1bf93cd"`
|
||||
)
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "order_item_change" DROP CONSTRAINT "FK_5f9688929761f7df108b630e64a"`
|
||||
)
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "order_item_change" DROP CONSTRAINT "FK_b4d53b8d03c9f5e7d4317e818d9"`
|
||||
)
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "order_item_change" DROP CONSTRAINT "FK_44feeebb258bf4cfa4cc4202281"`
|
||||
)
|
||||
|
||||
await queryRunner.query(`DROP TABLE "order_edit"`)
|
||||
await queryRunner.query(`DROP TABLE "order_item_change"`)
|
||||
await queryRunner.query(`DROP TYPE "order_item_change_type_enum"`)
|
||||
}
|
||||
}
|
||||
157
packages/medusa/src/models/order-edit.ts
Normal file
157
packages/medusa/src/models/order-edit.ts
Normal file
@@ -0,0 +1,157 @@
|
||||
import { BeforeInsert, Column, JoinColumn, ManyToOne, OneToMany } from "typeorm"
|
||||
|
||||
import OrderEditingFeatureFlag from "../loaders/feature-flags/order-editing"
|
||||
import { FeatureFlagEntity } from "../utils/feature-flag-decorators"
|
||||
import { resolveDbType } from "../utils/db-aware-column"
|
||||
import { OrderItemChange } from "./order-item-change"
|
||||
import { SoftDeletableEntity } from "../interfaces"
|
||||
import { generateEntityId } from "../utils"
|
||||
import { LineItem } from "./line-item"
|
||||
import { Order } from "./order"
|
||||
|
||||
@FeatureFlagEntity(OrderEditingFeatureFlag.key)
|
||||
export class OrderEdit extends SoftDeletableEntity {
|
||||
@Column()
|
||||
order_id: string
|
||||
|
||||
@ManyToOne(() => Order, (o) => o.edits)
|
||||
@JoinColumn({ name: "order_id" })
|
||||
order: Order
|
||||
|
||||
@OneToMany(() => OrderItemChange, (oic) => oic.order_edit, {
|
||||
cascade: true,
|
||||
})
|
||||
changes: OrderItemChange[]
|
||||
|
||||
@Column({ nullable: true })
|
||||
internal_note?: string
|
||||
|
||||
@Column()
|
||||
created_by: string // customer or user ID
|
||||
|
||||
@Column({ nullable: true })
|
||||
requested_by?: string // customer or user ID
|
||||
|
||||
@Column({ type: resolveDbType("timestamptz"), nullable: true })
|
||||
requested_at?: Date
|
||||
|
||||
@Column({ nullable: true })
|
||||
confirmed_by?: string // customer or user ID
|
||||
|
||||
@Column({ type: resolveDbType("timestamptz"), nullable: true })
|
||||
confirmed_at?: Date
|
||||
|
||||
@Column({ nullable: true })
|
||||
declined_by?: string // customer or user ID
|
||||
|
||||
@Column({ nullable: true })
|
||||
declined_reason?: string
|
||||
|
||||
@Column({ type: resolveDbType("timestamptz"), nullable: true })
|
||||
declined_at?: Date
|
||||
|
||||
@Column({ nullable: true })
|
||||
canceled_by?: string
|
||||
|
||||
@Column({ type: resolveDbType("timestamptz"), nullable: true })
|
||||
canceled_at?: Date
|
||||
|
||||
// Computed
|
||||
subtotal: number
|
||||
discount_total?: number
|
||||
tax_total: number
|
||||
total: number
|
||||
difference_due: number
|
||||
|
||||
items: LineItem[]
|
||||
|
||||
@BeforeInsert()
|
||||
private beforeInsert(): void {
|
||||
this.id = generateEntityId(this.id, "oe")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @schema order_edit
|
||||
* title: "Order Edit"
|
||||
* description: "Order edit keeps track of order items changes."
|
||||
* x-resourceId: order_edit
|
||||
* required:
|
||||
* - order_id
|
||||
* - order
|
||||
* - changes
|
||||
* - created_by
|
||||
* properties:
|
||||
* id:
|
||||
* type: string
|
||||
* description: The order edit's ID
|
||||
* example: oe_01G8TJSYT9M6AVS5N4EMNFS1EK
|
||||
* order_id:
|
||||
* type: string
|
||||
* description: The ID of the order that is edited
|
||||
* example: order_01G2SG30J8C85S4A5CHM2S1NS2
|
||||
* order:
|
||||
* description: Order object
|
||||
* $ref: "#/components/schemas/order"
|
||||
* changes:
|
||||
* type: array
|
||||
* description: Line item changes array.
|
||||
* items:
|
||||
* $ref: "#/components/schemas/order_item_changes"
|
||||
* internal_note:
|
||||
* description: "An optional note with additional details about the order edit."
|
||||
* type: string
|
||||
* example: Included two more items B to the order.
|
||||
* created_by:
|
||||
* type: string
|
||||
* description: "The unique identifier of the user or customer who created the order edit."
|
||||
* requested_by:
|
||||
* type: string
|
||||
* description: "The unique identifier of the user or customer who requested the order edit."
|
||||
* requested_at:
|
||||
* type: string
|
||||
* description: "The date with timezone at which the edit was requested."
|
||||
* format: date-time
|
||||
* confirmed_by:
|
||||
* type: string
|
||||
* description: "The unique identifier of the user or customer who confirmed the order edit."
|
||||
* confirmed_at:
|
||||
* type: string
|
||||
* description: "The date with timezone at which the edit was confirmed."
|
||||
* format: date-time
|
||||
* declined_by:
|
||||
* type: string
|
||||
* description: "The unique identifier of the user or customer who declined the order edit."
|
||||
* declined_at:
|
||||
* type: string
|
||||
* description: "The date with timezone at which the edit was declined."
|
||||
* format: date-time
|
||||
* declined_reason:
|
||||
* description: "An optional note why the order edit is declined."
|
||||
* type: string
|
||||
* subtotal:
|
||||
* type: integer
|
||||
* description: The subtotal for line items computed from changes.
|
||||
* example: 8000
|
||||
* discount_total:
|
||||
* type: integer
|
||||
* description: The total of discount
|
||||
* example: 800
|
||||
* tax_total:
|
||||
* type: integer
|
||||
* description: The total of tax
|
||||
* example: 0
|
||||
* total:
|
||||
* type: integer
|
||||
* description: The total amount of the edited order.
|
||||
* example: 8200
|
||||
* difference_due:
|
||||
* type: integer
|
||||
* description: The difference between the total amount of the order and total amount of edited order.
|
||||
* example: 8200
|
||||
* items:
|
||||
* type: array
|
||||
* description: Computed line items from the changes.
|
||||
* items:
|
||||
* $ref: "#/components/schemas/line_item"
|
||||
*/
|
||||
102
packages/medusa/src/models/order-item-change.ts
Normal file
102
packages/medusa/src/models/order-item-change.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import {
|
||||
BeforeInsert,
|
||||
Column,
|
||||
JoinColumn,
|
||||
ManyToOne,
|
||||
OneToOne,
|
||||
Unique,
|
||||
} from "typeorm"
|
||||
|
||||
import { SoftDeletableEntity } from "../interfaces"
|
||||
import OrderEditingFeatureFlag from "../loaders/feature-flags/order-editing"
|
||||
import { FeatureFlagEntity } from "../utils/feature-flag-decorators"
|
||||
import { generateEntityId } from "../utils"
|
||||
import { DbAwareColumn } from "../utils/db-aware-column"
|
||||
import { OrderEdit } from "./order-edit"
|
||||
import { LineItem } from "./line-item"
|
||||
|
||||
export enum OrderEditItemChangeType {
|
||||
ITEM_ADD = "item_add",
|
||||
ITEM_REMOVE = "item_remove",
|
||||
ITEM_UPDATE = "item_update",
|
||||
}
|
||||
|
||||
@FeatureFlagEntity(OrderEditingFeatureFlag.key)
|
||||
@Unique(["order_edit_id", "original_line_item_id"])
|
||||
@Unique(["order_edit_id", "line_item_id"])
|
||||
export class OrderItemChange extends SoftDeletableEntity {
|
||||
@DbAwareColumn({
|
||||
type: "enum",
|
||||
enum: OrderEditItemChangeType,
|
||||
})
|
||||
type: OrderEditItemChangeType
|
||||
|
||||
@Column()
|
||||
order_edit_id: string
|
||||
|
||||
@ManyToOne(() => OrderEdit, (oe) => oe.changes)
|
||||
@JoinColumn({ name: "order_edit_id" })
|
||||
order_edit: OrderEdit
|
||||
|
||||
@Column({ nullable: true })
|
||||
original_line_item_id?: string
|
||||
|
||||
@ManyToOne(() => LineItem, { nullable: true })
|
||||
@JoinColumn({ name: "original_line_item_id" })
|
||||
original_line_item?: LineItem
|
||||
|
||||
@Column({ nullable: true })
|
||||
line_item_id?: string
|
||||
|
||||
@OneToOne(() => LineItem, { nullable: true })
|
||||
@JoinColumn({ name: "line_item_id" })
|
||||
line_item?: LineItem
|
||||
|
||||
@BeforeInsert()
|
||||
private beforeInsert(): void {
|
||||
this.id = generateEntityId(this.id, "oic")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @schema order_item_change
|
||||
* title: "Order Item Change"
|
||||
* description: "Represents an order edit item change"
|
||||
* x-resourceId: order_item_change
|
||||
* required:
|
||||
* - type
|
||||
* - order_edit_id
|
||||
* properties:
|
||||
* id:
|
||||
* type: string
|
||||
* description: The order item change's ID
|
||||
* example: oic_01G8TJSYT9M6AVS5N4EMNFS1EK
|
||||
* type:
|
||||
* type: string
|
||||
* description: The order's status
|
||||
* enum:
|
||||
* - item_add
|
||||
* - item_remove
|
||||
* - item_update
|
||||
* order_edit_id:
|
||||
* type: string
|
||||
* description: The ID of the order edit
|
||||
* example: oe_01G2SG30J8C85S4A5CHM2S1NS2
|
||||
* order_edit:
|
||||
* description: Order edit object
|
||||
* $ref: "#/components/schemas/order_edit"
|
||||
* original_line_item_id:
|
||||
* type: string
|
||||
* description: The ID of the original line item in the order
|
||||
* example: item_01G8ZC9GWT6B2GP5FSXRXNFNGN
|
||||
* original_line_item:
|
||||
* description: Original line item object.
|
||||
* $ref: "#/components/schemas/line_item"
|
||||
* line_item_id:
|
||||
* type: string
|
||||
* description: The ID of the cloned line item.
|
||||
* example: item_01G8ZC9GWT6B2GP5FSXRXNFNGN
|
||||
* line_item:
|
||||
* description: Line item object.
|
||||
* $ref: "#/components/schemas/line_item"
|
||||
*/
|
||||
@@ -42,6 +42,8 @@ import { ShippingMethod } from "./shipping-method"
|
||||
import { Swap } from "./swap"
|
||||
import { generateEntityId } from "../utils/generate-entity-id"
|
||||
import { manualAutoIncrement } from "../utils/manual-auto-increment"
|
||||
import { OrderEdit } from "./order-edit"
|
||||
import OrderEditingFeatureFlag from "../loaders/feature-flags/order-editing"
|
||||
|
||||
export enum OrderStatus {
|
||||
PENDING = "pending",
|
||||
@@ -208,6 +210,14 @@ export class Order extends BaseEntity {
|
||||
@JoinColumn({ name: "draft_order_id" })
|
||||
draft_order: DraftOrder
|
||||
|
||||
@FeatureFlagDecorators(OrderEditingFeatureFlag.key, [
|
||||
OneToMany(
|
||||
() => OrderEdit,
|
||||
(oe) => oe.order
|
||||
),
|
||||
])
|
||||
edits: OrderEdit[]
|
||||
|
||||
@OneToMany(() => LineItem, (lineItem) => lineItem.order, {
|
||||
cascade: ["insert"],
|
||||
})
|
||||
@@ -406,25 +416,25 @@ export class Order extends BaseEntity {
|
||||
* description: The returns associated with the order. Available if the relation `returns` is expanded.
|
||||
* items:
|
||||
* type: object
|
||||
* description: A return object.
|
||||
* description: A return object.
|
||||
* claims:
|
||||
* type: array
|
||||
* description: The claims associated with the order. Available if the relation `claims` is expanded.
|
||||
* items:
|
||||
* type: object
|
||||
* description: A claim order object.
|
||||
* description: A claim order object.
|
||||
* refunds:
|
||||
* type: array
|
||||
* description: The refunds associated with the order. Available if the relation `refunds` is expanded.
|
||||
* items:
|
||||
* type: object
|
||||
* description: A refund object.
|
||||
* description: A refund object.
|
||||
* swaps:
|
||||
* type: array
|
||||
* description: The swaps associated with the order. Available if the relation `swaps` is expanded.
|
||||
* items:
|
||||
* type: object
|
||||
* description: A swap object.
|
||||
* description: A swap object.
|
||||
* draft_order_id:
|
||||
* type: string
|
||||
* description: The ID of the draft order this order is associated with.
|
||||
@@ -437,6 +447,11 @@ export class Order extends BaseEntity {
|
||||
* description: The line items that belong to the order. Available if the relation `items` is expanded.
|
||||
* items:
|
||||
* $ref: "#/components/schemas/line_item"
|
||||
* edits:
|
||||
* type: array
|
||||
* description: [EXPERIMENTAL] Order edits done on the order. Available if the relation `edits` is expanded.
|
||||
* items:
|
||||
* $ref: "#/components/schemas/order_edit"
|
||||
* gift_card_transactions:
|
||||
* type: array
|
||||
* description: The gift card transactions used in the order. Available if the relation `gift_card_transactions` is expanded.
|
||||
|
||||
6
packages/medusa/src/repositories/order-edit.ts
Normal file
6
packages/medusa/src/repositories/order-edit.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { EntityRepository, Repository } from "typeorm"
|
||||
|
||||
import { OrderEdit } from "../models/order-edit"
|
||||
|
||||
@EntityRepository(OrderEdit)
|
||||
export class OrderEditRepository extends Repository<OrderEdit> {}
|
||||
6
packages/medusa/src/repositories/order-item-change.ts
Normal file
6
packages/medusa/src/repositories/order-item-change.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { EntityRepository, Repository } from "typeorm"
|
||||
|
||||
import { OrderItemChange } from "../models/order-item-change"
|
||||
|
||||
@EntityRepository(OrderItemChange)
|
||||
export class OrderItemChangeRepository extends Repository<OrderItemChange> {}
|
||||
Reference in New Issue
Block a user