|
|
@@ -7,14 +7,18 @@ import {
|
|
|
PaymentQueryResponse,
|
|
|
CreatePaymentOrderParams,
|
|
|
CreatePaymentOrderResponse,
|
|
|
- UserQueryOrderResponse
|
|
|
+ CreateSinglePaymentOrderParams,
|
|
|
+ UserQueryOrderResponse,
|
|
|
+ SingleListQueryParams,
|
|
|
+ SingleListResponse
|
|
|
} from '../dto/payment.dto'
|
|
|
import axios from 'axios'
|
|
|
import crypto from 'crypto'
|
|
|
import { randomInt } from 'crypto'
|
|
|
import Decimal from 'decimal.js'
|
|
|
import { IncomeRecordsService } from './income-records.service'
|
|
|
-import { IncomeType, OrderType } from '../entities/income-records.entity'
|
|
|
+import { IncomeRecords, IncomeType, OrderType } from '../entities/income-records.entity'
|
|
|
+import { PaginationResponse } from '../dto/common.dto'
|
|
|
import { MemberService } from './member.service'
|
|
|
import { UserService } from './user.service'
|
|
|
import { TeamService } from './team.service'
|
|
|
@@ -237,6 +241,67 @@ export class PaymentService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ async createSinglePaymentOrder(params: CreateSinglePaymentOrderParams): Promise<CreatePaymentOrderResponse> {
|
|
|
+ try {
|
|
|
+ const user = await this.userService.findById(params.userId)
|
|
|
+ if (!user) {
|
|
|
+ throw new Error('用户不存在')
|
|
|
+ }
|
|
|
+
|
|
|
+ // 单片购买固定价格
|
|
|
+ const price = '10.00'
|
|
|
+ const out_trade_no = `${Date.now()}${params.userId}${params.resourceId}${randomInt(0, 1e4)
|
|
|
+ .toString()
|
|
|
+ .padStart(4, '0')}`
|
|
|
+
|
|
|
+ const paymentParams: CreatePaymentParams = {
|
|
|
+ pid: Number(this.pid),
|
|
|
+ type: 'alipay',
|
|
|
+ out_trade_no,
|
|
|
+ notify_url: `https://9g15.vip/api/payment/notify`,
|
|
|
+ return_url: `https://yz1df.cc/video/${params.resourceId}?pay=true`,
|
|
|
+ name: `单片购买 - 资源ID: ${params.resourceId}`,
|
|
|
+ money: price,
|
|
|
+ client_ip: params.ip
|
|
|
+ }
|
|
|
+
|
|
|
+ const result = await this.createOrder(paymentParams)
|
|
|
+
|
|
|
+ // 创建收入记录
|
|
|
+ try {
|
|
|
+ // 计算佣金
|
|
|
+ let agentId = 0
|
|
|
+ let incomeAmount = new Decimal(price)
|
|
|
+
|
|
|
+ await this.incomeRecordsService.create({
|
|
|
+ agentId,
|
|
|
+ userId: user.id,
|
|
|
+ incomeAmount: incomeAmount.toNumber(),
|
|
|
+ incomeType: IncomeType.TIP,
|
|
|
+ orderType: OrderType.SINGLE_TIP,
|
|
|
+ orderPrice: new Decimal(price).toNumber(),
|
|
|
+ orderNo: out_trade_no,
|
|
|
+ payChannel: 'alipay',
|
|
|
+ payNo: result.trade_no || '',
|
|
|
+ resourceId: params.resourceId.toString()
|
|
|
+ })
|
|
|
+ } catch (incomeError) {
|
|
|
+ this.app.log.error('Failed to create income record:', incomeError)
|
|
|
+ throw new Error('Failed to create income record')
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ code: result.code,
|
|
|
+ msg: result.msg,
|
|
|
+ code_url: result.code_url,
|
|
|
+ out_trade_no: result.out_trade_no
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ this.app.log.error('Failed to create single payment order:', error)
|
|
|
+ throw error
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
async queryOrder(params: { trade_no?: string; out_trade_no?: string }): Promise<PaymentQueryResponse> {
|
|
|
try {
|
|
|
if (!params.trade_no && !params.out_trade_no) {
|
|
|
@@ -275,7 +340,7 @@ export class PaymentService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- async userQueryOrder(userId: number, orderNo?: string): Promise<UserQueryOrderResponse> {
|
|
|
+ async userQueryOrder(userId: number, orderNo?: string, resourceId?: string): Promise<UserQueryOrderResponse> {
|
|
|
const responseData: UserQueryOrderResponse = {
|
|
|
orderNo: orderNo || '',
|
|
|
msg: '',
|
|
|
@@ -300,7 +365,7 @@ export class PaymentService {
|
|
|
incomeRecord = recentRecord
|
|
|
responseData.orderNo = targetOrderNo
|
|
|
} else {
|
|
|
- incomeRecord = await this.incomeRecordsService.findByOrderNo(orderNo, userId)
|
|
|
+ incomeRecord = await this.incomeRecordsService.findByOrderNo(orderNo, userId, resourceId)
|
|
|
if (!incomeRecord) {
|
|
|
responseData.msg = '没有找到订单'
|
|
|
return responseData
|
|
|
@@ -355,4 +420,40 @@ export class PaymentService {
|
|
|
const normalizedType = type.toLowerCase().trim()
|
|
|
return PaymentService.STRING_TO_ORDER_TYPE_MAP[normalizedType] ?? OrderType.SINGLE_TIP
|
|
|
}
|
|
|
+
|
|
|
+ async userSingleQuery(userId: number, resourceId: string): Promise<boolean> {
|
|
|
+ const incomeRecord = await this.incomeRecordsService.findSingleByResourceId(resourceId, userId)
|
|
|
+ if (!incomeRecord) {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ return true
|
|
|
+ }
|
|
|
+
|
|
|
+ async userSingleList(userId: number, query: SingleListQueryParams): Promise<SingleListResponse> {
|
|
|
+ const { page = 0, size = 20, resourceId } = query
|
|
|
+
|
|
|
+ const records = await this.incomeRecordsService.findAll({
|
|
|
+ page,
|
|
|
+ size,
|
|
|
+ userId,
|
|
|
+ orderType: OrderType.SINGLE_TIP,
|
|
|
+ status: true,
|
|
|
+ delFlag: false,
|
|
|
+ ...(resourceId && { resourceId }),
|
|
|
+ select: ['id', 'userId', 'resourceId', 'status', 'createdAt']
|
|
|
+ })
|
|
|
+
|
|
|
+ const content = records.content.map(record => ({
|
|
|
+ id: record.id,
|
|
|
+ userId: record.userId,
|
|
|
+ resourceId: record.resourceId,
|
|
|
+ status: record.status,
|
|
|
+ createdAt: record.createdAt.toISOString()
|
|
|
+ }))
|
|
|
+
|
|
|
+ return {
|
|
|
+ content,
|
|
|
+ metadata: records.metadata
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|