diff --git a/app/controllers/cachers.rb b/app/controllers/cachers.rb
index e256f15ec..4d2590e56 100644
--- a/app/controllers/cachers.rb
+++ b/app/controllers/cachers.rb
@@ -22,6 +22,11 @@ def missing
end
def generate
+ @model = params[:by] ? Kernel.const_get(params[:by].camel_case + "Cache") : BranchCache
+ if @from_date and @to_date
+ (@from_date..@to_date).each{|date| @model.update(:date => date)}
+ else
+ @model.update(:date => (@date || Date.today))
if Branch.count > 0
if @from_date and @to_date
(@from_date..@to_date).each{|date| BranchCache.update(date)}
@@ -52,10 +57,21 @@ def freshen
def consolidate
get_cachers
group_by = @level.to_s.singularize
- group_by_model = Kernel.const_get(group_by.camelcase)
+ group_by_model = Kernel.const_get(group_by.camelcase) rescue Kernel.const_get(params[:by].camel_case)
unless group_by == "loan"
@cachers = @cachers.group_by{|c| c.send("#{group_by}_id".to_sym)}.to_hash.map do |group_by_id, cachers|
- cachers.reduce(:consolidate)
+ # when we are aggregating "by" something else we need to consolidate cachers that span across dates and
+ # add cachers for the same date
+ if params[:by]
+ $debug = true if group_by_id == 2
+ cachers_for_date = cachers.group_by{|c| c.date}.to_hash.map{|d, cs| [d,cs.reduce(:+)]}.to_hash
+ r = cachers_for_date.values.reduce(:consolidate)
+ r.model_id = group_by_id
+ r.branch_id = nil
+ r
+ else
+ cachers.reduce(:consolidate)
+ end
end
end
display @cachers, :template => 'cachers/index', :layout => (params[:layout] or Nothing).to_sym
@@ -103,37 +119,60 @@ def parse_dates
def get_cachers
q = {}
q[:branch_id] = params[:branch_id] unless params[:branch_id].blank?
- if (not params[:branch_id].blank?)
- q[:center_id] = params[:center_id] unless (params[:center_id].blank? or params[:center_id].to_i == 0)
- else
- q[:model_name] = "Branch"
+ unless params[:branch_id].blank?
+ if params[:center_id]
+ q[:center_id] = params[:center_id] unless (params[:center_id].blank? or params[:center_id].to_i == 0)
+ else
+ q[:center_id.not] = 0
+ end
+ end
+ if true
+ if params[:by]
+ q[:model_name] = params[:by].camel_case
+ q[:center_id] ||= 0 unless q[:center_id.not]
+ q[:model_id] = params[:model_id] if params[:model_id]
+ else
+ q[:model_name] = ["Branch","Center"]
+ end
end
q[:date] = @date if @date
q[:date] = @from_date..@to_date if (@from_date and @to_date)
q[:stale] = true if params[:stale]
@cachers = Cacher.all(q)
q.delete(:model_name)
- @missing_centers = CenterCache.missing(q)
+ if params[:by]
+ @missing_centers = {} # TODO
+ else
+ @missing_centers = {} #CenterCache.missing(q)
+ end
get_context
end
def get_context
@center = params[:center_id].blank? ? nil : Center.get(params[:center_id])
@branch = params[:branch_id].blank? ? nil : Branch.get(params[:branch_id])
+ @area = params[:area_id].blank? ? nil : Area.get(params[:area_id])
+ @region = params[:region_id].blank? ? nil : Region.get(params[:region_id])
@center_names = @cachers.blank? ? {} : Center.all(:id => @cachers.aggregate(:center_id)).aggregate(:id, :name).to_hash
@branch_names = @cachers.blank? ? {} : Branch.all(:id => @cachers.aggregate(:branch_id)).aggregate(:id, :name).to_hash
q = (@from_date and @to_date) ? {:date => @from_date..@to_date} : {:date => @date}
- @stale_centers = CenterCache.all(q.merge(:stale => true))
+ @stale_centers = Cacher.all(q.merge(:stale => true))
@stale_branches = BranchCache.all(q.merge(:stale => true))
@last_cache_update = @cachers.aggregate(:updated_at.min)
@resource = params[:action] == "index" ? :cachers : (params[:action].to_s + "_" + "cachers").to_sym
@keys = [:branch_id, :center_id] + (ReportFormat.get(params[:report_format]) || ReportFormat.first).keys
@total_keys = @keys[2..-1]
if @resource == :split_cachers
- @level = params[:center_id].blank? ? :branches : :centers
+ @level = (params[:center_id].blank? ? :branches : :centers)
@keys = [:date] + @keys
else
- @level = (not params[:center_id].blank?) ? :loans : ((not params[:branch_id].blank?) ? :centers : :branches)
+ @level = @center ? :loans : (@branch ? :centers : (@area ? :branches : (@region ? :areas : :branches)))
+ if params[:by]
+ @level = :model unless @level == :loans
+ @keys = [:model_name] + @keys
+ @model = Kernel.const_get(params[:by].camel_case)
+ else
+ end
end
end
diff --git a/app/models/cache_observer.rb b/app/models/cache_observer.rb
index 11f37278a..a0fdf22d9 100644
--- a/app/models/cache_observer.rb
+++ b/app/models/cache_observer.rb
@@ -4,13 +4,16 @@ class CacheObserver
observe Payment, Loan
def self.get_date(obj)
- date = obj.respond_to?(:applied_on) ? obj.applied_on : (obj.respond_to?(:received_on) ? obj.received_on : nil)
+ date = obj.respond_to?(:applied_on) ? obj.applied_on : (obj.respond_to?(:received_on) ? obj.received_on : enil)
end
def self.make_stale(obj)
center_id = obj.c_center_id
date = CacheObserver.get_date(obj)
+ loan = obj.is_a?(Loan) ? obj : obj.loan
+ info = loan.info(date)
CenterCache.stalify(:center_id => obj.c_center_id, :date => date) if date
+ FundingLineCache.stalify(:center_id => obj.c_center_id, :date => date, :model_id => info.funding_line_id)
end
after :create do
diff --git a/app/models/cacher.rb b/app/models/cacher.rb
index 45c198423..284c7cd07 100644
--- a/app/models/cacher.rb
+++ b/app/models/cacher.rb
@@ -8,6 +8,11 @@ class Cacher
property :model_id, Integer, :nullable => false, :index => true, :unique => [:model_name, :date], :key => true
property :branch_id, Integer, :index => true, :key => true
property :center_id, Integer, :index => true, :key => true
+<<<<<<< HEAD
+
+ property :funding_line_id, Integer, :index => true
+=======
+>>>>>>> 53f1094295262f8d6c7e371a03dedd10ddff71af
property :scheduled_outstanding_total, Float, :nullable => false
property :scheduled_outstanding_principal, Float, :nullable => false
property :actual_outstanding_total, Float, :nullable => false
@@ -150,6 +155,7 @@ def + (other)
me = self.attributes; other = other.attributes;
attrs = me + other; attrs[:date] = date; attrs[:model_name] = "Sum";
attrs[:model_id] = nil; attrs[:branch_id] = nil; attrs[:center_id] = nil;
+ attrs[:stale] = me[:stale] || other[:stale]
Cacher.new(attrs)
end
@@ -163,7 +169,7 @@ def self.process_queue
class BranchCache < Cacher
def self.recreate(date = Date.today, branch_ids = nil)
- self.update(date, branch_ids, true)
+ self.update(:date => date, :branch_ids => branch_ids, :force => true)
end
def self.update(date = Date.today, branch_ids = nil, force = false)
@@ -271,7 +277,8 @@ class CenterCache < Cacher
# these have to be hooks, for obvious reasons, but for now we make do with some hardcoded magic!
-s EXTRA_FIELDS = [:delayed_disbursals]
+ EXTRA_FIELDS = [:delayed_disbursals]
+
def self.update(hash = {})
# creates a cache per center for branches and centers per the hash passed as argument
t = Time.now
@@ -348,8 +355,16 @@ def self.stalify(options = {})
@center = Center.get(cid)
d = options[:date].class != Date ? (Date.parse(options[:date]) rescue nil) : options[:date]
raise ArgumentError.new("Cannot parse date") unless d
-
- repository.adapter.execute("UPDATE cachers SET stale=1 WHERE center_id=#{cid} OR (center_id = 0 AND branch_id = #{@center.branch_id}) AND date >= '#{d.strftime('%Y-%m-%d')}' AND stale=0")
+ sql = %Q{
+ UPDATE cachers
+ SET stale=1
+ WHERE (center_id=#{cid}
+ OR (center_id = 0
+ AND branch_id = #{@center.branch_id}))
+ AND date >= '#{d.strftime('%Y-%m-%d')}'
+ AND stale=0
+ AND type IN ('CenterCache','BranchCache')}
+ repository.adapter.execute(sql)
# puts "STALIFIED CENTERS in #{(Time.now - t).round(2)} secs"
end
@@ -370,3 +385,189 @@ def self.missing(selection)
end
+
+
+class Cache < Cacher
+
+ # this class is for caching according to properties other than branch and center id i.e. funding line, staff member, loan product and
+ # any other arbitrary collection of loan including portfolios
+ # all references to funding line in comments is purely for illustration and not meant literally
+
+
+ def self.update(hash = {})
+ debugger
+ # is our cache based off fields in the loan history table?
+ base_model_name = self.to_s.gsub("Cache","")
+ loan_history_field = "#{base_model_name.snake_case}_id".to_sym
+ # creates a cache per funding line for branches and funding lines per the hash passed as argument
+ date = hash.delete(:date) || Date.today
+ force = hash.delete(:force) || false
+ hash = hash.select{|k,v| [:branch_id, :center_id, loan_history_field].include?(k)}.to_hash
+
+ unless force
+ # the problem of doing 2 factor stalification - we might have within the same center some loans that belong to a stale funding line
+ # and others that belong to other fuding lines.
+ # therefore, the incremental update must necessarily be per loan_ids.
+ # we have to find the loan ids in the stale funding line
+ fl_caches = self.all(:center_id.not => 0, :date => date)
+ stale_caches = fl_caches.stale.aggregate(:model_id, :center_id)
+ missing_caches = LoanHistory.all(:date.gte => date).aggregate(loan_history_field, :center_id) - fl_caches.aggregate(:model_id, :center_id)
+ caches_to_do = stale_caches + missing_caches
+ unless caches_to_do.blank?
+ ids = caches_to_do.map{|x| "(#{x.join(',')})"}
+ sql = "select loan_id from loan_history where (#{loan_history_field}, center_id) in (#{ids.join(',')}) group by loan_id"
+ loan_ids = repository.adapter.query(sql)
+ hash[:loan_id] = loan_ids
+ end
+ end
+
+ fl_data = self.create(hash.merge(:date => date, :group_by => [:branch_id, :center_id, loan_history_field])).deepen.values.sum
+ return false if fl_data == nil
+ now = DateTime.now
+ fl_data.delete(:no_group)
+ return true if fl_data.empty?
+ fls = fl_data.map do |center_id,funding_line_hash|
+ funding_line_hash.map do |fl_id, fl|
+ fl_data[center_id][fl_id].merge({:type => self.to_s,:model_name => base_model_name, :model_id => fl_id, :date => date, :updated_at => now})
+ end
+ end.flatten
+ if fls.nil?
+ return false
+ end
+ _fls = fls.map{|fl| fl.delete(loan_history_field); fl}
+ sql = get_bulk_insert_sql("cachers", _fls)
+ # destroy the relevant funding_line caches in the database
+ debugger
+ ids = fl_data.map{|center_id, models|
+ models.map{|fl_id, data|
+ [center_id, fl_id]
+ }
+ }
+ ids = ids.flatten(1).map{|x| "(#{x.join(',')})"}.join(",")
+ raise unless repository.adapter.execute("delete from cachers where model_name = '#{base_model_name}' and (center_id, model_id) in (#{ids})")
+ repository.adapter.execute(sql)
+
+ # now do the branch aggregates for each funding line cache
+ Kernel.const_get(base_model_name).all.each do |fl|
+ debugger
+ relevant_branch_ids = (hash[:center_ids] ? Center.all(:id => hash[:center_ids]) : Center.all).aggregate(:branch_id)
+ branch_data_hash = self.all(:model_name => base_model_name, :branch_id => relevant_branch_ids, :date => date, :center_id.gt => 0, :model_id => fl.id).group_by{|x| x.branch_id}.to_hash
+
+ # we now have {:branch => [{...center data...}, {...center data...}]}, ...
+ # we have to convert this to {:branch => { sum of centers data }, ...}
+
+ branch_data = branch_data_hash.map do |bid,ccs|
+ sum_centers = ccs.map do |c|
+ center_sum_attrs = c.attributes.select{|k,v| v.is_a? Numeric}.to_hash
+ end
+ [bid, sum_centers.reduce({}){|s,h| s+h}]
+ end.to_hash
+
+ # TODO then add the loans that do not belong to any center
+ # this does not exist right now so there is no code here.
+ # when you add clients directly to the branch, do also update the code here
+
+ branch_data.map do |bid, c|
+ debugger
+ bc = self.first_or_new({:model_name => base_model_name, :branch_id => bid, :date => date, :model_id => fl.id, :center_id => 0})
+ attrs = c.merge(:branch_id => bid, :center_id => 0, :model_id => fl.id, :stale => false, :updated_at => DateTime.now, :model_name => base_model_name)
+ if bc.new?
+ bc.attributes = attrs.merge(:id => nil, :updated_at => DateTime.now)
+ bc.save
+ else
+ bc.update(attrs.merge(:id => bc.id))
+ end
+ end
+ end
+ end
+
+
+ def self.create(hash = {})
+ # creates a cacher from loan_history table for any arbitrary condition. Also does grouping
+ debugger
+ base_model_name = self.to_s.gsub("Cache","")
+ loan_history_field = "#{base_model_name.snake_case}_id".to_sym
+ date = hash.delete(:date) || Date.today
+ group_by = hash.delete(:group_by) || [:branch_id, :center_id, loan_history_field]
+ cols = hash.delete(:cols) || COLS
+ flow_cols = FLOW_COLS
+ balances = LoanHistory.latest_sum(hash,date, group_by, cols)
+ pmts = LoanHistory.composite_key_sum(LoanHistory.all(hash.merge(:date => date)).aggregate(:composite_key), group_by, flow_cols)
+ # if there are no loan history rows that match today, then pmts is just a single hash, else it is a hash of hashes
+
+`` # set up some default hashes to use in case we get dodgy results back.
+ ng_pmts = flow_cols.map{|c| [c,0]}.to_hash # ng = no good. we return this if we get dodgy data
+ ng_bals = cols.map{|c| [c,0]}.to_hash # ng = no good. we return this if we get dodgy data
+ # workaround for the situation where no rows get returned for centers without loans.
+ # this makes it very difficult to find missing center caches so we must have a row for all centers, even if it is full of zeros
+ # find all relevant centers
+
+ # if we are doing only a subset of centers / funding lines, we do it using loan_ids.
+ # so if we have some loan_ids, then we just use these
+ if hash[:loan_id]
+ universe = LoanHistory.all(hash).aggregate(:branch_id, :center_id, loan_history_field)
+ else
+ # else we find all the centers that we're interested in
+ _u = Center.all(hash[:center_id] ? {:id => hash[:center_id]} : {}).aggregate(:branch_id, :id) # array of [[:branch_id, :center_id]...] for all branches and centers
+ # now add the funding line id to each of these universes
+ universe = Kernel.const_get(base_model_name).all.map{|f|
+ __u = Marshal.load(Marshal.dump(_u)) # effing ruby pass by reference....my ass
+ __u.map{|u| u.push(f.id)}
+ }.flatten(1)
+ end
+ universe.map do |k|
+ _p = pmts[k] || ng_pmts
+ _b = balances[k] || ng_bals
+ extra = balances[k] ? {} : {:center_id => k[1], :branch_id => k[0], :model_id => k[2]} # for ng rows, we need to insert center_id and branch_id
+ [k, _p.merge(_b).merge(extra)]
+ end.to_hash
+
+ end
+
+
+ # executes an SQL statement to mark all center caches and branch caches for this center as stale. Only does this for cachers on or after options[:date]
+ # params [Hash] a hash of options thus {:center_id => Integer, :date => Date or String, :model_id => Integer}
+ def self.stalify(options = {})
+ base_model_name = self.to_s.gsub("Cache","")
+ loan_history_field = "#{base_model_name.snake_case}_id".to_sym
+
+ t = Time.now
+ raise NotAcceptable unless [:center_id, :date].map{|o| options[o]}.compact.size == 2
+ cid = options[:center_id]
+ @center = Center.get(cid)
+ d = options[:date].class != Date ? (Date.parse(options[:date]) rescue nil) : options[:date]
+ raise ArgumentError.new("Cannot parse date") unless d
+
+ sql = %Q{
+ UPDATE cachers SET stale=1
+ WHERE model_name = '#{base_model_name}'
+ AND model_id=#{options[:model_id]}
+ AND (center_id = #{cid}
+ OR (center_id = 0 AND branch_id = #{@center.branch_id})
+ OR (branch_id = 0 and center_id = 0 and model_id = #{options[:model_id]})
+ )
+ AND date >= '#{d.strftime('%Y-%m-%d')}' AND stale=0}
+ repository.adapter.execute(sql)
+ end
+
+ # finds the missing caches given some caches
+ def self.missing(selection)
+ base_model_name = self.to_s.gsub("Cache","")
+ loan_history_field = "#{base_model_name.snake_case}_id".to_sym
+
+ bs = self.all(selection).aggregate(:date, :model_id).group_by{|x| x[0]}.to_hash.map{|k,v| [k, v.map{|x| x[1]}]}.to_hash
+ # bs is a hash of {:date => [:center_id,...]}
+ date = selection.delete(:date)
+ selection[:id] = selection.delete(loan_history_field) if selection[loan_history_field]
+ hs = Kernel.const_get(base_model_name).all(selection.merge(:creation_date.lte => date)).aggregate(:id)
+ date.map{|d| [d,hs - (bs[d] || [])]}.to_hash
+ end
+end
+
+
+class FundingLineCache < Cache
+end
+
+class LoanProductCache < Cache
+end
+
diff --git a/app/models/data_access_observer.rb b/app/models/data_access_observer.rb
index e573429ec..9886e0baf 100644
--- a/app/models/data_access_observer.rb
+++ b/app/models/data_access_observer.rb
@@ -1,6 +1,6 @@
class DataAccessObserver
include DataMapper::Observer
- observe *(DataMapper::Model.descendants.to_a - [AuditTrail, Cacher, BranchCache, CenterCache] + [Branch, Center, ClientGroup, Client, Loan, Payment, Fee]).uniq # strange bug where observer drops some of the descnedants.
+ observe *(DataMapper::Model.descendants.to_a - [AuditTrail, Cacher, BranchCache, CenterCache, FundingLineCache] + [Branch, Center, ClientGroup, Client, Loan, Payment, Fee]).uniq # strange bug where observer drops some of the descnedants.
def self.insert_session(id)
diff --git a/app/models/loan.rb b/app/models/loan.rb
index 9197e6175..10bfbc453 100644
--- a/app/models/loan.rb
+++ b/app/models/loan.rb
@@ -86,6 +86,7 @@ def set_bullet_installments
property :created_by_user_id, Integer, :nullable => true, :index => true
property :cheque_number, String, :length => 20, :nullable => true, :index => true
property :cycle_number, Integer, :default => 1, :nullable => false, :index => true
+ property :loan_pool_id, Integer, :nullable => true, :index => true
#these amount and disbursal dates are required for TakeOver loan types.
property :original_amount, Integer
@@ -144,6 +145,8 @@ def set_bullet_installments
belongs_to :verified_by, :child_key => [:verified_by_user_id], :model => 'User'
belongs_to :repayment_style
+ belongs_to :loan_pool
+
belongs_to :organization, :parent_key => [:org_guid], :child_key => [:parent_org_guid], :nullable => true
property :parent_org_guid, String, :nullable => true
diff --git a/app/views/browse/_totalinfo.html.haml b/app/views/browse/_totalinfo.html.haml
index 38c6de9b4..5db640099 100644
--- a/app/views/browse/_totalinfo.html.haml
+++ b/app/views/browse/_totalinfo.html.haml
@@ -55,7 +55,7 @@
%td.number
%h1
= (cbc.fees_due_today + cbc.fees_paid_today).to_currency(:mostfit_default)
- - total[:paid] += cbc.fees_due_today
+ - total[:due] += cbc.fees_due_today
%td.number
%h1.green
= cbc.fees_paid_today.to_currency(:mostfit_default)
diff --git a/app/views/cachers/_areas.html.haml b/app/views/cachers/_areas.html.haml
new file mode 100644
index 000000000..47cbeee51
--- /dev/null
+++ b/app/views/cachers/_areas.html.haml
@@ -0,0 +1,31 @@
+%h1 Branches
+%table.report.nojs
+ %thead
+ %tr.header
+ - @keys.each do |at|
+ %th
+ = at.to_s.gsub("_","
")
+ - unless @resource == :split_cachers
+ %th
+ split
+ - @calculated_total_row = {}
+
+ - @cachers.sort_by{|c| [c.date,@area_names[c.area_id]]}.each do |c|
+ - next if (c.actual_outstanding_principal == 0) and (c.total_paid == 0) and c.total_due == 0
+ - cls = (c.stale ? "stale" : "") + " " + cycle('odd','even')
+ = partial :cache_row, :cache => c, :cls => cls
+ %tfoot
+ %tr.total
+ - @keys.each_with_index do |k,i|
+ %th{:style => "text-align: right"}
+ - if i == 0
+ Sum of Cached Values
+ - else
+ - if @total_keys.include?(k)
+ = @calculated_total_row[k].to_currency
+ - else
+
+ %th
+
+
+
diff --git a/app/views/cachers/_cache_row.html.haml b/app/views/cachers/_cache_row.html.haml
index 0f41accb0..69d7de55b 100644
--- a/app/views/cachers/_cache_row.html.haml
+++ b/app/views/cachers/_cache_row.html.haml
@@ -8,7 +8,10 @@
- else
- val = cache.send(at) rescue 0
%td{:style => "text-align: right", :class => "#{at} text"}
- - if at == :date
+ - if at == :model_name
+ - @thing = @model.get(cache.model_id) rescue nil
+ = (link_to @thing.name, resource(:cachers, request.send(:query_params).merge(:model_id => cache.model_id))) if @thing
+ - elsif at == :date
= link_to val.strftime("%Y/%m/%d"), resource(:cachers, request.send(:query_params).merge(:date => val))
- date = val
- elsif at == :branch_id
@@ -37,4 +40,4 @@
- unless @resource == :split_cachers
%td
= (link_to 'split', url(:split_cachers, request.send(:query_params).merge(:branch_id => bid))) if @level == :branches
- = (link_to 'split', url(:split_cachers, request.send(:query_params).merge(:center_id => cid))) if @level == :centers
\ No newline at end of file
+ = (link_to 'split', url(:split_cachers, request.send(:query_params).merge(:center_id => cid))) if @level == :centers
diff --git a/app/views/cachers/_loans.html.haml b/app/views/cachers/_loans.html.haml
index c447f689f..a3d5af136 100644
--- a/app/views/cachers/_loans.html.haml
+++ b/app/views/cachers/_loans.html.haml
@@ -12,7 +12,10 @@
-# only fix payments that are mismatched with the schedule
-# = check_box :name => :only_mismatches, :checked => :checked
- total = {}
- - histories = LoanHistory.latest({:center_id => params[:center_id]}, @date)
+ - debugger
+ - selection = {:center_id => params[:center_id]}
+ - selection.merge!("#{params[:by]}_id".to_sym => params[:model_id]) if params[:by]
+ - histories = LoanHistory.latest(selection, @date)
%h1
== Center #{@center.name}
%table.report.nojs
@@ -34,11 +37,11 @@
%td
= link_to h.loan.client.name, resource(h.loan.client)
- @keys.each do |at|
- - val = h.send(at)
+ - val = h.send(at) rescue "-"
%td
= val.is_a?(Numeric) ? val : val
- total[at] ||= 0
- - total[at] += h.send(at) if h.send(at).is_a? Numeric
+ - (total[at] += h.send(at) if h.send(at).is_a? Numeric) rescue "-"
%tfoot
%tr.total
%td
@@ -54,4 +57,4 @@
%tr.total
- @center_row = CenterCache.first(:date => @date, :center_id => params[:center_id])
- @keys = [:x,:y,:z] + @keys
- = (partial :cache_row, :cache => @center_row, :cls => "total", :ignore_total => true) if @center_row
\ No newline at end of file
+ = (partial :cache_row, :cache => @center_row, :cls => "total", :ignore_total => true) if @center_row
diff --git a/app/views/cachers/_model.html.haml b/app/views/cachers/_model.html.haml
new file mode 100644
index 000000000..16baa2bd2
--- /dev/null
+++ b/app/views/cachers/_model.html.haml
@@ -0,0 +1,31 @@
+%h1 Model
+%table.report.nojs
+ %thead
+ %tr.header
+ - @keys.each do |at|
+ %th
+ = at.to_s.gsub("_","
")
+ - unless @resource == :split_cachers
+ %th
+ split
+ - @calculated_total_row = {}
+
+ - @cachers.each do |c|
+ - next if (c.actual_outstanding_principal == 0) and (c.total_paid == 0) and c.total_due == 0
+ - cls = (c.stale ? "stale" : "") + " " + cycle('odd','even')
+ = partial :cache_row, :cache => c, :cls => cls
+ %tfoot
+ %tr.total
+ - @keys.each_with_index do |k,i|
+ %th{:style => "text-align: right"}
+ - if i == 0
+ Sum of Cached Values
+ - else
+ - if @total_keys.include?(k)
+ = @calculated_total_row[k].to_currency
+ - else
+
+ %th
+
+
+
diff --git a/app/views/cachers/index.html.haml b/app/views/cachers/index.html.haml
index 2c751d38e..6284d11af 100644
--- a/app/views/cachers/index.html.haml
+++ b/app/views/cachers/index.html.haml
@@ -28,9 +28,8 @@
6: { sorter: 'mostfit_currency' },
7: { sorter: 'mostfit_currency' }
}} )});
-
- unless @stale_centers.empty? and @stale_branches.empty? and @missing_centers.values.flatten.empty?
- .nb
+ .warn
= link_to "#{@stale_centers.count} stale centers", resource(:cachers, query_params.merge(:model_name => "Center", :stale => true, :date => @date))
and
= link_to "#{@stale_branches.count} stale branches", resource(:cachers, query_params.merge(:model_name => "Branch", :stale => true, :date => @date))
@@ -80,6 +79,12 @@
= select :name => 'report_format', :collection => ReportFormat.all,:text_method => :name, :value_method => :id, :selected => (params[:report_format] || 1).to_s, :prompt => 'Select a report format', :class => 'chosen'
= submit 'apply filter'
+ %b by
+ - root_url_hash = query_params.dup
+ - root_url_hash.delete(:by); root_url_hash.delete(:branch_id); root_url_hash.delete(:center_id); root_url_hash.delete(:model_id)
+ = link_to 'funding_line', url(:consolidate_cachers, root_url_hash.merge(:by => "funding_line"))
+ = link_to 'loan_product', url(:consolidate_cachers, root_url_hash.merge(:by => "loan_product"))
+
- if @cachers.count == 0
%h3
No caches found.
diff --git a/app/views/data_entry/payments/by_center.html.haml b/app/views/data_entry/payments/by_center.html.haml
index 269052a8e..b5f167705 100644
--- a/app/views/data_entry/payments/by_center.html.haml
+++ b/app/views/data_entry/payments/by_center.html.haml
@@ -1,15 +1,22 @@
:javascript
- $(document).ready(function() {
- $("#paying_branch_selector").change(function(){
- $("#paying_center_selector").html('');
+ function load_centers() {
+ $("#paying_center_selector").html('');
$.ajax({
type: "GET",
- url: "/branches/centers/"+$("#paying_branch_selector").val()+"?paying=true&date=#{@date.strftime('%Y-%m-%d')}",
+ url: "/branches/centers/"+$("#paying_branch_selector").val()+"?paying=true&date=" + $("#for_date").val(),
success: function(data){
$("#paying_center_selector").html(data);
}
});
- });
+ }
+
+ $(document).ready(function() {
+ $("#paying_branch_selector").change(function(){
+ load_centers();
+ });
+ $("#for_date").change(function(){
+ load_centers();
+ });
});
- if @center and @date
@@ -205,6 +212,12 @@
%h1 Choose a center to record a repayment for
= form_for(@payment, :action => url(:enter_payments, :action => 'by_center'), :method => :get) do
%table.form
+ %tr
+ %th
+ For Date
+ %td
+ = date_select 'for_date', (@date || Date.today), {:id => 'for_date'}
+ = hidden_field :name => 'return', :value => url(:data_entry)
%tr
%th
In branch
@@ -215,17 +228,6 @@
Centers repaying today
%td
= select :name => 'center_id', :id => 'paying_center_selector', :collection => Center.all(:branch_id => params[:branch_id]), :text_method => :name, :value_method => :id, :selected => params[:center_id].to_s, :prompt => 'Select a center'
- %tr
- %th
- or any other center
- %td
- = text_field :name => 'center_text', :id => 'center_text'
- %tr
- %th
- For Date
- %td
- = date_select :name => 'for_date', :value => @date || Date.today
- = hidden_field :name => 'return', :value => url(:data_entry)
%tr
%td{:colspan => "2"}
= submit 'Submit'
diff --git a/config/router.rb b/config/router.rb
index c3cf08602..24e9b2a7e 100644
--- a/config/router.rb
+++ b/config/router.rb
@@ -83,6 +83,7 @@
end
end
end
+ resources :funding_lines
resources :funders do
resources :portfolios
resources :funding_lines
diff --git a/gems/cache/columnize-0.3.6.gem b/gems/cache/columnize-0.3.6.gem
new file mode 100644
index 000000000..7e57d68ad
Binary files /dev/null and b/gems/cache/columnize-0.3.6.gem differ
diff --git a/gems/cache/linecache-0.46.gem b/gems/cache/linecache-0.46.gem
new file mode 100644
index 000000000..d5ad13028
Binary files /dev/null and b/gems/cache/linecache-0.46.gem differ
diff --git a/gems/cache/rbx-require-relative-0.0.5.gem b/gems/cache/rbx-require-relative-0.0.5.gem
new file mode 100644
index 000000000..4b7e4420f
Binary files /dev/null and b/gems/cache/rbx-require-relative-0.0.5.gem differ
diff --git a/gems/cache/ruby-debug-base-0.10.4.gem b/gems/cache/ruby-debug-base-0.10.4.gem
new file mode 100644
index 000000000..dffd48cc5
Binary files /dev/null and b/gems/cache/ruby-debug-base-0.10.4.gem differ
diff --git a/lib/reportage.rb b/lib/reportage.rb
index dd760b203..06ca845aa 100644
--- a/lib/reportage.rb
+++ b/lib/reportage.rb
@@ -93,15 +93,15 @@ def columns(cols)
# Conjure a bucket class on demand ;). So, we don't have to define empty bucket
# classes for each model that we want to use bucketing with.
-module Kernel
- def self.const_missing(name)
- if name.to_s =~ /Bucket\z/
- const_set(name, Class.new(Bucket))
- else
- super
- end
- end
-end
+#module Kernel
+# def self.const_missing(name)
+# if name.to_s =~ /Bucket\z/
+# const_set(name, Class.new(Bucket))
+# else
+# super
+# end
+# end
+#end
class LoanBucket < Bucket
diff --git a/lib/tasks/add_cache_to_loans.rake b/lib/tasks/add_cache_to_loans.rake
index bb5540bf8..804f38f88 100644
--- a/lib/tasks/add_cache_to_loans.rake
+++ b/lib/tasks/add_cache_to_loans.rake
@@ -13,7 +13,7 @@ require "merb-core"
Merb.start_environment(:environment => ENV['MERB_ENV'] || 'development')
namespace :mostfit do
- namespace :conversion do
+ namespace :data do
desc "This rake task adds some cached values to loans"
task :update_loan_cache do
puts "marking centers..."
@@ -64,6 +64,18 @@ namespace :mostfit do
SET c_client_group_id =
(SELECT c.client_group_id from clients c
WHERE loans.client_id = c.id)})
+ puts "updating loan history areas"
+ repository.adapter.execute(%Q{
+ UPDATE loan_history
+ SET area_id =
+ (SELECT area_id from branches b
+ WHERE b.id = branch_id)})
+ puts "updating loan history regions"
+ repository.adapter.execute(%Q{
+ UPDATE loan_history
+ SET region_id =
+ (SELECT region_id from areas a
+ WHERE a.id = area_id)})
end
end
diff --git a/lib/tasks/convert_takeover_to_new_layout.rake b/lib/tasks/convert_takeover_to_new_layout.rake
index 54be5f697..55d8028cc 100644
--- a/lib/tasks/convert_takeover_to_new_layout.rake
+++ b/lib/tasks/convert_takeover_to_new_layout.rake
@@ -18,7 +18,7 @@ namespace :mostfit do
repository.adapter.execute("truncate table loan_history;") rescue nil
Rake::Task['db:autoupgrade'].invoke
Rake::Task['mostfit:db:prepare'].invoke
- Rake::Task['mostfit:conversion:update_loan_cache'].invoke
+ Rake::Task['mostfit:data:update_loan_cache'].invoke
Rake::Task['mostfit:data:create_history'].invoke
end
end
diff --git a/lib/tasks/prepare_db.rake b/lib/tasks/prepare_db.rake
index 07de13df9..20d7bf397 100644
--- a/lib/tasks/prepare_db.rake
+++ b/lib/tasks/prepare_db.rake
@@ -15,6 +15,7 @@ namespace :mostfit do
desc "populate the database using the csv's"
task :prepare do
repository.adapter.execute("create index index_loan_history_date_center_id_idx on loan_history(date, center_id);") rescue nil
+ repository.adapter.execute("create index index_loan_history_funding_line_id_idx on loan_history(funding_line_id);") rescue nil
repository.adapter.execute("create index index_loan_history_center_id_date on loan_history(center_id,date);") rescue nil
repository.adapter.execute("create index index_loans_deleted_at on loans(deleted_at);") rescue nil
repository.adapter.execute("create index index_clients_deleted_at on clients(deleted_at);") rescue nil
diff --git a/public/stylesheets/style.less b/public/stylesheets/style.less
index dc8d0a5c3..06d3d5e55 100644
--- a/public/stylesheets/style.less
+++ b/public/stylesheets/style.less
@@ -1853,6 +1853,15 @@ table.moreinfo thead th {
margin: 2px;
}
+.warn {
+ background: lightpink;
+ color:#514721;
+ border-color:#FFD324;
+ padding: 3px;
+ border: solid 2px;
+ margin: 2px;
+}
+
table.report {
tr.stale {
background:#ff9999;