diff --git a/packages/medusa/src/api/routes/admin/orders/index.ts b/packages/medusa/src/api/routes/admin/orders/index.ts index 1d79058ac9..073f11c898 100644 --- a/packages/medusa/src/api/routes/admin/orders/index.ts +++ b/packages/medusa/src/api/routes/admin/orders/index.ts @@ -10,7 +10,6 @@ import middlewares, { transformQuery } from "../../../middlewares" import { AdminGetOrdersParams } from "./list-orders" import { FlagRouter } from "../../../../utils/flag-router" import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels" -import OrderEditingFeatureFlag from "../../../../loaders/feature-flags/order-editing" const route = Router() diff --git a/packages/medusa/src/migrations/1664880666982-payment-collection.ts b/packages/medusa/src/migrations/1664880666982-payment-collection.ts new file mode 100644 index 0000000000..c66fec1dd9 --- /dev/null +++ b/packages/medusa/src/migrations/1664880666982-payment-collection.ts @@ -0,0 +1,116 @@ +import { MigrationInterface, QueryRunner } from "typeorm" + +import OrderEditingFeatureFlag from "../loaders/feature-flags/order-editing" + +export const featureFlag = OrderEditingFeatureFlag.key + +export class paymentCollection1664880666982 implements MigrationInterface { + name = "paymentCollection1664880666982" + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(` + CREATE TYPE "PAYMENT_COLLECTION_TYPE_ENUM" AS ENUM ('order_edit'); + + CREATE TYPE "PAYMENT_COLLECTION_STATUS_ENUM" AS ENUM ( + 'not_paid', 'awaiting', 'authorized', 'partially_authorized', 'captured', + 'partially_captured', 'refunded', 'partially_refunded', 'canceled', 'requires_action' + ); + + CREATE TABLE IF NOT EXISTS payment_collection + ( + 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 NULL, + type "PAYMENT_COLLECTION_TYPE_ENUM" NOT NULL, + status "PAYMENT_COLLECTION_STATUS_ENUM" NOT NULL, + description text NULL, + amount integer NOT NULL, + authorized_amount integer NULL, + refunded_amount integer NULL, + region_id character varying NOT NULL, + currency_code character varying NOT NULL, + metadata jsonb NULL, + created_by character varying NOT NULL, + CONSTRAINT "PK_payment_collection_id" PRIMARY KEY ("id") + ); + CREATE INDEX "IDX_payment_collection_region_id" ON "payment_collection" ("region_id") WHERE deleted_at IS NULL; + CREATE INDEX "IDX_payment_collection_currency_code" ON "payment_collection" ("currency_code") WHERE deleted_at IS NULL; + + ALTER TABLE "payment_collection" ADD CONSTRAINT "FK_payment_collection_region_id" FOREIGN KEY ("region_id") REFERENCES "region"("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + + + CREATE TABLE payment_collection_sessions + ( + payment_collection_id CHARACTER VARYING NOT NULL, + payment_session_id CHARACTER VARYING NOT NULL, + CONSTRAINT "PK_payment_collection_sessions" PRIMARY KEY ("payment_collection_id", "payment_session_id") + ); + CREATE INDEX "IDX_payment_collection_sessions_payment_collection_id" ON "payment_collection_sessions" ("payment_collection_id"); + CREATE INDEX "IDX_payment_collection_sessions_payment_session_id" ON "payment_collection_sessions" ("payment_session_id"); + + ALTER TABLE "payment_collection_sessions" ADD CONSTRAINT "FK_payment_collection_sessions_payment_collection_id" FOREIGN KEY ("payment_collection_id") REFERENCES "payment_collection"("id") ON DELETE CASCADE ON UPDATE NO ACTION; + ALTER TABLE "payment_collection_sessions" ADD CONSTRAINT "FK_payment_collection_sessions_payment_session_id" FOREIGN KEY ("payment_session_id") REFERENCES "payment_session"("id") ON DELETE CASCADE ON UPDATE NO ACTION; + + + CREATE TABLE payment_collection_payments + ( + payment_collection_id CHARACTER VARYING NOT NULL, + payment_id CHARACTER VARYING NOT NULL, + CONSTRAINT "PK_payment_collection_payments" PRIMARY KEY ("payment_collection_id", "payment_id") + ); + CREATE INDEX "IDX_payment_collection_payments_payment_collection_id" ON "payment_collection_payments" ("payment_collection_id"); + CREATE INDEX "IDX_payment_collection_payments_payment_id" ON "payment_collection_payments" ("payment_id"); + + ALTER TABLE "payment_collection_payments" ADD CONSTRAINT "FK_payment_collection_payments_payment_collection_id" FOREIGN KEY ("payment_collection_id") REFERENCES "payment_collection"("id") ON DELETE CASCADE ON UPDATE NO ACTION; + ALTER TABLE "payment_collection_payments" ADD CONSTRAINT "FK_payment_collection_payments_payment_id" FOREIGN KEY ("payment_id") REFERENCES "payment"("id") ON DELETE CASCADE ON UPDATE NO ACTION; + + + ALTER TABLE order_edit ADD COLUMN payment_collection_id character varying NULL; + CREATE INDEX "IDX_order_edit_payment_collection_id" ON "order_edit" ("payment_collection_id"); + ALTER TABLE "order_edit" ADD CONSTRAINT "FK_order_edit_payment_collection_id" FOREIGN KEY ("payment_collection_id") REFERENCES "payment_collection"("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + + ALTER TABLE payment_session ADD COLUMN payment_authorized_at timestamp WITH time zone NULL; + `) + + // Add missing indexes + await queryRunner.query(` + CREATE INDEX "IDX_order_edit_order_id" ON "order_edit" ("order_id"); + CREATE INDEX "IDX_money_amount_currency_code" ON "money_amount" ("currency_code"); + CREATE INDEX "IDX_order_currency_code" ON "order" ("currency_code"); + CREATE INDEX "IDX_payment_currency_code" ON "payment" ("currency_code"); + CREATE INDEX "IDX_region_currency_code" ON "region" ("currency_code"); + `) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(` + ALTER TABLE payment_collection DROP CONSTRAINT "FK_payment_collection_region_id"; + ALTER TABLE payment_collection_sessions DROP CONSTRAINT "FK_payment_collection_sessions_payment_collection_id"; + ALTER TABLE payment_collection_sessions DROP CONSTRAINT "FK_payment_collection_sessions_payment_session_id"; + ALTER TABLE payment_collection_payments DROP CONSTRAINT "FK_payment_collection_payments_payment_collection_id"; + ALTER TABLE payment_collection_payments DROP CONSTRAINT "FK_payment_collection_payments_payment_id"; + ALTER TABLE order_edit DROP COLUMN payment_collection_id; + ALTER TABLE payment_session DROP COLUMN payment_authorized_at; + + DROP TABLE payment_collection; + DROP TABLE payment_collection_sessions; + DROP TABLE payment_collection_payments; + + DROP TYPE "PAYMENT_COLLECTION_TYPE_ENUM"; + DROP TYPE "PAYMENT_COLLECTION_STATUS_ENUM"; + + DROP INDEX "IDX_order_edit_payment_collection_id"; + ALTER TABLE order_edit DROP CONSTRAINT "FK_order_edit_payment_collection_id"; + + `) + + await queryRunner.query(` + DROP INDEX "IDX_order_edit_order_id"; + DROP INDEX "IDX_money_amount_currency_code"; + DROP INDEX "IDX_order_currency_code"; + DROP INDEX "IDX_payment_currency_code"; + DROP INDEX "IDX_region_currency_code"; + `) + } +} diff --git a/packages/medusa/src/models/index.ts b/packages/medusa/src/models/index.ts index 58e0e1bb1a..21a567fbfe 100644 --- a/packages/medusa/src/models/index.ts +++ b/packages/medusa/src/models/index.ts @@ -40,6 +40,7 @@ export * from "./order-item-change" export * from "./payment" export * from "./payment-provider" export * from "./payment-session" +export * from "./payment-collection" export * from "./price-list" export * from "./product" export * from "./product-collection" diff --git a/packages/medusa/src/models/money-amount.ts b/packages/medusa/src/models/money-amount.ts index b0884a9669..0fc064b9d1 100644 --- a/packages/medusa/src/models/money-amount.ts +++ b/packages/medusa/src/models/money-amount.ts @@ -16,6 +16,7 @@ import { generateEntityId } from "../utils/generate-entity-id" @Entity() export class MoneyAmount extends SoftDeletableEntity { + @Index() @Column() currency_code: string diff --git a/packages/medusa/src/models/order-edit.ts b/packages/medusa/src/models/order-edit.ts index bd36737d38..afa954827f 100644 --- a/packages/medusa/src/models/order-edit.ts +++ b/packages/medusa/src/models/order-edit.ts @@ -2,19 +2,20 @@ import { AfterLoad, BeforeInsert, Column, + Index, JoinColumn, ManyToOne, OneToMany, + OneToOne, } 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 { BaseEntity } from "../interfaces" import { generateEntityId } from "../utils" -import { LineItem } from "./line-item" -import { Order } from "./order" + +import { LineItem, Order, OrderItemChange, PaymentCollection } from "." export enum OrderEditStatus { CONFIRMED = "confirmed", @@ -26,6 +27,7 @@ export enum OrderEditStatus { @FeatureFlagEntity(OrderEditingFeatureFlag.key) export class OrderEdit extends BaseEntity { + @Index() @Column() order_id: string @@ -74,6 +76,14 @@ export class OrderEdit extends BaseEntity { @OneToMany(() => LineItem, (lineItem) => lineItem.order_edit) items: LineItem[] + @Index() + @Column({ nullable: true }) + payment_collection_id: string + + @OneToOne(() => PaymentCollection) + @JoinColumn({ name: "payment_collection_id" }) + payment_collection: PaymentCollection + // Computed shipping_total: number discount_total: number diff --git a/packages/medusa/src/models/order.ts b/packages/medusa/src/models/order.ts index 2268cbc504..a30d72d7d5 100644 --- a/packages/medusa/src/models/order.ts +++ b/packages/medusa/src/models/order.ts @@ -140,6 +140,7 @@ export class Order extends BaseEntity { @JoinColumn({ name: "region_id" }) region: Region + @Index() @Column() currency_code: string diff --git a/packages/medusa/src/models/payment-collection.ts b/packages/medusa/src/models/payment-collection.ts new file mode 100644 index 0000000000..6d2cbbd390 --- /dev/null +++ b/packages/medusa/src/models/payment-collection.ts @@ -0,0 +1,110 @@ +import { + BeforeInsert, + Column, + Index, + JoinColumn, + JoinTable, + ManyToMany, + ManyToOne, +} from "typeorm" + +import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" +import { DbAwareColumn } from "../utils/db-aware-column" +import { generateEntityId } from "../utils" +import { Currency, Payment, PaymentSession, Region } from "." + +import OrderEditingFeatureFlag from "../loaders/feature-flags/order-editing" +import { FeatureFlagEntity } from "../utils/feature-flag-decorators" + +export enum PaymentCollectionStatus { + NOT_PAID = "not_paid", + AWAITING = "awaiting", + AUTHORIZED = "authorized", + PARTIALLY_AUTHORIZED = "partially_authorized", + CAPTURED = "captured", + PARTIALLY_CAPTURED = "partially_captured", + REFUNDED = "refunded", + PARTIALLY_REFUNDED = "partially_refunded", + CANCELED = "canceled", + REQUIRES_ACTION = "requires_action", +} + +export enum PaymentCollectionType { + ORDER_EDIT = "order_edit", +} + +@FeatureFlagEntity(OrderEditingFeatureFlag.key) +export class PaymentCollection extends SoftDeletableEntity { + @DbAwareColumn({ type: "enum", enum: PaymentCollectionType }) + type: string + + @DbAwareColumn({ type: "enum", enum: PaymentCollectionStatus }) + status: string + + @Column({ nullable: true }) + description: string + + @Column({ type: "int" }) + amount: number + + @Column({ type: "int", nullable: true }) + authorized_amount: number + + @Column({ type: "int", nullable: true }) + refunded_amount: number + + @Index() + @Column() + region_id: string + + @ManyToOne(() => Region) + @JoinColumn({ name: "region_id" }) + region: Region + + @Index() + @Column() + currency_code: string + + @ManyToOne(() => Currency) + @JoinColumn({ name: "currency_code", referencedColumnName: "code" }) + currency: Currency + + @ManyToMany(() => PaymentSession) + @JoinTable({ + name: "payment_collection_sessions", + joinColumn: { + name: "payment_collection_id", + referencedColumnName: "id", + }, + inverseJoinColumn: { + name: "payment_session_id", + referencedColumnName: "id", + }, + }) + payment_sessions: PaymentSession[] + + @ManyToMany(() => Payment) + @JoinTable({ + name: "payment_collection_payments", + joinColumn: { + name: "payment_collection_id", + referencedColumnName: "id", + }, + inverseJoinColumn: { + name: "payment_id", + referencedColumnName: "id", + }, + }) + payments: Payment[] + + @DbAwareColumn({ type: "jsonb" }) + metadata: Record + + @Column() + created_by: string + + @BeforeInsert() + private beforeInsert(): void { + this.id = generateEntityId(this.id, "paycol") + } +} diff --git a/packages/medusa/src/models/payment-session.ts b/packages/medusa/src/models/payment-session.ts index 2945f11041..41630a86ab 100644 --- a/packages/medusa/src/models/payment-session.ts +++ b/packages/medusa/src/models/payment-session.ts @@ -10,8 +10,10 @@ import { import { BaseEntity } from "../interfaces" import { Cart } from "./cart" -import { DbAwareColumn } from "../utils/db-aware-column" +import { DbAwareColumn, resolveDbType } from "../utils/db-aware-column" import { generateEntityId } from "../utils" +import { FeatureFlagDecorators } from "../utils/feature-flag-decorators" +import OrderEditingFeatureFlag from "../loaders/feature-flags/order-editing" export enum PaymentSessionStatus { AUTHORIZED = "authorized", @@ -49,6 +51,11 @@ export class PaymentSession extends BaseEntity { @Column({ nullable: true }) idempotency_key: string + @FeatureFlagDecorators(OrderEditingFeatureFlag.key, [ + Column({ type: resolveDbType("timestamptz"), nullable: true }), + ]) + payment_authorized_at: Date + @BeforeInsert() private beforeInsert(): void { this.id = generateEntityId(this.id, "ps") diff --git a/packages/medusa/src/models/payment.ts b/packages/medusa/src/models/payment.ts index 456c86156d..0719b0e63f 100644 --- a/packages/medusa/src/models/payment.ts +++ b/packages/medusa/src/models/payment.ts @@ -17,7 +17,10 @@ import { Swap } from "./swap" import { generateEntityId } from "../utils/generate-entity-id" @Index(["cart_id"], { where: "canceled_at IS NOT NULL" }) -@Index("UniquePaymentActive", ["cart_id"], { where: "canceled_at IS NULL", unique: true, }) +@Index("UniquePaymentActive", ["cart_id"], { + where: "canceled_at IS NULL", + unique: true, +}) @Entity() export class Payment extends BaseEntity { @Index() @@ -40,16 +43,14 @@ export class Payment extends BaseEntity { @Column({ nullable: true }) order_id: string - @ManyToOne( - () => Order, - (order) => order.payments - ) + @ManyToOne(() => Order, (order) => order.payments) @JoinColumn({ name: "order_id" }) order: Order @Column({ type: "int" }) amount: number + @Index() @Column() currency_code: string diff --git a/packages/medusa/src/models/region.ts b/packages/medusa/src/models/region.ts index 12aa581714..16adf80be1 100644 --- a/packages/medusa/src/models/region.ts +++ b/packages/medusa/src/models/region.ts @@ -2,6 +2,7 @@ import { BeforeInsert, Column, Entity, + Index, JoinColumn, JoinTable, ManyToMany, @@ -26,6 +27,7 @@ export class Region extends SoftDeletableEntity { @Column() name: string + @Index() @Column() currency_code: string diff --git a/packages/medusa/src/repositories/payment-collection.ts b/packages/medusa/src/repositories/payment-collection.ts new file mode 100644 index 0000000000..6e58146cd6 --- /dev/null +++ b/packages/medusa/src/repositories/payment-collection.ts @@ -0,0 +1,6 @@ +import { PaymentCollection } from "./../models/payment-collection" +import { EntityRepository, Repository } from "typeorm" + +@EntityRepository(PaymentCollection) +// eslint-disable-next-line max-len +export class PaymentCollectionRepository extends Repository {}