488 lines
14 KiB
C++
488 lines
14 KiB
C++
|
|
#include "sqlite_database.h"
|
||
|
|
|
||
|
|
#include "sqlite_statement.h"
|
||
|
|
#include <iostream>
|
||
|
|
#include <utility> // std::exchange
|
||
|
|
|
||
|
|
// Constructor: Opens the SQLite database
|
||
|
|
SQLiteDatabase::SQLiteDatabase(const std::string &db_file) {
|
||
|
|
// WARNING: The database is not blocked
|
||
|
|
if (sqlite3_open(db_file.c_str(), &db_) != SQLITE_OK) {
|
||
|
|
std::cerr << "Failed to open database:" << sqlite3_errmsg(db_) << std::endl;
|
||
|
|
db_ = nullptr;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Destructor: Closes the database connection
|
||
|
|
SQLiteDatabase::~SQLiteDatabase() {
|
||
|
|
if (db_) {
|
||
|
|
sqlite3_close(db_);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
SQLiteDatabase::SQLiteDatabase(SQLiteDatabase &&other) noexcept
|
||
|
|
: db_(std::exchange(other.db_, nullptr)) {}
|
||
|
|
|
||
|
|
SQLiteDatabase &SQLiteDatabase::operator=(SQLiteDatabase &&other) noexcept {
|
||
|
|
if (this != &other) {
|
||
|
|
if (db_) {
|
||
|
|
sqlite3_close(db_);
|
||
|
|
}
|
||
|
|
db_ = std::exchange(other.db_, nullptr);
|
||
|
|
}
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Helper function for executing non-SELECT queries
|
||
|
|
int SQLiteDatabase::executeNonQuery(
|
||
|
|
const std::string &query,
|
||
|
|
const std::function<void(SQLiteStatement &)> &bindFunc) {
|
||
|
|
SQLiteStatement stmt(db_, query);
|
||
|
|
|
||
|
|
if (db_ == nullptr) {
|
||
|
|
throw std::runtime_error("Database is not open");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (bindFunc) {
|
||
|
|
bindFunc(stmt);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!stmt.execute()) {
|
||
|
|
std::cerr << "Failed to execute query:" << sqlite3_errmsg(db_);
|
||
|
|
}
|
||
|
|
|
||
|
|
return stmt.changes();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Helper function for executing SELECT queries
|
||
|
|
std::vector<std::vector<std::string>> SQLiteDatabase::executeSelectQuery(
|
||
|
|
const std::string &query,
|
||
|
|
const std::function<void(SQLiteStatement &)> &bindFunc) {
|
||
|
|
std::vector<std::vector<std::string>> results;
|
||
|
|
SQLiteStatement stmt(db_, query);
|
||
|
|
|
||
|
|
if (db_ == nullptr) {
|
||
|
|
throw std::runtime_error("Database is not open");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (bindFunc) {
|
||
|
|
bindFunc(stmt);
|
||
|
|
}
|
||
|
|
|
||
|
|
while (stmt.step()) {
|
||
|
|
std::vector<std::string> row;
|
||
|
|
for (int i = 0, count = stmt.getColumnCount(); i < count; ++i) {
|
||
|
|
row.emplace_back(stmt.getColumnText(i));
|
||
|
|
}
|
||
|
|
results.push_back(row);
|
||
|
|
}
|
||
|
|
|
||
|
|
return results;
|
||
|
|
}
|
||
|
|
|
||
|
|
// INFO: ----- GENRE -----
|
||
|
|
|
||
|
|
// Add a new genre
|
||
|
|
bool SQLiteDatabase::addGenre(const NewGenre &genre) {
|
||
|
|
const std::string query = "INSERT INTO genres (genre_name) VALUES (?);";
|
||
|
|
int changes = executeNonQuery(query, [&genre](SQLiteStatement &stmt) {
|
||
|
|
stmt.bind(1, genre.genre_name);
|
||
|
|
});
|
||
|
|
|
||
|
|
return changes > 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Remove a genre by ID
|
||
|
|
bool SQLiteDatabase::removeGenre(int genre_id) {
|
||
|
|
const std::string query = "DELETE FROM genres WHERE genre_id = ?;";
|
||
|
|
int changes = executeNonQuery(
|
||
|
|
query, [&genre_id](SQLiteStatement &stmt) { stmt.bind(1, genre_id); });
|
||
|
|
|
||
|
|
return changes > 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Update an existing genre
|
||
|
|
bool SQLiteDatabase::updateGenre(const Genre &genre) {
|
||
|
|
const std::string query =
|
||
|
|
"UPDATE genres SET genre_name = ? WHERE genre_id = ?;";
|
||
|
|
int changes = executeNonQuery(query, [&genre](SQLiteStatement &stmt) {
|
||
|
|
stmt.bind(1, genre.genre_name);
|
||
|
|
stmt.bind(2, genre.genre_id);
|
||
|
|
});
|
||
|
|
|
||
|
|
return changes > 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get a genre by ID
|
||
|
|
Genre SQLiteDatabase::getGenre(int genre_id) {
|
||
|
|
const std::string query = "SELECT * FROM genres WHERE genre_id = ?;";
|
||
|
|
auto result = executeSelectQuery(
|
||
|
|
query, [&genre_id](SQLiteStatement &stmt) { stmt.bind(1, genre_id); });
|
||
|
|
|
||
|
|
if (!result.empty()) {
|
||
|
|
auto genre_id = std::stoi(result[0][0]);
|
||
|
|
auto genre_name = result[0][1];
|
||
|
|
Genre genre(genre_id, genre_name);
|
||
|
|
return genre;
|
||
|
|
}
|
||
|
|
return {};
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get all genres
|
||
|
|
std::vector<Genre> SQLiteDatabase::getAllGenres() {
|
||
|
|
const std::string query = "SELECT * FROM genres;";
|
||
|
|
auto result = executeSelectQuery(query);
|
||
|
|
|
||
|
|
std::vector<Genre> genres;
|
||
|
|
for (const auto &row : result) {
|
||
|
|
genres.push_back({std::stoi(row[0]), row[1]});
|
||
|
|
}
|
||
|
|
|
||
|
|
return genres;
|
||
|
|
}
|
||
|
|
|
||
|
|
// INFO: ----- MOVIE -----
|
||
|
|
|
||
|
|
// Add a new movie
|
||
|
|
bool SQLiteDatabase::addMovie(const NewMovie &movie) {
|
||
|
|
const std::string query =
|
||
|
|
"INSERT INTO movies (title, genre_id, duration) VALUES (?, ?, ?);";
|
||
|
|
int changes = executeNonQuery(query, [&movie](SQLiteStatement &stmt) {
|
||
|
|
stmt.bind(1, movie.title);
|
||
|
|
stmt.bind(2, movie.genre_id);
|
||
|
|
stmt.bind(3, movie.duration);
|
||
|
|
});
|
||
|
|
|
||
|
|
return changes > 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Remove a movie by ID
|
||
|
|
bool SQLiteDatabase::removeMovie(int movie_id) {
|
||
|
|
const std::string query = "DELETE FROM movies WHERE movie_id = ?;";
|
||
|
|
int changes = executeNonQuery(
|
||
|
|
query, [&movie_id](SQLiteStatement &stmt) { stmt.bind(1, movie_id); });
|
||
|
|
|
||
|
|
return changes > 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Update an existing movie
|
||
|
|
bool SQLiteDatabase::updateMovie(const Movie &movie) {
|
||
|
|
const std::string query =
|
||
|
|
"UPDATE movies SET title = ?, genre_id = ?, duration = ? WHERE movie_id "
|
||
|
|
"= ?;";
|
||
|
|
int changes = executeNonQuery(query, [&movie](SQLiteStatement &stmt) {
|
||
|
|
stmt.bind(1, movie.title);
|
||
|
|
stmt.bind(2, movie.genre_id);
|
||
|
|
stmt.bind(3, movie.duration);
|
||
|
|
stmt.bind(4, movie.movie_id);
|
||
|
|
});
|
||
|
|
|
||
|
|
return changes > 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get a movie by ID
|
||
|
|
Movie SQLiteDatabase::getMovie(int movie_id) {
|
||
|
|
const std::string query = "SELECT * FROM movies WHERE movie_id = ?;";
|
||
|
|
auto result = executeSelectQuery(
|
||
|
|
query, [&movie_id](SQLiteStatement &stmt) { stmt.bind(1, movie_id); });
|
||
|
|
|
||
|
|
if (!result.empty()) {
|
||
|
|
auto movie_id = std::stoi(result[0][0]);
|
||
|
|
auto title = result[0][1];
|
||
|
|
auto genre_id = std::stoi(result[0][2]);
|
||
|
|
auto duration = std::stoi(result[0][3]);
|
||
|
|
Movie movie(movie_id, title, genre_id, duration);
|
||
|
|
return movie;
|
||
|
|
}
|
||
|
|
return {};
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get all movies
|
||
|
|
std::vector<Movie> SQLiteDatabase::getAllMovies() {
|
||
|
|
const std::string query = "SELECT * FROM movies;";
|
||
|
|
auto result = executeSelectQuery(query);
|
||
|
|
std::vector<Movie> movies;
|
||
|
|
|
||
|
|
for (const auto &row : result) {
|
||
|
|
movies.push_back(
|
||
|
|
{std::stoi(row[0]), row[1], std::stoi(row[2]), std::stoi(row[3])});
|
||
|
|
}
|
||
|
|
return movies;
|
||
|
|
}
|
||
|
|
|
||
|
|
// INFO: ----- HALL -----
|
||
|
|
|
||
|
|
// Add a new hall
|
||
|
|
bool SQLiteDatabase::addHall(const NewHall &hall) {
|
||
|
|
const std::string query =
|
||
|
|
"INSERT INTO halls (hall_name, capacity) VALUES (?, ?);";
|
||
|
|
int changes = executeNonQuery(query, [&hall](SQLiteStatement &stmt) {
|
||
|
|
stmt.bind(1, hall.hall_name);
|
||
|
|
stmt.bind(2, hall.capacity);
|
||
|
|
});
|
||
|
|
|
||
|
|
return changes > 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Remove a hall by ID
|
||
|
|
bool SQLiteDatabase::removeHall(int hall_id) {
|
||
|
|
const std::string query = "DELETE FROM halls WHERE hall_id = ?;";
|
||
|
|
int changes = executeNonQuery(
|
||
|
|
query, [&hall_id](SQLiteStatement &stmt) { stmt.bind(1, hall_id); });
|
||
|
|
|
||
|
|
return changes > 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Update an existing hall
|
||
|
|
bool SQLiteDatabase::updateHall(const Hall &hall) {
|
||
|
|
const std::string query =
|
||
|
|
"UPDATE halls SET hall_name = ?, capacity = ? WHERE hall_id = ?;";
|
||
|
|
int changes = executeNonQuery(query, [&hall](SQLiteStatement &stmt) {
|
||
|
|
stmt.bind(1, hall.hall_name);
|
||
|
|
stmt.bind(2, hall.capacity);
|
||
|
|
stmt.bind(3, hall.hall_id);
|
||
|
|
});
|
||
|
|
|
||
|
|
return changes > 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get a hall by ID
|
||
|
|
Hall SQLiteDatabase::getHall(int hall_id) {
|
||
|
|
const std::string query = "SELECT * FROM halls WHERE hall_id = ?;";
|
||
|
|
auto result = executeSelectQuery(
|
||
|
|
query, [&hall_id](SQLiteStatement &stmt) { stmt.bind(1, hall_id); });
|
||
|
|
|
||
|
|
if (!result.empty()) {
|
||
|
|
auto hall_id = std::stoi(result[0][0]);
|
||
|
|
auto hall_name = result[0][1];
|
||
|
|
auto capacity = std::stoi(result[0][2]);
|
||
|
|
Hall hall(hall_id, hall_name, capacity);
|
||
|
|
return hall;
|
||
|
|
}
|
||
|
|
return {};
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get all halls
|
||
|
|
std::vector<Hall> SQLiteDatabase::getAllHalls() {
|
||
|
|
const std::string query = "SELECT * FROM halls;";
|
||
|
|
auto result = executeSelectQuery(query);
|
||
|
|
std::vector<Hall> halls;
|
||
|
|
|
||
|
|
for (const auto &row : result) {
|
||
|
|
halls.push_back({std::stoi(row[0]), row[1], std::stoi(row[2])});
|
||
|
|
}
|
||
|
|
return halls;
|
||
|
|
}
|
||
|
|
|
||
|
|
// INFO: ----- SESSION -----
|
||
|
|
|
||
|
|
// Add a new session
|
||
|
|
bool SQLiteDatabase::addSession(const NewSession &session) {
|
||
|
|
const std::string query = "INSERT INTO sessions (movie_id, hall_id, "
|
||
|
|
"begin_at, ticket_price) VALUES (?, ?, ?, ?);";
|
||
|
|
int changes = executeNonQuery(query, [&session](SQLiteStatement &stmt) {
|
||
|
|
stmt.bind(1, session.movie_id);
|
||
|
|
stmt.bind(2, session.hall_id);
|
||
|
|
stmt.bind(3, session.begin_at);
|
||
|
|
stmt.bind(4, session.ticket_price);
|
||
|
|
});
|
||
|
|
|
||
|
|
return changes > 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Remove a session by ID
|
||
|
|
bool SQLiteDatabase::removeSession(int session_id) {
|
||
|
|
const std::string query = "DELETE FROM sessions WHERE session_id = ?;";
|
||
|
|
int changes = executeNonQuery(query, [&session_id](SQLiteStatement &stmt) {
|
||
|
|
stmt.bind(1, session_id);
|
||
|
|
});
|
||
|
|
|
||
|
|
return changes > 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Update an existing session
|
||
|
|
bool SQLiteDatabase::updateSession(const Session &session) {
|
||
|
|
const std::string query = "UPDATE sessions SET movie_id = ?, hall_id = ?, "
|
||
|
|
"begin_at = ?, ticket_price = ? WHERE "
|
||
|
|
"session_id = ?;";
|
||
|
|
int changes = executeNonQuery(query, [&session](SQLiteStatement &stmt) {
|
||
|
|
stmt.bind(1, session.movie_id);
|
||
|
|
stmt.bind(2, session.hall_id);
|
||
|
|
stmt.bind(3, session.begin_at);
|
||
|
|
stmt.bind(4, session.ticket_price);
|
||
|
|
stmt.bind(5, session.session_id);
|
||
|
|
});
|
||
|
|
|
||
|
|
return changes > 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get a session by ID
|
||
|
|
Session SQLiteDatabase::getSession(int session_id) {
|
||
|
|
const std::string query = "SELECT * FROM sessions WHERE session_id = ?;";
|
||
|
|
auto result = executeSelectQuery(query, [&session_id](SQLiteStatement &stmt) {
|
||
|
|
stmt.bind(1, session_id);
|
||
|
|
});
|
||
|
|
|
||
|
|
if (!result.empty()) {
|
||
|
|
auto session_id = std::stoi(result[0][0]);
|
||
|
|
auto movie_id = std::stoi(result[0][1]);
|
||
|
|
auto hall_id = std::stoi(result[0][2]);
|
||
|
|
auto begin_at = result[0][3];
|
||
|
|
auto ticket_price = std::stod(result[0][4]);
|
||
|
|
Session session(session_id, movie_id, hall_id, begin_at, ticket_price);
|
||
|
|
return session;
|
||
|
|
}
|
||
|
|
return {};
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get all sessions
|
||
|
|
std::vector<Session> SQLiteDatabase::getAllSessions() {
|
||
|
|
const std::string query = "SELECT * FROM sessions;";
|
||
|
|
auto result = executeSelectQuery(query);
|
||
|
|
std::vector<Session> sessions;
|
||
|
|
|
||
|
|
for (const auto &row : result) {
|
||
|
|
sessions.push_back({std::stoi(row[0]), std::stoi(row[1]), std::stoi(row[2]),
|
||
|
|
row[3], std::stod(row[4])});
|
||
|
|
}
|
||
|
|
return sessions;
|
||
|
|
}
|
||
|
|
|
||
|
|
// INFO: ----- TICKET -----
|
||
|
|
|
||
|
|
// Add a new ticket
|
||
|
|
bool SQLiteDatabase::addTicket(const NewTicket &ticket) {
|
||
|
|
const std::string query = "INSERT INTO tickets (session_id, seat_number, "
|
||
|
|
"sold_at) VALUES (?, ?, ?);";
|
||
|
|
int changes = executeNonQuery(query, [&ticket](SQLiteStatement &stmt) {
|
||
|
|
stmt.bind(1, ticket.session_id);
|
||
|
|
stmt.bind(2, ticket.seat_number);
|
||
|
|
stmt.bind(3, ticket.sold_at);
|
||
|
|
});
|
||
|
|
|
||
|
|
return changes > 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Remove a ticket by ID
|
||
|
|
bool SQLiteDatabase::removeTicket(int ticket_id) {
|
||
|
|
const std::string query = "DELETE FROM tickets WHERE ticket_id = ?;";
|
||
|
|
int changes = executeNonQuery(
|
||
|
|
query, [&ticket_id](SQLiteStatement &stmt) { stmt.bind(1, ticket_id); });
|
||
|
|
|
||
|
|
return changes > 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Update an existing ticket
|
||
|
|
bool SQLiteDatabase::updateTicket(const Ticket &ticket) {
|
||
|
|
const std::string query = "UPDATE tickets SET session_id = ?, seat_number = "
|
||
|
|
"?, sold_at = ? WHERE ticket_id = ?;";
|
||
|
|
int changes = executeNonQuery(query, [&ticket](SQLiteStatement &stmt) {
|
||
|
|
stmt.bind(1, ticket.session_id);
|
||
|
|
stmt.bind(2, ticket.seat_number);
|
||
|
|
stmt.bind(3, ticket.sold_at);
|
||
|
|
stmt.bind(4, ticket.ticket_id);
|
||
|
|
});
|
||
|
|
|
||
|
|
return changes > 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get a ticket by ID
|
||
|
|
Ticket SQLiteDatabase::getTicket(int ticket_id) {
|
||
|
|
const std::string query = "SELECT * FROM tickets WHERE ticket_id = ?;";
|
||
|
|
auto result = executeSelectQuery(
|
||
|
|
query, [&ticket_id](SQLiteStatement &stmt) { stmt.bind(1, ticket_id); });
|
||
|
|
|
||
|
|
if (!result.empty()) {
|
||
|
|
auto ticket_id = std::stoi(result[0][0]);
|
||
|
|
auto session_id = std::stoi(result[0][1]);
|
||
|
|
auto seat_number = std::stoi(result[0][2]);
|
||
|
|
auto sold_at = result[0][3];
|
||
|
|
Ticket ticket(ticket_id, session_id, seat_number, sold_at);
|
||
|
|
return ticket;
|
||
|
|
}
|
||
|
|
return {};
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get all tickets
|
||
|
|
std::vector<Ticket> SQLiteDatabase::getAllTickets() {
|
||
|
|
const std::string query = "SELECT * FROM tickets;";
|
||
|
|
auto result = executeSelectQuery(query);
|
||
|
|
std::vector<Ticket> tickets;
|
||
|
|
|
||
|
|
for (const auto &row : result) {
|
||
|
|
tickets.push_back(
|
||
|
|
{std::stoi(row[0]), std::stoi(row[1]), std::stoi(row[2]), row[3]});
|
||
|
|
}
|
||
|
|
return tickets;
|
||
|
|
}
|
||
|
|
|
||
|
|
// INFO: ----- REFUND -----
|
||
|
|
|
||
|
|
// Add a new refund
|
||
|
|
bool SQLiteDatabase::addRefund(const NewRefund &refund) {
|
||
|
|
const std::string query =
|
||
|
|
"INSERT INTO refunds (ticket_id, refund_at, refund_amount) "
|
||
|
|
"VALUES (?, ?, ?);";
|
||
|
|
int changes = executeNonQuery(query, [&refund](SQLiteStatement &stmt) {
|
||
|
|
stmt.bind(1, refund.ticket_id);
|
||
|
|
stmt.bind(2, refund.refund_at);
|
||
|
|
stmt.bind(3, refund.refund_amount);
|
||
|
|
});
|
||
|
|
|
||
|
|
return changes > 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Remove a refund by ID
|
||
|
|
bool SQLiteDatabase::removeRefund(int refund_id) {
|
||
|
|
const std::string query = "DELETE FROM refunds WHERE refund_id = ?;";
|
||
|
|
int changes = executeNonQuery(
|
||
|
|
query, [&refund_id](SQLiteStatement &stmt) { stmt.bind(1, refund_id); });
|
||
|
|
|
||
|
|
return changes > 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Update an existing refund
|
||
|
|
bool SQLiteDatabase::updateRefund(const Refund &refund) {
|
||
|
|
const std::string query =
|
||
|
|
"UPDATE refunds SET ticket_id = ?, refund_at = ?, refund_amount = ? "
|
||
|
|
"WHERE refund_id = ?;";
|
||
|
|
int changes = executeNonQuery(query, [&refund](SQLiteStatement &stmt) {
|
||
|
|
stmt.bind(1, refund.ticket_id);
|
||
|
|
stmt.bind(2, refund.refund_at);
|
||
|
|
stmt.bind(3, refund.refund_amount);
|
||
|
|
stmt.bind(4, refund.refund_id);
|
||
|
|
});
|
||
|
|
|
||
|
|
return changes > 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get a refund by ID
|
||
|
|
Refund SQLiteDatabase::getRefund(int refund_id) {
|
||
|
|
const std::string query = "SELECT * FROM refunds WHERE refund_id = ?;";
|
||
|
|
auto result = executeSelectQuery(
|
||
|
|
query, [&refund_id](SQLiteStatement &stmt) { stmt.bind(1, refund_id); });
|
||
|
|
|
||
|
|
if (!result.empty()) {
|
||
|
|
auto refund_id = std::stoi(result[0][0]);
|
||
|
|
auto ticket_id = std::stoi(result[0][1]);
|
||
|
|
auto refund_at = result[0][2];
|
||
|
|
auto refund_amount = std::stod(result[0][3]);
|
||
|
|
Refund refund(refund_id, ticket_id, refund_at, refund_amount);
|
||
|
|
return refund;
|
||
|
|
}
|
||
|
|
return {};
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get all refunds
|
||
|
|
std::vector<Refund> SQLiteDatabase::getAllRefunds() {
|
||
|
|
const std::string query = "SELECT * FROM refunds;";
|
||
|
|
auto result = executeSelectQuery(query);
|
||
|
|
std::vector<Refund> refunds;
|
||
|
|
|
||
|
|
for (const auto &row : result) {
|
||
|
|
refunds.push_back(
|
||
|
|
{std::stoi(row[0]), std::stoi(row[1]), row[2], std::stod(row[3])});
|
||
|
|
}
|
||
|
|
return refunds;
|
||
|
|
}
|