diff --git a/app/controllers/extra_bills_controller.rb b/app/controllers/extra_bills_controller.rb new file mode 100644 index 0000000..3caed45 --- /dev/null +++ b/app/controllers/extra_bills_controller.rb @@ -0,0 +1,70 @@ +class ExtraBillsController < ApplicationController + before_action :set_extra_bill, only: %i[ show edit update destroy ] + + # GET /extra_bills or /extra_bills.json + def index + @extra_bills = ExtraBill.all + end + + # GET /extra_bills/1 or /extra_bills/1.json + def show + end + + # GET /extra_bills/new + def new + @extra_bill = ExtraBill.new + end + + # GET /extra_bills/1/edit + def edit + end + + # POST /extra_bills or /extra_bills.json + def create + @extra_bill = ExtraBill.new(extra_bill_params) + + respond_to do |format| + if @extra_bill.save + format.html { redirect_to extra_bill_url(@extra_bill), notice: "Extra bill was successfully created." } + format.json { render :show, status: :created, location: @extra_bill } + else + format.html { render :new, status: :unprocessable_entity } + format.json { render json: @extra_bill.errors, status: :unprocessable_entity } + end + end + end + + # PATCH/PUT /extra_bills/1 or /extra_bills/1.json + def update + respond_to do |format| + if @extra_bill.update(extra_bill_params) + format.html { redirect_to extra_bill_url(@extra_bill), notice: "Extra bill was successfully updated." } + format.json { render :show, status: :ok, location: @extra_bill } + else + format.html { render :edit, status: :unprocessable_entity } + format.json { render json: @extra_bill.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /extra_bills/1 or /extra_bills/1.json + def destroy + @extra_bill.destroy + + respond_to do |format| + format.html { redirect_to extra_bills_url, notice: "Extra bill was successfully destroyed." } + format.json { head :no_content } + end + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_extra_bill + @extra_bill = ExtraBill.find(params[:id]) + end + + # Only allow a list of trusted parameters through. + def extra_bill_params + params.require(:extra_bill).permit(:description, :amount, :deduct_autopaid) + end +end diff --git a/app/helpers/extra_bills_helper.rb b/app/helpers/extra_bills_helper.rb new file mode 100644 index 0000000..e5a38c2 --- /dev/null +++ b/app/helpers/extra_bills_helper.rb @@ -0,0 +1,2 @@ +module ExtraBillsHelper +end diff --git a/app/models/expense.rb b/app/models/expense.rb index 2a1104e..48febb8 100644 --- a/app/models/expense.rb +++ b/app/models/expense.rb @@ -14,4 +14,12 @@ class Expense < ApplicationRecord def self.total Expense.sum(&:payment) end + + def self.monthly_total + Expense.all.map(&:monthly).sum.round(2) + end + + def self.autopaid_total + Expense.where(autopaid: true).map(&:monthly).sum.round(2) + end end diff --git a/app/models/extra_bill.rb b/app/models/extra_bill.rb new file mode 100644 index 0000000..95d1845 --- /dev/null +++ b/app/models/extra_bill.rb @@ -0,0 +1,5 @@ +class ExtraBill < ApplicationRecord + def adjusted_amount + deduct_autopaid? ? amount - Expense.autopaid_total : amount + end +end diff --git a/app/models/member.rb b/app/models/member.rb index 4e713a3..c8aad4b 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -17,7 +17,7 @@ class Member < ApplicationRecord ((Income.total - others_included_income) / Income.total).round(2) end - def burden_amount - burden_percent * Expense.all.map(&:monthly).sum.round(2) + def burden_amount(total_amount: Expense.monthly_total) + burden_percent * total_amount end end diff --git a/app/views/extra_bills/_extra_bill.html.erb b/app/views/extra_bills/_extra_bill.html.erb new file mode 100644 index 0000000..e077fb7 --- /dev/null +++ b/app/views/extra_bills/_extra_bill.html.erb @@ -0,0 +1,53 @@ +
+

+ Description: + <%= extra_bill.description %> +

+ +

+ Amount: + <%= extra_bill.amount %> +

+ +

+ Adjusted Amount: + <%= extra_bill.adjusted_amount %> +

+ +

+ Accounted For: + <%= Expense.autopaid_total %> +

+ +

+ Deduct autopaid: + <%= extra_bill.deduct_autopaid %> +

+ +

+ + + + + + + + + + <% Member.all.each do |member| %> + + + + + + <% end %> + +
MemberBurden PercentBurden Amount
<%= member.name %><%= member.burden_percent * 100 %>%<%= number_to_currency(member.burden_amount(total_amount: extra_bill.adjusted_amount)) %>
+

+ + <% if action_name != "show" %> + <%= link_to "Show this extra bill", extra_bill, class: "rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %> + <%= link_to 'Edit this extra bill', edit_extra_bill_path(extra_bill), class: "rounded-lg py-3 ml-2 px-5 bg-gray-100 inline-block font-medium" %> +
+ <% end %> +
diff --git a/app/views/extra_bills/_extra_bill.json.jbuilder b/app/views/extra_bills/_extra_bill.json.jbuilder new file mode 100644 index 0000000..b4b6212 --- /dev/null +++ b/app/views/extra_bills/_extra_bill.json.jbuilder @@ -0,0 +1,2 @@ +json.extract! extra_bill, :id, :description, :amount, :deduct_autopaid, :created_at, :updated_at +json.url extra_bill_url(extra_bill, format: :json) diff --git a/app/views/extra_bills/_form.html.erb b/app/views/extra_bills/_form.html.erb new file mode 100644 index 0000000..a00dfbf --- /dev/null +++ b/app/views/extra_bills/_form.html.erb @@ -0,0 +1,32 @@ +<%= form_with(model: extra_bill, class: "contents") do |form| %> + <% if extra_bill.errors.any? %> +
+

<%= pluralize(extra_bill.errors.count, "error") %> prohibited this extra_bill from being saved:

+ + +
+ <% end %> + +
+ <%= form.label :description %> + <%= form.text_field :description, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full" %> +
+ +
+ <%= form.label :amount %> + <%= form.text_field :amount, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full" %> +
+ +
+ <%= form.label :deduct_autopaid %> + <%= form.check_box :deduct_autopaid, class: "block mt-2 h-5 w-5" %> +
+ +
+ <%= form.submit class: "rounded-lg py-3 px-5 bg-blue-600 text-white inline-block font-medium cursor-pointer" %> +
+<% end %> diff --git a/app/views/extra_bills/edit.html.erb b/app/views/extra_bills/edit.html.erb new file mode 100644 index 0000000..01fc93d --- /dev/null +++ b/app/views/extra_bills/edit.html.erb @@ -0,0 +1,8 @@ +
+

Editing extra bill

+ + <%= render "form", extra_bill: @extra_bill %> + + <%= link_to "Show this extra bill", @extra_bill, class: "ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %> + <%= link_to "Back to extra bills", extra_bills_path, class: "ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %> +
diff --git a/app/views/extra_bills/index.html.erb b/app/views/extra_bills/index.html.erb new file mode 100644 index 0000000..b3926a1 --- /dev/null +++ b/app/views/extra_bills/index.html.erb @@ -0,0 +1,14 @@ +
+ <% if notice.present? %> +

<%= notice %>

+ <% end %> + +
+

Extra bills

+ <%= link_to 'New extra bill', new_extra_bill_path, class: "rounded-lg py-3 px-5 bg-blue-600 text-white block font-medium" %> +
+ +
+ <%= render @extra_bills %> +
+
diff --git a/app/views/extra_bills/index.json.jbuilder b/app/views/extra_bills/index.json.jbuilder new file mode 100644 index 0000000..c9fcca7 --- /dev/null +++ b/app/views/extra_bills/index.json.jbuilder @@ -0,0 +1 @@ +json.array! @extra_bills, partial: "extra_bills/extra_bill", as: :extra_bill diff --git a/app/views/extra_bills/new.html.erb b/app/views/extra_bills/new.html.erb new file mode 100644 index 0000000..93bdabb --- /dev/null +++ b/app/views/extra_bills/new.html.erb @@ -0,0 +1,7 @@ +
+

New extra bill

+ + <%= render "form", extra_bill: @extra_bill %> + + <%= link_to 'Back to extra bills', extra_bills_path, class: "ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %> +
diff --git a/app/views/extra_bills/show.html.erb b/app/views/extra_bills/show.html.erb new file mode 100644 index 0000000..1575349 --- /dev/null +++ b/app/views/extra_bills/show.html.erb @@ -0,0 +1,15 @@ +
+
+ <% if notice.present? %> +

<%= notice %>

+ <% end %> + + <%= render @extra_bill %> + + <%= link_to 'Edit this extra_bill', edit_extra_bill_path(@extra_bill), class: "mt-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %> +
+ <%= button_to 'Destroy this extra_bill', extra_bill_path(@extra_bill), method: :delete, class: "mt-2 rounded-lg py-3 px-5 bg-gray-100 font-medium" %> +
+ <%= link_to 'Back to extra_bills', extra_bills_path, class: "ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %> +
+
diff --git a/app/views/extra_bills/show.json.jbuilder b/app/views/extra_bills/show.json.jbuilder new file mode 100644 index 0000000..7659dc9 --- /dev/null +++ b/app/views/extra_bills/show.json.jbuilder @@ -0,0 +1 @@ +json.partial! "extra_bills/extra_bill", extra_bill: @extra_bill diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 9029348..46a0e9e 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -16,6 +16,7 @@ diff --git a/config/routes.rb b/config/routes.rb index 7d04545..7f55438 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,5 @@ Rails.application.routes.draw do + resources :extra_bills resource :dashboard, only: :show resources :incomes resources :members diff --git a/db/migrate/20230224232804_create_extra_bills.rb b/db/migrate/20230224232804_create_extra_bills.rb new file mode 100644 index 0000000..ba3b671 --- /dev/null +++ b/db/migrate/20230224232804_create_extra_bills.rb @@ -0,0 +1,11 @@ +class CreateExtraBills < ActiveRecord::Migration[7.0] + def change + create_table :extra_bills do |t| + t.string :description + t.decimal :amount + t.boolean :deduct_autopaid + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 11a339c..e3c238e 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2022_11_20_205511) do +ActiveRecord::Schema[7.0].define(version: 2023_02_24_232804) do create_table "expenses", force: :cascade do |t| t.string "description", default: "", null: false t.decimal "payment", precision: 8, scale: 2, default: "0.0", null: false @@ -21,6 +21,14 @@ ActiveRecord::Schema[7.0].define(version: 2022_11_20_205511) do t.datetime "updated_at", null: false end + create_table "extra_bills", force: :cascade do |t| + t.string "description" + t.decimal "amount" + t.boolean "deduct_autopaid" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "incomes", force: :cascade do |t| t.string "description", default: "", null: false t.boolean "included", default: true, null: false diff --git a/test/controllers/extra_bills_controller_test.rb b/test/controllers/extra_bills_controller_test.rb new file mode 100644 index 0000000..35049d2 --- /dev/null +++ b/test/controllers/extra_bills_controller_test.rb @@ -0,0 +1,48 @@ +require "test_helper" + +class ExtraBillsControllerTest < ActionDispatch::IntegrationTest + setup do + @extra_bill = extra_bills(:one) + end + + test "should get index" do + get extra_bills_url + assert_response :success + end + + test "should get new" do + get new_extra_bill_url + assert_response :success + end + + test "should create extra_bill" do + assert_difference("ExtraBill.count") do + post extra_bills_url, params: { extra_bill: { amount: @extra_bill.amount, deduct_autopaid: @extra_bill.deduct_autopaid, description: @extra_bill.description } } + end + + assert_redirected_to extra_bill_url(ExtraBill.last) + end + + test "should show extra_bill" do + get extra_bill_url(@extra_bill) + assert_response :success + end + + test "should get edit" do + get edit_extra_bill_url(@extra_bill) + assert_response :success + end + + test "should update extra_bill" do + patch extra_bill_url(@extra_bill), params: { extra_bill: { amount: @extra_bill.amount, deduct_autopaid: @extra_bill.deduct_autopaid, description: @extra_bill.description } } + assert_redirected_to extra_bill_url(@extra_bill) + end + + test "should destroy extra_bill" do + assert_difference("ExtraBill.count", -1) do + delete extra_bill_url(@extra_bill) + end + + assert_redirected_to extra_bills_url + end +end diff --git a/test/fixtures/extra_bills.yml b/test/fixtures/extra_bills.yml new file mode 100644 index 0000000..febbccc --- /dev/null +++ b/test/fixtures/extra_bills.yml @@ -0,0 +1,11 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + description: MyString + amount: 9.99 + deduct_autopaid: false + +two: + description: MyString + amount: 9.99 + deduct_autopaid: false diff --git a/test/models/extra_bill_test.rb b/test/models/extra_bill_test.rb new file mode 100644 index 0000000..01a4bf0 --- /dev/null +++ b/test/models/extra_bill_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class ExtraBillTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/system/extra_bills_test.rb b/test/system/extra_bills_test.rb new file mode 100644 index 0000000..77ec8ea --- /dev/null +++ b/test/system/extra_bills_test.rb @@ -0,0 +1,45 @@ +require "application_system_test_case" + +class ExtraBillsTest < ApplicationSystemTestCase + setup do + @extra_bill = extra_bills(:one) + end + + test "visiting the index" do + visit extra_bills_url + assert_selector "h1", text: "Extra bills" + end + + test "should create extra bill" do + visit extra_bills_url + click_on "New extra bill" + + fill_in "Amount", with: @extra_bill.amount + check "Deduct autopaid" if @extra_bill.deduct_autopaid + fill_in "Description", with: @extra_bill.description + click_on "Create Extra bill" + + assert_text "Extra bill was successfully created" + click_on "Back" + end + + test "should update Extra bill" do + visit extra_bill_url(@extra_bill) + click_on "Edit this extra bill", match: :first + + fill_in "Amount", with: @extra_bill.amount + check "Deduct autopaid" if @extra_bill.deduct_autopaid + fill_in "Description", with: @extra_bill.description + click_on "Update Extra bill" + + assert_text "Extra bill was successfully updated" + click_on "Back" + end + + test "should destroy Extra bill" do + visit extra_bill_url(@extra_bill) + click_on "Destroy this extra bill", match: :first + + assert_text "Extra bill was successfully destroyed" + end +end