import { db } from '../db/database'; import { Dispute, DisputeEvent, DisputeStatus } from './dispute-flow.model'; export class DisputeFlowService { static async createDispute(disputeData: Omit): Promise { const { dealId, openedByUserId, reasonCode, summary, requestedOutcome } = disputeData; const result = await db.query( `INSERT INTO disputes (deal_id, opened_by_user_id, reason_code, summary, requested_outcome) VALUES (?, ?, ?, ?, ?)`, [dealId, openedByUserId, reasonCode, summary, requestedOutcome] ); const disputeId = result.insertId; // Create initial event await db.query( `INSERT INTO dispute_events (dispute_id, event_type, actor_user_id, payload_json) VALUES (?, ?, ?, ?)`, [disputeId, 'dispute_opened', openedByUserId, JSON.stringify({ reasonCode, summary })] ); // Fetch and return the created dispute const [disputes] = await db.query('SELECT * FROM disputes WHERE id = ?', [disputeId]); return disputes[0]; } static async addEvidence(disputeId: number, actorUserId: number, evidenceData: any): Promise { // Check if dispute exists and is in correct status const [disputes] = await db.query('SELECT status FROM disputes WHERE id = ?', [disputeId]); if (disputes.length === 0) { throw new Error('Dispute not found'); } const dispute = disputes[0]; if (dispute.status !== 'evidence') { throw new Error('Evidence can only be added when dispute status is "evidence"'); } await db.query( `INSERT INTO dispute_events (dispute_id, event_type, actor_user_id, payload_json) VALUES (?, ?, ?, ?)`, [disputeId, 'evidence_added', actorUserId, JSON.stringify(evidenceData)] ); } static async updateDisputeStatus(disputeId: number, actorUserId: number, newStatus: DisputeStatus): Promise { // Check if dispute exists const [disputes] = await db.query('SELECT status FROM disputes WHERE id = ?', [disputeId]); if (disputes.length === 0) { throw new Error('Dispute not found'); } const dispute = disputes[0]; // Validate status transition const validTransitions: Record = { open: ['evidence'], evidence: ['mediation', 'resolved', 'cancelled'], mediation: ['resolved', 'cancelled'], resolved: [], cancelled: [] }; if (!validTransitions[dispute.status].includes(newStatus)) { throw new Error(`Invalid status transition from ${dispute.status} to ${newStatus}`); } // Update dispute status await db.query('UPDATE disputes SET status = ? WHERE id = ?', [newStatus, disputeId]); // Create event await db.query( `INSERT INTO dispute_events (dispute_id, event_type, actor_user_id, payload_json) VALUES (?, ?, ?, ?)`, [disputeId, 'status_changed', actorUserId, JSON.stringify({ oldStatus: dispute.status, newStatus })] ); } static async resolveDispute(disputeId: number, actorUserId: number, decisionData: { decision: string; decisionReason: string; }): Promise { // Check if dispute exists and is in mediation or evidence status const [disputes] = await db.query('SELECT status FROM disputes WHERE id = ?', [disputeId]); if (disputes.length === 0) { throw new Error('Dispute not found'); } const dispute = disputes[0]; if (dispute.status !== 'mediation' && dispute.status !== 'evidence') { throw new Error('Dispute can only be resolved when status is "mediation" or "evidence"'); } // Update dispute with final decision await db.query( `UPDATE disputes SET status = 'resolved', final_decision = ?, final_reason = ?, decided_by_user_id = ?, decided_at = NOW() WHERE id = ?`, [decisionData.decision, decisionData.decisionReason, actorUserId, disputeId] ); // Create event await db.query( `INSERT INTO dispute_events (dispute_id, event_type, actor_user_id, payload_json) VALUES (?, ?, ?, ?)`, [disputeId, 'dispute_resolved', actorUserId, JSON.stringify(decisionData)] ); } static async getDispute(disputeId: number): Promise { const [disputes] = await db.query('SELECT * FROM disputes WHERE id = ?', [disputeId]); return disputes.length > 0 ? disputes[0] : null; } static async getDisputeEvents(disputeId: number): Promise { const [events] = await db.query('SELECT * FROM dispute_events WHERE dispute_id = ? ORDER BY created_at ASC', [disputeId]); return events; } }