diff options
Diffstat (limited to 'source/store.cc')
| -rw-r--r-- | source/store.cc | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/source/store.cc b/source/store.cc new file mode 100644 index 0000000..528e358 --- /dev/null +++ b/source/store.cc @@ -0,0 +1,235 @@ +#include <algorithm> +#include <cctype> +#include <functional> +#include <optional> +#include <string> +#include <string_view> +#include <utility> +#include <vector> + +#include <book_store/book.hh> +#include <book_store/book_count.hh> +#include <book_store/customer.hh> +#include <book_store/price.hh> +#include <book_store/purchase_error.hh> +#include <book_store/store.hh> + +namespace book_store { +auto store::append_book(const product::book &book) -> void { + if (this->books_max_size() != 0 && + this->_books.size() < this->books_max_size()) { + this->_books.push_back(book); + } +} + +auto store::append_customer(const customer_type &person) -> void { + if (this->people_max_size() != 0 && + this->_customers.size() < this->people_max_size()) { + this->_customers.push_back(person); + } +} + +auto store::purchase_book(size_type person_id, std::string_view isbn, + product::book_count count) + -> std::optional<purchase_error> { + auto person = this->find_person_by_id(person_id); + + if (!person) { + return purchase_error( + purchase_error::purchase_error_type::person_not_found); + } + + auto book = this->find_book_by_isbn(isbn); + + if (!book) { + return purchase_error(purchase_error::purchase_error_type::book_not_found); + } + + if (book->get().copies() < count) { + return purchase_error( + purchase_error::purchase_error_type::not_enough_stock); + } + + auto &customer = *person; + auto book_price = book.value().get().price_usd(); + + if (customer.is_member()) { + auto discount = 1.0 - (this->_membership_discount_percent * 0.01); + + book_price = + static_cast<product::price::usd::price_type>(book_price * discount); + + if (customer.books_bought() % 11 == 0) { + auto transaction_count = 0; + auto transaction_total = 0.0; + + for (auto &transaction : this->_transactions) { + if (transaction.first == person_id) { + transaction_total += transaction.second.price_usd(); + transaction_count += 1; + } + } + + if (transaction_count >= 10) { + book_price = (transaction_total / transaction_count) * discount; + } + + customer.amount_spent(0); + } + } + + customer.books_bought(customer.books_bought() + count); + // There's some fun casting going on here. It's all safe, though ... probably. + customer.amount_spent(customer.amount_spent() + + static_cast<product::price::usd::price_type>( + (static_cast<product::book_count::book_count_type>( + book_price.value()) * + count.value()))); + book.value().get().copies(book.value().get().copies() - count); + this->_transactions.emplace_back( + person_id, product::book{book.value().get().title().data(), + book.value().get().authors(), + book.value().get().publisher().data(), + book.value().get().isbn().data(), book_price, + product::book_count(count)}); + + return std::nullopt; +} + +auto store::tick_year() -> void { + for (auto &customer : this->_customers) { + customer.amount_spent(customer.amount_spent() + this->_membership_fee); + } +} + +auto store::membership_fee(product::price::usd fee) -> void { + this->_membership_fee = fee; +} + +auto store::membership_discount_percent(discount_percent_type discount_percent) + -> void { + this->_membership_discount_percent = discount_percent; +} + +auto store::books_max_size() const noexcept -> size_type { + return this->_books_max_size; +} + +auto store::people_max_size() const noexcept -> size_type { + return this->_customers_max_size; +} + +auto store::books_size() const noexcept -> size_type { + return this->_books.size(); +} + +auto store::people_size() const noexcept -> size_type { + return this->_customers.size(); +} + +auto store::membership_fee() const noexcept -> product::price::usd { + return this->_membership_fee; +} + +auto store::membership_discount_percent() const noexcept + -> discount_percent_type { + return this->_membership_discount_percent; +} + +auto store::find_person_by_id(size_type person_id) + -> std::optional<customer_type> { + for (auto &person : this->_customers) { + if (person.id() == person_id) { + return person; + } + } + + return std::nullopt; +} + +auto store::find_book_by_isbn(std::string_view isbn) + -> std::optional<std::reference_wrapper<product::book>> { + for (auto &book : this->_books) { + std::string book_isbn = book.isbn().data(); + std::string search_isbn = isbn.data(); + + std::transform( + book_isbn.begin(), book_isbn.end(), book_isbn.begin(), + [](unsigned char character) { return std::tolower(character); }); + std::transform( + search_isbn.begin(), search_isbn.end(), search_isbn.begin(), + [](unsigned char character) { return std::tolower(character); }); + + if (book_isbn == search_isbn) { + return book; + } + } + + return std::nullopt; +} + +auto store::find_books_by_title(std::string_view title) + -> std::vector<product::book> { + std::vector<product::book> books; + + for (auto &book : this->_books) { + std::string book_title = book.title().data(); + std::string search_title = title.data(); + + std::transform( + book_title.begin(), book_title.end(), book_title.begin(), + [](unsigned char character) { return std::tolower(character); }); + std::transform( + search_title.begin(), search_title.end(), search_title.begin(), + [](unsigned char character) { return std::tolower(character); }); + + if (book_title.find(search_title) != std::string::npos) { + books.push_back(book); + } + } + + return books; +} + +auto store::find_books_by_author(std::string_view name) + -> std::vector<product::book> { + std::vector<product::book> books; + + for (auto &book : this->_books) { + for (auto &author : book.authors()) { + std::string author_name = author.full_name(); + std::string search_name = name.data(); + + std::transform( + author_name.begin(), author_name.end(), author_name.begin(), + [](unsigned char character) { return std::tolower(character); }); + std::transform( + search_name.begin(), search_name.end(), search_name.begin(), + [](unsigned char character) { return std::tolower(character); }); + + if (author_name.find(search_name) != std::string::npos) { + books.push_back(book); + } + } + } + + return books; +} + +auto store::transactions_by_id(size_type person_id) + -> std::vector<product::book> { + std::vector<product::book> books; + + for (auto &transaction : this->_transactions) { + if (transaction.first == person_id) { + books.push_back(transaction.second); + } + } + + return books; +} + +auto store::books() -> books_type & { return this->_books; } + +auto store::people() -> customer_container & { return this->_customers; } +} // namespace book_store |