summaryrefslogtreecommitdiff
path: root/source/store.cc
diff options
context:
space:
mode:
authorFuwn <[email protected]>2024-05-31 00:00:12 -0700
committerFuwn <[email protected]>2024-05-31 00:20:41 -0700
commit968e1c4af014b7f40bfaa4f57fcc0f38e5e0d847 (patch)
treedf80525ad0cc9e4b561bfb0772c30ccc5b64b4a2 /source/store.cc
parentfeat: initial commit (diff)
downloadcst_136_assignment_eight-main.tar.xz
cst_136_assignment_eight-main.zip
feat: final releaseHEADmain
Diffstat (limited to 'source/store.cc')
-rw-r--r--source/store.cc235
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