Skip to content

Commit

Permalink
Add class and type for financial transactions foodcoops#367
Browse files Browse the repository at this point in the history
This change introduces two new data types to group the financial
transactions. Now every transaction has a "type", which itself belongs
to a "class".
Types should be used add structured information to an transaction, instead
of writing it into the notice textfield. E.g. this could be used to have
different types depending on the source of money (cash vs. bank transfer).
Classes are shown as different columns in the tables and will be uses to
group transactions of specific types. They should be used if not the whole
amount of ordergroup should be used to order fodd. E.g. if there is a
deposit or membership fee, which is independent of the normal credit.
This will allow us to implement additional features based on classes in
the future. E.g. the sum of transactions in the "membership fee" class
must be positive to allow food orders or show a big warning if it is bellow
a certain value.
  • Loading branch information
paroga committed Feb 25, 2016
1 parent 6bf8e6b commit bdeb0b1
Show file tree
Hide file tree
Showing 29 changed files with 224 additions and 12 deletions.
15 changes: 15 additions & 0 deletions app/controllers/admin/financial_transaction_classes_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class Admin::FinancialTransactionClassesController < Admin::BaseController
inherit_resources

def index
@financial_transaction_classes = FinancialTransactionClass.order('name ASC')
end

def destroy
@financial_transaction_class = FinancialTransactionClass.find(params[:id])
@financial_transaction_class.destroy
redirect_to admin_financial_transaction_classes_url, notice: t('admin.financial_transaction_classes.destroy.notice')
rescue => error
redirect_to admin_financial_transaction_classes_url, alert: t('admin.financial_transaction_classes.destroy.error', error: error.message)
end
end
15 changes: 15 additions & 0 deletions app/controllers/admin/financial_transaction_types_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class Admin::FinancialTransactionTypesController < Admin::BaseController
inherit_resources

def index
@financial_transaction_types = FinancialTransactionType.order('name ASC')
end

def destroy
@financial_transaction_type = FinancialTransactionClass.find(params[:id])
@financial_transaction_type.destroy
redirect_to admin_financial_transaction_types_url, notice: t('admin.financial_transaction_types.destroy.notice')
rescue => error
redirect_to admin_financial_transaction_types_url, alert: t('admin.financial_transaction_types.destroy.error', error: error.message)
end
end
5 changes: 4 additions & 1 deletion app/controllers/finance/financial_transactions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def index_collection

def new
@financial_transaction = @ordergroup.financial_transactions.build
@financial_transaction.financial_transaction_type = FinancialTransactionType.first
end

def create
Expand All @@ -55,10 +56,12 @@ def new_collection

def create_collection
raise I18n.t('finance.financial_transactions.controller.create_collection.error_note_required') if params[:note].blank?
type = FinancialTransactionType.find_by_id(params[:type])
type = FinancialTransactionType.first if type.nil?
params[:financial_transactions].each do |trans|
# ignore empty amount fields ...
unless trans[:amount].blank?
Ordergroup.find(trans[:ordergroup_id]).add_financial_transaction!(trans[:amount], params[:note], @current_user)
Ordergroup.find(trans[:ordergroup_id]).add_financial_transaction!(trans[:amount], params[:note], @current_user, type)
end
end
redirect_to finance_ordergroups_url, notice: I18n.t('finance.financial_transactions.controller.create_collection.notice')
Expand Down
3 changes: 2 additions & 1 deletion app/models/financial_transaction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
class FinancialTransaction < ActiveRecord::Base
belongs_to :ordergroup
belongs_to :user
belongs_to :financial_transaction_type

validates_presence_of :amount, :note, :user_id, :ordergroup_id
validates_numericality_of :amount, greater_then: -100_000,
Expand All @@ -12,6 +13,6 @@ class FinancialTransaction < ActiveRecord::Base

# Use this save method instead of simple save and after callback
def add_transaction!
ordergroup.add_financial_transaction! amount, note, user
ordergroup.add_financial_transaction! amount, note, user, financial_transaction_type
end
end
7 changes: 7 additions & 0 deletions app/models/financial_transaction_class.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class FinancialTransactionClass < ActiveRecord::Base
has_many :financial_transaction_types

validates :name, presence: true

scope :table_columns, -> { order(name: :asc) }
end
7 changes: 7 additions & 0 deletions app/models/financial_transaction_type.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class FinancialTransactionType < ActiveRecord::Base
belongs_to :financial_transaction_class
has_many :financial_transactions

validates :name, presence: true
validates :financial_transaction_class, presence: true
end
2 changes: 1 addition & 1 deletion app/models/order.rb
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ def close!(user)
transaction do # Start updating account balances
for group_order in gos
price = group_order.price * -1 # decrease! account balance
group_order.ordergroup.add_financial_transaction!(price, transaction_note, user)
group_order.ordergroup.add_financial_transaction!(price, transaction_note, user, FinancialTransactionType.first) # TODO: make type a config option
end

if stockit? # Decreases the quantity of stock_articles
Expand Down
6 changes: 3 additions & 3 deletions app/models/ordergroup.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ def get_available_funds(exclude = nil)

# Creates a new FinancialTransaction for this Ordergroup and updates the account_balance accordingly.
# Throws an exception if it fails.
def add_financial_transaction!(amount, note, user)
transaction do
t = FinancialTransaction.new(:ordergroup => self, :amount => amount, :note => note, :user => user)
def add_financial_transaction!(amount, note, user, financial_transaction_type)
transaction do
t = FinancialTransaction.new(:ordergroup => self, :amount => amount, :note => note, :user => user, :financial_transaction_type => financial_transaction_type)
t.save!
self.account_balance = financial_transactions.sum('amount')
save!
Expand Down
5 changes: 5 additions & 0 deletions app/views/admin/financial_transaction_classes/_form.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
= simple_form_for [:admin, @financial_transaction_class] do |f|
= f.input :name
.form-actions
= f.button :submit
= link_to t('ui.or_cancel'), :back
3 changes: 3 additions & 0 deletions app/views/admin/financial_transaction_classes/edit.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- title t '.title'

= render 'form'
21 changes: 21 additions & 0 deletions app/views/admin/financial_transaction_classes/index.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
- title t '.title'

- content_for :actionbar do
= link_to t('.new_financial_transaction_class'), new_admin_financial_transaction_class_path, class: 'btn btn-primary'

- content_for :sidebar do
%p= t('.first_paragraph', url: link_to(t('.new_financial_transaction_classes'), new_admin_financial_transaction_class_path)).html_safe

%table.table.table-striped
%thead
%tr
%th= t '.name'
%th= t 'ui.actions'
%tbody
- for financial_transaction_class in @financial_transaction_classes
%tr
%td= link_to financial_transaction_class.name, [:admin, financial_transaction_class]
%td
= link_to t('ui.edit'), edit_admin_financial_transaction_class_path(financial_transaction_class), class: 'btn btn-mini'
= link_to t('ui.delete'), [:admin, financial_transaction_class], :data => {:confirm => t('admin.confirm', name: financial_transaction_class.name)},
:method => :delete, class: 'btn btn-mini btn-danger'
3 changes: 3 additions & 0 deletions app/views/admin/financial_transaction_classes/new.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- title t '.title'

= render 'form'
4 changes: 4 additions & 0 deletions app/views/admin/financial_transaction_classes/show.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- title t '.title', name: @financial_transaction_class.name

= link_to t('ui.edit'), edit_admin_financial_transaction_class_path(@financial_transaction_class), class: 'btn'
= link_to t('ui.delete'), [:admin, @financial_transaction_class], :data => {:confirm => t('.confirm')}, :method => :delete, class: 'btn btn-danger'
6 changes: 6 additions & 0 deletions app/views/admin/financial_transaction_types/_form.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
= simple_form_for [:admin, @financial_transaction_type] do |f|
= f.input :name
= f.association :financial_transaction_class, :include_blank => false
.form-actions
= f.button :submit
= link_to t('ui.or_cancel'), :back
3 changes: 3 additions & 0 deletions app/views/admin/financial_transaction_types/edit.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- title t '.title'

= render 'form'
21 changes: 21 additions & 0 deletions app/views/admin/financial_transaction_types/index.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
- title t '.title'

- content_for :actionbar do
= link_to t('.new_financial_transaction_type'), new_admin_financial_transaction_type_path, class: 'btn btn-primary'

- content_for :sidebar do
%p= t('.first_paragraph', url: link_to(t('.new_financial_transaction_types'), new_admin_financial_transaction_type_path)).html_safe

%table.table.table-striped
%thead
%tr
%th= t '.name'
%th= t 'ui.actions'
%tbody
- for financial_transaction_type in @financial_transaction_types
%tr
%td= link_to financial_transaction_type.name, [:admin, financial_transaction_type]
%td
= link_to t('ui.edit'), edit_admin_financial_transaction_type_path(financial_transaction_type), class: 'btn btn-mini'
= link_to t('ui.delete'), [:admin, financial_transaction_type], :data => {:confirm => t('admin.confirm', name: financial_transaction_type.name)},
:method => :delete, class: 'btn btn-mini btn-danger'
3 changes: 3 additions & 0 deletions app/views/admin/financial_transaction_types/new.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- title t '.title'

= render 'form'
8 changes: 8 additions & 0 deletions app/views/admin/financial_transaction_types/show.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
- title t '.title', name: @financial_transaction_type.name

%p
%b= heading_helper(FinancialTransactionType, :financial_transaction_class) + ':'
= @financial_transaction_type.financial_transaction_class.name

= link_to t('ui.edit'), edit_admin_financial_transaction_type_path(@financial_transaction_type), class: 'btn'
= link_to t('ui.delete'), [:admin, @financial_transaction_type], :data => {:confirm => t('.confirm')}, :method => :delete, class: 'btn btn-danger'
16 changes: 14 additions & 2 deletions app/views/finance/financial_transactions/_transactions.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,26 @@
- if with_ordergroup
%th= heading_helper FinancialTransaction, :ordergroup
%th= heading_helper FinancialTransaction, :user
- if FinancialTransactionType.count > 1
%th= heading_helper FinancialTransaction, :financial_transaction_type
%th= sort_link_helper heading_helper(FinancialTransaction, :note), "note"
%th= sort_link_helper heading_helper(FinancialTransaction, :amount), "amount"
- FinancialTransactionClass.table_columns.each do |c|
%th
- if c.name?
= sort_link_helper c.name, "amount"
- else
= sort_link_helper heading_helper(FinancialTransaction, :amount), "amount"
%tbody
- @financial_transactions.each do |t|
%tr
%td= format_time(t.created_on)
- if with_ordergroup
%td= h link_to t.ordergroup.name, finance_ordergroup_transactions_path(t.ordergroup)
%td= h show_user(t.user)
- if FinancialTransactionType.count > 1
%td= h t.financial_transaction_type.name
%td= h t.note
%td.currency{:style => "color:#{t.amount < 0 ? 'red' : 'black'}; width:5em"}= number_to_currency(t.amount)
- FinancialTransactionClass.table_columns.each do |c|
%td.currency{:style => "color:#{t.amount < 0 ? 'red' : 'black'}; width:5em"}
- if t.financial_transaction_type.financial_transaction_class == c
= number_to_currency(t.amount)
4 changes: 4 additions & 0 deletions app/views/finance/financial_transactions/new.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
= simple_form_for @financial_transaction, :url => finance_ordergroup_transactions_path(@ordergroup),
:validate => true do |f|
= f.hidden_field :ordergroup_id
- if FinancialTransactionType.count > 1
= f.association :financial_transaction_type, :as => :radio_buttons
- else
= f.association :financial_transaction_type, :as => :hidden
= f.input :amount
= f.input :note, :as => :text
.form-actions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
.well.well-small= t('.sidebar')

= form_tag finance_create_transaction_collection_path do
- if FinancialTransactionType.count > 1
%p
%b= heading_helper FinancialTransaction, :financial_transaction_type
= select_tag :type, options_for_select(FinancialTransactionType.order(:name).map { |t| [ t.name, t.id ] })
%p
%b= heading_helper FinancialTransaction, :note
= text_field_tag :note, params[:note], class: 'input-xlarge', required: 'required'
Expand Down
16 changes: 14 additions & 2 deletions app/views/home/index.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,27 @@
%tr
%th= heading_helper FinancialTransaction, :created_on
%th= heading_helper FinancialTransaction, :user
- if FinancialTransactionType.count > 1
%th= heading_helper FinancialTransaction, :financial_transaction_type
%th= heading_helper FinancialTransaction, :note
%th= heading_helper FinancialTransaction, :amount
- FinancialTransactionClass.table_columns.each do |fc|
%th
- if fc.name?
= fc.name
- else
= heading_helper FinancialTransaction, :amount
- for ft in current_user.ordergroup.financial_transactions.limit(5).order('created_on DESC')
%tr
%td= format_time(ft.created_on)
%td= h(show_user(ft.user))
- if FinancialTransactionType.count > 1
%td= h(ft.financial_transaction_type.name)
%td= h(ft.note)
- color = ft.amount < 0 ? 'red' : 'black'
%td{:style => "color:#{color}; width:5em", :class => "currency"}= number_to_currency(ft.amount)
- FinancialTransactionClass.table_columns.each do |fc|
%td{:style => "color:#{color}; width:5em", :class => "currency"}
- if ft.financial_transaction_type.financial_transaction_class == fc
= number_to_currency(ft.amount)
%br/
%p= link_to t('.my_ordergroup.transactions.view'), my_ordergroup_path

Expand Down
2 changes: 2 additions & 0 deletions config/navigation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
subnav.item :users, I18n.t('navigation.admin.users'), admin_users_path
subnav.item :ordergroups, I18n.t('navigation.admin.ordergroups'), admin_ordergroups_path
subnav.item :workgroups, I18n.t('navigation.admin.workgroups'), admin_workgroups_path
subnav.item :financial_transaction_classes, I18n.t('navigation.admin.financial_transaction_classes'), admin_financial_transaction_classes_path
subnav.item :financial_transaction_types, I18n.t('navigation.admin.financial_transaction_types'), admin_financial_transaction_types_path
subnav.item :config, I18n.t('navigation.admin.config'), admin_config_path
end

Expand Down
4 changes: 4 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,10 @@
namespace :admin do
root to: 'base#index'

resources :financial_transaction_classes

resources :financial_transaction_types

resources :users do
post :sudo, on: :member
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
class CreateFinancialTransactionClassAndTypes < ActiveRecord::Migration
def change
create_table :financial_transaction_classes do |t|
t.string :name, :null => false
end

create_table :financial_transaction_types do |t|
t.string :name, :null => false
t.references :financial_transaction_class, :null => false
end

change_table :financial_transactions do |t|
t.references :financial_transaction_type
end

execute "INSERT INTO financial_transaction_classes (id, name) VALUES (1, '')"
execute "INSERT INTO financial_transaction_types (id, name, financial_transaction_class_id) VALUES (1, 'Foodsoft', 1)"
execute "UPDATE financial_transactions SET financial_transaction_type_id = 1"

change_column_null :financial_transactions, :financial_transaction_type_id, false
end
end
12 changes: 11 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 20160218151041) do
ActiveRecord::Schema.define(version: 20160219123220) do

create_table "article_categories", force: :cascade do |t|
t.string "name", limit: 255, default: "", null: false
Expand Down Expand Up @@ -76,12 +76,22 @@

add_index "deliveries", ["supplier_id"], name: "index_deliveries_on_supplier_id", using: :btree

create_table "financial_transaction_classes", force: :cascade do |t|
t.string "name", null: false
end

create_table "financial_transaction_types", force: :cascade do |t|
t.string "name", null: false
t.integer "financial_transaction_class_id", null: false
end

create_table "financial_transactions", force: :cascade do |t|
t.integer "ordergroup_id", limit: 4, default: 0, null: false
t.decimal "amount", precision: 8, scale: 2, default: 0, null: false
t.text "note", limit: 65535, null: false
t.integer "user_id", limit: 4, default: 0, null: false
t.datetime "created_on", null: false
t.integer "financial_transaction_type_id", null: false
end

add_index "financial_transactions", ["ordergroup_id"], name: "index_financial_transactions_on_ordergroup_id", using: :btree
Expand Down
13 changes: 13 additions & 0 deletions spec/factories/financial_transaction_type.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
require 'factory_girl'

FactoryGirl.define do

factory :financial_transaction_class do
sequence(:name) { |n| Faker::Lorem.characters(rand(2..12)) + " ##{n}" }
end

factory :financial_transaction_type do
sequence(:name) { |n| Faker::Lorem.words(rand(2..4)).join(' ') + " ##{n}" }
end

end
2 changes: 2 additions & 0 deletions spec/integration/balancing_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
require_relative '../spec_helper'

feature 'settling an order', js: true do
let(:ftc) { create :financial_transaction_class }
let(:ftt) { create :financial_transaction_type, financial_transaction_class: ftc }
let(:admin) { create :user, groups:[create(:workgroup, role_finance: true)] }
let(:user) { create :user, groups:[create(:ordergroup)] }
let(:supplier) { create :supplier }
Expand Down
4 changes: 3 additions & 1 deletion spec/integration/product_distribution_example_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
require_relative '../spec_helper'

feature 'product distribution', js: true do
let(:ftc) { create :financial_transaction_class }
let(:ftt) { create :financial_transaction_type, financial_transaction_class: ftc }
let(:admin) { create :admin }
let(:user_a) { create :user, groups: [create(:ordergroup)] }
let(:user_b) { create :user, groups: [create(:ordergroup)] }
Expand All @@ -13,7 +15,7 @@
# make sure users have enough money to order
[user_a, user_b].each do |user|
ordergroup = Ordergroup.find(user.ordergroup.id)
ordergroup.add_financial_transaction! 5000, 'for ordering', admin
ordergroup.add_financial_transaction! 5000, 'for ordering', admin, ftt
end
order # make sure order is referenced
end
Expand Down

0 comments on commit bdeb0b1

Please sign in to comment.