chore(): Reorganize modules (#7210)
**What** Move all modules to the modules directory
This commit is contained in:
committed by
GitHub
parent
7a351eef09
commit
4eae25e1ef
14
packages/modules/order/src/index.ts
Normal file
14
packages/modules/order/src/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { initializeFactory, Modules } from "@medusajs/modules-sdk"
|
||||
import { moduleDefinition } from "./module-definition"
|
||||
|
||||
export * from "./models"
|
||||
export * from "./services"
|
||||
export * from "./types"
|
||||
|
||||
export const initialize = initializeFactory({
|
||||
moduleName: Modules.ORDER,
|
||||
moduleDefinition,
|
||||
})
|
||||
export const runMigrations = moduleDefinition.runMigrations
|
||||
export const revertMigration = moduleDefinition.revertMigration
|
||||
export default moduleDefinition
|
||||
35
packages/modules/order/src/joiner-config.ts
Normal file
35
packages/modules/order/src/joiner-config.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { Modules } from "@medusajs/modules-sdk"
|
||||
import { ModuleJoinerConfig } from "@medusajs/types"
|
||||
import { MapToConfig } from "@medusajs/utils"
|
||||
import { LineItem } from "@models"
|
||||
import Order from "./models/order"
|
||||
|
||||
export const LinkableKeys: Record<string, string> = {
|
||||
order_id: Order.name,
|
||||
order_item_id: LineItem.name,
|
||||
}
|
||||
|
||||
const entityLinkableKeysMap: MapToConfig = {}
|
||||
Object.entries(LinkableKeys).forEach(([key, value]) => {
|
||||
entityLinkableKeysMap[value] ??= []
|
||||
entityLinkableKeysMap[value].push({
|
||||
mapTo: key,
|
||||
valueFrom: key.split("_").pop()!,
|
||||
})
|
||||
})
|
||||
|
||||
export const entityNameToLinkableKeysMap: MapToConfig = entityLinkableKeysMap
|
||||
|
||||
export const joinerConfig: ModuleJoinerConfig = {
|
||||
serviceName: Modules.ORDER,
|
||||
primaryKeys: ["id"],
|
||||
linkableKeys: LinkableKeys,
|
||||
alias: [
|
||||
{
|
||||
name: ["order", "orders"],
|
||||
args: {
|
||||
entity: Order.name,
|
||||
},
|
||||
},
|
||||
],
|
||||
} as ModuleJoinerConfig
|
||||
2150
packages/modules/order/src/migrations/.snapshot-medusa-order.json
Normal file
2150
packages/modules/order/src/migrations/.snapshot-medusa-order.json
Normal file
File diff suppressed because it is too large
Load Diff
532
packages/modules/order/src/migrations/Migration20240219102530.ts
Normal file
532
packages/modules/order/src/migrations/Migration20240219102530.ts
Normal file
@@ -0,0 +1,532 @@
|
||||
import { generatePostgresAlterColummnIfExistStatement } from "@medusajs/utils"
|
||||
import { Migration } from "@mikro-orm/migrations"
|
||||
|
||||
export class Migration20240219102530 extends Migration {
|
||||
async up(): Promise<void> {
|
||||
const sql = `
|
||||
CREATE TABLE IF NOT EXISTS "order_address" (
|
||||
"id" TEXT NOT NULL,
|
||||
"customer_id" TEXT NULL,
|
||||
"company" TEXT NULL,
|
||||
"first_name" TEXT NULL,
|
||||
"last_name" TEXT NULL,
|
||||
"address_1" TEXT NULL,
|
||||
"address_2" TEXT NULL,
|
||||
"city" TEXT NULL,
|
||||
"country_code" TEXT NULL,
|
||||
"province" TEXT NULL,
|
||||
"postal_code" TEXT NULL,
|
||||
"phone" TEXT NULL,
|
||||
"metadata" JSONB NULL,
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT Now(),
|
||||
"updated_at" TIMESTAMPTZ NOT NULL DEFAULT Now(),
|
||||
CONSTRAINT "order_address_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_address_customer_id" ON "order_address" (
|
||||
customer_id
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "order" (
|
||||
"id" TEXT NOT NULL,
|
||||
"region_id" TEXT NULL,
|
||||
"customer_id" TEXT NULL,
|
||||
"version" INTEGER NOT NULL DEFAULT 1,
|
||||
"sales_channel_id" TEXT NULL,
|
||||
"status" text NOT NULL,
|
||||
"is_draft_order" BOOLEAN NOT NULL DEFAULT false,
|
||||
"email" text NULL,
|
||||
"currency_code" text NOT NULL,
|
||||
"shipping_address_id" text NULL,
|
||||
"billing_address_id" text NULL,
|
||||
"no_notification" boolean NULL,
|
||||
"metadata" jsonb NULL,
|
||||
"created_at" timestamptz NOT NULL DEFAULT now(),
|
||||
"updated_at" timestamptz NOT NULL DEFAULT now(),
|
||||
"deleted_at" timestamptz NULL,
|
||||
"canceled_at" timestamptz NULL,
|
||||
CONSTRAINT "order_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
ALTER TABLE "order"
|
||||
ADD COLUMN if NOT exists "deleted_at" timestamptz NULL;
|
||||
|
||||
ALTER TABLE "order"
|
||||
ADD COLUMN if NOT exists "is_draft_order" BOOLEAN NOT NULL DEFAULT false;
|
||||
|
||||
ALTER TABLE "order"
|
||||
ADD COLUMN if NOT exists "version" INTEGER NOT NULL DEFAULT 1;
|
||||
|
||||
|
||||
ALTER TABLE "order" ALTER COLUMN status TYPE text;
|
||||
DROP TYPE IF EXISTS order_status_enum CASCADE;
|
||||
CREATE TYPE order_status_enum AS ENUM (
|
||||
'pending',
|
||||
'completed',
|
||||
'draft',
|
||||
'archived',
|
||||
'canceled',
|
||||
'requires_action'
|
||||
);
|
||||
ALTER TABLE "order" ALTER COLUMN status DROP DEFAULT;
|
||||
ALTER TABLE "order" ALTER COLUMN status TYPE order_status_enum USING (status::text::order_status_enum);
|
||||
ALTER TABLE "order" ALTER COLUMN status SET DEFAULT 'pending';
|
||||
|
||||
|
||||
ALTER TABLE "order" DROP constraint if EXISTS "FK_6ff7e874f01b478c115fdd462eb" CASCADE;
|
||||
|
||||
ALTER TABLE "order" DROP constraint if EXISTS "FK_19b0c6293443d1b464f604c3316" CASCADE;
|
||||
|
||||
ALTER TABLE "order" DROP constraint if EXISTS "FK_717a141f96b76d794d409f38129" CASCADE;
|
||||
|
||||
ALTER TABLE "order" DROP constraint if EXISTS "FK_727b872f86c7378474a8fa46147" CASCADE;
|
||||
|
||||
ALTER TABLE "order" DROP constraint if EXISTS "FK_5568d3b9ce9f7abeeb37511ecf2" CASCADE;
|
||||
|
||||
ALTER TABLE "order" DROP constraint if EXISTS "FK_c99a206eb11ad45f6b7f04f2dcc" CASCADE;
|
||||
|
||||
ALTER TABLE "order" DROP constraint if EXISTS "FK_cd7812c96209c5bdd48a6b858b0" CASCADE;
|
||||
|
||||
ALTER TABLE "order" DROP constraint if EXISTS "FK_e1fcce2b18dbcdbe0a5ba9a68b8" CASCADE;
|
||||
|
||||
ALTER TABLE "order" DROP constraint if EXISTS "REL_c99a206eb11ad45f6b7f04f2dc" CASCADE;
|
||||
|
||||
ALTER TABLE "order" DROP constraint if EXISTS "UQ_727b872f86c7378474a8fa46147" CASCADE;
|
||||
|
||||
DROP INDEX if exists "IDX_19b0c6293443d1b464f604c331";
|
||||
|
||||
DROP INDEX if exists "IDX_579e01fb94f4f58db480857e05";
|
||||
|
||||
DROP INDEX if exists "IDX_5568d3b9ce9f7abeeb37511ecf";
|
||||
|
||||
DROP INDEX if exists "IDX_c99a206eb11ad45f6b7f04f2dc";
|
||||
|
||||
DROP INDEX if exists "IDX_cd7812c96209c5bdd48a6b858b";
|
||||
|
||||
DROP INDEX if exists "IDX_e1fcce2b18dbcdbe0a5ba9a68b";
|
||||
|
||||
${generatePostgresAlterColummnIfExistStatement(
|
||||
"order",
|
||||
["fulfillment_status", "payment_status", "display_id"],
|
||||
"DROP NOT NULL"
|
||||
)}
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_region_id" ON "order" (
|
||||
region_id
|
||||
)
|
||||
WHERE deleted_at IS NOT NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_customer_id" ON "order" (
|
||||
customer_id
|
||||
)
|
||||
WHERE deleted_at IS NOT NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_customer_id" ON "order" (
|
||||
customer_id
|
||||
)
|
||||
WHERE deleted_at IS NOT NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_currency_code" ON "order" (
|
||||
currency_code
|
||||
)
|
||||
WHERE deleted_at IS NOT NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_shipping_address_id" ON "order" (
|
||||
shipping_address_id
|
||||
)
|
||||
WHERE deleted_at IS NOT NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_billing_address_id" ON "order" (
|
||||
billing_address_id
|
||||
)
|
||||
WHERE deleted_at IS NOT NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_deleted_at" ON "order" (
|
||||
deleted_at
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_is_draft_order" ON "order" (
|
||||
is_draft_order
|
||||
)
|
||||
WHERE deleted_at IS NOT NULL;
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "order_summary" (
|
||||
"id" TEXT NOT NULL,
|
||||
"order_id" TEXT NOT NULL,
|
||||
"version" INTEGER NOT NULL DEFAULT 1,
|
||||
"totals" JSONB NULL,
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT Now(),
|
||||
"updated_at" TIMESTAMPTZ NOT NULL DEFAULT Now(),
|
||||
"deleted_at" timestamptz NULL,
|
||||
CONSTRAINT "order_summary_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_summary_order_id_version" ON "order_summary" (
|
||||
order_id,
|
||||
version
|
||||
)
|
||||
WHERE deleted_at IS NOT NULL;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "order_change" (
|
||||
"id" TEXT NOT NULL,
|
||||
"order_id" TEXT NOT NULL,
|
||||
"version" INTEGER NOT NULL,
|
||||
"description" TEXT NULL,
|
||||
"status" text check (
|
||||
"status" IN (
|
||||
'confirmed',
|
||||
'declined',
|
||||
'requested',
|
||||
'pending',
|
||||
'canceled'
|
||||
)
|
||||
) NOT NULL DEFAULT 'pending',
|
||||
"internal_note" text NULL,
|
||||
"created_by" text NULL,
|
||||
"requested_by" text NULL,
|
||||
"requested_at" timestamptz NULL,
|
||||
"confirmed_by" text NULL,
|
||||
"confirmed_at" timestamptz NULL,
|
||||
"declined_by" text NULL,
|
||||
"declined_reason" text NULL,
|
||||
"metadata" jsonb NULL,
|
||||
"declined_at" timestamptz NULL,
|
||||
"canceled_by" text NULL,
|
||||
"canceled_at" timestamptz NULL,
|
||||
"created_at" timestamptz NOT NULL DEFAULT now(),
|
||||
"updated_at" timestamptz NOT NULL DEFAULT now(),
|
||||
CONSTRAINT "order_change_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_change_order_id" ON "order_change" (
|
||||
order_id
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_change_order_id_version" ON "order_change" (
|
||||
order_id,
|
||||
version
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_change_status" ON "order_change" (status);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "order_change_action" (
|
||||
"id" TEXT NOT NULL,
|
||||
"order_id" TEXT NULL,
|
||||
"version" INTEGER NULL,
|
||||
"ordering" BIGSERIAL NOT NULL,
|
||||
"order_change_id" TEXT NULL,
|
||||
"reference" TEXT NULL,
|
||||
"reference_id" TEXT NULL,
|
||||
"action" TEXT NOT NULL,
|
||||
"details" JSONB NULL,
|
||||
"amount" NUMERIC NULL,
|
||||
"raw_amount" JSONB NULL,
|
||||
"internal_note" TEXT NULL,
|
||||
"applied" BOOLEAN NOT NULL DEFAULT false,
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT Now(),
|
||||
"updated_at" TIMESTAMPTZ NOT NULL DEFAULT Now(),
|
||||
CONSTRAINT "order_change_action_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_change_action_order_change_id" ON "order_change_action" (
|
||||
order_change_id
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_change_action_order_id" ON "order_change_action" (
|
||||
order_id
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_change_action_ordering" ON "order_change_action" (
|
||||
ordering
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "order_item" (
|
||||
"id" TEXT NOT NULL,
|
||||
"order_id" TEXT NOT NULL,
|
||||
"version" INTEGER NOT NULL,
|
||||
"item_id" TEXT NOT NULL,
|
||||
"quantity" NUMERIC NOT NULL,
|
||||
"raw_quantity" JSONB NOT NULL,
|
||||
"fulfilled_quantity" NUMERIC NOT NULL,
|
||||
"raw_fulfilled_quantity" JSONB NOT NULL,
|
||||
"shipped_quantity" NUMERIC NOT NULL,
|
||||
"raw_shipped_quantity" JSONB NOT NULL,
|
||||
"return_requested_quantity" NUMERIC NOT NULL,
|
||||
"raw_return_requested_quantity" JSONB NOT NULL,
|
||||
"return_received_quantity" NUMERIC NOT NULL,
|
||||
"raw_return_received_quantity" JSONB NOT NULL,
|
||||
"return_dismissed_quantity" NUMERIC NOT NULL,
|
||||
"raw_return_dismissed_quantity" JSONB NOT NULL,
|
||||
"written_off_quantity" NUMERIC NOT NULL,
|
||||
"raw_written_off_quantity" JSONB NOT NULL,
|
||||
"metadata" JSONB NULL,
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT Now(),
|
||||
"updated_at" TIMESTAMPTZ NOT NULL DEFAULT Now(),
|
||||
"deleted_at" timestamptz NULL,
|
||||
CONSTRAINT "order_item_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_item_order_id" ON "order_item" (
|
||||
order_id
|
||||
)
|
||||
WHERE deleted_at IS NOT NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_item_order_id_version" ON "order_item" (
|
||||
order_id,
|
||||
version
|
||||
)
|
||||
WHERE deleted_at IS NOT NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_item_item_id" ON "order_item" (
|
||||
item_id
|
||||
)
|
||||
WHERE deleted_at IS NOT NULL;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "order_shipping" (
|
||||
"id" TEXT NOT NULL,
|
||||
"order_id" TEXT NOT NULL,
|
||||
"version" INTEGER NOT NULL,
|
||||
"shipping_method_id" TEXT NOT NULL,
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT Now(),
|
||||
"updated_at" TIMESTAMPTZ NOT NULL DEFAULT Now(),
|
||||
"deleted_at" timestamptz NULL,
|
||||
CONSTRAINT "order_shipping_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_shipping_order_id" ON "order_shipping" (
|
||||
order_id
|
||||
)
|
||||
WHERE deleted_at IS NOT NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_shipping_order_id_version" ON "order_shipping" (
|
||||
order_id,
|
||||
version
|
||||
)
|
||||
WHERE deleted_at IS NOT NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_shipping_item_id" ON "order_shipping" (
|
||||
shipping_method_id
|
||||
)
|
||||
WHERE deleted_at IS NOT NULL;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "order_line_item" (
|
||||
"id" TEXT NOT NULL,
|
||||
"totals_id" TEXT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"subtitle" TEXT NULL,
|
||||
"thumbnail" TEXT NULL,
|
||||
"variant_id" TEXT NULL,
|
||||
"product_id" TEXT NULL,
|
||||
"product_title" TEXT NULL,
|
||||
"product_description" TEXT NULL,
|
||||
"product_subtitle" TEXT NULL,
|
||||
"product_type" TEXT NULL,
|
||||
"product_collection" TEXT NULL,
|
||||
"product_handle" TEXT NULL,
|
||||
"variant_sku" TEXT NULL,
|
||||
"variant_barcode" TEXT NULL,
|
||||
"variant_title" TEXT NULL,
|
||||
"variant_option_values" JSONB NULL,
|
||||
"requires_shipping" BOOLEAN NOT NULL DEFAULT true,
|
||||
"is_discountable" BOOLEAN NOT NULL DEFAULT true,
|
||||
"is_tax_inclusive" BOOLEAN NOT NULL DEFAULT false,
|
||||
"compare_at_unit_price" NUMERIC NULL,
|
||||
"raw_compare_at_unit_price" JSONB NULL,
|
||||
"unit_price" NUMERIC NOT NULL,
|
||||
"raw_unit_price" JSONB NOT NULL,
|
||||
"metadata" JSONB NULL,
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT Now(),
|
||||
"updated_at" TIMESTAMPTZ NOT NULL DEFAULT Now(),
|
||||
CONSTRAINT "order_line_item_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_line_item_variant_id" ON "order_line_item" (
|
||||
variant_id
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_line_item_product_id" ON "order_line_item" (
|
||||
product_id
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "order_line_item_tax_line" (
|
||||
"id" TEXT NOT NULL,
|
||||
"description" TEXT NULL,
|
||||
"tax_rate_id" TEXT NULL,
|
||||
"code" TEXT NOT NULL,
|
||||
"rate" NUMERIC NOT NULL,
|
||||
"raw_rate" JSONB NOT NULL,
|
||||
"provider_id" TEXT NULL,
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT Now(),
|
||||
"updated_at" TIMESTAMPTZ NOT NULL DEFAULT Now(),
|
||||
"item_id" TEXT NOT NULL,
|
||||
CONSTRAINT "order_line_item_tax_line_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_line_item_tax_line_item_id" ON "order_line_item_tax_line" (item_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "order_line_item_adjustment" (
|
||||
"id" TEXT NOT NULL,
|
||||
"description" TEXT NULL,
|
||||
"promotion_id" TEXT NULL,
|
||||
"code" TEXT NULL,
|
||||
"amount" NUMERIC NOT NULL,
|
||||
"raw_amount" JSONB NOT NULL,
|
||||
"provider_id" TEXT NULL,
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT Now(),
|
||||
"updated_at" TIMESTAMPTZ NOT NULL DEFAULT Now(),
|
||||
"item_id" TEXT NOT NULL,
|
||||
CONSTRAINT "order_line_item_adjustment_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_line_item_adjustment_item_id" ON "order_line_item_adjustment" (item_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "order_shipping_method" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"description" JSONB NULL,
|
||||
"amount" NUMERIC NOT NULL,
|
||||
"raw_amount" JSONB NOT NULL,
|
||||
"is_tax_inclusive" BOOLEAN NOT NULL DEFAULT false,
|
||||
"shipping_option_id" TEXT NULL,
|
||||
"data" JSONB NULL,
|
||||
"metadata" JSONB NULL,
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT Now(),
|
||||
"updated_at" TIMESTAMPTZ NOT NULL DEFAULT Now(),
|
||||
CONSTRAINT "order_shipping_method_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_shipping_method_shipping_option_id" ON "order_shipping_method" (
|
||||
shipping_option_id
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "order_shipping_method_adjustment" (
|
||||
"id" TEXT NOT NULL,
|
||||
"description" TEXT NULL,
|
||||
"promotion_id" TEXT NULL,
|
||||
"code" TEXT NULL,
|
||||
"amount" NUMERIC NOT NULL,
|
||||
"raw_amount" JSONB NOT NULL,
|
||||
"provider_id" TEXT NULL,
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT Now(),
|
||||
"updated_at" TIMESTAMPTZ NOT NULL DEFAULT Now(),
|
||||
"shipping_method_id" TEXT NOT NULL,
|
||||
CONSTRAINT "order_shipping_method_adjustment_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_shipping_method_adjustment_shipping_method_id" ON "order_shipping_method_adjustment" (
|
||||
shipping_method_id
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "order_shipping_method_tax_line" (
|
||||
"id" TEXT NOT NULL,
|
||||
"description" TEXT NULL,
|
||||
"tax_rate_id" TEXT NULL,
|
||||
"code" TEXT NOT NULL,
|
||||
"rate" NUMERIC NOT NULL,
|
||||
"raw_rate" JSONB NOT NULL,
|
||||
"provider_id" TEXT NULL,
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT Now(),
|
||||
"updated_at" TIMESTAMPTZ NOT NULL DEFAULT Now(),
|
||||
"shipping_method_id" TEXT NOT NULL,
|
||||
CONSTRAINT "order_shipping_method_tax_line_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_shipping_method_tax_line_shipping_method_id" ON "order_shipping_method_tax_line" (
|
||||
shipping_method_id
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "order_transaction" (
|
||||
"id" TEXT NOT NULL,
|
||||
"order_id" TEXT NOT NULL,
|
||||
"amount" NUMERIC NOT NULL,
|
||||
"raw_amount" JSONB NOT NULL,
|
||||
"currency_code" TEXT NOT NULL,
|
||||
"reference" TEXT NULL,
|
||||
"reference_id" TEXT NULL,
|
||||
"created_at" TIMESTAMPTZ NOT NULL DEFAULT Now(),
|
||||
"updated_at" TIMESTAMPTZ NOT NULL DEFAULT Now(),
|
||||
CONSTRAINT "order_transaction_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_transaction_order_id" ON "order_transaction" (
|
||||
order_id
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_transaction_currency_code" ON "order_transaction" (
|
||||
currency_code
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IDX_order_transaction_reference_id" ON "order_transaction" (
|
||||
reference_id
|
||||
);
|
||||
|
||||
ALTER TABLE if exists "order"
|
||||
ADD CONSTRAINT "order_shipping_address_id_foreign" FOREIGN KEY ("shipping_address_id") REFERENCES "order_address" ("id") ON
|
||||
UPDATE CASCADE ON
|
||||
DELETE CASCADE;
|
||||
|
||||
ALTER TABLE if exists "order"
|
||||
ADD CONSTRAINT "order_billing_address_id_foreign" FOREIGN KEY ("billing_address_id") REFERENCES "order_address" ("id") ON
|
||||
UPDATE CASCADE ON
|
||||
DELETE CASCADE;
|
||||
|
||||
ALTER TABLE if exists "order_change"
|
||||
ADD CONSTRAINT "order_change_order_id_foreign" FOREIGN KEY ("order_id") REFERENCES "order" ("id") ON
|
||||
UPDATE CASCADE ON
|
||||
DELETE CASCADE;
|
||||
|
||||
ALTER TABLE if exists "order_change_action"
|
||||
ADD CONSTRAINT "order_change_action_order_change_id_foreign" FOREIGN KEY ("order_change_id") REFERENCES "order_change" ("id") ON
|
||||
UPDATE CASCADE ON
|
||||
DELETE CASCADE;
|
||||
|
||||
ALTER TABLE if exists "order_item"
|
||||
ADD CONSTRAINT "order_item_order_id_foreign" FOREIGN KEY ("order_id") REFERENCES "order" ("id") ON
|
||||
UPDATE CASCADE ON
|
||||
DELETE CASCADE;
|
||||
|
||||
ALTER TABLE if exists "order_item"
|
||||
ADD CONSTRAINT "order_item_item_id_foreign" FOREIGN KEY ("item_id") REFERENCES "order_line_item" ("id") ON
|
||||
UPDATE CASCADE ON
|
||||
DELETE CASCADE;
|
||||
|
||||
ALTER TABLE if exists "order_line_item"
|
||||
ADD CONSTRAINT "order_line_item_totals_id_foreign" FOREIGN KEY ("totals_id") REFERENCES "order_item" ("id") ON
|
||||
UPDATE CASCADE ON
|
||||
DELETE CASCADE;
|
||||
|
||||
ALTER TABLE if exists "order_line_item_tax_line"
|
||||
ADD CONSTRAINT "order_line_item_tax_line_item_id_foreign" FOREIGN KEY ("item_id") REFERENCES "order_line_item" ("id") ON
|
||||
UPDATE CASCADE ON
|
||||
DELETE CASCADE;
|
||||
|
||||
ALTER TABLE if exists "order_line_item_adjustment"
|
||||
ADD CONSTRAINT "order_line_item_adjustment_item_id_foreign" FOREIGN KEY ("item_id") REFERENCES "order_line_item" ("id") ON
|
||||
UPDATE CASCADE ON
|
||||
DELETE CASCADE;
|
||||
|
||||
ALTER TABLE if exists "order_shipping"
|
||||
ADD CONSTRAINT "order_shipping_order_id_foreign" FOREIGN KEY ("order_id") REFERENCES "order" ("id") ON
|
||||
UPDATE CASCADE ON
|
||||
DELETE CASCADE;
|
||||
|
||||
ALTER TABLE if exists "order_shipping_method_adjustment"
|
||||
ADD CONSTRAINT "order_shipping_method_adjustment_shipping_method_id_foreign" FOREIGN KEY ("shipping_method_id") REFERENCES "order_shipping_method" ("id") ON
|
||||
UPDATE CASCADE ON
|
||||
DELETE CASCADE;
|
||||
|
||||
ALTER TABLE if exists "order_shipping_method_tax_line"
|
||||
ADD CONSTRAINT "order_shipping_method_tax_line_shipping_method_id_foreign" FOREIGN KEY ("shipping_method_id") REFERENCES "order_shipping_method" ("id") ON
|
||||
UPDATE CASCADE ON
|
||||
DELETE CASCADE;
|
||||
|
||||
ALTER TABLE if exists "order_transaction"
|
||||
ADD CONSTRAINT "order_transaction_order_id_foreign" FOREIGN KEY ("order_id") REFERENCES "order" ("id") ON
|
||||
UPDATE CASCADE ON
|
||||
DELETE CASCADE;
|
||||
`
|
||||
|
||||
this.addSql(sql)
|
||||
}
|
||||
}
|
||||
90
packages/modules/order/src/models/address.ts
Normal file
90
packages/modules/order/src/models/address.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import { DAL } from "@medusajs/types"
|
||||
import {
|
||||
createPsqlIndexStatementHelper,
|
||||
generateEntityId,
|
||||
} from "@medusajs/utils"
|
||||
import {
|
||||
BeforeCreate,
|
||||
Entity,
|
||||
OnInit,
|
||||
OptionalProps,
|
||||
PrimaryKey,
|
||||
Property,
|
||||
} from "@mikro-orm/core"
|
||||
|
||||
type OptionalAddressProps = DAL.EntityDateColumns
|
||||
|
||||
const CustomerIdIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order_address",
|
||||
columns: "customer_id",
|
||||
})
|
||||
|
||||
@Entity({ tableName: "order_address" })
|
||||
export default class Address {
|
||||
[OptionalProps]: OptionalAddressProps
|
||||
|
||||
@PrimaryKey({ columnType: "text" })
|
||||
id!: string
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
@CustomerIdIndex.MikroORMIndex()
|
||||
customer_id: string | null = null
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
company: string | null = null
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
first_name: string | null = null
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
last_name: string | null = null
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
address_1: string | null = null
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
address_2: string | null = null
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
city: string | null = null
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
country_code: string | null = null
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
province: string | null = null
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
postal_code: string | null = null
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
phone: string | null = null
|
||||
|
||||
@Property({ columnType: "jsonb", nullable: true })
|
||||
metadata: Record<string, unknown> | null = 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, "ordaddr")
|
||||
}
|
||||
|
||||
@OnInit()
|
||||
onInit() {
|
||||
this.id = generateEntityId(this.id, "ordaddr")
|
||||
}
|
||||
}
|
||||
52
packages/modules/order/src/models/adjustment-line.ts
Normal file
52
packages/modules/order/src/models/adjustment-line.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { BigNumberRawValue, DAL } from "@medusajs/types"
|
||||
import { BigNumber, MikroOrmBigNumberProperty } from "@medusajs/utils"
|
||||
import { OptionalProps, PrimaryKey, Property } from "@mikro-orm/core"
|
||||
|
||||
type OptionalAdjustmentLineProps = DAL.EntityDateColumns
|
||||
|
||||
/**
|
||||
* 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 = null
|
||||
|
||||
@Property({
|
||||
columnType: "text",
|
||||
nullable: true,
|
||||
})
|
||||
promotion_id: string | null = null
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
code: string | null = null
|
||||
|
||||
@MikroOrmBigNumberProperty()
|
||||
amount: BigNumber | number
|
||||
|
||||
@Property({ columnType: "jsonb" })
|
||||
raw_amount: BigNumberRawValue
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
provider_id: string | null = 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
|
||||
}
|
||||
14
packages/modules/order/src/models/index.ts
Normal file
14
packages/modules/order/src/models/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export { default as Address } from "./address"
|
||||
export { default as LineItem } from "./line-item"
|
||||
export { default as LineItemAdjustment } from "./line-item-adjustment"
|
||||
export { default as LineItemTaxLine } from "./line-item-tax-line"
|
||||
export { default as Order } from "./order"
|
||||
export { default as OrderChange } from "./order-change"
|
||||
export { default as OrderChangeAction } from "./order-change-action"
|
||||
export { default as OrderItem } from "./order-item"
|
||||
export { default as OrderShippingMethod } from "./order-shipping-method"
|
||||
export { default as OrderSummary } from "./order-summary"
|
||||
export { default as ShippingMethod } from "./shipping-method"
|
||||
export { default as ShippingMethodAdjustment } from "./shipping-method-adjustment"
|
||||
export { default as ShippingMethodTaxLine } from "./shipping-method-tax-line"
|
||||
export { default as Transaction } from "./transaction"
|
||||
42
packages/modules/order/src/models/line-item-adjustment.ts
Normal file
42
packages/modules/order/src/models/line-item-adjustment.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import {
|
||||
createPsqlIndexStatementHelper,
|
||||
generateEntityId,
|
||||
} from "@medusajs/utils"
|
||||
import { BeforeCreate, Entity, ManyToOne, OnInit } from "@mikro-orm/core"
|
||||
import AdjustmentLine from "./adjustment-line"
|
||||
import LineItem from "./line-item"
|
||||
|
||||
const ItemIdIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order_line_item_adjustment",
|
||||
columns: "item_id",
|
||||
})
|
||||
|
||||
@Entity({ tableName: "order_line_item_adjustment" })
|
||||
export default class LineItemAdjustment extends AdjustmentLine {
|
||||
@ManyToOne(() => LineItem, {
|
||||
persist: false,
|
||||
})
|
||||
item: LineItem
|
||||
|
||||
@ManyToOne({
|
||||
entity: () => LineItem,
|
||||
columnType: "text",
|
||||
fieldName: "item_id",
|
||||
onDelete: "cascade",
|
||||
mapToPk: true,
|
||||
})
|
||||
@ItemIdIndex.MikroORMIndex()
|
||||
item_id: string
|
||||
|
||||
@BeforeCreate()
|
||||
onCreate() {
|
||||
this.id = generateEntityId(this.id, "ordliadj")
|
||||
this.item_id ??= this.item?.id
|
||||
}
|
||||
|
||||
@OnInit()
|
||||
onInit() {
|
||||
this.id = generateEntityId(this.id, "ordliadj")
|
||||
this.item_id ??= this.item?.id
|
||||
}
|
||||
}
|
||||
49
packages/modules/order/src/models/line-item-tax-line.ts
Normal file
49
packages/modules/order/src/models/line-item-tax-line.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import {
|
||||
createPsqlIndexStatementHelper,
|
||||
generateEntityId,
|
||||
} from "@medusajs/utils"
|
||||
import {
|
||||
BeforeCreate,
|
||||
Cascade,
|
||||
Entity,
|
||||
ManyToOne,
|
||||
OnInit,
|
||||
} from "@mikro-orm/core"
|
||||
import LineItem from "./line-item"
|
||||
import TaxLine from "./tax-line"
|
||||
|
||||
const ItemIdIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order_line_item_tax_line",
|
||||
columns: "item_id",
|
||||
})
|
||||
|
||||
@Entity({ tableName: "order_line_item_tax_line" })
|
||||
export default class LineItemTaxLine extends TaxLine {
|
||||
@ManyToOne(() => LineItem, {
|
||||
fieldName: "item_id",
|
||||
persist: false,
|
||||
})
|
||||
item: LineItem
|
||||
|
||||
@ManyToOne({
|
||||
entity: () => LineItem,
|
||||
columnType: "text",
|
||||
fieldName: "item_id",
|
||||
cascade: [Cascade.PERSIST, Cascade.REMOVE],
|
||||
mapToPk: true,
|
||||
})
|
||||
@ItemIdIndex.MikroORMIndex()
|
||||
item_id: string
|
||||
|
||||
@BeforeCreate()
|
||||
onCreate() {
|
||||
this.id = generateEntityId(this.id, "ordlitxl")
|
||||
this.item_id ??= this.item?.id
|
||||
}
|
||||
|
||||
@OnInit()
|
||||
onInit() {
|
||||
this.id = generateEntityId(this.id, "ordlitxl")
|
||||
this.item_id ??= this.item?.id
|
||||
}
|
||||
}
|
||||
161
packages/modules/order/src/models/line-item.ts
Normal file
161
packages/modules/order/src/models/line-item.ts
Normal file
@@ -0,0 +1,161 @@
|
||||
import { BigNumberRawValue, DAL } from "@medusajs/types"
|
||||
import {
|
||||
BigNumber,
|
||||
MikroOrmBigNumberProperty,
|
||||
createPsqlIndexStatementHelper,
|
||||
generateEntityId,
|
||||
} from "@medusajs/utils"
|
||||
import {
|
||||
BeforeCreate,
|
||||
Cascade,
|
||||
Collection,
|
||||
Entity,
|
||||
OnInit,
|
||||
OneToMany,
|
||||
OptionalProps,
|
||||
PrimaryKey,
|
||||
Property,
|
||||
} from "@mikro-orm/core"
|
||||
import LineItemAdjustment from "./line-item-adjustment"
|
||||
import LineItemTaxLine from "./line-item-tax-line"
|
||||
|
||||
type OptionalLineItemProps =
|
||||
| "is_discoutable"
|
||||
| "is_tax_inclusive"
|
||||
| "compare_at_unit_price"
|
||||
| "requires_shipping"
|
||||
| DAL.EntityDateColumns
|
||||
|
||||
const ProductIdIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order_line_item",
|
||||
columns: "product_id",
|
||||
})
|
||||
|
||||
const VariantIdIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order_line_item",
|
||||
columns: "variant_id",
|
||||
})
|
||||
|
||||
@Entity({ tableName: "order_line_item" })
|
||||
export default class LineItem {
|
||||
[OptionalProps]?: OptionalLineItemProps
|
||||
|
||||
@PrimaryKey({ columnType: "text" })
|
||||
id: string
|
||||
|
||||
@Property({ columnType: "text" })
|
||||
title: string
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
subtitle: string | null = null
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
thumbnail: string | null = null
|
||||
|
||||
@Property({
|
||||
columnType: "text",
|
||||
nullable: true,
|
||||
})
|
||||
@VariantIdIndex.MikroORMIndex()
|
||||
variant_id: string | null = null
|
||||
|
||||
@Property({
|
||||
columnType: "text",
|
||||
nullable: true,
|
||||
})
|
||||
@ProductIdIndex.MikroORMIndex()
|
||||
product_id: string | null = null
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
product_title: string | null = null
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
product_description: string | null = null
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
product_subtitle: string | null = null
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
product_type: string | null = null
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
product_collection: string | null = null
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
product_handle: string | null = null
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
variant_sku: string | null = null
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
variant_barcode: string | null = null
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
variant_title: string | null = null
|
||||
|
||||
@Property({ columnType: "jsonb", nullable: true })
|
||||
variant_option_values: Record<string, unknown> | null = null
|
||||
|
||||
@Property({ columnType: "boolean" })
|
||||
requires_shipping = true
|
||||
|
||||
@Property({ columnType: "boolean" })
|
||||
is_discountable = true
|
||||
|
||||
@Property({ columnType: "boolean" })
|
||||
is_tax_inclusive = false
|
||||
|
||||
@MikroOrmBigNumberProperty({
|
||||
nullable: true,
|
||||
})
|
||||
compare_at_unit_price?: BigNumber | number | null = null
|
||||
|
||||
@Property({ columnType: "jsonb", nullable: true })
|
||||
raw_compare_at_unit_price: BigNumberRawValue | null = null
|
||||
|
||||
@MikroOrmBigNumberProperty({
|
||||
nullable: true,
|
||||
})
|
||||
unit_price: BigNumber | number
|
||||
|
||||
@Property({ columnType: "jsonb" })
|
||||
raw_unit_price: BigNumberRawValue
|
||||
|
||||
@OneToMany(() => LineItemTaxLine, (taxLine) => taxLine.item, {
|
||||
cascade: [Cascade.PERSIST, "soft-remove" as Cascade],
|
||||
})
|
||||
tax_lines = new Collection<LineItemTaxLine>(this)
|
||||
|
||||
@OneToMany(() => LineItemAdjustment, (adjustment) => adjustment.item, {
|
||||
cascade: [Cascade.PERSIST, "soft-remove" as Cascade],
|
||||
})
|
||||
adjustments = new Collection<LineItemAdjustment>(this)
|
||||
|
||||
@Property({ columnType: "jsonb", nullable: true })
|
||||
metadata: Record<string, unknown> | null = 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, "ordli")
|
||||
}
|
||||
|
||||
@OnInit()
|
||||
onInit() {
|
||||
this.id = generateEntityId(this.id, "ordli")
|
||||
}
|
||||
}
|
||||
151
packages/modules/order/src/models/order-change-action.ts
Normal file
151
packages/modules/order/src/models/order-change-action.ts
Normal file
@@ -0,0 +1,151 @@
|
||||
import { BigNumberRawValue, DAL } from "@medusajs/types"
|
||||
import {
|
||||
BigNumber,
|
||||
MikroOrmBigNumberProperty,
|
||||
createPsqlIndexStatementHelper,
|
||||
generateEntityId,
|
||||
} from "@medusajs/utils"
|
||||
import {
|
||||
BeforeCreate,
|
||||
Entity,
|
||||
ManyToOne,
|
||||
OnInit,
|
||||
OptionalProps,
|
||||
PrimaryKey,
|
||||
Property,
|
||||
} from "@mikro-orm/core"
|
||||
import Order from "./order"
|
||||
import OrderChange from "./order-change"
|
||||
|
||||
type OptionalLineItemProps = DAL.EntityDateColumns
|
||||
|
||||
const OrderChangeIdIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order_change_action",
|
||||
columns: "order_change_id",
|
||||
})
|
||||
|
||||
const OrderIdIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order_change_action",
|
||||
columns: "order_id",
|
||||
})
|
||||
|
||||
const ActionOrderingIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order_change_action",
|
||||
columns: "ordering",
|
||||
})
|
||||
|
||||
@Entity({ tableName: "order_change_action" })
|
||||
export default class OrderChangeAction {
|
||||
[OptionalProps]?: OptionalLineItemProps
|
||||
|
||||
@PrimaryKey({ columnType: "text" })
|
||||
id: string
|
||||
|
||||
@Property({ columnType: "integer", autoincrement: true })
|
||||
@ActionOrderingIndex.MikroORMIndex()
|
||||
ordering: number
|
||||
|
||||
@ManyToOne({
|
||||
entity: () => Order,
|
||||
columnType: "text",
|
||||
fieldName: "order_id",
|
||||
onDelete: "cascade",
|
||||
mapToPk: true,
|
||||
nullable: true,
|
||||
})
|
||||
@OrderIdIndex.MikroORMIndex()
|
||||
order_id: string | null = null
|
||||
|
||||
@ManyToOne(() => Order, {
|
||||
persist: false,
|
||||
nullable: true,
|
||||
})
|
||||
order: Order | null = null
|
||||
|
||||
@Property({ columnType: "integer", nullable: true })
|
||||
version: number | null = null
|
||||
|
||||
@ManyToOne({
|
||||
entity: () => OrderChange,
|
||||
columnType: "text",
|
||||
fieldName: "order_change_id",
|
||||
onDelete: "cascade",
|
||||
mapToPk: true,
|
||||
nullable: true,
|
||||
})
|
||||
@OrderChangeIdIndex.MikroORMIndex()
|
||||
order_change_id: string | null
|
||||
|
||||
@ManyToOne(() => OrderChange, {
|
||||
persist: false,
|
||||
nullable: true,
|
||||
})
|
||||
order_change: OrderChange | null = null
|
||||
|
||||
@Property({
|
||||
columnType: "text",
|
||||
nullable: true,
|
||||
})
|
||||
reference: string | null = null
|
||||
|
||||
@Property({
|
||||
columnType: "text",
|
||||
nullable: true,
|
||||
})
|
||||
reference_id: string | null = null
|
||||
|
||||
@Property({ columnType: "text" })
|
||||
action: string
|
||||
|
||||
@Property({ columnType: "jsonb" })
|
||||
details: Record<string, unknown> = {}
|
||||
|
||||
@MikroOrmBigNumberProperty({ nullable: true })
|
||||
amount: BigNumber | number | null = null
|
||||
|
||||
@Property({ columnType: "jsonb", nullable: true })
|
||||
raw_amount: BigNumberRawValue | null = null
|
||||
|
||||
@Property({
|
||||
columnType: "text",
|
||||
nullable: true,
|
||||
})
|
||||
internal_note: string | null = null
|
||||
|
||||
@Property({
|
||||
columnType: "boolean",
|
||||
defaultRaw: "false",
|
||||
})
|
||||
applied: boolean = false
|
||||
|
||||
@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, "ordchact")
|
||||
this.order_id ??= this.order?.id ?? this.order_change?.order_id ?? null
|
||||
this.order_change_id ??= this.order_change?.id ?? null
|
||||
this.version ??= this.order_change?.version ?? null
|
||||
}
|
||||
|
||||
@OnInit()
|
||||
onInit() {
|
||||
this.id = generateEntityId(this.id, "ordchact")
|
||||
this.order_id ??= this.order?.id ?? this.order_change?.order_id ?? null
|
||||
this.order_change_id ??= this.order_change?.id ?? null
|
||||
this.version ??= this.order_change?.version ?? null
|
||||
}
|
||||
}
|
||||
156
packages/modules/order/src/models/order-change.ts
Normal file
156
packages/modules/order/src/models/order-change.ts
Normal file
@@ -0,0 +1,156 @@
|
||||
import { DAL } from "@medusajs/types"
|
||||
import {
|
||||
OrderChangeStatus,
|
||||
createPsqlIndexStatementHelper,
|
||||
generateEntityId,
|
||||
} from "@medusajs/utils"
|
||||
import {
|
||||
BeforeCreate,
|
||||
Cascade,
|
||||
Collection,
|
||||
Entity,
|
||||
Enum,
|
||||
ManyToOne,
|
||||
OnInit,
|
||||
OneToMany,
|
||||
OptionalProps,
|
||||
PrimaryKey,
|
||||
Property,
|
||||
} from "@mikro-orm/core"
|
||||
import Order from "./order"
|
||||
import OrderChangeAction from "./order-change-action"
|
||||
|
||||
type OptionalLineItemProps = DAL.EntityDateColumns
|
||||
|
||||
const OrderIdIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order_change",
|
||||
columns: "order_id",
|
||||
})
|
||||
|
||||
const OrderChangeStatusIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order_change",
|
||||
columns: "status",
|
||||
})
|
||||
|
||||
const VersionIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order_change",
|
||||
columns: ["order_id", "version"],
|
||||
})
|
||||
|
||||
@Entity({ tableName: "order_change" })
|
||||
@VersionIndex.MikroORMIndex()
|
||||
export default class OrderChange {
|
||||
[OptionalProps]?: OptionalLineItemProps
|
||||
|
||||
@PrimaryKey({ columnType: "text" })
|
||||
id: string
|
||||
|
||||
@ManyToOne({
|
||||
entity: () => Order,
|
||||
columnType: "text",
|
||||
fieldName: "order_id",
|
||||
onDelete: "cascade",
|
||||
mapToPk: true,
|
||||
})
|
||||
@OrderIdIndex.MikroORMIndex()
|
||||
order_id: string
|
||||
|
||||
@ManyToOne(() => Order, {
|
||||
persist: false,
|
||||
})
|
||||
order: Order
|
||||
|
||||
@Property({ columnType: "integer" })
|
||||
@VersionIndex.MikroORMIndex()
|
||||
version: number
|
||||
|
||||
@OneToMany(() => OrderChangeAction, (action) => action.order_change, {
|
||||
cascade: [Cascade.PERSIST, "sotf-remove" as Cascade],
|
||||
})
|
||||
actions = new Collection<OrderChangeAction>(this)
|
||||
|
||||
@Property({
|
||||
columnType: "text",
|
||||
nullable: true,
|
||||
})
|
||||
description: string | null = null
|
||||
|
||||
@Enum({ items: () => OrderChangeStatus, default: OrderChangeStatus.PENDING })
|
||||
@OrderChangeStatusIndex.MikroORMIndex()
|
||||
status: OrderChangeStatus = OrderChangeStatus.PENDING
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
internal_note: string | null = null
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
created_by: string // customer, user, third party, etc.
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
requested_by: string | null = null // customer or user ID
|
||||
|
||||
@Property({
|
||||
columnType: "timestamptz",
|
||||
nullable: true,
|
||||
})
|
||||
requested_at: Date | null = null
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
confirmed_by: string | null = null // customer or user ID
|
||||
|
||||
@Property({
|
||||
columnType: "timestamptz",
|
||||
nullable: true,
|
||||
})
|
||||
confirmed_at: Date | null = null
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
declined_by: string | null = null // customer or user ID
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
declined_reason: string | null = null
|
||||
|
||||
@Property({ columnType: "jsonb", nullable: true })
|
||||
metadata: Record<string, unknown> | null = null
|
||||
|
||||
@Property({
|
||||
columnType: "timestamptz",
|
||||
nullable: true,
|
||||
})
|
||||
declined_at?: Date
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
canceled_by: string | null = null
|
||||
|
||||
@Property({
|
||||
columnType: "timestamptz",
|
||||
nullable: true,
|
||||
})
|
||||
canceled_at?: Date
|
||||
|
||||
@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, "ordch")
|
||||
this.order_id ??= this.order?.id
|
||||
}
|
||||
|
||||
@OnInit()
|
||||
onInit() {
|
||||
this.id = generateEntityId(this.id, "ordch")
|
||||
this.order_id ??= this.order?.id
|
||||
}
|
||||
}
|
||||
164
packages/modules/order/src/models/order-item.ts
Normal file
164
packages/modules/order/src/models/order-item.ts
Normal file
@@ -0,0 +1,164 @@
|
||||
import { BigNumberRawValue, DAL } from "@medusajs/types"
|
||||
import {
|
||||
BigNumber,
|
||||
MikroOrmBigNumberProperty,
|
||||
createPsqlIndexStatementHelper,
|
||||
generateEntityId,
|
||||
} from "@medusajs/utils"
|
||||
import {
|
||||
BeforeCreate,
|
||||
Entity,
|
||||
ManyToOne,
|
||||
OnInit,
|
||||
OptionalProps,
|
||||
PrimaryKey,
|
||||
Property,
|
||||
} from "@mikro-orm/core"
|
||||
import LineItem from "./line-item"
|
||||
import Order from "./order"
|
||||
|
||||
type OptionalLineItemProps = DAL.EntityDateColumns
|
||||
|
||||
const OrderIdIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order_item",
|
||||
columns: ["order_id"],
|
||||
where: "deleted_at IS NOT NULL",
|
||||
})
|
||||
|
||||
const OrderVersionIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order_item",
|
||||
columns: ["version"],
|
||||
where: "deleted_at IS NOT NULL",
|
||||
})
|
||||
|
||||
const ItemIdIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order_item",
|
||||
columns: ["item_id"],
|
||||
where: "deleted_at IS NOT NULL",
|
||||
})
|
||||
|
||||
const DeletedAtIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order",
|
||||
columns: "deleted_at",
|
||||
where: "deleted_at IS NOT NULL",
|
||||
})
|
||||
|
||||
@Entity({ tableName: "order_item" })
|
||||
export default class OrderItem {
|
||||
[OptionalProps]?: OptionalLineItemProps
|
||||
|
||||
@PrimaryKey({ columnType: "text" })
|
||||
id: string
|
||||
|
||||
@ManyToOne({
|
||||
entity: () => Order,
|
||||
mapToPk: true,
|
||||
fieldName: "order_id",
|
||||
columnType: "text",
|
||||
})
|
||||
@OrderIdIndex.MikroORMIndex()
|
||||
order_id: string
|
||||
|
||||
@Property({ columnType: "integer" })
|
||||
@OrderVersionIndex.MikroORMIndex()
|
||||
version: number
|
||||
|
||||
@ManyToOne(() => Order, {
|
||||
persist: false,
|
||||
})
|
||||
order: Order
|
||||
|
||||
@ManyToOne({
|
||||
entity: () => LineItem,
|
||||
fieldName: "item_id",
|
||||
mapToPk: true,
|
||||
columnType: "text",
|
||||
})
|
||||
@ItemIdIndex.MikroORMIndex()
|
||||
item_id: string
|
||||
|
||||
@ManyToOne(() => LineItem, {
|
||||
persist: false,
|
||||
})
|
||||
item: LineItem
|
||||
|
||||
@MikroOrmBigNumberProperty()
|
||||
quantity: BigNumber | number
|
||||
|
||||
@Property({ columnType: "jsonb" })
|
||||
raw_quantity: BigNumberRawValue
|
||||
|
||||
@MikroOrmBigNumberProperty()
|
||||
fulfilled_quantity: BigNumber | number = 0
|
||||
|
||||
@Property({ columnType: "jsonb" })
|
||||
raw_fulfilled_quantity: BigNumberRawValue
|
||||
|
||||
@MikroOrmBigNumberProperty()
|
||||
shipped_quantity: BigNumber | number = 0
|
||||
|
||||
@Property({ columnType: "jsonb" })
|
||||
raw_shipped_quantity: BigNumberRawValue
|
||||
|
||||
@MikroOrmBigNumberProperty()
|
||||
return_requested_quantity: BigNumber | number = 0
|
||||
|
||||
@Property({ columnType: "jsonb" })
|
||||
raw_return_requested_quantity: BigNumberRawValue
|
||||
|
||||
@MikroOrmBigNumberProperty()
|
||||
return_received_quantity: BigNumber | number = 0
|
||||
|
||||
@Property({ columnType: "jsonb" })
|
||||
raw_return_received_quantity: BigNumberRawValue
|
||||
|
||||
@MikroOrmBigNumberProperty()
|
||||
return_dismissed_quantity: BigNumber | number = 0
|
||||
|
||||
@Property({ columnType: "jsonb" })
|
||||
raw_return_dismissed_quantity: BigNumberRawValue
|
||||
|
||||
@MikroOrmBigNumberProperty()
|
||||
written_off_quantity: BigNumber | number = 0
|
||||
|
||||
@Property({ columnType: "jsonb" })
|
||||
raw_written_off_quantity: BigNumberRawValue
|
||||
|
||||
@Property({ columnType: "jsonb", nullable: true })
|
||||
metadata: Record<string, unknown> | null = 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
|
||||
|
||||
@Property({ columnType: "timestamptz", nullable: true })
|
||||
@DeletedAtIndex.MikroORMIndex()
|
||||
deleted_at: Date | null = null
|
||||
|
||||
@BeforeCreate()
|
||||
onCreate() {
|
||||
this.id = generateEntityId(this.id, "orditem")
|
||||
this.order_id ??= this.order?.id
|
||||
this.item_id ??= this.item?.id
|
||||
this.version ??= this.order?.version
|
||||
}
|
||||
|
||||
@OnInit()
|
||||
onInit() {
|
||||
this.id = generateEntityId(this.id, "orditem")
|
||||
this.order_id ??= this.order?.id
|
||||
this.item_id ??= this.item?.id
|
||||
this.version ??= this.order?.version
|
||||
}
|
||||
}
|
||||
117
packages/modules/order/src/models/order-shipping-method.ts
Normal file
117
packages/modules/order/src/models/order-shipping-method.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
import { DAL } from "@medusajs/types"
|
||||
import {
|
||||
createPsqlIndexStatementHelper,
|
||||
generateEntityId,
|
||||
} from "@medusajs/utils"
|
||||
import {
|
||||
BeforeCreate,
|
||||
Entity,
|
||||
ManyToOne,
|
||||
OnInit,
|
||||
OptionalProps,
|
||||
PrimaryKey,
|
||||
Property,
|
||||
} from "@mikro-orm/core"
|
||||
import Order from "./order"
|
||||
import ShippingMethod from "./shipping-method"
|
||||
|
||||
type OptionalShippingMethodProps = DAL.EntityDateColumns
|
||||
|
||||
const OrderIdIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order_shipping",
|
||||
columns: ["order_id"],
|
||||
where: "deleted_at IS NOT NULL",
|
||||
})
|
||||
|
||||
const OrderVersionIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order_shipping",
|
||||
columns: ["version"],
|
||||
where: "deleted_at IS NOT NULL",
|
||||
})
|
||||
|
||||
const ItemIdIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order_shipping",
|
||||
columns: ["shipping_method_id"],
|
||||
where: "deleted_at IS NOT NULL",
|
||||
})
|
||||
|
||||
const DeletedAtIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order",
|
||||
columns: "deleted_at",
|
||||
where: "deleted_at IS NOT NULL",
|
||||
})
|
||||
|
||||
@Entity({ tableName: "order_shipping" })
|
||||
export default class OrderShippingMethod {
|
||||
[OptionalProps]?: OptionalShippingMethodProps
|
||||
|
||||
@PrimaryKey({ columnType: "text" })
|
||||
id: string
|
||||
|
||||
@ManyToOne({
|
||||
entity: () => Order,
|
||||
mapToPk: true,
|
||||
fieldName: "order_id",
|
||||
columnType: "text",
|
||||
})
|
||||
@OrderIdIndex.MikroORMIndex()
|
||||
order_id: string
|
||||
|
||||
@Property({ columnType: "integer" })
|
||||
@OrderVersionIndex.MikroORMIndex()
|
||||
version: number
|
||||
|
||||
@ManyToOne(() => Order, {
|
||||
persist: false,
|
||||
})
|
||||
order: Order
|
||||
|
||||
@ManyToOne({
|
||||
entity: () => ShippingMethod,
|
||||
fieldName: "shipping_method_id",
|
||||
mapToPk: true,
|
||||
columnType: "text",
|
||||
})
|
||||
@ItemIdIndex.MikroORMIndex()
|
||||
shipping_method_id: string
|
||||
|
||||
@ManyToOne(() => ShippingMethod, {
|
||||
persist: false,
|
||||
})
|
||||
shipping_method: ShippingMethod
|
||||
|
||||
@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
|
||||
|
||||
@Property({ columnType: "timestamptz", nullable: true })
|
||||
@DeletedAtIndex.MikroORMIndex()
|
||||
deleted_at: Date | null = null
|
||||
|
||||
@BeforeCreate()
|
||||
onCreate() {
|
||||
this.id = generateEntityId(this.id, "ordspmv")
|
||||
this.order_id ??= this.order?.id
|
||||
this.shipping_method_id ??= this.shipping_method?.id
|
||||
this.version ??= this.order?.version
|
||||
}
|
||||
|
||||
@OnInit()
|
||||
onInit() {
|
||||
this.id = generateEntityId(this.id, "ordspmv")
|
||||
this.order_id ??= this.order?.id
|
||||
this.shipping_method_id ??= this.shipping_method?.id
|
||||
this.version ??= this.order?.version
|
||||
}
|
||||
}
|
||||
112
packages/modules/order/src/models/order-summary.ts
Normal file
112
packages/modules/order/src/models/order-summary.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
import {
|
||||
BigNumber,
|
||||
createPsqlIndexStatementHelper,
|
||||
generateEntityId,
|
||||
} from "@medusajs/utils"
|
||||
import {
|
||||
BeforeCreate,
|
||||
Entity,
|
||||
ManyToOne,
|
||||
OnInit,
|
||||
PrimaryKey,
|
||||
Property,
|
||||
} from "@mikro-orm/core"
|
||||
import { Order } from "@models"
|
||||
|
||||
type OrderSummaryTotals = {
|
||||
total: BigNumber
|
||||
subtotal: BigNumber
|
||||
total_tax: BigNumber
|
||||
|
||||
ordered_total: BigNumber
|
||||
fulfilled_total: BigNumber
|
||||
returned_total: BigNumber
|
||||
return_request_total: BigNumber
|
||||
write_off_total: BigNumber
|
||||
projected_total: BigNumber
|
||||
|
||||
net_total: BigNumber
|
||||
net_subtotal: BigNumber
|
||||
net_total_tax: BigNumber
|
||||
|
||||
future_total: BigNumber
|
||||
future_subtotal: BigNumber
|
||||
future_total_tax: BigNumber
|
||||
future_projected_total: BigNumber
|
||||
|
||||
balance: BigNumber
|
||||
future_balance: BigNumber
|
||||
}
|
||||
|
||||
const OrderIdVersionIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order_summary",
|
||||
columns: ["order_id", "version"],
|
||||
where: "deleted_at IS NOT NULL",
|
||||
})
|
||||
|
||||
const DeletedAtIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order",
|
||||
columns: "deleted_at",
|
||||
where: "deleted_at IS NOT NULL",
|
||||
})
|
||||
|
||||
@Entity({ tableName: "order_summary" })
|
||||
@OrderIdVersionIndex.MikroORMIndex()
|
||||
export default class OrderSummary {
|
||||
@PrimaryKey({ columnType: "text" })
|
||||
id: string
|
||||
|
||||
@ManyToOne({
|
||||
entity: () => Order,
|
||||
columnType: "text",
|
||||
fieldName: "order_id",
|
||||
mapToPk: true,
|
||||
onDelete: "cascade",
|
||||
})
|
||||
order_id: string
|
||||
|
||||
@ManyToOne(() => Order, {
|
||||
persist: false,
|
||||
})
|
||||
order: Order
|
||||
|
||||
@Property({
|
||||
columnType: "integer",
|
||||
defaultRaw: "1",
|
||||
})
|
||||
version: number = 1
|
||||
|
||||
@Property({ columnType: "jsonb" })
|
||||
totals: OrderSummaryTotals | null = {} as OrderSummaryTotals
|
||||
|
||||
@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
|
||||
|
||||
@Property({ columnType: "timestamptz", nullable: true })
|
||||
@DeletedAtIndex.MikroORMIndex()
|
||||
deleted_at: Date | null = null
|
||||
|
||||
@BeforeCreate()
|
||||
onCreate() {
|
||||
this.id = generateEntityId(this.id, "ordsum")
|
||||
this.order_id ??= this.order?.id
|
||||
}
|
||||
|
||||
@OnInit()
|
||||
onInit() {
|
||||
this.id = generateEntityId(this.id, "ordsum")
|
||||
this.order_id ??= this.order?.id
|
||||
}
|
||||
}
|
||||
214
packages/modules/order/src/models/order.ts
Normal file
214
packages/modules/order/src/models/order.ts
Normal file
@@ -0,0 +1,214 @@
|
||||
import { DAL } from "@medusajs/types"
|
||||
import {
|
||||
OrderStatus,
|
||||
createPsqlIndexStatementHelper,
|
||||
generateEntityId,
|
||||
} from "@medusajs/utils"
|
||||
import {
|
||||
BeforeCreate,
|
||||
Cascade,
|
||||
Collection,
|
||||
Entity,
|
||||
Enum,
|
||||
ManyToOne,
|
||||
OnInit,
|
||||
OneToMany,
|
||||
OptionalProps,
|
||||
PrimaryKey,
|
||||
Property,
|
||||
} from "@mikro-orm/core"
|
||||
import Address from "./address"
|
||||
import OrderItem from "./order-item"
|
||||
import OrderShippingMethod from "./order-shipping-method"
|
||||
import OrderSummary from "./order-summary"
|
||||
import Transaction from "./transaction"
|
||||
|
||||
type OptionalOrderProps =
|
||||
| "shipping_address"
|
||||
| "billing_address"
|
||||
| DAL.EntityDateColumns
|
||||
|
||||
const RegionIdIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order",
|
||||
columns: "region_id",
|
||||
where: "deleted_at IS NOT NULL",
|
||||
})
|
||||
|
||||
const CustomerIdIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order",
|
||||
columns: "customer_id",
|
||||
where: "deleted_at IS NOT NULL",
|
||||
})
|
||||
|
||||
const SalesChannelIdIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order",
|
||||
columns: "customer_id",
|
||||
where: "deleted_at IS NOT NULL",
|
||||
})
|
||||
|
||||
const OrderDeletedAtIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order",
|
||||
columns: "deleted_at",
|
||||
where: "deleted_at IS NOT NULL",
|
||||
})
|
||||
|
||||
const CurrencyCodeIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order",
|
||||
columns: "currency_code",
|
||||
where: "deleted_at IS NOT NULL",
|
||||
})
|
||||
|
||||
const ShippingAddressIdIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order",
|
||||
columns: "shipping_address_id",
|
||||
where: "deleted_at IS NOT NULL",
|
||||
})
|
||||
|
||||
const BillingAddressIdIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order",
|
||||
columns: "billing_address_id",
|
||||
where: "deleted_at IS NOT NULL",
|
||||
})
|
||||
|
||||
const IsDraftOrderIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order",
|
||||
columns: "is_draft_order",
|
||||
where: "deleted_at IS NOT NULL",
|
||||
})
|
||||
|
||||
@Entity({ tableName: "order" })
|
||||
export default class Order {
|
||||
[OptionalProps]?: OptionalOrderProps
|
||||
|
||||
@PrimaryKey({ columnType: "text" })
|
||||
id: string
|
||||
|
||||
@Property({
|
||||
columnType: "text",
|
||||
nullable: true,
|
||||
})
|
||||
@RegionIdIndex.MikroORMIndex()
|
||||
region_id: string | null = null
|
||||
|
||||
@Property({
|
||||
columnType: "text",
|
||||
nullable: true,
|
||||
})
|
||||
@CustomerIdIndex.MikroORMIndex()
|
||||
customer_id: string | null = null
|
||||
|
||||
@Property({
|
||||
columnType: "integer",
|
||||
defaultRaw: "1",
|
||||
})
|
||||
version: number = 1
|
||||
|
||||
@Property({
|
||||
columnType: "text",
|
||||
nullable: true,
|
||||
})
|
||||
@SalesChannelIdIndex.MikroORMIndex()
|
||||
sales_channel_id: string | null = null
|
||||
|
||||
@Enum({ items: () => OrderStatus, default: OrderStatus.PENDING })
|
||||
status: OrderStatus
|
||||
|
||||
@Property({
|
||||
columnType: "boolean",
|
||||
})
|
||||
@IsDraftOrderIndex.MikroORMIndex()
|
||||
is_draft_order = false
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
email: string | null = null
|
||||
|
||||
@Property({ columnType: "text" })
|
||||
@CurrencyCodeIndex.MikroORMIndex()
|
||||
currency_code: string
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
@ShippingAddressIdIndex.MikroORMIndex()
|
||||
shipping_address_id?: string | null
|
||||
|
||||
@ManyToOne({
|
||||
entity: () => Address,
|
||||
fieldName: "shipping_address_id",
|
||||
nullable: true,
|
||||
cascade: [Cascade.PERSIST],
|
||||
})
|
||||
shipping_address?: Address | null
|
||||
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
@BillingAddressIdIndex.MikroORMIndex()
|
||||
billing_address_id?: string | null
|
||||
|
||||
@ManyToOne({
|
||||
entity: () => Address,
|
||||
fieldName: "billing_address_id",
|
||||
nullable: true,
|
||||
cascade: [Cascade.PERSIST],
|
||||
})
|
||||
billing_address?: Address | null
|
||||
|
||||
@Property({ columnType: "boolean", nullable: true })
|
||||
no_notification: boolean | null = null
|
||||
|
||||
@OneToMany(() => OrderSummary, (summary) => summary.order, {
|
||||
cascade: [Cascade.PERSIST],
|
||||
})
|
||||
summary = new Collection<OrderSummary>(this)
|
||||
|
||||
@Property({ columnType: "jsonb", nullable: true })
|
||||
metadata: Record<string, unknown> | null = null
|
||||
|
||||
@OneToMany(() => OrderItem, (itemDetail) => itemDetail.order, {
|
||||
cascade: [Cascade.PERSIST],
|
||||
})
|
||||
items = new Collection<OrderItem>(this)
|
||||
|
||||
@OneToMany(
|
||||
() => OrderShippingMethod,
|
||||
(shippingMethod) => shippingMethod.order,
|
||||
{
|
||||
cascade: [Cascade.PERSIST],
|
||||
}
|
||||
)
|
||||
shipping_methods = new Collection<OrderShippingMethod>(this)
|
||||
|
||||
@OneToMany(() => Transaction, (transaction) => transaction.order, {
|
||||
cascade: [Cascade.PERSIST],
|
||||
})
|
||||
transactions = new Collection<Transaction>(this)
|
||||
|
||||
@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
|
||||
|
||||
@Property({ columnType: "timestamptz", nullable: true })
|
||||
@OrderDeletedAtIndex.MikroORMIndex()
|
||||
deleted_at: Date | null = null
|
||||
|
||||
@Property({ columnType: "timestamptz", nullable: true })
|
||||
canceled_at: Date | null = null
|
||||
|
||||
@BeforeCreate()
|
||||
onCreate() {
|
||||
this.id = generateEntityId(this.id, "order")
|
||||
}
|
||||
|
||||
@OnInit()
|
||||
onInit() {
|
||||
this.id = generateEntityId(this.id, "order")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import {
|
||||
createPsqlIndexStatementHelper,
|
||||
generateEntityId,
|
||||
} from "@medusajs/utils"
|
||||
import { BeforeCreate, Entity, ManyToOne, OnInit } from "@mikro-orm/core"
|
||||
import AdjustmentLine from "./adjustment-line"
|
||||
import ShippingMethod from "./shipping-method"
|
||||
|
||||
const ShippingMethodIdIdIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order_shipping_method_adjustment",
|
||||
columns: "shipping_method_id",
|
||||
})
|
||||
|
||||
@Entity({ tableName: "order_shipping_method_adjustment" })
|
||||
export default class ShippingMethodAdjustment extends AdjustmentLine {
|
||||
@ManyToOne(() => ShippingMethod, {
|
||||
persist: false,
|
||||
})
|
||||
shipping_method: ShippingMethod
|
||||
|
||||
@ManyToOne({
|
||||
entity: () => ShippingMethod,
|
||||
columnType: "text",
|
||||
fieldName: "shipping_method_id",
|
||||
mapToPk: true,
|
||||
onDelete: "cascade",
|
||||
})
|
||||
@ShippingMethodIdIdIndex.MikroORMIndex()
|
||||
shipping_method_id: string
|
||||
|
||||
@BeforeCreate()
|
||||
onCreate() {
|
||||
this.id = generateEntityId(this.id, "ordsmadj")
|
||||
this.shipping_method_id ??= this.shipping_method?.id
|
||||
}
|
||||
|
||||
@OnInit()
|
||||
onInit() {
|
||||
this.id = generateEntityId(this.id, "ordsmadj")
|
||||
this.shipping_method_id ??= this.shipping_method?.id
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import {
|
||||
createPsqlIndexStatementHelper,
|
||||
generateEntityId,
|
||||
} from "@medusajs/utils"
|
||||
import { BeforeCreate, Entity, ManyToOne, OnInit } from "@mikro-orm/core"
|
||||
import ShippingMethod from "./shipping-method"
|
||||
import TaxLine from "./tax-line"
|
||||
|
||||
const ShippingMethodIdIdIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order_shipping_method_tax_line",
|
||||
columns: "shipping_method_id",
|
||||
})
|
||||
|
||||
@Entity({ tableName: "order_shipping_method_tax_line" })
|
||||
export default class ShippingMethodTaxLine extends TaxLine {
|
||||
@ManyToOne(() => ShippingMethod, {
|
||||
persist: false,
|
||||
})
|
||||
shipping_method: ShippingMethod
|
||||
|
||||
@ManyToOne({
|
||||
entity: () => ShippingMethod,
|
||||
fieldName: "shipping_method_id",
|
||||
columnType: "text",
|
||||
mapToPk: true,
|
||||
onDelete: "cascade",
|
||||
})
|
||||
@ShippingMethodIdIdIndex.MikroORMIndex()
|
||||
shipping_method_id: string
|
||||
|
||||
@BeforeCreate()
|
||||
onCreate() {
|
||||
this.id = generateEntityId(this.id, "ordsmtxl")
|
||||
this.shipping_method_id ??= this.shipping_method?.id
|
||||
}
|
||||
|
||||
@OnInit()
|
||||
onInit() {
|
||||
this.id = generateEntityId(this.id, "ordsmtxl")
|
||||
this.shipping_method_id ??= this.shipping_method?.id
|
||||
}
|
||||
}
|
||||
100
packages/modules/order/src/models/shipping-method.ts
Normal file
100
packages/modules/order/src/models/shipping-method.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import { BigNumberRawValue } from "@medusajs/types"
|
||||
import {
|
||||
BigNumber,
|
||||
createPsqlIndexStatementHelper,
|
||||
generateEntityId,
|
||||
MikroOrmBigNumberProperty,
|
||||
} from "@medusajs/utils"
|
||||
import {
|
||||
BeforeCreate,
|
||||
Cascade,
|
||||
Collection,
|
||||
Entity,
|
||||
OneToMany,
|
||||
OnInit,
|
||||
PrimaryKey,
|
||||
Property,
|
||||
} from "@mikro-orm/core"
|
||||
import ShippingMethodAdjustment from "./shipping-method-adjustment"
|
||||
import ShippingMethodTaxLine from "./shipping-method-tax-line"
|
||||
|
||||
const ShippingOptionIdIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order_shipping_method",
|
||||
columns: "shipping_option_id",
|
||||
})
|
||||
|
||||
@Entity({ tableName: "order_shipping_method" })
|
||||
export default class ShippingMethod {
|
||||
@PrimaryKey({ columnType: "text" })
|
||||
id: string
|
||||
|
||||
@Property({ columnType: "text" })
|
||||
name: string
|
||||
|
||||
@Property({ columnType: "jsonb", nullable: true })
|
||||
description: string | null = null
|
||||
|
||||
@MikroOrmBigNumberProperty()
|
||||
amount: BigNumber | number
|
||||
|
||||
@Property({ columnType: "jsonb" })
|
||||
raw_amount: BigNumberRawValue
|
||||
|
||||
@Property({ columnType: "boolean" })
|
||||
is_tax_inclusive = false
|
||||
|
||||
@Property({
|
||||
columnType: "text",
|
||||
nullable: true,
|
||||
})
|
||||
@ShippingOptionIdIndex.MikroORMIndex()
|
||||
shipping_option_id: string | null = null
|
||||
|
||||
@Property({ columnType: "jsonb", nullable: true })
|
||||
data: Record<string, unknown> | null = null
|
||||
|
||||
@Property({ columnType: "jsonb", nullable: true })
|
||||
metadata: Record<string, unknown> | null = null
|
||||
|
||||
@OneToMany(
|
||||
() => ShippingMethodTaxLine,
|
||||
(taxLine) => taxLine.shipping_method,
|
||||
{
|
||||
cascade: [Cascade.PERSIST],
|
||||
}
|
||||
)
|
||||
tax_lines = new Collection<ShippingMethodTaxLine>(this)
|
||||
|
||||
@OneToMany(
|
||||
() => ShippingMethodAdjustment,
|
||||
(adjustment) => adjustment.shipping_method,
|
||||
{
|
||||
cascade: [Cascade.PERSIST],
|
||||
}
|
||||
)
|
||||
adjustments = new Collection<ShippingMethodAdjustment>(this)
|
||||
|
||||
@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, "ordsm")
|
||||
}
|
||||
@OnInit()
|
||||
onInit() {
|
||||
this.id = generateEntityId(this.id, "ordsm")
|
||||
}
|
||||
}
|
||||
48
packages/modules/order/src/models/tax-line.ts
Normal file
48
packages/modules/order/src/models/tax-line.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { BigNumberRawValue } from "@medusajs/types"
|
||||
import {BigNumber, MikroOrmBigNumberProperty} from "@medusajs/utils"
|
||||
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
|
||||
|
||||
@MikroOrmBigNumberProperty()
|
||||
rate: BigNumber | number
|
||||
|
||||
@Property({ columnType: "jsonb" })
|
||||
raw_rate: BigNumberRawValue
|
||||
|
||||
@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
|
||||
}
|
||||
107
packages/modules/order/src/models/transaction.ts
Normal file
107
packages/modules/order/src/models/transaction.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
import { BigNumberRawValue, DAL } from "@medusajs/types"
|
||||
import {
|
||||
BigNumber,
|
||||
MikroOrmBigNumberProperty,
|
||||
createPsqlIndexStatementHelper,
|
||||
generateEntityId,
|
||||
} from "@medusajs/utils"
|
||||
import {
|
||||
BeforeCreate,
|
||||
Entity,
|
||||
ManyToOne,
|
||||
OnInit,
|
||||
OptionalProps,
|
||||
PrimaryKey,
|
||||
Property,
|
||||
} from "@mikro-orm/core"
|
||||
import Order from "./order"
|
||||
|
||||
type OptionalLineItemProps = DAL.EntityDateColumns
|
||||
|
||||
const ReferenceIdIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order_transaction",
|
||||
columns: "reference_id",
|
||||
})
|
||||
|
||||
const OrderIdIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order_transaction",
|
||||
columns: "order_id",
|
||||
})
|
||||
|
||||
const CurrencyCodeIndex = createPsqlIndexStatementHelper({
|
||||
tableName: "order_transaction",
|
||||
columns: "currency_code",
|
||||
})
|
||||
|
||||
@Entity({ tableName: "order_transaction" })
|
||||
export default class Transaction {
|
||||
[OptionalProps]?: OptionalLineItemProps
|
||||
|
||||
@PrimaryKey({ columnType: "text" })
|
||||
id: string
|
||||
|
||||
@ManyToOne({
|
||||
entity: () => Order,
|
||||
columnType: "text",
|
||||
fieldName: "order_id",
|
||||
onDelete: "cascade",
|
||||
mapToPk: true,
|
||||
})
|
||||
@OrderIdIndex.MikroORMIndex()
|
||||
order_id: string
|
||||
|
||||
@ManyToOne(() => Order, {
|
||||
persist: false,
|
||||
})
|
||||
order: Order
|
||||
|
||||
@MikroOrmBigNumberProperty()
|
||||
amount: BigNumber | number
|
||||
|
||||
@Property({ columnType: "jsonb" })
|
||||
raw_amount: BigNumberRawValue
|
||||
|
||||
@Property({ columnType: "text" })
|
||||
@CurrencyCodeIndex.MikroORMIndex()
|
||||
currency_code: string
|
||||
|
||||
@Property({
|
||||
columnType: "text",
|
||||
nullable: true,
|
||||
})
|
||||
reference: string | null = null
|
||||
|
||||
@Property({
|
||||
columnType: "text",
|
||||
nullable: true,
|
||||
})
|
||||
@ReferenceIdIndex.MikroORMIndex()
|
||||
reference_id: string | null = 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, "ordtrx")
|
||||
this.order_id ??= this.order?.id
|
||||
}
|
||||
|
||||
@OnInit()
|
||||
onInit() {
|
||||
this.id = generateEntityId(this.id, "ordtrx")
|
||||
this.order_id ??= this.order?.id
|
||||
}
|
||||
}
|
||||
44
packages/modules/order/src/module-definition.ts
Normal file
44
packages/modules/order/src/module-definition.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { Modules } from "@medusajs/modules-sdk"
|
||||
import { ModuleExports } from "@medusajs/types"
|
||||
import { ModulesSdkUtils } from "@medusajs/utils"
|
||||
import * as Models from "@models"
|
||||
import * as ModuleModels from "@models"
|
||||
import * as ModuleRepositories from "@repositories"
|
||||
import * as ModuleServices from "@services"
|
||||
import { OrderModuleService } from "@services"
|
||||
|
||||
const migrationScriptOptions = {
|
||||
moduleName: Modules.ORDER,
|
||||
models: Models,
|
||||
pathToMigrations: __dirname + "/migrations",
|
||||
}
|
||||
|
||||
const runMigrations = ModulesSdkUtils.buildMigrationScript(
|
||||
migrationScriptOptions
|
||||
)
|
||||
|
||||
const revertMigration = ModulesSdkUtils.buildRevertMigrationScript(
|
||||
migrationScriptOptions
|
||||
)
|
||||
|
||||
const containerLoader = ModulesSdkUtils.moduleContainerLoaderFactory({
|
||||
moduleModels: ModuleModels,
|
||||
moduleRepositories: ModuleRepositories,
|
||||
moduleServices: ModuleServices,
|
||||
})
|
||||
|
||||
const connectionLoader = ModulesSdkUtils.mikroOrmConnectionLoaderFactory({
|
||||
moduleName: Modules.ORDER,
|
||||
moduleModels: Object.values(Models),
|
||||
migrationsPath: __dirname + "/migrations",
|
||||
})
|
||||
|
||||
const service = OrderModuleService
|
||||
const loaders = [containerLoader, connectionLoader] as any
|
||||
|
||||
export const moduleDefinition: ModuleExports = {
|
||||
service,
|
||||
loaders,
|
||||
revertMigration,
|
||||
runMigrations,
|
||||
}
|
||||
2
packages/modules/order/src/repositories/index.ts
Normal file
2
packages/modules/order/src/repositories/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export { MikroOrmBaseRepository as BaseRepository } from "@medusajs/utils"
|
||||
export * from "./order"
|
||||
121
packages/modules/order/src/repositories/order.ts
Normal file
121
packages/modules/order/src/repositories/order.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
import { Context, DAL } from "@medusajs/types"
|
||||
import { DALUtils } from "@medusajs/utils"
|
||||
import { LoadStrategy } from "@mikro-orm/core"
|
||||
import { EntityManager } from "@mikro-orm/postgresql"
|
||||
import { Order } from "@models"
|
||||
import { mapRepositoryToOrderModel } from "../utils/transform-order"
|
||||
|
||||
export class OrderRepository extends DALUtils.mikroOrmBaseRepositoryFactory<Order>(
|
||||
Order
|
||||
) {
|
||||
async find(
|
||||
options?: DAL.FindOptions<Order>,
|
||||
context?: Context
|
||||
): Promise<Order[]> {
|
||||
const manager = this.getActiveManager<EntityManager>(context)
|
||||
const knex = manager.getKnex()
|
||||
|
||||
const findOptions_ = { ...options } as any
|
||||
findOptions_.options ??= {}
|
||||
findOptions_.where ??= {}
|
||||
|
||||
if (!("strategy" in findOptions_.options)) {
|
||||
if (findOptions_.options.limit != null || findOptions_.options.offset) {
|
||||
Object.assign(findOptions_.options, {
|
||||
strategy: LoadStrategy.SELECT_IN,
|
||||
})
|
||||
} else {
|
||||
Object.assign(findOptions_.options, {
|
||||
strategy: LoadStrategy.JOINED,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const config = mapRepositoryToOrderModel(findOptions_)
|
||||
|
||||
let defaultVersion = knex.raw(`"o0"."version"`)
|
||||
const strategy = config.options.strategy ?? LoadStrategy.JOINED
|
||||
if (strategy === LoadStrategy.SELECT_IN) {
|
||||
const sql = manager
|
||||
.qb(Order, "_sub0")
|
||||
.select("version")
|
||||
.where({ id: knex.raw(`"o0"."order_id"`) })
|
||||
.getKnexQuery()
|
||||
.toString()
|
||||
|
||||
defaultVersion = knex.raw(`(${sql})`)
|
||||
}
|
||||
|
||||
const version = config.where.version ?? defaultVersion
|
||||
delete config.where?.version
|
||||
|
||||
config.options.populateWhere ??= {}
|
||||
|
||||
config.options.populateWhere.items ??= {}
|
||||
config.options.populateWhere.items.version = version
|
||||
|
||||
config.options.populateWhere.summary ??= {}
|
||||
config.options.populateWhere.summary.version = version
|
||||
|
||||
config.options.populateWhere.shipping_methods ??= {}
|
||||
config.options.populateWhere.shipping_methods.version = version
|
||||
|
||||
if (!config.options.orderBy) {
|
||||
config.options.orderBy = { id: "ASC" }
|
||||
}
|
||||
|
||||
return await manager.find(Order, config.where, config.options)
|
||||
}
|
||||
|
||||
async findAndCount(
|
||||
findOptions: DAL.FindOptions<Order> = { where: {} },
|
||||
context: Context = {}
|
||||
): Promise<[Order[], number]> {
|
||||
const manager = this.getActiveManager<EntityManager>(context)
|
||||
const knex = manager.getKnex()
|
||||
|
||||
const findOptions_ = { ...findOptions } as any
|
||||
findOptions_.options ??= {}
|
||||
findOptions_.where ??= {}
|
||||
|
||||
if (!("strategy" in findOptions_.options)) {
|
||||
Object.assign(findOptions_.options, {
|
||||
strategy: LoadStrategy.SELECT_IN,
|
||||
})
|
||||
}
|
||||
|
||||
const config = mapRepositoryToOrderModel(findOptions_)
|
||||
|
||||
let defaultVersion = knex.raw(`"o0"."version"`)
|
||||
const strategy = config.options.strategy ?? LoadStrategy.JOINED
|
||||
if (strategy === LoadStrategy.SELECT_IN) {
|
||||
const sql = manager
|
||||
.qb(Order, "_sub0")
|
||||
.select("version")
|
||||
.where({ id: knex.raw(`"o0"."order_id"`) })
|
||||
.getKnexQuery()
|
||||
.toString()
|
||||
|
||||
defaultVersion = knex.raw(`(${sql})`)
|
||||
}
|
||||
|
||||
const version = config.where.version ?? defaultVersion
|
||||
delete config.where.version
|
||||
|
||||
config.options.populateWhere ??= {}
|
||||
config.options.populateWhere.items ??= {}
|
||||
config.options.populateWhere.items.version = version
|
||||
|
||||
config.options.populateWhere.summary ??= {}
|
||||
config.options.populateWhere.summary.version = version
|
||||
|
||||
config.options.populateWhere.shipping_methods ??= {}
|
||||
config.options.populateWhere.shipping_methods.version = version
|
||||
|
||||
if (!config.options.orderBy) {
|
||||
config.options.orderBy = { id: "ASC" }
|
||||
}
|
||||
|
||||
return await manager.findAndCount(Order, config.where, config.options)
|
||||
}
|
||||
}
|
||||
29
packages/modules/order/src/scripts/bin/run-seed.ts
Normal file
29
packages/modules/order/src/scripts/bin/run-seed.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { Modules } from "@medusajs/modules-sdk"
|
||||
import { ModulesSdkUtils } from "@medusajs/utils"
|
||||
import * as Models from "@models"
|
||||
import { EOL } from "os"
|
||||
|
||||
const args = process.argv
|
||||
const path = args.pop() as string
|
||||
|
||||
export default (async () => {
|
||||
const { config } = await import("dotenv")
|
||||
config()
|
||||
if (!path) {
|
||||
throw new Error(
|
||||
`filePath is required.${EOL}Example: medusa-order-seed <filePath>`
|
||||
)
|
||||
}
|
||||
|
||||
const run = ModulesSdkUtils.buildSeedScript({
|
||||
moduleName: Modules.ORDER,
|
||||
models: Models,
|
||||
pathToMigrations: __dirname + "/../../migrations",
|
||||
seedHandler: async ({ manager, data }) => {
|
||||
// TODO: Add seed logic
|
||||
},
|
||||
})
|
||||
await run({ path })
|
||||
})()
|
||||
@@ -0,0 +1,160 @@
|
||||
import { OrderChangeEvent } from "../../../../types"
|
||||
import { ChangeActionType, calculateOrderChange } from "../../../../utils"
|
||||
|
||||
describe("Order Exchange - Actions", function () {
|
||||
const originalOrder = {
|
||||
items: [
|
||||
{
|
||||
id: "1",
|
||||
quantity: 1,
|
||||
unit_price: 10,
|
||||
|
||||
detail: {
|
||||
quantity: 1,
|
||||
shipped_quantity: 1,
|
||||
fulfilled_quantity: 1,
|
||||
return_requested_quantity: 0,
|
||||
return_received_quantity: 0,
|
||||
return_dismissed_quantity: 0,
|
||||
written_off_quantity: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
quantity: 2,
|
||||
unit_price: 100,
|
||||
|
||||
detail: {
|
||||
quantity: 2,
|
||||
shipped_quantity: 1,
|
||||
fulfilled_quantity: 1,
|
||||
return_requested_quantity: 0,
|
||||
return_received_quantity: 0,
|
||||
return_dismissed_quantity: 0,
|
||||
written_off_quantity: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
quantity: 3,
|
||||
unit_price: 20,
|
||||
|
||||
detail: {
|
||||
quantity: 3,
|
||||
shipped_quantity: 3,
|
||||
fulfilled_quantity: 3,
|
||||
return_requested_quantity: 0,
|
||||
return_received_quantity: 0,
|
||||
return_dismissed_quantity: 0,
|
||||
written_off_quantity: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
shipping_methods: [
|
||||
{
|
||||
id: "ship_123",
|
||||
price: 0,
|
||||
},
|
||||
],
|
||||
total: 270,
|
||||
}
|
||||
|
||||
it("should perform an item exchage", function () {
|
||||
const actions = [
|
||||
{
|
||||
action: ChangeActionType.RETURN_ITEM,
|
||||
reference_id: "return_123",
|
||||
details: {
|
||||
reference_id: "3",
|
||||
quantity: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: ChangeActionType.ITEM_ADD,
|
||||
reference_id: "item_555",
|
||||
details: {
|
||||
unit_price: 50,
|
||||
quantity: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: ChangeActionType.SHIPPING_ADD,
|
||||
reference_id: "shipping_345",
|
||||
amount: 5,
|
||||
},
|
||||
{
|
||||
action: ChangeActionType.SHIPPING_ADD,
|
||||
reference_id: "return_shipping_345",
|
||||
amount: 7.5,
|
||||
},
|
||||
] as OrderChangeEvent[]
|
||||
|
||||
const changes = calculateOrderChange({
|
||||
order: originalOrder,
|
||||
actions: actions,
|
||||
})
|
||||
|
||||
const sumToJSON = JSON.parse(JSON.stringify(changes.summary))
|
||||
expect(sumToJSON).toEqual({
|
||||
transactionTotal: 0,
|
||||
originalOrderTotal: 270,
|
||||
currentOrderTotal: 312.5,
|
||||
temporaryDifference: 62.5,
|
||||
futureDifference: 0,
|
||||
futureTemporaryDifference: 0,
|
||||
pendingDifference: 312.5,
|
||||
differenceSum: 42.5,
|
||||
})
|
||||
|
||||
const toJson = JSON.parse(JSON.stringify(changes.order.items))
|
||||
expect(toJson).toEqual([
|
||||
{
|
||||
id: "1",
|
||||
quantity: 1,
|
||||
unit_price: 10,
|
||||
detail: {
|
||||
quantity: 1,
|
||||
shipped_quantity: 1,
|
||||
fulfilled_quantity: 1,
|
||||
return_requested_quantity: 0,
|
||||
return_received_quantity: 0,
|
||||
return_dismissed_quantity: 0,
|
||||
written_off_quantity: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
quantity: 2,
|
||||
unit_price: 100,
|
||||
detail: {
|
||||
quantity: 2,
|
||||
shipped_quantity: 1,
|
||||
fulfilled_quantity: 1,
|
||||
return_requested_quantity: 0,
|
||||
return_received_quantity: 0,
|
||||
return_dismissed_quantity: 0,
|
||||
written_off_quantity: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
quantity: 3,
|
||||
unit_price: 20,
|
||||
detail: {
|
||||
quantity: 3,
|
||||
shipped_quantity: 3,
|
||||
fulfilled_quantity: 3,
|
||||
return_requested_quantity: "1",
|
||||
return_received_quantity: 0,
|
||||
return_dismissed_quantity: 0,
|
||||
written_off_quantity: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "item_555",
|
||||
unit_price: 50,
|
||||
quantity: 1,
|
||||
},
|
||||
])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,305 @@
|
||||
import { OrderChangeEvent } from "../../../../types"
|
||||
import { ChangeActionType, calculateOrderChange } from "../../../../utils"
|
||||
|
||||
describe("Order Return - Actions", function () {
|
||||
const originalOrder = {
|
||||
items: [
|
||||
{
|
||||
id: "1",
|
||||
quantity: 1,
|
||||
unit_price: 10,
|
||||
|
||||
detail: {
|
||||
quantity: 1,
|
||||
shipped_quantity: 1,
|
||||
fulfilled_quantity: 1,
|
||||
return_requested_quantity: 0,
|
||||
return_received_quantity: 0,
|
||||
return_dismissed_quantity: 0,
|
||||
written_off_quantity: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
quantity: 2,
|
||||
unit_price: 100,
|
||||
|
||||
detail: {
|
||||
quantity: 2,
|
||||
shipped_quantity: 1,
|
||||
fulfilled_quantity: 1,
|
||||
return_requested_quantity: 0,
|
||||
return_received_quantity: 0,
|
||||
return_dismissed_quantity: 0,
|
||||
written_off_quantity: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
quantity: 3,
|
||||
unit_price: 20,
|
||||
|
||||
detail: {
|
||||
quantity: 3,
|
||||
shipped_quantity: 3,
|
||||
fulfilled_quantity: 3,
|
||||
return_requested_quantity: 0,
|
||||
return_received_quantity: 0,
|
||||
return_dismissed_quantity: 0,
|
||||
written_off_quantity: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
shipping_methods: [
|
||||
{
|
||||
id: "ship_123",
|
||||
price: 0,
|
||||
},
|
||||
],
|
||||
total: 270,
|
||||
}
|
||||
|
||||
it("should validate return requests", function () {
|
||||
const actions = [
|
||||
{
|
||||
action: ChangeActionType.RETURN_ITEM,
|
||||
reference_id: "return_123",
|
||||
details: {
|
||||
reference_id: "1",
|
||||
quantity: 1,
|
||||
},
|
||||
},
|
||||
] as OrderChangeEvent[]
|
||||
|
||||
expect(() => {
|
||||
actions[0].details!.quantity = 2
|
||||
calculateOrderChange({
|
||||
order: originalOrder,
|
||||
actions,
|
||||
})
|
||||
}).toThrow(
|
||||
"Cannot request to return more items than what was shipped for item 1."
|
||||
)
|
||||
|
||||
expect(() => {
|
||||
actions[0].details!.reference_id = undefined
|
||||
calculateOrderChange({
|
||||
order: originalOrder,
|
||||
actions,
|
||||
})
|
||||
}).toThrow("Details reference ID is required.")
|
||||
|
||||
expect(() => {
|
||||
actions[0].details!.reference_id = "333"
|
||||
calculateOrderChange({
|
||||
order: originalOrder,
|
||||
actions,
|
||||
})
|
||||
}).toThrow(`Reference ID "333" not found.`)
|
||||
})
|
||||
|
||||
it("should validate return received", function () {
|
||||
const [] = []
|
||||
|
||||
const actions = [
|
||||
{
|
||||
action: ChangeActionType.RETURN_ITEM,
|
||||
reference_id: "return_123",
|
||||
details: {
|
||||
reference_id: "2",
|
||||
quantity: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: ChangeActionType.RETURN_ITEM,
|
||||
reference_id: "return_123",
|
||||
details: {
|
||||
reference_id: "3",
|
||||
quantity: 2,
|
||||
},
|
||||
},
|
||||
] as OrderChangeEvent[]
|
||||
|
||||
const changes = calculateOrderChange({
|
||||
order: originalOrder,
|
||||
actions,
|
||||
})
|
||||
|
||||
const toJson = JSON.parse(JSON.stringify(changes.order.items))
|
||||
expect(toJson).toEqual([
|
||||
{
|
||||
id: "1",
|
||||
quantity: 1,
|
||||
unit_price: 10,
|
||||
detail: {
|
||||
quantity: 1,
|
||||
shipped_quantity: 1,
|
||||
fulfilled_quantity: 1,
|
||||
return_requested_quantity: 0,
|
||||
return_received_quantity: 0,
|
||||
return_dismissed_quantity: 0,
|
||||
written_off_quantity: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
quantity: 2,
|
||||
unit_price: 100,
|
||||
detail: {
|
||||
quantity: 2,
|
||||
shipped_quantity: 1,
|
||||
fulfilled_quantity: 1,
|
||||
return_requested_quantity: "1",
|
||||
return_received_quantity: 0,
|
||||
return_dismissed_quantity: 0,
|
||||
written_off_quantity: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
quantity: 3,
|
||||
unit_price: 20,
|
||||
detail: {
|
||||
quantity: 3,
|
||||
shipped_quantity: 3,
|
||||
fulfilled_quantity: 3,
|
||||
return_requested_quantity: "2",
|
||||
return_received_quantity: 0,
|
||||
return_dismissed_quantity: 0,
|
||||
written_off_quantity: 0,
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
const modifiedOrder = {
|
||||
...originalOrder,
|
||||
items: [...changes.order.items],
|
||||
}
|
||||
|
||||
expect(() => {
|
||||
calculateOrderChange({
|
||||
order: modifiedOrder,
|
||||
actions: [
|
||||
{
|
||||
action: ChangeActionType.RETURN_ITEM,
|
||||
details: {
|
||||
reference_id: "3",
|
||||
quantity: 2,
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
}).toThrow(
|
||||
"Cannot request to return more items than what was shipped for item 3."
|
||||
)
|
||||
|
||||
expect(() => {
|
||||
calculateOrderChange({
|
||||
order: modifiedOrder,
|
||||
actions: [
|
||||
{
|
||||
action: ChangeActionType.RECEIVE_RETURN_ITEM,
|
||||
details: {
|
||||
reference_id: "3",
|
||||
quantity: 3,
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
}).toThrow(
|
||||
"Cannot receive more items than what was requested to be returned for item 3."
|
||||
)
|
||||
|
||||
expect(() => {
|
||||
calculateOrderChange({
|
||||
order: modifiedOrder,
|
||||
actions: [
|
||||
{
|
||||
action: ChangeActionType.RECEIVE_RETURN_ITEM,
|
||||
details: {
|
||||
reference_id: "3",
|
||||
quantity: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: ChangeActionType.RECEIVE_DAMAGED_RETURN_ITEM,
|
||||
details: {
|
||||
reference_id: "3",
|
||||
quantity: 2,
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
}).toThrow(
|
||||
"Cannot receive more items than what was requested to be returned for item 3."
|
||||
)
|
||||
|
||||
const receivedChanges = calculateOrderChange({
|
||||
order: modifiedOrder,
|
||||
actions: [
|
||||
{
|
||||
action: ChangeActionType.RECEIVE_RETURN_ITEM,
|
||||
details: {
|
||||
reference_id: "3",
|
||||
quantity: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: ChangeActionType.RECEIVE_DAMAGED_RETURN_ITEM,
|
||||
details: {
|
||||
reference_id: "3",
|
||||
quantity: 1,
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
const toJsonReceived = JSON.parse(
|
||||
JSON.stringify(receivedChanges.order.items)
|
||||
)
|
||||
expect(toJsonReceived).toEqual([
|
||||
{
|
||||
id: "1",
|
||||
quantity: 1,
|
||||
unit_price: 10,
|
||||
detail: {
|
||||
quantity: 1,
|
||||
shipped_quantity: 1,
|
||||
fulfilled_quantity: 1,
|
||||
return_requested_quantity: 0,
|
||||
return_received_quantity: 0,
|
||||
return_dismissed_quantity: 0,
|
||||
written_off_quantity: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
quantity: 2,
|
||||
unit_price: 100,
|
||||
detail: {
|
||||
quantity: 2,
|
||||
shipped_quantity: 1,
|
||||
fulfilled_quantity: 1,
|
||||
return_requested_quantity: "1",
|
||||
return_received_quantity: 0,
|
||||
return_dismissed_quantity: 0,
|
||||
written_off_quantity: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
quantity: 3,
|
||||
unit_price: 20,
|
||||
detail: {
|
||||
quantity: 3,
|
||||
shipped_quantity: 3,
|
||||
fulfilled_quantity: 3,
|
||||
return_requested_quantity: "0",
|
||||
return_received_quantity: "1",
|
||||
return_dismissed_quantity: "1",
|
||||
written_off_quantity: 0,
|
||||
},
|
||||
},
|
||||
])
|
||||
})
|
||||
})
|
||||
3
packages/modules/order/src/services/index.ts
Normal file
3
packages/modules/order/src/services/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export { default as OrderChangeService } from "./order-change-service"
|
||||
export { default as OrderModuleService } from "./order-module-service"
|
||||
export { default as OrderService } from "./order-service"
|
||||
139
packages/modules/order/src/services/order-change-service.ts
Normal file
139
packages/modules/order/src/services/order-change-service.ts
Normal file
@@ -0,0 +1,139 @@
|
||||
import {
|
||||
Context,
|
||||
DAL,
|
||||
FindConfig,
|
||||
OrderTypes,
|
||||
RepositoryService,
|
||||
} from "@medusajs/types"
|
||||
import {
|
||||
InjectManager,
|
||||
InjectTransactionManager,
|
||||
MedusaContext,
|
||||
MedusaError,
|
||||
ModulesSdkUtils,
|
||||
OrderChangeStatus,
|
||||
deduplicate,
|
||||
} from "@medusajs/utils"
|
||||
import { OrderChange } from "@models"
|
||||
|
||||
type InjectedDependencies = {
|
||||
orderChangeRepository: DAL.RepositoryService
|
||||
}
|
||||
|
||||
export default class OrderChangeService<
|
||||
TEntity extends OrderChange = OrderChange
|
||||
> extends ModulesSdkUtils.internalModuleServiceFactory<InjectedDependencies>(
|
||||
OrderChange
|
||||
)<TEntity> {
|
||||
protected readonly orderChangeRepository_: RepositoryService<TEntity>
|
||||
|
||||
constructor(container: InjectedDependencies) {
|
||||
// @ts-ignore
|
||||
super(...arguments)
|
||||
this.orderChangeRepository_ = container.orderChangeRepository
|
||||
}
|
||||
|
||||
@InjectManager("orderChangeRepository_")
|
||||
async listCurrentOrderChange<TEntityMethod = OrderTypes.OrderDTO>(
|
||||
orderId: string | string[],
|
||||
config: FindConfig<TEntityMethod> = {},
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<TEntity[]> {
|
||||
const allChanges = await super.list(
|
||||
{ order_id: orderId },
|
||||
config ?? {
|
||||
select: ["order_id", "status", "version"],
|
||||
order: {
|
||||
order_id: "ASC",
|
||||
version: "DESC",
|
||||
},
|
||||
}
|
||||
)
|
||||
if (!allChanges.length) {
|
||||
return []
|
||||
}
|
||||
|
||||
const lastChanges: string[] = []
|
||||
|
||||
const seen = new Set()
|
||||
for (let i = 0; i < allChanges.length; i++) {
|
||||
if (seen.has(allChanges[i].order_id)) {
|
||||
continue
|
||||
}
|
||||
seen.add(allChanges[i].order_id)
|
||||
|
||||
if (this.isActive(allChanges[i])) {
|
||||
lastChanges.push(allChanges[i].id)
|
||||
}
|
||||
}
|
||||
|
||||
let orderChange!: TEntity
|
||||
if (allChanges?.length > 0) {
|
||||
if (this.isActive(allChanges[0])) {
|
||||
orderChange = allChanges[0]
|
||||
}
|
||||
}
|
||||
|
||||
if (!orderChange) {
|
||||
return []
|
||||
}
|
||||
|
||||
const relations = deduplicate([...(config.relations ?? []), "actions"])
|
||||
config.relations = relations
|
||||
|
||||
const queryConfig = ModulesSdkUtils.buildQuery<TEntity>(
|
||||
{
|
||||
id: lastChanges,
|
||||
order: {
|
||||
items: {
|
||||
version: orderChange.version,
|
||||
},
|
||||
},
|
||||
},
|
||||
config
|
||||
)
|
||||
|
||||
return await this.orderChangeRepository_.find(queryConfig, sharedContext)
|
||||
}
|
||||
|
||||
isActive(orderChange: OrderChange): boolean {
|
||||
return (
|
||||
orderChange.status === OrderChangeStatus.PENDING ||
|
||||
orderChange.status === OrderChangeStatus.REQUESTED
|
||||
)
|
||||
}
|
||||
|
||||
async create(
|
||||
data: Partial<TEntity>[],
|
||||
sharedContext?: Context
|
||||
): Promise<TEntity[]>
|
||||
|
||||
async create(
|
||||
data: Partial<TEntity>,
|
||||
sharedContext?: Context
|
||||
): Promise<TEntity>
|
||||
|
||||
@InjectTransactionManager("orderChangeRepository_")
|
||||
async create(
|
||||
data: Partial<TEntity>[] | Partial<TEntity>,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<TEntity[] | TEntity> {
|
||||
const dataArr = Array.isArray(data) ? data : [data]
|
||||
const activeOrderEdit = await this.listCurrentOrderChange(
|
||||
dataArr.map((d) => d.order_id!),
|
||||
{},
|
||||
sharedContext
|
||||
)
|
||||
|
||||
if (activeOrderEdit.length > 0) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`An active order change already exists for the order(s) ${activeOrderEdit
|
||||
.map((a) => a.order_id)
|
||||
.join(",")}`
|
||||
)
|
||||
}
|
||||
|
||||
return await super.create(dataArr, sharedContext)
|
||||
}
|
||||
}
|
||||
2264
packages/modules/order/src/services/order-module-service.ts
Normal file
2264
packages/modules/order/src/services/order-module-service.ts
Normal file
File diff suppressed because it is too large
Load Diff
58
packages/modules/order/src/services/order-service.ts
Normal file
58
packages/modules/order/src/services/order-service.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import {
|
||||
Context,
|
||||
DAL,
|
||||
FindConfig,
|
||||
OrderTypes,
|
||||
RepositoryService,
|
||||
} from "@medusajs/types"
|
||||
import {
|
||||
InjectManager,
|
||||
MedusaContext,
|
||||
MedusaError,
|
||||
ModulesSdkUtils,
|
||||
} from "@medusajs/utils"
|
||||
import { Order } from "@models"
|
||||
|
||||
type InjectedDependencies = {
|
||||
orderRepository: DAL.RepositoryService
|
||||
}
|
||||
|
||||
export default class OrderService<
|
||||
TEntity extends Order = Order
|
||||
> extends ModulesSdkUtils.internalModuleServiceFactory<InjectedDependencies>(
|
||||
Order
|
||||
)<TEntity> {
|
||||
protected readonly orderRepository_: RepositoryService<TEntity>
|
||||
|
||||
constructor(container: InjectedDependencies) {
|
||||
// @ts-ignore
|
||||
super(...arguments)
|
||||
this.orderRepository_ = container.orderRepository
|
||||
}
|
||||
|
||||
@InjectManager("orderRepository_")
|
||||
async retrieveOrderVersion<TEntityMethod = OrderTypes.OrderDTO>(
|
||||
id: string,
|
||||
version: number,
|
||||
config: FindConfig<TEntityMethod> = {},
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<TEntity> {
|
||||
const queryConfig = ModulesSdkUtils.buildQuery<TEntity>(
|
||||
{ id, items: { version } },
|
||||
{ ...config, take: 1 }
|
||||
)
|
||||
const [result] = await this.orderRepository_.find(
|
||||
queryConfig,
|
||||
sharedContext
|
||||
)
|
||||
|
||||
if (!result) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_FOUND,
|
||||
`Order with id: "${id}" and version: "${version}" not found`
|
||||
)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
11
packages/modules/order/src/types/address.ts
Normal file
11
packages/modules/order/src/types/address.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { OrderTypes } from "@medusajs/types"
|
||||
|
||||
export type UpsertOrderAddressDTO = OrderTypes.UpsertOrderAddressDTO
|
||||
|
||||
export interface UpdateOrderAddressDTO extends UpsertOrderAddressDTO {
|
||||
id: string
|
||||
}
|
||||
|
||||
export interface CreateOrderAddressDTO extends UpsertOrderAddressDTO {}
|
||||
|
||||
export type OrderAddressDTO = OrderTypes.OrderAddressDTO
|
||||
18
packages/modules/order/src/types/index.ts
Normal file
18
packages/modules/order/src/types/index.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { IEventBusModuleService, Logger } from "@medusajs/types"
|
||||
|
||||
export * from "./address"
|
||||
export * from "./line-item"
|
||||
export * from "./line-item-adjustment"
|
||||
export * from "./line-item-tax-line"
|
||||
export * from "./order"
|
||||
export * from "./order-detail"
|
||||
export * from "./shipping-method"
|
||||
export * from "./shipping-method-adjustment"
|
||||
export * from "./shipping-method-tax-line"
|
||||
export * from "./transaction"
|
||||
export * from "./utils"
|
||||
|
||||
export type InitializeModuleInjectableDependencies = {
|
||||
logger?: Logger
|
||||
eventBusService?: IEventBusModuleService
|
||||
}
|
||||
9
packages/modules/order/src/types/line-item-adjustment.ts
Normal file
9
packages/modules/order/src/types/line-item-adjustment.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { OrderTypes } from "@medusajs/types"
|
||||
|
||||
export type CreateOrderLineItemAdjustmentDTO =
|
||||
OrderTypes.CreateOrderLineItemAdjustmentDTO
|
||||
|
||||
export interface UpdateOrderLineItemAdjustmentDTO
|
||||
extends Partial<CreateOrderLineItemAdjustmentDTO> {
|
||||
id: string
|
||||
}
|
||||
9
packages/modules/order/src/types/line-item-tax-line.ts
Normal file
9
packages/modules/order/src/types/line-item-tax-line.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { CreateOrderTaxLineDTO, UpdateOrderTaxLineDTO } from "./tax-line"
|
||||
|
||||
export interface CreateOrderLineItemTaxLineDTO extends CreateOrderTaxLineDTO {
|
||||
item_id: string
|
||||
}
|
||||
|
||||
export interface UpdateOrderLineItemTaxLineDTO extends UpdateOrderTaxLineDTO {
|
||||
item_id: string
|
||||
}
|
||||
40
packages/modules/order/src/types/line-item.ts
Normal file
40
packages/modules/order/src/types/line-item.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { BigNumberInput } from "@medusajs/types"
|
||||
|
||||
interface PartialUpsertOrderLineItemDTO {
|
||||
subtitle?: string
|
||||
thumbnail?: string
|
||||
|
||||
product_id?: string
|
||||
product_title?: string
|
||||
product_description?: string
|
||||
product_subtitle?: string
|
||||
product_type?: string
|
||||
product_collection?: string
|
||||
product_handle?: string
|
||||
|
||||
variant_id?: string
|
||||
variant_sku?: string
|
||||
variant_barcode?: string
|
||||
variant_title?: string
|
||||
variant_option_values?: Record<string, unknown>
|
||||
|
||||
requires_shipping?: boolean
|
||||
is_discountable?: boolean
|
||||
is_tax_inclusive?: boolean
|
||||
|
||||
compare_at_unit_price?: BigNumberInput
|
||||
}
|
||||
|
||||
export interface CreateOrderLineItemDTO extends PartialUpsertOrderLineItemDTO {
|
||||
version?: number
|
||||
title: string
|
||||
quantity: BigNumberInput
|
||||
unit_price: BigNumberInput
|
||||
order_id: string
|
||||
}
|
||||
|
||||
export interface UpdateOrderLineItemDTO
|
||||
extends PartialUpsertOrderLineItemDTO,
|
||||
Partial<CreateOrderLineItemDTO> {
|
||||
id: string
|
||||
}
|
||||
29
packages/modules/order/src/types/order-detail.ts
Normal file
29
packages/modules/order/src/types/order-detail.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { BigNumberInput } from "@medusajs/types"
|
||||
|
||||
export interface PartialUpsertOrderItemDTO {
|
||||
order_id?: string
|
||||
version?: number
|
||||
item_id?: string
|
||||
|
||||
quantity?: BigNumberInput
|
||||
fulfilled_quantity?: BigNumberInput
|
||||
return_requested_quantity?: BigNumberInput
|
||||
return_received_quantity?: BigNumberInput
|
||||
return_dismissed_quantity?: BigNumberInput
|
||||
written_off_quantity?: BigNumberInput
|
||||
|
||||
metadata?: Record<string, unknown>
|
||||
}
|
||||
|
||||
export interface CreateOrderItemDTO extends PartialUpsertOrderItemDTO {
|
||||
order_id: string
|
||||
version: number
|
||||
item_id: string
|
||||
quantity: BigNumberInput
|
||||
}
|
||||
|
||||
export interface UpdateOrderItemDTO
|
||||
extends PartialUpsertOrderItemDTO,
|
||||
Partial<CreateOrderItemDTO> {
|
||||
id: string
|
||||
}
|
||||
25
packages/modules/order/src/types/order.ts
Normal file
25
packages/modules/order/src/types/order.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { OrderStatus } from "@medusajs/utils"
|
||||
|
||||
export interface CreateOrderDTO {
|
||||
region_id?: string
|
||||
customer_id?: string
|
||||
sales_channel_id?: string
|
||||
email?: string
|
||||
currency_code: string
|
||||
status?: OrderStatus
|
||||
no_notification?: boolean
|
||||
metadata?: Record<string, unknown>
|
||||
}
|
||||
|
||||
export interface UpdateOrderDTO {
|
||||
id: string
|
||||
version?: number
|
||||
region_id?: string
|
||||
customer_id?: string
|
||||
sales_channel_id?: string
|
||||
email?: string
|
||||
currency_code?: string
|
||||
status?: OrderStatus
|
||||
no_notification?: boolean
|
||||
metadata?: Record<string, unknown>
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import { OrderTypes } from "@medusajs/types"
|
||||
|
||||
export type CreateOrderShippingMethodAdjustmentDTO =
|
||||
OrderTypes.CreateOrderShippingMethodAdjustmentDTO
|
||||
|
||||
export type UpdateOrderShippingMethodAdjustmentDTO =
|
||||
OrderTypes.UpdateOrderShippingMethodAdjustmentDTO
|
||||
11
packages/modules/order/src/types/shipping-method-tax-line.ts
Normal file
11
packages/modules/order/src/types/shipping-method-tax-line.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { CreateOrderTaxLineDTO, UpdateOrderTaxLineDTO } from "./tax-line"
|
||||
|
||||
export interface CreateOrderShippingMethodTaxLineDTO
|
||||
extends CreateOrderTaxLineDTO {
|
||||
shipping_method_id: string
|
||||
}
|
||||
|
||||
export interface UpdateOrderShippingMethodTaxLineDTO
|
||||
extends UpdateOrderTaxLineDTO {
|
||||
shipping_method_id: string
|
||||
}
|
||||
18
packages/modules/order/src/types/shipping-method.ts
Normal file
18
packages/modules/order/src/types/shipping-method.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { BigNumberInput } from "@medusajs/types"
|
||||
|
||||
export interface CreateOrderShippingMethodDTO {
|
||||
name: string
|
||||
shipping_option_id?: string
|
||||
order_id: string
|
||||
version?: number
|
||||
amount: BigNumberInput
|
||||
data?: Record<string, unknown>
|
||||
}
|
||||
|
||||
export interface UpdateOrderShippingMethodDTO {
|
||||
id: string
|
||||
shipping_option_id?: string
|
||||
name?: string
|
||||
amount?: BigNumberInput
|
||||
data?: Record<string, unknown>
|
||||
}
|
||||
5
packages/modules/order/src/types/tax-line.ts
Normal file
5
packages/modules/order/src/types/tax-line.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { OrderTypes } from "@medusajs/types"
|
||||
|
||||
export type CreateOrderTaxLineDTO = OrderTypes.CreateOrderTaxLineDTO
|
||||
|
||||
export type UpdateOrderTaxLineDTO = OrderTypes.UpdateOrderTaxLineDTO
|
||||
3
packages/modules/order/src/types/transaction.ts
Normal file
3
packages/modules/order/src/types/transaction.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { OrderTypes } from "@medusajs/types"
|
||||
|
||||
export type OrderTransactionDTO = OrderTypes.OrderTransactionDTO
|
||||
98
packages/modules/order/src/types/utils/index.ts
Normal file
98
packages/modules/order/src/types/utils/index.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import { BigNumberInput } from "@medusajs/types"
|
||||
|
||||
export type VirtualOrder = {
|
||||
items: {
|
||||
id: string
|
||||
unit_price: BigNumberInput
|
||||
quantity: BigNumberInput
|
||||
|
||||
detail: {
|
||||
id?: string
|
||||
quantity: BigNumberInput
|
||||
shipped_quantity: BigNumberInput
|
||||
fulfilled_quantity: BigNumberInput
|
||||
return_requested_quantity: BigNumberInput
|
||||
return_received_quantity: BigNumberInput
|
||||
return_dismissed_quantity: BigNumberInput
|
||||
written_off_quantity: BigNumberInput
|
||||
metadata?: Record<string, unknown>
|
||||
}
|
||||
}[]
|
||||
|
||||
shipping_methods: {
|
||||
id: string
|
||||
price: BigNumberInput
|
||||
}[]
|
||||
|
||||
total: BigNumberInput
|
||||
|
||||
metadata?: Record<string, unknown>
|
||||
}
|
||||
|
||||
export enum EVENT_STATUS {
|
||||
PENDING = "pending",
|
||||
VOIDED = "voided",
|
||||
DONE = "done",
|
||||
}
|
||||
|
||||
export interface OrderSummaryCalculated {
|
||||
currentOrderTotal: BigNumberInput
|
||||
originalOrderTotal: BigNumberInput
|
||||
transactionTotal: BigNumberInput
|
||||
futureDifference: BigNumberInput
|
||||
pendingDifference: BigNumberInput
|
||||
futureTemporaryDifference: BigNumberInput
|
||||
temporaryDifference: BigNumberInput
|
||||
differenceSum: BigNumberInput
|
||||
}
|
||||
|
||||
export interface OrderTransaction {
|
||||
amount: BigNumberInput
|
||||
}
|
||||
|
||||
export interface OrderChangeEvent {
|
||||
action: string
|
||||
amount?: BigNumberInput
|
||||
|
||||
reference?: string
|
||||
reference_id?: string
|
||||
|
||||
group_id?: string
|
||||
|
||||
evaluationOnly?: boolean
|
||||
|
||||
details?: any
|
||||
|
||||
resolve?: {
|
||||
group_id?: string
|
||||
reference_id?: string
|
||||
amount?: BigNumberInput
|
||||
}
|
||||
}
|
||||
|
||||
export type InternalOrderChangeEvent = OrderChangeEvent & {
|
||||
status?: EVENT_STATUS
|
||||
original_?: InternalOrderChangeEvent
|
||||
}
|
||||
|
||||
export type OrderReferences = {
|
||||
action: InternalOrderChangeEvent
|
||||
previousEvents?: InternalOrderChangeEvent[]
|
||||
currentOrder: VirtualOrder
|
||||
summary: OrderSummaryCalculated
|
||||
transactions: OrderTransaction[]
|
||||
type: ActionTypeDefinition
|
||||
actions: InternalOrderChangeEvent[]
|
||||
}
|
||||
|
||||
export interface ActionTypeDefinition {
|
||||
isDeduction?: boolean
|
||||
awaitRequired?: boolean
|
||||
versioning?: boolean
|
||||
void?: boolean
|
||||
commitsAction?: string
|
||||
operation?: (obj: OrderReferences) => BigNumberInput | void
|
||||
revert?: (obj: OrderReferences) => BigNumberInput | void
|
||||
validate?: (obj: OrderReferences) => void
|
||||
[key: string]: unknown
|
||||
}
|
||||
13
packages/modules/order/src/utils/action-key.ts
Normal file
13
packages/modules/order/src/utils/action-key.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
export enum ChangeActionType {
|
||||
CANCEL = "CANCEL",
|
||||
CANCEL_RETURN = "CANCEL_RETURN",
|
||||
FULFILL_ITEM = "FULFILL_ITEM",
|
||||
ITEM_ADD = "ITEM_ADD",
|
||||
ITEM_REMOVE = "ITEM_REMOVE",
|
||||
RECEIVE_DAMAGED_RETURN_ITEM = "RECEIVE_DAMAGED_RETURN_ITEM",
|
||||
RECEIVE_RETURN_ITEM = "RECEIVE_RETURN_ITEM",
|
||||
RETURN_ITEM = "RETURN_ITEM",
|
||||
SHIPPING_ADD = "SHIPPING_ADD",
|
||||
SHIP_ITEM = "SHIP_ITEM",
|
||||
WRITE_OFF_ITEM = "WRITE_OFF_ITEM",
|
||||
}
|
||||
73
packages/modules/order/src/utils/actions/cancel-return.ts
Normal file
73
packages/modules/order/src/utils/actions/cancel-return.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { MathBN, MedusaError, isDefined } from "@medusajs/utils"
|
||||
import { ChangeActionType } from "../action-key"
|
||||
import { OrderChangeProcessing } from "../calculate-order-change"
|
||||
|
||||
OrderChangeProcessing.registerActionType(ChangeActionType.CANCEL_RETURN, {
|
||||
operation({ action, currentOrder }) {
|
||||
const existing = currentOrder.items.find(
|
||||
(item) => item.id === action.details.reference_id
|
||||
)!
|
||||
|
||||
existing.detail.return_requested_quantity ??= 0
|
||||
|
||||
existing.detail.return_requested_quantity = MathBN.sub(
|
||||
existing.detail.return_requested_quantity,
|
||||
action.details.quantity
|
||||
)
|
||||
|
||||
return action.details.unit_price * action.details.quantity
|
||||
},
|
||||
revert({ action, currentOrder }) {
|
||||
const existing = currentOrder.items.find(
|
||||
(item) => item.id === action.details.reference_id
|
||||
)!
|
||||
|
||||
existing.detail.return_requested_quantity = MathBN.add(
|
||||
existing.detail.return_requested_quantity,
|
||||
action.details.quantity
|
||||
)
|
||||
},
|
||||
validate({ action, currentOrder }) {
|
||||
const refId = action.details?.reference_id
|
||||
if (!isDefined(refId)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
"Details reference ID is required."
|
||||
)
|
||||
}
|
||||
|
||||
if (!isDefined(action.amount) && !isDefined(action.details?.unit_price)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Unit price of item ${action.reference_id} is required if no action.amount is provided.`
|
||||
)
|
||||
}
|
||||
|
||||
const existing = currentOrder.items.find((item) => item.id === refId)
|
||||
|
||||
if (!existing) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Reference ID "${refId}" not found.`
|
||||
)
|
||||
}
|
||||
|
||||
if (!action.details?.quantity) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Quantity to cancel return of item ${refId} is required.`
|
||||
)
|
||||
}
|
||||
|
||||
const greater = MathBN.gt(
|
||||
action.details?.quantity,
|
||||
existing.detail?.return_requested_quantity
|
||||
)
|
||||
if (greater) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Cannot cancel more items than what was requested to return for item ${refId}.`
|
||||
)
|
||||
}
|
||||
},
|
||||
})
|
||||
6
packages/modules/order/src/utils/actions/cancel.ts
Normal file
6
packages/modules/order/src/utils/actions/cancel.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { ChangeActionType } from "../action-key"
|
||||
import { OrderChangeProcessing } from "../calculate-order-change"
|
||||
|
||||
OrderChangeProcessing.registerActionType(ChangeActionType.CANCEL, {
|
||||
void: true,
|
||||
})
|
||||
71
packages/modules/order/src/utils/actions/fulfill-item.ts
Normal file
71
packages/modules/order/src/utils/actions/fulfill-item.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { MathBN, MedusaError, isDefined } from "@medusajs/utils"
|
||||
import { ChangeActionType } from "../action-key"
|
||||
import { OrderChangeProcessing } from "../calculate-order-change"
|
||||
|
||||
OrderChangeProcessing.registerActionType(ChangeActionType.FULFILL_ITEM, {
|
||||
operation({ action, currentOrder }) {
|
||||
const existing = currentOrder.items.find(
|
||||
(item) => item.id === action.details.reference_id
|
||||
)!
|
||||
|
||||
existing.detail.fulfilled_quantity ??= 0
|
||||
|
||||
existing.detail.fulfilled_quantity = MathBN.add(
|
||||
existing.detail.fulfilled_quantity,
|
||||
action.details.quantity
|
||||
)
|
||||
},
|
||||
revert({ action, currentOrder }) {
|
||||
const existing = currentOrder.items.find(
|
||||
(item) => item.id === action.reference_id
|
||||
)!
|
||||
|
||||
existing.detail.fulfilled_quantity = MathBN.sub(
|
||||
existing.detail.fulfilled_quantity,
|
||||
action.details.quantity
|
||||
)
|
||||
},
|
||||
validate({ action, currentOrder }) {
|
||||
const refId = action.details?.reference_id
|
||||
if (!isDefined(refId)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
"Reference ID is required."
|
||||
)
|
||||
}
|
||||
|
||||
const existing = currentOrder.items.find((item) => item.id === refId)
|
||||
if (!existing) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Reference ID "${refId}" not found.`
|
||||
)
|
||||
}
|
||||
|
||||
if (!action.details?.quantity) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Quantity to fulfill of item ${refId} is required.`
|
||||
)
|
||||
}
|
||||
|
||||
if (action.details?.quantity < 1) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Quantity of item ${refId} must be greater than 0.`
|
||||
)
|
||||
}
|
||||
|
||||
const notFulfilled = MathBN.sub(
|
||||
existing.quantity,
|
||||
existing.detail?.fulfilled_quantity
|
||||
)
|
||||
const greater = MathBN.gt(action.details?.quantity, notFulfilled)
|
||||
if (greater) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Cannot fulfill more items than what was ordered for item ${refId}.`
|
||||
)
|
||||
}
|
||||
},
|
||||
})
|
||||
10
packages/modules/order/src/utils/actions/index.ts
Normal file
10
packages/modules/order/src/utils/actions/index.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export * from "./cancel"
|
||||
export * from "./cancel-return"
|
||||
export * from "./fulfill-item"
|
||||
export * from "./item-add"
|
||||
export * from "./item-remove"
|
||||
export * from "./receive-damaged-return-item"
|
||||
export * from "./receive-return-item"
|
||||
export * from "./return-item"
|
||||
export * from "./ship-item"
|
||||
export * from "./shipping-add"
|
||||
79
packages/modules/order/src/utils/actions/item-add.ts
Normal file
79
packages/modules/order/src/utils/actions/item-add.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { MathBN, MedusaError, isDefined } from "@medusajs/utils"
|
||||
import { VirtualOrder } from "@types"
|
||||
import { ChangeActionType } from "../action-key"
|
||||
import { OrderChangeProcessing } from "../calculate-order-change"
|
||||
|
||||
OrderChangeProcessing.registerActionType(ChangeActionType.ITEM_ADD, {
|
||||
operation({ action, currentOrder }) {
|
||||
const existing = currentOrder.items.find(
|
||||
(item) => item.id === action.reference_id
|
||||
)
|
||||
|
||||
if (existing) {
|
||||
existing.detail.quantity ??= 0
|
||||
|
||||
existing.quantity = MathBN.add(existing.quantity, action.details.quantity)
|
||||
|
||||
existing.detail.quantity = MathBN.add(
|
||||
existing.detail.quantity,
|
||||
action.details.quantity
|
||||
)
|
||||
} else {
|
||||
currentOrder.items.push({
|
||||
id: action.reference_id!,
|
||||
unit_price: action.details.unit_price,
|
||||
quantity: action.details.quantity,
|
||||
} as VirtualOrder["items"][0])
|
||||
}
|
||||
|
||||
return MathBN.mult(action.details.unit_price, action.details.quantity)
|
||||
},
|
||||
revert({ action, currentOrder }) {
|
||||
const existingIndex = currentOrder.items.findIndex(
|
||||
(item) => item.id === action.reference_id
|
||||
)
|
||||
|
||||
if (existingIndex > -1) {
|
||||
const existing = currentOrder.items[existingIndex]
|
||||
existing.quantity = MathBN.sub(existing.quantity, action.details.quantity)
|
||||
existing.detail.quantity = MathBN.sub(
|
||||
existing.detail.quantity,
|
||||
action.details.quantity
|
||||
)
|
||||
|
||||
if (MathBN.lte(existing.quantity, 0)) {
|
||||
currentOrder.items.splice(existingIndex, 1)
|
||||
}
|
||||
}
|
||||
},
|
||||
validate({ action }) {
|
||||
const refId = action.reference_id
|
||||
if (!isDefined(action.reference_id)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
"Reference ID is required."
|
||||
)
|
||||
}
|
||||
|
||||
if (!isDefined(action.amount) && !isDefined(action.details?.unit_price)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Unit price of item ${refId} is required if no action.amount is provided.`
|
||||
)
|
||||
}
|
||||
|
||||
if (!action.details?.quantity) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Quantity of item ${refId} is required.`
|
||||
)
|
||||
}
|
||||
|
||||
if (MathBN.lt(action.details?.quantity, 1)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Quantity of item ${refId} must be greater than 0.`
|
||||
)
|
||||
}
|
||||
},
|
||||
})
|
||||
99
packages/modules/order/src/utils/actions/item-remove.ts
Normal file
99
packages/modules/order/src/utils/actions/item-remove.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import { MathBN, MedusaError, isDefined } from "@medusajs/utils"
|
||||
import { VirtualOrder } from "@types"
|
||||
import { ChangeActionType } from "../action-key"
|
||||
import { OrderChangeProcessing } from "../calculate-order-change"
|
||||
|
||||
OrderChangeProcessing.registerActionType(ChangeActionType.ITEM_REMOVE, {
|
||||
isDeduction: true,
|
||||
operation({ action, currentOrder }) {
|
||||
const existingIndex = currentOrder.items.findIndex(
|
||||
(item) => item.id === action.reference_id
|
||||
)
|
||||
|
||||
const existing = currentOrder.items[existingIndex]
|
||||
|
||||
existing.detail.quantity ??= 0
|
||||
|
||||
existing.quantity = MathBN.sub(existing.quantity, action.details.quantity)
|
||||
existing.detail.quantity = MathBN.sub(
|
||||
existing.detail.quantity,
|
||||
action.details.quantity
|
||||
)
|
||||
|
||||
if (MathBN.lte(existing.quantity, 0)) {
|
||||
currentOrder.items.splice(existingIndex, 1)
|
||||
}
|
||||
|
||||
return MathBN.mult(existing.unit_price, action.details.quantity)
|
||||
},
|
||||
revert({ action, currentOrder }) {
|
||||
const existing = currentOrder.items.find(
|
||||
(item) => item.id === action.reference_id
|
||||
)
|
||||
|
||||
if (existing) {
|
||||
existing.quantity = MathBN.add(existing.quantity, action.details.quantity)
|
||||
existing.detail.quantity = MathBN.add(
|
||||
existing.detail.quantity,
|
||||
action.details.quantity
|
||||
)
|
||||
} else {
|
||||
currentOrder.items.push({
|
||||
id: action.reference_id!,
|
||||
unit_price: action.details.unit_price,
|
||||
quantity: action.details.quantity,
|
||||
} as VirtualOrder["items"][0])
|
||||
}
|
||||
},
|
||||
validate({ action, currentOrder }) {
|
||||
const refId = action.reference_id
|
||||
if (!isDefined(refId)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
"Reference ID is required."
|
||||
)
|
||||
}
|
||||
|
||||
const existing = currentOrder.items.find((item) => item.id === refId)
|
||||
if (!existing) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Reference ID "${refId}" not found.`
|
||||
)
|
||||
}
|
||||
|
||||
if (!isDefined(action.amount) && !isDefined(action.details?.unit_price)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Unit price of item ${refId} is required if no action.amount is provided.`
|
||||
)
|
||||
}
|
||||
|
||||
if (!action.details?.quantity) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Quantity of item ${refId} is required.`
|
||||
)
|
||||
}
|
||||
|
||||
if (MathBN.lt(action.details?.quantity, 1)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Quantity of item ${refId} must be greater than 0.`
|
||||
)
|
||||
}
|
||||
|
||||
const notFulfilled = MathBN.sub(
|
||||
existing.quantity,
|
||||
existing.detail?.fulfilled_quantity
|
||||
)
|
||||
|
||||
const greater = MathBN.gt(action.details?.quantity, notFulfilled)
|
||||
if (greater) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Cannot remove fulfilled item: Item ${refId}.`
|
||||
)
|
||||
}
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,112 @@
|
||||
import { MathBN, MedusaError, isDefined } from "@medusajs/utils"
|
||||
import { EVENT_STATUS } from "@types"
|
||||
import { ChangeActionType } from "../action-key"
|
||||
import { OrderChangeProcessing } from "../calculate-order-change"
|
||||
|
||||
OrderChangeProcessing.registerActionType(
|
||||
ChangeActionType.RECEIVE_DAMAGED_RETURN_ITEM,
|
||||
{
|
||||
isDeduction: true,
|
||||
commitsAction: "return_item",
|
||||
operation({ action, currentOrder, previousEvents }) {
|
||||
const existing = currentOrder.items.find(
|
||||
(item) => item.id === action.details.reference_id
|
||||
)!
|
||||
|
||||
let toReturn = action.details.quantity
|
||||
|
||||
existing.detail.return_dismissed_quantity ??= 0
|
||||
existing.detail.return_requested_quantity ??= 0
|
||||
|
||||
existing.detail.return_dismissed_quantity = MathBN.add(
|
||||
existing.detail.return_dismissed_quantity,
|
||||
toReturn
|
||||
)
|
||||
existing.detail.return_requested_quantity = MathBN.sub(
|
||||
existing.detail.return_requested_quantity,
|
||||
toReturn
|
||||
)
|
||||
|
||||
if (previousEvents) {
|
||||
for (const previousEvent of previousEvents) {
|
||||
previousEvent.original_ = JSON.parse(JSON.stringify(previousEvent))
|
||||
|
||||
let ret = MathBN.min(toReturn, previousEvent.details.quantity)
|
||||
toReturn = MathBN.sub(toReturn, ret)
|
||||
|
||||
previousEvent.details.quantity = MathBN.sub(
|
||||
previousEvent.details.quantity,
|
||||
ret
|
||||
)
|
||||
if (MathBN.lte(previousEvent.details.quantity, 0)) {
|
||||
previousEvent.status = EVENT_STATUS.DONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return MathBN.mult(existing.unit_price, action.details.quantity)
|
||||
},
|
||||
revert({ action, currentOrder, previousEvents }) {
|
||||
const existing = currentOrder.items.find(
|
||||
(item) => item.id === action.details.reference_id
|
||||
)!
|
||||
|
||||
existing.detail.return_dismissed_quantity = MathBN.sub(
|
||||
existing.detail.return_dismissed_quantity,
|
||||
action.details.quantity
|
||||
)
|
||||
existing.detail.return_requested_quantity = MathBN.add(
|
||||
existing.detail.return_requested_quantity,
|
||||
action.details.quantity
|
||||
)
|
||||
|
||||
if (previousEvents) {
|
||||
for (const previousEvent of previousEvents) {
|
||||
if (!previousEvent.original_) {
|
||||
continue
|
||||
}
|
||||
|
||||
previousEvent.details = JSON.parse(
|
||||
JSON.stringify(previousEvent.original_.details)
|
||||
)
|
||||
delete previousEvent.original_
|
||||
|
||||
previousEvent.status = EVENT_STATUS.PENDING
|
||||
}
|
||||
}
|
||||
},
|
||||
validate({ action, currentOrder }) {
|
||||
const refId = action.details?.reference_id
|
||||
if (!isDefined(refId)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
"Details reference ID is required."
|
||||
)
|
||||
}
|
||||
|
||||
const existing = currentOrder.items.find((item) => item.id === refId)
|
||||
|
||||
if (!existing) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Reference ID "${refId}" not found.`
|
||||
)
|
||||
}
|
||||
|
||||
if (!action.details?.quantity) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Quantity to return of item ${refId} is required.`
|
||||
)
|
||||
}
|
||||
|
||||
const quantityRequested = existing?.detail.return_requested_quantity || 0
|
||||
if (action.details?.quantity > quantityRequested) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Cannot receive more items than what was requested to be returned for item ${refId}.`
|
||||
)
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
119
packages/modules/order/src/utils/actions/receive-return-item.ts
Normal file
119
packages/modules/order/src/utils/actions/receive-return-item.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
import {
|
||||
MathBN,
|
||||
MedusaError,
|
||||
isDefined,
|
||||
transformPropertiesToBigNumber,
|
||||
} from "@medusajs/utils"
|
||||
import { EVENT_STATUS } from "@types"
|
||||
import { ChangeActionType } from "../action-key"
|
||||
import { OrderChangeProcessing } from "../calculate-order-change"
|
||||
|
||||
OrderChangeProcessing.registerActionType(ChangeActionType.RECEIVE_RETURN_ITEM, {
|
||||
isDeduction: true,
|
||||
commitsAction: "return_item",
|
||||
operation({ action, currentOrder, previousEvents }) {
|
||||
const existing = currentOrder.items.find(
|
||||
(item) => item.id === action.details.reference_id
|
||||
)!
|
||||
|
||||
let toReturn = action.details.quantity
|
||||
|
||||
existing.detail.return_received_quantity ??= 0
|
||||
existing.detail.return_requested_quantity ??= 0
|
||||
|
||||
existing.detail.return_received_quantity = MathBN.add(
|
||||
existing.detail.return_received_quantity,
|
||||
toReturn
|
||||
)
|
||||
existing.detail.return_requested_quantity = MathBN.sub(
|
||||
existing.detail.return_requested_quantity,
|
||||
toReturn
|
||||
)
|
||||
|
||||
if (previousEvents) {
|
||||
for (const previousEvent of previousEvents) {
|
||||
previousEvent.original_ = JSON.parse(JSON.stringify(previousEvent))
|
||||
|
||||
let ret = MathBN.min(toReturn, previousEvent.details.quantity)
|
||||
toReturn = MathBN.sub(toReturn, ret)
|
||||
|
||||
previousEvent.details.quantity = MathBN.sub(
|
||||
previousEvent.details.quantity,
|
||||
ret
|
||||
)
|
||||
|
||||
if (MathBN.lte(previousEvent.details.quantity, 0)) {
|
||||
previousEvent.status = EVENT_STATUS.DONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return MathBN.mult(existing.unit_price, action.details.quantity)
|
||||
},
|
||||
revert({ action, currentOrder, previousEvents }) {
|
||||
const existing = currentOrder.items.find(
|
||||
(item) => item.id === action.details.reference_id
|
||||
)!
|
||||
|
||||
existing.detail.return_received_quantity = MathBN.sub(
|
||||
existing.detail.return_received_quantity,
|
||||
action.details.quantity
|
||||
)
|
||||
existing.detail.return_requested_quantity = MathBN.add(
|
||||
existing.detail.return_requested_quantity,
|
||||
action.details.quantity
|
||||
)
|
||||
|
||||
if (previousEvents) {
|
||||
for (const previousEvent of previousEvents) {
|
||||
if (!previousEvent.original_) {
|
||||
continue
|
||||
}
|
||||
|
||||
previousEvent.details = JSON.parse(
|
||||
JSON.stringify(previousEvent.original_.details)
|
||||
)
|
||||
transformPropertiesToBigNumber(previousEvent.details?.metadata)
|
||||
|
||||
delete previousEvent.original_
|
||||
|
||||
previousEvent.status = EVENT_STATUS.PENDING
|
||||
}
|
||||
}
|
||||
},
|
||||
validate({ action, currentOrder }) {
|
||||
const refId = action.details?.reference_id
|
||||
if (!isDefined(refId)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
"Details reference ID is required."
|
||||
)
|
||||
}
|
||||
|
||||
const existing = currentOrder.items.find((item) => item.id === refId)
|
||||
|
||||
if (!existing) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Reference ID "${refId}" not found.`
|
||||
)
|
||||
}
|
||||
|
||||
if (!action.details?.quantity) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Quantity to receive return of item ${refId} is required.`
|
||||
)
|
||||
}
|
||||
|
||||
const quantityRequested = existing?.detail?.return_requested_quantity || 0
|
||||
|
||||
const greater = MathBN.gt(action.details?.quantity, quantityRequested)
|
||||
if (greater) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Cannot receive more items than what was requested to be returned for item ${refId}.`
|
||||
)
|
||||
}
|
||||
},
|
||||
})
|
||||
69
packages/modules/order/src/utils/actions/return-item.ts
Normal file
69
packages/modules/order/src/utils/actions/return-item.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { MathBN, MedusaError, isDefined } from "@medusajs/utils"
|
||||
import { ChangeActionType } from "../action-key"
|
||||
import { OrderChangeProcessing } from "../calculate-order-change"
|
||||
|
||||
OrderChangeProcessing.registerActionType(ChangeActionType.RETURN_ITEM, {
|
||||
isDeduction: true,
|
||||
awaitRequired: true,
|
||||
operation({ action, currentOrder }) {
|
||||
const existing = currentOrder.items.find(
|
||||
(item) => item.id === action.details.reference_id
|
||||
)!
|
||||
|
||||
existing.detail.return_requested_quantity ??= 0
|
||||
existing.detail.return_requested_quantity = MathBN.add(
|
||||
existing.detail.return_requested_quantity,
|
||||
action.details.quantity
|
||||
)
|
||||
|
||||
return MathBN.mult(existing.unit_price, action.details.quantity)
|
||||
},
|
||||
revert({ action, currentOrder }) {
|
||||
const existing = currentOrder.items.find(
|
||||
(item) => item.id === action.details.reference_id
|
||||
)!
|
||||
|
||||
existing.detail.return_requested_quantity = MathBN.sub(
|
||||
existing.detail.return_requested_quantity,
|
||||
action.details.quantity
|
||||
)
|
||||
},
|
||||
validate({ action, currentOrder }) {
|
||||
const refId = action.details?.reference_id
|
||||
if (!isDefined(refId)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
"Details reference ID is required."
|
||||
)
|
||||
}
|
||||
|
||||
const existing = currentOrder.items.find((item) => item.id === refId)
|
||||
|
||||
if (!existing) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Reference ID "${refId}" not found.`
|
||||
)
|
||||
}
|
||||
|
||||
if (!action.details?.quantity) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Quantity to return of item ${refId} is required.`
|
||||
)
|
||||
}
|
||||
|
||||
const quantityAvailable = MathBN.sub(
|
||||
existing!.detail?.shipped_quantity ?? 0,
|
||||
existing!.detail?.return_requested_quantity ?? 0
|
||||
)
|
||||
|
||||
const greater = MathBN.gt(action.details?.quantity, quantityAvailable)
|
||||
if (greater) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Cannot request to return more items than what was shipped for item ${refId}.`
|
||||
)
|
||||
}
|
||||
},
|
||||
})
|
||||
72
packages/modules/order/src/utils/actions/ship-item.ts
Normal file
72
packages/modules/order/src/utils/actions/ship-item.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { MathBN, MedusaError, isDefined } from "@medusajs/utils"
|
||||
import { ChangeActionType } from "../action-key"
|
||||
import { OrderChangeProcessing } from "../calculate-order-change"
|
||||
|
||||
OrderChangeProcessing.registerActionType(ChangeActionType.SHIP_ITEM, {
|
||||
operation({ action, currentOrder }) {
|
||||
const existing = currentOrder.items.find(
|
||||
(item) => item.id === action.details.reference_id
|
||||
)!
|
||||
|
||||
existing.detail.shipped_quantity ??= 0
|
||||
|
||||
existing.detail.shipped_quantity = MathBN.add(
|
||||
existing.detail.shipped_quantity,
|
||||
action.details.quantity
|
||||
)
|
||||
},
|
||||
revert({ action, currentOrder }) {
|
||||
const existing = currentOrder.items.find(
|
||||
(item) => item.id === action.reference_id
|
||||
)!
|
||||
|
||||
existing.detail.shipped_quantity = MathBN.sub(
|
||||
existing.detail.shipped_quantity,
|
||||
action.details.quantity
|
||||
)
|
||||
},
|
||||
validate({ action, currentOrder }) {
|
||||
const refId = action.details?.reference_id
|
||||
if (!isDefined(refId)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
"Reference ID is required."
|
||||
)
|
||||
}
|
||||
|
||||
const existing = currentOrder.items.find((item) => item.id === refId)
|
||||
if (!existing) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Reference ID "${refId}" not found.`
|
||||
)
|
||||
}
|
||||
|
||||
if (!action.details?.quantity) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Quantity to ship of item ${refId} is required.`
|
||||
)
|
||||
}
|
||||
|
||||
if (MathBN.lt(action.details?.quantity, 1)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Quantity of item ${refId} must be greater than 0.`
|
||||
)
|
||||
}
|
||||
|
||||
const notShipped = MathBN.sub(
|
||||
existing.detail?.fulfilled_quantity,
|
||||
existing.detail?.shipped_quantity
|
||||
)
|
||||
|
||||
const greater = MathBN.gt(action.details?.quantity, notShipped)
|
||||
if (greater) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Cannot ship more items than what was fulfilled for item ${refId}.`
|
||||
)
|
||||
}
|
||||
},
|
||||
})
|
||||
46
packages/modules/order/src/utils/actions/shipping-add.ts
Normal file
46
packages/modules/order/src/utils/actions/shipping-add.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { MedusaError, isDefined } from "@medusajs/utils"
|
||||
import { ChangeActionType } from "../action-key"
|
||||
import { OrderChangeProcessing } from "../calculate-order-change"
|
||||
|
||||
OrderChangeProcessing.registerActionType(ChangeActionType.SHIPPING_ADD, {
|
||||
operation({ action, currentOrder }) {
|
||||
const shipping = Array.isArray(currentOrder.shipping_methods)
|
||||
? currentOrder.shipping_methods
|
||||
: [currentOrder.shipping_methods]
|
||||
|
||||
shipping.push({
|
||||
id: action.reference_id!,
|
||||
price: action.amount as number,
|
||||
})
|
||||
|
||||
currentOrder.shipping_methods = shipping
|
||||
},
|
||||
revert({ action, currentOrder }) {
|
||||
const shipping = Array.isArray(currentOrder.shipping_methods)
|
||||
? currentOrder.shipping_methods
|
||||
: [currentOrder.shipping_methods]
|
||||
|
||||
const existingIndex = shipping.findIndex(
|
||||
(item) => item.id === action.reference_id
|
||||
)
|
||||
|
||||
if (existingIndex > -1) {
|
||||
shipping.splice(existingIndex, 1)
|
||||
}
|
||||
},
|
||||
validate({ action }) {
|
||||
if (!action.reference_id) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
"Reference ID is required."
|
||||
)
|
||||
}
|
||||
|
||||
if (!isDefined(action.amount)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
"Amount is required."
|
||||
)
|
||||
}
|
||||
},
|
||||
})
|
||||
61
packages/modules/order/src/utils/actions/write-off-item.ts
Normal file
61
packages/modules/order/src/utils/actions/write-off-item.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { MathBN, MedusaError, isDefined } from "@medusajs/utils"
|
||||
import { ChangeActionType } from "../action-key"
|
||||
import { OrderChangeProcessing } from "../calculate-order-change"
|
||||
|
||||
OrderChangeProcessing.registerActionType(ChangeActionType.WRITE_OFF_ITEM, {
|
||||
operation({ action, currentOrder }) {
|
||||
const existing = currentOrder.items.find(
|
||||
(item) => item.id === action.details.reference_id
|
||||
)!
|
||||
|
||||
existing.detail.written_off_quantity ??= 0
|
||||
existing.detail.written_off_quantity = MathBN.add(
|
||||
existing.detail.written_off_quantity,
|
||||
action.details.quantity
|
||||
)
|
||||
},
|
||||
revert({ action, currentOrder }) {
|
||||
const existing = currentOrder.items.find(
|
||||
(item) => item.id === action.details.reference_id
|
||||
)!
|
||||
|
||||
existing.detail.written_off_quantity = MathBN.sub(
|
||||
existing.detail.written_off_quantity,
|
||||
action.details.quantity
|
||||
)
|
||||
},
|
||||
validate({ action, currentOrder }) {
|
||||
const refId = action.details?.reference_id
|
||||
if (!isDefined(refId)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
"Details reference ID is required."
|
||||
)
|
||||
}
|
||||
|
||||
const existing = currentOrder.items.find((item) => item.id === refId)
|
||||
|
||||
if (!existing) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Reference ID "${refId}" not found.`
|
||||
)
|
||||
}
|
||||
|
||||
if (!action.details?.quantity) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Quantity to write-off item ${refId} is required.`
|
||||
)
|
||||
}
|
||||
|
||||
const quantityAvailable = existing!.quantity ?? 0
|
||||
const greater = MathBN.gt(action.details?.quantity, quantityAvailable)
|
||||
if (greater) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
"Cannot claim more items than what was ordered."
|
||||
)
|
||||
}
|
||||
},
|
||||
})
|
||||
412
packages/modules/order/src/utils/calculate-order-change.ts
Normal file
412
packages/modules/order/src/utils/calculate-order-change.ts
Normal file
@@ -0,0 +1,412 @@
|
||||
import { BigNumberInput, OrderSummaryDTO } from "@medusajs/types"
|
||||
import {
|
||||
BigNumber,
|
||||
MathBN,
|
||||
isDefined,
|
||||
transformPropertiesToBigNumber,
|
||||
} from "@medusajs/utils"
|
||||
import {
|
||||
ActionTypeDefinition,
|
||||
EVENT_STATUS,
|
||||
InternalOrderChangeEvent,
|
||||
OrderChangeEvent,
|
||||
OrderSummaryCalculated,
|
||||
OrderTransaction,
|
||||
VirtualOrder,
|
||||
} from "@types"
|
||||
|
||||
type InternalOrderSummary = OrderSummaryCalculated & {
|
||||
futureTemporarySum: BigNumberInput
|
||||
}
|
||||
|
||||
export class OrderChangeProcessing {
|
||||
private static typeDefinition: { [key: string]: ActionTypeDefinition } = {}
|
||||
private static defaultConfig = {
|
||||
awaitRequired: false,
|
||||
isDeduction: false,
|
||||
}
|
||||
|
||||
private order: VirtualOrder
|
||||
private transactions: OrderTransaction[]
|
||||
private actions: InternalOrderChangeEvent[]
|
||||
|
||||
private actionsProcessed: { [key: string]: InternalOrderChangeEvent[] } = {}
|
||||
private groupTotal: Record<string, BigNumberInput> = {}
|
||||
private summary: InternalOrderSummary
|
||||
|
||||
public static registerActionType(key: string, type: ActionTypeDefinition) {
|
||||
OrderChangeProcessing.typeDefinition[key] = type
|
||||
}
|
||||
|
||||
constructor({
|
||||
order,
|
||||
transactions,
|
||||
actions,
|
||||
}: {
|
||||
order: VirtualOrder
|
||||
transactions: OrderTransaction[]
|
||||
actions: InternalOrderChangeEvent[]
|
||||
}) {
|
||||
this.order = JSON.parse(JSON.stringify(order))
|
||||
this.transactions = JSON.parse(JSON.stringify(transactions ?? []))
|
||||
this.actions = JSON.parse(JSON.stringify(actions ?? []))
|
||||
|
||||
const transactionTotal = MathBN.add(...transactions.map((tr) => tr.amount))
|
||||
|
||||
transformPropertiesToBigNumber(this.order.metadata)
|
||||
|
||||
this.summary = {
|
||||
futureDifference: 0,
|
||||
futureTemporaryDifference: 0,
|
||||
temporaryDifference: 0,
|
||||
pendingDifference: 0,
|
||||
futureTemporarySum: 0,
|
||||
differenceSum: 0,
|
||||
currentOrderTotal: this.order.total ?? 0,
|
||||
originalOrderTotal: this.order.total ?? 0,
|
||||
transactionTotal,
|
||||
}
|
||||
}
|
||||
|
||||
private isEventActive(action: InternalOrderChangeEvent): boolean {
|
||||
const status = action.status
|
||||
return (
|
||||
status === undefined ||
|
||||
status === EVENT_STATUS.PENDING ||
|
||||
status === EVENT_STATUS.DONE
|
||||
)
|
||||
}
|
||||
private isEventDone(action: InternalOrderChangeEvent): boolean {
|
||||
const status = action.status
|
||||
return status === EVENT_STATUS.DONE
|
||||
}
|
||||
|
||||
private isEventPending(action: InternalOrderChangeEvent): boolean {
|
||||
const status = action.status
|
||||
return status === undefined || status === EVENT_STATUS.PENDING
|
||||
}
|
||||
|
||||
public processActions() {
|
||||
for (const action of this.actions) {
|
||||
this.processAction_(action)
|
||||
}
|
||||
|
||||
const summary = this.summary
|
||||
for (const action of this.actions) {
|
||||
if (!this.isEventActive(action)) {
|
||||
continue
|
||||
}
|
||||
|
||||
const type = {
|
||||
...OrderChangeProcessing.defaultConfig,
|
||||
...OrderChangeProcessing.typeDefinition[action.action],
|
||||
}
|
||||
|
||||
const amount = MathBN.mult(action.amount!, type.isDeduction ? -1 : 1)
|
||||
|
||||
if (action.group_id && !action.evaluationOnly) {
|
||||
this.groupTotal[action.group_id] ??= 0
|
||||
this.groupTotal[action.group_id] = MathBN.add(
|
||||
this.groupTotal[action.group_id],
|
||||
amount
|
||||
)
|
||||
}
|
||||
|
||||
if (type.awaitRequired && !this.isEventDone(action)) {
|
||||
if (action.evaluationOnly) {
|
||||
summary.futureTemporarySum = MathBN.add(
|
||||
summary.futureTemporarySum,
|
||||
amount
|
||||
)
|
||||
} else {
|
||||
summary.temporaryDifference = MathBN.add(
|
||||
summary.temporaryDifference,
|
||||
amount
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (action.evaluationOnly) {
|
||||
summary.futureDifference = MathBN.add(summary.futureDifference, amount)
|
||||
} else {
|
||||
if (!this.isEventDone(action) && !action.group_id) {
|
||||
summary.differenceSum = MathBN.add(summary.differenceSum, amount)
|
||||
}
|
||||
summary.currentOrderTotal = MathBN.add(
|
||||
summary.currentOrderTotal,
|
||||
amount
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const groupSum = MathBN.add(...Object.values(this.groupTotal))
|
||||
|
||||
summary.differenceSum = MathBN.add(summary.differenceSum, groupSum)
|
||||
|
||||
summary.transactionTotal = MathBN.sum(
|
||||
...this.transactions.map((tr) => tr.amount)
|
||||
)
|
||||
|
||||
summary.futureTemporaryDifference = MathBN.sub(
|
||||
summary.futureDifference,
|
||||
summary.futureTemporarySum
|
||||
)
|
||||
|
||||
summary.temporaryDifference = MathBN.sub(
|
||||
summary.differenceSum,
|
||||
summary.temporaryDifference
|
||||
)
|
||||
|
||||
summary.pendingDifference = MathBN.sub(
|
||||
summary.currentOrderTotal,
|
||||
summary.transactionTotal
|
||||
)
|
||||
}
|
||||
|
||||
private processAction_(
|
||||
action: InternalOrderChangeEvent,
|
||||
isReplay = false
|
||||
): BigNumberInput | void {
|
||||
const type = {
|
||||
...OrderChangeProcessing.defaultConfig,
|
||||
...OrderChangeProcessing.typeDefinition[action.action],
|
||||
}
|
||||
|
||||
this.actionsProcessed[action.action] ??= []
|
||||
|
||||
if (!isReplay) {
|
||||
this.actionsProcessed[action.action].push(action)
|
||||
}
|
||||
|
||||
let previousEvents: InternalOrderChangeEvent[] | undefined
|
||||
if (type.commitsAction) {
|
||||
previousEvents = (this.actionsProcessed[type.commitsAction] ?? []).filter(
|
||||
(ac_) =>
|
||||
ac_.reference_id === action.reference_id &&
|
||||
ac_.status !== EVENT_STATUS.VOIDED
|
||||
)
|
||||
}
|
||||
|
||||
let calculatedAmount = action.amount ?? 0
|
||||
const params = {
|
||||
actions: this.actions,
|
||||
action,
|
||||
previousEvents,
|
||||
currentOrder: this.order,
|
||||
summary: this.summary,
|
||||
transactions: this.transactions,
|
||||
type,
|
||||
}
|
||||
if (typeof type.validate === "function") {
|
||||
type.validate(params)
|
||||
}
|
||||
|
||||
if (typeof type.operation === "function") {
|
||||
calculatedAmount = type.operation(params) as BigNumberInput
|
||||
|
||||
// the action.amount has priority over the calculated amount
|
||||
if (!isDefined(action.amount)) {
|
||||
action.amount = calculatedAmount ?? 0
|
||||
}
|
||||
}
|
||||
|
||||
// If an action commits previous ones, replay them with updated values
|
||||
if (type.commitsAction) {
|
||||
for (const previousEvent of previousEvents ?? []) {
|
||||
this.processAction_(previousEvent, true)
|
||||
}
|
||||
}
|
||||
|
||||
if (action.resolve) {
|
||||
if (action.resolve.reference_id) {
|
||||
this.resolveReferences(action)
|
||||
}
|
||||
const groupId = action.resolve.group_id ?? "__default"
|
||||
if (action.resolve.group_id) {
|
||||
// resolve all actions in the same group
|
||||
this.resolveGroup(action)
|
||||
}
|
||||
if (action.resolve.amount && !action.evaluationOnly) {
|
||||
this.groupTotal[groupId] ??= 0
|
||||
this.groupTotal[groupId] = MathBN.sub(
|
||||
this.groupTotal[groupId],
|
||||
action.resolve.amount
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return calculatedAmount
|
||||
}
|
||||
|
||||
private resolveReferences(self: InternalOrderChangeEvent) {
|
||||
const resolve = self.resolve
|
||||
const resolveType = OrderChangeProcessing.typeDefinition[self.action]
|
||||
|
||||
Object.keys(this.actionsProcessed).forEach((actionKey) => {
|
||||
const type = OrderChangeProcessing.typeDefinition[actionKey]
|
||||
|
||||
const actions = this.actionsProcessed[actionKey]
|
||||
|
||||
for (const action of actions) {
|
||||
if (
|
||||
action === self ||
|
||||
!this.isEventPending(action) ||
|
||||
action.reference_id !== resolve?.reference_id
|
||||
) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (type.revert && (action.evaluationOnly || resolveType.void)) {
|
||||
let previousEvents: InternalOrderChangeEvent[] | undefined
|
||||
if (type.commitsAction) {
|
||||
previousEvents = (
|
||||
this.actionsProcessed[type.commitsAction] ?? []
|
||||
).filter(
|
||||
(ac_) =>
|
||||
ac_.reference_id === action.reference_id &&
|
||||
ac_.status !== EVENT_STATUS.VOIDED
|
||||
)
|
||||
}
|
||||
|
||||
type.revert({
|
||||
actions: this.actions,
|
||||
action,
|
||||
previousEvents,
|
||||
currentOrder: this.order,
|
||||
summary: this.summary,
|
||||
transactions: this.transactions,
|
||||
type,
|
||||
})
|
||||
|
||||
for (const previousEvent of previousEvents ?? []) {
|
||||
this.processAction_(previousEvent, true)
|
||||
}
|
||||
|
||||
action.status =
|
||||
action.evaluationOnly || resolveType.void
|
||||
? EVENT_STATUS.VOIDED
|
||||
: EVENT_STATUS.DONE
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private resolveGroup(self: InternalOrderChangeEvent) {
|
||||
const resolve = self.resolve
|
||||
|
||||
Object.keys(this.actionsProcessed).forEach((actionKey) => {
|
||||
const type = OrderChangeProcessing.typeDefinition[actionKey]
|
||||
const actions = this.actionsProcessed[actionKey]
|
||||
for (const action of actions) {
|
||||
if (!resolve?.group_id || action?.group_id !== resolve.group_id) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (
|
||||
type.revert &&
|
||||
action.status !== EVENT_STATUS.DONE &&
|
||||
action.status !== EVENT_STATUS.VOIDED &&
|
||||
(action.evaluationOnly || type.void)
|
||||
) {
|
||||
let previousEvents: InternalOrderChangeEvent[] | undefined
|
||||
if (type.commitsAction) {
|
||||
previousEvents = (
|
||||
this.actionsProcessed[type.commitsAction] ?? []
|
||||
).filter(
|
||||
(ac_) =>
|
||||
ac_.reference_id === action.reference_id &&
|
||||
ac_.status !== EVENT_STATUS.VOIDED
|
||||
)
|
||||
}
|
||||
|
||||
type.revert({
|
||||
actions: this.actions,
|
||||
action: action,
|
||||
previousEvents,
|
||||
currentOrder: this.order,
|
||||
summary: this.summary,
|
||||
transactions: this.transactions,
|
||||
type: OrderChangeProcessing.typeDefinition[action.action],
|
||||
})
|
||||
|
||||
for (const previousEvent of previousEvents ?? []) {
|
||||
this.processAction_(previousEvent, true)
|
||||
}
|
||||
|
||||
action.status =
|
||||
action.evaluationOnly || type.void
|
||||
? EVENT_STATUS.VOIDED
|
||||
: EVENT_STATUS.DONE
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
public getSummary(): OrderSummaryDTO {
|
||||
const summary = this.summary
|
||||
const orderSummary = {
|
||||
transactionTotal: new BigNumber(summary.transactionTotal),
|
||||
originalOrderTotal: new BigNumber(summary.originalOrderTotal),
|
||||
currentOrderTotal: new BigNumber(summary.currentOrderTotal),
|
||||
temporaryDifference: new BigNumber(summary.temporaryDifference),
|
||||
futureDifference: new BigNumber(summary.futureDifference),
|
||||
futureTemporaryDifference: new BigNumber(
|
||||
summary.futureTemporaryDifference
|
||||
),
|
||||
pendingDifference: new BigNumber(summary.pendingDifference),
|
||||
differenceSum: new BigNumber(summary.differenceSum),
|
||||
} as unknown as OrderSummaryDTO
|
||||
|
||||
/*
|
||||
{
|
||||
total: summary.currentOrderTotal
|
||||
|
||||
subtotal: number
|
||||
total_tax: number
|
||||
|
||||
ordered_total: summary.originalOrderTotal
|
||||
fulfilled_total: number
|
||||
returned_total: number
|
||||
return_request_total: number
|
||||
write_off_total: number
|
||||
projected_total: number
|
||||
|
||||
net_total: number
|
||||
net_subtotal: number
|
||||
net_total_tax: number
|
||||
|
||||
future_total: number
|
||||
future_subtotal: number
|
||||
future_total_tax: number
|
||||
future_projected_total: number
|
||||
|
||||
balance: summary.pendingDifference
|
||||
future_balance: number
|
||||
}
|
||||
*/
|
||||
|
||||
return orderSummary
|
||||
}
|
||||
|
||||
public getCurrentOrder(): VirtualOrder {
|
||||
return this.order
|
||||
}
|
||||
}
|
||||
|
||||
export function calculateOrderChange({
|
||||
order,
|
||||
transactions = [],
|
||||
actions = [],
|
||||
}: {
|
||||
order: VirtualOrder
|
||||
transactions?: OrderTransaction[]
|
||||
actions?: OrderChangeEvent[]
|
||||
}) {
|
||||
const calc = new OrderChangeProcessing({ order, transactions, actions })
|
||||
calc.processActions()
|
||||
|
||||
return {
|
||||
summary: calc.getSummary(),
|
||||
order: calc.getCurrentOrder(),
|
||||
}
|
||||
}
|
||||
3
packages/modules/order/src/utils/index.ts
Normal file
3
packages/modules/order/src/utils/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from "./action-key"
|
||||
export * from "./actions"
|
||||
export * from "./calculate-order-change"
|
||||
123
packages/modules/order/src/utils/transform-order.ts
Normal file
123
packages/modules/order/src/utils/transform-order.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
import { OrderTypes } from "@medusajs/types"
|
||||
import {
|
||||
createRawPropertiesFromBigNumber,
|
||||
decorateCartTotals,
|
||||
deduplicate,
|
||||
isDefined,
|
||||
} from "@medusajs/utils"
|
||||
|
||||
export function formatOrder(
|
||||
order,
|
||||
options: {
|
||||
includeTotals?: boolean
|
||||
}
|
||||
): OrderTypes.OrderDTO | OrderTypes.OrderDTO[] {
|
||||
const isArray = Array.isArray(order)
|
||||
const orders = [...(isArray ? order : [order])]
|
||||
|
||||
orders.map((order) => {
|
||||
order.items = order.items?.map((orderItem) => {
|
||||
const detail = { ...orderItem }
|
||||
delete detail.order
|
||||
delete detail.item
|
||||
|
||||
return {
|
||||
...orderItem.item,
|
||||
quantity: detail.quantity,
|
||||
raw_quantity: detail.raw_quantity,
|
||||
detail,
|
||||
}
|
||||
})
|
||||
|
||||
order.shipping_methods = order.shipping_methods?.map((shippingMethod) => {
|
||||
const sm = { ...shippingMethod.shipping_method }
|
||||
|
||||
delete shippingMethod.shipping_method
|
||||
return {
|
||||
...sm,
|
||||
order_id: shippingMethod.order_id,
|
||||
detail: {
|
||||
...shippingMethod,
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
order.summary = order.summary?.[0]?.totals
|
||||
|
||||
return options?.includeTotals
|
||||
? createRawPropertiesFromBigNumber(decorateCartTotals(order))
|
||||
: order
|
||||
})
|
||||
|
||||
return isArray ? orders : orders[0]
|
||||
}
|
||||
|
||||
export function mapRepositoryToOrderModel(config) {
|
||||
const conf = { ...config }
|
||||
|
||||
function replace(obj, type): string[] | undefined {
|
||||
if (!isDefined(obj[type])) {
|
||||
return
|
||||
}
|
||||
|
||||
return deduplicate(
|
||||
obj[type].sort().map((rel) => {
|
||||
if (rel == "items.quantity") {
|
||||
if (type === "fields") {
|
||||
obj.populate.push("items.item")
|
||||
}
|
||||
return "items.item.quantity"
|
||||
}
|
||||
if (rel == "summary" && type === "fields") {
|
||||
obj.populate.push("summary")
|
||||
return "summary.totals"
|
||||
} else if (
|
||||
rel.includes("shipping_methods") &&
|
||||
!rel.includes("shipping_methods.shipping_method")
|
||||
) {
|
||||
obj.populate.push("shipping_methods.shipping_method")
|
||||
|
||||
return rel.replace(
|
||||
"shipping_methods",
|
||||
"shipping_methods.shipping_method"
|
||||
)
|
||||
} else if (rel.includes("items.detail")) {
|
||||
return rel.replace("items.detail", "items")
|
||||
} else if (rel == "items") {
|
||||
return "items.item"
|
||||
} else if (rel.includes("items.") && !rel.includes("items.item")) {
|
||||
return rel.replace("items.", "items.item.")
|
||||
}
|
||||
return rel
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
conf.options.fields = replace(config.options, "fields")
|
||||
conf.options.populate = replace(config.options, "populate")
|
||||
|
||||
if (conf.where?.items) {
|
||||
const original = { ...conf.where.items }
|
||||
if (original.detail) {
|
||||
delete conf.where.items.detail
|
||||
}
|
||||
|
||||
conf.where.items = {
|
||||
item: conf.where?.items,
|
||||
}
|
||||
|
||||
if (original.quantity) {
|
||||
conf.where.items.quantity = original.quantity
|
||||
delete conf.where.items.item.quantity
|
||||
}
|
||||
|
||||
if (original.detail) {
|
||||
conf.where.items = {
|
||||
...original.detail,
|
||||
...conf.where.items,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return conf
|
||||
}
|
||||
Reference in New Issue
Block a user