namespace TaxBaik.Infrastructure.Repositories; using Dapper; using TaxBaik.Domain.Entities; using TaxBaik.Domain.Interfaces; public class ContractRepository(IDbConnectionFactory connectionFactory) : BaseRepository(connectionFactory), IContractRepository { public async Task CreateAsync(Contract contract, CancellationToken cancellationToken = default) { using var conn = Conn(); return await conn.QueryFirstAsync( @"INSERT INTO contracts (client_id, contract_number, service_type, contract_date, start_date, end_date, monthly_fee, total_amount, payment_status, status, notes, created_at, updated_at) VALUES (@ClientId, @ContractNumber, @ServiceType, @ContractDate, @StartDate, @EndDate, @MonthlyFee, @TotalAmount, @PaymentStatus, @Status, @Notes, NOW(), NOW()) RETURNING id", contract); } public async Task> GetAllAsync(CancellationToken cancellationToken = default) { using var conn = Conn(); return await conn.QueryAsync( @"SELECT id, client_id, contract_number, service_type, contract_date, start_date, end_date, monthly_fee, total_amount, payment_status, status, notes, created_at, updated_at FROM contracts ORDER BY contract_date DESC"); } public async Task GetByIdAsync(int id, CancellationToken cancellationToken = default) { using var conn = Conn(); return await conn.QueryFirstOrDefaultAsync( @"SELECT id, client_id, contract_number, service_type, contract_date, start_date, end_date, monthly_fee, total_amount, payment_status, status, notes, created_at, updated_at FROM contracts WHERE id = @Id", new { Id = id }); } public async Task> GetByClientIdAsync(int clientId, CancellationToken cancellationToken = default) { using var conn = Conn(); return await conn.QueryAsync( @"SELECT id, client_id, contract_number, service_type, contract_date, start_date, end_date, monthly_fee, total_amount, payment_status, status, notes, created_at, updated_at FROM contracts WHERE client_id = @ClientId ORDER BY contract_date DESC", new { ClientId = clientId }); } public async Task> GetActiveContractsAsync(CancellationToken cancellationToken = default) { using var conn = Conn(); return await conn.QueryAsync( @"SELECT id, client_id, contract_number, service_type, contract_date, start_date, end_date, monthly_fee, total_amount, payment_status, status, notes, created_at, updated_at FROM contracts WHERE status = 'active' ORDER BY client_id"); } public async Task> GetExpiringContractsAsync(int daysAhead = 30, CancellationToken cancellationToken = default) { using var conn = Conn(); return await conn.QueryAsync( @"SELECT id, client_id, contract_number, service_type, contract_date, start_date, end_date, monthly_fee, total_amount, payment_status, status, notes, created_at, updated_at FROM contracts WHERE status = 'active' AND end_date IS NOT NULL AND end_date BETWEEN CURRENT_DATE AND CURRENT_DATE + INTERVAL '1 day' * @DaysAhead ORDER BY end_date ASC", new { DaysAhead = daysAhead }); } public async Task UpdateAsync(Contract contract, CancellationToken cancellationToken = default) { using var conn = Conn(); await conn.ExecuteAsync( @"UPDATE contracts SET contract_number = @ContractNumber, service_type = @ServiceType, contract_date = @ContractDate, start_date = @StartDate, end_date = @EndDate, monthly_fee = @MonthlyFee, total_amount = @TotalAmount, payment_status = @PaymentStatus, status = @Status, notes = @Notes, updated_at = NOW() WHERE id = @Id", contract); } public async Task GetMonthlyRecurringRevenueAsync(CancellationToken cancellationToken = default) { using var conn = Conn(); var result = await conn.QueryFirstAsync( @"SELECT COALESCE(SUM(monthly_fee), 0) FROM contracts WHERE status = 'active' AND monthly_fee IS NOT NULL"); return result; } }