Binding interface for bank statements

This commit is contained in:
Martin Lensment 2015-04-15 11:32:51 +03:00
parent 2dfa65645b
commit 851e5368eb
15 changed files with 113 additions and 26 deletions

View file

@ -1,7 +1,7 @@
class Admin::BankStatementsController < AdminController class Admin::BankStatementsController < AdminController
load_and_authorize_resource load_and_authorize_resource
before_action :set_bank_statement, only: [:show, :download_import_file] before_action :set_bank_statement, only: [:show, :download_import_file, :bind_invoices]
def index def index
@q = BankStatement.search(params[:q]) @q = BankStatement.search(params[:q])
@ -10,7 +10,8 @@ class Admin::BankStatementsController < AdminController
end end
def show def show
@q = @bank_statement.bank_transactions.search(params[:q]) @q = @bank_statement.bank_transactions.includes(:account_activity).search(params[:q])
@q.sorts = 'account_activity_id desc' if @q.sorts.empty?
@bank_transactions = @q.result.page(params[:page]) @bank_transactions = @q.result.page(params[:page])
end end
@ -30,6 +31,16 @@ class Admin::BankStatementsController < AdminController
end end
end end
def bind_invoices
@bank_statement.bind_invoices
flash[:notice] = t('invoices_were_fully_binded') if @bank_statement.fully_binded?
flash[:warning] = t('invoices_were_partially_binded') if @bank_statement.partially_binded?
flash[:alert] = t('no_invoices_were_binded') if @bank_statement.not_binded?
redirect_to [:admin, @bank_statement]
end
def download_import_file def download_import_file
filename = @bank_statement.import_file_path.split('/').last filename = @bank_statement.import_file_path.split('/').last
send_data File.open(@bank_statement.import_file_path, 'r').read, filename: filename send_data File.open(@bank_statement.import_file_path, 'r').read, filename: filename

View file

@ -5,6 +5,10 @@ class BankStatement < ActiveRecord::Base
validates :bank_code, :iban, :queried_at, presence: true validates :bank_code, :iban, :queried_at, presence: true
FULLY_BINDED = 'fully_binded'
PARTIALLY_BINDED = 'partially_binded'
NOT_BINDED = 'not_binded'
def import def import
import_th6_file && save import_th6_file && save
end end
@ -50,7 +54,30 @@ class BankStatement < ActiveRecord::Base
nil nil
end end
def bind_with_invoices # TODO: Cache this to database so it can be used for searching
bank_transactions.unbinded.each(&:bind_with_invoice) def status
if bank_transactions.unbinded.count == bank_transactions.count
NOT_BINDED
elsif bank_transactions.unbinded.count == 0
FULLY_BINDED
else
PARTIALLY_BINDED
end
end
def not_binded?
status == NOT_BINDED
end
def partially_binded?
status == PARTIALLY_BINDED
end
def fully_binded?
status == FULLY_BINDED
end
def bind_invoices
bank_transactions.unbinded.each(&:bind_invoice)
end end
end end

View file

@ -8,10 +8,15 @@ class BankTransaction < ActiveRecord::Base
account_activity.present? account_activity.present?
end end
def binded_invoice
return unless binded?
account_activity.invoice
end
# For successful binding, reference number, invoice id and sum must match with the invoice # For successful binding, reference number, invoice id and sum must match with the invoice
# rubocop: disable Metrics/PerceivedComplexity # rubocop: disable Metrics/PerceivedComplexity
# rubocop: disable Metrics/CyclomaticComplexity # rubocop: disable Metrics/CyclomaticComplexity
def bind_with_invoice def bind_invoice
return if binded? return if binded?
registrar = Registrar.find_by(reference_no: reference_no) registrar = Registrar.find_by(reference_no: reference_no)
return unless registrar return unless registrar

View file

@ -7,6 +7,10 @@ class Invoice < ActiveRecord::Base
validates :invoice_type, :due_date, :currency, :seller_name, validates :invoice_type, :due_date, :currency, :seller_name,
:seller_iban, :buyer_name, :invoice_items, :vat_prc, presence: true :seller_iban, :buyer_name, :invoice_items, :vat_prc, presence: true
def to_s
I18n.t('invoice_no', no: id)
end
def seller_address def seller_address
[seller_street, seller_city, seller_state, seller_zip].reject(&:blank?).compact.join(', ') [seller_street, seller_city, seller_state, seller_zip].reject(&:blank?).compact.join(', ')
end end

View file

@ -11,18 +11,25 @@
%table.table.table-hover.table-bordered.table-condensed %table.table.table-hover.table-bordered.table-condensed
%thead %thead
%tr %tr
%th{class: 'col-xs-2'} %th{class: 'col-xs-3'}
= sort_link(@q, 'created_at', t('imported_at')) = sort_link(@q, 'created_at', t('imported_at'))
%th{class: 'col-xs-2'} %th{class: 'col-xs-3'}
= sort_link(@q, 'bank_code') = sort_link(@q, 'bank_code')
%th{class: 'col-xs-2'} %th{class: 'col-xs-3'}
= sort_link(@q, 'iban', t('iban').upcase) = sort_link(@q, 'iban', t('iban').upcase)
/ TODO: Make this searchable by caching the status to the database
%th{class: 'col-xs-3'}
= t('status')
%tbody %tbody
- @bank_statements.each do |x| - @bank_statements.each do |x|
%tr %tr
%td= link_to(l(x.created_at), admin_bank_statement_path(x)) %td= link_to(l(x.created_at), admin_bank_statement_path(x))
%td= x.bank_code %td= x.bank_code
%td= x.iban %td= x.iban
- sc = 'text-success' if x.status == BankStatement::FULLY_BINDED
- sc = 'text-warning' if x.status == BankStatement::PARTIALLY_BINDED
- sc = 'text-danger' if x.status == BankStatement::NOT_BINDED
%td{class: sc}= t(x.status)
.row .row
.col-md-12 .col-md-12
= paginate @bank_statements = paginate @bank_statements

View file

@ -3,7 +3,7 @@
%h2.text-center-xs= t('bank_statement') %h2.text-center-xs= t('bank_statement')
.col-sm-6 .col-sm-6
%h2.text-right.text-center-xs %h2.text-right.text-center-xs
= link_to(t('bind_with_invoices'), '#', class: 'btn btn-primary') = link_to(t('bind_invoices'), bind_invoices_admin_bank_statement_path, class: 'btn btn-primary', method: :post)
= link_to(t('back_to_bank_statements'), admin_bank_statements_path, class: 'btn btn-default') = link_to(t('back_to_bank_statements'), admin_bank_statements_path, class: 'btn btn-default')
%hr %hr
%row %row
@ -16,9 +16,15 @@
%dt= t('bank_code') %dt= t('bank_code')
%dd= @bank_statement.bank_code %dd= @bank_statement.bank_code
%dt= t('iban').upcase %dt= t('iban')
%dd= @bank_statement.iban %dd= @bank_statement.iban
%dt= t('status')
- sc = 'text-success' if @bank_statement.status == BankStatement::FULLY_BINDED
- sc = 'text-warning' if @bank_statement.status == BankStatement::PARTIALLY_BINDED
- sc = 'text-danger' if @bank_statement.status == BankStatement::NOT_BINDED
%dd{class: sc}= t(@bank_statement.status)
%dt= t('queried_at') %dt= t('queried_at')
%dd= l(@bank_statement.queried_at) %dd= l(@bank_statement.queried_at)
@ -46,7 +52,7 @@
%th{class: 'col-xs-2'} %th{class: 'col-xs-2'}
= sort_link(@q, 'currency') = sort_link(@q, 'currency')
%th{class: 'col-xs-2'} %th{class: 'col-xs-2'}
= sort_link(@q, 'account_activity', t('status')) = sort_link(@q, 'account_activity_id', t('status'))
%tbody %tbody
- @bank_transactions.each do |x| - @bank_transactions.each do |x|
%tr %tr
@ -54,10 +60,8 @@
%td= x.buyer_name %td= x.buyer_name
%td= x.sum %td= x.sum
%td= x.currency %td= x.currency
%td - c = x.binded? ? 'text-success' : 'text-danger'
- c = x.binded? ? 'label-success' : 'label-danger' %td{class: c}= x.binded? ? t('binded') : t('not_binded')
%span.label{class: c}= x.binded? ? t('binded') : t('not_binded')
&nbsp;
.row .row
.col-md-12 .col-md-12
= paginate @bank_transactions = paginate @bank_transactions

View file

@ -16,6 +16,14 @@
%dt= t('document_no') %dt= t('document_no')
%dd= @bank_transaction.document_no %dd= @bank_transaction.document_no
%dt= t('status')
- c = @bank_transaction.binded? ? 'text-success' : 'text-danger'
%dd{class: c}= @bank_transaction.binded? ? t('binded') : t('not_binded')
- if @bank_transaction.binded?
%dt= t('binded_invoice')
%dd= link_to(@bank_transaction.binded_invoice, '#')
%dt= t('bank_reference') %dt= t('bank_reference')
%dd= @bank_transaction.bank_reference %dd= @bank_transaction.bank_reference

View file

@ -63,10 +63,7 @@
/ /.nav-collapse / /.nav-collapse
.container .container
- display = (flash.empty?) ? 'none' : 'block' = render 'registrar/shared/flash'
#flash{style: "display: #{display};"}
- type = (flash[:notice]) ? 'bg-success' : 'bg-danger'
.alert{class: type}= flash[:notice] || flash[:alert]
= yield = yield
.footer.text-right .footer.text-right

View file

@ -1,4 +1,5 @@
- display = (flash[:notice] || flash[:alert]) ? 'block' : 'none' - display = (flash[:notice] || flash[:alert] || flash[:warning]) ? 'block' : 'none'
#flash{style: "display: #{display};"} #flash{style: "display: #{display};"}
- type = (flash[:notice]) ? 'bg-success' : 'bg-danger' - type = (flash[:notice]) ? 'bg-success' : 'bg-danger'
.alert{class: type}= flash[:notice] || flash[:alert] - type = 'bg-warning' if flash[:warning]
.alert{class: type}= flash[:notice] || flash[:alert] || flash[:warning]

View file

@ -659,7 +659,7 @@ en:
issue_date: 'Issue date' issue_date: 'Issue date'
due_date: 'Due date' due_date: 'Due date'
payment_term: 'Payment term' payment_term: 'Payment term'
iban: 'Iban' iban: 'IBAN'
bank: 'Bank' bank: 'Bank'
swift: 'Swift' swift: 'Swift'
issuer: 'Issuer' issuer: 'Issuer'
@ -692,7 +692,13 @@ en:
bank_reference: 'Bank reference' bank_reference: 'Bank reference'
document_no: 'Document no' document_no: 'Document no'
import_file: 'Import file' import_file: 'Import file'
bind_with_invoices: 'Bind with invoices' bind_invoices: 'Bind invoices'
url: 'URL' url: 'URL'
binded: 'Binded' binded: 'Binded'
not_binded: 'Not binded' not_binded: 'Not binded'
binded_invoice: 'Binded invoice'
fully_binded: 'Fully binded'
partially_binded: 'Partially binded'
invoices_were_fully_binded: 'Invoices were fully binded'
invoices_were_partially_binded: 'Invoices were partially binded'
no_invoices_were_binded: 'No invoices were binded'

View file

@ -86,6 +86,7 @@ Rails.application.routes.draw do
resources :keyrelays resources :keyrelays
resources :bank_statements do resources :bank_statements do
post 'bind_invoices', on: :member
get 'download_import_file', on: :member get 'download_import_file', on: :member
end end

View file

@ -0,0 +1,10 @@
class FixAccountBalancesToDecimal < ActiveRecord::Migration
def change
Account.all.each do |x|
x.balance = 0.0 unless x.balance
x.save
end
change_column :accounts, :balance, :decimal, null: false, default: 0
end
end

View file

@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20150414124630) do ActiveRecord::Schema.define(version: 20150415075408) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
@ -29,7 +29,7 @@ ActiveRecord::Schema.define(version: 20150414124630) do
create_table "accounts", force: :cascade do |t| create_table "accounts", force: :cascade do |t|
t.integer "registrar_id" t.integer "registrar_id"
t.string "account_type" t.string "account_type"
t.decimal "balance" t.decimal "balance", default: 0.0, null: false
t.datetime "created_at" t.datetime "created_at"
t.datetime "updated_at" t.datetime "updated_at"
end end

View file

@ -99,6 +99,12 @@ namespace :import do
x.save(validate: false) x.save(validate: false)
end end
Registrar.all.each do |x|
next if x.cash_account
x.accounts.create(account_type: Account::CASH)
x.save(validate: false)
end
puts "-----> Imported #{count} new registrars in #{(Time.zone.now.to_f - start).round(2)} seconds" puts "-----> Imported #{count} new registrars in #{(Time.zone.now.to_f - start).round(2)} seconds"
end end

View file

@ -59,7 +59,7 @@ describe BankStatement do
bs.bank_transactions.count.should == 2 bs.bank_transactions.count.should == 2
AccountActivity.count.should == 0 AccountActivity.count.should == 0
bs.bind_with_invoices bs.bind_invoices
AccountActivity.count.should == 1 AccountActivity.count.should == 1