feat: add per-org SMS wallet with adm panel and header credit
Bill all platform SMS (including OTP), allow negative balance with manual/auto cutoffs, and support own-panel bypass without wallet debit.
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "SmsAccount" (
|
||||
"id" TEXT NOT NULL,
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"balanceRials" INTEGER NOT NULL DEFAULT 0,
|
||||
"pricePerPartRials" INTEGER NOT NULL DEFAULT 2500,
|
||||
"isBlocked" BOOLEAN NOT NULL DEFAULT false,
|
||||
"autoBlockBelowRials" INTEGER,
|
||||
"alertCriticalRials" INTEGER NOT NULL DEFAULT 10000,
|
||||
"alertWarningRials" INTEGER NOT NULL DEFAULT 100000,
|
||||
"panelMode" TEXT NOT NULL DEFAULT 'platform',
|
||||
"ownPanelType" TEXT NOT NULL DEFAULT '0098',
|
||||
"ownPanelUsername" TEXT,
|
||||
"ownPanelPassword" TEXT,
|
||||
"ownPanelFrom" TEXT,
|
||||
"chargeCard" TEXT,
|
||||
"chargeIban" TEXT,
|
||||
"chargeHolder" TEXT,
|
||||
"chargeInstruction" TEXT,
|
||||
"alertDaysSent" INTEGER NOT NULL DEFAULT 0,
|
||||
"lastAlertDate" TIMESTAMP(3),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "SmsAccount_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "SmsLedger" (
|
||||
"id" TEXT NOT NULL,
|
||||
"smsAccountId" TEXT NOT NULL,
|
||||
"type" TEXT NOT NULL,
|
||||
"amountRials" INTEGER NOT NULL,
|
||||
"balanceAfterRials" INTEGER NOT NULL,
|
||||
"parts" INTEGER,
|
||||
"pricePerPartRials" INTEGER,
|
||||
"note" TEXT,
|
||||
"smsSendLogId" TEXT,
|
||||
"createdById" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "SmsLedger_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "SmsBillingSendLog" (
|
||||
"id" TEXT NOT NULL,
|
||||
"smsAccountId" TEXT NOT NULL,
|
||||
"receiver" TEXT NOT NULL,
|
||||
"body" TEXT NOT NULL,
|
||||
"parts" INTEGER NOT NULL,
|
||||
"pricePerPartRials" INTEGER NOT NULL,
|
||||
"totalAmountRials" INTEGER NOT NULL,
|
||||
"provider" TEXT,
|
||||
"source" TEXT,
|
||||
"isAlert" BOOLEAN NOT NULL DEFAULT false,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "SmsBillingSendLog_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "SmsAccount_organizationId_key" ON "SmsAccount"("organizationId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "SmsAccount_isBlocked_idx" ON "SmsAccount"("isBlocked");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "SmsAccount_balanceRials_idx" ON "SmsAccount"("balanceRials");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "SmsLedger_smsAccountId_createdAt_idx" ON "SmsLedger"("smsAccountId", "createdAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "SmsLedger_type_idx" ON "SmsLedger"("type");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "SmsBillingSendLog_smsAccountId_createdAt_idx" ON "SmsBillingSendLog"("smsAccountId", "createdAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "SmsBillingSendLog_source_idx" ON "SmsBillingSendLog"("source");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "SmsAccount" ADD CONSTRAINT "SmsAccount_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "SmsLedger" ADD CONSTRAINT "SmsLedger_smsAccountId_fkey" FOREIGN KEY ("smsAccountId") REFERENCES "SmsAccount"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "SmsBillingSendLog" ADD CONSTRAINT "SmsBillingSendLog_smsAccountId_fkey" FOREIGN KEY ("smsAccountId") REFERENCES "SmsAccount"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -206,6 +206,7 @@ model Organization {
|
||||
webhookEndpoints WebhookEndpoint[]
|
||||
smsCampaigns SmsCampaign[]
|
||||
outboundSmsLogs OutboundSmsLog[]
|
||||
smsAccount SmsAccount?
|
||||
financialAccounts FinancialAccount[]
|
||||
financialCategories FinancialCategory[]
|
||||
financialDocuments FinancialDocument[]
|
||||
@@ -2290,6 +2291,78 @@ model FinancialInstallment {
|
||||
@@index([dueDate])
|
||||
}
|
||||
|
||||
/// کیفپول و تنظیمات پیامک هر محیط (الگوی همکار / سوپرادمین آبشُده)
|
||||
model SmsAccount {
|
||||
id String @id @default(cuid())
|
||||
organizationId String @unique
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
balanceRials Int @default(0)
|
||||
pricePerPartRials Int @default(2500)
|
||||
isBlocked Boolean @default(false)
|
||||
/// اگر ست باشد: وقتی موجودی < این مقدار، ارسال قطع میشود (میتواند منفی باشد). null = فقط کلید دستی
|
||||
autoBlockBelowRials Int?
|
||||
alertCriticalRials Int @default(10000)
|
||||
alertWarningRials Int @default(100000)
|
||||
/// platform = سامانهٔ ما | own = پنل اختصاصی مشتری (بدون کسر/لاگ کیف)
|
||||
panelMode String @default("platform")
|
||||
/// وقتی panelMode=own: 0098 | asanak | trez
|
||||
ownPanelType String @default("0098")
|
||||
ownPanelUsername String?
|
||||
ownPanelPassword String?
|
||||
ownPanelFrom String?
|
||||
chargeCard String?
|
||||
chargeIban String?
|
||||
chargeHolder String?
|
||||
chargeInstruction String?
|
||||
alertDaysSent Int @default(0)
|
||||
lastAlertDate DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
ledgers SmsLedger[]
|
||||
sendLogs SmsBillingSendLog[]
|
||||
|
||||
@@index([isBlocked])
|
||||
@@index([balanceRials])
|
||||
}
|
||||
|
||||
model SmsLedger {
|
||||
id String @id @default(cuid())
|
||||
smsAccountId String
|
||||
smsAccount SmsAccount @relation(fields: [smsAccountId], references: [id], onDelete: Cascade)
|
||||
/// charge | debit | alert_debit
|
||||
type String
|
||||
amountRials Int
|
||||
balanceAfterRials Int
|
||||
parts Int?
|
||||
pricePerPartRials Int?
|
||||
note String?
|
||||
smsSendLogId String?
|
||||
createdById String?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([smsAccountId, createdAt])
|
||||
@@index([type])
|
||||
}
|
||||
|
||||
/// لاگ ارسال صورتحسابشده (همهٔ مسیرها وقتی panelMode=platform)
|
||||
model SmsBillingSendLog {
|
||||
id String @id @default(cuid())
|
||||
smsAccountId String
|
||||
smsAccount SmsAccount @relation(fields: [smsAccountId], references: [id], onDelete: Cascade)
|
||||
receiver String
|
||||
body String
|
||||
parts Int
|
||||
pricePerPartRials Int
|
||||
totalAmountRials Int
|
||||
provider String?
|
||||
source String?
|
||||
isAlert Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([smsAccountId, createdAt])
|
||||
@@index([source])
|
||||
}
|
||||
|
||||
/// لاگ یکپارچهٔ پیامک خروجی (دستی / کمپین / اتوماسیون)
|
||||
model OutboundSmsLog {
|
||||
id String @id @default(cuid())
|
||||
|
||||
Reference in New Issue
Block a user