Full Stack Game Retail System

Project Description

As part of a team of six, I developed a full-stack online game store for a fictional client, designed to manage game inventory, user accounts, and purchases. The project featured a responsive user interface, thorough test suite, and role-based account permissions. Following industry best practices, the system was built with a focus on reliability, usability, and scalability, achieving comprehensive test coverage and meeting all specified functional and non-functional requirements.

Technical Details

Languages & Technologies Used

Code Snippet

This service layer function completes the purchase of the logged in customer's cart. It first validates the customer delivery and payment information, then confirms the order itself is valid (eg. cart is not empty), and then creates the order, updating the database accordingly. See the full project on GitHub.

  /**
  * Processes the purchase of all items in a customer's cart.
  * 
  * @param username The username of the customer making the purchase.
  * @return Order if the purchase is successful.
  */
 @Transactional
 public Order purchaseCart(String username) {
     // Retrieve customer details by username
     Customer customer = customerRepo.findByUsername(username);
     if (customer == null) {
         throw new ResponseStatusException(HttpStatus.NOT_FOUND, "No such customer with username exists");
     }

     // Check if customer has payment information
     PaymentInformation paymentInformation = customer.getPaymentInformation();
     if (paymentInformation == null) {
         throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Customer does not have valid payment information");
     }

     // Validate postal code format for billing address
     if (!paymentInformation.getBillingAddress().getPostalCode()
             .matches("^[A-Za-z][0-9][A-Za-z][0-9][A-Za-z][0-9]$")) {
         throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
                 "Customer address postal code information is not valid");
     }

     // Validate credit card number and CVV code
     if (paymentInformation.getCardNumber().length() != 16) {
         throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Customer does not have valid credit card number");
     }
     if (Integer.toString(paymentInformation.getCvvCode()).length() != 3) {
         throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Customer does not have valid CVV code");
     }

     // Check if credit card is expired
     Date currentDate = new Date(System.currentTimeMillis());
     if (paymentInformation.getExpiryDate().before(currentDate)) {
         throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Customer credit card is expired");
     }

     // Retrieve all items in the customer's cart
     CartItem[] cartItems = getCartItems(customer);
     if (cartItems == null || cartItems.length <= 0) {
         throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Customer cart is empty");
     }

     // Check if there is enough stock for each game in the cart
     Game game;
     for (int i = 0; i < cartItems.length; i++) {
         game = cartItems[i].getKey().getGame();
         if (cartItems[i].getQuantity() > game.getStock()) {
             throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
                     String.format("There is not enough stock of %s to complete purchase", game.getTitle()));
         }
     }

     // Create a new order for the customer
     Order order = new Order(currentDate, null, customer);
     order = orderRepo.save(order);
     // Reduce stock for each game and create GameCopy records
     double totalPrice = 0;
     GameCopy gameCopy;
     for (int i = 0; i < cartItems.length; i++) {
         game = cartItems[i].getKey().getGame();
         game.setStock(game.getStock() - cartItems[i].getQuantity());
         game = gameRepo.save(game);
         double gamePrice = game.getPrice();

         for (int j = 0; j < cartItems[i].getQuantity(); j++) {
             gameCopy = new GameCopy(order, game);
             gameCopy = gameCopyRepo.save(gameCopy);
             totalPrice += gamePrice;
         }
     }
     // Clear customer's cart and save the order
     clearCart(customer);
     totalPrice *= 1.1;  // Add the 10% QST
     totalPrice += 5;   // Add $5 delivery fee
     order.setTotalPrice(totalPrice);
     order = orderRepo.save(order);
     return order;
 }