Feature: Created stock movement report.
This commit is contained in:
parent
bc7b4217cd
commit
cc89a548a5
2
.gitignore
vendored
2
.gitignore
vendored
@ -5,4 +5,4 @@ env
|
|||||||
*/__pycache__/
|
*/__pycache__/
|
||||||
*/.idea/
|
*/.idea/
|
||||||
.idea/
|
.idea/
|
||||||
*/*.egg-info/
|
*.egg-info/
|
@ -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')
|
||||||
|
52
brewman/static/partial/stock-movement.html
Normal file
52
brewman/static/partial/stock-movement.html
Normal 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>
|
4
brewman/static/scripts/angular_service.js
vendored
4
brewman/static/scripts/angular_service.js
vendored
@ -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');
|
||||||
}]);
|
}]);
|
||||||
|
@ -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}).
|
||||||
|
35
brewman/static/scripts/stock-movement.js
Normal file
35
brewman/static/scripts/stock-movement.js
Normal 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;
|
||||||
|
}]
|
||||||
|
};
|
@ -1,3 +0,0 @@
|
|||||||
/**
|
|
||||||
* Created by tanshu on 27/9/13.
|
|
||||||
*/
|
|
@ -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>
|
||||||
|
85
brewman/views/reports/stock_movement.py
Normal file
85
brewman/views/reports/stock_movement.py
Normal 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
|
Loading…
Reference in New Issue
Block a user