增加零号主收入结算确认
This commit is contained in:
@@ -133,7 +133,8 @@ type CounterCheckoutRequest struct {
|
||||
}
|
||||
|
||||
type AdminActionRequest struct {
|
||||
Reason string `json:"reason" binding:"required"`
|
||||
Reason string `json:"reason" binding:"required"`
|
||||
ConfirmZeroOwnerIncome bool `json:"confirm_zero_owner_income"`
|
||||
}
|
||||
|
||||
type PlatformHandoffRequest struct {
|
||||
|
||||
@@ -44,6 +44,8 @@ func writeOrderError(c *gin.Context, err error) {
|
||||
response.Error(c, http.StatusConflict, "checkout_cannot_submit", "当前订单不能发起结账")
|
||||
case errors.Is(err, ErrCheckoutCannotConfirm):
|
||||
response.Error(c, http.StatusConflict, "checkout_cannot_confirm", "当前结账不能确认")
|
||||
case errors.Is(err, ErrZeroOwnerIncomeConfirmation):
|
||||
response.Error(c, http.StatusConflict, "zero_owner_income_confirmation_required", "号主收入为 0,请确认后再结算")
|
||||
case errors.Is(err, ErrCheckoutCannotCounter):
|
||||
response.Error(c, http.StatusConflict, "checkout_cannot_counter", "当前结账不能修改")
|
||||
case errors.Is(err, ErrCheckoutMaxRounds):
|
||||
|
||||
@@ -159,6 +159,9 @@ func (r *Repository) AdminPlatformCheckoutConfirm(ctx context.Context, adminID u
|
||||
if normalizeCheckoutTurn(checkout) != checkoutTurnOwner {
|
||||
return ErrCheckoutCannotConfirm
|
||||
}
|
||||
if checkout.OwnerIncomeAmountCent == 0 && !req.ConfirmZeroOwnerIncome {
|
||||
return ErrZeroOwnerIncomeConfirmation
|
||||
}
|
||||
if err := ensureCheckoutCompletable(order, checkout); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -196,6 +199,7 @@ func (r *Repository) AdminPlatformCheckoutConfirm(ctx context.Context, adminID u
|
||||
"after_settlement_status": order.SettlementStatus,
|
||||
"offline_settlement_status": order.OfflineSettlementStatus,
|
||||
"offline_settlement_amount_cent": order.OfflineSettlementAmountCent,
|
||||
"confirm_zero_owner_income": req.ConfirmZeroOwnerIncome,
|
||||
})
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -2,6 +2,7 @@ package order
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -1794,3 +1795,48 @@ func createOpenPlatformCheckout(t *testing.T, db *gorm.DB, order model.RentalOrd
|
||||
}
|
||||
return checkout
|
||||
}
|
||||
|
||||
func TestAdminPlatformCheckoutConfirmRequiresExplicitConfirmationForZeroOwnerIncome(t *testing.T) {
|
||||
db := setupOrderTestDB(t)
|
||||
repo := NewRepository(db, Dependencies{
|
||||
RefundStarter: RefundStarterFunc(func(context.Context, uint64, int64, string, string) (string, error) {
|
||||
return "pending", nil
|
||||
}),
|
||||
})
|
||||
const adminID uint64 = 7001
|
||||
_, renter, order := createPlatformManagedCheckoutOrder(t, db, adminID)
|
||||
checkout := createOpenPlatformCheckout(t, db, order, renter.ID)
|
||||
checkout.OwnerIncomeAmountCent = 0
|
||||
if err := db.Save(&checkout).Error; err != nil {
|
||||
t.Fatalf("将号主收入调整为零失败: %v", err)
|
||||
}
|
||||
|
||||
err := repo.AdminPlatformCheckoutConfirm(t.Context(), *order.ManagedAdminID, order.ID, AdminActionRequest{
|
||||
Reason: "客服核对结算",
|
||||
}, AuditMeta{})
|
||||
if !errors.Is(err, ErrZeroOwnerIncomeConfirmation) {
|
||||
t.Fatalf("未确认零收入时 error = %v, want %v", err, ErrZeroOwnerIncomeConfirmation)
|
||||
}
|
||||
|
||||
var pending model.RentalOrder
|
||||
if err := db.First(&pending, order.ID).Error; err != nil {
|
||||
t.Fatalf("读取订单失败: %v", err)
|
||||
}
|
||||
if pending.Status != orderStatusPendingCheckoutConfirm {
|
||||
t.Fatalf("未确认零收入后订单状态 = %s, want %s", pending.Status, orderStatusPendingCheckoutConfirm)
|
||||
}
|
||||
|
||||
if err := repo.AdminPlatformCheckoutConfirm(t.Context(), *order.ManagedAdminID, order.ID, AdminActionRequest{
|
||||
Reason: "已确认号主收入为零",
|
||||
ConfirmZeroOwnerIncome: true,
|
||||
}, AuditMeta{}); err != nil {
|
||||
t.Fatalf("确认零收入后结算失败: %v", err)
|
||||
}
|
||||
var completed model.RentalOrder
|
||||
if err := db.First(&completed, order.ID).Error; err != nil {
|
||||
t.Fatalf("读取完成订单失败: %v", err)
|
||||
}
|
||||
if completed.Status != orderStatusCompleted {
|
||||
t.Fatalf("确认零收入后订单状态 = %s, want %s", completed.Status, orderStatusCompleted)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ var (
|
||||
ErrOrderCannotComplete = errors.New("order cannot complete")
|
||||
ErrCheckoutCannotSubmit = errors.New("checkout cannot submit")
|
||||
ErrCheckoutCannotConfirm = errors.New("checkout cannot confirm")
|
||||
ErrZeroOwnerIncomeConfirmation = errors.New("zero owner income confirmation required")
|
||||
ErrCheckoutCannotCounter = errors.New("checkout cannot counter")
|
||||
ErrCheckoutMaxRounds = errors.New("checkout max rounds reached")
|
||||
ErrCheckoutDepositShortfall = errors.New("checkout deposit shortfall")
|
||||
|
||||
@@ -68,6 +68,7 @@ type OrderActionType =
|
||||
| ''
|
||||
const actionType = ref<OrderActionType>('')
|
||||
const reason = ref('')
|
||||
const zeroOwnerIncomeConfirmed = ref(false)
|
||||
const refundStatus = ref<RefundStatus | null>(null)
|
||||
const platformHandoffVisible = ref(false)
|
||||
const platformHandoffContent = ref('')
|
||||
@@ -476,7 +477,11 @@ async function submitAction() {
|
||||
await adminResetHandoff(order.value.id, reason.value)
|
||||
ElMessage.success(`${resetActionLabel.value}成功`)
|
||||
} else if (actionType.value === 'platform_checkout_confirm') {
|
||||
await adminPlatformCheckoutConfirm(order.value.id, reason.value)
|
||||
await adminPlatformCheckoutConfirm(
|
||||
order.value.id,
|
||||
reason.value,
|
||||
zeroOwnerIncomeConfirmed.value
|
||||
)
|
||||
ElMessage.success('结账已确认')
|
||||
} else if (actionType.value === 'platform_checkout_dispute') {
|
||||
await adminPlatformCheckoutDispute(order.value.id, reason.value)
|
||||
@@ -500,6 +505,28 @@ async function submitAction() {
|
||||
}
|
||||
}
|
||||
|
||||
async function confirmPlatformCheckout() {
|
||||
if (!order.value) return
|
||||
zeroOwnerIncomeConfirmed.value = false
|
||||
if (Number(order.value.checkout?.owner_income_amount_cent ?? 0) === 0) {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
'本次结算的号主收入为 ¥0.0。确认后将完成结算,请再次确认是否继续。',
|
||||
'号主收入为零',
|
||||
{
|
||||
confirmButtonText: '仍确认结算',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}
|
||||
)
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
zeroOwnerIncomeConfirmed.value = true
|
||||
}
|
||||
openAction('platform_checkout_confirm')
|
||||
}
|
||||
|
||||
function openPlatformHandoff() {
|
||||
platformHandoffContent.value = ''
|
||||
platformHandoffReason.value = ''
|
||||
@@ -952,7 +979,7 @@ function paymentPaidAt(record: AdminPayment) {
|
||||
<el-button
|
||||
v-if="canPlatformCheckoutConfirm"
|
||||
type="primary"
|
||||
@click="openAction('platform_checkout_confirm')"
|
||||
@click="confirmPlatformCheckout"
|
||||
>
|
||||
{{ platformCheckoutConfirmAction?.label || '客服确认结账' }}
|
||||
</el-button>
|
||||
@@ -1500,6 +1527,17 @@ function paymentPaidAt(record: AdminPayment) {
|
||||
<p>
|
||||
<strong>{{ order.order_no }}</strong> · 商品编号 {{ listingCode }} · {{ order.title }}
|
||||
</p>
|
||||
<el-alert
|
||||
v-if="
|
||||
actionType === 'platform_checkout_confirm' &&
|
||||
Number(order.checkout?.owner_income_amount_cent ?? 0) === 0
|
||||
"
|
||||
title="号主收入为零"
|
||||
description="本次结算将按号主收入 ¥0.0 完成,请确认无误后再继续。"
|
||||
type="warning"
|
||||
:closable="false"
|
||||
show-icon
|
||||
/>
|
||||
<el-input
|
||||
v-model="reason"
|
||||
type="textarea"
|
||||
|
||||
@@ -458,10 +458,14 @@ export async function adminForceHandoff(id: number, content: string, reason: str
|
||||
return data.data
|
||||
}
|
||||
|
||||
export async function adminPlatformCheckoutConfirm(id: number, reason: string) {
|
||||
export async function adminPlatformCheckoutConfirm(
|
||||
id: number,
|
||||
reason: string,
|
||||
confirmZeroOwnerIncome = false
|
||||
) {
|
||||
const { data } = await apiClient.post<ApiResponse<{ confirmed: boolean }>>(
|
||||
`/admin/orders/${id}/platform-checkout/confirm`,
|
||||
{ reason }
|
||||
{ reason, confirm_zero_owner_income: confirmZeroOwnerIncome }
|
||||
)
|
||||
return data.data
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user