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
@@ -34,12 +34,16 @@ export function Settings() {
|
||||
<div className="form-grid">
|
||||
{SETTING_KEYS.map((k) => (
|
||||
<Field key={k} label={t(`admin.settings.${k.replace('.', '_')}`)}>
|
||||
<input
|
||||
className="bc-input"
|
||||
type={typeof draft[k] === 'number' ? 'number' : 'text'}
|
||||
value={String(draft[k])}
|
||||
onChange={(e) => setDraft({ ...draft, [k]: typeof draft[k] === 'number' ? Number(e.target.value) : e.target.value })}
|
||||
/>
|
||||
{typeof draft[k] === 'boolean' ? (
|
||||
<input type="checkbox" checked={draft[k] as boolean} onChange={(e) => setDraft({ ...draft, [k]: e.target.checked })} style={{ width: 22, height: 22 }} />
|
||||
) : (
|
||||
<input
|
||||
className="bc-input"
|
||||
type={typeof draft[k] === 'number' ? 'number' : 'text'}
|
||||
value={String(draft[k])}
|
||||
onChange={(e) => setDraft({ ...draft, [k]: typeof draft[k] === 'number' ? Number(e.target.value) : e.target.value })}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
))}
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user