Merge pull request #19606 from deepeshgarg007/shareholder_refactor

refactor: Share Transfer code cleanup and refactor
This commit is contained in:
Deepesh Garg 2019-11-26 07:54:57 +05:30 committed by GitHub
commit 31a4fa5dd3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 338 additions and 770 deletions

View File

@ -13,9 +13,9 @@ from frappe.utils import nowdate
class ShareDontExists(ValidationError): pass class ShareDontExists(ValidationError): pass
class ShareTransfer(Document): class ShareTransfer(Document):
def before_submit(self): def on_submit(self):
if self.transfer_type == 'Issue': if self.transfer_type == 'Issue':
shareholder = self.get_shareholder_doc(self.company) shareholder = self.get_company_shareholder()
shareholder.append('share_balance', { shareholder.append('share_balance', {
'share_type': self.share_type, 'share_type': self.share_type,
'from_no': self.from_no, 'from_no': self.from_no,
@ -28,7 +28,7 @@ class ShareTransfer(Document):
}) })
shareholder.save() shareholder.save()
doc = frappe.get_doc('Shareholder', self.to_shareholder) doc = self.get_shareholder_doc(self.to_shareholder)
doc.append('share_balance', { doc.append('share_balance', {
'share_type': self.share_type, 'share_type': self.share_type,
'from_no': self.from_no, 'from_no': self.from_no,
@ -41,11 +41,11 @@ class ShareTransfer(Document):
elif self.transfer_type == 'Purchase': elif self.transfer_type == 'Purchase':
self.remove_shares(self.from_shareholder) self.remove_shares(self.from_shareholder)
self.remove_shares(self.get_shareholder_doc(self.company).name) self.remove_shares(self.get_company_shareholder().name)
elif self.transfer_type == 'Transfer': elif self.transfer_type == 'Transfer':
self.remove_shares(self.from_shareholder) self.remove_shares(self.from_shareholder)
doc = frappe.get_doc('Shareholder', self.to_shareholder) doc = self.get_shareholder_doc(self.to_shareholder)
doc.append('share_balance', { doc.append('share_balance', {
'share_type': self.share_type, 'share_type': self.share_type,
'from_no': self.from_no, 'from_no': self.from_no,
@ -56,143 +56,127 @@ class ShareTransfer(Document):
}) })
doc.save() doc.save()
def on_cancel(self):
if self.transfer_type == 'Issue':
compnay_shareholder = self.get_company_shareholder()
self.remove_shares(compnay_shareholder.name)
self.remove_shares(self.to_shareholder)
elif self.transfer_type == 'Purchase':
compnay_shareholder = self.get_company_shareholder()
from_shareholder = self.get_shareholder_doc(self.from_shareholder)
from_shareholder.append('share_balance', {
'share_type': self.share_type,
'from_no': self.from_no,
'to_no': self.to_no,
'rate': self.rate,
'amount': self.amount,
'no_of_shares': self.no_of_shares
})
from_shareholder.save()
compnay_shareholder.append('share_balance', {
'share_type': self.share_type,
'from_no': self.from_no,
'to_no': self.to_no,
'rate': self.rate,
'amount': self.amount,
'no_of_shares': self.no_of_shares
})
compnay_shareholder.save()
elif self.transfer_type == 'Transfer':
self.remove_shares(self.to_shareholder)
from_shareholder = self.get_shareholder_doc(self.from_shareholder)
from_shareholder.append('share_balance', {
'share_type': self.share_type,
'from_no': self.from_no,
'to_no': self.to_no,
'rate': self.rate,
'amount': self.amount,
'no_of_shares': self.no_of_shares
})
from_shareholder.save()
def validate(self): def validate(self):
self.get_company_shareholder()
self.basic_validations() self.basic_validations()
self.folio_no_validation() self.folio_no_validation()
if self.transfer_type == 'Issue': if self.transfer_type == 'Issue':
if not self.get_shareholder_doc(self.company): # validate share doesn't exist in company
shareholder = frappe.get_doc({ ret_val = self.share_exists(self.get_company_shareholder().name)
'doctype': 'Shareholder', if ret_val in ('Complete', 'Partial'):
'title': self.company,
'company': self.company,
'is_company': 1
})
shareholder.insert()
# validate share doesnt exist in company
ret_val = self.share_exists(self.get_shareholder_doc(self.company).name)
if ret_val != False:
frappe.throw(_('The shares already exist'), frappe.DuplicateEntryError) frappe.throw(_('The shares already exist'), frappe.DuplicateEntryError)
else: else:
# validate share exists with from_shareholder # validate share exists with from_shareholder
ret_val = self.share_exists(self.from_shareholder) ret_val = self.share_exists(self.from_shareholder)
if ret_val != True: if ret_val in ('Outside', 'Partial'):
frappe.throw(_("The shares don't exist with the {0}") frappe.throw(_("The shares don't exist with the {0}")
.format(self.from_shareholder), ShareDontExists) .format(self.from_shareholder), ShareDontExists)
def basic_validations(self): def basic_validations(self):
if self.transfer_type == 'Purchase': if self.transfer_type == 'Purchase':
self.to_shareholder = '' self.to_shareholder = ''
if self.from_shareholder is None or self.from_shareholder is '': if not self.from_shareholder:
frappe.throw(_('The field From Shareholder cannot be blank')) frappe.throw(_('The field From Shareholder cannot be blank'))
if self.from_folio_no is None or self.from_folio_no is '': if not self.from_folio_no:
self.to_folio_no = self.autoname_folio(self.to_shareholder) self.to_folio_no = self.autoname_folio(self.to_shareholder)
if self.asset_account is None: if not self.asset_account:
frappe.throw(_('The field Asset Account cannot be blank')) frappe.throw(_('The field Asset Account cannot be blank'))
elif (self.transfer_type == 'Issue'): elif (self.transfer_type == 'Issue'):
self.from_shareholder = '' self.from_shareholder = ''
if self.to_shareholder is None or self.to_shareholder == '': if not self.to_shareholder:
frappe.throw(_('The field To Shareholder cannot be blank')) frappe.throw(_('The field To Shareholder cannot be blank'))
if self.to_folio_no is None or self.to_folio_no is '': if not self.to_folio_no:
self.to_folio_no = self.autoname_folio(self.to_shareholder) self.to_folio_no = self.autoname_folio(self.to_shareholder)
if self.asset_account is None: if not self.asset_account:
frappe.throw(_('The field Asset Account cannot be blank')) frappe.throw(_('The field Asset Account cannot be blank'))
else: else:
if self.from_shareholder is None or self.to_shareholder is None: if not self.from_shareholder or not self.to_shareholder:
frappe.throw(_('The fields From Shareholder and To Shareholder cannot be blank')) frappe.throw(_('The fields From Shareholder and To Shareholder cannot be blank'))
if self.to_folio_no is None or self.to_folio_no is '': if not self.to_folio_no:
self.to_folio_no = self.autoname_folio(self.to_shareholder) self.to_folio_no = self.autoname_folio(self.to_shareholder)
if self.equity_or_liability_account is None: if not self.equity_or_liability_account:
frappe.throw(_('The field Equity/Liability Account cannot be blank')) frappe.throw(_('The field Equity/Liability Account cannot be blank'))
if self.from_shareholder == self.to_shareholder: if self.from_shareholder == self.to_shareholder:
frappe.throw(_('The seller and the buyer cannot be the same')) frappe.throw(_('The seller and the buyer cannot be the same'))
if self.no_of_shares != self.to_no - self.from_no + 1: if self.no_of_shares != self.to_no - self.from_no + 1:
frappe.throw(_('The number of shares and the share numbers are inconsistent')) frappe.throw(_('The number of shares and the share numbers are inconsistent'))
if self.amount is None: if not self.amount:
self.amount = self.rate * self.no_of_shares self.amount = self.rate * self.no_of_shares
if self.amount != self.rate * self.no_of_shares: if self.amount != self.rate * self.no_of_shares:
frappe.throw(_('There are inconsistencies between the rate, no of shares and the amount calculated')) frappe.throw(_('There are inconsistencies between the rate, no of shares and the amount calculated'))
def share_exists(self, shareholder): def share_exists(self, shareholder):
# return True if exits, doc = self.get_shareholder_doc(shareholder)
# False if completely doesn't exist,
# 'partially exists' if partailly doesn't exist
ret_val = self.recursive_share_check(shareholder, self.share_type,
query = {
'from_no': self.from_no,
'to_no': self.to_no
}
)
if all(boolean == True for boolean in ret_val):
return True
elif True in ret_val:
return 'partially exists'
else:
return False
def recursive_share_check(self, shareholder, share_type, query):
# query = {'from_no': share_starting_no, 'to_no': share_ending_no}
# Recursive check if a given part of shares is held by the shareholder
# return a list containing True and False
# Eg. [True, False, True]
# All True implies its completely inside
# All False implies its completely outside
# A mix implies its partially inside/outside
does_share_exist = []
doc = frappe.get_doc('Shareholder', shareholder)
for entry in doc.share_balance: for entry in doc.share_balance:
if entry.share_type != share_type or \ if entry.share_type != self.share_type or \
entry.from_no > query['to_no'] or \ entry.from_no > self.to_no or \
entry.to_no < query['from_no']: entry.to_no < self.from_no:
continue # since query lies outside bounds continue # since query lies outside bounds
elif entry.from_no <= query['from_no'] and entry.to_no >= query['to_no']: elif entry.from_no <= self.from_no and entry.to_no >= self.to_no: #both inside
return [True] # absolute truth! return 'Complete' # absolute truth!
elif entry.from_no >= query['from_no'] and entry.to_no <= query['to_no']: elif entry.from_no <= self.from_no <= self.to_no:
# split and check return 'Partial'
does_share_exist.extend(self.recursive_share_check(shareholder, elif entry.from_no <= self.to_no <= entry.to_no:
share_type, return 'Partial'
{
'from_no': query['from_no'],
'to_no': entry.from_no - 1
}
))
does_share_exist.append(True)
does_share_exist.extend(self.recursive_share_check(shareholder,
share_type,
{
'from_no': entry.to_no + 1,
'to_no': query['to_no']
}
))
elif query['from_no'] <= entry.from_no <= query['to_no'] and entry.to_no >= query['to_no']:
does_share_exist.extend(self.recursive_share_check(shareholder,
share_type,
{
'from_no': query['from_no'],
'to_no': entry.from_no - 1
}
))
elif query['from_no'] <= entry.to_no <= query['to_no'] and entry.from_no <= query['from_no']:
does_share_exist.extend(self.recursive_share_check(shareholder,
share_type,
{
'from_no': entry.to_no + 1,
'to_no': query['to_no']
}
))
does_share_exist.append(False) return 'Outside'
return does_share_exist
def folio_no_validation(self): def folio_no_validation(self):
shareholders = ['from_shareholder', 'to_shareholder'] shareholders = ['from_shareholder', 'to_shareholder']
shareholders = [shareholder for shareholder in shareholders if self.get(shareholder) is not ''] shareholders = [shareholder for shareholder in shareholders if self.get(shareholder) is not '']
for shareholder in shareholders: for shareholder in shareholders:
doc = frappe.get_doc('Shareholder', self.get(shareholder)) doc = self.get_shareholder_doc(self.get(shareholder))
if doc.company != self.company: if doc.company != self.company:
frappe.throw(_('The shareholder does not belong to this company')) frappe.throw(_('The shareholder does not belong to this company'))
if doc.folio_no is '' or doc.folio_no is None: if not doc.folio_no:
doc.folio_no = self.from_folio_no \ doc.folio_no = self.from_folio_no \
if (shareholder == 'from_shareholder') else self.to_folio_no; if (shareholder == 'from_shareholder') else self.to_folio_no
doc.save() doc.save()
else: else:
if doc.folio_no and doc.folio_no != (self.from_folio_no if (shareholder == 'from_shareholder') else self.to_folio_no): if doc.folio_no and doc.folio_no != (self.from_folio_no if (shareholder == 'from_shareholder') else self.to_folio_no):
@ -200,24 +184,14 @@ class ShareTransfer(Document):
def autoname_folio(self, shareholder, is_company=False): def autoname_folio(self, shareholder, is_company=False):
if is_company: if is_company:
doc = self.get_shareholder_doc(shareholder) doc = self.get_company_shareholder()
else: else:
doc = frappe.get_doc('Shareholder' , shareholder) doc = self.get_shareholder_doc(shareholder)
doc.folio_no = make_autoname('FN.#####') doc.folio_no = make_autoname('FN.#####')
doc.save() doc.save()
return doc.folio_no return doc.folio_no
def remove_shares(self, shareholder): def remove_shares(self, shareholder):
self.iterative_share_removal(shareholder, self.share_type,
{
'from_no': self.from_no,
'to_no' : self.to_no
},
rate = self.rate,
amount = self.amount
)
def iterative_share_removal(self, shareholder, share_type, query, rate, amount):
# query = {'from_no': share_starting_no, 'to_no': share_ending_no} # query = {'from_no': share_starting_no, 'to_no': share_ending_no}
# Shares exist for sure # Shares exist for sure
# Iterate over all entries and modify entry if in entry # Iterate over all entries and modify entry if in entry
@ -227,31 +201,31 @@ class ShareTransfer(Document):
for entry in current_entries: for entry in current_entries:
# use spaceage logic here # use spaceage logic here
if entry.share_type != share_type or \ if entry.share_type != self.share_type or \
entry.from_no > query['to_no'] or \ entry.from_no > self.to_no or \
entry.to_no < query['from_no']: entry.to_no < self.from_no:
new_entries.append(entry) new_entries.append(entry)
continue # since query lies outside bounds continue # since query lies outside bounds
elif entry.from_no <= query['from_no'] and entry.to_no >= query['to_no']: elif entry.from_no <= self.from_no and entry.to_no >= self.to_no:
#split #split
if entry.from_no == query['from_no']: if entry.from_no == self.from_no:
if entry.to_no == query['to_no']: if entry.to_no == self.to_no:
pass #nothing to append pass #nothing to append
else: else:
new_entries.append(self.return_share_balance_entry(query['to_no']+1, entry.to_no, entry.rate)) new_entries.append(self.return_share_balance_entry(self.to_no+1, entry.to_no, entry.rate))
else: else:
if entry.to_no == query['to_no']: if entry.to_no == self.to_no:
new_entries.append(self.return_share_balance_entry(entry.from_no, query['from_no']-1, entry.rate)) new_entries.append(self.return_share_balance_entry(entry.from_no, self.from_no-1, entry.rate))
else: else:
new_entries.append(self.return_share_balance_entry(entry.from_no, query['from_no']-1, entry.rate)) new_entries.append(self.return_share_balance_entry(entry.from_no, self.from_no-1, entry.rate))
new_entries.append(self.return_share_balance_entry(query['to_no']+1, entry.to_no, entry.rate)) new_entries.append(self.return_share_balance_entry(self.to_no+1, entry.to_no, entry.rate))
elif entry.from_no >= query['from_no'] and entry.to_no <= query['to_no']: elif entry.from_no >= self.from_no and entry.to_no <= self.to_no:
# split and check # split and check
pass #nothing to append pass #nothing to append
elif query['from_no'] <= entry.from_no <= query['to_no'] and entry.to_no >= query['to_no']: elif self.from_no <= entry.from_no <= self.to_no and entry.to_no >= self.to_no:
new_entries.append(self.return_share_balance_entry(query['to_no']+1, entry.to_no, entry.rate)) new_entries.append(self.return_share_balance_entry(self.to_no+1, entry.to_no, entry.rate))
elif query['from_no'] <= entry.to_no <= query['to_no'] and entry.from_no <= query['from_no']: elif self.from_no <= entry.to_no <= self.to_no and entry.from_no <= self.from_no:
new_entries.append(self.return_share_balance_entry(entry.from_no, query['from_no']-1, entry.rate)) new_entries.append(self.return_share_balance_entry(entry.from_no, self.from_no-1, entry.rate))
else: else:
new_entries.append(entry) new_entries.append(entry)
@ -272,16 +246,34 @@ class ShareTransfer(Document):
} }
def get_shareholder_doc(self, shareholder): def get_shareholder_doc(self, shareholder):
# Get Shareholder doc based on the Shareholder title # Get Shareholder doc based on the Shareholder name
doc = frappe.get_list('Shareholder', if shareholder:
filters = [ query_filters = {'name': shareholder}
('Shareholder', 'title', '=', shareholder)
] name = frappe.db.get_value('Shareholder', {'name': shareholder}, 'name')
)
if len(doc) == 1: return frappe.get_doc('Shareholder', name)
return frappe.get_doc('Shareholder', doc[0]['name'])
else: #It will necessarily by 0 indicating it doesn't exist def get_company_shareholder(self):
return False # Get company doc or create one if not present
company_shareholder = frappe.db.get_value('Shareholder',
{
'company': self.company,
'is_company': 1
}, 'name')
if company_shareholder:
return frappe.get_doc('Shareholder', company_shareholder)
else:
shareholder = frappe.get_doc({
'doctype': 'Shareholder',
'title': self.company,
'company': self.company,
'is_company': 1
})
shareholder.insert()
return shareholder
@frappe.whitelist() @frappe.whitelist()
def make_jv_entry( company, account, amount, payment_account,\ def make_jv_entry( company, account, amount, payment_account,\

View File

@ -15,73 +15,73 @@ class TestShareTransfer(unittest.TestCase):
frappe.db.sql("delete from `tabShare Balance`") frappe.db.sql("delete from `tabShare Balance`")
share_transfers = [ share_transfers = [
{ {
"doctype" : "Share Transfer", "doctype": "Share Transfer",
"transfer_type" : "Issue", "transfer_type": "Issue",
"date" : "2018-01-01", "date": "2018-01-01",
"to_shareholder" : "SH-00001", "to_shareholder": "SH-00001",
"share_type" : "Equity", "share_type": "Equity",
"from_no" : 1, "from_no": 1,
"to_no" : 500, "to_no": 500,
"no_of_shares" : 500, "no_of_shares": 500,
"rate" : 10, "rate": 10,
"company" : "_Test Company", "company": "_Test Company",
"asset_account" : "Cash - _TC", "asset_account": "Cash - _TC",
"equity_or_liability_account": "Creditors - _TC" "equity_or_liability_account": "Creditors - _TC"
}, },
{ {
"doctype" : "Share Transfer", "doctype": "Share Transfer",
"transfer_type" : "Transfer", "transfer_type": "Transfer",
"date" : "2018-01-02", "date": "2018-01-02",
"from_shareholder" : "SH-00001", "from_shareholder": "SH-00001",
"to_shareholder" : "SH-00002", "to_shareholder": "SH-00002",
"share_type" : "Equity", "share_type": "Equity",
"from_no" : 101, "from_no": 101,
"to_no" : 200, "to_no": 200,
"no_of_shares" : 100, "no_of_shares": 100,
"rate" : 15, "rate": 15,
"company" : "_Test Company", "company": "_Test Company",
"equity_or_liability_account": "Creditors - _TC" "equity_or_liability_account": "Creditors - _TC"
}, },
{ {
"doctype" : "Share Transfer", "doctype": "Share Transfer",
"transfer_type" : "Transfer", "transfer_type": "Transfer",
"date" : "2018-01-03", "date": "2018-01-03",
"from_shareholder" : "SH-00001", "from_shareholder": "SH-00001",
"to_shareholder" : "SH-00003", "to_shareholder": "SH-00003",
"share_type" : "Equity", "share_type": "Equity",
"from_no" : 201, "from_no": 201,
"to_no" : 500, "to_no": 500,
"no_of_shares" : 300, "no_of_shares": 300,
"rate" : 20, "rate": 20,
"company" : "_Test Company", "company": "_Test Company",
"equity_or_liability_account": "Creditors - _TC" "equity_or_liability_account": "Creditors - _TC"
}, },
{ {
"doctype" : "Share Transfer", "doctype": "Share Transfer",
"transfer_type" : "Transfer", "transfer_type": "Transfer",
"date" : "2018-01-04", "date": "2018-01-04",
"from_shareholder" : "SH-00003", "from_shareholder": "SH-00003",
"to_shareholder" : "SH-00002", "to_shareholder": "SH-00002",
"share_type" : "Equity", "share_type": "Equity",
"from_no" : 201, "from_no": 201,
"to_no" : 400, "to_no": 400,
"no_of_shares" : 200, "no_of_shares": 200,
"rate" : 15, "rate": 15,
"company" : "_Test Company", "company": "_Test Company",
"equity_or_liability_account": "Creditors - _TC" "equity_or_liability_account": "Creditors - _TC"
}, },
{ {
"doctype" : "Share Transfer", "doctype": "Share Transfer",
"transfer_type" : "Purchase", "transfer_type": "Purchase",
"date" : "2018-01-05", "date": "2018-01-05",
"from_shareholder" : "SH-00003", "from_shareholder": "SH-00003",
"share_type" : "Equity", "share_type": "Equity",
"from_no" : 401, "from_no": 401,
"to_no" : 500, "to_no": 500,
"no_of_shares" : 100, "no_of_shares": 100,
"rate" : 25, "rate": 25,
"company" : "_Test Company", "company": "_Test Company",
"asset_account" : "Cash - _TC", "asset_account": "Cash - _TC",
"equity_or_liability_account": "Creditors - _TC" "equity_or_liability_account": "Creditors - _TC"
} }
] ]
@ -91,33 +91,33 @@ class TestShareTransfer(unittest.TestCase):
def test_invalid_share_transfer(self): def test_invalid_share_transfer(self):
doc = frappe.get_doc({ doc = frappe.get_doc({
"doctype" : "Share Transfer", "doctype": "Share Transfer",
"transfer_type" : "Transfer", "transfer_type": "Transfer",
"date" : "2018-01-05", "date": "2018-01-05",
"from_shareholder" : "SH-00003", "from_shareholder": "SH-00003",
"to_shareholder" : "SH-00002", "to_shareholder": "SH-00002",
"share_type" : "Equity", "share_type": "Equity",
"from_no" : 1, "from_no": 1,
"to_no" : 100, "to_no": 100,
"no_of_shares" : 100, "no_of_shares": 100,
"rate" : 15, "rate": 15,
"company" : "_Test Company", "company": "_Test Company",
"equity_or_liability_account": "Creditors - _TC" "equity_or_liability_account": "Creditors - _TC"
}) })
self.assertRaises(ShareDontExists, doc.insert) self.assertRaises(ShareDontExists, doc.insert)
doc = frappe.get_doc({ doc = frappe.get_doc({
"doctype" : "Share Transfer", "doctype": "Share Transfer",
"transfer_type" : "Purchase", "transfer_type": "Purchase",
"date" : "2018-01-02", "date": "2018-01-02",
"from_shareholder" : "SH-00001", "from_shareholder": "SH-00001",
"share_type" : "Equity", "share_type": "Equity",
"from_no" : 1, "from_no": 1,
"to_no" : 200, "to_no": 200,
"no_of_shares" : 200, "no_of_shares": 200,
"rate" : 15, "rate": 15,
"company" : "_Test Company", "company": "_Test Company",
"asset_account" : "Cash - _TC", "asset_account": "Cash - _TC",
"equity_or_liability_account": "Creditors - _TC" "equity_or_liability_account": "Creditors - _TC"
}) })
self.assertRaises(ShareDontExists, doc.insert) self.assertRaises(ShareDontExists, doc.insert)

View File

@ -1,587 +1,163 @@
{ {
"allow_copy": 0, "autoname": "naming_series:",
"allow_guest_to_view": 0, "creation": "2017-12-25 16:50:53.878430",
"allow_import": 0, "doctype": "DocType",
"allow_rename": 0, "editable_grid": 1,
"autoname": "naming_series:", "engine": "InnoDB",
"beta": 0, "field_order": [
"creation": "2017-12-25 16:50:53.878430", "title",
"custom": 0, "column_break_2",
"description": "", "naming_series",
"docstatus": 0, "section_break_2",
"doctype": "DocType", "folio_no",
"document_type": "", "column_break_4",
"editable_grid": 1, "company",
"engine": "InnoDB", "is_company",
"address_contacts",
"address_html",
"column_break_9",
"contact_html",
"section_break_3",
"share_balance",
"contact_list"
],
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0, "fieldname": "title",
"allow_in_quick_entry": 0, "fieldtype": "Data",
"allow_on_submit": 0, "label": "Title",
"bold": 0, "reqd": 1
"collapsible": 0, },
"columns": 0,
"fieldname": "title",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Title",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "column_break_2",
"allow_in_quick_entry": 0, "fieldtype": "Column Break"
"allow_on_submit": 0, },
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_2",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "naming_series",
"allow_in_quick_entry": 0, "fieldtype": "Select",
"allow_on_submit": 0, "options": "ACC-SH-.YYYY.-"
"bold": 0, },
"collapsible": 0,
"columns": 0,
"default": "",
"fieldname": "naming_series",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "",
"length": 0,
"no_copy": 0,
"options": "ACC-SH-.YYYY.-",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "section_break_2",
"allow_in_quick_entry": 0, "fieldtype": "Section Break"
"allow_on_submit": 0, },
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_2",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "folio_no",
"allow_in_quick_entry": 0, "fieldtype": "Data",
"allow_on_submit": 0, "label": "Folio no.",
"bold": 0, "read_only": 1,
"collapsible": 0,
"columns": 0,
"fieldname": "folio_no",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Folio no.",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 1 "unique": 1
}, },
{ {
"allow_bulk_edit": 0, "fieldname": "column_break_4",
"allow_in_quick_entry": 0, "fieldtype": "Column Break"
"allow_on_submit": 0, },
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_4",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "company",
"allow_in_quick_entry": 0, "fieldtype": "Link",
"allow_on_submit": 0, "in_list_view": 1,
"bold": 0, "label": "Company",
"collapsible": 0, "options": "Company",
"columns": 0, "reqd": 1
"fieldname": "company", },
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Company",
"length": 0,
"no_copy": 0,
"options": "Company",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "default": "0",
"allow_in_quick_entry": 0, "fieldname": "is_company",
"allow_on_submit": 0, "fieldtype": "Check",
"bold": 0, "hidden": 1,
"collapsible": 0, "label": "Is Company",
"columns": 0, "read_only": 1
"fieldname": "is_company", },
"fieldtype": "Check",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Is Company",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "address_contacts",
"allow_in_quick_entry": 0, "fieldtype": "Section Break",
"allow_on_submit": 0, "label": "Address and Contacts",
"bold": 0, "options": "fa fa-map-marker"
"collapsible": 0, },
"columns": 0,
"fieldname": "address_contacts",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Address and Contacts",
"length": 0,
"no_copy": 0,
"options": "fa fa-map-marker",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "address_html",
"allow_in_quick_entry": 0, "fieldtype": "HTML",
"allow_on_submit": 0, "label": "Address HTML",
"bold": 0, "read_only": 1
"collapsible": 0, },
"columns": 0,
"fieldname": "address_html",
"fieldtype": "HTML",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Address HTML",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "column_break_9",
"allow_in_quick_entry": 0, "fieldtype": "Column Break"
"allow_on_submit": 0, },
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_9",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "contact_html",
"allow_in_quick_entry": 0, "fieldtype": "HTML",
"allow_on_submit": 0, "label": "Contact HTML",
"bold": 0, "read_only": 1
"collapsible": 0, },
"columns": 0,
"fieldname": "contact_html",
"fieldtype": "HTML",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Contact HTML",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "section_break_3",
"allow_in_quick_entry": 0, "fieldtype": "Section Break",
"allow_on_submit": 0, "label": "Share Balance"
"bold": 0, },
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_3",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Share Balance",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "share_balance",
"allow_in_quick_entry": 0, "fieldtype": "Table",
"allow_on_submit": 0, "label": "Share Balance",
"bold": 0, "options": "Share Balance",
"collapsible": 0, "read_only": 1
"columns": 0, },
"fieldname": "share_balance",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Share Balance",
"length": 0,
"no_copy": 0,
"options": "Share Balance",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "description": "Hidden list maintaining the list of contacts linked to Shareholder",
"allow_in_quick_entry": 0, "fieldname": "contact_list",
"allow_on_submit": 0, "fieldtype": "Code",
"bold": 0, "hidden": 1,
"collapsible": 0, "label": "Contact List",
"columns": 0, "read_only": 1
"description": "Hidden list maintaining the list of contacts linked to Shareholder",
"fieldname": "contact_list",
"fieldtype": "Code",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Contact List",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
} }
], ],
"has_web_view": 0, "modified": "2019-11-17 23:24:11.395882",
"hide_heading": 0, "modified_by": "Administrator",
"hide_toolbar": 0, "module": "Accounts",
"idx": 0, "name": "Shareholder",
"image_view": 0, "name_case": "Title Case",
"in_create": 0, "owner": "Administrator",
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-09-18 14:14:24.953014",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Shareholder",
"name_case": "Title Case",
"owner": "Administrator",
"permissions": [ "permissions": [
{ {
"amend": 0, "create": 1,
"cancel": 0, "delete": 1,
"create": 1, "email": 1,
"delete": 1, "export": 1,
"email": 1, "print": 1,
"export": 1, "read": 1,
"if_owner": 0, "report": 1,
"import": 0, "role": "System Manager",
"permlevel": 0, "share": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1 "write": 1
}, },
{ {
"amend": 0, "create": 1,
"cancel": 0, "delete": 1,
"create": 1, "email": 1,
"delete": 1, "export": 1,
"email": 1, "print": 1,
"export": 1, "read": 1,
"if_owner": 0, "report": 1,
"import": 0, "role": "Accounts Manager",
"permlevel": 0, "share": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1 "write": 1
}, },
{ {
"amend": 0, "create": 1,
"cancel": 0, "delete": 1,
"create": 1, "email": 1,
"delete": 1, "export": 1,
"email": 1, "print": 1,
"export": 1, "read": 1,
"if_owner": 0, "report": 1,
"import": 0, "role": "Accounts User",
"permlevel": 0, "share": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1 "write": 1
} }
], ],
"quick_entry": 0, "search_fields": "folio_no",
"read_only": 0, "sort_field": "modified",
"read_only_onload": 0, "sort_order": "DESC",
"search_fields": "folio_no", "title_field": "title",
"show_name_in_global_search": 0, "track_changes": 1
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "title",
"track_changes": 1,
"track_seen": 0,
"track_views": 0
} }