Cash flow done.

This commit is contained in:
Tanshu 2012-10-17 00:21:43 +05:30
parent 16b2e8dd51
commit d221a4f4e9
11 changed files with 117 additions and 184 deletions

@ -106,8 +106,8 @@ def main(global_config, **settings):
config.add_route('trial_balance_date', '/TrialBalance/{date}') config.add_route('trial_balance_date', '/TrialBalance/{date}')
config.add_route('trial_balance', '/TrialBalance') config.add_route('trial_balance', '/TrialBalance')
config.add_route('cash_flow_id', '/Reports/CashFlow/{id}') config.add_route('cash_flow_id', '/CashFlow/{id}')
config.add_route('cash_flow', '/Reports/CashFlow') config.add_route('cash_flow', '/CashFlow')
config.add_route('profit_loss', '/Reports/ProfitLoss') config.add_route('profit_loss', '/Reports/ProfitLoss')

@ -0,0 +1,41 @@
<form method="post" autocomplete="off" class="horizontal-form" ng-controller="CashFlowCtrl">
<legend>Cash Flow</legend>
<div class="control-group">
<label for="txtStartDate" class="control-label">Date</label>
<div class="controls">
<datepicker id="txtStartDate" model="info" prop="StartDate" ng-model="info.StartDate"></datepicker>
<datepicker id="txtFinishDate" model="info" prop="FinishDate" ng-model="info.FinishDate"></datepicker>
<button ng-click="show()">Show</button>
</div>
</div>
<div class="control-group">
<label for="gvGrid" class="control-label"></label>
<div class="controls">
<table id="gvGrid" class="clean-table">
<thead>
<tr>
<th>Name</th>
<th>Inflow</th>
<th>Outflow</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in info.Body">
<td><a href="{{item.Url}}">{{item.Name}}</a></td>
<td class="right">{{item.Inflow}}</td>
<td class="right">{{item.Outflow}}</td>
</tr>
</tbody>
<tfoot>
<tr ng-repeat="item in info.Footer">
<td>{{item.Name}}</a></td>
<td class="right">{{item.Inflow}}</td>
<td class="right">{{item.Outflow}}</td>
</tr>
</tfoot>
</table>
</div>
</div>
</form>

@ -87,6 +87,11 @@ overlord_service.factory('TrialBalance', ['$resource', function ($resource) {
return $resource('/TrialBalance/:date'); return $resource('/TrialBalance/:date');
}]); }]);
// TODO: Replace hardcoded url with route_url
overlord_service.factory('CashFlow', ['$resource', function ($resource) {
return $resource('/CashFlow/:id');
}]);
// TODO: Replace hardcoded url with route_url // TODO: Replace hardcoded url with route_url
overlord_service.factory('LedgerService', ['$resource', function ($resource) { overlord_service.factory('LedgerService', ['$resource', function ($resource) {
return $resource('/Services/Accounts/:type'); return $resource('/Services/Accounts/:type');

@ -0,0 +1,17 @@
function CashFlowCtrl($scope, $routeParams, $location, CashFlow) {
if (typeof $routeParams.StartDate === 'undefined') {
$scope.info = CashFlow.get({});
} else if (typeof $routeParams.id === 'undefined') {
$scope.info = CashFlow.get({StartDate:$routeParams.StartDate, FinishDate:$routeParams.FinishDate});
} else {
$scope.info = CashFlow.get({id:$routeParams.id, StartDate:$routeParams.StartDate, FinishDate:$routeParams.FinishDate});
}
$scope.show = function () {
$scope.info = CashFlow.get({StartDate:$scope.info.StartDate, FinishDate:$scope.info.FinishDate}, function (u, putResponseHeaders) {
$location.path('/CashFlow').search({StartDate:u.StartDate, FinishDate:u.FinishDate});
}, function (data, status) {
$scope.toasts.push({Type:'Error', Message:data.data});
});
};
$('#txtStartDate').focus();
}

@ -1,28 +0,0 @@
function Populate(response) {
if (response != null) {
var stateObj = { 'StartDate': response.start_date, 'FinishDate': response.finish_date };
history.pushState(stateObj, 'Display', response.url);
var $table = $('#tbodyMain')
$table.html(response.body);
var $footer = $('#tfootMain')
$footer.html(response.footer);
}
}
function Show(startDate, finishDate) {
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
data: JSON.stringify({ startDate: startDate, finishDate: finishDate }),
dataType: "json",
success: function(response) {
Populate(response);
},
error: function(jqXHR, textStatus) {
$("#ctl00_statusDiv").removeClass().addClass("error");
var msg = $.parseJSON(jqXHR.responseText).Message;
$("#ctl00_statusDiv").html(msg);
}
});
return false;
}

@ -26,6 +26,9 @@ var overlord = angular.module('overlord', ['overlord.directive', 'overlord.filte
when('/ProductLedger', {templateUrl:'/partial/product-ledger.html', controller:ProductLedgerCtrl}). when('/ProductLedger', {templateUrl:'/partial/product-ledger.html', controller:ProductLedgerCtrl}).
when('/ProductLedger/:id', {templateUrl:'/partial/product-ledger.html', controller:ProductLedgerCtrl}). when('/ProductLedger/:id', {templateUrl:'/partial/product-ledger.html', controller:ProductLedgerCtrl}).
when('/CashFlow', {templateUrl:'/partial/cash-flow.html', controller:CashFlowCtrl}).
when('/CashFlow/:id', {templateUrl:'/partial/cash-flow.html', controller:CashFlowCtrl}).
// when('/Ledger', {templateUrl:'/partial/ledger.html', controller:LedgerCtrl, resolve: LedgerCtrl.resolve}). // when('/Ledger', {templateUrl:'/partial/ledger.html', controller:LedgerCtrl, resolve: LedgerCtrl.resolve}).
// when('/Ledger/:id', {templateUrl:'/partial/ledger.html', controller:LedgerCtrl, resolve: LedgerCtrl.resolve}). // when('/Ledger/:id', {templateUrl:'/partial/ledger.html', controller:LedgerCtrl, resolve: LedgerCtrl.resolve}).

@ -40,7 +40,8 @@
${h.ScriptLink(request, 'ledger.js')} ${h.ScriptLink(request, 'ledger.js')}
${h.ScriptLink(request, 'product-ledger.js')} ${h.ScriptLink(request, 'product-ledger.js')}
${h.ScriptLink(request, 'trial_balance.js')} ${h.ScriptLink(request, 'trial-balance.js')}
${h.ScriptLink(request, 'cash-flow.js')}
${h.ScriptLink(request, 'account.js')} ${h.ScriptLink(request, 'account.js')}
${h.ScriptLink(request, 'user.js')} ${h.ScriptLink(request, 'user.js')}

@ -1,58 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal"
metal:use-macro="base">
<tal:block metal:fill-slot="content">
${h.JsLink(request, 'cash_flow.js')}
<script type="text/javascript">
$(document).ready(function() {
$('#txtStartDate').datepicker({ dateFormat: 'dd-M-yy' });
${startDate}
$('#txtFinishDate').datepicker({ dateFormat: 'dd-M-yy'});
${finishDate}
show_url = '${request.route_url('cash_flow')}';
$("#btnSubmit").click(function() { return Show($('#txtStartDate').val(), $('#txtFinishDate').val()); });
});
</script>
<article tal:attributes="class pagecontentclass">
<section>
<h2 class="ribbon-header">Cash Flow</h2>
<form method="post" autocomplete="off">
${h.CsrfToken(request.session)}
<p>
${h.Label('Start Date:', 'txtStartDate')}
${h.TextInput('txtStartDate', css_class = 'non-search-box', autocomplete='off')}
</p>
<p>
${h.Label('Finish Date:', 'txtFinishDate')}
${h.TextInput('txtFinishDate', css_class = 'non-search-box', autocomplete='off')}
</p>
<p>
${h.SubmitButton('btnSubmit', 'Submit')}
</p>
<p>
<table id="gvGrid" class="clean-table">
<thead>
<tr>
<th class="TypeID hide">Type</th>
<th class="Name">Name</th>
<th class="Inflow">Inflow</th>
<th class="Outflow">Outflow</th>
</tr>
</thead>
<tbody id="tbodyMain">
${body}
</tbody>
<tfoot id="tfootMain">
${footer}
</tfoot>
</table>
</p>
${h.EndForm()}
</section>
</article>
</tal:block>
</html>

@ -8,8 +8,6 @@ from pyramid.view import view_config
from brewman.models.auth import User from brewman.models.auth import User
@view_config(context=HTTPNotFound, renderer='brewman:templates/404.mako') @view_config(context=HTTPNotFound, renderer='brewman:templates/404.mako')
def not_found(request): def not_found(request):
return {'title': '404', return {'title': '404',
@ -69,6 +67,7 @@ def login_ajax(request):
else: else:
return Response('name ' + username + ' Login Failure ' + password) return Response('name ' + username + ' Login Failure ' + password)
@view_config(route_name='favicon') @view_config(route_name='favicon')
def favicon(request): def favicon(request):
here = os.path.dirname(__file__) here = os.path.dirname(__file__)

@ -3,75 +3,42 @@ from sqlalchemy.orm.util import aliased
from sqlalchemy.sql.expression import func, desc from sqlalchemy.sql.expression import func, desc
from pyramid.view import view_config from pyramid.view import view_config
from brewman.helpers import Literal
from brewman.models import DBSession from brewman.models import DBSession
from brewman.models.master import Ledger, LedgerType from brewman.models.master import Ledger, LedgerType
from brewman.models.voucher import Voucher, Journal from brewman.models.voucher import Voucher, Journal
from brewman.views.services.session import services_session_period_start, services_session_period_finish
@view_config(request_method='GET', route_name='cash_flow_id', renderer='brewman:templates/reports/cash_flow.pt') @view_config(request_method='GET', route_name='cash_flow', renderer='brewman:templates/angular_base.mako',
@view_config(request_method='GET', route_name='cash_flow', renderer='brewman:templates/reports/cash_flow.pt') xhr=False)
def cash_flow(request): @view_config(request_method='GET', route_name='cash_flow_id', renderer='brewman:templates/angular_base.mako',
xhr=False)
def get_html(request):
return {}
@view_config(request_method='GET', route_name='cash_flow', renderer='json', xhr=True)
def get_cash_flow(request):
start_date = request.GET.get('StartDate', None)
finish_date = request.GET.get('FinishDate', None)
if start_date and finish_date:
return build_report(request, start_date, finish_date)
else:
return {'StartDate': services_session_period_start(request),
'FinishDate': services_session_period_finish(request), 'Body': [], 'Footer': {}}
@view_config(request_method='GET', route_name='cash_flow_id', renderer='json', xhr=True)
def get_cash_flow_id(request):
id = request.matchdict.get('id', None) id = request.matchdict.get('id', None)
startDate = request.GET.get('startDate', None) start_date = request.GET.get('StartDate', None)
finishDate = request.GET.get('finishDate', None) finish_date = request.GET.get('FinishDate', None)
should_build_report = False if startDate is None else True return build_report_id(request, int(id), start_date, finish_date)
if not should_build_report:
body = ""
footer = ""
elif id is None:
report = build_report(request, datetime.datetime.strptime(startDate, '%d-%b-%Y'),
datetime.datetime.strptime(finishDate, '%d-%b-%Y'))
body = Literal(report['body'])
footer = Literal(report['footer'])
else:
report = build_report_id(request, int(id), datetime.datetime.strptime(startDate, '%d-%b-%Y'),
datetime.datetime.strptime(finishDate, '%d-%b-%Y'))
body = Literal(report['body'])
footer = Literal(report['footer'])
if startDate == None:
startDate = Literal(
"StartDate('#txtStartDate', '{0}');".format(request.route_url('services_session_period_start')))
finishDate = Literal(
"FinishDate('#txtFinishDate', '{0}');".format(request.route_url('services_session_period_finish')))
else:
startDate = Literal("$('#txtStartDate').val('{0}');".format(startDate))
finishDate = Literal("$('#txtFinishDate').val('{0}');".format(finishDate))
return {'title': 'Cash Flow - Hops n Grains',
'pageclass': "page-blogpost page-sidebar-right",
'pagecontentclass': "page-content grid_12",
'page_header': '',
'body': body,
'footer': footer,
'startDate': startDate,
'finishDate': finishDate}
@view_config(request_method='POST', route_name='cash_flow_id', renderer='json', xhr=True) def build_report(request, start_date, finish_date):
@view_config(request_method='POST', route_name='cash_flow', renderer='json', xhr=True) report = {'StartDate': start_date, 'FinishDate': finish_date, 'Body': [], 'Footer': []}
def cash_flow_main(request):
id = request.matchdict.get('id', None)
startDate = datetime.datetime.strptime(request.json_body['startDate'], '%d-%b-%Y')
finishDate = datetime.datetime.strptime(request.json_body['finishDate'], '%d-%b-%Y')
if id is None:
result = build_report(request, startDate, finishDate)
result['url'] = request.route_url('cash_flow',
_query={'startDate': request.json_body['startDate'], 'finishDate': request.json_body['finishDate']})
else:
result = build_report_id(request, int(id), startDate, finishDate)
result['url'] = request.route_url('cash_flow', id=id,
_query={'startDate': request.json_body['startDate'], 'finishDate': request.json_body['finishDate']})
result['start_date'] = request.json_body['startDate']
result['finish_date'] = request.json_body['finishDate']
return result
def build_report(request, startDate, finishDate):
body = ''
sub_voucher = aliased(Voucher) sub_voucher = aliased(Voucher)
sub_journal = aliased(Journal) sub_journal = aliased(Journal)
sub_ledger = aliased(Ledger) sub_ledger = aliased(Ledger)
@ -80,8 +47,8 @@ def build_report(request, startDate, finishDate):
.join(sub_journal, sub_voucher.journals)\ .join(sub_journal, sub_voucher.journals)\
.join(sub_ledger, sub_journal.ledger)\ .join(sub_ledger, sub_journal.ledger)\
.filter(sub_ledger.type == LedgerType.by_name('Cash').id)\ .filter(sub_ledger.type == LedgerType.by_name('Cash').id)\
.filter(sub_voucher.date >= startDate)\ .filter(sub_voucher.date >= datetime.datetime.strptime(start_date, '%d-%b-%Y'))\
.filter(sub_voucher.date <= finishDate).subquery() .filter(sub_voucher.date <= datetime.datetime.strptime(finish_date, '%d-%b-%Y')).subquery()
query = DBSession.query(Ledger.type, func.sum(Journal.signed_amount))\ query = DBSession.query(Ledger.type, func.sum(Journal.signed_amount))\
.join(Journal, Voucher.journals)\ .join(Journal, Voucher.journals)\
@ -99,29 +66,20 @@ def build_report(request, startDate, finishDate):
outflow = "\u20B9 {0:.2f}".format(amount) if amount >= 0 else "" outflow = "\u20B9 {0:.2f}".format(amount) if amount >= 0 else ""
totalInflow += (amount * -1) if amount < 0 else 0 totalInflow += (amount * -1) if amount < 0 else 0
totalOutflow += amount if amount >= 0 else 0 totalOutflow += amount if amount >= 0 else 0
body += '<tr><td class="TypeID hide">' + str(lt.id) + '</td><td class="Name"><a href="' +\ report['Body'].append({'Name': lt.name, 'Url': request.route_url('cash_flow_id', id=str(lt.id),
request.route_url('cash_flow_id', id=str(lt.id), _query={'startDate': startDate.strftime("%d-%b-%Y"), _query={'StartDate': start_date, 'FinishDate': finish_date}), 'Inflow': inflow, 'Outflow': outflow})
'finishDate': finishDate.strftime(
"%d-%b-%Y")}) + '">' + lt.name +\
'</a></td><td class="Inflow right">' + inflow + '</td><td class="Outflow right">' + outflow +\
'</td></tr>'
total = LedgerType.by_name('Total') report['Footer'].append({'Name': 'Total', 'Inflow': "\u20B9 {0:.2f}".format(totalInflow),
body += '<tr><td class="TypeID hide">' + str(total.id) + '</td><td class="Name">' + total.name +\ 'Outflow': "\u20B9 {0:.2f}".format(totalOutflow)})
'</td><td class="Inflow right">' + "\u20B9 {0:.2f}".format(totalInflow) +\
'</td><td class="Outflow right">' + "\u20B9 {0:.2f}".format(totalOutflow) + '</td></tr>'
net = LedgerType.by_name('Net')
netInflow = totalInflow - totalOutflow netInflow = totalInflow - totalOutflow
footer = '<tr><td class="TypeID hide">' + str(net.id) + '</td><td class="Name">' + net.name +\ report['Footer'].append({'Name': 'Net', 'Inflow': ("\u20B9 {0:.2f}".format(netInflow) if netInflow >= 0 else ""),
'</td><td class="Inflow right">' + ("\u20B9 {0:.2f}".format(netInflow) if netInflow >= 0 else "") +\ 'Outflow': ("\u20B9 {0:.2f}".format(netInflow * -1) if netInflow < 0 else "")})
'</td><td class="Outflow right">' + ("\u20B9 {0:.2f}".format(netInflow * -1) if netInflow < 0 else "") +\ return report
'</td></tr>'
return {'body': body, 'footer': footer}
def build_report_id(request, ledgerType, startDate, finishDate): def build_report_id(request, ledger_type, start_date, finish_date):
body = '' report = {'StartDate': start_date, 'FinishDate': finish_date, 'Body': [], 'Footer': []}
sub_voucher = aliased(Voucher) sub_voucher = aliased(Voucher)
sub_journal = aliased(Journal) sub_journal = aliased(Journal)
sub_ledger = aliased(Ledger) sub_ledger = aliased(Ledger)
@ -130,14 +88,14 @@ def build_report_id(request, ledgerType, startDate, finishDate):
.join(sub_journal, sub_voucher.journals)\ .join(sub_journal, sub_voucher.journals)\
.join(sub_ledger, sub_journal.ledger)\ .join(sub_ledger, sub_journal.ledger)\
.filter(sub_ledger.type == LedgerType.by_name('Cash').id)\ .filter(sub_ledger.type == LedgerType.by_name('Cash').id)\
.filter(sub_voucher.date >= startDate)\ .filter(sub_voucher.date >= datetime.datetime.strptime(start_date, '%d-%b-%Y'))\
.filter(sub_voucher.date <= finishDate).subquery() .filter(sub_voucher.date <= datetime.datetime.strptime(finish_date, '%d-%b-%Y')).subquery()
query = DBSession.query(Ledger, func.sum(Journal.signed_amount))\ query = DBSession.query(Ledger, func.sum(Journal.signed_amount))\
.join(Journal, Voucher.journals)\ .join(Journal, Voucher.journals)\
.join(Ledger, Journal.ledger)\ .join(Ledger, Journal.ledger)\
.filter(Voucher.id.in_(sub_query))\ .filter(Voucher.id.in_(sub_query))\
.filter(Ledger.type == ledgerType)\ .filter(Ledger.type == ledger_type)\
.group_by(Ledger)\ .group_by(Ledger)\
.order_by(desc(func.sum(Journal.amount))).all() .order_by(desc(func.sum(Journal.amount))).all()
@ -148,14 +106,9 @@ def build_report_id(request, ledgerType, startDate, finishDate):
outflow = "\u20B9 {0:.2f}".format(amount) if amount >= 0 else "" outflow = "\u20B9 {0:.2f}".format(amount) if amount >= 0 else ""
totalInflow += (amount * -1) if amount < 0 else 0 totalInflow += (amount * -1) if amount < 0 else 0
totalOutflow += amount if amount >= 0 else 0 totalOutflow += amount if amount >= 0 else 0
body += '<tr><td class="TypeID hide">' + str(ledger.id) + '</td><td class="Name">' + ledger.name +\ report['Body'].append({'Name': ledger.name, 'Url': request.route_url('ledger_id', id=ledger.id,
'</td><td class="Inflow right">' + inflow + '</td><td class="Outflow right">' + outflow +\ _query={'StartDate': start_date, 'FinishDate': finish_date}), 'Inflow': inflow, 'Outflow': outflow})
'</td></tr>'
footer = '<tr><td class="TypeID hide"></td><td class="Name"><a href="' +\ report['Footer'].append({'Name': 'Total', 'Inflow': "\u20B9 {0:.2f}".format(totalInflow),
request.route_url('cash_flow', _query={'startDate': startDate.strftime("%d-%b-%Y"), 'Outflow': "\u20B9 {0:.2f}".format(totalOutflow)})
'finishDate': finishDate.strftime( return report
"%d-%b-%Y")}) + '">' + 'Total' +\
'</a></td><td class="Inflow right">' + "\u20B9 {0:.2f}".format(totalInflow) +\
'</td><td class="Outflow right">' + "\u20B9 {0:.2f}".format(totalOutflow) + '</td></tr>'
return {'body': body, 'footer': footer}