Added the Clents table to restrict the webapp on allowed clients via 10 yr long cookies and otp for intitial activation.

Added the reconcilable column to ledgers table for future implementation of reconcile account feature.
Purchase return should work now at.
Changed the class of add button in voucher forms to btn-info
Edit in Payment and Receipt should be working now.
JS Code Cleanup including missing ';', etc.
Added 'use strict'; to all js files
Added came_from in login in AngularJS.
Fixed error in purchase where it would look for purchase_ledger instead of ledger of product.
Added 'Clients' permission which is allowed remote logins and to authorize/deauthroize clients
Added JDBC Sqlite provider for use in PyCharm
This commit is contained in:
Tanshu committed 2012-11-04 15:27:46 +05:30
1 parent bccad85099
commit 16bbf37601
57 files changed
+899 -420

No files matched your search

+2 -2
View File
@@ -78,8 +78,8 @@ def main(global_config, **settings):
config.add_route('journal', '/Journal') config.add_route('journal', '/Journal')
config.add_route('purchase_id', '/Purchase/{id}') config.add_route('purchase_id', '/Purchase/{id}')
config.add_route('purchase', '/Purchase') config.add_route('purchase', '/Purchase')
config.add_route('purchase_return_id', '/PurchaseReturn/{id}') config.add_route('purchase_return_id', '/Return/{id}')
config.add_route('purchase_return', '/PurchaseReturn') config.add_route('purchase_return', '/Return')
config.add_route('payment_id', '/Payment/{id}') config.add_route('payment_id', '/Payment/{id}')
config.add_route('payment', '/Payment') config.add_route('payment', '/Payment')
config.add_route('receipt_id', '/Receipt/{id}') config.add_route('receipt_id', '/Receipt/{id}')
+50 -10
View File
@@ -1,9 +1,11 @@
import random
import string
import uuid import uuid
from sqlalchemy.schema import ForeignKey, Table from sqlalchemy.schema import ForeignKey, Table
from brewman.models.guidtype import GUID from brewman.models.guidtype import GUID
from hashlib import md5 from hashlib import md5
from sqlalchemy import Column, Boolean, Unicode from sqlalchemy import Column, Boolean, Unicode, Integer
from sqlalchemy.orm import synonym, relationship from sqlalchemy.orm import synonym, relationship
@@ -14,12 +16,50 @@ def encrypt(val):
return md5(val.encode('utf-8') + "Salt".encode('utf-8')).hexdigest() return md5(val.encode('utf-8') + "Salt".encode('utf-8')).hexdigest()
#class UserGroup(Base): class Client(Base):
# __tablename__ = 'auth_usergroups' __tablename__ = 'auth_clients'
#
# id = Column('UserGroupID', GUID(), primary_key=True) id = Column('ClientID', GUID(), primary_key=True, default=uuid.uuid4)
# user_id = Column('UserID', GUID(), ForeignKey('auth_users.UserID')) code = Column('Code', Integer, unique=True, nullable=False)
# group_id = Column('GroupID', GUID(), ForeignKey('auth_groups.GroupID')) name = Column('Name', Unicode(255), unique=True, nullable=False)
enabled = Column('Enabled', Boolean, nullable=False)
otp = Column('OTP', Integer)
def __init__(self, code=None, name=None, enabled=False, otp=None):
self.code = code
self.name = name
self.enabled = enabled
self.otp = otp
@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_code(cls, code):
if not isinstance(code, int):
code = int(code)
return DBSession.query(cls).filter(cls.code == code).first()
@classmethod
def list(cls):
return DBSession.query(cls).order_by(cls.name).all()
@classmethod
def enabled_list(cls):
return DBSession.query(cls).filter(cls.enabled == True).order_by(cls.name).all()
@classmethod
def create(cls):
client_code = random.randint(1000, 9999)
otp = random.randint(1000, 9999)
name = ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(6))
# name = str(client_code)
client = Client(client_code, name, False, otp)
DBSession.add(client)
return client
user_group = Table( user_group = Table(
@@ -27,7 +67,7 @@ user_group = Table(
Column('UserGroupID', GUID(), primary_key=True, default=uuid.uuid4), Column('UserGroupID', GUID(), primary_key=True, default=uuid.uuid4),
Column('UserID', GUID(), ForeignKey('auth_users.UserID')), Column('UserID', GUID(), ForeignKey('auth_users.UserID')),
Column('GroupID', GUID(), ForeignKey('auth_groups.GroupID')) Column('GroupID', GUID(), ForeignKey('auth_groups.GroupID'))
) )
#class RoleGroup(Base): #class RoleGroup(Base):
# __tablename__ = 'auth_rolegroups' # __tablename__ = 'auth_rolegroups'
@@ -37,12 +77,12 @@ user_group = Table(
# group_id = Column('GroupID', GUID(), ForeignKey('auth_groups.GroupID')) # group_id = Column('GroupID', GUID(), ForeignKey('auth_groups.GroupID'))
role_group = Table ( role_group = Table(
'auth_rolegroups', Base.metadata, 'auth_rolegroups', Base.metadata,
Column('RoleGroupID', GUID(), primary_key=True, default=uuid.uuid4), Column('RoleGroupID', GUID(), primary_key=True, default=uuid.uuid4),
Column('RoleID', GUID(), ForeignKey('auth_roles.RoleID')), Column('RoleID', GUID(), ForeignKey('auth_roles.RoleID')),
Column('GroupID', GUID(), ForeignKey('auth_groups.GroupID')) Column('GroupID', GUID(), ForeignKey('auth_groups.GroupID'))
) )
class User(Base): class User(Base):
+9 -6
View File
@@ -160,6 +160,7 @@ class LedgerBase(Base):
type = Column('Type', Integer, nullable=False) type = Column('Type', Integer, nullable=False)
ledger_type = Column('ledger_type', Unicode(50), nullable=False) ledger_type = Column('ledger_type', Unicode(50), nullable=False)
is_active = Column('IsActive', Boolean) is_active = Column('IsActive', Boolean)
is_reconcilable = Column('IsReconcilable', Boolean)
costcenter_id = Column('CostCenterID', GUID(), ForeignKey('entities_costcenters.CostCenterID')) costcenter_id = Column('CostCenterID', GUID(), ForeignKey('entities_costcenters.CostCenterID'))
__mapper_args__ = {'polymorphic_on': ledger_type} __mapper_args__ = {'polymorphic_on': ledger_type}
@@ -174,11 +175,12 @@ class LedgerBase(Base):
def type_object(self): def type_object(self):
return LedgerType.by_id(self.type) return LedgerType.by_id(self.type)
def __init__(self, code=None, name=None, type=None, is_active=None, costcenter_id=None): def __init__(self, code=None, name=None, type=None, is_active=None, is_reconcilable=False, costcenter_id=None):
self.code = code self.code = code
self.name = name self.name = name
self.type = type self.type = type
self.is_active = is_active self.is_active = is_active
self.is_reconcilable = is_reconcilable
self.costcenter_id = costcenter_id self.costcenter_id = costcenter_id
@classmethod @classmethod
@@ -253,7 +255,8 @@ class Employee(LedgerBase):
self.service_points = service_points self.service_points = service_points
self.joining_date = joining_date self.joining_date = joining_date
self.leaving_date = leaving_date self.leaving_date = leaving_date
super().__init__(code, name, 10, is_active, costcenter_id) super().__init__(code=code, name=name, type=10, is_active=is_active, is_reconcilable=False,
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]
@@ -341,14 +344,14 @@ class LedgerType:
list.append(LedgerType(5, 'Capital', True, False, False, 70, True)) list.append(LedgerType(5, 'Capital', True, False, False, 70, True))
list.append(LedgerType(6, 'Debtors', True, True, True, 30, True)) list.append(LedgerType(6, 'Debtors', True, True, True, 30, True))
list.append(LedgerType(7, 'Expenses', False, True, True, 40, True)) list.append(LedgerType(7, 'Expenses', False, True, True, 40, True))
# list.append(LedgerType(8, 'Discount', False, False, True, 30, True)) # list.append(LedgerType(8, 'Discount', False, False, True, 30, True))
list.append(LedgerType(9, 'Creditors', True, False, True, 60, True)) list.append(LedgerType(9, 'Creditors', True, False, True, 60, True))
list.append(LedgerType(10, 'Salary', True, True, True, 40, False)) list.append(LedgerType(10, 'Salary', True, True, True, 40, False))
list.append(LedgerType(11, 'Liabilities', True, False, True, 50, True)) list.append(LedgerType(11, 'Liabilities', True, False, True, 50, True))
list.append(LedgerType(12, 'Revenue', False, False, True, 30, True)) list.append(LedgerType(12, 'Revenue', False, False, True, 30, True))
# list.append(LedgerType(13, 'Tax', True, False, True, 80, True)) # list.append(LedgerType(13, 'Tax', True, False, True, 80, True))
# list.append(LedgerType(14, 'Total', False, False, False, 900, False)) # list.append(LedgerType(14, 'Total', False, False, False, 900, False))
# list.append(LedgerType(15, 'Net', False, False, False, 1000, False)) # list.append(LedgerType(15, 'Net', False, False, False, 1000, False))
return list return list
@@ -30,6 +30,9 @@
<label class="checkbox"> <label class="checkbox">
<input type="checkbox" ng-model="account.IsActive"> Is Active <input type="checkbox" ng-model="account.IsActive"> Is Active
</label> </label>
<label class="checkbox">
<input type="checkbox" ng-model="account.IsReconcilable"> Is Reconcilable
</label>
</div> </div>
</div> </div>
@@ -5,6 +5,7 @@
<th>Name</th> <th>Name</th>
<th>Type</th> <th>Type</th>
<th>Is Active?</th> <th>Is Active?</th>
<th>Is Reconcilable?</th>
<th>Cost Center</th> <th>Cost Center</th>
</tr> </tr>
</thead> </thead>
@@ -13,6 +14,7 @@
<td><a href="{{item.Url}}">{{item.Name}}</a></td> <td><a href="{{item.Url}}">{{item.Name}}</a></td>
<td>{{item.Type}}</td> <td>{{item.Type}}</td>
<td>{{item.IsActive}}</td> <td>{{item.IsActive}}</td>
<td>{{item.IsReconcilable}}</td>
<td>{{item.CostCenter}}</td> <td>{{item.CostCenter}}</td>
</tr> </tr>
</tbody> </tbody>
+2 -2
View File
@@ -67,14 +67,14 @@
</div> </div>
</div> </div>
<div class=" control-group" id="add"> <div class=" control-group" id="add">
<label for="txtBatch" class="control-label">Add</label> <label for="txtBatch" class="control-label">Product</label>
<div class="controls"> <div class="controls">
<autobatch id="txtBatch" url="/Services/Batches" selname="name" <autobatch id="txtBatch" url="/Services/Batches" selname="name"
batch="batch" ng-model="name"></autobatch> batch="batch" ng-model="name"></autobatch>
<input type="text" id="txtQuantity" class="span2" autocomplete="off" <input type="text" id="txtQuantity" class="span2" autocomplete="off"
placeholder="Quantity" ng-model="quantity"/> placeholder="Quantity" ng-model="quantity"/>
<button class="btn btn-success" ng-click="addInventory()">Add <i class="icon-plus-sign icon-white"></i> <button class="btn btn-info" ng-click="addInventory()">Add <i class="icon-plus-sign icon-white"></i>
</button> </button>
</div> </div>
</div> </div>
+10 -10
View File
@@ -15,7 +15,7 @@
</div> </div>
</div> </div>
<div class=" control-group" id="add"> <div class=" control-group" id="add">
<label for="ddlDebitCredit" class="control-label">Add</label> <label for="ddlDebitCredit" class="control-label">Account</label>
<div class="controls"> <div class="controls">
<select id="ddlDebitCredit" ng-model="debit"> <select id="ddlDebitCredit" ng-model="debit">
@@ -28,7 +28,7 @@
<span class="add-on">₹</span><input type="text" id="txtAmount" class="span2" autocomplete="off" <span class="add-on">₹</span><input type="text" id="txtAmount" class="span2" autocomplete="off"
placeholder="Amount" ng-model="amount"/> placeholder="Amount" ng-model="amount"/>
</div> </div>
<button class="btn" ng-click="addJournal()">Add</button> <button class="btn btn-info" ng-click="addJournal()">Add <i class="icon-plus-sign icon-white"></i></button>
</div> </div>
</div> </div>
<div class=" control-group"> <div class=" control-group">
@@ -38,18 +38,18 @@
<table id="gvGrid" class="table clean-table"> <table id="gvGrid" class="table clean-table">
<thead> <thead>
<tr> <tr>
<th class="Debit">Debit</th> <th>Debit</th>
<th class="Name">Name</th> <th>Name</th>
<th class="Amount">Amount</th> <th>Amount</th>
<th class="Delete">Delete</th> <th>Delete</th>
</tr> </tr>
</thead> </thead>
<tbody id="tbodyMain"> <tbody id="tbodyMain">
<tr ng-repeat="journal in voucher.Journals"> <tr ng-repeat="journal in voucher.Journals">
<td class="Debit">{{journal.Debit | debit}}</td> <td>{{journal.Debit | debit}}</td>
<td class="Name">{{journal.Ledger.Name}}</td> <td>{{journal.Ledger.Name}}</td>
<td data-column="Amount" class="Amount Editable">{{journal.Amount}}</td> <td>{{journal.Amount}}</td>
<td class="Delete"> <td>
<div class="btn-group"> <div class="btn-group">
<a class="btn btn-danger" ng-click="removeJournal(journal)"><i <a class="btn btn-danger" ng-click="removeJournal(journal)"><i
class="icon-trash icon-white"></i> Delete</a> class="icon-trash icon-white"></i> Delete</a>
@@ -0,0 +1,23 @@
<form method="post" autocomplete="off">
<div class="modal-header">
<h3 id="myModalLabel">Edit Payment</h3>
</div>
<div class="modal-body">
<div class=" control-group">
<label for="editAccount">Account</label>
<autocomplete id="editAccount" url="/Services/Accounts" selname="edit.Ledger.Name"
selid="edit.Ledger.LedgerID"></autocomplete>
<label for="editAmount">Amount</label>
<div class="input-prepend input-append">
<span class="add-on">₹</span><input type="text" id="editAmount" class="span2" autocomplete="off"
placeholder="Amount" ng-model="edit.Amount"/>
</div>
</div>
<hr>
</div>
<div class="modal-footer">
<button id="cancel" class="btn">Cancel</button>
<button id="action" class="btn btn-primary">Update</button>
</div>
</form>
+15 -6
View File
@@ -27,18 +27,17 @@
</div> </div>
</div> </div>
<div class=" control-group" id="add"> <div class=" control-group" id="add">
<label for="txtLedger" class="control-label">Add</label> <label for="txtLedger" class="control-label">Account</label>
<div class="controls"> <div class="controls">
<autocomplete id="txtLedger" url="/Services/Accounts" selname="name" <autocomplete id="txtLedger" url="/Services/Accounts" selname="ledger.Name"
selid="id" ng-model="name"></autocomplete> selid="ledger.LedgerID" ng-model="name"></autocomplete>
<div class=" input-prepend"> <div class=" input-prepend">
<span class="add-on">₹</span> <span class="add-on">₹</span>
<input type="text" id="txtAmount" class="span2" autocomplete="off" <input type="text" id="txtAmount" class="span2" autocomplete="off"
placeholder="Amount" ng-model="amount"/> placeholder="Amount" ng-model="amount"/>
</div> </div>
<button class="btn btn-success" ng-click="addJournal()">Add <i class="icon-plus-sign icon-white"></i> <button class="btn btn-info" ng-click="addJournal()">Add <i class="icon-plus-sign icon-white"></i></button>
</button>
</div> </div>
</div> </div>
@@ -59,7 +58,17 @@
<td>{{journal.Ledger.Name}}</td> <td>{{journal.Ledger.Name}}</td>
<td>{{journal.Amount}}</td> <td>{{journal.Amount}}</td>
<td> <td>
<button class="btn" ng-click="removeJournal(journal)">Delete</button> <div class="btn-group">
<a class="btn btn-danger" ng-click="removeJournal(journal)"><i
class="icon-trash icon-white"></i> Delete</a>
<a class="btn btn-danger dropdown-toggle" data-toggle="dropdown" href="#"><span
class="caret"></span></a>
<ul class="dropdown-menu">
<li><a ng-confirm url="/partial/payment-modal.html" before="toggleEdit(journal)"
on-action="toggleEdit(journal, true)" on-cancel="toggleEdit(journal, false)"><i
class="icon-pencil"></i> Edit</a></li>
</ul>
</div>
</td> </td>
</tr> </tr>
</tbody> </tbody>
@@ -0,0 +1,104 @@
<form method="post" autocomplete="off" class="form-horizontal">
<legend>Purchase Return Edit / New</legend>
<div class="control-group">
<label for="txtCode" class="control-label">Code</label>
<div class="controls">
<input type="text" id="txtCode" class="non-search-box" disabled="disabled" ng-model="voucher.Code"/>
</div>
</div>
<div class="control-group">
<label for="txtDate" class="control-label">Date</label>
<div class="controls">
<datepicker id="txtDate" model="voucher" prop="Date" ng-model="voucher.Date"></datepicker>
</div>
</div>
<div class="control-group" ng-repeat="journal in voucher.Journals | journalDebit:1">
<label for="txtLedger" class="control-label">Ledger</label>
<div class="controls">
<autocomplete id="txtLedger" url="/Services/Accounts"
selname="journal.Ledger.Name" selid="journal.Ledger.LedgerID"></autocomplete>
<div class="input-prepend">
<span class="add-on">₹</span><input type="text" id="txtLedgerAmount" class="span2"
autocomplete="off" readonly="readonly"
placeholder="Amount" ng-model="journal.Amount"/>
</div>
</div>
</div>
<div class=" control-group" id="add">
<label for="txtBatch" class="control-label">Product</label>
<div class="controls">
<autobatch id="txtBatch" url="/Services/Batches" selname="name"
batch="batch" ng-model="name"></autobatch>
<input type="text" id="txtQuantity" class="span2" autocomplete="off"
placeholder="Quantity" ng-model="quantity"/>
<button class="btn btn-info" ng-click="addInventory()">Add <i class="icon-plus-sign icon-white"></i>
</button>
</div>
</div>
<div class="control-group">
<label for="gvGrid" class="control-label"></label>
<div class="controls">
<table id="gvGrid" class="table clean-table">
<thead>
<tr>
<th>Product</th>
<th>Quantity</th>
<th>Rate</th>
<th>Tax</th>
<th>Discount</th>
<th>Amount</th>
<th>Delete</th>
</tr>
</thead>
<tbody id="tbodyMain">
<tr ng-repeat="inventory in voucher.Inventories">
<td>{{inventory.Product.Name}}</td>
<td>{{inventory.Quantity}}</td>
<td>{{inventory.Rate}}</td>
<td>{{inventory.Tax}}</td>
<td>{{inventory.Discount}}</td>
<td>{{inventory.Amount}}</td>
<td>
<button class="btn" ng-click="removeInventory(inventory)">Delete</button>
</td>
</tr>
</tbody>
<tfoot id="tfootMain">
</tfoot>
</table>
</div>
</div>
<div class="control-group">
<label for="txtNarration" class="control-label">Narration</label>
<div class="controls">
<textarea rows="2" cols="20" id="txtNarration"
class="non-search-box" ng-model="voucher.Narration"></textarea>
</div>
</div>
<div class="form-actions">
<button class="btn btn-primary" ng-click="save()"
ng-disabled="preventAlteration(voucher)">{{voucher.Code | save_button}}
</button>
<button class="btn btn-inverse" ng-click="post()" ng-hide="voucher.Code == '(Auto)'"
ng-disabled="voucher.Posted || !perms['Post Vouchers']">{{voucher.Posted | posted}}
</button>
<button class="btn btn-danger" ng-hide="voucher.Code == '(Auto)'" ng-disabled="preventAlteration(voucher)"
ng-confirm title="Delete Voucher" action-text="Are you sure? This cannot be undone."
action-button-text="Delete" action-function="delete()"> Delete
</button>
</div>
<div class="row-fluid">
Created on {{voucher.CreationDate}} and Last Edited on {{voucher.LastEditDate}} by {{voucher.User.Name}}.
Posted
by {{voucher.Poster}}
</div>
</form>
+1 -1
View File
@@ -44,7 +44,7 @@
placeholder="Tax" ng-model="tax"/> placeholder="Tax" ng-model="tax"/>
<input type="text" id="txtDiscount" autocomplete="off" class="non-search-box inline" <input type="text" id="txtDiscount" autocomplete="off" class="non-search-box inline"
placeholder="Discount" ng-model="discount"/> placeholder="Discount" ng-model="discount"/>
<button class="btn btn-success" ng-click="addInventory()">Add <i class="icon-plus-sign icon-white"></i> <button class="btn btn-info" ng-click="addInventory()">Add <i class="icon-plus-sign icon-white"></i>
</button> </button>
</div> </div>
</div> </div>
@@ -0,0 +1,23 @@
<form method="post" autocomplete="off">
<div class="modal-header">
<h3 id="myModalLabel">Edit Receipt</h3>
</div>
<div class="modal-body">
<div class=" control-group">
<label for="editAccount">Account</label>
<autocomplete id="editAccount" url="/Services/Accounts" selname="edit.Ledger.Name"
selid="edit.Ledger.LedgerID"></autocomplete>
<label for="editAmount">Amount</label>
<div class="input-prepend input-append">
<span class="add-on">₹</span><input type="text" id="editAmount" class="span2" autocomplete="off"
placeholder="Amount" ng-model="edit.Amount"/>
</div>
</div>
<hr>
</div>
<div class="modal-footer">
<button id="cancel" class="btn">Cancel</button>
<button id="action" class="btn btn-primary">Update</button>
</div>
</form>
+13 -3
View File
@@ -27,7 +27,7 @@
</div> </div>
</div> </div>
<div class=" control-group" id="add"> <div class=" control-group" id="add">
<label for="txtLedger" class="control-label">Add</label> <label for="txtLedger" class="control-label">Account</label>
<div class="controls"> <div class="controls">
<autocomplete id="txtLedger" url="/Services/Accounts" selname="name" <autocomplete id="txtLedger" url="/Services/Accounts" selname="name"
@@ -37,7 +37,7 @@
<input type="text" id="txtAmount" class="span2" autocomplete="off" <input type="text" id="txtAmount" class="span2" autocomplete="off"
placeholder="Amount" ng-model="amount"/> placeholder="Amount" ng-model="amount"/>
</div> </div>
<button class="btn btn-success" ng-click="addJournal()">Add <i class="icon-plus-sign icon-white"></i> <button class="btn btn-info" ng-click="addJournal()">Add <i class="icon-plus-sign icon-white"></i>
</button> </button>
</div> </div>
</div> </div>
@@ -59,7 +59,17 @@
<td>{{journal.Ledger.Name}}</td> <td>{{journal.Ledger.Name}}</td>
<td>{{journal.Amount}}</td> <td>{{journal.Amount}}</td>
<td> <td>
<button class="btn" ng-click="removeJournal(journal)">Delete</button> <div class="btn-group">
<a class="btn btn-danger" ng-click="removeJournal(journal)"><i
class="icon-trash icon-white"></i> Delete</a>
<a class="btn btn-danger dropdown-toggle" data-toggle="dropdown" href="#"><span
class="caret"></span></a>
<ul class="dropdown-menu">
<li><a ng-confirm url="/partial/receipt-modal.html" before="toggleEdit(journal)"
on-action="toggleEdit(journal, true)" on-cancel="toggleEdit(journal, false)"><i
class="icon-pencil"></i> Edit</a></li>
</ul>
</div>
</td> </td>
</tr> </tr>
</tbody> </tbody>
+6 -4
View File
@@ -1,4 +1,6 @@
function AccountListCtrl($scope, accounts) { 'use strict';
function AccountListCtrl($scope, accounts) {
$scope.info = accounts; $scope.info = accounts;
} }
AccountListCtrl.resolve = { AccountListCtrl.resolve = {
@@ -12,10 +14,10 @@ AccountListCtrl.resolve = {
Account.query({}, successCb); Account.query({}, successCb);
return deferred.promise; return deferred.promise;
} }
} };
function AccountCtrl($scope, $location, account, account_types, cost_centers) { function AccountCtrl($scope, $location, account, account_types, cost_centers) {
$scope.account = account $scope.account = account;
$scope.account_types = account_types; $scope.account_types = account_types;
$scope.cost_centers = cost_centers; $scope.cost_centers = cost_centers;
@@ -73,4 +75,4 @@ AccountCtrl.resolve = {
CostCenter.query({}, successCb); CostCenter.query({}, successCb);
return deferred.promise; return deferred.promise;
} }
} };
+46 -11
View File
@@ -1,6 +1,8 @@
'use strict';
var overlord_directive = angular.module('overlord.directive', []); var overlord_directive = angular.module('overlord.directive', []);
overlord_directive.directive('autocomplete', function () { overlord_directive.directive('autocomplete', function () {
var directiveDefinitionObject = { return {
restrict:'E', restrict:'E',
replace:true, replace:true,
transclude:true, transclude:true,
@@ -41,11 +43,10 @@ overlord_directive.directive('autocomplete', function () {
}); });
} }
}; };
return directiveDefinitionObject;
}); });
overlord_directive.directive('autobatch', function () { overlord_directive.directive('autobatch', function () {
var directiveDefinitionObject = { return {
restrict:'E', restrict:'E',
replace:true, replace:true,
transclude:true, transclude:true,
@@ -81,11 +82,10 @@ overlord_directive.directive('autobatch', function () {
}); });
} }
}; };
return directiveDefinitionObject;
}); });
overlord_directive.directive('datepicker', function () { overlord_directive.directive('datepicker', function () {
var directiveDefinitionObject = { return {
restrict:'E', restrict:'E',
replace:true, replace:true,
transclude:true, transclude:true,
@@ -102,17 +102,16 @@ overlord_directive.directive('datepicker', function () {
}); });
} }
}; };
return directiveDefinitionObject;
}); });
overlord_directive.directive('fadey', function () { overlord_directive.directive('fadey', function () {
var directiveDefinitionObject = { return {
restrict:'A', restrict:'A',
link:function (scope, element, attrs) { link:function (scope, element, attrs) {
var duration = 500; var duration = 500;
element = jQuery(element); element = jQuery(element);
element.hide(); element.hide();
element.fadeIn(duration) element.fadeIn(duration);
scope.destroy = function (complete) { scope.destroy = function (complete) {
element.fadeOut(duration, function () { element.fadeOut(duration, function () {
@@ -124,7 +123,6 @@ overlord_directive.directive('fadey', function () {
} }
}; };
return directiveDefinitionObject;
}); });
overlord_directive.directive('ngConfirm', function (modal, $parse) { overlord_directive.directive('ngConfirm', function (modal, $parse) {
@@ -197,7 +195,7 @@ overlord_directive.directive('ngConfirm', function (modal, $parse) {
overlord_directive.directive('journal-edit', function () { overlord_directive.directive('journal-edit', function () {
var directiveDefinitionObject = { return {
restrict:'A', restrict:'A',
replace:true, replace:true,
transclude:true, transclude:true,
@@ -210,5 +208,42 @@ overlord_directive.directive('journal-edit', function () {
}); });
} }
}; };
return directiveDefinitionObject;
}); });
overlord_directive.directive('ngEditRepeat', function (modal, $parse) {
return {
restrict:'E',
template:'' +
'<div class="btn-group">' +
' <a class="btn btn-danger" ng-click="removeJournal(journal)"><i class="icon-trash icon-white"></i> Delete</a>' +
' <a class="btn btn-danger dropdown-toggle" data-toggle="dropdown" href="#"><span class="caret"></span></a>' +
' <ul class="dropdown-menu">' +
' <li><a ng-confirm url="/partial/journal-modal.html" before="toggleEdit(journal)" on-action="toggleEdit(journal, true)" on-cancel="toggleEdit(journal, false)"><i class="icon-pencil"></i> Edit</a></li>' +
' </ul>' +
'</div>',
link:function postLink(scope, element, attrs) {
// Could have custom or boostrap modal options here
var options = {};
if (typeof attrs.url !== 'undefined') {
element.bind("click", function () {
if (typeof attrs.before !== 'undefined') {
var fn = $parse(attrs.before);
scope.$apply(function () {
fn(scope);
});
}
modal.template(attrs.url, attrs.onAction, attrs.onCancel, scope, options);
});
} else {
element.bind("click", function () {
var actionButton = {text:attrs["actionButtonText"], click:attrs["actionFunction"], class:attrs['class']};
var cancelButton = {text:attrs["cancelButtonText"], click:attrs["cancelFunction"]};
modal.confirm(attrs["title"], attrs["actionText"], actionButton, cancelButton, scope, options);
});
}
}
};
});
+2 -1
View File
@@ -1,3 +1,5 @@
'use strict';
var overlord_filter = angular.module('overlord.filter', []); var overlord_filter = angular.module('overlord.filter', []);
overlord_filter.filter('debit', function () { overlord_filter.filter('debit', function () {
return function (input) { return function (input) {
@@ -8,7 +10,6 @@ overlord_filter.filter('debit', function () {
} else { } else {
return ''; return '';
} }
;
}; };
}); });
+2
View File
@@ -1,3 +1,5 @@
'use strict';
var overlord_service = angular.module('overlord.service', ['ngResource']); var overlord_service = angular.module('overlord.service', ['ngResource']);
// TODO: Replace hardcoded url with route_url // TODO: Replace hardcoded url with route_url
+4 -2
View File
@@ -1,4 +1,6 @@
function AttendanceCtrl($scope, $location, Attendance, attendance_types, info) { 'use strict';
function AttendanceCtrl($scope, $location, Attendance, attendance_types, info) {
$scope.attendance_types = attendance_types; $scope.attendance_types = attendance_types;
$scope.info = info; $scope.info = info;
$scope.show = function () { $scope.show = function () {
@@ -36,4 +38,4 @@ AttendanceCtrl.resolve = {
AttendanceTypes.query({}, successCb); AttendanceTypes.query({}, successCb);
return deferred.promise; return deferred.promise;
} }
} };
+4 -2
View File
@@ -1,4 +1,6 @@
function CashFlowCtrl($scope, $routeParams, $location, cash_flow) { 'use strict';
function CashFlowCtrl($scope, $routeParams, $location, cash_flow) {
$scope.info = cash_flow; $scope.info = cash_flow;
$scope.show = function () { $scope.show = function () {
$location.path('/CashFlow').search({StartDate:$scope.info.StartDate, FinishDate:$scope.info.FinishDate}); $location.path('/CashFlow').search({StartDate:$scope.info.StartDate, FinishDate:$scope.info.FinishDate});
@@ -26,4 +28,4 @@ CashFlowCtrl.resolve = {
} }
return deferred.promise; return deferred.promise;
} }
} };
@@ -1,4 +1,6 @@
function ClosingStockCtrl($scope, $location, info) { 'use strict';
function ClosingStockCtrl($scope, $location, info) {
$scope.info = info; $scope.info = info;
$scope.show = function () { $scope.show = function () {
$location.path('/ClosingStock/' + $scope.info.Date); $location.path('/ClosingStock/' + $scope.info.Date);
@@ -22,4 +24,4 @@ ClosingStockCtrl.resolve = {
} }
return deferred.promise; return deferred.promise;
} }
} };
@@ -1,4 +1,6 @@
function CostCenterListCtrl($scope, cost_centers) { 'use strict';
function CostCenterListCtrl($scope, cost_centers) {
$scope.info = cost_centers; $scope.info = cost_centers;
} }
@@ -13,7 +15,7 @@ CostCenterListCtrl.resolve = {
CostCenter.query({}, successCb); CostCenter.query({}, successCb);
return deferred.promise; return deferred.promise;
} }
} };
function CostCenterCtrl($scope, $routeParams, $location, cost_center) { function CostCenterCtrl($scope, $routeParams, $location, cost_center) {
$scope.cost_center = cost_center; $scope.cost_center = cost_center;
@@ -51,4 +53,4 @@ CostCenterCtrl.resolve = {
CostCenter.get({id:id}, successCb); CostCenter.get({id:id}, successCb);
return deferred.promise; return deferred.promise;
} }
} };
+4 -2
View File
@@ -1,4 +1,6 @@
function DaybookCtrl($scope, $location, info) { 'use strict';
function DaybookCtrl($scope, $location, info) {
$scope.info = info; $scope.info = info;
$scope.show = function () { $scope.show = function () {
$location.path('/Daybook').search({StartDate:$scope.info.StartDate, FinishDate:$scope.info.FinishDate}); $location.path('/Daybook').search({StartDate:$scope.info.StartDate, FinishDate:$scope.info.FinishDate});
@@ -23,4 +25,4 @@ DaybookCtrl.resolve = {
} }
return deferred.promise; return deferred.promise;
} }
} };
@@ -1,4 +1,6 @@
overlord_service.factory('modal', function ($http, $compile) { 'use strict';
overlord_service.factory('delete-button', function ($http, $compile) {
var modal = {}; var modal = {};
modal.get = function (create) { modal.get = function (create) {
@@ -7,12 +9,12 @@ overlord_service.factory('modal', function ($http, $compile) {
modal.dialog.appendTo('BODY'); modal.dialog.appendTo('BODY');
} }
return modal.dialog; return modal.dialog;
} };
modal.compileAndRun = function (dialog, scope, options) { modal.compileAndRun = function (dialog, scope, options) {
$compile(dialog)(scope); $compile(dialog)(scope);
dialog.modal(options); dialog.modal(options);
} };
modal.alert = function (title, text, button, scope, options) { modal.alert = function (title, text, button, scope, options) {
text = (text) ? text : "Alert"; text = (text) ? text : "Alert";
@@ -35,7 +37,7 @@ overlord_service.factory('modal', function ($http, $compile) {
modal.close(); modal.close();
}); });
modal.compileAndRun(dialog, scope, options); modal.compileAndRun(dialog, scope, options);
} };
modal.confirm = function (title, actionText, actionButton, cancelButton, scope, options) { modal.confirm = function (title, actionText, actionButton, cancelButton, scope, options) {
actionText = (actionText) ? actionText : "Are you sure?"; actionText = (actionText) ? actionText : "Are you sure?";
@@ -68,14 +70,14 @@ overlord_service.factory('modal', function ($http, $compile) {
}); });
modal.compileAndRun(dialog, scope, options); modal.compileAndRun(dialog, scope, options);
} };
modal.close = function () { modal.close = function () {
var dialog = modal.get() var dialog = modal.get();
if (dialog) { if (dialog) {
dialog.modal('hide'); dialog.modal('hide');
} }
} };
return modal; return modal;
@@ -1,4 +1,6 @@
function EmployeeAttendanceCtrl($scope, $location, EmployeeAttendance, attendance_types, info) { 'use strict';
function EmployeeAttendanceCtrl($scope, $location, EmployeeAttendance, attendance_types, info) {
$scope.attendance_types = attendance_types; $scope.attendance_types = attendance_types;
$scope.info = info; $scope.info = info;
$scope.show = function () { $scope.show = function () {
@@ -39,4 +41,4 @@ EmployeeAttendanceCtrl.resolve = {
AttendanceTypes.query({}, successCb); AttendanceTypes.query({}, successCb);
return deferred.promise; return deferred.promise;
} }
} };
@@ -1,4 +1,6 @@
function EmployeeFunctionsCtrl($scope) { 'use strict';
function EmployeeFunctionsCtrl($scope) {
$scope.creditSalary = function () { $scope.creditSalary = function () {
$scope.toasts.push({Type:'Error', Message:'Not Implemented Yet'}); $scope.toasts.push({Type:'Error', Message:'Not Implemented Yet'});
}; };
+6 -4
View File
@@ -1,4 +1,6 @@
function EmployeeListCtrl($scope, employees) { 'use strict';
function EmployeeListCtrl($scope, employees) {
$scope.info = employees; $scope.info = employees;
} }
EmployeeListCtrl.resolve = { EmployeeListCtrl.resolve = {
@@ -12,12 +14,12 @@ EmployeeListCtrl.resolve = {
Employee.query({}, successCb); Employee.query({}, successCb);
return deferred.promise; return deferred.promise;
} }
} };
function EmployeeCtrl($scope, $routeParams, $location, employee, cost_centers) { function EmployeeCtrl($scope, $routeParams, $location, employee, cost_centers) {
$scope.employee = employee; $scope.employee = employee;
$scope.cost_centers = cost_centers $scope.cost_centers = cost_centers;
$scope.save = function () { $scope.save = function () {
$scope.employee.$save(function (u, putResponseHeaders) { $scope.employee.$save(function (u, putResponseHeaders) {
@@ -62,4 +64,4 @@ EmployeeCtrl.resolve = {
CostCenter.query({}, successCb); CostCenter.query({}, successCb);
return deferred.promise; return deferred.promise;
} }
} };
+5 -3
View File
@@ -1,4 +1,6 @@
function GroupListCtrl($scope, groups) { 'use strict';
function GroupListCtrl($scope, groups) {
$scope.info = groups; $scope.info = groups;
} }
@@ -13,7 +15,7 @@ GroupListCtrl.resolve = {
Group.query({}, successCb); Group.query({}, successCb);
return deferred.promise; return deferred.promise;
} }
} };
function GroupCtrl($scope, $location, group) { function GroupCtrl($scope, $location, group) {
$scope.group = group; $scope.group = group;
@@ -51,4 +53,4 @@ GroupCtrl.resolve = {
Group.get({id:id}, successCb); Group.get({id:id}, successCb);
return deferred.promise; return deferred.promise;
} }
} };
+7 -4
View File
@@ -1,4 +1,6 @@
function IssueCtrl($scope, $routeParams, $location, voucher, cost_centers, issue_grid, IssueGrid, Voucher) { 'use strict';
function IssueCtrl($scope, $routeParams, $location, voucher, cost_centers, issue_grid, IssueGrid, Voucher) {
$scope.voucher = voucher; $scope.voucher = voucher;
$scope.cost_centers = cost_centers; $scope.cost_centers = cost_centers;
$scope.smallGrid = issue_grid; $scope.smallGrid = issue_grid;
@@ -32,8 +34,8 @@
delete $scope.name; delete $scope.name;
delete $scope.quantity; delete $scope.quantity;
$('#txtBatch').val(''); $('#txtBatch').val('');
$('#txtBatch').focus();
} }
$('#txtBatch').focus();
}; };
$scope.removeInventory = function (inventory) { $scope.removeInventory = function (inventory) {
var index = this.voucher.Inventories.indexOf(inventory); var index = this.voucher.Inventories.indexOf(inventory);
@@ -79,7 +81,7 @@
if (typeof newInventories === 'undefined' || typeof oldInventories === 'undefined') { if (typeof newInventories === 'undefined' || typeof oldInventories === 'undefined') {
return; return;
} }
var amount = 0 var amount = 0;
for (var i = 0, l = newInventories.length; i < l; i++) { for (var i = 0, l = newInventories.length; i < l; i++) {
amount += newInventories[i].Amount; amount += newInventories[i].Amount;
} }
@@ -200,4 +202,5 @@ IssueCtrl.resolve = {
CostCenter.query({}, successCb); CostCenter.query({}, successCb);
return deferred.promise; return deferred.promise;
}} }
};
+5 -4
View File
@@ -1,4 +1,6 @@
function JournalCtrl($scope, $location, voucher) { 'use strict';
function JournalCtrl($scope, $location, voucher) {
$scope.voucher = voucher; $scope.voucher = voucher;
$scope.name = ''; $scope.name = '';
$scope.debit = 1; $scope.debit = 1;
@@ -97,7 +99,7 @@
$scope.toggleDebit = function () { $scope.toggleDebit = function () {
$("#editDebit").button('toggle'); $("#editDebit").button('toggle');
$scope.edit.Debit = ($scope.edit.Debit === 1) ? -1 : 1; $scope.edit.Debit = ($scope.edit.Debit === 1) ? -1 : 1;
} };
$scope.toggleEdit = function (journal, update) { $scope.toggleEdit = function (journal, update) {
if (typeof update === 'undefined') { if (typeof update === 'undefined') {
$scope.edit = {}; $scope.edit = {};
@@ -137,5 +139,4 @@ JournalCtrl.resolve = {
} }
return deferred.promise; return deferred.promise;
} }
};
}
+4 -2
View File
@@ -1,4 +1,6 @@
function LedgerCtrl($scope, $routeParams, $location, ledger) { 'use strict';
function LedgerCtrl($scope, $routeParams, $location, ledger) {
$scope.info = ledger; $scope.info = ledger;
$scope.show = function () { $scope.show = function () {
$location.path('/Ledger/' + $scope.info.Ledger.LedgerID).search('StartDate', $scope.info.StartDate).search('FinishDate', $scope.info.FinishDate); $location.path('/Ledger/' + $scope.info.Ledger.LedgerID).search('StartDate', $scope.info.StartDate).search('FinishDate', $scope.info.FinishDate);
@@ -25,6 +27,6 @@ LedgerCtrl.resolve = {
} }
return deferred.promise; return deferred.promise;
} }
} };
+4 -2
View File
@@ -1,4 +1,6 @@
function LoginCtrl($scope, $http, $location, $route, $routeParams) { 'use strict';
function LoginCtrl($scope, $http, $location, $route, $routeParams) {
$scope.submit = function () { $scope.submit = function () {
$http. $http.
post('/login', {username:$scope.username, password:$scope.password}). post('/login', {username:$scope.username, password:$scope.password}).
@@ -12,7 +14,7 @@
error(function (errorMessage) { error(function (errorMessage) {
$scope.toasts.push({Type:'Error', Message:errorMessage}); $scope.toasts.push({Type:'Error', Message:errorMessage});
}); });
} };
$('#username').focus(); $('#username').focus();
} }
@@ -1,3 +1,5 @@
'use strict';
overlord_service.factory('modal', function ($http, $compile) { overlord_service.factory('modal', function ($http, $compile) {
var modal = {}; var modal = {};
@@ -7,12 +9,12 @@ overlord_service.factory('modal', function ($http, $compile) {
modal.dialog.appendTo('BODY'); modal.dialog.appendTo('BODY');
} }
return modal.dialog; return modal.dialog;
} };
modal.compileAndRun = function (dialog, scope, options) { modal.compileAndRun = function (dialog, scope, options) {
$compile(dialog)(scope); $compile(dialog)(scope);
dialog.modal(options); dialog.modal(options);
} };
modal.alert = function (title, text, button, scope, options) { modal.alert = function (title, text, button, scope, options) {
text = (text) ? text : "Alert"; text = (text) ? text : "Alert";
@@ -35,7 +37,7 @@ overlord_service.factory('modal', function ($http, $compile) {
modal.close(); modal.close();
}); });
modal.compileAndRun(dialog, scope, options); modal.compileAndRun(dialog, scope, options);
} };
modal.confirm = function (title, actionText, actionButton, cancelButton, scope, options) { modal.confirm = function (title, actionText, actionButton, cancelButton, scope, options) {
actionText = (actionText) ? actionText : "Are you sure?"; actionText = (actionText) ? actionText : "Are you sure?";
@@ -68,7 +70,7 @@ overlord_service.factory('modal', function ($http, $compile) {
}); });
modal.compileAndRun(dialog, scope, options); modal.compileAndRun(dialog, scope, options);
} };
modal.template = function (url, onSuccess, onCancel, scope, options) { modal.template = function (url, onSuccess, onCancel, scope, options) {
$http.get(url).success(function (data) { $http.get(url).success(function (data) {
@@ -85,20 +87,20 @@ overlord_service.factory('modal', function ($http, $compile) {
if (onCancel) { if (onCancel) {
scope.$eval(onCancel); scope.$eval(onCancel);
} }
}) });
dialog.find("#cancel").click(function () { dialog.find("#cancel").click(function () {
modal.close(); modal.close();
}); });
modal.compileAndRun(dialog, scope, options); modal.compileAndRun(dialog, scope, options);
}); });
} };
modal.close = function () { modal.close = function () {
var dialog = modal.get() var dialog = modal.get();
if (dialog) { if (dialog) {
dialog.modal('hide'); dialog.modal('hide');
} }
} };
return modal; return modal;
+8 -2
View File
@@ -19,6 +19,9 @@ var overlord = angular.module('overlord', ['overlord.directive', 'overlord.filte
when('/Purchase', {templateUrl:'/partial/purchase.html', controller:PurchaseCtrl, resolve:PurchaseCtrl.resolve}). when('/Purchase', {templateUrl:'/partial/purchase.html', controller:PurchaseCtrl, resolve:PurchaseCtrl.resolve}).
when('/Purchase/:id', {templateUrl:'/partial/purchase.html', controller:PurchaseCtrl, resolve:PurchaseCtrl.resolve}). when('/Purchase/:id', {templateUrl:'/partial/purchase.html', controller:PurchaseCtrl, resolve:PurchaseCtrl.resolve}).
when('/Return', {templateUrl:'/partial/purchase-return.html', controller:PurchaseReturnCtrl, resolve:PurchaseReturnCtrl.resolve}).
when('/Return/:id', {templateUrl:'/partial/purchase-return.html', controller:PurchaseReturnCtrl, resolve:PurchaseReturnCtrl.resolve}).
when('/Issue', {templateUrl:'/partial/issue.html', controller:IssueCtrl, resolve:IssueCtrl.resolve}). when('/Issue', {templateUrl:'/partial/issue.html', controller:IssueCtrl, resolve:IssueCtrl.resolve}).
when('/Issue/:id', {templateUrl:'/partial/issue.html', controller:IssueCtrl, resolve:IssueCtrl.resolve}). when('/Issue/:id', {templateUrl:'/partial/issue.html', controller:IssueCtrl, resolve:IssueCtrl.resolve}).
@@ -123,13 +126,16 @@ var overlord = angular.module('overlord', ['overlord.directive', 'overlord.filte
}; };
}]); }]);
function BaseCtrl($rootScope, $scope, Auth, $location) { function BaseCtrl($rootScope, $scope, Auth, $location, $routeParams) {
$rootScope.spinner = {http:0, route:false}; $rootScope.spinner = {http:0, route:false};
$rootScope.$on('event:loginRequired', function () { $rootScope.$on('event:loginRequired', function () {
if ($rootScope.auth.isAuthenticated) { if ($rootScope.auth.isAuthenticated) {
$location.path('/'); $location.path('/');
} else { } else {
var came_from = $location.path(); var came_from = $routeParams.came_from;
if (typeof came_from === 'undefined' && $location.path() === '/login') {
came_from = $location.path();
}
$location.path('/login').search({came_from:came_from}); $location.path('/login').search({came_from:came_from});
} }
}); });
+48 -21
View File
@@ -1,27 +1,33 @@
function PaymentCtrl($scope, $location, voucher, ledgers) { 'use strict';
$scope.voucher = voucher
$scope.ledgers = ledgers;
$scope.addJournal = function () { function PaymentCtrl($scope, $location, voucher, ledgers) {
for (var i = 0, l = this.voucher.Journals.length; i < l; i++) { $scope.voucher = voucher;
if (this.voucher.Journals[i].Ledger.LedgerID === $scope.id) { $scope.ledgers = ledgers;
var amount = (this.voucher.Journals[i].Debit * this.voucher.Journals[i].Amount) + (parseInt($scope.debit) * Number($scope.amount)); function getOldJournal(ledgerID, journals) {
if (amount < 0) { for (var i = 0, l = journals.length; i < l; i++) {
this.voucher.Journals[i].Debit = -1; if (journals[i].Ledger.LedgerID === ledgerID) {
this.voucher.Journals[i].Amount = amount * -1; return journals[i];
} else {
this.voucher.Journals[i].Debit = 1;
this.voucher.Journals[i].Amount = amount;
}
break;
} }
} }
if (i >= l) {
this.voucher.Journals.push({Debit:1, Amount:Number($scope.amount), Ledger:{LedgerID:$scope.id, Name:$scope.name}}); }
$scope.addJournal = function () {
var oldJournal = getOldJournal($scope.ledger.LedgerID, this.voucher.Journals);
if (typeof oldJournal !== 'undefined') {
var amount = (oldJournal.Debit * oldJournal.Amount) + (parseInt($scope.debit) * Number($scope.amount));
if (amount < 0) {
oldJournal.Debit = -1;
oldJournal.Amount = amount * -1;
} else {
oldJournal.Debit = 1;
oldJournal.Amount = amount;
}
} else {
this.voucher.Journals.push({Debit:1, Amount:Number($scope.amount), Ledger:$scope.ledger});
} }
delete $scope.ledger;
delete $scope.amount; delete $scope.amount;
delete $scope.id;
delete $scope.name;
$('#txtLedger').focus(); $('#txtLedger').focus();
}; };
@@ -93,6 +99,27 @@
$scope.toasts.push({Type:'Error', Message:data.data}); $scope.toasts.push({Type:'Error', Message:data.data});
}); });
}; };
$scope.toggleEdit = function (journal, update) {
if (typeof update === 'undefined') {
$scope.edit = {};
angular.copy(journal, $scope.edit);
} else {
if (update === true && typeof $scope.edit !== 'undefined') {
if (journal.Ledger.LedgerID !== $scope.edit.Ledger.LedgerID) {
var oldJournal = getOldJournal($scope.edit.Ledger.LedgerID, $scope.voucher.Journals);
if (typeof oldJournal !== 'undefined') {
return false;
}
}
angular.copy($scope.edit, journal);
$scope.$apply();
return true;
} else if (update === false) {
delete $scope.edit;
}
}
}
} }
PaymentCtrl.resolve = { PaymentCtrl.resolve = {
@@ -117,9 +144,9 @@ PaymentCtrl.resolve = {
var successCb = function (result) { var successCb = function (result) {
deferred.resolve(result); deferred.resolve(result);
} };
LedgerService.query({type:1}, successCb); LedgerService.query({type:1}, successCb);
return deferred.promise; return deferred.promise;
} }
} };
@@ -1,4 +1,6 @@
function ProductGroupListCtrl($scope, product_groups) { 'use strict';
function ProductGroupListCtrl($scope, product_groups) {
$scope.info = product_groups $scope.info = product_groups
} }
@@ -13,7 +15,7 @@ ProductGroupListCtrl.resolve = {
ProductGroup.query({}, successCb); ProductGroup.query({}, successCb);
return deferred.promise; return deferred.promise;
} }
} };
function ProductGroupCtrl($scope, $location, product_group) { function ProductGroupCtrl($scope, $location, product_group) {
$scope.product_group = product_group; $scope.product_group = product_group;
@@ -51,4 +53,4 @@ ProductGroupCtrl.resolve = {
ProductGroup.get({id:id}, successCb); ProductGroup.get({id:id}, successCb);
return deferred.promise; return deferred.promise;
} }
} };
@@ -1,4 +1,6 @@
function ProductLedgerCtrl($scope, $routeParams, $location, product_ledger) { 'use strict';
function ProductLedgerCtrl($scope, $routeParams, $location, product_ledger) {
$scope.info = product_ledger; $scope.info = product_ledger;
$scope.show = function () { $scope.show = function () {
$location.path('/ProductLedger/' + $scope.info.Product.ProductID).search('StartDate', $scope.info.StartDate).search('FinishDate', $scope.info.FinishDate); $location.path('/ProductLedger/' + $scope.info.Product.ProductID).search('StartDate', $scope.info.StartDate).search('FinishDate', $scope.info.FinishDate);
@@ -24,4 +26,4 @@ ProductLedgerCtrl.resolve = {
} }
return deferred.promise; return deferred.promise;
} }
} };
+6 -4
View File
@@ -1,4 +1,6 @@
function ProductListCtrl($scope, products) { 'use strict';
function ProductListCtrl($scope, products) {
$scope.info = products; $scope.info = products;
} }
@@ -13,10 +15,10 @@ ProductListCtrl.resolve = {
Product.query({}, successCb); Product.query({}, successCb);
return deferred.promise; return deferred.promise;
} }
} };
function ProductCtrl($scope, $location, product, product_groups) { function ProductCtrl($scope, $location, product, product_groups) {
$scope.product = product $scope.product = product;
$scope.product_groups = product_groups; $scope.product_groups = product_groups;
$scope.save = function () { $scope.save = function () {
@@ -62,4 +64,4 @@ ProductCtrl.resolve = {
ProductGroup.query({}, successCb); ProductGroup.query({}, successCb);
return deferred.promise; return deferred.promise;
} }
} };
@@ -1,4 +1,6 @@
function ProfitLossCtrl($scope, $location, profit_loss) { 'use strict';
function ProfitLossCtrl($scope, $location, profit_loss) {
$scope.info = profit_loss; $scope.info = profit_loss;
$scope.show = function () { $scope.show = function () {
$location.path('/ProfitLoss').search({StartDate:$scope.info.StartDate, FinishDate:$scope.info.FinishDate}); $location.path('/ProfitLoss').search({StartDate:$scope.info.StartDate, FinishDate:$scope.info.FinishDate});
@@ -24,4 +26,4 @@ ProfitLossCtrl.resolve = {
} }
return deferred.promise; return deferred.promise;
} }
} };
@@ -1,4 +1,6 @@
function PurchaseEntriesCtrl($scope, $location, purchase_entries) { 'use strict';
function PurchaseEntriesCtrl($scope, $location, purchase_entries) {
$scope.info = purchase_entries; $scope.info = purchase_entries;
$scope.show = function () { $scope.show = function () {
@@ -25,6 +27,6 @@ PurchaseEntriesCtrl.resolve = {
} }
return deferred.promise; return deferred.promise;
} }
} };
@@ -0,0 +1,120 @@
'use strict';
function PurchaseReturnCtrl($scope, $location, voucher) {
$scope.voucher = voucher;
$scope.rate = 0;
$scope.addInventory = function () {
for (var i = 0, l = this.voucher.Inventories.length; i < l; i++) {
if (this.voucher.Inventories[i].Product.ProductID === $scope.batch.Product.ProductID) {
break;
}
}
if (i >= l && Number($scope.quantity) <= $scope.batch.QuantityRemaining) {
var amount = Number($scope.quantity) * $scope.batch.Rate * (1 + $scope.batch.Tax) * (1 - $scope.batch.Discount);
this.voucher.Inventories.push(
{
Product:$scope.batch.Product,
Quantity:Number($scope.quantity),
Rate:Number($scope.batch.Rate),
Tax:Number($scope.batch.Tax),
Discount:Number($scope.batch.Discount),
Amount:amount,
Batch:$scope.batch
});
delete $scope.batch;
delete $scope.name;
delete $scope.quantity;
$('#txtBatch').val('');
$('#txtBatch').focus();
}
};
$scope.removeInventory = function (inventory) {
var index = this.voucher.Inventories.indexOf(inventory);
this.voucher.Inventories.splice(index, 1);
};
$scope.$watch('voucher.Inventories', function (inventories, oldValue) {
var amount = 0;
if (typeof inventories !== 'undefined') {
for (var i = 0, l = inventories.length; i < l; i++) {
amount += Number(inventories[i].Amount);
}
}
if (typeof $scope.voucher.Journals !== 'undefined') {
for (var i = 0, l = $scope.voucher.Journals.length; i < l; i++) {
if ($scope.voucher.Journals[i].Debit === 1) {
$scope.voucher.Journals[i].Amount = amount;
break;
}
}
}
}, true);
$scope.preventAlteration = function (voucher) {
if (typeof $scope.perms === 'undefined') {
return false;
} else if (typeof voucher.VoucherID === 'undefined') {
return !$scope.perms['Purchase Return'];
} else if (voucher.Posted && !$scope.perms['Edit Posted Vouchers']) {
return true;
} else if (voucher.User.UserID != $scope.auth.UserID && !$scope.perms["Edit Other User's Vouchers"]) {
return true;
} else {
return false;
}
};
$scope.get = function (voucherid) {
$scope.voucher = Voucher.get({VoucherID:voucherid}, function (u, putResponseHeaders) {
$scope.toasts.push({Type:'Success', Message:u.Code});
}, function (data, status) {
$scope.toasts.push({Type:'Error', Message:data.data});
});
};
$scope.save = function () {
$scope.voucher.$save({type:'Purchase Return'}, function (u, putResponseHeaders) {
$scope.toasts.push({Type:'Success', Message:u.Code});
$location.path('/Return/' + u.VoucherID);
}, function (data, status) {
$scope.toasts.push({Type:'Error', Message:data.data});
});
};
$scope.delete = function () {
$scope.voucher.$delete(function (u, putResponseHeaders) {
$scope.toasts.push({Type:'Success', Message:''});
$location.path('/Return').replace();
}, function (data, status) {
$scope.toasts.push({Type:'Error', Message:data.data});
});
};
$scope.post = function () {
$scope.voucher.$post(function (u, putResponseHeaders) {
$scope.toasts.push({Type:'Success', Message:u.code});
}, function (data, status) {
$scope.toasts.push({Type:'Error', Message:data.data});
});
};
}
PurchaseReturnCtrl.resolve = {
voucher:function ($q, $route, Voucher) {
var deferred = $q.defer();
var id = $route.current.params.id;
var successCb = function (result) {
deferred.resolve(result);
};
if (typeof id === 'undefined') {
Voucher.get({type:'Purchase Return'}, successCb);
} else {
Voucher.get({id:id}, successCb);
}
return deferred.promise;
}
};
+5 -7
View File
@@ -1,5 +1,7 @@
function PurchaseCtrl($scope, $location, voucher) { 'use strict';
$scope.voucher = voucher
function PurchaseCtrl($scope, $location, voucher) {
$scope.voucher = voucher;
$scope.rate = 0; $scope.rate = 0;
$scope.addInventory = function () { $scope.addInventory = function () {
@@ -37,10 +39,6 @@
this.voucher.Inventories.splice(index, 1); this.voucher.Inventories.splice(index, 1);
}; };
$scope.ledgerName = function (journal) {
return journal.Ledger.Name;
};
$scope.$watch('voucher.Inventories', function (inventories, oldValue) { $scope.$watch('voucher.Inventories', function (inventories, oldValue) {
var amount = 0; var amount = 0;
if (typeof inventories !== 'undefined') { if (typeof inventories !== 'undefined') {
@@ -124,4 +122,4 @@ PurchaseCtrl.resolve = {
} }
return deferred.promise; return deferred.promise;
} }
} };
@@ -1,4 +1,6 @@
function RawMaterialCostCtrl($scope, $routeParams, $location, raw_material_cost) { 'use strict';
function RawMaterialCostCtrl($scope, $routeParams, $location, raw_material_cost) {
$scope.info = raw_material_cost; $scope.info = raw_material_cost;
$scope.show = function () { $scope.show = function () {
$location.path('/RawMaterialCost').search({StartDate:$scope.info.StartDate, FinishDate:$scope.info.FinishDate}); $location.path('/RawMaterialCost').search({StartDate:$scope.info.StartDate, FinishDate:$scope.info.FinishDate});
@@ -26,4 +28,4 @@ RawMaterialCostCtrl.resolve = {
} }
return deferred.promise; return deferred.promise;
} }
} };
+48 -21
View File
@@ -1,27 +1,33 @@
function ReceiptCtrl($scope, $routeParams, $location, voucher, ledgers, Voucher) { 'use strict';
$scope.voucher = voucher
$scope.ledgers = ledgers;
$scope.addJournal = function () { function ReceiptCtrl($scope, $routeParams, $location, voucher, ledgers, Voucher) {
for (var i = 0, l = this.voucher.Journals.length; i < l; i++) { $scope.voucher = voucher;
if (this.voucher.Journals[i].Ledger.LedgerID === $scope.id) { $scope.ledgers = ledgers;
var amount = (this.voucher.Journals[i].Debit * this.voucher.Journals[i].Amount) + (parseInt($scope.debit) * Number($scope.amount)); function getOldJournal(ledgerID, journals) {
if (amount < 0) { for (var i = 0, l = journals.length; i < l; i++) {
this.voucher.Journals[i].Debit = -1; if (journals[i].Ledger.LedgerID === ledgerID) {
this.voucher.Journals[i].Amount = amount * -1; return journals[i];
} else {
this.voucher.Journals[i].Debit = 1;
this.voucher.Journals[i].Amount = amount;
}
break;
} }
} }
if (i >= l) {
this.voucher.Journals.push({Debit:-1, Amount:Number($scope.amount), Ledger:{LedgerID:$scope.id, Name:$scope.name}}); }
$scope.addJournal = function () {
var oldJournal = getOldJournal($scope.ledger.LedgerID, this.voucher.Journals);
if (typeof oldJournal !== 'undefined') {
var amount = (oldJournal.Debit * oldJournal.Amount) + (parseInt($scope.debit) * Number($scope.amount));
if (amount < 0) {
oldJournal.Debit = -1;
oldJournal.Amount = amount * -1;
} else {
oldJournal.Debit = 1;
oldJournal.Amount = amount;
}
} else {
this.voucher.Journals.push({Debit:-1, Amount:Number($scope.amount), Ledger:$scope.ledger});
} }
delete $scope.ledger;
delete $scope.amount; delete $scope.amount;
delete $scope.id;
delete $scope.name;
$('#txtLedger').focus(); $('#txtLedger').focus();
}; };
@@ -93,6 +99,27 @@
$scope.toasts.push({Type:'Error', Message:data.data}); $scope.toasts.push({Type:'Error', Message:data.data});
}); });
}; };
$scope.toggleEdit = function (journal, update) {
if (typeof update === 'undefined') {
$scope.edit = {};
angular.copy(journal, $scope.edit);
} else {
if (update === true && typeof $scope.edit !== 'undefined') {
if (journal.Ledger.LedgerID !== $scope.edit.Ledger.LedgerID) {
var oldJournal = getOldJournal($scope.edit.Ledger.LedgerID, $scope.voucher.Journals);
if (typeof oldJournal !== 'undefined') {
return false;
}
}
angular.copy($scope.edit, journal);
$scope.$apply();
return true;
} else if (update === false) {
delete $scope.edit;
}
}
}
} }
ReceiptCtrl.resolve = { ReceiptCtrl.resolve = {
@@ -117,9 +144,9 @@ ReceiptCtrl.resolve = {
var successCb = function (result) { var successCb = function (result) {
deferred.resolve(result); deferred.resolve(result);
} };
LedgerService.query({type:1}, successCb); LedgerService.query({type:1}, successCb);
return deferred.promise; return deferred.promise;
} }
} };
@@ -1,4 +1,6 @@
function TrialBalanceCtrl($scope, $routeParams, $location, trial_balance) { 'use strict';
function TrialBalanceCtrl($scope, $routeParams, $location, trial_balance) {
$scope.info = trial_balance; $scope.info = trial_balance;
$scope.show = function () { $scope.show = function () {
@@ -23,4 +25,4 @@ TrialBalanceCtrl.resolve = {
} }
return deferred.promise; return deferred.promise;
} }
} };
+4 -2
View File
@@ -1,4 +1,6 @@
function UnpostedCtrl($scope, info) { 'use strict';
function UnpostedCtrl($scope, info) {
$scope.info = info; $scope.info = info;
} }
UnpostedCtrl.resolve = { UnpostedCtrl.resolve = {
@@ -12,4 +14,4 @@ UnpostedCtrl.resolve = {
Unposted.query({}, successCb); Unposted.query({}, successCb);
return deferred.promise; return deferred.promise;
} }
} };
+5 -3
View File
@@ -1,4 +1,6 @@
function UserListCtrl($scope, users) { 'use strict';
function UserListCtrl($scope, users) {
$scope.info = users; $scope.info = users;
} }
@@ -13,7 +15,7 @@ UserListCtrl.resolve = {
User.query({}, successCb); User.query({}, successCb);
return deferred.promise; return deferred.promise;
} }
} };
function UserCtrl($scope, $location, user) { function UserCtrl($scope, $location, user) {
$scope.user = user; $scope.user = user;
@@ -51,4 +53,4 @@ UserCtrl.resolve = {
User.get({id:id}, successCb); User.get({id:id}, successCb);
return deferred.promise; return deferred.promise;
} }
} };
+2 -1
View File
@@ -37,6 +37,7 @@
<script src="/script/payment.js"> </script> <script src="/script/payment.js"> </script>
<script src="/script/receipt.js"> </script> <script src="/script/receipt.js"> </script>
<script src="/script/purchase.js"> </script> <script src="/script/purchase.js"> </script>
<script src="/script/purchase-return.js"> </script>
<script src="/script/issue.js"> </script> <script src="/script/issue.js"> </script>
<script src="/script/employee-attendance.js"> </script> <script src="/script/employee-attendance.js"> </script>
@@ -90,7 +91,7 @@
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a href="/Journal">Journal</a></li> <li><a href="/Journal">Journal</a></li>
<li><a href="/Purchase">Purchase</a></li> <li><a href="/Purchase">Purchase</a></li>
<li><a href="/PurchaseReturn">Purchase Return</a></li> <li><a href="/Return">Purchase Return</a></li>
<li><a href="/Payment">Payment</a></li> <li><a href="/Payment">Payment</a></li>
<li><a href="/Receipt">Receipt</a></li> <li><a href="/Receipt">Receipt</a></li>
<li><a href="/Issue">Issue</a></li> <li><a href="/Issue">Issue</a></li>
+13 -8
View File
@@ -22,8 +22,9 @@ def save_update(request):
try: try:
id = request.matchdict.get('id', None) id = request.matchdict.get('id', None)
if id is None: if id is None:
item = Ledger(0, request.json_body['Name'], int(request.json_body['Type']), request.json_body['IsActive'], item = Ledger(code=0, name=request.json_body['Name'], type=int(request.json_body['Type']),
uuid.UUID(request.json_body['CostCenter']['CostCenterID'])).create() is_active=request.json_body['IsActive'], is_reconcilble=request.json_body['IsReconcilable'],
costcenter_id=uuid.UUID(request.json_body['CostCenter']['CostCenterID'])).create()
else: else:
new_type = int(request.json_body['Type']) new_type = int(request.json_body['Type'])
item = Ledger.by_id(uuid.UUID(id)) item = Ledger.by_id(uuid.UUID(id))
@@ -32,6 +33,7 @@ def save_update(request):
item.type = new_type item.type = new_type
item.name = request.json_body['Name'] item.name = request.json_body['Name']
item.is_active = request.json_body['IsActive'] item.is_active = request.json_body['IsActive']
item.is_reconcilable = request.json_body['IsReconcilable']
item.costcenter_id = uuid.UUID(request.json_body['CostCenter']['CostCenterID']) item.costcenter_id = uuid.UUID(request.json_body['CostCenter']['CostCenterID'])
transaction.commit() transaction.commit()
return account_info(item.id) return account_info(item.id)
@@ -65,17 +67,20 @@ def show_blank(request):
return account_info(None) return account_info(None)
@view_config(request_method='GET', route_name='account', renderer='json', request_param='list', xhr=True, permission='Authenticated') @view_config(request_method='GET', route_name='account', renderer='json', request_param='list', xhr=True,
permission='Authenticated')
def show_list(request): def show_list(request):
list = Ledger.list() list = Ledger.list()
ledgers = [] ledgers = []
for item in list: for item in list:
ledgers.append({'Name': item.name, 'Type': item.type_object.name, 'IsActive': item.is_active, ledgers.append({'Name': item.name, 'Type': item.type_object.name, 'IsActive': 'Yes' if item.is_active else 'No',
'CostCenter': item.costcenter.name, 'Url': request.route_url('account_id', id=item.id)}) 'IsReconcilable': 'Yes' if item.is_reconcilable else '', 'CostCenter': item.costcenter.name,
'Url': request.route_url('account_id', id=item.id)})
return ledgers return ledgers
@view_config(request_method='GET', route_name='account_type_list', renderer='json', xhr=True, permission='Authenticated') @view_config(request_method='GET', route_name='account_type_list', renderer='json', xhr=True,
permission='Authenticated')
def account_type_list(request): def account_type_list(request):
account_types = [] account_types = []
for item in LedgerType.list(): for item in LedgerType.list():
@@ -86,11 +91,11 @@ def account_type_list(request):
def account_info(id): def account_info(id):
if id is None: if id is None:
account = {'Code': '(Auto)', 'Type': LedgerType.by_name('Creditors').id, 'IsActive': True, account = {'Code': '(Auto)', 'Type': LedgerType.by_name('Creditors').id, 'IsActive': True,
'CostCenter': CostCenter.overall()} 'IsReconcilable': False, 'CostCenter': CostCenter.overall()}
else: else:
account = Ledger.by_id(id) account = Ledger.by_id(id)
account = {'LedgerID': account.id, 'Code': account.code, 'Name': account.name, 'Type': account.type, account = {'LedgerID': account.id, 'Code': account.code, 'Name': account.name, 'Type': account.type,
'IsActive': account.is_active, 'IsActive': account.is_active, 'IsReconcilable':account.is_reconcilable,
'CostCenter': {'CostCenterID': account.costcenter_id, 'Name': account.costcenter.name}} 'CostCenter': {'CostCenterID': account.costcenter_id, 'Name': account.costcenter.name}}
return account return account
+58 -5
View File
@@ -1,12 +1,12 @@
from datetime import date, timedelta from datetime import date, timedelta
import uuid import uuid
from pyramid.httpexceptions import HTTPFound
from pyramid.response import Response from pyramid.response import Response
from pyramid.security import authenticated_userid, remember from pyramid.security import authenticated_userid, remember
from pyramid.view import view_config from pyramid.view import view_config
import transaction
from brewman import groupfinder from brewman import groupfinder
from brewman.models.auth import Role, User from brewman.models.auth import Role, User, Client
from brewman.views.transactions import session_current_date from brewman.views.transactions import session_current_date
@view_config(route_name='services_session_current_date', renderer='json', xhr=True, permission='Authenticated') @view_config(route_name='services_session_current_date', renderer='json', xhr=True, permission='Authenticated')
@@ -48,17 +48,70 @@ def user_permission(request):
@view_config(request_method='POST', route_name='login', renderer='json') @view_config(request_method='POST', route_name='login', renderer='json')
def login(request): def login(request):
username = request.json_body['username'] username = request.json_body.get('username', None)
password = request.json_body['password'] password = request.json_body.get('password', None)
found, user = User.auth(username, password) found, user = User.auth(username, password)
# client = request.cookies.get('ClientID', None)
# otp = request.json_body.get('otp', None)
# client_name = request.json_body.get('ClientName', None)
# allowed, response = check_client(client, otp, client_name, user if found else None)
# if found and allowed:
if found: if found:
headers = remember(request, str(user.id)) headers = remember(request, str(user.id))
request.response.headers = headers request.response.headers = headers
# if allowed and isinstance(response, Client):
# request.response.set_cookie('ClientID', value=str(response.code), max_age=10 * 365 * 24 * 60 * 60)
return request.response return request.response
else: elif not found:
response = Response("Login failed") response = Response("Login failed")
response.status_int = 500 response.status_int = 500
return response return response
# else:
# return response
def check_client(client, otp, client_name, user):
client = None if client is None else Client.by_code(client)
if len(Client.enabled_list()) == 0 and user is not None and 'Clients' in groupfinder(user.id, None):
client = Client.create()
client.otp = None
client.name = 'First'
client.enabled = True
transaction.commit()
return True, client
if client is None:
client = Client.create()
response = Response("Unknown Client")
response.status_int = 401
response.set_cookie('ClientID', value=str(client.code), max_age=10 * 365 * 24 * 60 * 60)
return False, response
if client.enabled:
return True, None
if client.otp is None:
response = Response("Client is Forbidden")
response.status_int = 401
return False, response
if otp is None:
response = Response("OTP not supplied")
response.status_int = 401
return False, response
elif client.otp != int(otp):
response = Response("OTP is wrong")
response.status_int = 401
return False, response
else:
client.otp = None
client.enabled = True
client.name = client_name
transaction.commit()
return True, None
def get_first_day(dt, d_years=0, d_months=0): def get_first_day(dt, d_years=0, d_months=0):
@@ -85,7 +85,8 @@ def delete(request):
item.product.name)) item.product.name))
item.batch.quantity_remaining -= item.quantity item.batch.quantity_remaining -= item.quantity
elif voucher.type == 'Purchase Return': elif voucher.type == 'Purchase Return':
pass for item in voucher.inventories:
item.batch.quantity_remaining += item.quantity
DBSession.delete(voucher) DBSession.delete(voucher)
transaction.commit() transaction.commit()
return blank_voucher(additionalInfo=json_voucher) return blank_voucher(additionalInfo=json_voucher)
@@ -142,6 +143,8 @@ def blank_voucher(type=None, date=None, additionalInfo=None):
json_voucher['Journals'].append({'Ledger': LedgerBase.cash_in_hand(), 'Amount': 0, 'Debit': 1}) json_voucher['Journals'].append({'Ledger': LedgerBase.cash_in_hand(), 'Amount': 0, 'Debit': 1})
elif type == 'Purchase': elif type == 'Purchase':
json_voucher['Journals'].append({'Ledger': LedgerBase.local_purchase(), 'Amount': 0, 'Debit': -1}) json_voucher['Journals'].append({'Ledger': LedgerBase.local_purchase(), 'Amount': 0, 'Debit': -1})
elif type == 'Purchase Return':
json_voucher['Journals'].append({'Ledger': LedgerBase.local_purchase(), 'Amount': 0, 'Debit': 1})
elif type == 'Issue': elif type == 'Issue':
if additionalInfo is None: if additionalInfo is None:
json_voucher['Journals'].append({'Ledger': {'LedgerID': LedgerBase.all_purchases()}, json_voucher['Journals'].append({'Ledger': {'LedgerID': LedgerBase.all_purchases()},
@@ -30,6 +30,11 @@ class blank_voucher_view(object):
return self.get_blank() return self.get_blank()
@view_config(request_param='type=Purchase Return', permission='Purchase Return')
def purchase_return(self):
return self.get_blank()
@view_config(request_param='type=Issue', permission='Issue') @view_config(request_param='type=Issue', permission='Issue')
def issue(self): def issue(self):
voucher_type = self.request.GET.get('type', None) voucher_type = self.request.GET.get('type', None)
@@ -123,7 +123,7 @@ def purchase_update_journals(voucher, journals):
journals = dict() journals = dict()
amount = 0 amount = 0
for item in voucher.inventories: for item in voucher.inventories:
ledger = Product.by_id(item.product_id).purchase_ledger ledger = Product.by_id(item.product_id).ledger
amount += item.amount amount += item.amount
if ledger.id in journals: if ledger.id in journals:
journals[ledger.id].amount += item.amount journals[ledger.id].amount += item.amount
@@ -142,7 +142,7 @@ def purchase_update_journals(voucher, journals):
else: else:
DBSession.delete(item) DBSession.delete(item)
voucher.journals.remove(item) voucher.journals.remove(item)
for item in journals: for item in journals.values():
DBSession.add(item) DBSession.add(item)
voucher.journals.append(item) voucher.journals.append(item)
@@ -0,0 +1,134 @@
import datetime
from decimal import Decimal
import uuid
from brewman.models import DBSession
from brewman.models.master import Product, LedgerBase
from brewman.models.operations import create_purchase_voucher, create_basic
from brewman.models.validation_exception import ValidationError
from brewman.models.voucher import Voucher, VoucherType, Batch, Inventory, Journal
__author__ = 'tanshu'
def purchase_return_create_voucher(json, user):
dt = datetime.datetime.strptime(json['Date'], '%d-%b-%Y')
voucher = Voucher(date=dt, narration=json['Narration'], user_id=user.id,
type=VoucherType.by_name(json['Type']), posted=False)
create_basic(voucher)
for item in json['Inventories']:
purchase_return_create_inventory(voucher, item)
for item in purchase_return_create_journals(voucher.inventories, json['Journals'][0]['Ledger']['LedgerID']):
DBSession.add(item)
voucher.journals.append(item)
create_purchase_voucher(voucher)
DBSession.flush()
return voucher
def purchase_return_create_inventory(voucher, item):
batch = Batch.by_id(uuid.UUID(item['Batch']['BatchID']))
inventory_id = uuid.UUID(item['InventoryID']) if 'InventoryID' in item else None
quantity = Decimal(item['Quantity'])
if quantity <= 0:
raise ValidationError("Quantity of {0} cannot be zero".format(item.product.name))
if quantity > batch.quantity_remaining:
raise ValidationError("Quantity available is {0} only".format(batch.quantity_remaining))
batch.quantity_remaining -= quantity
item = Inventory(id=inventory_id, product_id=batch.product.id, quantity=quantity, rate=batch.rate, tax=batch.tax,
discount=batch.discount, batch=batch)
DBSession.add(item)
voucher.inventories.append(item)
def purchase_return_create_journals(inventories, ledgerID):
otherLedger = LedgerBase.by_id(uuid.UUID(ledgerID))
journals = dict()
amount = 0
for item in inventories:
ledger = Product.by_id(item.product_id).ledger
amount += item.amount
if ledger.id in journals:
journals[ledger.id].amount += item.amount
else:
journals[ledger.id] = Journal(debit=-1, cost_center_id=ledger.costcenter_id, ledger_id=ledger.id,
amount=item.amount)
journals[otherLedger.id] = Journal(debit=1, cost_center_id=otherLedger.costcenter_id, ledger_id=otherLedger.id,
amount=amount)
return list(journals.values())
def purchase_return_update_voucher(voucher, json, user):
voucher.date = datetime.datetime.strptime(json['Date'], '%d-%b-%Y')
voucher.narration = json['Narration']
voucher.user_id = user.id
voucher.posted = False
voucher.last_edit_date = datetime.datetime.now()
purchase_return_update_inventory(voucher, json['Inventories'], json['Date'])
purchase_return_update_journals(voucher, json['Journals'])
return voucher
def purchase_return_update_inventory(voucher, newInventories, date):
for it in range(len(voucher.inventories), 0, -1):
item = voucher.inventories[it - 1]
found = False
for j in range(len(newInventories), 0, -1):
i = newInventories[j - 1]
if 'InventoryID' in i and item.id == uuid.UUID(i['InventoryID']):
product = Product.by_id(uuid.UUID(i['Product']['ProductID']))
found = True
if item.product_id != product.id:
raise ValidationError('Product cannot be changed')
quantity = Decimal(i['Quantity'])
if quantity == 0:
raise ValidationError("Quantity of {0} cannot be zero".format(item.product.name))
if quantity - item.quantity > item.batch.quantity_remaining:
raise ValidationError("Maximum quantity available is {0}".format(
item.quantity + item.batch.quantity_remaining))
item.batch.quantity_remaining -= (quantity - item.quantity)
item.quantity = quantity
newInventories.remove(i)
break
if not found:
item.batch.quantity_remaining += item.quantity
DBSession.delete(item)
voucher.inventories.remove(item)
for i in newInventories:
purchase_return_create_inventory(voucher, i)
def purchase_return_update_journals(voucher, journals):
otherLedger = [ff for ff in journals if ff['Debit'] == 1]
otherLedger = LedgerBase.by_id(uuid.UUID(otherLedger[0]['Ledger']['LedgerID']))
journals = dict()
amount = 0
for item in voucher.inventories:
ledger = Product.by_id(item.product_id).ledger
amount += item.amount
if ledger.id in journals:
journals[ledger.id].amount += item.amount
else:
journals[ledger.id] = Journal(debit=-1, cost_center_id=ledger.costcenter_id, ledger_id=ledger.id,
amount=item.amount)
journals[otherLedger.id] = Journal(debit=1, cost_center_id=otherLedger.costcenter_id, ledger_id=otherLedger.id,
amount=amount)
for i in range(len(voucher.journals), 0, -1):
item = voucher.journals[i - 1]
if item.ledger_id in journals:
item.debit = journals[item.ledger_id].debit
item.amount = journals[item.ledger_id].amount
item.cost_center_id = journals[item.ledger_id].cost_center_id
del journals[item.ledger_id]
else:
DBSession.delete(item)
voucher.journals.remove(item)
for item in journals.values():
DBSession.add(item)
voucher.journals.append(item)
@@ -7,6 +7,7 @@ from brewman.models.auth import User
from brewman.models.validation_exception import ValidationError from brewman.models.validation_exception import ValidationError
from brewman.models.voucher import Voucher from brewman.models.voucher import Voucher
from brewman.views.services.voucher import voucher_info, journal_create_voucher, purchase_create_voucher, issue_create_voucher from brewman.views.services.voucher import voucher_info, journal_create_voucher, purchase_create_voucher, issue_create_voucher
from brewman.views.services.voucher.purchase_return import purchase_return_create_voucher
__author__ = 'tanshu' __author__ = 'tanshu'
@@ -36,6 +37,11 @@ class save_voucher(object):
return self.save() return self.save()
@view_config(request_param='type=Purchase Return', permission='Purchase Return')
def purchase_return(self):
return self.save()
@view_config(request_param='type=Issue', permission='Issue') @view_config(request_param='type=Issue', permission='Issue')
def issue(self): def issue(self):
return self.save() return self.save()
@@ -49,6 +55,8 @@ class save_voucher(object):
voucher = journal_create_voucher(request.json_body, user) voucher = journal_create_voucher(request.json_body, user)
elif request.json_body['Type'] in ['Purchase']: elif request.json_body['Type'] in ['Purchase']:
voucher = purchase_create_voucher(request.json_body, user) voucher = purchase_create_voucher(request.json_body, user)
elif request.json_body['Type'] in ['Purchase Return']:
voucher = purchase_return_create_voucher(request.json_body, user)
elif request.json_body['Type'] in ['Issue']: elif request.json_body['Type'] in ['Issue']:
voucher = issue_create_voucher(request.json_body, user) voucher = issue_create_voucher(request.json_body, user)
transaction.commit() transaction.commit()
@@ -8,6 +8,7 @@ from brewman.models.auth import User
from brewman.models.validation_exception import ValidationError from brewman.models.validation_exception import ValidationError
from brewman.models.voucher import Voucher from brewman.models.voucher import Voucher
from brewman.views.services.voucher import voucher_info, issue_update_voucher, purchase_update_voucher, journal_update_voucher from brewman.views.services.voucher import voucher_info, issue_update_voucher, purchase_update_voucher, journal_update_voucher
from brewman.views.services.voucher.purchase_return import purchase_return_update_voucher
__author__ = 'tanshu' __author__ = 'tanshu'
@@ -53,6 +54,11 @@ class update_voucher(object):
return self.update() return self.update()
@view_config(request_param='type=Purchase Return', permission='Purchase Return')
def purchase_return(self):
return self.update()
@view_config(request_param='type=Issue', permission='Issue') @view_config(request_param='type=Issue', permission='Issue')
def issue(self): def issue(self):
return self.update() return self.update()
@@ -65,6 +71,8 @@ class update_voucher(object):
voucher = journal_update_voucher(self.voucher, self.json, self.user) voucher = journal_update_voucher(self.voucher, self.json, self.user)
elif self.json['Type'] in ['Purchase']: elif self.json['Type'] in ['Purchase']:
voucher = purchase_update_voucher(self.voucher, self.json, self.user) voucher = purchase_update_voucher(self.voucher, self.json, self.user)
elif self.json['Type'] in ['Purchase Return']:
voucher = purchase_return_update_voucher(self.voucher, self.json, self.user)
elif self.json['Type'] in ['Issue']: elif self.json['Type'] in ['Issue']:
voucher = issue_update_voucher(self.voucher, self.json, self.user) voucher = issue_update_voucher(self.voucher, self.json, self.user)
transaction.commit() transaction.commit()
@@ -1,6 +1,7 @@
from datetime import date from datetime import date
from pyramid.view import view_config from pyramid.view import view_config
__author__ = 'tanshu'
@view_config(request_method='GET', route_name='journal_id', renderer='brewman:templates/angular_base.mako', @view_config(request_method='GET', route_name='journal_id', renderer='brewman:templates/angular_base.mako',
permission='Journal') permission='Journal')
@@ -18,6 +19,10 @@ from pyramid.view import view_config
permission='Purchase') permission='Purchase')
@view_config(request_method='GET', route_name='purchase', renderer='brewman:templates/angular_base.mako', @view_config(request_method='GET', route_name='purchase', renderer='brewman:templates/angular_base.mako',
permission='Purchase') permission='Purchase')
@view_config(request_method='GET', route_name='purchase_return_id', renderer='brewman:templates/angular_base.mako',
permission='Purchase Return')
@view_config(request_method='GET', route_name='purchase_return', renderer='brewman:templates/angular_base.mako',
permission='Purchase Return')
@view_config(request_method='GET', route_name='issue_id', renderer='brewman:templates/angular_base.mako', @view_config(request_method='GET', route_name='issue_id', renderer='brewman:templates/angular_base.mako',
permission='Issue') permission='Issue')
@view_config(request_method='GET', route_name='issue', renderer='brewman:templates/angular_base.mako', @view_config(request_method='GET', route_name='issue', renderer='brewman:templates/angular_base.mako',
@@ -1,226 +0,0 @@
import datetime
import transaction
import uuid
from decimal import Decimal
from pyramid.response import Response
from pyramid.security import authenticated_userid
from pyramid.view import view_config
from brewman.models import DBSession
from brewman.models.auth import User
from brewman.models.master import Product, Ledger
from brewman.models.validation_exception import ValidationError
from brewman.models.voucher import Voucher, Journal, VoucherType, Inventory, Batch
@view_config(request_method='GET', route_name='purchase_return_id', renderer='brewman:templates/transaction/purchase_return.mako',
permission='Purchase Return Update')
@view_config(request_method='GET', route_name='purchase_return', renderer='brewman:templates/transaction/purchase_return.mako',
permission='Purchase Return Create')
def purchase_get(request):
id = request.matchdict.get('id', None)
if id is None:
currentDate = Literal(
"CurrentDate('#txtDate', '{0}');".format(request.route_url('services_session_current_date')))
voucher_id = ''
posted = ''
code = ''
narration = ''
body = ''
ledger = ''
else:
voucher = Voucher.by_id(uuid.UUID(id))
currentDate = Literal("$('#txtDate').val('{0}');".format(voucher.date.strftime('%d-%b-%Y')))
voucher_id = Literal("$('#VoucherID').val('{0}');".format(voucher.id))
posted = Literal("$('#Posted').val(true);") if voucher.posted else ''
code = Literal("$('#txtCode').val('{0}');".format(voucher.code))
narration = Literal("$('#txtNarration').val('{0}');".format(voucher.narration))
body = Literal(build_body(voucher))
for item in voucher.journals:
if item.debit == 1:
journal = item
break
ledger = Literal("$('#txtLedger').val('{0}');".format(journal.ledger.name))
return {'title': 'Purchase - Hops n Grains',
'pageclass': "page-blogpost page-sidebar-right",
'pagecontentclass': "page-content grid_12",
'page_header': '',
'id': id,
'currentDate': currentDate,
'voucher_id': voucher_id,
'posted': posted,
'code': code,
'narration': narration,
'body': body,
'ledger': ledger}
@view_config(request_method='POST', route_name='purchase_return_id', renderer='json', xhr=True, permission='Purchase Return Update')
@view_config(request_method='POST', route_name='purchase_return', renderer='json', xhr=True, permission='Purchase Return Create')
def purchase_post(request):
try:
id = request.matchdict.get('id', None)
user = User.get_by_id(uuid.UUID(authenticated_userid(request)))
if id == None:
voucher = create_voucher(request.json_body['voucher'], user)
else:
voucher = update_voucher(uuid.UUID(id), request.json_body['voucher'], user)
transaction.commit()
return "Voucher with Code {0} {1}".format(voucher.code, ('Created' if id is None else 'Updated' ))
except ValidationError as ex:
transaction.abort()
response = Response("Failed validation: {0}".format(ex.message))
response.status_int = 500
return response
def build_body(voucher):
body = ''
for item in voucher.inventories:
body += '<tr class="Inventory" id="{0}"><td class="InventoryID hide">{1}</td>'\
'<td class="ProductID hide">{0}</td><td class="Product">{2}</td><td class="Quantity">{3:.5f}</td>'\
'<td class="Rate">{4:.5f}</td><td class="Tax">{5:.5f}</td><td class="Discount">{6:.5f}</td>'\
'<td class="Amount">{7:.5f}</td><td class="BatchID hide">{8}</td><td class="Delete">'\
'<input type="submit" class="subtract" onClick="return DeleteRow(\'{0}\');" value="Delete"/></td></tr>'\
.format(str(item.product_id), str(item.id), item.product.full_name, item.quantity, item. rate, item.tax,
item.discount, item.amount, str(item.batch_id))
return body
def create_voucher(json, user):
dt = datetime.datetime.strptime(json['Date'], '%d-%b-%Y')
voucher = Voucher(date=dt, narration=json['Narration'], user_id=user.id,
type=VoucherType.by_name('Purchase Return'), posted=False)
for item in json['Inventories']:
voucher.inventories.append(create_inventory(item, json['Date']))
for item in create_journals(voucher.inventories, json['Journals'][0]['Ledger']['Name']):
voucher.journals.append(item)
voucher.create()
return voucher
def create_inventory(item, date):
product = Product.by_id(uuid.UUID(item['Product']['ProductID']))
inventory_id = uuid.UUID(item['InventoryID'])
if uuid.UUID('00000000-0000-0000-0000-000000000000') == inventory_id:
inventory_id = None
quantity = Decimal(item['Quantity'])
rate = Decimal(item['Rate'])
tax = Decimal(item['Tax'])
discount = Decimal(item['Discount'])
batch = Batch(name=date, product_id=product.id, quantity_remaining=quantity, rate=rate, tax=tax,
discount=discount)
return Inventory(id=inventory_id, product_id=product.id, batch=batch, quantity=quantity, rate=rate, tax=tax,
discount=discount)
def create_journals(inventories, ledgerString):
otherLedger = Ledger.by_name(ledgerString)
journals = dict()
amount = 0
for item in inventories:
ledger = Product.by_id(item.product_id).purchase_ledger
amount += item.amount
if ledger.id in journals:
journals[ledger.id].amount += item.amount
else:
journals[ledger.id] = Journal(debit=1, cost_center_id=ledger.costcenter_id, ledger_id=ledger.id,
amount=item.amount)
journals[otherLedger.id] = Journal(debit=-1, cost_center_id=otherLedger.costcenter_id, ledger_id=otherLedger.id,
amount=amount)
return list(journals.values())
def update_voucher(id, json, user):
voucher = Voucher.by_id(id)
voucher.date = datetime.datetime.strptime(json['Date'], '%d-%b-%Y')
voucher.narration = json['Narration']
voucher.user_id = user.id
voucher.posted = False
voucher.last_edit_date = datetime.datetime.now()
update_inventory(voucher, json['Inventories'], json['Date'])
update_journals(voucher, json['Journals'][0]['Ledger']['Name'])
return voucher
def update_inventory(voucher, newInventories, date):
for item in voucher.inventories:
found = False
for i in newInventories:
if item.id == uuid.UUID(i['InventoryID']):
product = Product.by_id(uuid.UUID(i['Product']['ProductID']))
found = True
if item.product_id != product.id:
raise ValidationError('Product cannot be changed')
quantity = Decimal(i['Quantity'])
if quantity == 0:
raise ValidationError("Quantity of {0} cannot be zero".format(item.product.name))
if item.quantity - quantity > 0 and item.batch.quantity_remaining < (item.quantity - quantity):
raise ValidationError("{0} has been issued, minimum quantity is".format(
item.quantity - item.batch.quantity_remaining))
item.batch.quantity_remaining -= (item.quantity - quantity)
item.quantity = quantity
rate = Decimal(i['Rate'])
discount = Decimal(i['Discount'])
tax = Decimal(i['Tax'])
item.rate = rate
item.batch.rate = rate
item.discount = discount
item.batch.discount = discount
item.tax = tax
item.batch.tax = tax
newInventories.remove(i)
break
if not found:
if item.quantity != item.batch.quantity_remaining:
raise ValidationError("{0} has been issued, it cannot be deleted".format(item.product.name))
else:
DBSession.delete(item.batch)
DBSession.delete(item)
voucher.inventories.remove(item)
for i in newInventories:
product = Product.by_id(uuid.UUID(i['Product']['ProductID']))
quantity = Decimal(i['Quantity'])
rate = Decimal(i['Rate'])
tax = Decimal(i['Tax'])
discount = Decimal(i['Discount'])
batch = Batch(name=date, product_id=product.id, quantity_remaining=quantity, rate=rate, tax=tax,
discount=discount)
inventory = Inventory(id=None, product_id=product.id, batch=batch, quantity=quantity, rate=rate, tax=tax,
discount=discount)
inventory.create(DBSession)
voucher.inventories.append(inventory)
def update_journals(voucher, ledgerString):
otherLedger = Ledger.by_name(ledgerString)
journals = dict()
amount = 0
for item in voucher.inventories:
ledger = Product.by_id(item.product_id).purchase_ledger
amount += item.amount
if ledger.id in journals:
journals[ledger.id].amount += item.amount
else:
journals[ledger.id] = Journal(debit=1, cost_center_id=ledger.costcenter_id, ledger_id=ledger.id,
amount=item.amount)
journals[otherLedger.id] = Journal(debit=-1, cost_center_id=otherLedger.costcenter_id, ledger_id=otherLedger.id,
amount=amount)
for item in voucher.journals:
if item.ledger_id in journals:
item.debit = journals[item.ledger_id].debit
item.amount = journals[item.ledger_id].amount
item.cost_center_id = journals[item.ledger_id].cost_center_id
del journals[item.ledger_id]
else:
DBSession.delete(item)
voucher.journals.remove(item)
for item in journals:
DBSession.add(item)
voucher.journals.append(item)