fix(worker-platform): 拼单取消后可重入,大厅置顶始终优先
This commit is contained in:
@@ -174,6 +174,8 @@ function resolveWorkOrderShareJoinError(
|
||||
| 'sharing_disabled'
|
||||
| 'work_order_owner_conflict'
|
||||
| 'sharing_quantity_full'
|
||||
| 'worker_share_exists'
|
||||
| 'worker_share_locked'
|
||||
| 'worker_active_order_limit'
|
||||
| 'worker_deposit_insufficient'
|
||||
| null,
|
||||
@@ -183,6 +185,8 @@ function resolveWorkOrderShareJoinError(
|
||||
sharing_disabled: '该订单未启用拼单',
|
||||
work_order_owner_conflict: '你已整单接取该订单,无需拼单',
|
||||
sharing_quantity_full: '拼单数量已满或超出剩余数量',
|
||||
worker_share_exists: '你已参与该拼单,剩余份数可用「立即抢单」追加',
|
||||
worker_share_locked: '你的拼单份额已提交或已验收,不能再追加份数',
|
||||
worker_active_order_limit: '已达到当前等级最大同时接单量',
|
||||
worker_deposit_insufficient: '余额不足,无法冻结所需押金',
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
resolveWorkOrderShareCancellationStatus,
|
||||
resolveWorkOrderShareDepositAmount,
|
||||
resolveWorkOrderSharingCancellationPlan,
|
||||
resolveWorkOrderShareJoinMode,
|
||||
resolveWorkOrderShareJoinQuantity,
|
||||
resolveOpenSharingSyncReward,
|
||||
} from '../../repositories/worker-platform/index.js'
|
||||
@@ -1660,6 +1661,60 @@ test('拼单份数全部承接后不再显示在抢单大厅', () => {
|
||||
assert.equal(isWorkOrderSharingFilled(false, 15, 15), false)
|
||||
})
|
||||
|
||||
test('拼单份额取消后允许原打手重新加入', () => {
|
||||
assert.equal(resolveWorkOrderShareJoinMode({ existingShareStatus: 'cancelled' }), 'rejoin')
|
||||
assert.equal(
|
||||
resolveWorkOrderShareJoinMode({ existingShareStatus: 'cancelled', takeRemaining: true }),
|
||||
'rejoin',
|
||||
)
|
||||
})
|
||||
|
||||
test('拼单份额未提交时只有立即抢单可以追加份数', () => {
|
||||
assert.equal(
|
||||
resolveWorkOrderShareJoinMode({ existingShareStatus: 'joined', takeRemaining: true }),
|
||||
'append',
|
||||
)
|
||||
assert.equal(resolveWorkOrderShareJoinMode({ existingShareStatus: 'joined' }), 'reject')
|
||||
})
|
||||
|
||||
test('拼单份额已提交或已验收后不再允许追加份数', () => {
|
||||
assert.equal(
|
||||
resolveWorkOrderShareJoinMode({ existingShareStatus: 'submitted', takeRemaining: true }),
|
||||
'reject',
|
||||
)
|
||||
assert.equal(
|
||||
resolveWorkOrderShareJoinMode({ existingShareStatus: 'accepted', takeRemaining: true }),
|
||||
'reject',
|
||||
)
|
||||
})
|
||||
|
||||
test('打手首次参与拼单时新建份额', () => {
|
||||
assert.equal(resolveWorkOrderShareJoinMode({ existingShareStatus: null }), 'create')
|
||||
})
|
||||
|
||||
test('取消的拼单份额重新加入必须复用原行并重置超时与验收状态', async () => {
|
||||
const { readFile } = await import('node:fs/promises')
|
||||
const shareRepoSrc = await readFile(
|
||||
new URL('../../repositories/worker-platform/work-order-share-repo.ts', import.meta.url),
|
||||
'utf8',
|
||||
)
|
||||
assert.ok(
|
||||
shareRepoSrc.includes('resolveWorkOrderShareJoinMode'),
|
||||
'joinWorkOrderShare 必须按份额状态区分新建、追加、重入与拒绝',
|
||||
)
|
||||
assert.ok(
|
||||
shareRepoSrc.includes("status = 'joined',") &&
|
||||
shareRepoSrc.includes('created_at = $5') &&
|
||||
shareRepoSrc.includes('submitted_at = NULL') &&
|
||||
shareRepoSrc.includes('accepted_at = NULL'),
|
||||
'复用 cancelled 份额时必须重置 created_at(超时时钟)与验收时间,避免重入后立即被判超时',
|
||||
)
|
||||
assert.ok(
|
||||
shareRepoSrc.includes('const currentFrozenDeposit = revivingCancelledShare'),
|
||||
'取消份额的押金已退还,重新加入时必须按已有押金为 0 重新计算',
|
||||
)
|
||||
})
|
||||
|
||||
function buildWorkOrderRow(overrides: Partial<WorkOrderRow> = {}): WorkOrderRow {
|
||||
return {
|
||||
id: 1,
|
||||
@@ -3092,6 +3147,25 @@ test('打手端「我的订单」必须走"先取 id 再取详情"的延迟分
|
||||
assert.ok(src.includes('rowsById.get(id)'), 'ANY() 不保证顺序,必须按 id 顺序还原分页结果')
|
||||
})
|
||||
|
||||
test('大厅候选集必须优先保留置顶单,不能被容量上限挤出', async () => {
|
||||
const { readFile } = await import('node:fs/promises')
|
||||
const src = await readFile(
|
||||
new URL('../../repositories/worker-platform/work-order-query-repo.ts', import.meta.url),
|
||||
'utf8',
|
||||
)
|
||||
const start = src.indexOf('function buildHallCandidateIdsSql')
|
||||
const hallSql = src.slice(start, start + 2600)
|
||||
assert.equal(
|
||||
(hallSql.match(/candidate\.pinned_at DESC NULLS LAST/g) || []).length,
|
||||
2,
|
||||
'主分类与子分类的窗口排名都必须优先置顶单',
|
||||
)
|
||||
assert.ok(
|
||||
hallSql.includes('ranked.pinned_at DESC NULLS LAST'),
|
||||
'最终候选集 LIMIT 前必须优先置顶单,否则置顶单会被新单挤出大厅',
|
||||
)
|
||||
})
|
||||
|
||||
test('打手等级筛选必须先把等级解析成打手 id,并用 UNION 形式(不能用 OR + IN 子查询)', async () => {
|
||||
const { readFile } = await import('node:fs/promises')
|
||||
const src = await readFile(
|
||||
|
||||
Reference in New Issue
Block a user