Backoffice stage 3: orders and providers, auto-assignment
- Auto-assignment: a new order is offered to the best free provider (same ranking as
the dispatcher hint); a decline or timeout passes it to the next one; nobody is
offered the same order twice; after N tries it waits for a dispatcher and the team
is notified once. The worker retries waiting orders every minute. Settings
assign.auto / assign.maxAutoOffers (toggle on the Orders page, checkbox in old admin).
- Orders: list by day with groups (need a provider, offered, assigned, in progress,
done, cancelled), periods and search; order card with progress, provider or ranked
candidates ("offer" / "pick automatically"), details, checklist and photos,
history in plain words, client, money (superadmin), payment, status change,
reschedule (slots or custom time), cancel with fee.
- New order for a client (from the client card or the Orders page): params form,
address, free slots for 14 days, price with the client's discount.
- Providers: list with rating, orders, declines, low ratings, next order; card with
quality, ratings, upcoming orders, schedule and districts, admission documents,
block/unblock with reason, new bot link, money and payouts (superadmin).
- Payout gets paidAt/note/createdById; Provider gets blockedReason/blockedAt/adminNote
and documents (ProviderDoc).
- Tests for auto-assignment.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
2772837e29
commit
e7de4f5893
33 files changed
+4521
-45
No files matched your search
@@ -0,0 +1,26 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Provider" ADD COLUMN "adminNote" TEXT,
|
||||
ADD COLUMN "blockedAt" TIMESTAMP(3),
|
||||
ADD COLUMN "blockedReason" TEXT;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "ProviderDoc" (
|
||||
"id" TEXT NOT NULL,
|
||||
"providerId" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"fileKey" TEXT NOT NULL,
|
||||
"fileName" TEXT NOT NULL,
|
||||
"mime" TEXT NOT NULL,
|
||||
"size" INTEGER NOT NULL,
|
||||
"uploadedById" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "ProviderDoc_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "ProviderDoc_providerId_idx" ON "ProviderDoc"("providerId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ProviderDoc" ADD CONSTRAINT "ProviderDoc_providerId_fkey" FOREIGN KEY ("providerId") REFERENCES "Provider"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Payout" ADD COLUMN "createdById" TEXT,
|
||||
ADD COLUMN "note" TEXT,
|
||||
ADD COLUMN "paidAt" TIMESTAMP(3);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Payout_providerId_createdAt_idx" ON "Payout"("providerId", "createdAt");
|
||||
|
||||
@@ -290,10 +290,16 @@ model Provider {
|
||||
/// пресет ставок (джун / мидл / прайват); если задан — заменяет rateType/rateValue
|
||||
payoutPresetId String?
|
||||
payoutPreset PayoutPreset? @relation(fields: [payoutPresetId], references: [id])
|
||||
/// допуск: почему заблокирован и когда (active = false)
|
||||
blockedReason String?
|
||||
blockedAt DateTime?
|
||||
/// заметка команды об исполнителе (он не видит)
|
||||
adminNote String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
districts ProviderDistrict[]
|
||||
docs ProviderDoc[]
|
||||
schedule ProviderSchedule[]
|
||||
orders Order[]
|
||||
offers OrderOffer[]
|
||||
@@ -305,6 +311,22 @@ model Provider {
|
||||
chatThreads ChatThread[]
|
||||
}
|
||||
|
||||
/// Документы исполнителя для допуска: паспорт, договор, справка… Файл — в приватном хранилище
|
||||
model ProviderDoc {
|
||||
id String @id @default(cuid())
|
||||
providerId String
|
||||
provider Provider @relation(fields: [providerId], references: [id], onDelete: Cascade)
|
||||
title String
|
||||
fileKey String
|
||||
fileName String
|
||||
mime String
|
||||
size Int
|
||||
uploadedById String?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([providerId])
|
||||
}
|
||||
|
||||
/// Пресет ставок исполнителя: для каждой строки цены — фикс или % (см. packages/core/src/payout.ts)
|
||||
model PayoutPreset {
|
||||
id String @id @default(cuid())
|
||||
@@ -832,7 +854,13 @@ model Payout {
|
||||
periodEnd DateTime
|
||||
amount Int
|
||||
status PayoutStatus @default(DRAFT)
|
||||
/// когда выплачено и как (наличные, перевод…), кто отметил
|
||||
paidAt DateTime?
|
||||
note String?
|
||||
createdById String?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([providerId, createdAt])
|
||||
}
|
||||
|
||||
// ───────────── Админка ─────────────
|
||||
|
||||
Reference in new issue
Block a user