接单平台新增拼单与取消接单能力
拼单功能: - 工单/物品规则支持拼单配置(启用、总数量、单价),总价=单价×数量三方联动,启用拼单时工单金额自动同步拼单总价 - 拼单参与按数量冻结比例押金,验收通过后按份额结算报酬,升级统计按数量计入 - 抢单大厅拼单入口:紫色渐变大按钮带单价展示,拼单进度/剩余份数,弹窗输入数量实时预估报酬与押金 - 我的订单展示拼单份额(数量×单价、状态),拼单者各自提交验收,全部提交后管理员统一验收 - 新增 work_order_shares 表与迁移 008 取消接单: - 进行中订单可取消(押金全额退还、工单回大厅),30 天内限 5 次防滥用
This commit is contained in:
@@ -11,6 +11,9 @@ import {
|
||||
countWorkerActiveOrders,
|
||||
countWorkCategoryUsages,
|
||||
countWorkerLevelUsages,
|
||||
countWorkOrderPendingSharingSubmissions,
|
||||
cancelWorkerWorkOrder,
|
||||
countWorkerCancellationsSince,
|
||||
createWorkOrder,
|
||||
createWorkOrderEvent,
|
||||
createWorkerFinanceRequest,
|
||||
@@ -24,23 +27,29 @@ import {
|
||||
getWorkerLevelById,
|
||||
getWorkerLevelByKey,
|
||||
getWorkerUserByInviteCode,
|
||||
incrementWorkerSessionVersion,
|
||||
getWorkOrderById,
|
||||
getWorkOrderByOrderItemId,
|
||||
getWorkerUserById,
|
||||
getWorkerUserByUsername,
|
||||
listAllWorkCategories,
|
||||
listWorkerFinanceRequests,
|
||||
listPendingMaterialWorkOrdersByPlatformOrderId,
|
||||
listWorkerWalletLedgers,
|
||||
getWorkOrderById,
|
||||
getWorkOrderByOrderItemId,
|
||||
getWorkOrderShare,
|
||||
grabWorkOrder,
|
||||
incrementWorkerSessionVersion,
|
||||
joinWorkOrderShare,
|
||||
listAllWorkCategories,
|
||||
listPendingMaterialWorkOrdersByPlatformOrderId,
|
||||
listWorkerFinanceRequests,
|
||||
listWorkerSharesByWorker,
|
||||
listWorkerWalletLedgers,
|
||||
listWorkCategories,
|
||||
listWorkOrders,
|
||||
listWorkProductRules,
|
||||
listWorkerLevels,
|
||||
listWorkerUsers,
|
||||
listWorkOrderShares,
|
||||
listWorkOrderSharesByOrderIds,
|
||||
resolveProblemWorkOrder,
|
||||
reviewWorkerFinanceRequest,
|
||||
submitWorkOrderShareAcceptance,
|
||||
updateWorkOrder,
|
||||
updateWorkerPassword,
|
||||
updateWorkerUser,
|
||||
@@ -52,6 +61,7 @@ import {
|
||||
type WorkOrderRow,
|
||||
type WorkProductRuleRow,
|
||||
type WorkerLevelRow,
|
||||
type WorkOrderShareRow,
|
||||
type WorkerWalletLedgerRow,
|
||||
type WorkerUserRow,
|
||||
type GrabWorkOrderFailureReason,
|
||||
@@ -88,6 +98,8 @@ const DEFAULT_CATEGORY_KEY = 'default'
|
||||
const DEFAULT_DEPOSIT_THRESHOLD_AMOUNT = 20_000
|
||||
const INVITE_CODE_LENGTH = 8
|
||||
const INVITE_CODE_RETRY_LIMIT = 5
|
||||
const WORKER_CANCEL_LIMIT_PER_WINDOW = 5
|
||||
const WORKER_CANCEL_LIMIT_WINDOW_MS = 30 * 24 * 60 * 60 * 1000
|
||||
const IGNORABLE_WORKER_AUTH_ERROR_CODES = new Set([
|
||||
'worker_auth_required',
|
||||
'worker_auth_invalid',
|
||||
@@ -652,8 +664,16 @@ export async function listWorkerHallOrders(query: JsonObject = {}, session: Work
|
||||
const worker = await getRequiredWorker(session.workerId)
|
||||
const permissions = resolveWorkerPermissions(worker)
|
||||
const categories = (await listWorkCategories()).map(mapWorkCategory)
|
||||
const myShares = await listWorkerSharesByWorker(worker.id)
|
||||
const myShareByOrderId = new Map(
|
||||
myShares
|
||||
.filter((share) => Number(share.work_order_id))
|
||||
.map((share) => [Number(share.work_order_id), share]),
|
||||
)
|
||||
return {
|
||||
items: items.map((item) => mapWorkOrderForWorker(item, permissions)),
|
||||
items: items.map((item) =>
|
||||
mapWorkOrderForWorker(item, permissions, myShareByOrderId.get(Number(item.id))),
|
||||
),
|
||||
pagination: { page, pageSize, total },
|
||||
categories,
|
||||
}
|
||||
@@ -711,15 +731,104 @@ export async function listWorkerMyOrders(query: JsonObject = {}, session: Worker
|
||||
pageSize,
|
||||
status: String(query.status || '').trim(),
|
||||
keyword: String(query.keyword || '').trim(),
|
||||
workerId: worker.id,
|
||||
workerSharingId: worker.id,
|
||||
})
|
||||
const permissions = resolveWorkerPermissions(worker)
|
||||
const myShares = await listWorkerSharesByWorker(worker.id)
|
||||
const myShareByOrderId = new Map(
|
||||
myShares.map((share) => [Number(share.work_order_id), share]),
|
||||
)
|
||||
return {
|
||||
items: items.map((item) => mapWorkOrderForWorker(item, permissions)),
|
||||
items: items.map((item) =>
|
||||
mapWorkOrderForWorker(item, permissions, myShareByOrderId.get(Number(item.id))),
|
||||
),
|
||||
pagination: { page, pageSize, total },
|
||||
}
|
||||
}
|
||||
|
||||
export async function joinWorkerSharingOrder(
|
||||
workOrderId: number | string,
|
||||
payload: JsonObject = {},
|
||||
session: WorkerSession,
|
||||
) {
|
||||
requireActiveWorkerSession(session)
|
||||
const worker = await getRequiredWorker(session.workerId)
|
||||
const permissions = resolveWorkerPermissions(worker)
|
||||
const quantity = normalizePositiveInteger(payload.quantity, 1)
|
||||
const now = nowIso()
|
||||
const result = await joinWorkOrderShare({
|
||||
workOrderId: Number(workOrderId),
|
||||
workerId: Number(worker.id),
|
||||
quantity,
|
||||
maxActiveOrders: permissions.maxActiveOrders,
|
||||
now,
|
||||
})
|
||||
if (!result.share) {
|
||||
throw resolveWorkOrderShareJoinError(result.failureReason)
|
||||
}
|
||||
return { share: mapWorkOrderShare(result.share) }
|
||||
}
|
||||
|
||||
function resolveWorkOrderShareJoinError(
|
||||
failureReason: 'work_order_not_open' | 'sharing_disabled' | 'work_order_owner_conflict' | 'sharing_quantity_full' | 'worker_active_order_limit' | 'worker_deposit_insufficient' | null,
|
||||
): Error {
|
||||
const messages: Record<string, string> = {
|
||||
work_order_not_open: '该订单当前不可拼单',
|
||||
sharing_disabled: '该订单未启用拼单',
|
||||
work_order_owner_conflict: '你已整单接取该订单,无需拼单',
|
||||
sharing_quantity_full: '拼单数量已满或超出剩余数量',
|
||||
worker_active_order_limit: '已达到当前等级最大同时接单量',
|
||||
worker_deposit_insufficient: '余额不足,无法冻结所需押金',
|
||||
}
|
||||
return createHttpError(messages[failureReason || ''] || '拼单失败', {
|
||||
statusCode: 409,
|
||||
errorCode: `work_order_sharing_${failureReason || 'failed'}`,
|
||||
})
|
||||
}
|
||||
|
||||
export async function cancelWorkerOrder(
|
||||
workOrderId: number | string,
|
||||
session: WorkerSession,
|
||||
) {
|
||||
requireActiveWorkerSession(session)
|
||||
const worker = await getRequiredWorker(session.workerId)
|
||||
const now = nowIso()
|
||||
const since = new Date(Date.now() - WORKER_CANCEL_LIMIT_WINDOW_MS).toISOString()
|
||||
const cancelCount = await countWorkerCancellationsSince(worker.id, since)
|
||||
if (cancelCount >= WORKER_CANCEL_LIMIT_PER_WINDOW) {
|
||||
throw createHttpError(
|
||||
`30 天内取消接单已达 ${WORKER_CANCEL_LIMIT_PER_WINDOW} 次上限,请谨慎接单`,
|
||||
{
|
||||
statusCode: 409,
|
||||
errorCode: 'worker_cancel_limit_reached',
|
||||
},
|
||||
)
|
||||
}
|
||||
const result = await cancelWorkerWorkOrder({
|
||||
workOrderId: Number(workOrderId),
|
||||
workerId: Number(worker.id),
|
||||
now,
|
||||
})
|
||||
if (result.failureReason === 'work_order_owner_required') {
|
||||
throw createHttpError('只能取消自己接的订单', {
|
||||
statusCode: 403,
|
||||
errorCode: 'work_order_owner_required',
|
||||
})
|
||||
}
|
||||
if (!result.order) {
|
||||
throw createHttpError('当前订单状态不能取消,仅进行中的订单可取消', {
|
||||
statusCode: 409,
|
||||
errorCode: 'work_order_cancel_status_invalid',
|
||||
})
|
||||
}
|
||||
return {
|
||||
order: mapWorkOrderForWorker(
|
||||
result.order,
|
||||
resolveWorkerPermissions(await getRequiredWorker(session.workerId)),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
export async function submitWorkerOrderAcceptance(
|
||||
workOrderId: number | string,
|
||||
payload: JsonObject = {},
|
||||
@@ -727,7 +836,12 @@ export async function submitWorkerOrderAcceptance(
|
||||
) {
|
||||
requireActiveWorkerSession(session)
|
||||
const workOrder = await getRequiredWorkOrder(workOrderId)
|
||||
if (Number(workOrder.assigned_worker_id || 0) !== Number(session.workerId)) {
|
||||
const workerId = Number(session.workerId)
|
||||
const sharingShare = await getWorkOrderShare(workOrder.id, workerId)
|
||||
if (sharingShare) {
|
||||
return submitWorkerSharingAcceptance(workOrder, sharingShare, payload, session)
|
||||
}
|
||||
if (Number(workOrder.assigned_worker_id || 0) !== workerId) {
|
||||
throw createHttpError('只能提交自己的订单', {
|
||||
statusCode: 403,
|
||||
errorCode: 'work_order_owner_required',
|
||||
@@ -784,6 +898,60 @@ export async function submitWorkerOrderAcceptance(
|
||||
}
|
||||
}
|
||||
|
||||
async function submitWorkerSharingAcceptance(
|
||||
workOrder: WorkOrderRow,
|
||||
sharingShare: WorkOrderShareRow,
|
||||
payload: JsonObject = {},
|
||||
session: WorkerSession,
|
||||
) {
|
||||
if (workOrder.status === WORK_ORDER_STATUS.ACCEPTED) {
|
||||
throw createHttpError('该拼单已验收完成', {
|
||||
statusCode: 409,
|
||||
errorCode: 'work_order_sharing_accepted',
|
||||
})
|
||||
}
|
||||
const now = nowIso()
|
||||
const files = normalizeUploadedFiles(payload.files)
|
||||
const imageUrls = [
|
||||
...files.map((file) => file.url || file.mediumUrl || file.thumbnailUrl).filter(Boolean),
|
||||
...normalizeStringArray(payload.imageUrls),
|
||||
]
|
||||
if (imageUrls.length === 0) {
|
||||
throw createHttpError('请上传验收图片', {
|
||||
statusCode: 400,
|
||||
errorCode: 'work_order_acceptance_image_required',
|
||||
})
|
||||
}
|
||||
const acceptance = {
|
||||
note: String(payload.note || '').trim(),
|
||||
files,
|
||||
imageUrls: [...new Set(imageUrls)],
|
||||
submittedAt: now,
|
||||
}
|
||||
const result = await submitWorkOrderShareAcceptance({
|
||||
workOrderId: Number(workOrder.id),
|
||||
workerId: Number(session.workerId),
|
||||
acceptanceJson: JSON.stringify(acceptance),
|
||||
now,
|
||||
})
|
||||
if (result.failureReason === 'share_status_invalid') {
|
||||
throw createHttpError('当前拼单份额已提交,请勿重复提交', {
|
||||
statusCode: 409,
|
||||
errorCode: 'work_order_sharing_share_submitted',
|
||||
})
|
||||
}
|
||||
if (!result.share) {
|
||||
throw createHttpError('未找到拼单份额', {
|
||||
statusCode: 404,
|
||||
errorCode: 'work_order_sharing_share_not_found',
|
||||
})
|
||||
}
|
||||
return {
|
||||
share: mapWorkOrderShare(result.share),
|
||||
sharingPendingCount: await countWorkOrderPendingSharingSubmissions(Number(workOrder.id)),
|
||||
}
|
||||
}
|
||||
|
||||
export async function collectLookupWorkOrder(payload: JsonObject = {}) {
|
||||
const orderNo = String(payload.orderNo || payload.platformOrderId || '').trim()
|
||||
if (!orderNo) {
|
||||
@@ -995,12 +1163,39 @@ export async function saveAdminWorkProductRule(payload: JsonObject = {}) {
|
||||
}
|
||||
|
||||
const rewardAmount = normalizeAmountFen(payload.rewardAmount ?? payload.rewardAmountYuan, 0)
|
||||
if (rewardAmount <= 0) {
|
||||
const sharingEnabled = normalizeBoolean(
|
||||
payload.sharingEnabled ?? payload.sharing_enabled,
|
||||
false,
|
||||
)
|
||||
const sharingUnitReward = normalizeAmountFen(
|
||||
payload.sharingUnitReward ?? payload.sharingUnitRewardYuan,
|
||||
0,
|
||||
)
|
||||
const sharingTotalAmount = normalizeAmountFen(
|
||||
payload.sharingTotalAmount ?? payload.sharingTotalAmountYuan,
|
||||
0,
|
||||
)
|
||||
const sharingTotalQuantity = resolveSharingQuantity(
|
||||
sharingTotalAmount,
|
||||
normalizePositiveInteger(payload.sharingTotalQuantity ?? payload.sharing_total_quantity, 1),
|
||||
sharingUnitReward,
|
||||
)
|
||||
const resolvedSharingTotalAmount =
|
||||
sharingTotalAmount > 0 ? sharingTotalAmount : sharingUnitReward * sharingTotalQuantity
|
||||
if (sharingEnabled) {
|
||||
if (resolvedSharingTotalAmount <= 0) {
|
||||
throw createHttpError('启用拼单时请填写拼单总价或单价', {
|
||||
statusCode: 400,
|
||||
errorCode: 'work_product_rule_sharing_amount_invalid',
|
||||
})
|
||||
}
|
||||
} else if (rewardAmount <= 0) {
|
||||
throw createHttpError('接单金额必须大于 0', {
|
||||
statusCode: 400,
|
||||
errorCode: 'work_product_rule_reward_invalid',
|
||||
})
|
||||
}
|
||||
const finalRewardAmount = sharingEnabled ? resolvedSharingTotalAmount : rewardAmount
|
||||
|
||||
const depositThresholdAmount = normalizeAmountFen(
|
||||
payload.depositThresholdAmount ?? payload.depositThresholdAmountYuan,
|
||||
@@ -1008,8 +1203,8 @@ export async function saveAdminWorkProductRule(payload: JsonObject = {}) {
|
||||
)
|
||||
const requiredDepositAmount =
|
||||
payload.requiredDepositAmount === undefined && payload.requiredDepositAmountYuan === undefined
|
||||
? rewardAmount > depositThresholdAmount
|
||||
? rewardAmount
|
||||
? finalRewardAmount > depositThresholdAmount
|
||||
? finalRewardAmount
|
||||
: 0
|
||||
: normalizeAmountFen(payload.requiredDepositAmount ?? payload.requiredDepositAmountYuan, 0)
|
||||
const fields = normalizeRequirementFieldsFromPayload(payload)
|
||||
@@ -1030,9 +1225,12 @@ export async function saveAdminWorkProductRule(payload: JsonObject = {}) {
|
||||
null,
|
||||
enabled: normalizeBoolean(payload.enabled, true),
|
||||
autoCreate: normalizeBoolean(payload.autoCreate ?? payload.auto_create, false),
|
||||
rewardAmount,
|
||||
rewardAmount: finalRewardAmount,
|
||||
requiredDepositAmount,
|
||||
depositThresholdAmount,
|
||||
sharingEnabled,
|
||||
sharingTotalQuantity,
|
||||
sharingUnitReward,
|
||||
requirementJson: JSON.stringify({ fields }),
|
||||
sortOrder: normalizeInteger(payload.sortOrder, 100),
|
||||
now: nowIso(),
|
||||
@@ -1188,12 +1386,113 @@ export async function listAdminWorkOrders(query: JsonObject = {}) {
|
||||
status: String(query.status || '').trim(),
|
||||
keyword: String(query.keyword || '').trim(),
|
||||
})
|
||||
const shares = await listWorkOrderSharesByOrderIds(items.map((item) => Number(item.id)))
|
||||
const sharesByOrderId = new Map<number, WorkOrderShareRow[]>()
|
||||
for (const share of shares) {
|
||||
const orderId = Number(share.work_order_id)
|
||||
const bucket = sharesByOrderId.get(orderId) || []
|
||||
bucket.push(share)
|
||||
sharesByOrderId.set(orderId, bucket)
|
||||
}
|
||||
return {
|
||||
items: items.map(mapWorkOrderAdmin),
|
||||
items: items.map((item) => {
|
||||
const orderShares = sharesByOrderId.get(Number(item.id)) || []
|
||||
const joinedQuantity = orderShares
|
||||
.filter((share) => share.status !== 'cancelled')
|
||||
.reduce((sum, share) => sum + Number(share.quantity || 0), 0)
|
||||
const pendingSubmissionCount = orderShares.filter(
|
||||
(share) => share.status === 'joined',
|
||||
).length
|
||||
return {
|
||||
...mapWorkOrderAdmin(item),
|
||||
sharingProgress: {
|
||||
joinedQuantity,
|
||||
pendingSubmissionCount,
|
||||
},
|
||||
}
|
||||
}),
|
||||
pagination: { page, pageSize, total },
|
||||
}
|
||||
}
|
||||
|
||||
export async function getAdminWorkOrderSharing(workOrderId: number | string) {
|
||||
const workOrder = await getRequiredWorkOrder(workOrderId)
|
||||
const shares = await listWorkOrderShares(workOrder.id)
|
||||
return {
|
||||
order: mapWorkOrderAdmin(workOrder),
|
||||
shares: shares.map(mapWorkOrderShare),
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateAdminWorkOrderSharing(
|
||||
workOrderId: number | string,
|
||||
payload: JsonObject = {},
|
||||
) {
|
||||
const workOrder = await getRequiredWorkOrder(workOrderId)
|
||||
if (![WORK_ORDER_STATUS.PENDING_MATERIAL, WORK_ORDER_STATUS.UNASSIGNED, WORK_ORDER_STATUS.OPEN].includes(workOrder.status as never)) {
|
||||
throw createHttpError('只有待完善、未分配或待抢单的工单可以配置拼单', {
|
||||
statusCode: 409,
|
||||
errorCode: 'work_order_sharing_config_status_invalid',
|
||||
})
|
||||
}
|
||||
const enabled = normalizeBoolean(
|
||||
payload.enabled ?? payload.sharingEnabled ?? payload.sharing_enabled,
|
||||
false,
|
||||
)
|
||||
const unitReward = normalizeAmountFen(
|
||||
payload.unitReward ?? payload.sharingUnitReward ?? payload.sharingUnitRewardYuan,
|
||||
0,
|
||||
)
|
||||
const totalAmount = normalizeAmountFen(
|
||||
payload.totalAmount ?? payload.sharingTotalAmount ?? payload.sharingTotalAmountYuan,
|
||||
0,
|
||||
)
|
||||
const totalQuantity = resolveSharingQuantity(
|
||||
totalAmount,
|
||||
normalizePositiveInteger(
|
||||
payload.totalQuantity ?? payload.sharingTotalQuantity ?? payload.sharing_total_quantity,
|
||||
1,
|
||||
),
|
||||
unitReward,
|
||||
)
|
||||
const resolvedTotalAmount = totalAmount > 0 ? totalAmount : unitReward * totalQuantity
|
||||
const now = nowIso()
|
||||
const updated = await updateWorkOrder(workOrder.id, {
|
||||
sharing_enabled: enabled,
|
||||
sharing_total_quantity: totalQuantity,
|
||||
sharing_unit_reward: unitReward,
|
||||
reward_amount: enabled ? resolvedTotalAmount : workOrder.reward_amount,
|
||||
updated_at: now,
|
||||
})
|
||||
await createWorkOrderEvent({
|
||||
workOrderId: workOrder.id,
|
||||
actorType: 'admin',
|
||||
actorId: '',
|
||||
eventType: 'sharing_config_updated',
|
||||
fromStatus: workOrder.status,
|
||||
toStatus: updated?.status || workOrder.status,
|
||||
payloadJson: JSON.stringify({
|
||||
enabled,
|
||||
totalQuantity,
|
||||
unitReward,
|
||||
totalAmount: resolvedTotalAmount,
|
||||
}),
|
||||
now,
|
||||
})
|
||||
return { order: mapWorkOrderAdmin(updated || workOrder) }
|
||||
}
|
||||
|
||||
function resolveSharingQuantity(
|
||||
totalAmount: number,
|
||||
fallbackQuantity: number,
|
||||
unitReward: number,
|
||||
): number {
|
||||
if (totalAmount > 0 && unitReward > 0) {
|
||||
return Math.max(1, Math.round(totalAmount / unitReward))
|
||||
}
|
||||
return Math.max(1, fallbackQuantity)
|
||||
}
|
||||
|
||||
export async function submitAdminWorkOrderMaterial(
|
||||
workOrderId: number | string,
|
||||
payload: JsonObject = {},
|
||||
@@ -1450,7 +1749,16 @@ export async function acceptAdminWorkOrder(workOrderId: number | string) {
|
||||
})
|
||||
}
|
||||
const now = nowIso()
|
||||
const updated = await acceptWorkOrderAndSettle({ workOrderId: workOrder.id, now })
|
||||
const { order: updated, failureReason } = await acceptWorkOrderAndSettle({
|
||||
workOrderId: workOrder.id,
|
||||
now,
|
||||
})
|
||||
if (failureReason === 'sharing_pending_submissions') {
|
||||
throw createHttpError('还有拼单打手未提交验收资料,暂不能统一验收', {
|
||||
statusCode: 409,
|
||||
errorCode: 'work_order_sharing_pending_submissions',
|
||||
})
|
||||
}
|
||||
if (!updated) {
|
||||
throw createHttpError('验收失败,订单状态可能已变化', {
|
||||
statusCode: 409,
|
||||
@@ -1521,6 +1829,9 @@ export async function syncWorkerOrdersForSourceOrder(
|
||||
rewardAmount,
|
||||
requiredDepositAmount,
|
||||
depositThresholdAmount,
|
||||
sharingEnabled: rule.sharing_enabled === true,
|
||||
sharingTotalQuantity: Number(rule.sharing_total_quantity || 1),
|
||||
sharingUnitReward: Number(rule.sharing_unit_reward || 0),
|
||||
materialJson: JSON.stringify({
|
||||
source: {
|
||||
orderId: Number(order.id),
|
||||
@@ -1781,6 +2092,11 @@ function mapWorkProductRule(rule: WorkProductRuleRow | null | undefined) {
|
||||
depositThresholdAmount: Number(
|
||||
rule.deposit_threshold_amount || DEFAULT_DEPOSIT_THRESHOLD_AMOUNT,
|
||||
),
|
||||
sharing: {
|
||||
enabled: rule.sharing_enabled === true,
|
||||
totalQuantity: Number(rule.sharing_total_quantity || 1),
|
||||
unitReward: Number(rule.sharing_unit_reward || 0),
|
||||
},
|
||||
requirement: {
|
||||
fields: normalizeRequirementFields(requirement.fields),
|
||||
},
|
||||
@@ -1883,6 +2199,11 @@ function mapWorkOrderAdmin(workOrder: WorkOrderRow) {
|
||||
status: workOrder.status,
|
||||
rewardAmount: Number(workOrder.reward_amount || 0),
|
||||
requiredDepositAmount: Number(workOrder.required_deposit_amount || 0),
|
||||
sharing: {
|
||||
enabled: workOrder.sharing_enabled === true,
|
||||
totalQuantity: Number(workOrder.sharing_total_quantity || 1),
|
||||
unitReward: Number(workOrder.sharing_unit_reward || 0),
|
||||
},
|
||||
depositThresholdAmount: Number(
|
||||
workOrder.deposit_threshold_amount || DEFAULT_DEPOSIT_THRESHOLD_AMOUNT,
|
||||
),
|
||||
@@ -1909,6 +2230,7 @@ function mapWorkOrderAdmin(workOrder: WorkOrderRow) {
|
||||
function mapWorkOrderForWorker(
|
||||
workOrder: WorkOrderRow,
|
||||
permissions: { depositFreeAmount: number },
|
||||
myShare?: WorkOrderShareRow | null,
|
||||
) {
|
||||
const mapped = mapWorkOrderAdmin(workOrder)
|
||||
const {
|
||||
@@ -1922,6 +2244,32 @@ function mapWorkOrderForWorker(
|
||||
return {
|
||||
...visibleOrder,
|
||||
freezeDepositAmount: resolveFreezeDepositAmount(workOrder, permissions),
|
||||
myShare: myShare ? mapWorkOrderShare(myShare) : null,
|
||||
}
|
||||
}
|
||||
|
||||
function mapWorkOrderShare(share: WorkOrderShareRow) {
|
||||
return {
|
||||
shareId: Number(share.id),
|
||||
workOrderId: Number(share.work_order_id),
|
||||
workerId: Number(share.worker_id),
|
||||
quantity: Number(share.quantity || 0),
|
||||
unitReward: Number(share.unit_reward || 0),
|
||||
shareReward: Number(share.share_reward || 0),
|
||||
shareDeposit: Number(share.share_deposit || 0),
|
||||
status: share.status,
|
||||
acceptance: safeParseJson(share.acceptance_json),
|
||||
submittedAt: share.submitted_at,
|
||||
acceptedAt: share.accepted_at,
|
||||
createdAt: share.created_at,
|
||||
updatedAt: share.updated_at,
|
||||
worker: share.worker_id
|
||||
? {
|
||||
workerId: Number(share.worker_id),
|
||||
username: share.worker_username || '',
|
||||
displayName: share.worker_display_name || share.worker_username || '',
|
||||
}
|
||||
: null,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user