feat(domain): add income calculation with commission support

This commit is contained in:
zetaloop
2026-02-23 11:04:48 +08:00
parent 77d23d0c9d
commit 2222dccbb7
3 changed files with 90 additions and 5 deletions
+33
View File
@@ -0,0 +1,33 @@
import type { Shop } from "@/lib/types"
type ShopCommission = Pick<Shop, "commissionType" | "commissionValue">
export interface IncomeCalculation {
income: number
commissionLabel: string
}
function roundCurrency(amount: number) {
return Number(amount.toFixed(2))
}
export function calculateOrderIncome(totalPrice: number, shop?: ShopCommission): IncomeCalculation {
if (!shop) {
return {
income: roundCurrency(totalPrice),
commissionLabel: "独立接单无抽成",
}
}
if (shop.commissionType === "percentage") {
return {
income: roundCurrency(totalPrice * (1 - shop.commissionValue / 100)),
commissionLabel: `扣除${shop.commissionValue}%抽成`,
}
}
return {
income: roundCurrency(Math.max(0, totalPrice - shop.commissionValue)),
commissionLabel: `扣除¥${shop.commissionValue}固定抽成`,
}
}
+11 -5
View File
@@ -1,6 +1,8 @@
import { create } from "zustand" import { create } from "zustand"
import { calculateOrderIncome } from "@/lib/domain/income"
import { generateId } from "@/lib/id" import { generateId } from "@/lib/id"
import { mockTransactions, walletBalance } from "@/lib/mock" import { mockTransactions, walletBalance } from "@/lib/mock"
import { useShopStore } from "@/store/shops"
import type { WalletTransaction } from "@/lib/types" import type { WalletTransaction } from "@/lib/types"
interface WalletState { interface WalletState {
@@ -10,7 +12,7 @@ interface WalletState {
withdraw: (amount: number) => void withdraw: (amount: number) => void
deductBalance: (orderId: string, amount: number) => boolean deductBalance: (orderId: string, amount: number) => boolean
refundPayment: (orderId: string, amount: number) => boolean refundPayment: (orderId: string, amount: number) => boolean
addIncome: (orderId: string, amount: number) => void addIncome: (orderId: string, totalPrice: number, shopId?: string) => void
addTransaction: (transaction: WalletTransaction) => void addTransaction: (transaction: WalletTransaction) => void
} }
@@ -109,8 +111,8 @@ export const useWalletStore = create<WalletState>((set, get) => ({
return true return true
}, },
addIncome: (orderId, amount) => { addIncome: (orderId, totalPrice, shopId) => {
if (!Number.isFinite(amount) || amount <= 0) return if (!Number.isFinite(totalPrice) || totalPrice <= 0) return
const state = get() const state = get()
const exists = state.transactions.some( const exists = state.transactions.some(
@@ -118,15 +120,19 @@ export const useWalletStore = create<WalletState>((set, get) => ({
) )
if (exists) return if (exists) return
const shop = shopId
? useShopStore.getState().shops.find((item) => item.id === shopId)
: undefined
const { income, commissionLabel } = calculateOrderIncome(totalPrice, shop)
const now = new Date().toISOString() const now = new Date().toISOString()
const income = Number((amount * 0.85).toFixed(2))
set((prev) => ({ set((prev) => ({
transactions: [ transactions: [
{ {
id: generateId("tx"), id: generateId("tx"),
type: "income", type: "income",
amount: income, amount: income,
description: `订单 ${orderId} 收入(扣除15%抽成`, description: `订单 ${orderId} 收入(${commissionLabel}`,
createdAt: now, createdAt: now,
}, },
...prev.transactions, ...prev.transactions,
+46
View File
@@ -0,0 +1,46 @@
import { describe, expect, it } from "vitest"
import { calculateOrderIncome } from "@/lib/domain/income"
describe("calculateOrderIncome", () => {
it("calculates percentage commission income", () => {
const result = calculateOrderIncome(100, {
commissionType: "percentage",
commissionValue: 12,
})
expect(result).toEqual({
income: 88,
commissionLabel: "扣除12%抽成",
})
})
it("calculates fixed commission income", () => {
const result = calculateOrderIncome(60, {
commissionType: "fixed",
commissionValue: 8,
})
expect(result).toEqual({
income: 52,
commissionLabel: "扣除¥8固定抽成",
})
})
it("keeps full income for independent orders", () => {
const result = calculateOrderIncome(90)
expect(result).toEqual({
income: 90,
commissionLabel: "独立接单无抽成",
})
})
it("does not return negative income for fixed commission", () => {
const result = calculateOrderIncome(6, {
commissionType: "fixed",
commissionValue: 8,
})
expect(result.income).toBe(0)
})
})