Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"creationdata",
"criticalhit",
"crystalserver",
"cuid",
"currentmount",
"currenttournamentphase",
"dailyreward",
Expand Down Expand Up @@ -149,6 +150,7 @@
"openapi",
"openssl",
"optiontracking",
"orderform",
"orpc",
"otplib",
"outfitid",
Expand All @@ -162,6 +164,7 @@
"premdays",
"premiumuntil",
"previewstate",
"purchasecomplete",
"pvptype",
"qrcode",
"quickloot",
Expand Down Expand Up @@ -203,6 +206,8 @@
"usecase",
"usecases",
"usehooks",
"uuid",
"vaul",
"verdana",
"vipgroup",
"vipgrouplist",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
-- CreateTable
CREATE TABLE `miforge_shop_orders` (
`id` VARCHAR(191) NOT NULL,
`account_id` INTEGER UNSIGNED NOT NULL,
`payment_option_id` VARCHAR(191) NULL,
`status` ENUM('DRAFT', 'CANCELLED', 'PAID', 'PENDING_PAYMENT', 'REFUNDED', 'CONTESTED') NOT NULL DEFAULT 'DRAFT',
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),

PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- CreateTable
CREATE TABLE `miforge_shop_order_items` (
`id` VARCHAR(191) NOT NULL,
`quantity` INTEGER NOT NULL DEFAULT 1,
`unit_price_cents` INTEGER UNSIGNED NOT NULL,
`total_price_cents` INTEGER UNSIGNED NOT NULL,
`effective_quantity` INTEGER UNSIGNED NOT NULL,
`order_id` VARCHAR(191) NOT NULL,
`product_id` VARCHAR(191) NOT NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),

PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- CreateTable
CREATE TABLE `miforge_shop_products` (
`id` VARCHAR(191) NOT NULL,
`category` ENUM('COINS', 'RECOVERY_KEY', 'CHANGE_NAME') NOT NULL,
`slug` VARCHAR(100) NOT NULL,
`title` VARCHAR(255) NOT NULL,
`description` TEXT NULL,
`enabled` BOOLEAN NOT NULL DEFAULT true,
`base_unit_quantity` INTEGER NOT NULL DEFAULT 1,
`quantity_mode` ENUM('FIXED', 'VARIABLE') NOT NULL,
`min_units` INTEGER UNSIGNED NOT NULL DEFAULT 1,
`max_units` INTEGER UNSIGNED NULL,
`unit_step` INTEGER UNSIGNED NOT NULL DEFAULT 1,
`unit_price_cents` INTEGER UNSIGNED NOT NULL,
`display_unit_label` VARCHAR(32) NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),

UNIQUE INDEX `miforge_shop_products_slug_key`(`slug`),
INDEX `idx_shop_product_slug`(`slug`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- CreateTable
CREATE TABLE `miforge_shop_payment_options` (
`id` VARCHAR(191) NOT NULL,
`provider` ENUM('MERCADO_PAGO') NOT NULL,
`method` ENUM('PIX') NOT NULL,
`enabled` BOOLEAN NOT NULL DEFAULT true,
`label` VARCHAR(100) NOT NULL,
`description` TEXT NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),

UNIQUE INDEX `miforge_shop_payment_options_provider_method_key`(`provider`, `method`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- AddForeignKey
ALTER TABLE `miforge_shop_orders` ADD CONSTRAINT `miforge_shop_orders_account_id_fkey` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE `miforge_shop_orders` ADD CONSTRAINT `miforge_shop_orders_payment_option_id_fkey` FOREIGN KEY (`payment_option_id`) REFERENCES `miforge_shop_payment_options`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE `miforge_shop_order_items` ADD CONSTRAINT `miforge_shop_order_items_order_id_fkey` FOREIGN KEY (`order_id`) REFERENCES `miforge_shop_orders`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE `miforge_shop_order_items` ADD CONSTRAINT `miforge_shop_order_items_product_id_fkey` FOREIGN KEY (`product_id`) REFERENCES `miforge_shop_products`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
1 change: 1 addition & 0 deletions apps/api/prisma/models/base.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ model accounts {
audits miforge_account_audit[]
confirmations miforge_account_confirmations[]
oauths miforge_account_oauths[]
orders miforge_shop_order[]

two_factor_enabled Boolean @default(false)
two_factor_secret String? @db.VarChar(64)
Expand Down
115 changes: 115 additions & 0 deletions apps/api/prisma/models/shop.prisma
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
enum ShopOrderStatus {
DRAFT
CANCELLED
PAID
PENDING_PAYMENT
REFUNDED
CONTESTED
}

model miforge_shop_order {
id String @id @default(uuid(7))

accountId Int @map("account_id") @db.UnsignedInt
account accounts @relation(fields: [accountId], references: [id], onDelete: Cascade)

paymentOptionId String? @map("payment_option_id")
paymentOption miforge_shop_payment_option? @relation(fields: [paymentOptionId], references: [id], onDelete: Restrict)

status ShopOrderStatus @default(DRAFT)

items miforge_shop_order_item[]

createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")

@@map("miforge_shop_orders")
}

model miforge_shop_order_item {
id String @id @default(uuid(7))

quantity Int @default(1)

// Snapshot pricing fields to avoid price changes affecting existing orders
unitPriceCents Int @map("unit_price_cents") @db.UnsignedInt
totalPriceCents Int @map("total_price_cents") @db.UnsignedInt
effectiveQuantity Int @map("effective_quantity") @db.UnsignedInt

orderId String @map("order_id")
order miforge_shop_order @relation(fields: [orderId], references: [id], onDelete: Cascade)

productId String @map("product_id")
product miforge_shop_product @relation(fields: [productId], references: [id], onDelete: Restrict)

createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")

@@map("miforge_shop_order_items")
}

enum ShopProductCategory {
COINS
RECOVERY_KEY
CHANGE_NAME
}

enum ShopProductQuantityMode {
FIXED // e.g, recovery key, premium time.
VARIABLE // e.g., coins
}

model miforge_shop_product {
id String @id @default(uuid(7))

category ShopProductCategory
slug String @unique @db.VarChar(100)
title String @db.VarChar(255)
description String? @db.Text
enabled Boolean @default(true)

baseUnitQuantity Int @default(1) @map("base_unit_quantity")

quantityMode ShopProductQuantityMode @map("quantity_mode")
minUnits Int @default(1) @map("min_units") @db.UnsignedInt
maxUnits Int? @map("max_units") @db.UnsignedInt
unitStep Int @default(1) @map("unit_step") @db.UnsignedInt

unitPriceCents Int @map("unit_price_cents") @db.UnsignedInt
displayUnitLabel String? @map("display_unit_label") @db.VarChar(32)

orders miforge_shop_order_item[]

createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")

@@index([slug], name: "idx_shop_product_slug")
@@map("miforge_shop_products")
}

enum ShopPaymentProvider {
MERCADO_PAGO
}

enum ShopPaymentMethod {
PIX
}

model miforge_shop_payment_option {
id String @id @default(uuid(7))

orders miforge_shop_order[]

provider ShopPaymentProvider
method ShopPaymentMethod

enabled Boolean @default(true)
label String @db.VarChar(100)
description String? @db.Text

createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")

@@unique([provider, method], name: "uniq_shop_payment_option_provider_method")
@@map("miforge_shop_payment_options")
}
44 changes: 44 additions & 0 deletions apps/api/prisma/seed/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,50 @@ async function main() {
}
})

console.log("[seed] Seeding default payment options")
if (env.MERCADO_PAGO_ENABLED) {
await prisma.miforge_shop_payment_option.upsert({
where: {
uniq_shop_payment_option_provider_method: {
method: "PIX",
provider: "MERCADO_PAGO"
}
},
create: {
method: "PIX",
provider: "MERCADO_PAGO",
label: "Mercado Pago - PIX",
enabled: true,
description: "Pay using Mercado Pago's PIX integration.",
},
update: {}
})
}


console.log("[seed] Seeding default product coins")
await prisma.miforge_shop_product.upsert({
where: {
slug: "default-coins",
},
create: {
category: "COINS",
quantityMode: 'VARIABLE',
slug: "default-coins",
title: "Coins",
unitPriceCents: 200, // 25 coins for R$2.00
baseUnitQuantity: 25,
description: "Purchase in-game coins to use on various services.",
displayUnitLabel: "Coins",
enabled: true,
minUnits: 1,
maxUnits: 400,
unitStep: 1,
},
update: {
}
})

for (const config of server_configs) {
const existing = await prisma.server_config.findUnique({
where: {
Expand Down
2 changes: 2 additions & 0 deletions apps/api/src/application/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@ export * from "./lostAccount";
export * from "./players";
export * from "./recoveryKey";
export * from "./session";
export * from "./shopOrder";
export * from "./shopProducts";
export * from "./tibiaclient";
export * from "./worlds";
Loading