244 lines
5.7 KiB
TypeScript
244 lines
5.7 KiB
TypeScript
/**
|
|
* Queries de transactions (transações do sistema de escrow)
|
|
* Operações para a tabela transactions
|
|
*/
|
|
|
|
import { query } from "../index";
|
|
|
|
export interface Transaction {
|
|
transaction_id: number;
|
|
listing_id: number | null;
|
|
buyer_id: number;
|
|
seller_id: number;
|
|
item_name: string;
|
|
quantity: number;
|
|
server_name: string;
|
|
amount: number;
|
|
payment_method: "pix" | "tibia_coins" | "gold_coins" | null;
|
|
escrow_fee: number | null;
|
|
transaction_status:
|
|
| "pending"
|
|
| "deposited"
|
|
| "item_delivered"
|
|
| "completed"
|
|
| "disputed"
|
|
| "cancelled"
|
|
| "refunded";
|
|
created_at: Date;
|
|
deposited_at: Date | null;
|
|
delivered_at: Date | null;
|
|
completed_at: Date | null;
|
|
buyer_confirmed: boolean;
|
|
seller_confirmed: boolean;
|
|
buyer_notes: string | null;
|
|
seller_notes: string | null;
|
|
}
|
|
|
|
export interface CreateTransactionData {
|
|
listing_id?: number;
|
|
buyer_id: number;
|
|
seller_id: number;
|
|
item_name: string;
|
|
quantity: number;
|
|
server_name: string;
|
|
amount: number;
|
|
payment_method: "pix" | "tibia_coins" | "gold_coins";
|
|
escrow_fee?: number;
|
|
}
|
|
|
|
export interface UpdateTransactionStatusData {
|
|
transaction_status: Transaction["transaction_status"];
|
|
deposited_at?: Date;
|
|
delivered_at?: Date;
|
|
completed_at?: Date;
|
|
buyer_confirmed?: boolean;
|
|
seller_confirmed?: boolean;
|
|
buyer_notes?: string;
|
|
seller_notes?: string;
|
|
}
|
|
|
|
/**
|
|
* Cria uma nova transação
|
|
*/
|
|
export async function createTransaction(
|
|
data: CreateTransactionData,
|
|
): Promise<Transaction> {
|
|
// Calcular escrow_fee se não fornecido (2% do valor)
|
|
const escrowFee = data.escrow_fee ?? Number((data.amount * 0.02).toFixed(2));
|
|
|
|
const result = await query<Transaction>(
|
|
`
|
|
INSERT INTO transactions (
|
|
listing_id, buyer_id, seller_id, item_name, quantity,
|
|
server_name, amount, payment_method, escrow_fee
|
|
)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
|
RETURNING *
|
|
`,
|
|
[
|
|
data.listing_id || null,
|
|
data.buyer_id,
|
|
data.seller_id,
|
|
data.item_name,
|
|
data.quantity,
|
|
data.server_name,
|
|
data.amount,
|
|
data.payment_method,
|
|
escrowFee,
|
|
],
|
|
);
|
|
|
|
return result.rows[0];
|
|
}
|
|
|
|
/**
|
|
* Busca transação por ID
|
|
*/
|
|
export async function getTransactionById(
|
|
transactionId: number,
|
|
): Promise<Transaction | null> {
|
|
const result = await query<Transaction>(
|
|
`
|
|
SELECT * FROM transactions WHERE transaction_id = $1
|
|
`,
|
|
[transactionId],
|
|
);
|
|
|
|
return result.rows[0] || null;
|
|
}
|
|
|
|
/**
|
|
* Atualiza status da transação
|
|
*/
|
|
export async function updateTransactionStatus(
|
|
transactionId: number,
|
|
data: UpdateTransactionStatusData,
|
|
): Promise<Transaction | null> {
|
|
const updates: string[] = [];
|
|
const params: any[] = [];
|
|
let paramIndex = 1;
|
|
|
|
updates.push(`transaction_status = $${paramIndex}`);
|
|
params.push(data.transaction_status);
|
|
paramIndex++;
|
|
|
|
if (data.deposited_at !== undefined) {
|
|
updates.push(`deposited_at = $${paramIndex}`);
|
|
params.push(data.deposited_at);
|
|
paramIndex++;
|
|
}
|
|
|
|
if (data.delivered_at !== undefined) {
|
|
updates.push(`delivered_at = $${paramIndex}`);
|
|
params.push(data.delivered_at);
|
|
paramIndex++;
|
|
}
|
|
|
|
if (data.completed_at !== undefined) {
|
|
updates.push(`completed_at = $${paramIndex}`);
|
|
params.push(data.completed_at);
|
|
paramIndex++;
|
|
}
|
|
|
|
if (data.buyer_confirmed !== undefined) {
|
|
updates.push(`buyer_confirmed = $${paramIndex}`);
|
|
params.push(data.buyer_confirmed);
|
|
paramIndex++;
|
|
}
|
|
|
|
if (data.seller_confirmed !== undefined) {
|
|
updates.push(`seller_confirmed = $${paramIndex}`);
|
|
params.push(data.seller_confirmed);
|
|
paramIndex++;
|
|
}
|
|
|
|
if (data.buyer_notes !== undefined) {
|
|
updates.push(`buyer_notes = $${paramIndex}`);
|
|
params.push(data.buyer_notes);
|
|
paramIndex++;
|
|
}
|
|
|
|
if (data.seller_notes !== undefined) {
|
|
updates.push(`seller_notes = $${paramIndex}`);
|
|
params.push(data.seller_notes);
|
|
paramIndex++;
|
|
}
|
|
|
|
params.push(transactionId);
|
|
const result = await query<Transaction>(
|
|
`
|
|
UPDATE transactions
|
|
SET ${updates.join(", ")}
|
|
WHERE transaction_id = $${paramIndex}
|
|
RETURNING *
|
|
`,
|
|
params,
|
|
);
|
|
|
|
return result.rows[0] || null;
|
|
}
|
|
|
|
/**
|
|
* Busca transações de um usuário (comprador ou vendedor)
|
|
*/
|
|
export async function getTransactionsByUser(
|
|
userId: number,
|
|
filters: {
|
|
role?: "buyer" | "seller" | "both";
|
|
status?: Transaction["transaction_status"];
|
|
page?: number;
|
|
pageSize?: number;
|
|
} = {},
|
|
): Promise<{ transactions: Transaction[]; total: number }> {
|
|
const { role = "both", status, page = 1, pageSize = 20 } = filters;
|
|
|
|
const conditions: string[] = [];
|
|
const params: any[] = [];
|
|
let paramIndex = 1;
|
|
|
|
if (role === "buyer") {
|
|
conditions.push(`buyer_id = $${paramIndex}`);
|
|
} else if (role === "seller") {
|
|
conditions.push(`seller_id = $${paramIndex}`);
|
|
} else {
|
|
conditions.push(
|
|
`(buyer_id = $${paramIndex} OR seller_id = $${paramIndex})`,
|
|
);
|
|
}
|
|
params.push(userId);
|
|
paramIndex++;
|
|
|
|
if (status) {
|
|
conditions.push(`transaction_status = $${paramIndex}`);
|
|
params.push(status);
|
|
paramIndex++;
|
|
}
|
|
|
|
const whereClause =
|
|
conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
|
|
// Contar total
|
|
const countResult = await query<{ count: string }>(
|
|
`SELECT COUNT(*) as count FROM transactions ${whereClause}`,
|
|
params,
|
|
);
|
|
const total = parseInt(countResult.rows[0].count, 10);
|
|
|
|
// Buscar transações
|
|
const offset = (page - 1) * pageSize;
|
|
const result = await query<Transaction>(
|
|
`
|
|
SELECT * FROM transactions
|
|
${whereClause}
|
|
ORDER BY created_at DESC
|
|
LIMIT $${paramIndex} OFFSET $${paramIndex + 1}
|
|
`,
|
|
[...params, pageSize, offset],
|
|
);
|
|
|
|
return {
|
|
transactions: result.rows,
|
|
total,
|
|
};
|
|
}
|