Feature: Created stock movement report.

This commit is contained in:
Amritanshu 2013-10-14 15:03:26 +05:30
parent bc7b4217cd
commit cc89a548a5
9 changed files with 183 additions and 4 deletions

2
.gitignore vendored
View File

@ -5,4 +5,4 @@ env
*/__pycache__/ */__pycache__/
*/.idea/ */.idea/
.idea/ .idea/
*/*.egg-info/ *.egg-info/

View File

@ -125,6 +125,9 @@ def main(global_config, **settings):
config.add_route('api_profit_loss', '/api/ProfitLoss') config.add_route('api_profit_loss', '/api/ProfitLoss')
config.add_route('profit_loss', '/ProfitLoss') config.add_route('profit_loss', '/ProfitLoss')
config.add_route('api_stock_movement', '/api/StockMovement')
config.add_route('stock_movement', '/StockMovement')
add_route(config, 'balance_sheet', '/BalanceSheet', has_list=False, variable='date') add_route(config, 'balance_sheet', '/BalanceSheet', has_list=False, variable='date')
config.add_route('api_purchase_entries', '/api/PurchaseEntries') config.add_route('api_purchase_entries', '/api/PurchaseEntries')

View File

@ -0,0 +1,52 @@
<form class="form-horizontal" role=form>
<h2>Stock Movement</h2>
<div class="form-group">
<label for="txtStartDate" class="col-md-2 control-label">Date</label>
<div class="col-md-4">
<div class="input-group">
<input class="form-control" id="txtStartDate" type="text" datepicker-popup="dd-MMM-yyyy"
ng-model="info.StartDate"/>
<span class="input-group-btn">
<button class="btn btn-default"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</div>
</div>
<div class="col-md-4">
<div class="input-group">
<input type="text" id="txtFinishDate" class="form-control" datepicker-popup="dd-MMM-yyyy"
ng-model="info.FinishDate"/>
<span class="input-group-btn">
<button class="btn btn-default"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</div>
</div>
<div class="col-md-2">
<button class="btn btn-info" ng-click="show()">Show <i class="glyphicon glyphicon-eye-open"></i></button>
</div>
</div>
<table class="table table-condensed table-bordered table-striped">
<thead>
<tr>
<th>Group</th>
<th>Name</th>
<th>Opening</th>
<th>Purchase</th>
<th>Issue</th>
<th>Closing</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in info.Body">
<td>{{item.Group}}</td>
<td>{{item.Name}}</td>
<td class="text-right">{{item.Opening | number:2}}</td>
<td class="text-right">{{item.Purchase | number:2}}</td>
<td class="text-right">{{item.Issue | number:2}}</td>
<td class="text-right">{{item.Closing | number:2}}</td>
</tr>
</tbody>
</table>
</form>

View File

@ -126,6 +126,10 @@ overlord_service.factory('ProfitLoss', ['$resource', function ($resource) {
return $resource('/api/ProfitLoss'); return $resource('/api/ProfitLoss');
}]); }]);
overlord_service.factory('StockMovement', ['$resource', function ($resource) {
return $resource('/api/StockMovement');
}]);
overlord_service.factory('BalanceSheet', ['$resource', function ($resource) { overlord_service.factory('BalanceSheet', ['$resource', function ($resource) {
return $resource('/api/BalanceSheet/:date'); return $resource('/api/BalanceSheet/:date');
}]); }]);

View File

@ -52,6 +52,7 @@ var overlord = angular.module('overlord', ['overlord.directive', 'overlord.filte
when('/Daybook', {templateUrl: '/partial/daybook.html', controller: DaybookCtrl, resolve: DaybookCtrl.resolve}). when('/Daybook', {templateUrl: '/partial/daybook.html', controller: DaybookCtrl, resolve: DaybookCtrl.resolve}).
when('/Unposted', {templateUrl: '/partial/unposted.html', controller: UnpostedCtrl, resolve: UnpostedCtrl.resolve}). when('/Unposted', {templateUrl: '/partial/unposted.html', controller: UnpostedCtrl, resolve: UnpostedCtrl.resolve}).
when('/ProfitLoss', {templateUrl: '/partial/profit-loss.html', controller: ProfitLossCtrl, resolve: ProfitLossCtrl.resolve}). when('/ProfitLoss', {templateUrl: '/partial/profit-loss.html', controller: ProfitLossCtrl, resolve: ProfitLossCtrl.resolve}).
when('/StockMovement', {templateUrl: '/partial/stock-movement.html', controller: StockMovementCtrl, resolve: StockMovementCtrl.resolve}).
when('/NetTransactions', {templateUrl: '/partial/net-transactions.html', controller: NetTransactionsCtrl, resolve: NetTransactionsCtrl.resolve}). when('/NetTransactions', {templateUrl: '/partial/net-transactions.html', controller: NetTransactionsCtrl, resolve: NetTransactionsCtrl.resolve}).
when('/PurchaseEntries', {templateUrl: '/partial/purchase-entries.html', controller: PurchaseEntriesCtrl, resolve: PurchaseEntriesCtrl.resolve}). when('/PurchaseEntries', {templateUrl: '/partial/purchase-entries.html', controller: PurchaseEntriesCtrl, resolve: PurchaseEntriesCtrl.resolve}).
when('/EmployeeFunctions', {templateUrl: '/partial/employee-functions.html', controller: EmployeeFunctionsCtrl}). when('/EmployeeFunctions', {templateUrl: '/partial/employee-functions.html', controller: EmployeeFunctionsCtrl}).

View File

@ -0,0 +1,35 @@
'use strict';
var StockMovementCtrl = ['$scope', '$location', 'dateFilter', 'stock_movement', function ($scope, $location, dateFilter, stock_movement) {
$scope.info = stock_movement;
$scope.show = function () {
if (angular.isDate($scope.info.StartDate)) {
$scope.info.StartDate = dateFilter($scope.info.StartDate, 'dd-MMM-yyyy');
}
if (angular.isDate($scope.info.FinishDate)) {
$scope.info.FinishDate = dateFilter($scope.info.FinishDate, 'dd-MMM-yyyy');
}
$location.path('/StockMovement').search({StartDate: $scope.info.StartDate, FinishDate: $scope.info.FinishDate});
};
$('#txtStartDate').focus();
}];
StockMovementCtrl.resolve = {
stock_movement: ['$q', '$route', 'StockMovement', function ($q, $route, StockMovement) {
var deferred = $q.defer();
var start_date = $route.current.params.StartDate;
var finish_date = $route.current.params.FinishDate;
var successCb = function (result) {
deferred.resolve(result);
};
if (typeof start_date === 'undefined' || typeof finish_date === 'undefined') {
StockMovement.get({}, successCb);
} else {
StockMovement.get({StartDate: start_date, FinishDate: finish_date}, successCb);
}
return deferred.promise;
}]
};

View File

@ -1,3 +0,0 @@
/**
* Created by tanshu on 27/9/13.
*/

View File

@ -77,6 +77,7 @@
<script src="/script/net-transactions.js"></script> <script src="/script/net-transactions.js"></script>
<script src="/script/closing-stock.js"></script> <script src="/script/closing-stock.js"></script>
<script src="/script/profit-loss.js"></script> <script src="/script/profit-loss.js"></script>
<script src="/script/stock-movement.js"></script>
<script src="/script/balance-sheet.js"></script> <script src="/script/balance-sheet.js"></script>
<script src="/script/purchase-entries.js"></script> <script src="/script/purchase-entries.js"></script>
<script src="/script/cash-flow.js"></script> <script src="/script/cash-flow.js"></script>
@ -144,6 +145,7 @@
<li><a href="/RawMaterialCost">Raw Material Cost</a></li> <li><a href="/RawMaterialCost">Raw Material Cost</a></li>
<li><a href="/PurchaseEntries">Purchase Entries</a></li> <li><a href="/PurchaseEntries">Purchase Entries</a></li>
<li><a href="/ClosingStock">Closing Stock</a></li> <li><a href="/ClosingStock">Closing Stock</a></li>
<li><a href="/StockMovement">Stock Movement</a></li>
<li class="divider"></li> <li class="divider"></li>
<li><a href="/TrialBalance">Trail Balance</a></li> <li><a href="/TrialBalance">Trail Balance</a></li>
<li><a href="/ProfitLoss">Profit and Loss</a></li> <li><a href="/ProfitLoss">Profit and Loss</a></li>

View File

@ -0,0 +1,85 @@
import datetime
from sqlalchemy.sql.expression import func
from pyramid.view import view_config
from brewman.models import DBSession
from brewman.models.master import Product, CostCenter
from brewman.models.voucher import Voucher, Journal, VoucherType, Inventory
from brewman.views.services.session import session_period_start, session_period_finish
@view_config(request_method='GET', route_name='stock_movement', renderer='brewman:templates/angular_base.mako',
permission='Stock Movement')
def html(request):
return {}
@view_config(request_method='GET', route_name='api_stock_movement', renderer='json', permission='Stock Movement')
def get_stock_movement(request):
start_date = request.GET.get('StartDate', None)
finish_date = request.GET.get('FinishDate', None)
if start_date and finish_date:
report = {'StartDate': start_date, 'FinishDate': finish_date}
start_date = datetime.datetime.strptime(start_date, '%d-%b-%Y')
finish_date = datetime.datetime.strptime(finish_date, '%d-%b-%Y')
report['Body'] = build_stock_movement(start_date, finish_date)
return report
else:
return {'StartDate': session_period_start(request),
'FinishDate': session_period_finish(request), 'Body': []}
def build_stock_movement(start_date, finish_date):
dict = {}
quantity_sum = func.sum(Journal.debit * Inventory.quantity).label('Quantity')
openings = DBSession.query(Product, quantity_sum) \
.join(Product.inventories).join(Inventory.voucher).join(Voucher.journals) \
.filter(Voucher.date < start_date) \
.filter(Journal.cost_center_id == CostCenter.cost_center_purchase()) \
.group_by(Product).all()
for product, quantity in openings:
dict[product.id] = {'ProductID': product.id, 'Name': product.full_name, 'Group': product.product_group.name,
'Opening': quantity}
purchases = DBSession.query(Product, quantity_sum) \
.join(Product.inventories).join(Inventory.voucher).join(Voucher.journals) \
.filter(Voucher.date >= start_date) \
.filter(Voucher.date <= finish_date) \
.filter(Voucher.type != VoucherType.by_name('Issue').id) \
.filter(Journal.cost_center_id == CostCenter.cost_center_purchase()) \
.group_by(Product).all()
for product, quantity in purchases:
if product.id in dict:
dict[product.id]['Purchase'] = quantity
else:
dict[product.id] = {'ProductID': product.id, 'Name': product.full_name, 'Group': product.product_group.name,
'Purchase': quantity}
issues = DBSession.query(Product, quantity_sum) \
.join(Product.inventories).join(Inventory.voucher).join(Voucher.journals) \
.filter(Voucher.date >= start_date) \
.filter(Voucher.date <= finish_date) \
.filter(Voucher.type != VoucherType.by_name('Issue').id) \
.filter(Journal.cost_center_id == CostCenter.cost_center_purchase()) \
.group_by(Product).all()
for product, quantity in issues:
if product.id in dict:
dict[product.id]['Issue'] = quantity
else:
dict[product.id] = {'ProductID': product.id, 'Name': product.full_name, 'Group': product.product_group.name,
'Issue': quantity}
list = [value for key, value in dict.items()]
list = sorted(list, key=lambda x: x['Name'].lower())
list = sorted(list, key=lambda x: x['Group'].lower())
for i in range(len(list), 0, -1):
item = list[i - 1]
opening = item['Opening'] if 'Opening' in item else 0
purchase = item['Purchase'] if 'Purchase' in item else 0
issue = item['Issue'] if 'Issue' in item else 0
closing = opening + purchase - issue
if opening == 0 and purchase == 0 and issue == 0:
list.remove(item)
else:
item['Closing'] = closing
return list