diff --git a/app/controllers/transactions_controller.rb b/app/controllers/transactions_controller.rb index 648565f..613eab0 100644 --- a/app/controllers/transactions_controller.rb +++ b/app/controllers/transactions_controller.rb @@ -13,15 +13,16 @@ def new end def create - @transaction = @wallet.transactions.build(transaction_params) - - if @transaction.save - respond_to do |format| - format.turbo_stream - format.html { redirect_to transactions_path, notice: "Transaction created successfully!" } - end - else - render :new, status: :unprocessable_entity + @transaction = TransactionService.new(@wallet, transaction_params).execute + + respond_to do |format| + format.turbo_stream + format.html { redirect_to @wallet, notice: "Transaction created successfully!" } + end + rescue ActiveRecord::RecordInvalid => e + respond_to do |format| + format.turbo_stream { render turbo_stream: turbo_stream.replace("transaction_form", partial: "form", locals: { transaction: e.record }) } + format.html { render :new, status: :unprocessable_entity } end end diff --git a/app/services/transaction_service.rb b/app/services/transaction_service.rb new file mode 100644 index 0000000..5704719 --- /dev/null +++ b/app/services/transaction_service.rb @@ -0,0 +1,44 @@ +class TransactionService + def initialize(wallet, transaction_params) + @wallet = wallet + @transaction_params = transaction_params + end + + def execute + ActiveRecord::Base.transaction do + @transaction = @wallet.transactions.create!(@transaction_params) + update_holding + @transaction + end + end + + private + + def update_holding + holding = @wallet.holdings.lock.find_or_initialize_by(instrument_id: @transaction.instrument_id) + + if @transaction.buy? + handle_buy(holding) + else + handle_sell(holding) + end + + if holding.quantity.zero? + holding.destroy! + else + holding.save! + end + end + + def handle_buy(holding) + new_quantity = holding.quantity.to_f + @transaction.quantity + new_total_cost = (holding.quantity.to_f * holding.average_price.to_f) + (@transaction.quantity * @transaction.price) + holding.quantity = new_quantity + holding.average_price = new_total_cost / new_quantity + end + + def handle_sell(holding) + raise ActiveRecord::RecordInvalid.new(holding) if holding.quantity < @transaction.quantity + holding.quantity -= @transaction.quantity + end +end