Cash flow done.
This commit is contained in:
parent
16b2e8dd51
commit
d221a4f4e9
@ -106,8 +106,8 @@ def main(global_config, **settings):
|
||||
config.add_route('trial_balance_date', '/TrialBalance/{date}')
|
||||
config.add_route('trial_balance', '/TrialBalance')
|
||||
|
||||
config.add_route('cash_flow_id', '/Reports/CashFlow/{id}')
|
||||
config.add_route('cash_flow', '/Reports/CashFlow')
|
||||
config.add_route('cash_flow_id', '/CashFlow/{id}')
|
||||
config.add_route('cash_flow', '/CashFlow')
|
||||
|
||||
config.add_route('profit_loss', '/Reports/ProfitLoss')
|
||||
|
||||
|
41
brewman/brewman/static/partial/cash-flow.html
Normal file
41
brewman/brewman/static/partial/cash-flow.html
Normal file
@ -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');
|
||||
}]);
|
||||
|
||||
// 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
|
||||
overlord_service.factory('LedgerService', ['$resource', function ($resource) {
|
||||
return $resource('/Services/Accounts/:type');
|
||||
|
17
brewman/brewman/static/scripts/cash-flow.js
Normal file
17
brewman/brewman/static/scripts/cash-flow.js
Normal file
@ -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/: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/:id', {templateUrl:'/partial/ledger.html', controller:LedgerCtrl, resolve: LedgerCtrl.resolve}).
|
||||
|
||||
|
@ -40,7 +40,8 @@
|
||||
|
||||
${h.ScriptLink(request, '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, '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
|
||||
|
||||
|
||||
|
||||
|
||||
@view_config(context=HTTPNotFound, renderer='brewman:templates/404.mako')
|
||||
def not_found(request):
|
||||
return {'title': '404',
|
||||
@ -69,6 +67,7 @@ def login_ajax(request):
|
||||
else:
|
||||
return Response('name ' + username + ' Login Failure ' + password)
|
||||
|
||||
|
||||
@view_config(route_name='favicon')
|
||||
def favicon(request):
|
||||
here = os.path.dirname(__file__)
|
||||
|
@ -3,75 +3,42 @@ from sqlalchemy.orm.util import aliased
|
||||
from sqlalchemy.sql.expression import func, desc
|
||||
|
||||
from pyramid.view import view_config
|
||||
from brewman.helpers import Literal
|
||||
|
||||
from brewman.models import DBSession
|
||||
from brewman.models.master import Ledger, LedgerType
|
||||
|
||||
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/reports/cash_flow.pt')
|
||||
def cash_flow(request):
|
||||
@view_config(request_method='GET', route_name='cash_flow', renderer='brewman:templates/angular_base.mako',
|
||||
xhr=False)
|
||||
@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)
|
||||
startDate = request.GET.get('startDate', None)
|
||||
finishDate = request.GET.get('finishDate', None)
|
||||
should_build_report = False if startDate is None else True
|
||||
|
||||
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}
|
||||
start_date = request.GET.get('StartDate', None)
|
||||
finish_date = request.GET.get('FinishDate', None)
|
||||
return build_report_id(request, int(id), start_date, finish_date)
|
||||
|
||||
|
||||
@view_config(request_method='POST', route_name='cash_flow_id', renderer='json', xhr=True)
|
||||
@view_config(request_method='POST', route_name='cash_flow', renderer='json', xhr=True)
|
||||
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 = ''
|
||||
def build_report(request, start_date, finish_date):
|
||||
report = {'StartDate': start_date, 'FinishDate': finish_date, 'Body': [], 'Footer': []}
|
||||
sub_voucher = aliased(Voucher)
|
||||
sub_journal = aliased(Journal)
|
||||
sub_ledger = aliased(Ledger)
|
||||
@ -80,8 +47,8 @@ def build_report(request, startDate, finishDate):
|
||||
.join(sub_journal, sub_voucher.journals)\
|
||||
.join(sub_ledger, sub_journal.ledger)\
|
||||
.filter(sub_ledger.type == LedgerType.by_name('Cash').id)\
|
||||
.filter(sub_voucher.date >= startDate)\
|
||||
.filter(sub_voucher.date <= finishDate).subquery()
|
||||
.filter(sub_voucher.date >= datetime.datetime.strptime(start_date, '%d-%b-%Y'))\
|
||||
.filter(sub_voucher.date <= datetime.datetime.strptime(finish_date, '%d-%b-%Y')).subquery()
|
||||
|
||||
query = DBSession.query(Ledger.type, func.sum(Journal.signed_amount))\
|
||||
.join(Journal, Voucher.journals)\
|
||||
@ -99,29 +66,20 @@ def build_report(request, startDate, finishDate):
|
||||
outflow = "\u20B9 {0:.2f}".format(amount) if amount >= 0 else ""
|
||||
totalInflow += (amount * -1) 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="' +\
|
||||
request.route_url('cash_flow_id', id=str(lt.id), _query={'startDate': startDate.strftime("%d-%b-%Y"),
|
||||
'finishDate': finishDate.strftime(
|
||||
"%d-%b-%Y")}) + '">' + lt.name +\
|
||||
'</a></td><td class="Inflow right">' + inflow + '</td><td class="Outflow right">' + outflow +\
|
||||
'</td></tr>'
|
||||
report['Body'].append({'Name': lt.name, 'Url': request.route_url('cash_flow_id', id=str(lt.id),
|
||||
_query={'StartDate': start_date, 'FinishDate': finish_date}), 'Inflow': inflow, 'Outflow': outflow})
|
||||
|
||||
total = LedgerType.by_name('Total')
|
||||
body += '<tr><td class="TypeID hide">' + str(total.id) + '</td><td class="Name">' + total.name +\
|
||||
'</td><td class="Inflow right">' + "\u20B9 {0:.2f}".format(totalInflow) +\
|
||||
'</td><td class="Outflow right">' + "\u20B9 {0:.2f}".format(totalOutflow) + '</td></tr>'
|
||||
report['Footer'].append({'Name': 'Total', 'Inflow': "\u20B9 {0:.2f}".format(totalInflow),
|
||||
'Outflow': "\u20B9 {0:.2f}".format(totalOutflow)})
|
||||
|
||||
net = LedgerType.by_name('Net')
|
||||
netInflow = totalInflow - totalOutflow
|
||||
footer = '<tr><td class="TypeID hide">' + str(net.id) + '</td><td class="Name">' + net.name +\
|
||||
'</td><td class="Inflow right">' + ("\u20B9 {0:.2f}".format(netInflow) if netInflow >= 0 else "") +\
|
||||
'</td><td class="Outflow right">' + ("\u20B9 {0:.2f}".format(netInflow * -1) if netInflow < 0 else "") +\
|
||||
'</td></tr>'
|
||||
return {'body': body, 'footer': footer}
|
||||
report['Footer'].append({'Name': 'Net', 'Inflow': ("\u20B9 {0:.2f}".format(netInflow) if netInflow >= 0 else ""),
|
||||
'Outflow': ("\u20B9 {0:.2f}".format(netInflow * -1) if netInflow < 0 else "")})
|
||||
return report
|
||||
|
||||
|
||||
def build_report_id(request, ledgerType, startDate, finishDate):
|
||||
body = ''
|
||||
def build_report_id(request, ledger_type, start_date, finish_date):
|
||||
report = {'StartDate': start_date, 'FinishDate': finish_date, 'Body': [], 'Footer': []}
|
||||
sub_voucher = aliased(Voucher)
|
||||
sub_journal = aliased(Journal)
|
||||
sub_ledger = aliased(Ledger)
|
||||
@ -130,14 +88,14 @@ def build_report_id(request, ledgerType, startDate, finishDate):
|
||||
.join(sub_journal, sub_voucher.journals)\
|
||||
.join(sub_ledger, sub_journal.ledger)\
|
||||
.filter(sub_ledger.type == LedgerType.by_name('Cash').id)\
|
||||
.filter(sub_voucher.date >= startDate)\
|
||||
.filter(sub_voucher.date <= finishDate).subquery()
|
||||
.filter(sub_voucher.date >= datetime.datetime.strptime(start_date, '%d-%b-%Y'))\
|
||||
.filter(sub_voucher.date <= datetime.datetime.strptime(finish_date, '%d-%b-%Y')).subquery()
|
||||
|
||||
query = DBSession.query(Ledger, func.sum(Journal.signed_amount))\
|
||||
.join(Journal, Voucher.journals)\
|
||||
.join(Ledger, Journal.ledger)\
|
||||
.filter(Voucher.id.in_(sub_query))\
|
||||
.filter(Ledger.type == ledgerType)\
|
||||
.filter(Ledger.type == ledger_type)\
|
||||
.group_by(Ledger)\
|
||||
.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 ""
|
||||
totalInflow += (amount * -1) 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 +\
|
||||
'</td><td class="Inflow right">' + inflow + '</td><td class="Outflow right">' + outflow +\
|
||||
'</td></tr>'
|
||||
report['Body'].append({'Name': ledger.name, 'Url': request.route_url('ledger_id', id=ledger.id,
|
||||
_query={'StartDate': start_date, 'FinishDate': finish_date}), 'Inflow': inflow, 'Outflow': outflow})
|
||||
|
||||
footer = '<tr><td class="TypeID hide"></td><td class="Name"><a href="' +\
|
||||
request.route_url('cash_flow', _query={'startDate': startDate.strftime("%d-%b-%Y"),
|
||||
'finishDate': finishDate.strftime(
|
||||
"%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}
|
||||
report['Footer'].append({'Name': 'Total', 'Inflow': "\u20B9 {0:.2f}".format(totalInflow),
|
||||
'Outflow': "\u20B9 {0:.2f}".format(totalOutflow)})
|
||||
return report
|
||||
|
Loading…
Reference in New Issue
Block a user