Montify stores integration: multi-store connections, customer/order/transaction sync, webhooks
This commit is contained in:
@@ -0,0 +1,162 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE IF NOT EXISTS "MontifyConnection" (
|
||||
"id" TEXT NOT NULL,
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"label" TEXT NOT NULL,
|
||||
"baseUrl" TEXT NOT NULL,
|
||||
"storeId" TEXT NOT NULL DEFAULT '',
|
||||
"tokenCiphertext" TEXT NOT NULL,
|
||||
"tokenIv" TEXT NOT NULL,
|
||||
"tokenTag" TEXT NOT NULL,
|
||||
"tokenLast4" TEXT NOT NULL DEFAULT '',
|
||||
"enabled" BOOLEAN NOT NULL DEFAULT true,
|
||||
"webhookRemoteId" TEXT,
|
||||
"webhookSecretCiphertext" TEXT,
|
||||
"webhookSecretIv" TEXT,
|
||||
"webhookSecretTag" TEXT,
|
||||
"customersCursor" TIMESTAMP(3),
|
||||
"syncStatus" TEXT NOT NULL DEFAULT 'idle',
|
||||
"syncStartedAt" TIMESTAMP(3),
|
||||
"lastSyncAt" TIMESTAMP(3),
|
||||
"lastSyncResult" JSONB,
|
||||
"lastHealthAt" TIMESTAMP(3),
|
||||
"lastHealthOk" BOOLEAN,
|
||||
"lastError" TEXT,
|
||||
"lastWebhookAt" TIMESTAMP(3),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "MontifyConnection_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE IF NOT EXISTS "MontifyLink" (
|
||||
"id" TEXT NOT NULL,
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"connectionId" TEXT NOT NULL,
|
||||
"entityType" TEXT NOT NULL,
|
||||
"externalId" TEXT NOT NULL,
|
||||
"entityId" TEXT NOT NULL,
|
||||
"externalUpdatedAt" TIMESTAMP(3),
|
||||
"ordersSyncedAt" TIMESTAMP(3),
|
||||
"data" JSONB,
|
||||
"syncedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "MontifyLink_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE IF NOT EXISTS "MontifyOrder" (
|
||||
"id" TEXT NOT NULL,
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"connectionId" TEXT NOT NULL,
|
||||
"externalId" TEXT NOT NULL,
|
||||
"customerExternalId" TEXT,
|
||||
"personId" TEXT,
|
||||
"orderReference" TEXT,
|
||||
"orderStatus" TEXT,
|
||||
"paymentStatus" TEXT,
|
||||
"paymentType" TEXT,
|
||||
"totalPrice" DECIMAL(20,2),
|
||||
"discountTotalPrice" DECIMAL(20,2),
|
||||
"totalDiscounts" DECIMAL(20,2),
|
||||
"totalTax" DECIMAL(20,2),
|
||||
"totalQty" DECIMAL(14,3),
|
||||
"profit" DECIMAL(20,2),
|
||||
"percentProfit" DECIMAL(10,3),
|
||||
"sumGold" DECIMAL(14,3),
|
||||
"sumSilver" DECIMAL(14,3),
|
||||
"address" JSONB,
|
||||
"note" TEXT,
|
||||
"cancelReason" TEXT,
|
||||
"cancelledAt" TIMESTAMP(3),
|
||||
"closedAt" TIMESTAMP(3),
|
||||
"codeDiscount" TEXT,
|
||||
"items" JSONB NOT NULL DEFAULT '[]',
|
||||
"externalCreatedAt" TIMESTAMP(3),
|
||||
"externalUpdatedAt" TIMESTAMP(3),
|
||||
"deletedAt" TIMESTAMP(3),
|
||||
"raw" JSONB,
|
||||
"syncedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "MontifyOrder_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE IF NOT EXISTS "MontifyTransaction" (
|
||||
"id" TEXT NOT NULL,
|
||||
"organizationId" TEXT NOT NULL,
|
||||
"connectionId" TEXT NOT NULL,
|
||||
"externalId" TEXT NOT NULL,
|
||||
"customerExternalId" TEXT,
|
||||
"personId" TEXT,
|
||||
"type" TEXT,
|
||||
"amount" DECIMAL(24,4),
|
||||
"currency" TEXT,
|
||||
"status" TEXT,
|
||||
"referenceCode" TEXT,
|
||||
"externalCreatedAt" TIMESTAMP(3),
|
||||
"raw" JSONB,
|
||||
"syncedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "MontifyTransaction_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE IF NOT EXISTS "MontifyWebhookDelivery" (
|
||||
"id" TEXT NOT NULL,
|
||||
"connectionId" TEXT NOT NULL,
|
||||
"deliveryId" TEXT NOT NULL,
|
||||
"event" TEXT NOT NULL,
|
||||
"status" TEXT NOT NULL DEFAULT 'received',
|
||||
"error" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "MontifyWebhookDelivery_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX IF NOT EXISTS "MontifyConnection_organizationId_enabled_idx" ON "MontifyConnection"("organizationId", "enabled");
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "MontifyLink_connectionId_entityType_externalId_key" ON "MontifyLink"("connectionId", "entityType", "externalId");
|
||||
CREATE INDEX IF NOT EXISTS "MontifyLink_organizationId_entityType_entityId_idx" ON "MontifyLink"("organizationId", "entityType", "entityId");
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "MontifyOrder_connectionId_externalId_key" ON "MontifyOrder"("connectionId", "externalId");
|
||||
CREATE INDEX IF NOT EXISTS "MontifyOrder_organizationId_personId_idx" ON "MontifyOrder"("organizationId", "personId");
|
||||
CREATE INDEX IF NOT EXISTS "MontifyOrder_organizationId_externalCreatedAt_idx" ON "MontifyOrder"("organizationId", "externalCreatedAt");
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "MontifyTransaction_connectionId_externalId_key" ON "MontifyTransaction"("connectionId", "externalId");
|
||||
CREATE INDEX IF NOT EXISTS "MontifyTransaction_organizationId_personId_idx" ON "MontifyTransaction"("organizationId", "personId");
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "MontifyWebhookDelivery_connectionId_deliveryId_key" ON "MontifyWebhookDelivery"("connectionId", "deliveryId");
|
||||
CREATE INDEX IF NOT EXISTS "MontifyWebhookDelivery_connectionId_createdAt_idx" ON "MontifyWebhookDelivery"("connectionId", "createdAt");
|
||||
|
||||
-- AddForeignKey
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "MontifyConnection" ADD CONSTRAINT "MontifyConnection_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "MontifyLink" ADD CONSTRAINT "MontifyLink_connectionId_fkey" FOREIGN KEY ("connectionId") REFERENCES "MontifyConnection"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "MontifyOrder" ADD CONSTRAINT "MontifyOrder_connectionId_fkey" FOREIGN KEY ("connectionId") REFERENCES "MontifyConnection"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "MontifyTransaction" ADD CONSTRAINT "MontifyTransaction_connectionId_fkey" FOREIGN KEY ("connectionId") REFERENCES "MontifyConnection"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "MontifyWebhookDelivery" ADD CONSTRAINT "MontifyWebhookDelivery_connectionId_fkey" FOREIGN KEY ("connectionId") REFERENCES "MontifyConnection"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
|
||||
|
||||
-- ماژول جدید برای محیطهایی که فهرست ماژول ذخیرهشده دارند و ووکامرس فعال است
|
||||
UPDATE "Organization"
|
||||
SET "enabledModules" = array_append("enabledModules", 'montify')
|
||||
WHERE cardinality("enabledModules") > 0
|
||||
AND 'woocommerce' = ANY("enabledModules")
|
||||
AND NOT ('montify' = ANY("enabledModules"));
|
||||
@@ -201,6 +201,7 @@ model Organization {
|
||||
webhookEndpoints WebhookEndpoint[]
|
||||
smsCampaigns SmsCampaign[]
|
||||
wooCommerceConnections WooCommerceConnection[]
|
||||
montifyConnections MontifyConnection[]
|
||||
voipConnections VoipConnection[]
|
||||
reservationServices ReservationService[]
|
||||
reservationAppointments ReservationAppointment[]
|
||||
@@ -2080,6 +2081,147 @@ model WooCommerceOrderLink {
|
||||
@@index([invoiceId])
|
||||
}
|
||||
|
||||
/// اتصال فروشگاه Montify (هر فروشگاه: Base URL + توکن اختصاصی)
|
||||
model MontifyConnection {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
label String
|
||||
baseUrl String
|
||||
storeId String @default("")
|
||||
tokenCiphertext String
|
||||
tokenIv String
|
||||
tokenTag String
|
||||
tokenLast4 String @default("")
|
||||
enabled Boolean @default(true)
|
||||
webhookRemoteId String?
|
||||
webhookSecretCiphertext String?
|
||||
webhookSecretIv String?
|
||||
webhookSecretTag String?
|
||||
/// بیشترین updated_at مشتریان دریافتشده (برای updated_after)
|
||||
customersCursor DateTime?
|
||||
/// idle | running | ok | error
|
||||
syncStatus String @default("idle")
|
||||
syncStartedAt DateTime?
|
||||
lastSyncAt DateTime?
|
||||
lastSyncResult Json?
|
||||
lastHealthAt DateTime?
|
||||
lastHealthOk Boolean?
|
||||
lastError String?
|
||||
lastWebhookAt DateTime?
|
||||
links MontifyLink[]
|
||||
orders MontifyOrder[]
|
||||
transactions MontifyTransaction[]
|
||||
deliveries MontifyWebhookDelivery[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([organizationId, enabled])
|
||||
}
|
||||
|
||||
/// پیوند مشتری فروشگاه با شخص CRM (entityType = customer، entityId = Person.id)
|
||||
model MontifyLink {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
connectionId String
|
||||
connection MontifyConnection @relation(fields: [connectionId], references: [id], onDelete: Cascade)
|
||||
entityType String
|
||||
externalId String
|
||||
entityId String
|
||||
externalUpdatedAt DateTime?
|
||||
/// آخرین زمان دریافت سفارشهای این مشتری (updated_after سفارشها)
|
||||
ordersSyncedAt DateTime?
|
||||
/// پروفایل فروشگاهی مشتری: wallet_balance، gold_wallet_balance، summary، engagement، …
|
||||
data Json?
|
||||
syncedAt DateTime @default(now())
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([connectionId, entityType, externalId])
|
||||
@@index([organizationId, entityType, entityId])
|
||||
}
|
||||
|
||||
/// سفارش فروشگاه (فقطخواندنی، نگاشت مستند: code → order_reference، sts → order_status)
|
||||
model MontifyOrder {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
connectionId String
|
||||
connection MontifyConnection @relation(fields: [connectionId], references: [id], onDelete: Cascade)
|
||||
externalId String
|
||||
customerExternalId String?
|
||||
personId String?
|
||||
orderReference String?
|
||||
orderStatus String?
|
||||
paymentStatus String?
|
||||
paymentType String?
|
||||
totalPrice Decimal? @db.Decimal(20, 2)
|
||||
discountTotalPrice Decimal? @db.Decimal(20, 2)
|
||||
totalDiscounts Decimal? @db.Decimal(20, 2)
|
||||
totalTax Decimal? @db.Decimal(20, 2)
|
||||
totalQty Decimal? @db.Decimal(14, 3)
|
||||
profit Decimal? @db.Decimal(20, 2)
|
||||
percentProfit Decimal? @db.Decimal(10, 3)
|
||||
sumGold Decimal? @db.Decimal(14, 3)
|
||||
sumSilver Decimal? @db.Decimal(14, 3)
|
||||
address Json?
|
||||
note String?
|
||||
cancelReason String?
|
||||
cancelledAt DateTime?
|
||||
closedAt DateTime?
|
||||
codeDiscount String?
|
||||
items Json @default("[]")
|
||||
externalCreatedAt DateTime?
|
||||
externalUpdatedAt DateTime?
|
||||
deletedAt DateTime?
|
||||
raw Json?
|
||||
syncedAt DateTime @default(now())
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([connectionId, externalId])
|
||||
@@index([organizationId, personId])
|
||||
@@index([organizationId, externalCreatedAt])
|
||||
}
|
||||
|
||||
/// تراکنش مالی مشتری در فروشگاه (واریز/برداشت ریالی یا گرم طلا)
|
||||
model MontifyTransaction {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
connectionId String
|
||||
connection MontifyConnection @relation(fields: [connectionId], references: [id], onDelete: Cascade)
|
||||
externalId String
|
||||
customerExternalId String?
|
||||
personId String?
|
||||
type String?
|
||||
amount Decimal? @db.Decimal(24, 4)
|
||||
currency String?
|
||||
status String?
|
||||
referenceCode String?
|
||||
externalCreatedAt DateTime?
|
||||
raw Json?
|
||||
syncedAt DateTime @default(now())
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([connectionId, externalId])
|
||||
@@index([organizationId, personId])
|
||||
}
|
||||
|
||||
model MontifyWebhookDelivery {
|
||||
id String @id @default(cuid())
|
||||
connectionId String
|
||||
connection MontifyConnection @relation(fields: [connectionId], references: [id], onDelete: Cascade)
|
||||
deliveryId String
|
||||
event String
|
||||
/// received | processed | failed
|
||||
status String @default("received")
|
||||
error String?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@unique([connectionId, deliveryId])
|
||||
@@index([connectionId, createdAt])
|
||||
}
|
||||
|
||||
/// اتصال تلفن سازمانی / سانترال (وبهوک عمومی)
|
||||
model VoipConnection {
|
||||
id String @id @default(cuid())
|
||||
|
||||
Reference in New Issue
Block a user