修正后台订单号主实际收入
This commit is contained in:
@@ -40,3 +40,4 @@ deploy/caddy/conf.d/show.caddy
|
|||||||
|
|
||||||
logs
|
logs
|
||||||
.gocache
|
.gocache
|
||||||
|
artifacts/
|
||||||
|
|||||||
@@ -61,11 +61,20 @@ func (r *Repository) ListAdmin(ctx context.Context, query AdminOrderQuery) (*Pag
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkouts, err := r.latestAdminCheckouts(ctx, rows)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
items := make([]OrderDTO, 0, len(rows))
|
items := make([]OrderDTO, 0, len(rows))
|
||||||
paymentTimeoutMinutes := pendingPaymentTimeoutMinutes(db)
|
paymentTimeoutMinutes := pendingPaymentTimeoutMinutes(db)
|
||||||
for _, row := range rows {
|
for _, row := range rows {
|
||||||
dto := row.toAdminDTO()
|
dto := row.toAdminDTO()
|
||||||
applyPaymentDeadline(&dto, row.RentalOrder, paymentTimeoutMinutes)
|
applyPaymentDeadline(&dto, row.RentalOrder, paymentTimeoutMinutes)
|
||||||
|
if checkout, ok := checkouts[row.ID]; ok && shouldAttachAdminCheckout(row) {
|
||||||
|
checkoutDTO := toCheckoutAdminDTO(checkout)
|
||||||
|
refreshCheckoutSettlementDTO(&checkoutDTO, row.RentalOrder, checkout)
|
||||||
|
dto.Checkout = &checkoutDTO
|
||||||
|
}
|
||||||
items = append(items, dto)
|
items = append(items, dto)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,6 +86,41 @@ func (r *Repository) ListAdmin(ctx context.Context, query AdminOrderQuery) (*Pag
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// latestAdminCheckouts loads one latest checkout per order so the admin order
|
||||||
|
// list can display finalized income without issuing one query per row.
|
||||||
|
func (r *Repository) latestAdminCheckouts(ctx context.Context, rows []orderRow) (map[uint64]model.OrderCheckout, error) {
|
||||||
|
result := make(map[uint64]model.OrderCheckout, len(rows))
|
||||||
|
if len(rows) == 0 {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
orderIDs := make([]uint64, 0, len(rows))
|
||||||
|
for _, row := range rows {
|
||||||
|
orderIDs = append(orderIDs, row.ID)
|
||||||
|
}
|
||||||
|
latest := r.db.WithContext(ctx).
|
||||||
|
Table("order_checkouts").
|
||||||
|
Select("MAX(id) AS id").
|
||||||
|
Where("order_id IN ?", orderIDs).
|
||||||
|
Group("order_id")
|
||||||
|
var checkouts []model.OrderCheckout
|
||||||
|
if err := r.db.WithContext(ctx).
|
||||||
|
Table("order_checkouts AS oc").
|
||||||
|
Joins("JOIN (?) AS latest ON latest.id = oc.id", latest).
|
||||||
|
Find(&checkouts).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, checkout := range checkouts {
|
||||||
|
result[checkout.OrderID] = checkout
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func shouldAttachAdminCheckout(row orderRow) bool {
|
||||||
|
return shouldAttachCheckout(row.Status) ||
|
||||||
|
row.SettlementStatus == settlementStatusSettled ||
|
||||||
|
row.SettlementStatus == settlementStatusArbitrated
|
||||||
|
}
|
||||||
|
|
||||||
func applyAdminOrderFilters(db *gorm.DB, query AdminOrderQuery) *gorm.DB {
|
func applyAdminOrderFilters(db *gorm.DB, query AdminOrderQuery) *gorm.DB {
|
||||||
if query.Status != "" {
|
if query.Status != "" {
|
||||||
db = db.Where("o.status = ?", query.Status)
|
db = db.Where("o.status = ?", query.Status)
|
||||||
|
|||||||
@@ -1796,6 +1796,38 @@ func createOpenPlatformCheckout(t *testing.T, db *gorm.DB, order model.RentalOrd
|
|||||||
return checkout
|
return checkout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestListAdminUsesFinalizedCheckoutOwnerIncome(t *testing.T) {
|
||||||
|
db := setupOrderTestDB(t)
|
||||||
|
repo := NewRepository(db)
|
||||||
|
adminID := uint64(7002)
|
||||||
|
_, renter, order := createPlatformManagedCheckoutOrder(t, db, adminID)
|
||||||
|
order.Status = orderStatusCompleted
|
||||||
|
order.SettlementStatus = settlementStatusSettled
|
||||||
|
if err := db.Save(&order).Error; err != nil {
|
||||||
|
t.Fatalf("save completed order failed: %v", err)
|
||||||
|
}
|
||||||
|
checkout := createOpenPlatformCheckout(t, db, order, renter.ID)
|
||||||
|
checkout.Status = checkoutStatusAccepted
|
||||||
|
checkout.OwnerIncomeAmountCent = 6000
|
||||||
|
if err := db.Save(&checkout).Error; err != nil {
|
||||||
|
t.Fatalf("save finalized checkout failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := repo.ListAdmin(t.Context(), AdminOrderQuery{Page: 1, PageSize: 20})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ListAdmin() error = %v", err)
|
||||||
|
}
|
||||||
|
if len(result.Items) != 1 {
|
||||||
|
t.Fatalf("ListAdmin() returned %d items, want 1", len(result.Items))
|
||||||
|
}
|
||||||
|
if result.Items[0].Checkout == nil || result.Items[0].Checkout.OwnerIncomeAmountCent == nil {
|
||||||
|
t.Fatal("ListAdmin() did not include finalized checkout owner income")
|
||||||
|
}
|
||||||
|
if *result.Items[0].Checkout.OwnerIncomeAmountCent != 6000 {
|
||||||
|
t.Fatalf("owner income = %d, want 6000", *result.Items[0].Checkout.OwnerIncomeAmountCent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestAdminPlatformCheckoutConfirmRequiresExplicitConfirmationForZeroOwnerIncome(t *testing.T) {
|
func TestAdminPlatformCheckoutConfirmRequiresExplicitConfirmationForZeroOwnerIncome(t *testing.T) {
|
||||||
db := setupOrderTestDB(t)
|
db := setupOrderTestDB(t)
|
||||||
repo := NewRepository(db, Dependencies{
|
repo := NewRepository(db, Dependencies{
|
||||||
|
|||||||
@@ -164,6 +164,12 @@ function userText(value: string | number | undefined) {
|
|||||||
function isPlatformManaged(row: Order) {
|
function isPlatformManaged(row: Order) {
|
||||||
return row.handoff_mode === 'platform' || row.settlement_mode === 'platform_managed'
|
return row.handoff_mode === 'platform' || row.settlement_mode === 'platform_managed'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ownerActualIncome(row: Order) {
|
||||||
|
if (row.settlement_status !== 'settled' && row.settlement_status !== 'arbitrated') return null
|
||||||
|
const value = row.checkout?.owner_income_amount_cent
|
||||||
|
return typeof value === 'number' ? value : null
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -331,11 +337,12 @@ function isPlatformManaged(row: Order) {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="号主收入" width="120" align="right">
|
<el-table-column label="号主实际收入" width="130" align="right">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<strong class="owner-income-cell"
|
<strong v-if="ownerActualIncome(row) !== null" class="owner-income-cell">
|
||||||
>¥{{ money(amountYuan(row.owner_rent_amount_cent)) }}</strong
|
¥{{ money(amountYuan(ownerActualIncome(row))) }}
|
||||||
>
|
</strong>
|
||||||
|
<span v-else class="owner-income-empty">-</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="创建时间" width="170">
|
<el-table-column label="创建时间" width="170">
|
||||||
@@ -453,6 +460,10 @@ function isPlatformManaged(row: Order) {
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.owner-income-empty {
|
||||||
|
color: #8f9bba;
|
||||||
|
}
|
||||||
|
|
||||||
.order-link {
|
.order-link {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
color: #2f6bff;
|
color: #2f6bff;
|
||||||
|
|||||||
Reference in New Issue
Block a user