Added settings table to store user settings.

Added settings page, view, route and controller.
Added lock_date setting to prevent changes to voucher upto and including that date.

The sql for this update is:

CREATE TABLE settings (
	"SettingID" UUID NOT NULL,
	"Name" VARCHAR(255) NOT NULL,
	"Data" BYTEA,
	PRIMARY KEY ("SettingID"),
	UNIQUE ("Name")
);

INSERT INTO auth_roles ("RoleID", "Name") VALUES ('d52de0be-9388-4b0b-a359-7e122ab6e53a', 'Lock Date');

Signed-off-by: Tanshu <tanshu@gmail.com>
This commit is contained in:
Tanshu
2013-07-08 01:33:02 +05:30
parent 30a38f7ed9
commit d187c1ee2f
13 changed files with 176 additions and 14 deletions

View File

@ -86,6 +86,8 @@ def main(global_config, **settings):
config.add_route('api_message', '/api/Message') config.add_route('api_message', '/api/Message')
config.add_route('api_tag_list', '/api/Tags') config.add_route('api_tag_list', '/api/Tags')
config.add_route('settings', '/Settings')
config.add_route('api_lock_date', '/api/LockDate')
add_route(config, 'attendance', '/Attendance', has_list=False, variable='date') add_route(config, 'attendance', '/Attendance', has_list=False, variable='date')

View File

@ -13,6 +13,7 @@ def initialize_sql(engine):
# from brewman.models.voucher import Attendance, Batch, Fingerprint, Inventory, Journal, Product, SalaryDeduction, Voucher, VoucherType # from brewman.models.voucher import Attendance, Batch, Fingerprint, Inventory, Journal, Product, SalaryDeduction, Voucher, VoucherType
# from brewman.models.master import Product, AttendanceType, CostCenter, Employee, Ledger, LedgerBase, LedgerType, ProductGroup # from brewman.models.master import Product, AttendanceType, CostCenter, Employee, Ledger, LedgerBase, LedgerType, ProductGroup
# from brewman.models.auth import Client, Group, Role, User, role_group, user_group # from brewman.models.auth import Client, Group, Role, User, role_group, user_group
# from .master import DbSetting
DBSession.configure(bind=engine) DBSession.configure(bind=engine)
Base.metadata.bind = engine Base.metadata.bind = engine
# Base.metadata.create_all(engine) # Base.metadata.create_all(engine)

View File

@ -1,11 +1,12 @@
import uuid import uuid
from sqlalchemy import UniqueConstraint, Column, Integer, Unicode, Numeric, Boolean, ForeignKey, func, DateTime, desc from sqlalchemy import UniqueConstraint, Column, Integer, Unicode, Numeric, Boolean, ForeignKey, func, DateTime, desc, PickleType
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
from brewman.models import Base, DBSession from brewman.models import Base, DBSession
from brewman.models.guidtype import GUID from brewman.models.guidtype import GUID
__author__ = 'tanshu' __author__ = 'tanshu'
class Product(Base): class Product(Base):
__tablename__ = 'entities_products' __tablename__ = 'entities_products'
__tableagrs__ = (UniqueConstraint('Name', 'Units')) __tableagrs__ = (UniqueConstraint('Name', 'Units'))
@ -267,7 +268,7 @@ class Employee(LedgerBase):
self.joining_date = joining_date self.joining_date = joining_date
self.leaving_date = leaving_date self.leaving_date = leaving_date
super().__init__(code=code, name=name, type=10, is_active=is_active, is_reconcilable=False, super().__init__(code=code, name=name, type=10, is_active=is_active, is_reconcilable=False,
costcenter_id=costcenter_id) costcenter_id=costcenter_id)
def create(self): def create(self):
code = DBSession.query(func.max(LedgerBase.code)).filter(LedgerBase.type == self.type).one()[0] code = DBSession.query(func.max(LedgerBase.code)).filter(LedgerBase.type == self.type).one()[0]
@ -383,4 +384,31 @@ class LedgerType:
list = cls.list() list = cls.list()
for item in list: for item in list:
if item.id == id: if item.id == id:
return item return item
class DbSetting(Base):
__tablename__ = 'settings'
id = Column('SettingID', GUID(), primary_key=True, default=uuid.uuid4)
name = Column('Name', Unicode(255), unique=True, nullable=False)
data = Column('Data', PickleType)
def __init__(self, id=None, name=None, data=None):
self.id = id
self.name = name
self.data = data
@classmethod
def by_id(cls, id):
if not isinstance(id, uuid.UUID):
id = uuid.UUID(id)
return DBSession.query(cls).filter(cls.id == id).first()
@classmethod
def by_name(cls, name):
return DBSession.query(cls).filter(cls.name == name).first()
@classmethod
def list(cls):
return DBSession.query(cls).order_by(cls.name).all()

View File

@ -1,6 +1,6 @@
CACHE MANIFEST CACHE MANIFEST
# version 2013-06-24.1 # version 2013-06-30.1
CACHE: CACHE:
/partial/404.html /partial/404.html

View File

@ -0,0 +1,12 @@
<form method="post" autocomplete="off" class="form-horizontal">
<legend>Settings</legend>
<div class="control-group">
<label for="txtLockDate" class="control-label">Lock Date</label>
<div class="controls">
<datepicker id="txtLockDate" model="lockDate" ng-model="lockDate"></datepicker>
<button class="btn btn-primary" ng-click="setLockDate()">Set</button>
<button class="btn btn-danger" ng-click="clearLockDate()">Clear</button>
</div>
</div>
</form>

View File

@ -11,6 +11,13 @@ var HomeCtrl = ['$scope', '$location', 'messages', 'Message', function ($scope,
$scope.chosen = result.Type; $scope.chosen = result.Type;
}); });
} }
$scope.getTags = function (tag) {
Message.query({type: $scope.Type, tag: tag}, function (result) {
$scope.info = result.Threads;
$scope.tags = result.Tags;
$scope.chosen = result.Type;
});
}
}]; }];
HomeCtrl.resolve = { HomeCtrl.resolve = {
messages: ['$q', '$route', 'Message', function ($q, $route, Message) { messages: ['$q', '$route', 'Message', function ($q, $route, Message) {

View File

@ -92,6 +92,8 @@ var overlord = angular.module('overlord', ['overlord.directive', 'overlord.filte
when('/Message', {templateUrl: '/partial/message-detail.html', controller: MessageCtrl, resolve: MessageCtrl.resolve}). when('/Message', {templateUrl: '/partial/message-detail.html', controller: MessageCtrl, resolve: MessageCtrl.resolve}).
when('/Message/:id', {templateUrl: '/partial/message-detail.html', controller: MessageCtrl, resolve: MessageCtrl.resolve}). when('/Message/:id', {templateUrl: '/partial/message-detail.html', controller: MessageCtrl, resolve: MessageCtrl.resolve}).
when('/Settings', {templateUrl: '/partial/settings.html', controller: SettingsCtrl, resolve: SettingsCtrl.resolve}).
otherwise({templateUrl: '/partial/404.html'}); otherwise({templateUrl: '/partial/404.html'});
$locationProvider.html5Mode(true).hashPrefix('!'); $locationProvider.html5Mode(true).hashPrefix('!');
}]) }])

View File

@ -0,0 +1,32 @@
'use strict';
var SettingsCtrl = ['$scope', '$http', 'lockDate', function ($scope, $http, lockDate) {
$scope.lockDate = lockDate.data['Lock Date'];
$scope.setLockDate = function () {
$http({method: 'POST', url: '/api/LockDate', params: {Date: $scope.lockDate}}).
success(function (data) {
$scope.lockDate = data['Lock Date'];
$scope.toasts.push({Type: 'Success', Message: ''});
}).
error(function (errorMessage) {
$scope.toasts.push({Type: 'Error', Message: errorMessage});
});
};
$scope.clearLockDate = function () {
$http({method: 'POST', url: '/api/LockDate', params: {Clear: ''}}).
success(function (data) {
$scope.lockDate = data['Lock Date'];
$scope.toasts.push({Type: 'Success', Message: ''});
}).
error(function (errorMessage) {
$scope.toasts.push({Type: 'Error', Message: errorMessage});
});
};
}]
SettingsCtrl.resolve = {
lockDate: ['$http', function ($http) {
return $http.get('/api/LockDate', {});
}]
};

View File

@ -40,6 +40,7 @@
<script src="/script/growl-service.js"></script> <script src="/script/growl-service.js"></script>
<script src="/script/home.js"></script> <script src="/script/home.js"></script>
<script src="/script/login.js"></script> <script src="/script/login.js"></script>
<script src="/script/settings.js"></script>
<script src="/script/message.js"></script> <script src="/script/message.js"></script>
<script src="/script/journal.js"></script> <script src="/script/journal.js"></script>
@ -179,7 +180,7 @@
<li><a href="/Users">Users</a></li> <li><a href="/Users">Users</a></li>
<li><a href="/Groups">Groups</a></li> <li><a href="/Groups">Groups</a></li>
<li><a href="/Clients">Clients</a></li> <li><a href="/Clients">Clients</a></li>
<li><a href="/AccountsTesting/Maintenance/Split.aspx">Split Data</a></li> <li><a href="/Settings">Settings</a></li>
</ul> </ul>
</li> </li>
<ul class="nav" ng-hide="auth.isAuthenticated"> <ul class="nav" ng-hide="auth.isAuthenticated">

View File

@ -7,12 +7,12 @@ import transaction
from brewman import groupfinder from brewman import groupfinder
from brewman.models import DBSession from brewman.models import DBSession
from brewman.models.auth import User from brewman.models.auth import User
from brewman.models.master import LedgerBase, CostCenter from brewman.models.master import LedgerBase, CostCenter, DbSetting
from brewman.models.validation_exception import ValidationError, TryCatchFunction from brewman.models.validation_exception import ValidationError, TryCatchFunction
from brewman.models.voucher import Voucher, VoucherType, Batch, Inventory from brewman.models.voucher import Voucher, VoucherType, Batch, Inventory
from brewman.views.services.voucher.issue import issue_create_voucher, issue_update_voucher from .issue import issue_create_voucher, issue_update_voucher
from brewman.views.services.voucher.journal import journal_update_voucher, journal_create_voucher from .journal import journal_update_voucher, journal_create_voucher
from brewman.views.services.voucher.purchase import purchase_create_voucher, purchase_update_voucher from .purchase import purchase_create_voucher, purchase_update_voucher
__author__ = 'tanshu' __author__ = 'tanshu'
@ -54,6 +54,9 @@ def journal_get(request):
def voucher_post(request): def voucher_post(request):
user = User.by_id(uuid.UUID(authenticated_userid(request))) user = User.by_id(uuid.UUID(authenticated_userid(request)))
voucher = Voucher.by_id(uuid.UUID(request.matchdict['id'])) voucher = Voucher.by_id(uuid.UUID(request.matchdict['id']))
lock_date = get_lock_date()
if lock_date >= voucher.date:
raise ValidationError("Vouchers upto {0} have been locked.".format(lock_date.strftime('%d-%b-%Y')))
voucher.posted = True voucher.posted = True
voucher.poster_id = user.id voucher.poster_id = user.id
transaction.commit() transaction.commit()
@ -76,6 +79,12 @@ def check_delete_permissions(request, voucher):
response = Response("You are not allowed (0) vouchers".format(VoucherType.by_id(voucher.type).name)) response = Response("You are not allowed (0) vouchers".format(VoucherType.by_id(voucher.type).name))
response.status_int = 403 response.status_int = 403
return response return response
lock_date = get_lock_date()
if lock_date >= voucher.date:
response = Response("Vouchers upto {0} have been locked.".format(lock_date.strftime('%d-%b-%Y')))
response.status_int = 403
return response
@view_config(request_method='DELETE', route_name='api_voucher_id', renderer='json') @view_config(request_method='DELETE', route_name='api_voucher_id', renderer='json')
@ -245,3 +254,9 @@ def get_edit_url(request, voucher):
else: else:
return '#' return '#'
def get_lock_date():
lock_date = DbSetting.by_name('Lock Date')
if lock_date is not None and lock_date.data is not None:
return lock_date.data
return None

View File

@ -1,14 +1,15 @@
import datetime
import uuid import uuid
from pyramid.security import authenticated_userid from pyramid.security import authenticated_userid
from pyramid.view import view_defaults, view_config from pyramid.view import view_defaults, view_config
import transaction import transaction
from brewman.models.auth import User from brewman.models.auth import User
from brewman.models.validation_exception import TryCatchFunction from brewman.models.validation_exception import TryCatchFunction, ValidationError
from brewman.models.voucher import Voucher from brewman.models.voucher import Voucher
from brewman.views.services.session import session_current_date_set from brewman.views.services.session import session_current_date_set
from brewman.views.services.voucher import voucher_info, journal_create_voucher, purchase_create_voucher, issue_create_voucher from . import voucher_info, journal_create_voucher, purchase_create_voucher, issue_create_voucher, get_lock_date
from brewman.views.services.voucher.purchase_return import purchase_return_create_voucher from .purchase_return import purchase_return_create_voucher
from brewman.views.services.voucher.salary_deduction import salary_deduction_create_voucher from .salary_deduction import salary_deduction_create_voucher
__author__ = 'tanshu' __author__ = 'tanshu'
@ -19,6 +20,9 @@ class save_voucher(object):
self.request = request self.request = request
self.user = User.by_id(uuid.UUID(authenticated_userid(request))) self.user = User.by_id(uuid.UUID(authenticated_userid(request)))
self.json = request.json_body self.json = request.json_body
self.lock_date = get_lock_date()
self.voucher_date = datetime.datetime.strptime(self.json['Date'], '%d-%b-%Y')
@view_config(request_param='type=Journal', permission='Journal') @view_config(request_param='type=Journal', permission='Journal')
def journal(self): def journal(self):
@ -55,6 +59,9 @@ class save_voucher(object):
@TryCatchFunction @TryCatchFunction
def save(self): def save(self):
if self.lock_date >= self.voucher_date:
raise ValidationError("Vouchers upto {0} have been locked.".format(self.lock_date.strftime('%d-%b-%Y')))
if self.json['Type'] in ['Journal', 'Payment', 'Receipt']: if self.json['Type'] in ['Journal', 'Payment', 'Receipt']:
voucher = journal_create_voucher(self.json, self.user) voucher = journal_create_voucher(self.json, self.user)
elif self.json['Type'] in ['Purchase']: elif self.json['Type'] in ['Purchase']:

View File

@ -1,3 +1,4 @@
import datetime
import uuid import uuid
from pyramid.response import Response from pyramid.response import Response
from pyramid.security import authenticated_userid from pyramid.security import authenticated_userid
@ -8,7 +9,7 @@ from brewman.models.auth import User
from brewman.models.validation_exception import ValidationError, TryCatchFunction from brewman.models.validation_exception import ValidationError, TryCatchFunction
from brewman.models.voucher import Voucher from brewman.models.voucher import Voucher
from brewman.views.services.session import session_current_date_set from brewman.views.services.session import session_current_date_set
from brewman.views.services.voucher import voucher_info, issue_update_voucher, purchase_update_voucher, journal_update_voucher from . import voucher_info, issue_update_voucher, purchase_update_voucher, journal_update_voucher, get_lock_date
from brewman.views.services.voucher.purchase_return import purchase_return_update_voucher from brewman.views.services.voucher.purchase_return import purchase_return_update_voucher
from brewman.views.services.voucher.salary_deduction import salary_deduction_update_voucher from brewman.views.services.voucher.salary_deduction import salary_deduction_update_voucher
@ -22,6 +23,9 @@ class update_voucher(object):
self.user = User.by_id(uuid.UUID(authenticated_userid(request))) self.user = User.by_id(uuid.UUID(authenticated_userid(request)))
self.voucher = Voucher.by_id(uuid.UUID(request.matchdict.get('id', None))) self.voucher = Voucher.by_id(uuid.UUID(request.matchdict.get('id', None)))
self.json = request.json_body self.json = request.json_body
self.lock_date = get_lock_date()
self.voucher_date = datetime.datetime.strptime(self.json['Date'], '%d-%b-%Y')
permissions = groupfinder(self.user.id, self.request) permissions = groupfinder(self.user.id, self.request)
if self.voucher.posted and not 'Edit Posted Vouchers' in permissions: if self.voucher.posted and not 'Edit Posted Vouchers' in permissions:
@ -32,6 +36,10 @@ class update_voucher(object):
response = Response("You are not allowed to edit other user's vouchers") response = Response("You are not allowed to edit other user's vouchers")
response.status_int = 403 response.status_int = 403
self.error = response self.error = response
elif self.lock_date >= self.voucher_date or self.lock_date >= self.voucher.date:
response = Response("Vouchers upto {0} have been locked.".format(self.lock_date.strftime('%d-%b-%Y')))
response.status_int = 403
self.error = response
else: else:
self.error = None self.error = None

View File

@ -0,0 +1,47 @@
import datetime
from pyramid.view import view_config
import transaction
from brewman.models import DBSession
from brewman.models.master import DbSetting
from brewman.models.validation_exception import TryCatchFunction
@view_config(route_name='settings', renderer='brewman:templates/angular_base.mako', permission='Authenticated')
def html(request):
return {}
@view_config(request_method='POST', route_name='api_lock_date', request_param='Date', renderer='json',
permission='Lock Date')
@TryCatchFunction
def set_lock_date(request):
date = datetime.datetime.strptime(request.GET['Date'], '%d-%b-%Y')
lock_date = DbSetting.by_name('Lock Date')
if lock_date is not None:
lock_date.data = date
else:
lock_date = DbSetting(name='Lock Date', data=date)
DBSession.add(lock_date)
transaction.commit()
return {'Lock Date': date.strftime('%d-%b-%Y')}
@view_config(request_method='POST', route_name='api_lock_date', request_param='Clear', renderer='json',
permission='Lock Date')
@TryCatchFunction
def clear_lock_date(request):
lock_date = DbSetting.by_name('Lock Date')
if lock_date is not None and lock_date.data is not None:
lock_date.data = None
transaction.commit()
return {'Lock Date': ''}
@view_config(request_method='GET', route_name='api_lock_date', renderer='json', permission='Authenticated')
def get_lock_date(request):
lock_date = DbSetting.by_name('Lock Date')
if lock_date is not None and lock_date.data is not None:
return {'Lock Date': lock_date.data.strftime('%d-%b-%Y')}
return {'Lock Date': ''}