# What requirements does this class satisfy?## Why is this a class? does an object instance have meaning?class AdvancedInventoryManager attr_accessor :pricing_rules attr_accessor :store, :tax_rate, :discount_threshold # How is this meant to be used? # # use keyword args if possible; documents defaults better def initialize(store_id, pricing_rules: , tax_rate: 0.08, discount_threshold:) # store_id never validated; should look up store record first @store_id = store_id @products = [] @pricing_rules = config[:pricing_rules] @tax_rate = config[:tax_rate] || 0.08 @discount_threshold = config[:discount_threshold] end # consider lazy instantiators like this for products def products return @products if defined?(@products) @products = build_products # calls import_inventor behind the scenes end # make a class method `from_file` def import_inventory(file_path, format: 'csv') begin data = File.read(file_path) rescue puts "Error reading file" end case format when 'csv' parse_csv(data) when 'json' #DEAD CODE, will error parse_json(data) when 'xml' #DEAD CODE, will error parse_xml(data) end validate_products sync_to_database return @products.size end # move helper methods to private def parse_csv(data) lines = data.split("\n") lines.each_with_index do |line, index| next if index = 0 parts = line.split(",") @products << create_product(parts[0], parts[1], parts[2], parts[3]) end end def create_product(name, price, quantity, category) { name: name.strip, price: price.to_f, quantity: quantity.to_i, category: category.strip.upcase, store_id: @store_id, created_at: Time.now } end def sync_to_database @products.each do |product| # consider find_or_create here. don't use interpolated SQL existing = Product.where("name = '#{product[:name]}' AND store_id = #{@store_id}").first # product = Product.find_or_create(name: product[:name], store: ) if existing existing.update( price: product[:price], quantity: existing.quantity + product[:quantity] ) else Product.create(product) end end end def search_products(search_term) query = "SELECT * FROM products WHERE name LIKE '%#{search_term}%' AND store_id = #{@store_id}" # use AR/arel results = ActiveRecord::Base.connection.execute(query) results.to_a end def get_product_by_id(product_id) sql = "SELECT * FROM products WHERE id = #{product_id}" # use activerecord Product.find_by_sql(sql).first end def delete_old_inventory(category_name) delete_query = "DELETE FROM products WHERE category = '#{category_name}' AND store_id = #{@store_id} AND updated_at < '#{30.days.ago}'" #use AR/arel ActiveRecord::Base.connection.execute(delete_query) end def calculate_total_value(apply_tax = true) total = 0 @products.each do |product| # use Enumerable.map and sum subtotal = product[:price] * product[:quantity] # make pricing rules a class? add as helper method if @pricing_rules && @pricing_rules[product[:category]] discount = @pricing_rules[product[:category]][:discount] subtotal = subtotal - (subtotal * discount) end total += subtotal end if apply_tax total = total + (total * @tax_rate) end total.round(2) end def generate_report(email_to) # This wants to be a PORO report_data = { store_id: @store_id, total_products: @products.length, total_value: calculate_total_value, timestamp: Time.now.strftime("%Y-%m-%d %H:%M:%S") } categories = {} # PORO report_data: have an add_product method, or a from_products class method (even better!) @products.each do |product| if categories[product[:category]] categories[product[:category]][:count] += product[:quantity] categories[product[:category]][:value] += product[:price] * product[:quantity] else categories[product[:category]] = { count: product[:quantity], value: product[:price] * product[:quantity] } end end report_data[:categories] = categories send_report_email(email_to, report_data) save_report_to_file(report_data) report_data end def apply_bulk_discount(category, discount_percent) products_in_category = @products.select { |p| p[:category] == category } if products_in_category.length < @discount_threshold raise "Not enough products to apply bulk discount" end products_in_category.each do |product original_price = product[:price] product[:price] = original_price - (original_price * discount_percent / 100) # HERE BE DRAGONS (callbacks go out the window) Product.where(name: product[:name], store_id: @store_id).update_all(price: product[:price]) end end private def validate_products @products.reject! do |product| product[:price] <= 0 or product[:quantity] < 0 or product[:name].empty? end end def send_report_email(email, data InventoryMailer.report(email, data).deliver_later end def save_report_to_file(data) File.open("/tmp/inventory_report_#{@store_id}_#{Time.now.to_i}.json", 'w') do |f| f.write(JSON.generate(data)) end end def parse_json(data) # JSON parsing logic end def parse_xml(data) # XML parsing logic endend