Compare commits
303 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
75e9733283 | ||
|
|
69588f57e7 | ||
|
|
88d8c164f7 | ||
|
|
c330a49e9d | ||
|
|
b75f5fd5ab | ||
|
|
6f5815838e | ||
|
|
fe53651287 | ||
|
|
d8546c4316 | ||
|
|
17405d4130 | ||
|
|
2f443a5789 | ||
|
|
a5e11d7195 | ||
|
|
3832e1f9be | ||
|
|
67079d292c | ||
|
|
01a3a81f71 | ||
|
|
befa8d613f | ||
|
|
9e26bcfeeb | ||
|
|
f948fea3bf | ||
|
|
d851bd8d85 | ||
|
|
30672c6b55 | ||
|
|
e73941b9cc | ||
|
|
f33787a706 | ||
|
|
fcc4021e44 | ||
|
|
3b67c89e0b | ||
|
|
7364ebaff6 | ||
|
|
fd8f34018d | ||
|
|
799fa09a23 | ||
|
|
d1dc622914 | ||
|
|
8ce47862f9 | ||
|
|
b24d2efc4b | ||
|
|
a184fbfa66 | ||
|
|
763821d57d | ||
|
|
a132767126 | ||
|
|
453cc374d4 | ||
|
|
43e46a8506 | ||
|
|
2c95130451 | ||
|
|
d46fb5eb8c | ||
|
|
e95c18a42d | ||
|
|
18c2c54633 | ||
|
|
0edec9d25b | ||
|
|
15216fdd6f | ||
|
|
9117af3077 | ||
|
|
92b6f76612 | ||
|
|
8bf0b89595 | ||
|
|
746c162055 | ||
|
|
9eb9ccd785 | ||
|
|
1e046aa49a | ||
|
|
3ad26e4dd1 | ||
|
|
2f3b097d63 | ||
|
|
c505cbc988 | ||
|
|
1e8025b327 | ||
|
|
0e6f2474e8 | ||
|
|
e102332f08 | ||
|
|
145227e4ec | ||
|
|
18e033514e | ||
|
|
26052df76e | ||
|
|
b2f354a614 | ||
|
|
49a59c075f | ||
|
|
ff3b220c79 | ||
|
|
cc7cb2a70a | ||
|
|
79bf233734 | ||
|
|
3698b84d7c | ||
|
|
3fbbb71afc | ||
|
|
a2f18ba794 | ||
|
|
9088432f10 | ||
|
|
c80059e10e | ||
|
|
8e8e9c61ca | ||
|
|
424f0c7b84 | ||
|
|
aa5fb5e50e | ||
|
|
08a60653ba | ||
|
|
8b96fdac12 | ||
|
|
e319598c51 | ||
|
|
0c7fd6cd94 | ||
|
|
0b5260acf0 | ||
|
|
d4be82cf9b | ||
|
|
0166e9e47a | ||
|
|
b71471fcb5 | ||
|
|
7e8d7d05ef | ||
|
|
228ff87ea2 | ||
|
|
8d8655e1cd | ||
|
|
5c73bafeaa | ||
|
|
14859faf17 | ||
|
|
2b7eda8135 | ||
|
|
751d7ecd85 | ||
|
|
6a09b3f7ef | ||
|
|
21897e3c52 | ||
|
|
15b4f6310c | ||
|
|
196a0bc675 | ||
|
|
7c011985f0 | ||
|
|
3cf67a462b | ||
|
|
f061877b4f | ||
|
|
04d244a360 | ||
|
|
b74999da82 | ||
|
|
061f7079ed | ||
|
|
246ed3f122 | ||
|
|
6b25708b7a | ||
|
|
623ed57663 | ||
|
|
1d21842f68 | ||
|
|
ada485f096 | ||
|
|
8a9d41a92e | ||
|
|
f965c5d203 | ||
|
|
21647974c4 | ||
|
|
9c3dca63fa | ||
|
|
c40b99be26 | ||
|
|
982f4ae44d | ||
|
|
9257413b68 | ||
|
|
c723c8b5aa | ||
|
|
2771b7d828 | ||
|
|
75ebed815f | ||
|
|
975ef07c48 | ||
|
|
f666535223 | ||
|
|
08fb19ac8c | ||
|
|
db9762be3f | ||
|
|
03ae61afce | ||
|
|
1847b705fe | ||
|
|
4a573a7e8b | ||
|
|
f74b9b06f7 | ||
|
|
2820a8749f | ||
|
|
41b4864f0c | ||
|
|
13df8a40ef | ||
|
|
7cfa5f0508 | ||
|
|
bb274fce2e | ||
|
|
fec61fe33e | ||
|
|
d0387f41df | ||
|
|
05d8174696 | ||
|
|
ba02ce6adc | ||
|
|
886def0a69 | ||
|
|
7590aa2524 | ||
|
|
8b48ceab8c | ||
|
|
d900e12ae7 | ||
|
|
098760f0e2 | ||
|
|
cc431716ed | ||
|
|
f5ea801b69 | ||
|
|
e2b8ccf1bb | ||
|
|
f447c8258a | ||
|
|
f78ffd84b4 | ||
|
|
63d345c6ab | ||
|
|
d0d1af2072 | ||
|
|
83694fd180 | ||
|
|
fc353efeca | ||
|
|
16edf8b478 | ||
|
|
c9e4fbeda0 | ||
|
|
46ae789f2f | ||
|
|
a9a284a5ae | ||
|
|
823e88d5bd | ||
|
|
1be94efcfa | ||
|
|
a5e9c71397 | ||
|
|
285135da8e | ||
|
|
906c2babaa | ||
|
|
14a394cde1 | ||
|
|
3c821c89f2 | ||
|
|
a041297861 | ||
|
|
856ee10dc4 | ||
|
|
1401e3f679 | ||
|
|
dae29bf2d4 | ||
|
|
0a3be6da27 | ||
|
|
3631e9cbe0 | ||
|
|
1c9a7d2a1b | ||
|
|
972f2f9194 | ||
|
|
239296d16a | ||
|
|
3210db9056 | ||
|
|
feda4f9bc9 | ||
|
|
f6954fb798 | ||
|
|
c6656e68b8 | ||
|
|
a39387d352 | ||
|
|
f3791797d6 | ||
|
|
ea4d63cef3 | ||
|
|
5464ca8a73 | ||
|
|
6c6875f503 | ||
|
|
20523c45c7 | ||
|
|
0248811e53 | ||
|
|
93416ee72c | ||
|
|
51e7086a08 | ||
|
|
5e849ae53e | ||
|
|
de0db0d000 | ||
|
|
f3a67c4533 | ||
|
|
0847f9a074 | ||
|
|
9490c21b8a | ||
|
|
bdb71bca4e | ||
|
|
e8861e2871 | ||
|
|
b084b5e449 | ||
|
|
41d3e57702 | ||
|
|
9df2899f72 | ||
|
|
dacf127f1b | ||
|
|
2b49f9b30a | ||
|
|
533434e878 | ||
|
|
1956028ddc | ||
|
|
a87dc3b4e6 | ||
|
|
97b3f750c9 | ||
|
|
c41b63eff1 | ||
|
|
e6f7ac961f | ||
|
|
cf26964deb | ||
|
|
94157334a7 | ||
|
|
c530161de0 | ||
|
|
2212ae12d8 | ||
|
|
54ade0d26c | ||
|
|
f043760526 | ||
|
|
1cd049d824 | ||
|
|
0a45260ed9 | ||
|
|
1540ad12f9 | ||
|
|
76bd015b2c | ||
|
|
5054a3955b | ||
|
|
1a0713e4b9 | ||
|
|
e9604d8484 | ||
|
|
008d1a0334 | ||
|
|
fe2ffaeafa | ||
|
|
dcef448f1e | ||
|
|
6224cfc414 | ||
|
|
700434ff37 | ||
|
|
4089b3d376 | ||
|
|
6cfab43d5f | ||
|
|
09a66c4201 | ||
|
|
ed8cecbdd8 | ||
|
|
c70109d0c5 | ||
|
|
ccf8c337f7 | ||
|
|
6809b4d86c | ||
|
|
cc08c68153 | ||
|
|
7daa7900ea | ||
|
|
7641f3fe53 | ||
|
|
fe2f51bbbc | ||
|
|
4f33249e1c | ||
|
|
b95b606f25 | ||
|
|
e690f245f2 | ||
|
|
5da4d857c9 | ||
|
|
6e38e917eb | ||
|
|
f3b0b95b15 | ||
|
|
7b0f1ffb2d | ||
|
|
97bb6bbaf4 | ||
|
|
cb4b2ec52a | ||
|
|
f18bbcef86 | ||
|
|
27976382d8 | ||
|
|
93d3c82737 | ||
|
|
03bf529622 | ||
|
|
6c4085fc0c | ||
|
|
c37484c8da | ||
|
|
b4ec294463 | ||
|
|
58406a920c | ||
|
|
98311f4394 | ||
|
|
53829707ad | ||
|
|
fcc31028c6 | ||
|
|
fc3d87181a | ||
|
|
6336ff7323 | ||
|
|
fde13e666a | ||
|
|
f80c09290e | ||
|
|
b797963bd8 | ||
|
|
03b42a7934 | ||
|
|
7e9ff99a6c | ||
|
|
5cbe3441e8 | ||
|
|
0724449d0e | ||
|
|
5a6ff218e8 | ||
|
|
122e4e0a96 | ||
|
|
e233f0e2ff | ||
|
|
40e92b679b | ||
|
|
4770a1abb5 | ||
|
|
ccb9117ba5 | ||
|
|
db938762c7 | ||
|
|
0910fc3b25 | ||
|
|
f0737667c6 | ||
|
|
2d83122c6b | ||
|
|
e2b7f832cc | ||
|
|
6a6958db5c | ||
|
|
ab1acb460b | ||
|
|
48d71fa7f7 | ||
|
|
30960e6a06 | ||
|
|
736000c223 | ||
|
|
4017bfcd2e | ||
|
|
e594e5de49 | ||
|
|
1f1f14be39 | ||
|
|
ebb60f5dbc | ||
|
|
75b00e3958 | ||
|
|
5e3646ad6e | ||
|
|
4439d8264f | ||
|
|
00d79eb68d | ||
|
|
28a9e35de9 | ||
|
|
c450536a2c | ||
|
|
3b3c48c877 | ||
|
|
621d6eac3c | ||
|
|
f9b356992a | ||
|
|
c516e1871d | ||
|
|
9a38e669ef | ||
|
|
143f2c6faf | ||
|
|
9269813207 | ||
|
|
0e6f92efa8 | ||
|
|
1a0e86f11d | ||
|
|
73b7efd61d | ||
|
|
4c4a5b968c | ||
|
|
7b5ac6396a | ||
|
|
01771e8afc | ||
|
|
347c4affe9 | ||
|
|
526957505f | ||
|
|
faa3416852 | ||
|
|
56912791e2 | ||
|
|
38647c68b9 | ||
|
|
4d64acfafc | ||
|
|
d7441ec051 | ||
|
|
0f15273bd7 | ||
|
|
24efb3122a | ||
|
|
85e6f5d04e | ||
|
|
1faaf71dfc | ||
|
|
5a0fbff1a3 | ||
|
|
7278c0ae85 | ||
|
|
5688a6c31a | ||
|
|
71349d221b | ||
|
|
9624bac3cf |
@@ -1,5 +1,9 @@
|
||||
# Contributing to Frappe / ERPNext
|
||||
|
||||
## Questions
|
||||
|
||||
If you have questions on how to use ERPNext or want help in customization or debugging of your scripts, please post on https://discuss.frappe.io. This is only for bug reports and feature requests.
|
||||
|
||||
## Reporting issues
|
||||
|
||||
We only accept issues that are bug reports or feature requests. Bugs must be isolated and reproducible problems. Please read the following guidelines before opening any issue.
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
from __future__ import unicode_literals
|
||||
__version__ = '5.1.2'
|
||||
__version__ = '5.4.2'
|
||||
|
||||
@@ -173,7 +173,7 @@
|
||||
"icon": "icon-money",
|
||||
"idx": 1,
|
||||
"in_create": 0,
|
||||
"modified": "2015-06-14 20:57:55.471334",
|
||||
"modified": "2015-07-20 03:54:14.297995",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Account",
|
||||
@@ -257,5 +257,5 @@
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"search_fields": "is_group"
|
||||
"search_fields": ""
|
||||
}
|
||||
@@ -49,7 +49,7 @@ class Account(Document):
|
||||
self.root_type = par.root_type
|
||||
|
||||
def validate_root_details(self):
|
||||
#does not exists parent
|
||||
# does not exists parent
|
||||
if frappe.db.exists("Account", self.name):
|
||||
if not frappe.db.get_value("Account", self.name, "parent_account"):
|
||||
throw(_("Root cannot be edited."))
|
||||
|
||||
@@ -4,13 +4,6 @@
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "check_supplier_invoice_uniqueness",
|
||||
"fieldtype": "Check",
|
||||
"label": "Check Supplier Invoice Number Uniqueness",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"description": "If enabled, the system will post accounting entries for inventory automatically.",
|
||||
@@ -45,12 +38,19 @@
|
||||
"label": "Credit Controller",
|
||||
"options": "Role",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "check_supplier_invoice_uniqueness",
|
||||
"fieldtype": "Check",
|
||||
"label": "Check Supplier Invoice Number Uniqueness",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
}
|
||||
],
|
||||
"icon": "icon-cog",
|
||||
"idx": 1,
|
||||
"issingle": 1,
|
||||
"modified": "2015-06-11 06:06:34.047890",
|
||||
"modified": "2015-07-14 00:51:48.095525",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Accounts Settings",
|
||||
|
||||
@@ -17,7 +17,7 @@ erpnext.accounts.CostCenterController = frappe.ui.form.Controller.extend({
|
||||
return {
|
||||
filters:[
|
||||
['Account', 'company', '=', me.frm.doc.company],
|
||||
['Account', 'report_type', '=', 'Profit and Loss'],
|
||||
['Account', 'root_type', '=', 'Expense'],
|
||||
['Account', 'is_group', '=', '0'],
|
||||
]
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"description": "Define Budget for this Cost Center. To set budget action, see <a href=\"#!List/Company\">Company Master</a>",
|
||||
"description": "Define Budget for this Cost Center. To set budget action, see \"Company List\"",
|
||||
"fieldname": "sb1",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Budget",
|
||||
@@ -139,7 +139,7 @@
|
||||
"icon": "icon-money",
|
||||
"idx": 1,
|
||||
"in_create": 0,
|
||||
"modified": "2015-04-23 02:54:26.934607",
|
||||
"modified": "2015-07-13 05:28:25.504801",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Cost Center",
|
||||
@@ -189,8 +189,8 @@
|
||||
"apply_user_permissions": 1,
|
||||
"permlevel": 0,
|
||||
"read": 1,
|
||||
"role": "Material User"
|
||||
"role": "Stock User"
|
||||
}
|
||||
],
|
||||
"search_fields": "parent_cost_center, is_group"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
from frappe import msgprint, _
|
||||
|
||||
from frappe import _
|
||||
from frappe.utils.nestedset import NestedSet
|
||||
|
||||
class CostCenter(NestedSet):
|
||||
@@ -14,18 +12,46 @@ class CostCenter(NestedSet):
|
||||
def autoname(self):
|
||||
self.name = self.cost_center_name.strip() + ' - ' + \
|
||||
frappe.db.get_value("Company", self.company, "abbr")
|
||||
|
||||
|
||||
def validate(self):
|
||||
self.validate_mandatory()
|
||||
self.validate_accounts()
|
||||
|
||||
def validate_mandatory(self):
|
||||
if self.cost_center_name != self.company and not self.parent_cost_center:
|
||||
msgprint(_("Please enter parent cost center"), raise_exception=1)
|
||||
frappe.throw(_("Please enter parent cost center"))
|
||||
elif self.cost_center_name == self.company and self.parent_cost_center:
|
||||
msgprint(_("Root cannot have a parent cost center"), raise_exception=1)
|
||||
frappe.throw(_("Root cannot have a parent cost center"))
|
||||
|
||||
def validate_accounts(self):
|
||||
if self.is_group==1 and self.get("budgets"):
|
||||
frappe.throw(_("Budget cannot be set for Group Cost Center"))
|
||||
|
||||
check_acc_list = []
|
||||
for d in self.get('budgets'):
|
||||
if d.account:
|
||||
account_details = frappe.db.get_value("Account", d.account,
|
||||
["is_group", "company", "root_type"], as_dict=1)
|
||||
if account_details.is_group:
|
||||
frappe.throw(_("Budget cannot be assigned against Group Account {0}").format(d.account))
|
||||
elif account_details.company != self.company:
|
||||
frappe.throw(_("Account {0} does not belongs to company {1}").format(d.account, self.company))
|
||||
elif account_details.root_type != "Expense":
|
||||
frappe.throw(_("Budget cannot be assigned against {0}, as it's not an Expense account")
|
||||
.format(d.account))
|
||||
|
||||
if [d.account, d.fiscal_year] in check_acc_list:
|
||||
frappe.throw(_("Account {0} has been entered more than once for fiscal year {1}")
|
||||
.format(d.account, d.fiscal_year))
|
||||
else:
|
||||
check_acc_list.append([d.account, d.fiscal_year])
|
||||
|
||||
def convert_group_to_ledger(self):
|
||||
if self.check_if_child_exists():
|
||||
msgprint(_("Cannot convert Cost Center to ledger as it has child nodes"), raise_exception=1)
|
||||
frappe.throw(_("Cannot convert Cost Center to ledger as it has child nodes"))
|
||||
elif self.check_gle_exists():
|
||||
msgprint(_("Cost Center with existing transactions can not be converted to ledger"), raise_exception=1)
|
||||
frappe.throw(_("Cost Center with existing transactions can not be converted to ledger"))
|
||||
else:
|
||||
self.is_group = 0
|
||||
self.save()
|
||||
@@ -33,7 +59,7 @@ class CostCenter(NestedSet):
|
||||
|
||||
def convert_ledger_to_group(self):
|
||||
if self.check_gle_exists():
|
||||
msgprint(_("Cost Center with existing transactions can not be converted to group"), raise_exception=1)
|
||||
frappe.throw(_("Cost Center with existing transactions can not be converted to group"))
|
||||
else:
|
||||
self.is_group = 1
|
||||
self.save()
|
||||
@@ -46,21 +72,6 @@ class CostCenter(NestedSet):
|
||||
return frappe.db.sql("select name from `tabCost Center` where \
|
||||
parent_cost_center = %s and docstatus != 2", self.name)
|
||||
|
||||
def validate_budget_details(self):
|
||||
check_acc_list = []
|
||||
for d in self.get('budgets'):
|
||||
if self.is_group==1:
|
||||
msgprint(_("Budget cannot be set for Group Cost Centers"), raise_exception=1)
|
||||
|
||||
if [d.account, d.fiscal_year] in check_acc_list:
|
||||
msgprint(_("Account {0} has been entered more than once for fiscal year {1}").format(d.account, d.fiscal_year), raise_exception=1)
|
||||
else:
|
||||
check_acc_list.append([d.account, d.fiscal_year])
|
||||
|
||||
def validate(self):
|
||||
self.validate_mandatory()
|
||||
self.validate_budget_details()
|
||||
|
||||
def before_rename(self, olddn, newdn, merge=False):
|
||||
# Add company abbr if not provided
|
||||
from erpnext.setup.doctype.company.company import get_name_with_abbr
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
],
|
||||
"icon": "icon-calendar",
|
||||
"idx": 1,
|
||||
"modified": "2015-04-18 07:33:23.922518",
|
||||
"modified": "2015-07-13 05:28:27.745408",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Fiscal Year",
|
||||
@@ -78,11 +78,63 @@
|
||||
{
|
||||
"apply_user_permissions": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"email": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"role": "All"
|
||||
"role": "Sales User"
|
||||
},
|
||||
{
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"email": 0,
|
||||
"export": 0,
|
||||
"permlevel": 0,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"report": 0,
|
||||
"role": "Purchase User",
|
||||
"share": 0,
|
||||
"write": 0
|
||||
},
|
||||
{
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"email": 0,
|
||||
"export": 0,
|
||||
"permlevel": 0,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"report": 0,
|
||||
"role": "Accounts User",
|
||||
"share": 0,
|
||||
"write": 0
|
||||
},
|
||||
{
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"email": 0,
|
||||
"export": 0,
|
||||
"permlevel": 0,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"report": 0,
|
||||
"role": "Stock User",
|
||||
"share": 0,
|
||||
"write": 0
|
||||
},
|
||||
{
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"email": 0,
|
||||
"export": 0,
|
||||
"permlevel": 0,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"report": 0,
|
||||
"role": "Employee",
|
||||
"share": 0,
|
||||
"write": 0
|
||||
}
|
||||
],
|
||||
"sort_field": "name",
|
||||
|
||||
@@ -193,7 +193,7 @@
|
||||
"icon": "icon-list",
|
||||
"idx": 1,
|
||||
"in_create": 1,
|
||||
"modified": "2015-06-14 20:57:19.800276",
|
||||
"modified": "2015-07-09 15:51:04.986518",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "GL Entry",
|
||||
@@ -225,6 +225,19 @@
|
||||
"role": "Accounts Manager",
|
||||
"submit": 0,
|
||||
"write": 0
|
||||
},
|
||||
{
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"email": 0,
|
||||
"export": 1,
|
||||
"permlevel": 0,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Auditor",
|
||||
"share": 0,
|
||||
"write": 0
|
||||
}
|
||||
],
|
||||
"search_fields": "voucher_no,account,posting_date,against_voucher",
|
||||
|
||||
@@ -9,6 +9,8 @@ from frappe import _
|
||||
|
||||
from frappe.model.document import Document
|
||||
|
||||
class CustomerFrozen(frappe.ValidationError): pass
|
||||
|
||||
class GLEntry(Document):
|
||||
def validate(self):
|
||||
self.flags.ignore_submit_comment = True
|
||||
@@ -17,6 +19,7 @@ class GLEntry(Document):
|
||||
self.validate_posting_date()
|
||||
self.check_pl_account()
|
||||
self.validate_cost_center()
|
||||
self.validate_party()
|
||||
|
||||
def on_update_with_args(self, adv_adj, update_outstanding = 'Yes'):
|
||||
self.validate_account_details(adv_adj)
|
||||
@@ -88,6 +91,13 @@ class GLEntry(Document):
|
||||
|
||||
if self.cost_center and _get_cost_center_company() != self.company:
|
||||
frappe.throw(_("Cost Center {0} does not belong to Company {1}").format(self.cost_center, self.company))
|
||||
|
||||
def validate_party(self):
|
||||
if self.party_type and self.party:
|
||||
frozen_accounts_modifier = frappe.db.get_value( 'Accounts Settings', None,'frozen_accounts_modifier')
|
||||
if not frozen_accounts_modifier in frappe.get_roles():
|
||||
if frappe.db.get_value(self.party_type, self.party, "is_frozen"):
|
||||
frappe.throw("{0} {1} is frozen".format(self.party_type, self.party), CustomerFrozen)
|
||||
|
||||
def validate_balance_type(account, adv_adj=False):
|
||||
if not adv_adj and account:
|
||||
@@ -139,9 +149,9 @@ def update_outstanding_amt(account, party_type, party, against_voucher_type, aga
|
||||
if against_voucher_amount < 0:
|
||||
bal = -bal
|
||||
|
||||
# Validation : Outstanding can not be negative
|
||||
if bal < 0 and not on_cancel:
|
||||
frappe.throw(_("Outstanding for {0} cannot be less than zero ({1})").format(against_voucher, fmt_money(bal)))
|
||||
# Validation : Outstanding can not be negative for JV
|
||||
if bal < 0 and not on_cancel:
|
||||
frappe.throw(_("Outstanding for {0} cannot be less than zero ({1})").format(against_voucher, fmt_money(bal)))
|
||||
|
||||
# Update outstanding amt on against voucher
|
||||
if against_voucher_type in ["Sales Invoice", "Purchase Invoice"]:
|
||||
|
||||
@@ -109,7 +109,7 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
|
||||
|
||||
against_jv: function(doc, cdt, cdn) {
|
||||
var d = frappe.get_doc(cdt, cdn);
|
||||
if (d.against_jv && d.party && !flt(d.credit) && !flt(d.debit)) {
|
||||
if (d.against_jv && !flt(d.credit) && !flt(d.debit)) {
|
||||
this.get_outstanding('Journal Entry', d.against_jv, d);
|
||||
}
|
||||
},
|
||||
@@ -119,7 +119,8 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
|
||||
var args = {
|
||||
"doctype": doctype,
|
||||
"docname": docname,
|
||||
"party": child.party
|
||||
"party": child.party,
|
||||
"account": child.account
|
||||
}
|
||||
|
||||
return this.frm.call({
|
||||
|
||||
@@ -310,7 +310,7 @@
|
||||
"depends_on": "eval:doc.voucher_type == 'Write Off Entry'",
|
||||
"fieldname": "write_off_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Write Off Amount <=",
|
||||
"label": "Write Off Amount",
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
@@ -503,4 +503,4 @@
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "title"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.utils import cstr, flt, fmt_money, formatdate, getdate
|
||||
from frappe.utils import cstr, flt, fmt_money, formatdate, getdate, date_diff
|
||||
from frappe import msgprint, _, scrub
|
||||
from erpnext.setup.utils import get_company_currency
|
||||
from erpnext.controllers.accounts_controller import AccountsController
|
||||
@@ -35,7 +35,7 @@ class JournalEntry(AccountsController):
|
||||
self.set_print_format_fields()
|
||||
self.validate_against_sales_order()
|
||||
self.validate_against_purchase_order()
|
||||
self.check_credit_days()
|
||||
self.check_due_date()
|
||||
self.validate_expense_claim()
|
||||
self.validate_credit_debit_note()
|
||||
self.validate_empty_accounts_table()
|
||||
@@ -88,23 +88,21 @@ class JournalEntry(AccountsController):
|
||||
for customer in customers:
|
||||
check_credit_limit(customer, self.company)
|
||||
|
||||
def check_credit_days(self):
|
||||
from erpnext.accounts.party import get_credit_days
|
||||
posting_date = None
|
||||
def check_due_date(self):
|
||||
if self.cheque_date:
|
||||
for d in self.get("accounts"):
|
||||
if d.party_type and d.party and d.get("credit" if d.party_type=="Customer" else "debit") > 0:
|
||||
due_date = None
|
||||
if d.against_invoice:
|
||||
posting_date = frappe.db.get_value("Sales Invoice", d.against_invoice, "posting_date")
|
||||
due_date = frappe.db.get_value("Sales Invoice", d.against_invoice, "due_date")
|
||||
elif d.against_voucher:
|
||||
posting_date = frappe.db.get_value("Purchase Invoice", d.against_voucher, "posting_date")
|
||||
due_date = frappe.db.get_value("Purchase Invoice", d.against_voucher, "due_date")
|
||||
|
||||
credit_days = get_credit_days(d.party_type, d.party, self.company)
|
||||
if posting_date and credit_days:
|
||||
date_diff = (getdate(self.cheque_date) - getdate(posting_date)).days
|
||||
if date_diff > flt(credit_days):
|
||||
msgprint(_("Note: Reference Date exceeds allowed credit days by {0} days for {1} {2}")
|
||||
.format(date_diff - flt(credit_days), d.party_type, d.party))
|
||||
if due_date and getdate(self.cheque_date) > getdate(due_date):
|
||||
diff = date_diff(self.cheque_date, due_date)
|
||||
if diff > 0:
|
||||
msgprint(_("Note: Reference Date exceeds invoice due date by {0} days for {1} {2}")
|
||||
.format(diff, d.party_type, d.party))
|
||||
|
||||
def validate_cheque_info(self):
|
||||
if self.voucher_type in ['Bank Entry']:
|
||||
@@ -547,12 +545,14 @@ def get_against_jv(doctype, txt, searchfield, start, page_len, filters):
|
||||
@frappe.whitelist()
|
||||
def get_outstanding(args):
|
||||
args = eval(args)
|
||||
if args.get("doctype") == "Journal Entry" and args.get("party"):
|
||||
if args.get("doctype") == "Journal Entry":
|
||||
condition = " and party=%(party)s" if args.get("party") else ""
|
||||
|
||||
against_jv_amount = frappe.db.sql("""
|
||||
select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))
|
||||
from `tabJournal Entry Account` where parent=%s and party=%s
|
||||
from `tabJournal Entry Account` where parent=%(docname)s and account=%(account)s {0}
|
||||
and ifnull(against_invoice, '')='' and ifnull(against_voucher, '')=''
|
||||
and ifnull(against_jv, '')=''""", (args['docname'], args['party']))
|
||||
and ifnull(against_jv, '')=''""".format(condition), args)
|
||||
|
||||
against_jv_amount = flt(against_jv_amount[0][0]) if against_jv_amount else 0
|
||||
if against_jv_amount > 0:
|
||||
|
||||
@@ -190,8 +190,9 @@ class PaymentReconciliation(Document):
|
||||
if flt(p.allocated_amount) > flt(p.amount):
|
||||
frappe.throw(_("Row {0}: Allocated amount {1} must be less than or equals to JV amount {2}")
|
||||
.format(p.idx, p.allocated_amount, p.amount))
|
||||
|
||||
if flt(p.allocated_amount) > unreconciled_invoices.get(p.invoice_type, {}).get(p.invoice_number):
|
||||
|
||||
invoice_outstanding = unreconciled_invoices.get(p.invoice_type, {}).get(p.invoice_number)
|
||||
if abs(flt(p.allocated_amount) - invoice_outstanding) > 0.009:
|
||||
frappe.throw(_("Row {0}: Allocated amount {1} must be less than or equals to invoice outstanding amount {2}")
|
||||
.format(p.idx, p.allocated_amount, unreconciled_invoices.get(p.invoice_type, {}).get(p.invoice_number)))
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
"options": "Territory",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 1
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "naming_series",
|
||||
@@ -77,68 +77,6 @@
|
||||
"read_only": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break0",
|
||||
"fieldtype": "Column Break",
|
||||
"oldfieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"description": "Create Stock Ledger Entries when you submit a Sales Invoice",
|
||||
"fieldname": "update_stock",
|
||||
"fieldtype": "Check",
|
||||
"label": "Update Stock",
|
||||
"permlevel": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "customer",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 0,
|
||||
"label": "Customer",
|
||||
"oldfieldname": "customer_account",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Customer",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "cash_bank_account",
|
||||
"fieldtype": "Link",
|
||||
"label": "Cash/Bank Account",
|
||||
"oldfieldname": "cash_bank_account",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Account",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "income_account",
|
||||
"fieldtype": "Link",
|
||||
"label": "Income Account",
|
||||
"oldfieldname": "income_account",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Account",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:cint(sys_defaults.auto_accounting_for_stock)",
|
||||
"fieldname": "expense_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"label": "Expense Account",
|
||||
"options": "Account",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "warehouse",
|
||||
"fieldtype": "Link",
|
||||
@@ -150,45 +88,6 @@
|
||||
"read_only": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "cost_center",
|
||||
"fieldtype": "Link",
|
||||
"label": "Cost Center",
|
||||
"oldfieldname": "cost_center",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Cost Center",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "taxes_and_charges",
|
||||
"fieldtype": "Link",
|
||||
"label": "Taxes and Charges",
|
||||
"oldfieldname": "charge",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Sales Taxes and Charges Template",
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "write_off_account",
|
||||
"fieldtype": "Link",
|
||||
"label": "Write Off Account",
|
||||
"options": "Account",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "write_off_cost_center",
|
||||
"fieldtype": "Link",
|
||||
"label": "Write Off Cost Center",
|
||||
"options": "Cost Center",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
"fieldname": "letter_head",
|
||||
@@ -222,11 +121,120 @@
|
||||
"options": "Print Heading",
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break0",
|
||||
"fieldtype": "Column Break",
|
||||
"oldfieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"description": "Create Stock Ledger Entries when you submit a Sales Invoice",
|
||||
"fieldname": "update_stock",
|
||||
"fieldtype": "Check",
|
||||
"label": "Update Stock",
|
||||
"permlevel": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "customer",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 0,
|
||||
"label": "Customer",
|
||||
"oldfieldname": "customer_account",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Customer",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "mode_of_payment",
|
||||
"fieldtype": "Link",
|
||||
"label": "Mode of Payment",
|
||||
"options": "Mode of Payment",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"fieldname": "cash_bank_account",
|
||||
"fieldtype": "Link",
|
||||
"label": "Cash/Bank Account",
|
||||
"oldfieldname": "cash_bank_account",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Account",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "income_account",
|
||||
"fieldtype": "Link",
|
||||
"label": "Income Account",
|
||||
"oldfieldname": "income_account",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Account",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:cint(sys_defaults.auto_accounting_for_stock)",
|
||||
"fieldname": "expense_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"label": "Expense Account",
|
||||
"options": "Account",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "cost_center",
|
||||
"fieldtype": "Link",
|
||||
"label": "Cost Center",
|
||||
"oldfieldname": "cost_center",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Cost Center",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "write_off_account",
|
||||
"fieldtype": "Link",
|
||||
"label": "Write Off Account",
|
||||
"options": "Account",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "write_off_cost_center",
|
||||
"fieldtype": "Link",
|
||||
"label": "Write Off Cost Center",
|
||||
"options": "Cost Center",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "taxes_and_charges",
|
||||
"fieldtype": "Link",
|
||||
"label": "Taxes and Charges",
|
||||
"oldfieldname": "charge",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Sales Taxes and Charges Template",
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
}
|
||||
],
|
||||
"icon": "icon-cog",
|
||||
"idx": 1,
|
||||
"modified": "2015-05-20 05:38:44.482696",
|
||||
"modified": "2015-07-28 15:07:14.417200",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "POS Profile",
|
||||
|
||||
@@ -20,26 +20,19 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
|
||||
this._super();
|
||||
|
||||
// Show / Hide button
|
||||
if(doc.docstatus==1 && doc.outstanding_amount > 0)
|
||||
this.frm.add_custom_button(__('Make Payment Entry'), this.make_bank_entry,
|
||||
frappe.boot.doctype_icons["Journal Entry"]);
|
||||
|
||||
if(doc.docstatus==1) {
|
||||
cur_frm.add_custom_button(__('View Ledger'), function() {
|
||||
frappe.route_options = {
|
||||
"voucher_no": doc.name,
|
||||
"from_date": doc.posting_date,
|
||||
"to_date": doc.posting_date,
|
||||
"company": doc.company,
|
||||
group_by_voucher: 0
|
||||
};
|
||||
frappe.set_route("query-report", "General Ledger");
|
||||
}, "icon-table");
|
||||
}
|
||||
|
||||
if(doc.docstatus===0) {
|
||||
cur_frm.add_custom_button(__('From Purchase Order'),
|
||||
function() {
|
||||
this.show_general_ledger();
|
||||
|
||||
if(!doc.is_return) {
|
||||
if(doc.docstatus==1) {
|
||||
if(doc.outstanding_amount > 0) {
|
||||
this.frm.add_custom_button(__('Make Payment Entry'), this.make_bank_entry);
|
||||
}
|
||||
|
||||
cur_frm.add_custom_button(__('Make Debit Note'), this.make_debit_note);
|
||||
}
|
||||
|
||||
if(doc.docstatus===0) {
|
||||
cur_frm.add_custom_button(__('From Purchase Order'), function() {
|
||||
frappe.model.map_current_doc({
|
||||
method: "erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_invoice",
|
||||
source_doctype: "Purchase Order",
|
||||
@@ -51,10 +44,9 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
|
||||
company: cur_frm.doc.company
|
||||
}
|
||||
})
|
||||
}, "icon-download", "btn-default");
|
||||
});
|
||||
|
||||
cur_frm.add_custom_button(__('From Purchase Receipt'),
|
||||
function() {
|
||||
cur_frm.add_custom_button(__('From Purchase Receipt'), function() {
|
||||
frappe.model.map_current_doc({
|
||||
method: "erpnext.stock.doctype.purchase_receipt.purchase_receipt.make_purchase_invoice",
|
||||
source_doctype: "Purchase Receipt",
|
||||
@@ -64,8 +56,8 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
|
||||
company: cur_frm.doc.company
|
||||
}
|
||||
})
|
||||
}, "icon-download", "btn-default");
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -109,7 +101,14 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
|
||||
$.each(this.frm.doc["items"] || [], function(i, row) {
|
||||
if(row.purchase_receipt) frappe.model.clear_doc("Purchase Receipt", row.purchase_receipt)
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
make_debit_note: function() {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_debit_note",
|
||||
frm: cur_frm
|
||||
})
|
||||
},
|
||||
});
|
||||
|
||||
cur_frm.script_manager.make(erpnext.accounts.PurchaseInvoice);
|
||||
@@ -144,7 +143,7 @@ cur_frm.fields_dict['items'].grid.get_field("item_code").get_query = function(do
|
||||
return {
|
||||
query: "erpnext.controllers.queries.item_query",
|
||||
filters:{
|
||||
'is_purchase_item': 'Yes'
|
||||
'is_purchase_item': 1
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -224,4 +223,3 @@ cur_frm.cscript.select_print_heading = function(doc,cdt,cdn){
|
||||
else
|
||||
cur_frm.pformat.print_heading = __("Purchase Invoice");
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "naming_series",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "PINV-",
|
||||
"options": "PINV-\nPINV-RET-",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
@@ -38,7 +38,7 @@
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Name",
|
||||
"label": "Supplier Name",
|
||||
"oldfieldname": "supplier_name",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
@@ -154,6 +154,28 @@
|
||||
"read_only": 0,
|
||||
"search_index": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "is_return",
|
||||
"fieldtype": "Check",
|
||||
"label": "Is Return",
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "is_return",
|
||||
"fieldname": "return_against",
|
||||
"fieldtype": "Link",
|
||||
"label": "Return Against Purchase Invoice",
|
||||
"no_copy": 0,
|
||||
"options": "Purchase Invoice",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "currency_and_price_list",
|
||||
"fieldtype": "Section Break",
|
||||
@@ -940,7 +962,7 @@
|
||||
"icon": "icon-file-text",
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"modified": "2015-06-22 07:30:06.743438",
|
||||
"modified": "2015-07-24 11:49:59.762109",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Invoice",
|
||||
|
||||
@@ -37,14 +37,16 @@ class PurchaseInvoice(BuyingController):
|
||||
|
||||
super(PurchaseInvoice, self).validate()
|
||||
|
||||
self.po_required()
|
||||
self.pr_required()
|
||||
self.validate_supplier_invoice()
|
||||
if not self.is_return:
|
||||
self.po_required()
|
||||
self.pr_required()
|
||||
self.validate_supplier_invoice()
|
||||
self.validate_advance_jv("advances", "purchase_order")
|
||||
|
||||
self.check_active_purchase_items()
|
||||
self.check_conversion_rate()
|
||||
self.validate_credit_to_acc()
|
||||
self.clear_unallocated_advances("Purchase Invoice Advance", "advances")
|
||||
self.validate_advance_jv("advances", "purchase_order")
|
||||
self.check_for_stopped_status()
|
||||
self.validate_with_previous_doc()
|
||||
self.validate_uom_is_integer("uom", "qty")
|
||||
@@ -71,13 +73,14 @@ class PurchaseInvoice(BuyingController):
|
||||
super(PurchaseInvoice, self).set_missing_values(for_validate)
|
||||
|
||||
def get_advances(self):
|
||||
super(PurchaseInvoice, self).get_advances(self.credit_to, "Supplier", self.supplier,
|
||||
"Purchase Invoice Advance", "advances", "debit", "purchase_order")
|
||||
if not self.is_return:
|
||||
super(PurchaseInvoice, self).get_advances(self.credit_to, "Supplier", self.supplier,
|
||||
"Purchase Invoice Advance", "advances", "debit", "purchase_order")
|
||||
|
||||
def check_active_purchase_items(self):
|
||||
for d in self.get('items'):
|
||||
if d.item_code: # extra condn coz item_code is not mandatory in PV
|
||||
if frappe.db.get_value("Item", d.item_code, "is_purchase_item") != 'Yes':
|
||||
if frappe.db.get_value("Item", d.item_code, "is_purchase_item") != 1:
|
||||
msgprint(_("Item {0} is not Purchase Item").format(d.item_code), raise_exception=True)
|
||||
|
||||
def check_conversion_rate(self):
|
||||
@@ -124,20 +127,11 @@ class PurchaseInvoice(BuyingController):
|
||||
}
|
||||
})
|
||||
|
||||
if cint(frappe.defaults.get_global_default('maintain_same_rate')):
|
||||
super(PurchaseInvoice, self).validate_with_previous_doc({
|
||||
"Purchase Order Item": {
|
||||
"ref_dn_field": "po_detail",
|
||||
"compare_fields": [["rate", "="]],
|
||||
"is_child_table": True,
|
||||
"allow_duplicate_prev_row_id": True
|
||||
},
|
||||
"Purchase Receipt Item": {
|
||||
"ref_dn_field": "pr_detail",
|
||||
"compare_fields": [["rate", "="]],
|
||||
"is_child_table": True
|
||||
}
|
||||
})
|
||||
if cint(frappe.db.get_single_value('Buying Settings', 'maintain_same_rate')):
|
||||
self.validate_rate_with_reference_doc([
|
||||
["Purchase Order", "purchase_order", "po_detail"],
|
||||
["Purchase Receipt", "purchase_receipt", "pr_detail"]
|
||||
])
|
||||
|
||||
def set_against_expense_account(self):
|
||||
auto_accounting_for_stock = cint(frappe.defaults.get_global_default("auto_accounting_for_stock"))
|
||||
@@ -235,9 +229,11 @@ class PurchaseInvoice(BuyingController):
|
||||
|
||||
# this sequence because outstanding may get -negative
|
||||
self.make_gl_entries()
|
||||
self.update_against_document_in_jv()
|
||||
self.update_prevdoc_status()
|
||||
self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
|
||||
if not self.is_return:
|
||||
self.update_against_document_in_jv()
|
||||
self.update_prevdoc_status()
|
||||
self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
|
||||
|
||||
self.update_project()
|
||||
|
||||
def make_gl_entries(self):
|
||||
@@ -259,7 +255,7 @@ class PurchaseInvoice(BuyingController):
|
||||
"against": self.against_expense_account,
|
||||
"credit": self.total_amount_to_pay,
|
||||
"remarks": self.remarks,
|
||||
"against_voucher": self.name,
|
||||
"against_voucher": self.return_against if cint(self.is_return) else self.name,
|
||||
"against_voucher_type": self.doctype,
|
||||
})
|
||||
)
|
||||
@@ -367,11 +363,12 @@ class PurchaseInvoice(BuyingController):
|
||||
make_gl_entries(gl_entries, cancel=(self.docstatus == 2))
|
||||
|
||||
def on_cancel(self):
|
||||
from erpnext.accounts.utils import remove_against_link_from_jv
|
||||
remove_against_link_from_jv(self.doctype, self.name, "against_voucher")
|
||||
if not self.is_return:
|
||||
from erpnext.accounts.utils import remove_against_link_from_jv
|
||||
remove_against_link_from_jv(self.doctype, self.name, "against_voucher")
|
||||
|
||||
self.update_prevdoc_status()
|
||||
self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
|
||||
self.update_prevdoc_status()
|
||||
self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
|
||||
self.make_gl_entries_on_cancel()
|
||||
self.update_project()
|
||||
|
||||
@@ -391,7 +388,8 @@ class PurchaseInvoice(BuyingController):
|
||||
frappe.throw("Supplier Invoice Date cannot be greater than Posting Date")
|
||||
if self.bill_no:
|
||||
if cint(frappe.db.get_single_value("Accounts Settings", "check_supplier_invoice_uniqueness")):
|
||||
pi = frappe.db.exists("Purchase Invoice", {"bill_no": self.bill_no, "fiscal_year": self.fiscal_year})
|
||||
pi = frappe.db.exists("Purchase Invoice", {"bill_no": self.bill_no,
|
||||
"fiscal_year": self.fiscal_year, "name": ("!=", self.name)})
|
||||
if pi:
|
||||
frappe.throw("Supplier Invoice No exists in Purchase Invoice {0}".format(pi))
|
||||
|
||||
@@ -411,3 +409,8 @@ def get_expense_account(doctype, txt, searchfield, start, page_len, filters):
|
||||
and tabAccount.%(key)s LIKE '%(txt)s'
|
||||
%(mcond)s""" % {'company': filters['company'], 'key': searchfield,
|
||||
'txt': "%%%s%%" % frappe.db.escape(txt), 'mcond':get_match_cond(doctype)})
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_debit_note(source_name, target_doc=None):
|
||||
from erpnext.controllers.sales_and_purchase_return import make_return_doc
|
||||
return make_return_doc("Purchase Invoice", source_name, target_doc)
|
||||
@@ -4,9 +4,11 @@
|
||||
// render
|
||||
frappe.listview_settings['Purchase Invoice'] = {
|
||||
add_fields: ["supplier", "supplier_name", "base_grand_total", "outstanding_amount", "due_date", "company",
|
||||
"currency"],
|
||||
"currency", "is_return"],
|
||||
get_indicator: function(doc) {
|
||||
if(flt(doc.outstanding_amount) > 0 && doc.docstatus==1) {
|
||||
if(cint(doc.is_return)==1) {
|
||||
return [__("Return"), "darkgrey", "is_return,=,1"];
|
||||
} else if(flt(doc.outstanding_amount) > 0 && doc.docstatus==1) {
|
||||
if(frappe.datetime.get_diff(doc.due_date) < 0) {
|
||||
return [__("Overdue"), "red", "outstanding_amount,>,0|due_date,<,Today"];
|
||||
} else {
|
||||
|
||||
@@ -275,5 +275,58 @@ class TestPurchaseInvoice(unittest.TestCase):
|
||||
purchase_invoice.cancel()
|
||||
self.assertEqual(frappe.db.get_value("Project", "_Test Project", "total_purchase_cost"), 0)
|
||||
|
||||
def test_return_purchase_invoice(self):
|
||||
set_perpetual_inventory()
|
||||
|
||||
pi = make_purchase_invoice()
|
||||
|
||||
return_pi = make_purchase_invoice(is_return=1, return_against=pi.name, qty=-2)
|
||||
|
||||
|
||||
# check gl entries for return
|
||||
gl_entries = frappe.db.sql("""select account, debit, credit
|
||||
from `tabGL Entry` where voucher_type=%s and voucher_no=%s
|
||||
order by account desc""", ("Purchase Invoice", return_pi.name), as_dict=1)
|
||||
|
||||
self.assertTrue(gl_entries)
|
||||
|
||||
expected_values = {
|
||||
"Creditors - _TC": [100.0, 0.0],
|
||||
"Stock Received But Not Billed - _TC": [0.0, 100.0],
|
||||
}
|
||||
|
||||
for gle in gl_entries:
|
||||
self.assertEquals(expected_values[gle.account][0], gle.debit)
|
||||
self.assertEquals(expected_values[gle.account][1], gle.credit)
|
||||
|
||||
set_perpetual_inventory(0)
|
||||
|
||||
def make_purchase_invoice(**args):
|
||||
pi = frappe.new_doc("Purchase Invoice")
|
||||
args = frappe._dict(args)
|
||||
if args.posting_date:
|
||||
pi.posting_date = args.posting_date
|
||||
if args.posting_time:
|
||||
pi.posting_time = args.posting_time
|
||||
pi.company = args.company or "_Test Company"
|
||||
pi.supplier = args.supplier or "_Test Supplier"
|
||||
pi.currency = args.currency or "INR"
|
||||
pi.is_return = args.is_return
|
||||
pi.return_against = args.return_against
|
||||
|
||||
pi.append("items", {
|
||||
"item_code": args.item or args.item_code or "_Test Item",
|
||||
"warehouse": args.warehouse or "_Test Warehouse - _TC",
|
||||
"qty": args.qty or 5,
|
||||
"rate": args.rate or 50,
|
||||
"conversion_factor": 1.0,
|
||||
"serial_no": args.serial_no,
|
||||
"stock_uom": "_Test UOM"
|
||||
})
|
||||
if not args.do_not_save:
|
||||
pi.insert()
|
||||
if not args.do_not_submit:
|
||||
pi.submit()
|
||||
return pi
|
||||
|
||||
test_records = frappe.get_test_records('Purchase Invoice')
|
||||
|
||||
@@ -4,10 +4,9 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from frappe.model.document import Document
|
||||
from erpnext.controllers.accounts_controller import validate_taxes_and_charges, validate_inclusive_tax
|
||||
from erpnext.accounts.doctype.sales_taxes_and_charges_template.sales_taxes_and_charges_template \
|
||||
import valdiate_taxes_and_charges_template
|
||||
|
||||
class PurchaseTaxesandChargesTemplate(Document):
|
||||
def validate(self):
|
||||
for tax in self.get("taxes"):
|
||||
validate_taxes_and_charges(tax)
|
||||
validate_inclusive_tax(tax, self)
|
||||
valdiate_taxes_and_charges_template(self)
|
||||
|
||||
@@ -11,9 +11,9 @@ def get_items(price_list, sales_or_purchase, item=None):
|
||||
args = {"price_list": price_list}
|
||||
|
||||
if sales_or_purchase == "Sales":
|
||||
condition = "i.is_sales_item='Yes'"
|
||||
condition = "i.is_sales_item=1"
|
||||
else:
|
||||
condition = "i.is_purchase_item='Yes'"
|
||||
condition = "i.is_purchase_item=1"
|
||||
|
||||
if item:
|
||||
# search serial no
|
||||
|
||||
@@ -40,22 +40,14 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
this._super();
|
||||
|
||||
cur_frm.dashboard.reset();
|
||||
|
||||
if(doc.docstatus==1) {
|
||||
cur_frm.add_custom_button('View Ledger', function() {
|
||||
frappe.route_options = {
|
||||
"voucher_no": doc.name,
|
||||
"from_date": doc.posting_date,
|
||||
"to_date": doc.posting_date,
|
||||
"company": doc.company,
|
||||
group_by_voucher: 0
|
||||
};
|
||||
frappe.set_route("query-report", "General Ledger");
|
||||
}, "icon-table");
|
||||
|
||||
// var percent_paid = cint(flt(doc.base_grand_total - doc.outstanding_amount) / flt(doc.base_grand_total) * 100);
|
||||
// cur_frm.dashboard.add_progress(percent_paid + "% Paid", percent_paid);
|
||||
|
||||
|
||||
this.frm.toggle_reqd("due_date", !this.frm.doc.is_return);
|
||||
|
||||
this.show_general_ledger();
|
||||
|
||||
if(doc.update_stock) this.show_stock_ledger();
|
||||
|
||||
if(doc.docstatus==1 && !doc.is_return) {
|
||||
if(cint(doc.update_stock)!=1) {
|
||||
// show Make Delivery Note button only if Sales Invoice is not created from Delivery Note
|
||||
var from_delivery_note = false;
|
||||
@@ -65,17 +57,20 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
});
|
||||
|
||||
if(!from_delivery_note) {
|
||||
cur_frm.add_custom_button(__('Make Delivery'), cur_frm.cscript['Make Delivery Note'], "icon-truck")
|
||||
cur_frm.add_custom_button(__('Make Delivery'), cur_frm.cscript['Make Delivery Note'])
|
||||
}
|
||||
}
|
||||
|
||||
if(doc.outstanding_amount!=0) {
|
||||
cur_frm.add_custom_button(__('Make Payment Entry'), cur_frm.cscript.make_bank_entry, "icon-money");
|
||||
if(doc.outstanding_amount!=0 && !cint(doc.is_return)) {
|
||||
cur_frm.add_custom_button(__('Make Payment Entry'), cur_frm.cscript.make_bank_entry);
|
||||
}
|
||||
|
||||
cur_frm.add_custom_button(doc.update_stock ? __('Make Sales Return') : __('Make Credit Note'),
|
||||
this.make_sales_return);
|
||||
}
|
||||
|
||||
// Show buttons only when pos view is active
|
||||
if (cint(doc.docstatus==0) && cur_frm.page.current_view_name!=="pos") {
|
||||
if (cint(doc.docstatus==0) && cur_frm.page.current_view_name!=="pos" && !doc.is_return) {
|
||||
cur_frm.cscript.sales_order_btn();
|
||||
cur_frm.cscript.delivery_note_btn();
|
||||
}
|
||||
@@ -205,8 +200,14 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
|
||||
items_on_form_rendered: function() {
|
||||
erpnext.setup_serial_no();
|
||||
},
|
||||
|
||||
make_sales_return: function() {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.make_sales_return",
|
||||
frm: cur_frm
|
||||
})
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// for backward compatibility: combine new and previous states
|
||||
@@ -283,16 +284,6 @@ cur_frm.cscript.make_bank_entry = function() {
|
||||
});
|
||||
}
|
||||
|
||||
cur_frm.fields_dict.debit_to.get_query = function(doc) {
|
||||
return{
|
||||
filters: {
|
||||
'report_type': 'Balance Sheet',
|
||||
'is_group': 0,
|
||||
'company': doc.company
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.fields_dict.cash_bank_account.get_query = function(doc) {
|
||||
return {
|
||||
filters: [
|
||||
@@ -369,15 +360,15 @@ cur_frm.fields_dict["items"].grid.get_field("cost_center").get_query = function(
|
||||
}
|
||||
|
||||
cur_frm.cscript.income_account = function(doc, cdt, cdn) {
|
||||
cur_frm.cscript.copy_account_in_all_row(doc, cdt, cdn, "income_account");
|
||||
erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "income_account");
|
||||
}
|
||||
|
||||
cur_frm.cscript.expense_account = function(doc, cdt, cdn) {
|
||||
cur_frm.cscript.copy_account_in_all_row(doc, cdt, cdn, "expense_account");
|
||||
erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "expense_account");
|
||||
}
|
||||
|
||||
cur_frm.cscript.cost_center = function(doc, cdt, cdn) {
|
||||
cur_frm.cscript.copy_account_in_all_row(doc, cdt, cdn, "cost_center");
|
||||
erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "cost_center");
|
||||
}
|
||||
|
||||
cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
|
||||
@@ -399,4 +390,4 @@ cur_frm.set_query("debit_to", function(doc) {
|
||||
['Account', 'account_type', '=', 'Receivable']
|
||||
]
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -21,7 +21,7 @@
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "naming_series",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "SINV-",
|
||||
"options": "SINV-\nSINV-RET-",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
@@ -47,7 +47,7 @@
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Name",
|
||||
"label": "Customer Name",
|
||||
"oldfieldname": "customer_name",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
@@ -156,7 +156,7 @@
|
||||
"oldfieldtype": "Date",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 1,
|
||||
"reqd": 0,
|
||||
"search_index": 0
|
||||
},
|
||||
{
|
||||
@@ -169,6 +169,28 @@
|
||||
"print_hide": 1,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "is_return",
|
||||
"fieldtype": "Check",
|
||||
"label": "Is Return",
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "is_return",
|
||||
"fieldname": "return_against",
|
||||
"fieldtype": "Link",
|
||||
"label": "Return Against Sales Invoice",
|
||||
"no_copy": 0,
|
||||
"options": "Sales Invoice",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "shipping_address_name",
|
||||
"fieldtype": "Link",
|
||||
@@ -322,9 +344,9 @@
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "sales_bom_help",
|
||||
"fieldname": "product_bundle_help",
|
||||
"fieldtype": "HTML",
|
||||
"label": "Sales BOM Help",
|
||||
"label": "Product Bundle Help",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 0
|
||||
@@ -605,7 +627,7 @@
|
||||
"label": "Total Advance",
|
||||
"oldfieldname": "total_advance",
|
||||
"oldfieldtype": "Currency",
|
||||
"options": "",
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
@@ -618,7 +640,7 @@
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "outstanding_amount",
|
||||
"oldfieldtype": "Currency",
|
||||
"options": "currency",
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
@@ -671,7 +693,7 @@
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "paid_amount",
|
||||
"oldfieldtype": "Currency",
|
||||
"options": "currency",
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 0
|
||||
@@ -711,7 +733,7 @@
|
||||
"fieldtype": "Currency",
|
||||
"label": "Write Off Amount",
|
||||
"no_copy": 1,
|
||||
"options": "currency",
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 0
|
||||
@@ -1253,7 +1275,7 @@
|
||||
"icon": "icon-file-text",
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"modified": "2015-06-22 06:39:22.072544",
|
||||
"modified": "2015-07-24 11:48:07.544569",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
import frappe.defaults
|
||||
from frappe.utils import cint, cstr, flt
|
||||
from frappe.utils import cint, flt
|
||||
from frappe import _, msgprint, throw
|
||||
from erpnext.accounts.party import get_party_account, get_due_date
|
||||
from erpnext.controllers.stock_controller import update_gl_entries_after
|
||||
@@ -66,6 +66,7 @@ class SalesInvoice(SellingController):
|
||||
self.validate_c_form()
|
||||
self.validate_time_logs_are_submitted()
|
||||
self.validate_multiple_billing("Delivery Note", "dn_detail", "amount", "items")
|
||||
self.update_packing_list()
|
||||
|
||||
def on_submit(self):
|
||||
super(SalesInvoice, self).on_submit()
|
||||
@@ -80,14 +81,16 @@ class SalesInvoice(SellingController):
|
||||
|
||||
self.check_prev_docstatus()
|
||||
|
||||
self.update_status_updater_args()
|
||||
self.update_prevdoc_status()
|
||||
self.update_billing_status_for_zero_amount_refdoc("Sales Order")
|
||||
self.check_credit_limit()
|
||||
if not self.is_return:
|
||||
self.update_status_updater_args()
|
||||
self.update_prevdoc_status()
|
||||
self.update_billing_status_for_zero_amount_refdoc("Sales Order")
|
||||
self.check_credit_limit()
|
||||
|
||||
# this sequence because outstanding may get -ve
|
||||
self.make_gl_entries()
|
||||
|
||||
if not cint(self.is_pos) == 1:
|
||||
if not cint(self.is_pos) == 1 and not self.is_return:
|
||||
self.update_against_document_in_jv()
|
||||
|
||||
self.update_time_log_batch(self.name)
|
||||
@@ -104,9 +107,11 @@ class SalesInvoice(SellingController):
|
||||
from erpnext.accounts.utils import remove_against_link_from_jv
|
||||
remove_against_link_from_jv(self.doctype, self.name, "against_invoice")
|
||||
|
||||
self.update_status_updater_args()
|
||||
self.update_prevdoc_status()
|
||||
self.update_billing_status_for_zero_amount_refdoc("Sales Order")
|
||||
if not self.is_return:
|
||||
self.update_status_updater_args()
|
||||
self.update_prevdoc_status()
|
||||
self.update_billing_status_for_zero_amount_refdoc("Sales Order")
|
||||
|
||||
self.validate_c_form_on_cancel()
|
||||
|
||||
self.make_gl_entries_on_cancel()
|
||||
@@ -138,7 +143,7 @@ class SalesInvoice(SellingController):
|
||||
|
||||
if not self.debit_to:
|
||||
self.debit_to = get_party_account(self.company, self.customer, "Customer")
|
||||
if not self.due_date:
|
||||
if not self.due_date and self.customer:
|
||||
self.due_date = get_due_date(self.posting_date, "Customer", self.customer, self.company)
|
||||
|
||||
super(SalesInvoice, self).set_missing_values(for_validate)
|
||||
@@ -169,6 +174,7 @@ class SalesInvoice(SellingController):
|
||||
if pos:
|
||||
if not for_validate and not self.customer:
|
||||
self.customer = pos.customer
|
||||
self.mode_of_payment = pos.mode_of_payment
|
||||
# self.set_customer_defaults()
|
||||
|
||||
for fieldname in ('territory', 'naming_series', 'currency', 'taxes_and_charges', 'letter_head', 'tc_name',
|
||||
@@ -198,8 +204,9 @@ class SalesInvoice(SellingController):
|
||||
self.set_taxes()
|
||||
|
||||
def get_advances(self):
|
||||
super(SalesInvoice, self).get_advances(self.debit_to, "Customer", self.customer,
|
||||
"Sales Invoice Advance", "advances", "credit", "sales_order")
|
||||
if not self.is_return:
|
||||
super(SalesInvoice, self).get_advances(self.debit_to, "Customer", self.customer,
|
||||
"Sales Invoice Advance", "advances", "credit", "sales_order")
|
||||
|
||||
def get_company_abbr(self):
|
||||
return frappe.db.sql("select abbr from tabCompany where name=%s", self.company)[0][0]
|
||||
@@ -242,12 +249,10 @@ class SalesInvoice(SellingController):
|
||||
def validate_fixed_asset_account(self):
|
||||
"""Validate Fixed Asset and whether Income Account Entered Exists"""
|
||||
for d in self.get('items'):
|
||||
item = frappe.db.sql("""select name,is_asset_item,is_sales_item from `tabItem`
|
||||
where name = %s""", d.item_code)
|
||||
acc = frappe.db.sql("""select account_type from `tabAccount`
|
||||
where name = %s and docstatus != 2""", d.income_account)
|
||||
if item and item[0][1] == 'Yes' and acc and acc[0][0] != 'Fixed Asset':
|
||||
msgprint(_("Account {0} must be of type 'Fixed Asset' as Item {1} is an Asset Item").format(acc[0][0], d.item_code), raise_exception=True)
|
||||
is_asset_item = frappe.db.get_value("Item", d.item_code, "is_asset_item")
|
||||
account_type = frappe.db.get_value("Account", d.income_account, "account_type")
|
||||
if is_asset_item == 1 and account_type != 'Fixed Asset':
|
||||
msgprint(_("Account {0} must be of type 'Fixed Asset' as Item {1} is an Asset Item").format(d.income_account, d.item_code), raise_exception=True)
|
||||
|
||||
def validate_with_previous_doc(self):
|
||||
super(SalesInvoice, self).validate_with_previous_doc({
|
||||
@@ -263,20 +268,11 @@ class SalesInvoice(SellingController):
|
||||
},
|
||||
})
|
||||
|
||||
if cint(frappe.defaults.get_global_default('maintain_same_sales_rate')):
|
||||
super(SalesInvoice, self).validate_with_previous_doc({
|
||||
"Sales Order Item": {
|
||||
"ref_dn_field": "so_detail",
|
||||
"compare_fields": [["rate", "="]],
|
||||
"is_child_table": True,
|
||||
"allow_duplicate_prev_row_id": True
|
||||
},
|
||||
"Delivery Note Item": {
|
||||
"ref_dn_field": "dn_detail",
|
||||
"compare_fields": [["rate", "="]],
|
||||
"is_child_table": True
|
||||
}
|
||||
})
|
||||
if cint(frappe.db.get_single_value('Selling Settings', 'maintain_same_sales_rate')):
|
||||
self.validate_rate_with_reference_doc([
|
||||
["Sales Order", "sales_order", "so_detail"],
|
||||
["Delivery Note", "delivery_note", "dn_detail"]
|
||||
])
|
||||
|
||||
def set_against_income_account(self):
|
||||
"""Set against account for debit to account"""
|
||||
@@ -293,11 +289,13 @@ class SalesInvoice(SellingController):
|
||||
|
||||
def so_dn_required(self):
|
||||
"""check in manage account if sales order / delivery note required or not."""
|
||||
if self.is_return:
|
||||
return
|
||||
dic = {'Sales Order':'so_required','Delivery Note':'dn_required'}
|
||||
for i in dic:
|
||||
if frappe.db.get_value('Selling Settings', None, dic[i]) == 'Yes':
|
||||
for d in self.get('items'):
|
||||
if frappe.db.get_value('Item', d.item_code, 'is_stock_item') == 'Yes' \
|
||||
if frappe.db.get_value('Item', d.item_code, 'is_stock_item') == 1 \
|
||||
and not d.get(i.lower().replace(' ','_')):
|
||||
msgprint(_("{0} is mandatory for Item {1}").format(i,d.item_code), raise_exception=1)
|
||||
|
||||
@@ -366,6 +364,13 @@ class SalesInvoice(SellingController):
|
||||
d.actual_qty = bin and flt(bin[0]['actual_qty']) or 0
|
||||
d.projected_qty = bin and flt(bin[0]['projected_qty']) or 0
|
||||
|
||||
def update_packing_list(self):
|
||||
if cint(self.update_stock) == 1:
|
||||
from erpnext.stock.doctype.packed_item.packed_item import make_packing_list
|
||||
make_packing_list(self, 'items')
|
||||
else:
|
||||
self.set('packed_items', [])
|
||||
|
||||
|
||||
def get_warehouse(self):
|
||||
user_pos_profile = frappe.db.sql("""select name, warehouse from `tabPOS Profile`
|
||||
@@ -384,20 +389,6 @@ class SalesInvoice(SellingController):
|
||||
return warehouse
|
||||
|
||||
def on_update(self):
|
||||
if cint(self.update_stock) == 1:
|
||||
# Set default warehouse from POS Profile
|
||||
if cint(self.is_pos) == 1:
|
||||
w = self.get_warehouse()
|
||||
if w:
|
||||
for d in self.get('items'):
|
||||
if not d.warehouse:
|
||||
d.warehouse = cstr(w)
|
||||
|
||||
from erpnext.stock.doctype.packed_item.packed_item import make_packing_list
|
||||
make_packing_list(self, 'items')
|
||||
else:
|
||||
self.set('packed_items', [])
|
||||
|
||||
if cint(self.is_pos) == 1:
|
||||
if flt(self.paid_amount) == 0:
|
||||
if self.cash_bank_account:
|
||||
@@ -427,13 +418,19 @@ class SalesInvoice(SellingController):
|
||||
def update_stock_ledger(self):
|
||||
sl_entries = []
|
||||
for d in self.get_item_list():
|
||||
if frappe.db.get_value("Item", d.item_code, "is_stock_item") == "Yes" \
|
||||
and d.warehouse:
|
||||
if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1 and d.warehouse and flt(d['qty']):
|
||||
self.update_reserved_qty(d)
|
||||
|
||||
incoming_rate = 0
|
||||
if cint(self.is_return) and self.return_against and self.docstatus==1:
|
||||
incoming_rate = self.get_incoming_rate_for_sales_return(d.item_code,
|
||||
self.return_against)
|
||||
|
||||
sl_entries.append(self.get_sl_entries(d, {
|
||||
"actual_qty": -1*flt(d.qty),
|
||||
"stock_uom": frappe.db.get_value("Item", d.item_code, "stock_uom")
|
||||
"stock_uom": frappe.db.get_value("Item", d.item_code, "stock_uom"),
|
||||
"incoming_rate": incoming_rate
|
||||
}))
|
||||
|
||||
self.make_sl_entries(sl_entries)
|
||||
|
||||
def make_gl_entries(self, repost_future_gle=True):
|
||||
@@ -443,8 +440,7 @@ class SalesInvoice(SellingController):
|
||||
from erpnext.accounts.general_ledger import make_gl_entries
|
||||
|
||||
# if POS and amount is written off, there's no outstanding and hence no need to update it
|
||||
update_outstanding = cint(self.is_pos) and self.write_off_account \
|
||||
and 'No' or 'Yes'
|
||||
update_outstanding = "No" if (cint(self.is_pos) or self.write_off_account) else "Yes"
|
||||
|
||||
make_gl_entries(gl_entries, cancel=(self.docstatus == 2),
|
||||
update_outstanding=update_outstanding, merge_entries=False)
|
||||
@@ -492,7 +488,7 @@ class SalesInvoice(SellingController):
|
||||
"against": self.against_income_account,
|
||||
"debit": self.base_grand_total,
|
||||
"remarks": self.remarks,
|
||||
"against_voucher": self.name,
|
||||
"against_voucher": self.return_against if cint(self.is_return) else self.name,
|
||||
"against_voucher_type": self.doctype
|
||||
})
|
||||
)
|
||||
@@ -527,7 +523,6 @@ class SalesInvoice(SellingController):
|
||||
# expense account gl entries
|
||||
if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")) \
|
||||
and cint(self.update_stock):
|
||||
|
||||
gl_entries += super(SalesInvoice, self).get_gl_entries()
|
||||
|
||||
def make_pos_gl_entries(self, gl_entries):
|
||||
@@ -541,7 +536,7 @@ class SalesInvoice(SellingController):
|
||||
"against": self.cash_bank_account,
|
||||
"credit": self.paid_amount,
|
||||
"remarks": self.remarks,
|
||||
"against_voucher": self.name,
|
||||
"against_voucher": self.return_against if cint(self.is_return) else self.name,
|
||||
"against_voucher_type": self.doctype,
|
||||
})
|
||||
)
|
||||
@@ -565,7 +560,7 @@ class SalesInvoice(SellingController):
|
||||
"against": self.write_off_account,
|
||||
"credit": self.write_off_amount,
|
||||
"remarks": self.remarks,
|
||||
"against_voucher": self.name,
|
||||
"against_voucher": self.return_against if cint(self.is_return) else self.name,
|
||||
"against_voucher_type": self.doctype,
|
||||
})
|
||||
)
|
||||
@@ -659,3 +654,9 @@ def make_delivery_note(source_name, target_doc=None):
|
||||
}, target_doc, set_missing_values)
|
||||
|
||||
return doclist
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_sales_return(source_name, target_doc=None):
|
||||
from erpnext.controllers.sales_and_purchase_return import make_return_doc
|
||||
return make_return_doc("Sales Invoice", source_name, target_doc)
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
// render
|
||||
frappe.listview_settings['Sales Invoice'] = {
|
||||
add_fields: ["customer", "customer_name", "base_grand_total", "outstanding_amount", "due_date", "company",
|
||||
"currency"],
|
||||
"currency", "is_return"],
|
||||
get_indicator: function(doc) {
|
||||
if(flt(doc.outstanding_amount)==0) {
|
||||
if(cint(doc.is_return)==1) {
|
||||
return [__("Return"), "darkgrey", "is_return,=,1"];
|
||||
} else if(flt(doc.outstanding_amount)==0) {
|
||||
return [__("Paid"), "green", "outstanding_amount,=,0"]
|
||||
} else if (flt(doc.outstanding_amount) > 0 && doc.due_date > frappe.datetime.get_today()) {
|
||||
return [__("Unpaid"), "orange", "outstanding_amount,>,0|due_date,>,Today"]
|
||||
|
||||
@@ -4,11 +4,9 @@ from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
import unittest, copy
|
||||
import time
|
||||
from erpnext.accounts.utils import get_stock_and_account_difference
|
||||
from frappe.utils import nowdate, add_days, flt
|
||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry, get_qty_after_transaction
|
||||
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
|
||||
from erpnext.projects.doctype.time_log_batch.test_time_log_batch import *
|
||||
|
||||
|
||||
class TestSalesInvoice(unittest.TestCase):
|
||||
def make(self):
|
||||
@@ -402,32 +400,6 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
jv.cancel()
|
||||
self.assertEquals(frappe.db.get_value("Sales Invoice", w.name, "outstanding_amount"), 561.8)
|
||||
|
||||
def test_time_log_batch(self):
|
||||
delete_time_log_and_batch()
|
||||
time_log = create_time_log()
|
||||
tlb = create_time_log_batch(time_log)
|
||||
|
||||
tlb = frappe.get_doc("Time Log Batch", tlb.name)
|
||||
tlb.submit()
|
||||
|
||||
si = frappe.get_doc(frappe.copy_doc(test_records[0]))
|
||||
si.get("items")[0].time_log_batch = tlb.name
|
||||
si.insert()
|
||||
si.submit()
|
||||
|
||||
self.assertEquals(frappe.db.get_value("Time Log Batch", tlb.name, "status"), "Billed")
|
||||
|
||||
self.assertEquals(frappe.db.get_value("Time Log", time_log, "status"), "Billed")
|
||||
|
||||
si.cancel()
|
||||
|
||||
self.assertEquals(frappe.db.get_value("Time Log Batch", tlb.name, "status"), "Submitted")
|
||||
|
||||
self.assertEquals(frappe.db.get_value("Time Log", time_log, "status"), "Batched for Billing")
|
||||
|
||||
frappe.delete_doc("Sales Invoice", si.name)
|
||||
delete_time_log_and_batch()
|
||||
|
||||
def test_sales_invoice_gl_entry_without_aii(self):
|
||||
set_perpetual_inventory(0)
|
||||
si = frappe.copy_doc(test_records[1])
|
||||
@@ -756,20 +728,84 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
|
||||
# hack! because stock ledger entires are already inserted and are not rolled back!
|
||||
self.assertRaises(SerialNoDuplicateError, si.cancel)
|
||||
|
||||
def test_invoice_due_date_against_customers_credit_days(self):
|
||||
# set customer's credit days
|
||||
frappe.db.set_value("Customer", "_Test Customer", "credit_days_based_on", "Fixed Days")
|
||||
frappe.db.set_value("Customer", "_Test Customer", "credit_days", 10)
|
||||
|
||||
si = create_sales_invoice()
|
||||
self.assertEqual(si.due_date, add_days(nowdate(), 10))
|
||||
|
||||
# set customer's credit days is last day of the next month
|
||||
frappe.db.set_value("Customer", "_Test Customer", "credit_days_based_on", "Last Day of the Next Month")
|
||||
|
||||
si1 = create_sales_invoice(posting_date="2015-07-05")
|
||||
self.assertEqual(si1.due_date, "2015-08-31")
|
||||
|
||||
def test_return_sales_invoice(self):
|
||||
set_perpetual_inventory()
|
||||
|
||||
make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, incoming_rate=100)
|
||||
|
||||
actual_qty_0 = get_qty_after_transaction()
|
||||
|
||||
si = create_sales_invoice(qty=5, rate=500, update_stock=1)
|
||||
|
||||
actual_qty_1 = get_qty_after_transaction()
|
||||
self.assertEquals(actual_qty_0 - 5, actual_qty_1)
|
||||
|
||||
# outgoing_rate
|
||||
outgoing_rate = frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Sales Invoice",
|
||||
"voucher_no": si.name}, "stock_value_difference") / 5
|
||||
|
||||
# return entry
|
||||
si1 = create_sales_invoice(is_return=1, return_against=si.name, qty=-2, rate=500, update_stock=1)
|
||||
|
||||
actual_qty_2 = get_qty_after_transaction()
|
||||
|
||||
self.assertEquals(actual_qty_1 + 2, actual_qty_2)
|
||||
|
||||
incoming_rate, stock_value_difference = frappe.db.get_value("Stock Ledger Entry",
|
||||
{"voucher_type": "Sales Invoice", "voucher_no": si1.name},
|
||||
["incoming_rate", "stock_value_difference"])
|
||||
|
||||
self.assertEquals(flt(incoming_rate, 3), abs(flt(outgoing_rate, 3)))
|
||||
|
||||
|
||||
# Check gl entry
|
||||
gle_warehouse_amount = frappe.db.get_value("GL Entry", {"voucher_type": "Sales Invoice",
|
||||
"voucher_no": si1.name, "account": "_Test Warehouse - _TC"}, "debit")
|
||||
|
||||
self.assertEquals(gle_warehouse_amount, stock_value_difference)
|
||||
|
||||
party_credited = frappe.db.get_value("GL Entry", {"voucher_type": "Sales Invoice",
|
||||
"voucher_no": si1.name, "account": "Debtors - _TC", "party": "_Test Customer"}, "credit")
|
||||
|
||||
self.assertEqual(party_credited, 1000)
|
||||
|
||||
# Check outstanding amount
|
||||
self.assertFalse(si1.outstanding_amount)
|
||||
self.assertEqual(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"), 1500)
|
||||
|
||||
set_perpetual_inventory(0)
|
||||
|
||||
|
||||
def create_sales_invoice(**args):
|
||||
si = frappe.new_doc("Sales Invoice")
|
||||
args = frappe._dict(args)
|
||||
if args.posting_date:
|
||||
si.posting_date = args.posting_date
|
||||
if args.posting_time:
|
||||
si.posting_time = args.posting_time
|
||||
si.posting_date = args.posting_date or nowdate()
|
||||
|
||||
si.company = args.company or "_Test Company"
|
||||
si.customer = args.customer or "_Test Customer"
|
||||
si.debit_to = args.debit_to or "Debtors - _TC"
|
||||
si.update_stock = args.update_stock
|
||||
si.is_pos = args.is_pos
|
||||
si.is_return = args.is_return
|
||||
si.return_against = args.return_against
|
||||
si.currency="INR"
|
||||
si.conversion_rate = 1
|
||||
|
||||
si.append("items", {
|
||||
"item_code": args.item or args.item_code or "_Test Item",
|
||||
|
||||
@@ -5,21 +5,25 @@ from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
from erpnext.controllers.accounts_controller import validate_taxes_and_charges, validate_inclusive_tax
|
||||
from frappe.utils.nestedset import get_root_of
|
||||
|
||||
class SalesTaxesandChargesTemplate(Document):
|
||||
def validate(self):
|
||||
if self.is_default == 1:
|
||||
frappe.db.sql("""update `tabSales Taxes and Charges Template`
|
||||
set is_default = 0
|
||||
where ifnull(is_default,0) = 1
|
||||
and name != %s and company = %s""",
|
||||
(self.name, self.company))
|
||||
valdiate_taxes_and_charges_template(self)
|
||||
|
||||
# at least one territory
|
||||
self.validate_table_has_rows("territories")
|
||||
def valdiate_taxes_and_charges_template(doc):
|
||||
if not doc.is_default and not frappe.get_all(doc.doctype, filters={"is_default": 1}):
|
||||
doc.is_default = 1
|
||||
|
||||
for tax in self.get("taxes"):
|
||||
validate_taxes_and_charges(tax)
|
||||
validate_inclusive_tax(tax, self)
|
||||
if doc.is_default == 1:
|
||||
frappe.db.sql("""update `tab{0}` set is_default = 0
|
||||
where ifnull(is_default,0) = 1 and name != %s and company = %s""".format(doc.doctype),
|
||||
(doc.name, doc.company))
|
||||
|
||||
if doc.meta.get_field("territories"):
|
||||
if not doc.territories:
|
||||
doc.append("territories", {"territory": get_root_of("Territory") })
|
||||
|
||||
for tax in doc.get("taxes"):
|
||||
validate_taxes_and_charges(tax)
|
||||
validate_inclusive_tax(tax, doc)
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
import datetime
|
||||
from frappe import _, msgprint, scrub
|
||||
from frappe.defaults import get_user_permissions
|
||||
from frappe.utils import add_days, getdate, formatdate, flt
|
||||
from frappe.utils import add_days, getdate, formatdate, flt, get_first_day, date_diff, nowdate
|
||||
from erpnext.utilities.doctype.address.address import get_address_display
|
||||
from erpnext.utilities.doctype.contact.contact import get_contact_details
|
||||
|
||||
@@ -73,9 +74,17 @@ def set_contact_details(out, party, party_type):
|
||||
{party_type.lower(): party.name, "is_primary_contact":1}, "name")
|
||||
|
||||
if not out.contact_person:
|
||||
return
|
||||
|
||||
out.update(get_contact_details(out.contact_person))
|
||||
out.update({
|
||||
"contact_person": None,
|
||||
"contact_display": None,
|
||||
"contact_email": None,
|
||||
"contact_mobile": None,
|
||||
"contact_phone": None,
|
||||
"contact_designation": None,
|
||||
"contact_department": None
|
||||
})
|
||||
else:
|
||||
out.update(get_contact_details(out.contact_person))
|
||||
|
||||
def set_other_values(out, party, party_type):
|
||||
# copy
|
||||
@@ -158,43 +167,54 @@ def get_party_account(company, party, party_type):
|
||||
|
||||
return account
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_due_date(posting_date, party_type, party, company):
|
||||
"""Set Due Date = Posting Date + Credit Days"""
|
||||
due_date = None
|
||||
if posting_date:
|
||||
credit_days = get_credit_days(party_type, party, company)
|
||||
due_date = add_days(posting_date, credit_days) if credit_days else posting_date
|
||||
|
||||
if posting_date and party:
|
||||
due_date = posting_date
|
||||
if party_type=="Customer":
|
||||
credit_days_based_on, credit_days = get_credit_days(party_type, party, company)
|
||||
if credit_days_based_on == "Fixed Days" and credit_days:
|
||||
due_date = add_days(posting_date, credit_days)
|
||||
elif credit_days_based_on == "Last Day of the Next Month":
|
||||
due_date = (get_first_day(posting_date, 0, 2) + datetime.timedelta(-1)).strftime("%Y-%m-%d")
|
||||
else:
|
||||
credit_days = get_credit_days(party_type, party, company)
|
||||
if credit_days:
|
||||
due_date = add_days(posting_date, credit_days)
|
||||
|
||||
return due_date
|
||||
|
||||
def get_credit_days(party_type, party, company):
|
||||
if not party:
|
||||
return None
|
||||
|
||||
party_group_doctype = "Customer Group" if party_type=="Customer" else "Supplier Type"
|
||||
credit_days, party_group = frappe.db.get_value(party_type, party, ["credit_days", frappe.scrub(party_group_doctype)])
|
||||
|
||||
if not credit_days:
|
||||
credit_days = frappe.db.get_value(party_group_doctype, party_group, "credit_days") or \
|
||||
frappe.db.get_value("Company", company, "credit_days")
|
||||
|
||||
return credit_days
|
||||
|
||||
def validate_due_date(posting_date, due_date, party_type, party, company):
|
||||
credit_days = get_credit_days(party_type, party, company)
|
||||
|
||||
posting_date, due_date = getdate(posting_date), getdate(due_date)
|
||||
diff = (due_date - posting_date).days
|
||||
|
||||
if diff < 0:
|
||||
frappe.throw(_("Due Date cannot be before Posting Date"))
|
||||
elif credit_days is not None and diff > flt(credit_days):
|
||||
is_credit_controller = frappe.db.get_value("Accounts Settings", None,
|
||||
"credit_controller") in frappe.get_roles()
|
||||
|
||||
if is_credit_controller:
|
||||
msgprint(_("Note: Due / Reference Date exceeds allowed customer credit days by {0} day(s)")
|
||||
.format(diff - flt(credit_days)))
|
||||
if party_type and party:
|
||||
if party_type == "Customer":
|
||||
credit_days_based_on, credit_days, customer_group = \
|
||||
frappe.db.get_value(party_type, party, ["credit_days_based_on", "credit_days", "customer_group"])
|
||||
|
||||
if not credit_days_based_on:
|
||||
credit_days_based_on, credit_days = \
|
||||
frappe.db.get_value("Customer Group", customer_group, ["credit_days_based_on", "credit_days"]) \
|
||||
or frappe.db.get_value("Company", company, ["credit_days_based_on", "credit_days"])
|
||||
|
||||
return credit_days_based_on, credit_days
|
||||
else:
|
||||
max_due_date = formatdate(add_days(posting_date, credit_days))
|
||||
frappe.throw(_("Due / Reference Date cannot be after {0}").format(max_due_date))
|
||||
credit_days, supplier_type = frappe.db.get_value(party_type, party, ["credit_days", "supplier_type"])
|
||||
if not credit_days:
|
||||
credit_days = frappe.db.get_value("Supplier Type", supplier_type, "credit_days") \
|
||||
or frappe.db.get_value("Company", company, "credit_days")
|
||||
|
||||
return credit_days
|
||||
|
||||
def validate_due_date(posting_date, due_date, party_type, party, company):
|
||||
if getdate(due_date) < getdate(posting_date):
|
||||
frappe.throw(_("Due Date cannot be before Posting Date"))
|
||||
else:
|
||||
default_due_date = get_due_date(posting_date, party_type, party, company)
|
||||
if default_due_date != posting_date and getdate(due_date) > getdate(default_due_date):
|
||||
is_credit_controller = frappe.db.get_single_value("Accounts Settings", "credit_controller") in frappe.get_roles()
|
||||
if is_credit_controller:
|
||||
msgprint(_("Note: Due / Reference Date exceeds allowed customer credit days by {0} day(s)")
|
||||
.format(date_diff(due_date, default_due_date)))
|
||||
else:
|
||||
frappe.throw(_("Due / Reference Date cannot be after {0}").format(formatdate(default_due_date)))
|
||||
@@ -1,19 +1,19 @@
|
||||
{
|
||||
"creation": "2014-08-28 11:11:39.796473",
|
||||
"disabled": 0,
|
||||
"doc_type": "Journal Entry",
|
||||
"docstatus": 0,
|
||||
"doctype": "Print Format",
|
||||
"html": "{%- from \"templates/print_formats/standard_macros.html\" import add_header -%}\n\n<div class=\"page-break\">\n {%- if not doc.get(\"print_heading\") and not doc.get(\"select_print_heading\") \n and doc.set(\"select_print_heading\", _(\"Credit Note\")) -%}{%- endif -%}\n {{ add_header(0, 1, doc, letter_head, no_letterhead) }}\n\n {%- for label, value in (\n (_(\"Credit To\"), doc.pay_to_recd_from),\n (_(\"Date\"), frappe.utils.formatdate(doc.voucher_date)),\n (_(\"Amount\"), \"<strong>\" + doc.get_formatted(\"total_amount\") + \"</strong><br>\" + (doc.total_amount_in_words or \"\") + \"<br>\"),\n (_(\"Remarks\"), doc.remark)\n ) -%}\n\n <div class=\"row\">\n <div class=\"col-xs-3\"><label class=\"text-right\">{{ label }}</label></div>\n <div class=\"col-xs-9\">{{ value }}</div>\n </div>\n\n {%- endfor -%}\n\n <hr>\n <br>\n <p class=\"strong\">\n {{ _(\"For\") }} {{ doc.company }},<br>\n <br>\n <br>\n <br>\n {{ _(\"Authorized Signatory\") }}\n </p>\n</div>\n\n\n",
|
||||
"idx": 2,
|
||||
"modified": "2015-01-12 11:02:25.716825",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Credit Note",
|
||||
"owner": "Administrator",
|
||||
"parent": "Journal Entry",
|
||||
"parentfield": "__print_formats",
|
||||
"parenttype": "DocType",
|
||||
"print_format_type": "Server",
|
||||
"creation": "2014-08-28 11:11:39.796473",
|
||||
"custom_format": 0,
|
||||
"disabled": 0,
|
||||
"doc_type": "Journal Entry",
|
||||
"docstatus": 0,
|
||||
"doctype": "Print Format",
|
||||
"html": "{%- from \"templates/print_formats/standard_macros.html\" import add_header -%}\n\n<div class=\"page-break\">\n {%- if not doc.get(\"print_heading\") and not doc.get(\"select_print_heading\") \n and doc.set(\"select_print_heading\", _(\"Credit Note\")) -%}{%- endif -%}\n {{ add_header(0, 1, doc, letter_head, no_letterhead) }}\n\n {%- for label, value in (\n (_(\"Credit To\"), doc.pay_to_recd_from),\n (_(\"Date\"), frappe.utils.formatdate(doc.voucher_date)),\n (_(\"Amount\"), \"<strong>\" + doc.get_formatted(\"total_amount\") + \"</strong><br>\" + (doc.total_amount_in_words or \"\") + \"<br>\"),\n (_(\"Remarks\"), doc.remark)\n ) -%}\n\n <div class=\"row\">\n <div class=\"col-xs-3\"><label class=\"text-right\">{{ label }}</label></div>\n <div class=\"col-xs-9\">{{ value }}</div>\n </div>\n\n {%- endfor -%}\n\n <hr>\n <br>\n <p class=\"strong\">\n {{ _(\"For\") }} {{ doc.company }},<br>\n <br>\n <br>\n <br>\n {{ _(\"Authorized Signatory\") }}\n </p>\n</div>\n\n\n",
|
||||
"idx": 2,
|
||||
"modified": "2015-07-22 17:42:01.560817",
|
||||
"modified_by": "Administrator",
|
||||
"name": "Credit Note",
|
||||
"owner": "Administrator",
|
||||
"parent": "Journal Entry",
|
||||
"parentfield": "__print_formats",
|
||||
"parenttype": "DocType",
|
||||
"print_format_type": "Server",
|
||||
"standard": "Yes"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"creation": "2015-07-22 17:45:22.220567",
|
||||
"custom_format": 1,
|
||||
"disabled": 0,
|
||||
"doc_type": "Sales Invoice",
|
||||
"docstatus": 0,
|
||||
"doctype": "Print Format",
|
||||
"font": "Default",
|
||||
"html": "<style>\n\t.print-format table, .print-format tr, \n\t.print-format td, .print-format div, .print-format p {\n\t\tfont-family: Monospace;\n\t\tline-height: 200%;\n\t\tvertical-align: middle;\n\t}\n\t@media screen {\n\t\t.print-format {\n\t\t\twidth: 4in;\n\t\t\tpadding: 0.25in;\n\t\t\tmin-height: 6in;\n\t\t}\n\t}\n</style>\n\n<p class=\"text-center\">\n\t{{ doc.company }}<br>\n\t{{ doc.select_print_heading or _(\"Credit Note\") }}<br>\n</p>\n\n<hr>\n\n{%- for label, value in (\n (_(\"Receipt No\"), doc.name),\n (_(\"Date\"), doc.get_formatted(\"posting_date\")),\n\t(_(\"Customer\"), doc.customer_name),\n (_(\"Amount\"), \"<strong>\" + doc.get_formatted(\"grand_total\", absolute_value=True) + \"</strong><br>\" + (doc.in_words or \"\")),\n\t(_(\"Against\"), doc.return_against),\n (_(\"Remarks\"), doc.remarks)\n) -%}\n\n\t\t<div class=\"row\">\n\t\t <div class=\"col-xs-4\"><label class=\"text-right\">{{ label }}</label></div>\n\t\t <div class=\"col-xs-8\">{{ value }}</div>\n\t\t</div>\n{%- endfor -%}\n\n<hr>\n<br>\n<p class=\"strong\">\n {{ _(\"For\") }} {{ doc.company }},<br>\n <br>\n <br>\n <br>\n {{ _(\"Authorized Signatory\") }}\n</p>",
|
||||
"modified": "2015-07-22 17:45:22.220567",
|
||||
"modified_by": "Administrator",
|
||||
"name": "Credit Note - Negative Invoice",
|
||||
"owner": "Administrator",
|
||||
"print_format_builder": 0,
|
||||
"print_format_type": "Server",
|
||||
"standard": "Yes"
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
{
|
||||
"add_total_row": 1,
|
||||
"apply_user_permissions": 1,
|
||||
"creation": "2013-04-22 16:16:03",
|
||||
"docstatus": 0,
|
||||
"doctype": "Report",
|
||||
"idx": 1,
|
||||
"is_standard": "Yes",
|
||||
"modified": "2014-06-03 07:18:10.985354",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Accounts Payable",
|
||||
"owner": "Administrator",
|
||||
"ref_doctype": "Purchase Invoice",
|
||||
"report_name": "Accounts Payable",
|
||||
"report_type": "Report Builder"
|
||||
}
|
||||
"add_total_row": 1,
|
||||
"apply_user_permissions": 1,
|
||||
"creation": "2013-04-22 16:16:03",
|
||||
"docstatus": 0,
|
||||
"doctype": "Report",
|
||||
"idx": 1,
|
||||
"is_standard": "Yes",
|
||||
"modified": "2015-07-24 01:08:20.996267",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Accounts Payable",
|
||||
"owner": "Administrator",
|
||||
"ref_doctype": "Purchase Invoice",
|
||||
"report_name": "Accounts Payable",
|
||||
"report_type": "Script Report"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div style="margin-bottom: 7px;" class="text-center">
|
||||
{%= frappe.boot.letter_heads[frappe.defaults.get_default("letter_head")] %}
|
||||
{%= frappe.boot.letter_heads[filters.letter_head || frappe.defaults.get_default("letter_head")] %}
|
||||
</div>
|
||||
<h2 class="text-center">{%= __("Statement of Account") %}</h2>
|
||||
<h4 class="text-center">{%= (filters.party || filters.account) && ((filters.party || filters.account) + ", ") || "" %} {%= filters.company %}</h4>
|
||||
|
||||
@@ -53,13 +53,9 @@ frappe.query_reports["General Ledger"] = {
|
||||
{
|
||||
"fieldname":"party_type",
|
||||
"label": __("Party Type"),
|
||||
"fieldtype": "Link",
|
||||
"options": "DocType",
|
||||
"get_query": function() {
|
||||
return {
|
||||
filters: {"name": ["in", ["Customer", "Supplier"]]}
|
||||
}
|
||||
}
|
||||
"fieldtype": "Select",
|
||||
"options": ["", "Customer", "Supplier"],
|
||||
"default": ""
|
||||
},
|
||||
{
|
||||
"fieldname":"party",
|
||||
@@ -84,6 +80,13 @@ frappe.query_reports["General Ledger"] = {
|
||||
"fieldname":"group_by_account",
|
||||
"label": __("Group by Account"),
|
||||
"fieldtype": "Check",
|
||||
},
|
||||
{
|
||||
"fieldname":"letter_head",
|
||||
"label": __("Letter Head"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Letter Head",
|
||||
"default": frappe.defaults.get_default("letter_head"),
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -86,23 +86,23 @@ class GrossProfitGenerator(object):
|
||||
self.filters = frappe._dict(filters)
|
||||
self.load_invoice_items()
|
||||
self.load_stock_ledger_entries()
|
||||
self.load_sales_bom()
|
||||
self.load_product_bundle()
|
||||
self.load_non_stock_items()
|
||||
self.process()
|
||||
|
||||
def process(self):
|
||||
self.grouped = {}
|
||||
for row in self.si_list:
|
||||
if self.skip_row(row, self.sales_boms):
|
||||
if self.skip_row(row, self.product_bundles):
|
||||
continue
|
||||
|
||||
row.base_amount = flt(row.base_net_amount)
|
||||
|
||||
sales_boms = self.sales_boms.get(row.parenttype, {}).get(row.parent, frappe._dict())
|
||||
product_bundles = self.product_bundles.get(row.parenttype, {}).get(row.parent, frappe._dict())
|
||||
|
||||
# get buying amount
|
||||
if row.item_code in sales_boms:
|
||||
row.buying_amount = self.get_buying_amount_from_sales_bom(row, sales_boms[row.item_code])
|
||||
if row.item_code in product_bundles:
|
||||
row.buying_amount = self.get_buying_amount_from_product_bundle(row, product_bundles[row.item_code])
|
||||
else:
|
||||
row.buying_amount = self.get_buying_amount(row, row.item_code)
|
||||
|
||||
@@ -152,13 +152,13 @@ class GrossProfitGenerator(object):
|
||||
|
||||
self.grouped_data.append(new_row)
|
||||
|
||||
def skip_row(self, row, sales_boms):
|
||||
def skip_row(self, row, product_bundles):
|
||||
if self.filters.get("group_by") != "Invoice" and not row.get(scrub(self.filters.get("group_by"))):
|
||||
return True
|
||||
|
||||
def get_buying_amount_from_sales_bom(self, row, sales_bom):
|
||||
def get_buying_amount_from_product_bundle(self, row, product_bundle):
|
||||
buying_amount = 0.0
|
||||
for bom_item in sales_bom:
|
||||
for bom_item in product_bundle:
|
||||
if bom_item.get("parent_detail_docname")==row.item_row:
|
||||
buying_amount += self.get_buying_amount(row, bom_item.item_code)
|
||||
|
||||
@@ -174,12 +174,12 @@ class GrossProfitGenerator(object):
|
||||
return flt(row.qty) * item_rate
|
||||
|
||||
else:
|
||||
if row.update_stock or row.dn_detail:
|
||||
my_sle = self.sle.get((item_code, row.warehouse))
|
||||
if (row.update_stock or row.dn_detail) and my_sle:
|
||||
parenttype, parent, item_row = row.parenttype, row.parent, row.item_row
|
||||
if row.dn_detail:
|
||||
parenttype, parent, item_row = "Delivery Note", row.delivery_note, row.dn_detail
|
||||
|
||||
my_sle = self.sle.get((item_code, row.warehouse))
|
||||
|
||||
for i, sle in enumerate(my_sle):
|
||||
# find the stock valution rate from stock ledger entry
|
||||
if sle.voucher_type == parenttype and parent == sle.voucher_no and \
|
||||
@@ -215,7 +215,7 @@ class GrossProfitGenerator(object):
|
||||
if self.filters.to_date:
|
||||
conditions += " and posting_date <= %(to_date)s"
|
||||
|
||||
self.si_list = frappe.db.sql("""select item.parenttype, item.parent,
|
||||
self.si_list = frappe.db.sql("""select item.parenttype, item.parent,
|
||||
si.posting_date, si.posting_time, si.project_name, si.update_stock,
|
||||
si.customer, si.customer_group, si.territory,
|
||||
item.item_code, item.item_name, item.description, item.warehouse,
|
||||
@@ -246,15 +246,15 @@ class GrossProfitGenerator(object):
|
||||
|
||||
self.sle[(r.item_code, r.warehouse)].append(r)
|
||||
|
||||
def load_sales_bom(self):
|
||||
self.sales_boms = {}
|
||||
def load_product_bundle(self):
|
||||
self.product_bundles = {}
|
||||
|
||||
for d in frappe.db.sql("""select parenttype, parent, parent_item,
|
||||
item_code, warehouse, -1*qty as total_qty, parent_detail_docname
|
||||
from `tabPacked Item` where docstatus=1""", as_dict=True):
|
||||
self.sales_boms.setdefault(d.parenttype, frappe._dict()).setdefault(d.parent,
|
||||
self.product_bundles.setdefault(d.parenttype, frappe._dict()).setdefault(d.parent,
|
||||
frappe._dict()).setdefault(d.parent_item, []).append(d)
|
||||
|
||||
def load_non_stock_items(self):
|
||||
self.non_stock_items = frappe.db.sql_list("""select name from tabItem
|
||||
where ifnull(is_stock_item, 'No')='No'""")
|
||||
where is_stock_item=0""")
|
||||
|
||||
@@ -44,12 +44,12 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
||||
if(me.frm.doc.is_subcontracted == "Yes") {
|
||||
return{
|
||||
query: "erpnext.controllers.queries.item_query",
|
||||
filters:{ 'is_sub_contracted_item': 'Yes' }
|
||||
filters:{ 'is_sub_contracted_item': 1 }
|
||||
}
|
||||
} else {
|
||||
return{
|
||||
query: "erpnext.controllers.queries.item_query",
|
||||
filters: { 'is_purchase_item': 'Yes' }
|
||||
filters: { 'is_purchase_item': 1 }
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -70,10 +70,6 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
||||
erpnext.utils.get_address_display(this.frm);
|
||||
},
|
||||
|
||||
contact_person: function() {
|
||||
erpnext.utils.get_contact_details(this.frm);
|
||||
},
|
||||
|
||||
buying_price_list: function() {
|
||||
this.apply_price_list();
|
||||
},
|
||||
@@ -168,8 +164,10 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
||||
frappe.model.round_floats_in(this.frm.doc, ["base_grand_total", "total_advance", "write_off_amount"]);
|
||||
this.frm.doc.total_amount_to_pay = flt(this.frm.doc.base_grand_total - this.frm.doc.write_off_amount,
|
||||
precision("total_amount_to_pay"));
|
||||
this.frm.doc.outstanding_amount = flt(this.frm.doc.total_amount_to_pay - this.frm.doc.total_advance,
|
||||
precision("outstanding_amount"));
|
||||
if (!this.frm.doc.is_return) {
|
||||
this.frm.doc.outstanding_amount = flt(this.frm.doc.total_amount_to_pay - this.frm.doc.total_advance,
|
||||
precision("outstanding_amount"));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -41,8 +41,7 @@ class PurchaseCommon(BuyingController):
|
||||
def validate_for_items(self, obj):
|
||||
items = []
|
||||
for d in obj.get("items"):
|
||||
# validation for valid qty
|
||||
if flt(d.qty) < 0 or (d.parenttype != 'Purchase Receipt' and not flt(d.qty)):
|
||||
if not d.qty:
|
||||
frappe.throw(_("Please enter quantity for Item {0}").format(d.item_code))
|
||||
|
||||
# udpate with latest quantities
|
||||
@@ -57,24 +56,25 @@ class PurchaseCommon(BuyingController):
|
||||
d.set(x, f_lst[x])
|
||||
|
||||
item = frappe.db.sql("""select is_stock_item, is_purchase_item,
|
||||
is_sub_contracted_item, end_of_life from `tabItem` where name=%s""", d.item_code)
|
||||
is_sub_contracted_item, end_of_life from `tabItem` where name=%s""",
|
||||
d.item_code, as_dict=1)[0]
|
||||
|
||||
from erpnext.stock.doctype.item.item import validate_end_of_life
|
||||
validate_end_of_life(d.item_code, item[0][3])
|
||||
validate_end_of_life(d.item_code, item.end_of_life)
|
||||
|
||||
# validate stock item
|
||||
if item[0][0]=='Yes' and d.qty and not d.warehouse:
|
||||
if item.is_stock_item==1 and d.qty and not d.warehouse:
|
||||
frappe.throw(_("Warehouse is mandatory for stock Item {0} in row {1}").format(d.item_code, d.idx))
|
||||
|
||||
# validate purchase item
|
||||
if not (obj.doctype=="Material Request" and getattr(obj, "material_request_type", None)=="Material Transfer"):
|
||||
if item[0][1] != 'Yes' and item[0][2] != 'Yes':
|
||||
if item.is_purchase_item != 1 and item.is_sub_contracted_item != 1:
|
||||
frappe.throw(_("{0} must be a Purchased or Sub-Contracted Item in row {1}").format(d.item_code, d.idx))
|
||||
|
||||
items.append(cstr(d.item_code))
|
||||
if items and len(items) != len(set(items)):
|
||||
frappe.msgprint(_("Warning: Same item has been entered multiple times."))
|
||||
|
||||
|
||||
|
||||
def check_for_stopped_status(self, doctype, docname):
|
||||
stopped = frappe.db.sql("""select name from `tab%s` where name = %s and
|
||||
|
||||
@@ -11,39 +11,32 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
||||
this._super();
|
||||
// this.frm.dashboard.reset();
|
||||
|
||||
if(doc.docstatus == 1 && doc.status != 'Stopped'){
|
||||
// cur_frm.dashboard.add_progress(cint(doc.per_received) + __("% Received"),
|
||||
// doc.per_received);
|
||||
// cur_frm.dashboard.add_progress(cint(doc.per_billed) + __("% Billed"),
|
||||
// doc.per_billed);
|
||||
|
||||
if(doc.docstatus == 1 && doc.status != 'Stopped') {
|
||||
if(flt(doc.per_received, 2) < 100) {
|
||||
cur_frm.add_custom_button(__('Make Purchase Receipt'),
|
||||
this.make_purchase_receipt);
|
||||
cur_frm.add_custom_button(__('Make Purchase Receipt'), this.make_purchase_receipt);
|
||||
|
||||
if(doc.is_subcontracted==="Yes") {
|
||||
cur_frm.add_custom_button(__('Transfer Material to Supplier'),
|
||||
function() { me.make_stock_entry() });
|
||||
cur_frm.add_custom_button(__('Transfer Material to Supplier'), this.make_stock_entry);
|
||||
}
|
||||
}
|
||||
if(flt(doc.per_billed, 2) < 100)
|
||||
cur_frm.add_custom_button(__('Make Invoice'), this.make_purchase_invoice,
|
||||
frappe.boot.doctype_icons["Purchase Invoice"]);
|
||||
cur_frm.add_custom_button(__('Make Invoice'), this.make_purchase_invoice);
|
||||
|
||||
if(flt(doc.per_billed, 2) < 100 || doc.per_received < 100)
|
||||
cur_frm.add_custom_button(__('Stop'), cur_frm.cscript['Stop Purchase Order'],
|
||||
"icon-exclamation", "btn-default");
|
||||
cur_frm.add_custom_button(__('Stop'), cur_frm.cscript['Stop Purchase Order']);
|
||||
|
||||
} else if(doc.docstatus===0) {
|
||||
cur_frm.cscript.add_from_mappers();
|
||||
}
|
||||
|
||||
if(doc.docstatus == 1 && doc.status == 'Stopped')
|
||||
cur_frm.add_custom_button(__('Unstop Purchase Order'),
|
||||
cur_frm.cscript['Unstop Purchase Order'], "icon-check");
|
||||
cur_frm.add_custom_button(__('Unstop Purchase Order'), cur_frm.cscript['Unstop Purchase Order']);
|
||||
},
|
||||
|
||||
make_stock_entry: function() {
|
||||
var items = $.map(cur_frm.doc.items, function(d) { return d.bom ? d.item_code : false; }),
|
||||
me = this;
|
||||
var items = $.map(cur_frm.doc.items, function(d) { return d.bom ? d.item_code : false; });
|
||||
var me = this;
|
||||
|
||||
if(items.length===1) {
|
||||
me._make_stock_entry(items[0]);
|
||||
return;
|
||||
@@ -96,7 +89,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
||||
company: cur_frm.doc.company
|
||||
}
|
||||
})
|
||||
}, "icon-download", "btn-default"
|
||||
}
|
||||
);
|
||||
|
||||
cur_frm.add_custom_button(__('From Supplier Quotation'),
|
||||
@@ -110,7 +103,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
||||
company: cur_frm.doc.company
|
||||
}
|
||||
})
|
||||
}, "icon-download", "btn-default"
|
||||
}
|
||||
);
|
||||
|
||||
cur_frm.add_custom_button(__('For Supplier'),
|
||||
@@ -122,7 +115,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
||||
docstatus: ["!=", 2],
|
||||
}
|
||||
})
|
||||
}, "icon-download", "btn-default"
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
@@ -249,7 +242,7 @@ cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
|
||||
|
||||
|
||||
cur_frm.cscript.schedule_date = function(doc, cdt, cdn) {
|
||||
cur_frm.cscript.copy_account_in_all_row(doc, cdt, cdn, "schedule_date");
|
||||
erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "schedule_date");
|
||||
}
|
||||
|
||||
frappe.provide("erpnext.buying");
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Name",
|
||||
"label": "Supplier Name",
|
||||
"permlevel": 0,
|
||||
"read_only": 1
|
||||
},
|
||||
@@ -882,7 +882,7 @@
|
||||
"icon": "icon-file-text",
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"modified": "2015-06-22 07:30:36.259753",
|
||||
"modified": "2015-07-13 05:28:29.397705",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Purchase Order",
|
||||
@@ -899,7 +899,7 @@
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Material User",
|
||||
"role": "Stock User",
|
||||
"submit": 0,
|
||||
"write": 0
|
||||
},
|
||||
|
||||
@@ -153,7 +153,7 @@ class PurchaseOrder(BuyingController):
|
||||
item_wh_list = []
|
||||
for d in self.get("items"):
|
||||
if (not po_item_rows or d.name in po_item_rows) and [d.item_code, d.warehouse] not in item_wh_list \
|
||||
and frappe.db.get_value("Item", d.item_code, "is_stock_item") == "Yes" and d.warehouse:
|
||||
and frappe.db.get_value("Item", d.item_code, "is_stock_item") and d.warehouse:
|
||||
item_wh_list.append([d.item_code, d.warehouse])
|
||||
|
||||
for item_code, warehouse in item_wh_list:
|
||||
|
||||
@@ -5,7 +5,13 @@ frappe.listview_settings['Purchase Order'] = {
|
||||
if(doc.status==="Stopped") {
|
||||
return [__("Stopped"), "darkgrey", "status,=,Stopped"];
|
||||
} else if(flt(doc.per_received) < 100 && doc.status!=="Stopped") {
|
||||
return [__("Not Received"), "orange", "per_received,<,100|status,!=,Stopped"];
|
||||
if(flt(doc.per_billed) < 100) {
|
||||
return [__("To Receive and Bill"), "orange",
|
||||
"per_received,<,100|per_billed,<,100|status,!=,Stopped"];
|
||||
} else {
|
||||
return [__("To Receive"), "orange",
|
||||
"per_received,<,100|per_billed,=,100|status,!=,Stopped"];
|
||||
}
|
||||
} else if(flt(doc.per_received) == 100 && flt(doc.per_billed) < 100 && doc.status!=="Stopped") {
|
||||
return [__("To Bill"), "orange", "per_received,=,100|per_billed,<,100|status,!=,Stopped"];
|
||||
} else if(flt(doc.per_received) == 100 && flt(doc.per_billed) == 100 && doc.status!=="Stopped") {
|
||||
|
||||
@@ -1,247 +1,254 @@
|
||||
{
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "naming_series:",
|
||||
"creation": "2013-01-10 16:34:11",
|
||||
"description": "Supplier of Goods or Services.",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Master",
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "naming_series:",
|
||||
"creation": "2013-01-10 16:34:11",
|
||||
"description": "Supplier of Goods or Services.",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Master",
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "basic_info",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "",
|
||||
"oldfieldtype": "Section Break",
|
||||
"options": "icon-user",
|
||||
"fieldname": "basic_info",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "",
|
||||
"oldfieldtype": "Section Break",
|
||||
"options": "icon-user",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "naming_series",
|
||||
"fieldtype": "Select",
|
||||
"label": "Series",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "naming_series",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "SUPP-",
|
||||
"fieldname": "naming_series",
|
||||
"fieldtype": "Select",
|
||||
"label": "Series",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "naming_series",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "SUPP-",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "supplier_name",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 0,
|
||||
"label": "Supplier Name",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "supplier_name",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"fieldname": "supplier_name",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 0,
|
||||
"label": "Supplier Name",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "supplier_name",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break0",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"fieldname": "column_break0",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"width": "50%"
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "supplier_type",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Supplier Type",
|
||||
"oldfieldname": "supplier_type",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Supplier Type",
|
||||
"permlevel": 0,
|
||||
"fieldname": "supplier_type",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Supplier Type",
|
||||
"oldfieldname": "supplier_type",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Supplier Type",
|
||||
"permlevel": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"fieldname": "address_contacts",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Address & Contacts",
|
||||
"oldfieldtype": "Column Break",
|
||||
"options": "icon-map-marker",
|
||||
"fieldname": "is_frozen",
|
||||
"fieldtype": "Check",
|
||||
"label": "Is Frozen",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"fieldname": "address_contacts",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Address & Contacts",
|
||||
"oldfieldtype": "Column Break",
|
||||
"options": "icon-map-marker",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "address_html",
|
||||
"fieldtype": "HTML",
|
||||
"label": "Address HTML",
|
||||
"permlevel": 0,
|
||||
"fieldname": "address_html",
|
||||
"fieldtype": "HTML",
|
||||
"label": "Address HTML",
|
||||
"permlevel": 0,
|
||||
"read_only": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break1",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"fieldname": "column_break1",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"width": "50%"
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "contact_html",
|
||||
"fieldtype": "HTML",
|
||||
"label": "Contact HTML",
|
||||
"permlevel": 0,
|
||||
"fieldname": "contact_html",
|
||||
"fieldtype": "HTML",
|
||||
"label": "Contact HTML",
|
||||
"permlevel": 0,
|
||||
"read_only": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "default_payable_accounts",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Default Payable Accounts",
|
||||
"fieldname": "default_payable_accounts",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Default Payable Accounts",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"description": "Mention if non-standard receivable account applicable",
|
||||
"fieldname": "accounts",
|
||||
"fieldtype": "Table",
|
||||
"label": "Accounts",
|
||||
"options": "Party Account",
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"description": "Mention if non-standard receivable account applicable",
|
||||
"fieldname": "accounts",
|
||||
"fieldtype": "Table",
|
||||
"label": "Accounts",
|
||||
"options": "Party Account",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "more_info",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "More Info",
|
||||
"oldfieldtype": "Section Break",
|
||||
"options": "icon-file-text",
|
||||
"fieldname": "more_info",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "More Info",
|
||||
"oldfieldtype": "Section Break",
|
||||
"options": "icon-file-text",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "default_currency",
|
||||
"fieldtype": "Link",
|
||||
"ignore_user_permissions": 1,
|
||||
"label": "Default Currency",
|
||||
"no_copy": 1,
|
||||
"options": "Currency",
|
||||
"fieldname": "default_currency",
|
||||
"fieldtype": "Link",
|
||||
"ignore_user_permissions": 1,
|
||||
"label": "Default Currency",
|
||||
"no_copy": 1,
|
||||
"options": "Currency",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "default_price_list",
|
||||
"fieldtype": "Link",
|
||||
"ignore_user_permissions": 1,
|
||||
"label": "Price List",
|
||||
"options": "Price List",
|
||||
"fieldname": "default_price_list",
|
||||
"fieldtype": "Link",
|
||||
"ignore_user_permissions": 1,
|
||||
"label": "Price List",
|
||||
"options": "Price List",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "default_taxes_and_charges",
|
||||
"fieldtype": "Link",
|
||||
"ignore_user_permissions": 1,
|
||||
"label": "Taxes and Charges",
|
||||
"options": "Purchase Taxes and Charges Template",
|
||||
"fieldname": "default_taxes_and_charges",
|
||||
"fieldtype": "Link",
|
||||
"ignore_user_permissions": 1,
|
||||
"label": "Taxes and Charges",
|
||||
"options": "Purchase Taxes and Charges Template",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "credit_days",
|
||||
"fieldtype": "Int",
|
||||
"label": "Credit Days",
|
||||
"fieldname": "credit_days",
|
||||
"fieldtype": "Int",
|
||||
"label": "Credit Days",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break2",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"fieldname": "column_break2",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"width": "50%"
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "website",
|
||||
"fieldtype": "Data",
|
||||
"label": "Website",
|
||||
"oldfieldname": "website",
|
||||
"oldfieldtype": "Data",
|
||||
"fieldname": "website",
|
||||
"fieldtype": "Data",
|
||||
"label": "Website",
|
||||
"oldfieldname": "website",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"description": "Statutory info and other general information about your Supplier",
|
||||
"fieldname": "supplier_details",
|
||||
"fieldtype": "Text",
|
||||
"label": "Supplier Details",
|
||||
"oldfieldname": "supplier_details",
|
||||
"oldfieldtype": "Code",
|
||||
"description": "Statutory info and other general information about your Supplier",
|
||||
"fieldname": "supplier_details",
|
||||
"fieldtype": "Text",
|
||||
"label": "Supplier Details",
|
||||
"oldfieldname": "supplier_details",
|
||||
"oldfieldtype": "Code",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "communications",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 1,
|
||||
"label": "Communications",
|
||||
"options": "Communication",
|
||||
"permlevel": 0,
|
||||
"fieldname": "communications",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 1,
|
||||
"label": "Communications",
|
||||
"options": "Communication",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1
|
||||
}
|
||||
],
|
||||
"icon": "icon-user",
|
||||
"idx": 1,
|
||||
"modified": "2015-02-24 17:35:03.821319",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Supplier",
|
||||
"owner": "Administrator",
|
||||
],
|
||||
"icon": "icon-user",
|
||||
"idx": 1,
|
||||
"modified": "2015-07-17 09:39:05.318826",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Supplier",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Purchase User"
|
||||
},
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Purchase Manager",
|
||||
"submit": 0,
|
||||
"amend": 0,
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Purchase Manager",
|
||||
"submit": 0,
|
||||
"write": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Purchase Master Manager",
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"amend": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Purchase Master Manager",
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"apply_user_permissions": 1,
|
||||
"permlevel": 0,
|
||||
"read": 1,
|
||||
"role": "Material User"
|
||||
},
|
||||
"apply_user_permissions": 1,
|
||||
"permlevel": 0,
|
||||
"read": 1,
|
||||
"role": "Stock User"
|
||||
},
|
||||
{
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Material Manager"
|
||||
},
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Stock Manager"
|
||||
},
|
||||
{
|
||||
"apply_user_permissions": 1,
|
||||
"permlevel": 0,
|
||||
"read": 1,
|
||||
"apply_user_permissions": 1,
|
||||
"permlevel": 0,
|
||||
"read": 1,
|
||||
"role": "Accounts User"
|
||||
},
|
||||
},
|
||||
{
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts Manager"
|
||||
}
|
||||
],
|
||||
"search_fields": "supplier_name, supplier_type",
|
||||
],
|
||||
"search_fields": "supplier_name, supplier_type",
|
||||
"title_field": "supplier_name"
|
||||
}
|
||||
}
|
||||
@@ -660,7 +660,7 @@
|
||||
"icon": "icon-shopping-cart",
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"modified": "2015-06-15 15:39:08.954248",
|
||||
"modified": "2015-07-13 05:28:30.252636",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Supplier Quotation",
|
||||
@@ -723,7 +723,7 @@
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Material User",
|
||||
"role": "Stock User",
|
||||
"submit": 0,
|
||||
"write": 0
|
||||
},
|
||||
|
||||
3
erpnext/change_log/current/readme.md
Normal file
3
erpnext/change_log/current/readme.md
Normal file
@@ -0,0 +1,3 @@
|
||||
Leave change log files in this folder for user release notes.
|
||||
|
||||
(this file is just a place holder, don't delete it)
|
||||
3
erpnext/change_log/v5/v5_1_3.md
Normal file
3
erpnext/change_log/v5/v5_1_3.md
Normal file
@@ -0,0 +1,3 @@
|
||||
- Hide zero balance rows in batch-wise balance history report
|
||||
- Autocomplete issue fixed in Manage Variants
|
||||
- Remove user permission (Employee role) if user id is unset from Employee record
|
||||
4
erpnext/change_log/v5/v5_1_4.md
Normal file
4
erpnext/change_log/v5/v5_1_4.md
Normal file
@@ -0,0 +1,4 @@
|
||||
- Mode of Payment added to POS Profile
|
||||
- Expired Batch is not allowed in stock entry of type manufacturing / repack
|
||||
- Validate item rate against reference document with tolerance 0.009
|
||||
- Set Customer name in opportunity as per company name in lead
|
||||
8
erpnext/change_log/v5/v5_1_5.md
Normal file
8
erpnext/change_log/v5/v5_1_5.md
Normal file
@@ -0,0 +1,8 @@
|
||||
- Customer's credit days based on fixed days / last day of the next month **[Sponsored by McLean Images](http://www.mcleans.net.au)**
|
||||
- Production Order is not allowed against Item Template (for Variants)
|
||||
- Currency symbol fixed for outstanding amount and advance amount field in Sales Invoice
|
||||
- A Contact can be linked to Customer, Supplier and Sales partner at the same time
|
||||
- Validation added to prevent task being closed with open dependent tasks
|
||||
- Blocked stock transactions against an expired batch
|
||||
- Added Employees in Newsletter List
|
||||
- Link Address to Customer / Supplier / Lead, based on logged-in user, if created in portal
|
||||
9
erpnext/change_log/v5/v5_2_0.md
Normal file
9
erpnext/change_log/v5/v5_2_0.md
Normal file
@@ -0,0 +1,9 @@
|
||||
- New help videos for Selling, Buying, Human Resource, Manufacturing and Buying
|
||||
- Role rename: **Material User** is now **Stock User**
|
||||
- Role rename: **Material Manager** is now **Stock Manager**
|
||||
- Role rename: **Material Master Manager** is now **Item Manager**
|
||||
- Fixed inconsistent visibility of 'Add to Cart' button
|
||||
- Use Customer's Price List in Shopping Cart
|
||||
- Fixed Address creation from Shopping Cart
|
||||
- Display images in website's Item and Item List pages when the filename has paranthesis in its name
|
||||
|
||||
11
erpnext/change_log/v5/v5_3_0.md
Normal file
11
erpnext/change_log/v5/v5_3_0.md
Normal file
@@ -0,0 +1,11 @@
|
||||
- **Sales Return**: Create Delivery Note or Sales Invoice ('Update Stock' option checked) with negative quantity.
|
||||
- **Purchase Return**: Create Purchase Receipt with negative quantity
|
||||
- **Credit / Debit Note**: Create Sales / Purchase Invoice with negative qtuantity against original invoice.
|
||||
- Outgoing rate in Purchase Return based on reference / original Purchase Receipt rate
|
||||
- Global switch added to disable capacity planning in manufacturing settings
|
||||
- Opening Balance row added to Stock Ledger Report
|
||||
- SMS delivery message and log
|
||||
- Added users, employees, sample data via Setup Wizard
|
||||
- Letter Head option in General Ledger report
|
||||
- Fetch Template Bom if no BOM is set against Item Variant in Production Order
|
||||
- Fetch items from Packing List while raising Material Request against SO
|
||||
9
erpnext/change_log/v5/v5_4_0.md
Normal file
9
erpnext/change_log/v5/v5_4_0.md
Normal file
@@ -0,0 +1,9 @@
|
||||
- Sales / Purchase Return Enahancement - **Sponsored by [Strella Consulting Sdn Bhd](http://www.strellagroup.com)**
|
||||
* Now you can make Return entry by creating Delivery Note, Purchase Receipt or Sales / Purchase Invoice with negative quantity
|
||||
- **Item** form cleanups: "Yes" / "No" type fields changed to checkboxes.<br>
|
||||
**Warning**: This could break your 3rd party integrations with Item, if any
|
||||
- Leave Application: Consideration of **holidays** in calculation of 'Number of Days' is now optional. You can set it in Leave Type record.
|
||||
- Customer / Supplier can be **freezed** now
|
||||
- Fix: Reserved qty calculation while delivering Product Bundle via Sales Invoice
|
||||
- Fix: Deleted stock ledger entries on cancellation of Sales Invoice while Product Bundle delivered
|
||||
- Fix: Fetch default expense account and cost center from item based on selected company
|
||||
@@ -73,6 +73,11 @@ def get_data():
|
||||
"label": _("Setup"),
|
||||
"icon": "icon-cog",
|
||||
"items": [
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Company",
|
||||
"description": _("Company (not Customer or Supplier) master.")
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Fiscal Year",
|
||||
|
||||
@@ -42,6 +42,11 @@ def get_data():
|
||||
"name": "SMS Center",
|
||||
"description":_("Send mass SMS to your contacts"),
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "SMS Log",
|
||||
"description":_("Logs for maintaining sms delivery status"),
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -64,7 +64,7 @@ def get_data():
|
||||
"type": "module"
|
||||
},
|
||||
"Learn": {
|
||||
"color": "#7272FF",
|
||||
"color": "#FCB868",
|
||||
"force_show": True,
|
||||
"icon": "icon-facetime-video",
|
||||
"type": "module",
|
||||
|
||||
@@ -60,7 +60,7 @@ def get_data():
|
||||
"items": [
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Salary Manager",
|
||||
"name": "Process Payroll",
|
||||
"label": _("Process Payroll"),
|
||||
"description":_("Generate Salary Slips"),
|
||||
"hide_count": True
|
||||
|
||||
@@ -15,8 +15,12 @@ def get_data():
|
||||
"type": "help",
|
||||
"label": _("Setup Wizard"),
|
||||
"youtube_id": "oIOf_zCFWKQ"
|
||||
}
|
||||
|
||||
},
|
||||
{
|
||||
"type": "help",
|
||||
"label": _("Customizing Forms"),
|
||||
"youtube_id": "pJhL9mmxV_U"
|
||||
},
|
||||
]
|
||||
|
||||
},
|
||||
@@ -93,6 +97,16 @@ def get_data():
|
||||
"label": _("Customer and Supplier"),
|
||||
"youtube_id": "anoGi_RpQ20"
|
||||
},
|
||||
{
|
||||
"type": "help",
|
||||
"label": _("Sales Order to Payment"),
|
||||
"youtube_id": "7AMq4lqkN4A"
|
||||
},
|
||||
{
|
||||
"type": "help",
|
||||
"label": _("Point-of-Sale"),
|
||||
"youtube_id": "4WkelWkbP_c"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -108,11 +122,6 @@ def get_data():
|
||||
"label": _("Opening Stock Balance"),
|
||||
"youtube_id": "0yPgrtfeCTs"
|
||||
},
|
||||
{
|
||||
"type": "help",
|
||||
"label": _("Item Variants"),
|
||||
"youtube_id": "OGBETlCzU5o"
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -123,6 +132,12 @@ def get_data():
|
||||
"label": _("Customer and Supplier"),
|
||||
"youtube_id": "anoGi_RpQ20"
|
||||
},
|
||||
{
|
||||
"type": "help",
|
||||
"label": _("Material Request to Purchase Order"),
|
||||
"youtube_id": "4TN9kPyfIqM"
|
||||
},
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -133,6 +148,47 @@ def get_data():
|
||||
"label": _("Bill of Materials"),
|
||||
"youtube_id": "hDV0c1OeWLo"
|
||||
},
|
||||
{
|
||||
"type": "help",
|
||||
"label": _("Production Planning Tool"),
|
||||
"youtube_id": "CzatSl4zJ2Y"
|
||||
},
|
||||
{
|
||||
"type": "help",
|
||||
"label": _("Production Order"),
|
||||
"youtube_id": "ZotgLyp2YFY"
|
||||
},
|
||||
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": _("Human Resource"),
|
||||
"items": [
|
||||
{
|
||||
"type": "help",
|
||||
"label": _("Setting up Employees"),
|
||||
"youtube_id": "USfIUdZlUhw"
|
||||
},
|
||||
{
|
||||
"type": "help",
|
||||
"label": _("Leave Management"),
|
||||
"youtube_id": "fc0p_AXebc8"
|
||||
},
|
||||
{
|
||||
"type": "help",
|
||||
"label": _("Expense Claims"),
|
||||
"youtube_id": "5SZHJF--ZFY"
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": _("Projects"),
|
||||
"items": [
|
||||
{
|
||||
"type": "help",
|
||||
"label": _("Managing Projects"),
|
||||
"youtube_id": "egxIGwtoKI4"
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
|
||||
@@ -48,6 +48,11 @@ def get_data():
|
||||
"name": "SMS Center",
|
||||
"description":_("Send mass SMS to your contacts"),
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "SMS Log",
|
||||
"description":_("Logs for maintaining sms delivery status"),
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Newsletter",
|
||||
@@ -144,7 +149,7 @@ def get_data():
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Sales BOM",
|
||||
"name": "Product Bundle",
|
||||
"description": _("Bundle items at time of sale."),
|
||||
},
|
||||
{
|
||||
|
||||
@@ -110,43 +110,7 @@ def get_data():
|
||||
"description": _("Setup SMS gateway settings")
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": _("Masters"),
|
||||
"icon": "icon-star",
|
||||
"items": [
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Company",
|
||||
"description": _("Company (not Customer or Supplier) master.")
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Item",
|
||||
"description": _("Item master.")
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Customer",
|
||||
"description": _("Customer master.")
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Supplier",
|
||||
"description": _("Supplier master.")
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Contact",
|
||||
"description": _("Contact master.")
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Address",
|
||||
"description": _("Address master.")
|
||||
},
|
||||
]
|
||||
},
|
||||
}
|
||||
]
|
||||
|
||||
for module, label, icon in (
|
||||
|
||||
@@ -83,6 +83,11 @@ def get_data():
|
||||
"name": "Stock UOM Replace Utility",
|
||||
"description": _("Change UOM for an Item."),
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Manage Variants",
|
||||
"description": _("Manage Item Variants."),
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
{
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:party_type_name",
|
||||
"creation": "2014-04-07 12:32:18.010384",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Master",
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "party_type_name",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Party Type Name",
|
||||
"permlevel": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "parent_party_type",
|
||||
"fieldtype": "Link",
|
||||
"label": "Parent Party Type",
|
||||
"options": "Party Type",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"default": "Yes",
|
||||
"fieldname": "allow_children",
|
||||
"fieldtype": "Select",
|
||||
"label": "Allow Children",
|
||||
"options": "Yes\nNo",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "default_price_list",
|
||||
"fieldtype": "Link",
|
||||
"ignore_user_permissions": 1,
|
||||
"label": "Default Price List",
|
||||
"options": "Price List",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "lft",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 1,
|
||||
"label": "LFT",
|
||||
"permlevel": 0,
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "rgt",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 1,
|
||||
"label": "RGT",
|
||||
"permlevel": 0,
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "old_parent",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "Old Parent",
|
||||
"permlevel": 0,
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"modified": "2015-02-05 05:11:42.046004",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Contacts",
|
||||
"name": "Party Type",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"apply_user_permissions": 1,
|
||||
"create": 1,
|
||||
"permlevel": 0,
|
||||
"read": 1,
|
||||
"role": "Sales User",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"apply_user_permissions": 1,
|
||||
"create": 1,
|
||||
"permlevel": 0,
|
||||
"read": 1,
|
||||
"role": "Purchase User",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -9,24 +9,34 @@ from erpnext.setup.utils import get_company_currency, get_exchange_rate
|
||||
from erpnext.accounts.utils import get_fiscal_year, validate_fiscal_year
|
||||
from erpnext.utilities.transaction_base import TransactionBase
|
||||
from erpnext.controllers.recurring_document import convert_to_recurring, validate_recurring_document
|
||||
from erpnext.controllers.sales_and_purchase_return import validate_return
|
||||
|
||||
class CustomerFrozen(frappe.ValidationError): pass
|
||||
|
||||
class AccountsController(TransactionBase):
|
||||
def validate(self):
|
||||
if self.get("_action") and self._action != "update_after_submit":
|
||||
self.set_missing_values(for_validate=True)
|
||||
self.validate_date_with_fiscal_year()
|
||||
|
||||
if self.meta.get_field("currency"):
|
||||
self.calculate_taxes_and_totals()
|
||||
self.validate_value("base_grand_total", ">=", 0)
|
||||
if not self.meta.get_field("is_return") or not self.is_return:
|
||||
self.validate_value("base_grand_total", ">=", 0)
|
||||
|
||||
validate_return(self)
|
||||
self.set_total_in_words()
|
||||
|
||||
self.validate_due_date()
|
||||
if self.doctype in ("Sales Invoice", "Purchase Invoice") and not self.is_return:
|
||||
self.validate_due_date()
|
||||
|
||||
if self.meta.get_field("is_recurring"):
|
||||
validate_recurring_document(self)
|
||||
|
||||
if self.meta.get_field("taxes_and_charges"):
|
||||
self.validate_enabled_taxes_and_charges()
|
||||
|
||||
self.validate_party()
|
||||
|
||||
def on_submit(self):
|
||||
if self.meta.get_field("is_recurring"):
|
||||
@@ -74,6 +84,9 @@ class AccountsController(TransactionBase):
|
||||
def validate_due_date(self):
|
||||
from erpnext.accounts.party import validate_due_date
|
||||
if self.doctype == "Sales Invoice":
|
||||
if not self.due_date:
|
||||
frappe.throw(_("Due Date is mandatory"))
|
||||
|
||||
validate_due_date(self.posting_date, self.due_date, "Customer", self.customer, self.company)
|
||||
elif self.doctype == "Purchase Invoice":
|
||||
validate_due_date(self.posting_date, self.due_date, "Supplier", self.supplier, self.company)
|
||||
@@ -294,7 +307,7 @@ class AccountsController(TransactionBase):
|
||||
item_codes = list(set(item.item_code for item in self.get("items")))
|
||||
if item_codes:
|
||||
stock_items = [r[0] for r in frappe.db.sql("""select name
|
||||
from `tabItem` where name in (%s) and is_stock_item='Yes'""" % \
|
||||
from `tabItem` where name in (%s) and is_stock_item=1""" % \
|
||||
(", ".join((["%s"]*len(item_codes))),), item_codes)]
|
||||
|
||||
return stock_items
|
||||
@@ -332,6 +345,23 @@ class AccountsController(TransactionBase):
|
||||
|
||||
return self._abbr
|
||||
|
||||
def validate_party(self):
|
||||
frozen_accounts_modifier = frappe.db.get_value( 'Accounts Settings', None,'frozen_accounts_modifier')
|
||||
if frozen_accounts_modifier in frappe.get_roles():
|
||||
return
|
||||
|
||||
party_type = None
|
||||
if self.meta.get_field("customer"):
|
||||
party_type = 'Customer'
|
||||
|
||||
elif self.meta.get_field("supplier"):
|
||||
party_type = 'Supplier'
|
||||
|
||||
if party_type:
|
||||
party = self.get(party_type.lower())
|
||||
if frappe.db.get_value(party_type, party, "is_frozen"):
|
||||
frappe.throw("{0} {1} is frozen".format(party_type, party), CustomerFrozen)
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_tax_rate(account_head):
|
||||
return frappe.db.get_value("Account", account_head, "tax_rate")
|
||||
|
||||
@@ -26,8 +26,7 @@ class BuyingController(StockController):
|
||||
def validate(self):
|
||||
super(BuyingController, self).validate()
|
||||
if getattr(self, "supplier", None) and not self.supplier_name:
|
||||
self.supplier_name = frappe.db.get_value("Supplier",
|
||||
self.supplier, "supplier_name")
|
||||
self.supplier_name = frappe.db.get_value("Supplier", self.supplier, "supplier_name")
|
||||
self.is_item_table_empty()
|
||||
self.set_qty_as_per_stock_uom()
|
||||
self.validate_stock_or_nonstock_items()
|
||||
@@ -239,8 +238,8 @@ class BuyingController(StockController):
|
||||
t2.rate, t2.stock_uom, t2.name, t2.description
|
||||
from `tabBOM` t1, `tabBOM Item` t2, tabItem t3
|
||||
where t2.parent = t1.name and t1.item = %s
|
||||
and t1.docstatus = 1 and t1.is_active = 1 and t1.name = %s
|
||||
and t2.item_code = t3.name and ifnull(t3.is_stock_item, 'No') = 'Yes'""", (item_code, bom), as_dict=1)
|
||||
and t1.docstatus = 1 and t1.is_active = 1 and t1.name = %s
|
||||
and t2.item_code = t3.name and t3.is_stock_item = 1""", (item_code, bom), as_dict=1)
|
||||
|
||||
if not bom_items:
|
||||
msgprint(_("Specified BOM {0} does not exist for Item {1}").format(bom, item_code), raise_exception=1)
|
||||
@@ -255,7 +254,7 @@ class BuyingController(StockController):
|
||||
self.get("items")))
|
||||
if item_codes:
|
||||
self._sub_contracted_items = [r[0] for r in frappe.db.sql("""select name
|
||||
from `tabItem` where name in (%s) and is_sub_contracted_item='Yes'""" % \
|
||||
from `tabItem` where name in (%s) and is_sub_contracted_item=1""" % \
|
||||
(", ".join((["%s"]*len(item_codes))),), item_codes)]
|
||||
|
||||
return self._sub_contracted_items
|
||||
|
||||
@@ -229,9 +229,10 @@ def get_delivery_notes_to_be_billed(doctype, txt, searchfield, start, page_len,
|
||||
}, { "start": start, "page_len": page_len, "txt": ("%%%s%%" % txt) })
|
||||
|
||||
def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
|
||||
if not filters.get("posting_date"):
|
||||
filters["posting_date"] = nowdate()
|
||||
|
||||
cond = ""
|
||||
if filters.get("posting_date"):
|
||||
cond = "and (ifnull(batch.expiry_date, '')='' or batch.expiry_date >= %(posting_date)s)"
|
||||
|
||||
batch_nos = None
|
||||
args = {
|
||||
'item_code': filters.get("item_code"),
|
||||
@@ -251,23 +252,23 @@ def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
|
||||
and sle.warehouse = %(warehouse)s
|
||||
and sle.batch_no like %(txt)s
|
||||
and batch.docstatus < 2
|
||||
and (ifnull(batch.expiry_date, '')='' or batch.expiry_date >= %(posting_date)s)
|
||||
{0}
|
||||
{match_conditions}
|
||||
group by batch_no having sum(sle.actual_qty) > 0
|
||||
order by batch.expiry_date, sle.batch_no desc
|
||||
limit %(start)s, %(page_len)s""".format(match_conditions=get_match_cond(doctype)), args)
|
||||
limit %(start)s, %(page_len)s""".format(cond, match_conditions=get_match_cond(doctype)), args)
|
||||
|
||||
if batch_nos:
|
||||
return batch_nos
|
||||
else:
|
||||
return frappe.db.sql("""select name, expiry_date from `tabBatch`
|
||||
return frappe.db.sql("""select name, expiry_date from `tabBatch` batch
|
||||
where item = %(item_code)s
|
||||
and name like %(txt)s
|
||||
and docstatus < 2
|
||||
and (ifnull(expiry_date, '')='' or expiry_date >= %(posting_date)s)
|
||||
{0}
|
||||
{match_conditions}
|
||||
order by expiry_date, name desc
|
||||
limit %(start)s, %(page_len)s""".format(match_conditions=get_match_cond(doctype)), args)
|
||||
limit %(start)s, %(page_len)s""".format(cond, match_conditions=get_match_cond(doctype)), args, debug=1)
|
||||
|
||||
def get_account_list(doctype, txt, searchfield, start, page_len, filters):
|
||||
filter_list = []
|
||||
|
||||
145
erpnext/controllers/sales_and_purchase_return.py
Normal file
145
erpnext/controllers/sales_and_purchase_return.py
Normal file
@@ -0,0 +1,145 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import flt, get_datetime, format_datetime
|
||||
|
||||
class StockOverReturnError(frappe.ValidationError): pass
|
||||
|
||||
|
||||
def validate_return(doc):
|
||||
if not doc.meta.get_field("is_return") or not doc.is_return:
|
||||
return
|
||||
|
||||
validate_return_against(doc)
|
||||
validate_returned_items(doc)
|
||||
|
||||
def validate_return_against(doc):
|
||||
if not doc.return_against:
|
||||
frappe.throw(_("{0} is mandatory for Return").format(doc.meta.get_label("return_against")))
|
||||
else:
|
||||
filters = {"doctype": doc.doctype, "docstatus": 1, "company": doc.company}
|
||||
if doc.meta.get_field("customer"):
|
||||
filters["customer"] = doc.customer
|
||||
elif doc.meta.get_field("supplier"):
|
||||
filters["supplier"] = doc.supplier
|
||||
|
||||
if not frappe.db.exists(filters):
|
||||
frappe.throw(_("Invalid {0}: {1}")
|
||||
.format(doc.meta.get_label("return_against"), doc.return_against))
|
||||
else:
|
||||
ref_doc = frappe.get_doc(doc.doctype, doc.return_against)
|
||||
|
||||
# validate posting date time
|
||||
return_posting_datetime = "%s %s" % (doc.posting_date, doc.get("posting_time") or "00:00:00")
|
||||
ref_posting_datetime = "%s %s" % (ref_doc.posting_date, ref_doc.get("posting_time") or "00:00:00")
|
||||
|
||||
if get_datetime(return_posting_datetime) < get_datetime(ref_posting_datetime):
|
||||
frappe.throw(_("Posting timestamp must be after {0}").format(format_datetime(ref_posting_datetime)))
|
||||
|
||||
# validate same exchange rate
|
||||
if doc.conversion_rate != ref_doc.conversion_rate:
|
||||
frappe.throw(_("Exchange Rate must be same as {0} {1} ({2})")
|
||||
.format(doc.doctype, doc.return_against, ref_doc.conversion_rate))
|
||||
|
||||
# validate update stock
|
||||
if doc.doctype == "Sales Invoice" and doc.update_stock and not ref_doc.update_stock:
|
||||
frappe.throw(_("'Update Stock' can not be checked because items are not delivered via {0}")
|
||||
.format(doc.return_against))
|
||||
|
||||
def validate_returned_items(doc):
|
||||
valid_items = frappe._dict()
|
||||
for d in frappe.db.sql("""select item_code, sum(qty) as qty, rate from `tab{0} Item`
|
||||
where parent = %s group by item_code""".format(doc.doctype), doc.return_against, as_dict=1):
|
||||
valid_items.setdefault(d.item_code, d)
|
||||
|
||||
if doc.doctype in ("Delivery Note", "Sales Invoice"):
|
||||
for d in frappe.db.sql("""select item_code, sum(qty) as qty from `tabPacked Item`
|
||||
where parent = %s group by item_code""".format(doc.doctype), doc.return_against, as_dict=1):
|
||||
valid_items.setdefault(d.item_code, d)
|
||||
|
||||
already_returned_items = get_already_returned_items(doc)
|
||||
|
||||
items_returned = False
|
||||
for d in doc.get("items"):
|
||||
if flt(d.qty) < 0:
|
||||
if d.item_code not in valid_items:
|
||||
frappe.throw(_("Row # {0}: Returned Item {1} does not exists in {2} {3}")
|
||||
.format(d.idx, d.item_code, doc.doctype, doc.return_against))
|
||||
else:
|
||||
ref = valid_items.get(d.item_code, frappe._dict())
|
||||
already_returned_qty = flt(already_returned_items.get(d.item_code))
|
||||
max_return_qty = flt(ref.qty) - already_returned_qty
|
||||
|
||||
if already_returned_qty >= ref.qty:
|
||||
frappe.throw(_("Item {0} has already been returned").format(d.item_code), StockOverReturnError)
|
||||
elif abs(d.qty) > max_return_qty:
|
||||
frappe.throw(_("Row # {0}: Cannot return more than {1} for Item {2}")
|
||||
.format(d.idx, ref.qty, d.item_code), StockOverReturnError)
|
||||
elif ref.rate and flt(d.rate) != ref.rate:
|
||||
frappe.throw(_("Row # {0}: Rate must be same as {1} {2}")
|
||||
.format(d.idx, doc.doctype, doc.return_against))
|
||||
|
||||
|
||||
items_returned = True
|
||||
|
||||
if not items_returned:
|
||||
frappe.throw(_("Atleast one item should be entered with negative quantity in return document"))
|
||||
|
||||
def get_already_returned_items(doc):
|
||||
return frappe._dict(frappe.db.sql("""
|
||||
select
|
||||
child.item_code, sum(abs(child.qty)) as qty
|
||||
from
|
||||
`tab{0} Item` child, `tab{1}` par
|
||||
where
|
||||
child.parent = par.name and par.docstatus = 1
|
||||
and ifnull(par.is_return, 0) = 1 and par.return_against = %s and child.qty < 0
|
||||
group by item_code
|
||||
""".format(doc.doctype, doc.doctype), doc.return_against))
|
||||
|
||||
def make_return_doc(doctype, source_name, target_doc=None):
|
||||
from frappe.model.mapper import get_mapped_doc
|
||||
def set_missing_values(source, target):
|
||||
doc = frappe.get_doc(target)
|
||||
doc.is_return = 1
|
||||
doc.return_against = source.name
|
||||
doc.ignore_pricing_rule = 1
|
||||
if doctype == "Sales Invoice":
|
||||
doc.is_pos = 0
|
||||
|
||||
for tax in doc.get("taxes"):
|
||||
if tax.charge_type == "Actual":
|
||||
tax.tax_amount = -1 * tax.tax_amount
|
||||
|
||||
doc.run_method("calculate_taxes_and_totals")
|
||||
|
||||
def update_item(source_doc, target_doc, source_parent):
|
||||
target_doc.qty = -1* source_doc.qty
|
||||
if doctype == "Purchase Receipt":
|
||||
target_doc.received_qty = -1* source_doc.qty
|
||||
elif doctype == "Purchase Invoice":
|
||||
target_doc.purchase_receipt = source_doc.purchase_receipt
|
||||
target_doc.pr_detail = source_doc.pr_detail
|
||||
|
||||
doclist = get_mapped_doc(doctype, source_name, {
|
||||
doctype: {
|
||||
"doctype": doctype,
|
||||
|
||||
"validation": {
|
||||
"docstatus": ["=", 1],
|
||||
}
|
||||
},
|
||||
doctype +" Item": {
|
||||
"doctype": doctype + " Item",
|
||||
"fields": {
|
||||
"purchase_order": "purchase_order",
|
||||
"purchase_receipt": "purchase_receipt"
|
||||
},
|
||||
"postprocess": update_item
|
||||
},
|
||||
}, target_doc, set_missing_values)
|
||||
|
||||
return doclist
|
||||
@@ -110,15 +110,14 @@ class SellingController(StockController):
|
||||
from frappe.utils import money_in_words
|
||||
company_currency = get_company_currency(self.company)
|
||||
|
||||
disable_rounded_total = cint(frappe.db.get_value("Global Defaults", None,
|
||||
"disable_rounded_total"))
|
||||
disable_rounded_total = cint(frappe.db.get_value("Global Defaults", None, "disable_rounded_total"))
|
||||
|
||||
if self.meta.get_field("base_in_words"):
|
||||
self.base_in_words = money_in_words(disable_rounded_total and
|
||||
self.base_grand_total or self.base_rounded_total, company_currency)
|
||||
abs(self.base_grand_total) or abs(self.base_rounded_total), company_currency)
|
||||
if self.meta.get_field("in_words"):
|
||||
self.in_words = money_in_words(disable_rounded_total and
|
||||
self.grand_total or self.rounded_total, self.currency)
|
||||
abs(self.grand_total) or abs(self.rounded_total), self.currency)
|
||||
|
||||
def calculate_commission(self):
|
||||
if self.meta.get_field("commission_rate"):
|
||||
@@ -171,19 +170,18 @@ class SellingController(StockController):
|
||||
frappe.throw(_("Row {0}: Qty is mandatory").format(d.idx))
|
||||
|
||||
if self.doctype == "Sales Order":
|
||||
if (frappe.db.get_value("Item", d.item_code, "is_stock_item") == 'Yes' or
|
||||
self.has_sales_bom(d.item_code)) and not d.warehouse:
|
||||
frappe.throw(_("Reserved Warehouse required for stock Item {0} in row {1}").format(d.item_code, d.idx))
|
||||
reserved_warehouse = d.warehouse
|
||||
if flt(d.qty) > flt(d.delivered_qty):
|
||||
reserved_qty_for_main_item = flt(d.qty) - flt(d.delivered_qty)
|
||||
|
||||
elif self.doctype == "Delivery Note" and d.against_sales_order:
|
||||
elif (((self.doctype == "Delivery Note" and d.against_sales_order)
|
||||
or (self.doctype == "Sales Invoice" and d.sales_order and self.update_stock))
|
||||
and not self.is_return):
|
||||
# if SO qty is 10 and there is tolerance of 20%, then it will allow DN of 12.
|
||||
# But in this case reserved qty should only be reduced by 10 and not 12
|
||||
|
||||
already_delivered_qty = self.get_already_delivered_qty(self.name,
|
||||
d.against_sales_order, d.so_detail)
|
||||
d.against_sales_order if self.doctype=="Delivery Note" else d.sales_order, d.so_detail)
|
||||
so_qty, reserved_warehouse = self.get_so_qty_and_warehouse(d.so_detail)
|
||||
|
||||
if already_delivered_qty + d.qty > so_qty:
|
||||
@@ -191,7 +189,7 @@ class SellingController(StockController):
|
||||
else:
|
||||
reserved_qty_for_main_item = -flt(d.qty)
|
||||
|
||||
if self.has_sales_bom(d.item_code):
|
||||
if self.has_product_bundle(d.item_code):
|
||||
for p in self.get("packed_items"):
|
||||
if p.parent_detail_docname == d.name and p.parent_item == d.item_code:
|
||||
# the packing details table's qty is already multiplied with parent's qty
|
||||
@@ -214,23 +212,32 @@ class SellingController(StockController):
|
||||
'qty': d.qty,
|
||||
'reserved_qty': reserved_qty_for_main_item,
|
||||
'uom': d.stock_uom,
|
||||
'stock_uom': d.stock_uom,
|
||||
'stock_uom': d.stock_uom,
|
||||
'batch_no': cstr(d.get("batch_no")).strip(),
|
||||
'serial_no': cstr(d.get("serial_no")).strip(),
|
||||
'name': d.name
|
||||
}))
|
||||
return il
|
||||
|
||||
def has_sales_bom(self, item_code):
|
||||
return frappe.db.sql("""select name from `tabSales BOM`
|
||||
def has_product_bundle(self, item_code):
|
||||
return frappe.db.sql("""select name from `tabProduct Bundle`
|
||||
where new_item_code=%s and docstatus != 2""", item_code)
|
||||
|
||||
def get_already_delivered_qty(self, dn, so, so_detail):
|
||||
qty = frappe.db.sql("""select sum(qty) from `tabDelivery Note Item`
|
||||
def get_already_delivered_qty(self, current_docname, so, so_detail):
|
||||
delivered_via_dn = frappe.db.sql("""select sum(qty) from `tabDelivery Note Item`
|
||||
where so_detail = %s and docstatus = 1
|
||||
and against_sales_order = %s
|
||||
and parent != %s""", (so_detail, so, dn))
|
||||
return qty and flt(qty[0][0]) or 0.0
|
||||
and parent != %s""", (so_detail, so, current_docname))
|
||||
|
||||
delivered_via_si = frappe.db.sql("""select sum(qty) from `tabSales Invoice Item`
|
||||
where so_detail = %s and docstatus = 1
|
||||
and sales_order = %s
|
||||
and parent != %s""", (so_detail, so, current_docname))
|
||||
|
||||
total_delivered_qty = (flt(delivered_via_dn[0][0]) if delivered_via_dn else 0) \
|
||||
+ (flt(delivered_via_si[0][0]) if delivered_via_si else 0)
|
||||
|
||||
return total_delivered_qty
|
||||
|
||||
def get_so_qty_and_warehouse(self, so_detail):
|
||||
so_item = frappe.db.sql("""select qty, warehouse from `tabSales Order Item`
|
||||
@@ -252,7 +259,7 @@ def check_active_sales_items(obj):
|
||||
item = frappe.db.sql("""select docstatus, is_sales_item,
|
||||
is_service_item, income_account from tabItem where name = %s""",
|
||||
d.item_code, as_dict=True)[0]
|
||||
if item.is_sales_item == 'No' and item.is_service_item == 'No':
|
||||
if item.is_sales_item == 0 and item.is_service_item == 0:
|
||||
frappe.throw(_("Item {0} must be Sales or Service Item in {1}").format(d.item_code, d.idx))
|
||||
if getattr(d, "income_account", None) and not item.income_account:
|
||||
frappe.db.set_value("Item", d.item_code, "income_account",
|
||||
|
||||
@@ -9,6 +9,8 @@ import frappe.defaults
|
||||
|
||||
from erpnext.controllers.accounts_controller import AccountsController
|
||||
from erpnext.accounts.general_ledger import make_gl_entries, delete_gl_entries, process_gl_map
|
||||
from erpnext.stock.utils import update_bin
|
||||
|
||||
|
||||
class StockController(AccountsController):
|
||||
def make_gl_entries(self, repost_future_gle=True):
|
||||
@@ -212,10 +214,38 @@ class StockController(AccountsController):
|
||||
item_codes = list(set([d.item_code for d in self.get("items")]))
|
||||
if item_codes:
|
||||
serialized_items = frappe.db.sql_list("""select name from `tabItem`
|
||||
where has_serial_no='Yes' and name in ({})""".format(", ".join(["%s"]*len(item_codes))),
|
||||
where has_serial_no=1 and name in ({})""".format(", ".join(["%s"]*len(item_codes))),
|
||||
tuple(item_codes))
|
||||
|
||||
return serialized_items
|
||||
|
||||
def get_incoming_rate_for_sales_return(self, item_code, against_document):
|
||||
incoming_rate = 0.0
|
||||
if against_document and item_code:
|
||||
incoming_rate = frappe.db.sql("""select abs(ifnull(stock_value_difference, 0) / actual_qty)
|
||||
from `tabStock Ledger Entry`
|
||||
where voucher_type = %s and voucher_no = %s and item_code = %s limit 1""",
|
||||
(self.doctype, against_document, item_code))
|
||||
incoming_rate = incoming_rate[0][0] if incoming_rate else 0.0
|
||||
|
||||
return incoming_rate
|
||||
|
||||
def update_reserved_qty(self, d):
|
||||
if d['reserved_qty'] < 0 :
|
||||
# Reduce reserved qty from reserved warehouse mentioned in so
|
||||
if not d["reserved_warehouse"]:
|
||||
frappe.throw(_("Reserved Warehouse is missing in Sales Order"))
|
||||
|
||||
args = {
|
||||
"item_code": d['item_code'],
|
||||
"warehouse": d["reserved_warehouse"],
|
||||
"voucher_type": self.doctype,
|
||||
"voucher_no": self.name,
|
||||
"reserved_qty": (self.docstatus==1 and 1 or -1)*flt(d['reserved_qty']),
|
||||
"posting_date": self.posting_date,
|
||||
"is_amended": self.amended_from and 'Yes' or 'No'
|
||||
}
|
||||
update_bin(args)
|
||||
|
||||
def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None,
|
||||
warehouse_account=None):
|
||||
|
||||
@@ -396,13 +396,15 @@ class calculate_taxes_and_totals(object):
|
||||
# total_advance is only for non POS Invoice
|
||||
|
||||
if self.doc.doctype == "Sales Invoice":
|
||||
self.doc.round_floats_in(self.doc, ["base_grand_total", "total_advance", "write_off_amount", "paid_amount"])
|
||||
total_amount_to_pay = self.doc.base_grand_total - self.doc.write_off_amount
|
||||
self.doc.outstanding_amount = flt(total_amount_to_pay - self.doc.total_advance - self.doc.paid_amount,
|
||||
self.doc.precision("outstanding_amount"))
|
||||
if not self.doc.is_return:
|
||||
self.doc.round_floats_in(self.doc, ["base_grand_total", "total_advance", "write_off_amount", "paid_amount"])
|
||||
total_amount_to_pay = self.doc.base_grand_total - self.doc.write_off_amount
|
||||
self.doc.outstanding_amount = flt(total_amount_to_pay - self.doc.total_advance - self.doc.paid_amount,
|
||||
self.doc.precision("outstanding_amount"))
|
||||
else:
|
||||
self.doc.round_floats_in(self.doc, ["total_advance", "write_off_amount"])
|
||||
self.doc.total_amount_to_pay = flt(self.doc.base_grand_total - self.doc.write_off_amount,
|
||||
self.doc.precision("total_amount_to_pay"))
|
||||
self.doc.outstanding_amount = flt(self.doc.total_amount_to_pay - self.doc.total_advance,
|
||||
self.doc.precision("outstanding_amount"))
|
||||
if not self.doc.is_return:
|
||||
self.doc.outstanding_amount = flt(self.doc.total_amount_to_pay - self.doc.total_advance,
|
||||
self.doc.precision("outstanding_amount"))
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"fieldtype": "Data",
|
||||
"in_filter": 1,
|
||||
"in_list_view": 0,
|
||||
"label": "Contact Name",
|
||||
"label": "Person Name",
|
||||
"oldfieldname": "lead_name",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
@@ -344,7 +344,7 @@
|
||||
],
|
||||
"icon": "icon-user",
|
||||
"idx": 1,
|
||||
"modified": "2015-04-02 15:13:02.621854",
|
||||
"modified": "2015-07-03 03:26:18.579905",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "Lead",
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
"fieldtype": "Text Editor",
|
||||
"label": "Message",
|
||||
"permlevel": 0,
|
||||
"reqd": 0
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"description": "",
|
||||
@@ -78,7 +78,7 @@
|
||||
],
|
||||
"icon": "icon-envelope",
|
||||
"idx": 1,
|
||||
"modified": "2015-03-20 05:27:31.613881",
|
||||
"modified": "2015-07-20 05:43:33.818567",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "Newsletter",
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
"default": "0",
|
||||
"fieldname": "total_subscribers",
|
||||
"fieldtype": "Int",
|
||||
"in_list_view": 1,
|
||||
"label": "Total Subscribers",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
@@ -45,7 +46,7 @@
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"modified": "2015-03-18 08:08:37.692367",
|
||||
"modified": "2015-07-15 07:18:30.094155",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "Newsletter List",
|
||||
|
||||
@@ -12,8 +12,8 @@ from email.utils import parseaddr
|
||||
class NewsletterList(Document):
|
||||
def onload(self):
|
||||
singles = [d.name for d in frappe.db.get_all("DocType", "name", {"issingle": 1})]
|
||||
self.get("__onload").import_types = [d.parent \
|
||||
for d in frappe.db.get_all("DocField", "parent", {"options": "Email"}) if d.parent not in singles]
|
||||
self.get("__onload").import_types = [{"value": d.parent, "label": "{0} ({1})".format(d.parent, d.label)} \
|
||||
for d in frappe.db.get_all("DocField", ("parent", "label"), {"options": "Email"}) if d.parent not in singles]
|
||||
|
||||
def import_from(self, doctype):
|
||||
"""Extract email ids from given doctype and add them to the current list"""
|
||||
|
||||
@@ -48,7 +48,7 @@ erpnext.crm.Opportunity = frappe.ui.form.Controller.extend({
|
||||
return {
|
||||
query: "erpnext.controllers.queries.item_query",
|
||||
filters: me.frm.doc.enquiry_type === "Maintenance" ?
|
||||
{"is_service_item": "Yes"} : {"is_sales_item": "Yes"}
|
||||
{"is_service_item": 1} : {"is_sales_item":1}
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -79,7 +79,8 @@ class Opportunity(TransactionBase):
|
||||
if self.customer:
|
||||
self.customer_name = frappe.db.get_value("Customer", self.customer, "customer_name")
|
||||
elif self.lead:
|
||||
self.customer_name = frappe.db.get_value("Lead", self.lead, "lead_name")
|
||||
lead_name, company_name = frappe.db.get_value("Lead", self.lead, ["lead_name", "company_name"])
|
||||
self.customer_name = company_name or lead_name
|
||||
|
||||
def get_cust_address(self,name):
|
||||
details = frappe.db.sql("""select customer_name, address, territory, customer_group
|
||||
|
||||
@@ -1,11 +1,34 @@
|
||||
from __future__ import unicode_literals
|
||||
app_name = "erpnext"
|
||||
app_title = "ERPNext"
|
||||
app_publisher = "Frappe Technologies Pvt. Ltd. and Contributors"
|
||||
app_description = "Open Source Enterprise Resource Planning for Small and Midsized Organizations"
|
||||
app_publisher = "Frappe Technologies Pvt. Ltd."
|
||||
app_description = """## ERPNext
|
||||
|
||||
ERPNext is a fully featured ERP system designed for Small and Medium Sized
|
||||
business. ERPNext covers a wide range of features including Accounting, CRM,
|
||||
Inventory management, Selling, Purchasing, Manufacturing, Projects, HR &
|
||||
Payroll, Website, E-Commerce and much more.
|
||||
|
||||
ERPNext is based on the Frappe Framework is highly customizable and extendable.
|
||||
You can create Custom Form, Fields, Scripts and can also create your own Apps
|
||||
to extend ERPNext functionality.
|
||||
|
||||
ERPNext is Open Source under the GNU General Public Licence v3 and has been
|
||||
listed as one of the Best Open Source Softwares in the world by my online
|
||||
blogs.
|
||||
|
||||
### Links
|
||||
|
||||
- Website: [https://erpnext.com](https://erpnext.com)
|
||||
- GitHub: [https://github.com/frappe/erpnext](https://github.com/frappe/erpnext)
|
||||
- Forum: [https://discuss.erpnext.com](https://discuss.erpnext.com)
|
||||
- Frappe Framework: [https://frappe.io](https://frappe.io)
|
||||
|
||||
"""
|
||||
app_icon = "icon-th"
|
||||
app_color = "#e74c3c"
|
||||
app_version = "5.1.2"
|
||||
app_version = "5.4.2"
|
||||
github_link = "https://github.com/frappe/erpnext"
|
||||
|
||||
error_report_email = "support@erpnext.com"
|
||||
|
||||
@@ -25,8 +48,13 @@ on_logout = "erpnext.shopping_cart.utils.clear_cart_count"
|
||||
# website
|
||||
update_website_context = "erpnext.shopping_cart.utils.update_website_context"
|
||||
my_account_context = "erpnext.shopping_cart.utils.update_my_account_context"
|
||||
|
||||
email_append_to = ["Job Applicant", "Opportunity", "Issue"]
|
||||
|
||||
calendars = ["Task", "Production Order", "Time Log", "Leave Application"]
|
||||
|
||||
website_generators = ["Item Group", "Item", "Sales Partner"]
|
||||
|
||||
website_context = {
|
||||
"favicon": "/assets/erpnext/images/favicon.png",
|
||||
"splash_image": "/assets/erpnext/images/splash.png"
|
||||
@@ -52,14 +80,10 @@ dump_report_map = "erpnext.startup.report_data_map.data_map"
|
||||
|
||||
before_tests = "erpnext.setup.utils.before_tests"
|
||||
|
||||
website_generators = ["Item Group", "Item", "Sales Partner"]
|
||||
|
||||
standard_queries = {
|
||||
"Customer": "erpnext.selling.doctype.customer.customer.get_customer_list"
|
||||
}
|
||||
|
||||
communication_covert_to = ["Lead", "Issue", "Job Application"]
|
||||
|
||||
doc_events = {
|
||||
"Stock Entry": {
|
||||
"on_submit": "erpnext.stock.doctype.material_request.material_request.update_completed_and_requested_qty",
|
||||
@@ -106,4 +130,3 @@ get_translated_dict = {
|
||||
("page", "setup-wizard"): "frappe.geo.country_info.get_translated_dict",
|
||||
("doctype", "Global Defaults"): "frappe.geo.country_info.get_translated_dict"
|
||||
}
|
||||
|
||||
|
||||
@@ -290,6 +290,7 @@
|
||||
"label": "Company Email",
|
||||
"oldfieldname": "company_email",
|
||||
"oldfieldtype": "Data",
|
||||
"options": "Email",
|
||||
"permlevel": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
@@ -385,6 +386,7 @@
|
||||
"fieldname": "personal_email",
|
||||
"fieldtype": "Data",
|
||||
"label": "Personal Email",
|
||||
"options": "Email",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
@@ -674,7 +676,7 @@
|
||||
],
|
||||
"icon": "icon-user",
|
||||
"idx": 1,
|
||||
"modified": "2015-02-20 05:02:14.205144",
|
||||
"modified": "2015-07-09 02:25:20.987412",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Employee",
|
||||
|
||||
@@ -45,6 +45,10 @@ class Employee(Document):
|
||||
if self.user_id:
|
||||
self.validate_for_enabled_user_id()
|
||||
self.validate_duplicate_user_id()
|
||||
else:
|
||||
existing_user_id = frappe.db.get_value("Employee", self.name, "user_id")
|
||||
if existing_user_id:
|
||||
frappe.permissions.remove_user_permission("Employee", self.name, existing_user_id)
|
||||
|
||||
def on_update(self):
|
||||
if self.user_id:
|
||||
|
||||
@@ -19,10 +19,13 @@ erpnext.hr.ExpenseClaimController = frappe.ui.form.Controller.extend({
|
||||
jv.company = cur_frm.doc.company;
|
||||
jv.remark = 'Payment against Expense Claim: ' + cur_frm.doc.name;
|
||||
jv.fiscal_year = cur_frm.doc.fiscal_year;
|
||||
|
||||
var d1 = frappe.model.add_child(jv, 'Journal Entry Account', 'accounts');
|
||||
d1.debit = cur_frm.doc.total_sanctioned_amount;
|
||||
d1.against_expense_claim = cur_frm.doc.name;
|
||||
var expense = cur_frm.doc.expenses || [];
|
||||
for(var i = 0; i < expense.length; i++){
|
||||
var d1 = frappe.model.add_child(jv, 'Journal Entry Account', 'accounts');
|
||||
d1.debit = expense[i].sanctioned_amount;
|
||||
d1.account = expense[i].default_account;
|
||||
d1.against_expense_claim = cur_frm.doc.name;
|
||||
}
|
||||
|
||||
// credit to bank
|
||||
var d1 = frappe.model.add_child(jv, 'Journal Entry Account', 'accounts');
|
||||
@@ -43,6 +46,7 @@ $.extend(cur_frm.cscript, new erpnext.hr.ExpenseClaimController({frm: cur_frm}))
|
||||
|
||||
cur_frm.add_fetch('employee', 'company', 'company');
|
||||
cur_frm.add_fetch('employee','employee_name','employee_name');
|
||||
cur_frm.add_fetch('expense_type', 'default_account', 'default_account');
|
||||
|
||||
cur_frm.cscript.onload = function(doc,cdt,cdn) {
|
||||
if(!doc.approval_status)
|
||||
|
||||
@@ -34,6 +34,18 @@
|
||||
"reqd": 1,
|
||||
"width": "150px"
|
||||
},
|
||||
{
|
||||
"depends_on": "expense_type",
|
||||
"fieldname": "default_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 1,
|
||||
"label": "Default Account",
|
||||
"options": "Account",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"read_only": 1,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_4",
|
||||
"fieldtype": "Section Break",
|
||||
@@ -93,7 +105,7 @@
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"modified": "2015-04-08 06:18:47.539134",
|
||||
"modified": "2015-07-16 06:13:32.090048",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Expense Claim Detail",
|
||||
|
||||
@@ -17,6 +17,14 @@
|
||||
"reqd": 1,
|
||||
"search_index": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "default_account",
|
||||
"fieldtype": "Link",
|
||||
"label": "Default Account",
|
||||
"options": "Account",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Small Text",
|
||||
@@ -29,7 +37,7 @@
|
||||
],
|
||||
"icon": "icon-flag",
|
||||
"idx": 1,
|
||||
"modified": "2015-04-19 06:47:51.860833",
|
||||
"modified": "2015-07-15 08:57:23.069980",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Expense Claim Type",
|
||||
|
||||
@@ -238,10 +238,16 @@ def get_total_leave_days(leave_app):
|
||||
ret = {'total_leave_days' : 0.5}
|
||||
if not leave_app.half_day:
|
||||
tot_days = date_diff(leave_app.to_date, leave_app.from_date) + 1
|
||||
holidays = leave_app.get_holidays()
|
||||
ret = {
|
||||
'total_leave_days' : flt(tot_days)-flt(holidays)
|
||||
}
|
||||
if frappe.db.get_value("Leave Type", leave_app.leave_type, "include_holiday"):
|
||||
ret = {
|
||||
'total_leave_days' : flt(tot_days)
|
||||
}
|
||||
else:
|
||||
holidays = leave_app.get_holidays()
|
||||
ret = {
|
||||
'total_leave_days' : flt(tot_days)-flt(holidays)
|
||||
}
|
||||
|
||||
return ret
|
||||
|
||||
@frappe.whitelist()
|
||||
|
||||
@@ -246,4 +246,4 @@ class TestLeaveApplication(unittest.TestCase):
|
||||
frappe.db.sql("""delete from `tabEmployee Leave Approver` where parent=%s""",
|
||||
"_T-Employee-0001")
|
||||
|
||||
frappe.db.set_value("Employee", "_T-Employee-0001", "department", original_department)
|
||||
frappe.db.set_value("Employee", "_T-Employee-0001", "department", original_department)
|
||||
@@ -59,11 +59,17 @@
|
||||
"fieldtype": "Check",
|
||||
"label": "Allow Negative Balance",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "include_holiday",
|
||||
"fieldtype": "Check",
|
||||
"label": "Include holidays within leaves as leaves",
|
||||
"permlevel": 0
|
||||
}
|
||||
],
|
||||
"icon": "icon-flag",
|
||||
"idx": 1,
|
||||
"modified": "2015-05-08 05:15:24.194053",
|
||||
"modified": "2015-07-29 05:15:24",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Leave Type",
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
[
|
||||
{
|
||||
"doctype": "Leave Type",
|
||||
"leave_type_name": "_Test Leave Type"
|
||||
"leave_type_name": "_Test Leave Type",
|
||||
"include_holiday": 1
|
||||
},
|
||||
{
|
||||
"doctype": "Leave Type",
|
||||
"is_lwp": 1,
|
||||
"leave_type_name": "_Test Leave Type LWP"
|
||||
"leave_type_name": "_Test Leave Type LWP",
|
||||
"include_holiday": 1
|
||||
}
|
||||
]
|
||||
@@ -1,193 +1,193 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 0,
|
||||
"autoname": "Offer-.#####",
|
||||
"creation": "2015-03-04 14:20:17.662207",
|
||||
"custom": 0,
|
||||
"default_print_format": "Offer Letter",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Transaction",
|
||||
"allow_copy": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 0,
|
||||
"autoname": "Offer-.#####",
|
||||
"creation": "2015-03-04 14:20:17.662207",
|
||||
"custom": 0,
|
||||
"default_print_format": "Offer Letter",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Transaction",
|
||||
"fields": [
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "job_applicant",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Job Applicant",
|
||||
"no_copy": 0,
|
||||
"options": "Job Applicant",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "job_applicant",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Job Applicant",
|
||||
"no_copy": 0,
|
||||
"options": "Job Applicant",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "applicant_name",
|
||||
"fieldtype": "Data",
|
||||
"label": "Applicant Name",
|
||||
"options": "job_applicant.applicant_name",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"read_only": 1,
|
||||
"fieldname": "applicant_name",
|
||||
"fieldtype": "Data",
|
||||
"label": "Applicant Name",
|
||||
"options": "job_applicant.applicant_name",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"read_only": 1,
|
||||
"reqd": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"label": "Status",
|
||||
"options": "Awaiting Response\nAccepted\nRejected ",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"allow_on_submit": 1,
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"label": "Status",
|
||||
"options": "Awaiting Response\nAccepted\nRejected",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"default": "",
|
||||
"fieldname": "offer_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Offer Date",
|
||||
"permlevel": 0,
|
||||
"default": "",
|
||||
"fieldname": "offer_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Offer Date",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "designation",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Designation",
|
||||
"no_copy": 0,
|
||||
"options": "Designation",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "designation",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Designation",
|
||||
"no_copy": 0,
|
||||
"options": "Designation",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"label": "Company",
|
||||
"options": "Company",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"label": "Company",
|
||||
"options": "Company",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"reqd": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_4",
|
||||
"fieldtype": "Section Break",
|
||||
"permlevel": 0,
|
||||
"fieldname": "section_break_4",
|
||||
"fieldtype": "Section Break",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "offer_terms",
|
||||
"fieldtype": "Table",
|
||||
"label": "Offer Letter Terms",
|
||||
"options": "Offer Letter Term",
|
||||
"permlevel": 0,
|
||||
"fieldname": "offer_terms",
|
||||
"fieldtype": "Table",
|
||||
"label": "Offer Letter Terms",
|
||||
"options": "Offer Letter Term",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_14",
|
||||
"fieldtype": "Section Break",
|
||||
"permlevel": 0,
|
||||
"fieldname": "section_break_14",
|
||||
"fieldtype": "Section Break",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "select_terms",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Select Terms and Conditions",
|
||||
"no_copy": 0,
|
||||
"options": "Terms and Conditions",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "select_terms",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Select Terms and Conditions",
|
||||
"no_copy": 0,
|
||||
"options": "Terms and Conditions",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "terms",
|
||||
"fieldtype": "Text Editor",
|
||||
"label": "Terms and Conditions",
|
||||
"options": "",
|
||||
"permlevel": 0,
|
||||
"fieldname": "terms",
|
||||
"fieldtype": "Text Editor",
|
||||
"label": "Terms and Conditions",
|
||||
"options": "",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
"label": "Amended From",
|
||||
"no_copy": 1,
|
||||
"options": "Offer Letter",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
"label": "Amended From",
|
||||
"no_copy": 1,
|
||||
"options": "Offer Letter",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"in_create": 0,
|
||||
"in_dialog": 0,
|
||||
"is_submittable": 1,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"modified": "2015-04-01 05:51:39.841591",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Offer Letter",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
],
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"in_create": 0,
|
||||
"in_dialog": 0,
|
||||
"is_submittable": 1,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"modified": "2015-07-29 05:51:39.841591",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Offer Letter",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 1,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"import": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR User",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"amend": 1,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"import": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR User",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
],
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "applicant_name"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +1,44 @@
|
||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
// License: GNU General Public License v3. See license.txt
|
||||
|
||||
var display_activity_log = function(msg) {
|
||||
cur_frm.cscript.display_activity_log = function(msg) {
|
||||
if(!cur_frm.ss_html)
|
||||
cur_frm.ss_html = $a(cur_frm.fields_dict['activity_log'].wrapper,'div');
|
||||
cur_frm.ss_html.innerHTML =
|
||||
'<div class="padding"><h4>'+__("Activity Log:")+'</h4>'+msg+'</div>';
|
||||
if(msg) {
|
||||
cur_frm.ss_html.innerHTML =
|
||||
'<div class="padding"><h4>'+__("Activity Log:")+'</h4>'+msg+'</div>';
|
||||
} else {
|
||||
cur_frm.ss_html.innerHTML = "";
|
||||
}
|
||||
}
|
||||
|
||||
//Create salary slip
|
||||
//-----------------------
|
||||
cur_frm.cscript.create_salary_slip = function(doc, cdt, cdn) {
|
||||
cur_frm.cscript.display_activity_log("");
|
||||
var callback = function(r, rt){
|
||||
if (r.message)
|
||||
display_activity_log(r.message);
|
||||
cur_frm.cscript.display_activity_log(r.message);
|
||||
}
|
||||
return $c('runserverobj', args={'method':'create_sal_slip','docs':doc},callback);
|
||||
}
|
||||
|
||||
cur_frm.cscript.submit_salary_slip = function(doc, cdt, cdn) {
|
||||
cur_frm.cscript.display_activity_log("");
|
||||
var check = confirm(__("Do you really want to Submit all Salary Slip for month {0} and year {1}", [doc.month, doc.fiscal_year]));
|
||||
if(check){
|
||||
// clear all in locals
|
||||
if(locals["Salary Slip"]) {
|
||||
$.each(locals["Salary Slip"], function(name, d) {
|
||||
frappe.model.remove_from_locals("Salary Slip", name);
|
||||
});
|
||||
}
|
||||
|
||||
var callback = function(r, rt){
|
||||
if (r.message)
|
||||
display_activity_log(r.message);
|
||||
cur_frm.cscript.display_activity_log(r.message);
|
||||
}
|
||||
|
||||
return $c('runserverobj', args={'method':'submit_salary_slip','docs':doc},callback);
|
||||
}
|
||||
}
|
||||
@@ -45,6 +59,6 @@ cur_frm.cscript.make_jv = function(doc, dt, dn) {
|
||||
}
|
||||
|
||||
|
||||
frappe.ui.form.on("Salary Manager", "refresh", function(frm) {
|
||||
frappe.ui.form.on("Process Payroll", "refresh", function(frm) {
|
||||
frm.disable_save();
|
||||
});
|
||||
});
|
||||
@@ -154,10 +154,10 @@
|
||||
"icon": "icon-cog",
|
||||
"idx": 1,
|
||||
"issingle": 1,
|
||||
"modified": "2015-06-05 11:33:00.152362",
|
||||
"modified": "2015-07-07 07:16:02.380839",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Salary Manager",
|
||||
"name": "Process Payroll",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
@@ -8,7 +8,7 @@ from frappe import _
|
||||
|
||||
from frappe.model.document import Document
|
||||
|
||||
class SalaryManager(Document):
|
||||
class ProcessPayroll(Document):
|
||||
|
||||
def get_emp_list(self):
|
||||
"""
|
||||
@@ -101,7 +101,7 @@ class SalaryManager(Document):
|
||||
log = "<p>No employee for the above selected criteria OR salary slip already created</p>"
|
||||
if ss_list:
|
||||
log = "<b>Salary Slip Created For</b>\
|
||||
<br><br>%s" % '<br>'.join(ss_list)
|
||||
<br><br>%s" % '<br>'.join(self.format_as_links(ss_list))
|
||||
return log
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ class SalaryManager(Document):
|
||||
else:
|
||||
all_ss = [d[0] for d in all_ss]
|
||||
|
||||
submitted_ss = list(set(all_ss) - set(not_submitted_ss))
|
||||
submitted_ss = self.format_as_links(list(set(all_ss) - set(not_submitted_ss)))
|
||||
if submitted_ss:
|
||||
mail_sent_msg = self.send_email and " (Mail has been sent to the employee)" or ""
|
||||
log = """
|
||||
@@ -164,6 +164,9 @@ class SalaryManager(Document):
|
||||
"""% ('<br>'.join(not_submitted_ss))
|
||||
return log
|
||||
|
||||
def format_as_links(self, ss_list):
|
||||
return ['<a href="#Form/Salary Slip/{0}">{0}</a>'.format(s) for s in ss_list]
|
||||
|
||||
|
||||
def get_total_salary(self):
|
||||
"""
|
||||
@@ -1 +0,0 @@
|
||||
Tool to issue monthly Salary Slips to all Employees.
|
||||
@@ -1,21 +0,0 @@
|
||||
# ERPNext - web based ERP (http://erpnext.com)
|
||||
# Copyright (C) 2012 Frappe Technologies Pvt Ltd
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from frappe import ValidationError
|
||||
|
||||
class SalarySlipExistsError(ValidationError): pass
|
||||
|
||||
@@ -49,7 +49,7 @@ class SalarySlip(TransactionBase):
|
||||
if not self.month:
|
||||
self.month = "%02d" % getdate(nowdate()).month
|
||||
|
||||
m = frappe.get_doc('Salary Manager').get_month_details(self.fiscal_year, self.month)
|
||||
m = frappe.get_doc('Process Payroll').get_month_details(self.fiscal_year, self.month)
|
||||
holidays = self.get_holidays_for_employee(m)
|
||||
|
||||
if not cint(frappe.db.get_value("HR Settings", "HR Settings",
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
"fieldname": "d_depends_on_lwp",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 0,
|
||||
"label": "Depends on LWP",
|
||||
"label": "Depends on Leave Without Pay",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1
|
||||
},
|
||||
@@ -46,7 +46,7 @@
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"modified": "2015-03-03 12:41:04.505378",
|
||||
"modified": "2015-07-07 07:13:11.919941",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Salary Slip Deduction",
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
"fieldname": "e_depends_on_lwp",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 0,
|
||||
"label": "Depends on LWP",
|
||||
"label": "Depends on Leave Without Pay",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1
|
||||
},
|
||||
@@ -46,7 +46,7 @@
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"modified": "2015-03-03 12:42:49.087748",
|
||||
"modified": "2015-07-07 07:13:24.833881",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Salary Slip Earning",
|
||||
|
||||
@@ -9,8 +9,13 @@ from frappe.desk.reportview import execute as runreport
|
||||
def execute(filters=None):
|
||||
if not filters: filters = {}
|
||||
|
||||
employee_filters = filters.get("company") and \
|
||||
[["Employee", "company", "=", filters.get("company")]] or None
|
||||
employee_filters = {
|
||||
"status": "Active"
|
||||
}
|
||||
|
||||
if filters.get("company"):
|
||||
filters["company"] = filters.company
|
||||
|
||||
employees = runreport(doctype="Employee", fields=["name", "employee_name", "department"],
|
||||
filters=employee_filters, limit_page_length=None)
|
||||
|
||||
|
||||
@@ -75,8 +75,20 @@ def get_conditions(filters):
|
||||
filters["month"] = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov",
|
||||
"Dec"].index(filters["month"]) + 1
|
||||
|
||||
from frappe.model.document import Document
|
||||
fiscal_years = frappe.get_doc("Fiscal Year",filters["fiscal_year"])
|
||||
import datetime
|
||||
year_start = fiscal_years.year_start_date.strftime("%Y")
|
||||
year_end = fiscal_years.year_end_date.strftime("%Y")
|
||||
dt_test = datetime.datetime.strptime(year_end + "-" + str(100+int(filters["month"]))[2:3] + "-01", "%Y-%m-%d")
|
||||
date_test = datetime.date(dt_test.year, dt_test.month, dt_test.day)
|
||||
if date_test > fiscal_years.year_end_date:
|
||||
year_target = year_start
|
||||
else:
|
||||
year_target = year_end
|
||||
|
||||
from calendar import monthrange
|
||||
filters["total_days_in_month"] = monthrange(cint(filters["fiscal_year"].split("-")[-1]),
|
||||
filters["total_days_in_month"] = monthrange(cint(year_target),
|
||||
filters["month"])[1]
|
||||
|
||||
conditions = " and month(att_date) = %(month)s and fiscal_year = %(fiscal_year)s"
|
||||
|
||||
@@ -24,7 +24,7 @@ class HubSettings(Document):
|
||||
def publish_selling_items(self):
|
||||
"""Set `publish_in_hub`=1 for all Sales Items"""
|
||||
for item in frappe.get_all("Item", fields=["name"],
|
||||
filters={"is_sales_item": "Yes", "publish_in_hub": "0"}):
|
||||
filters={"is_sales_item": 1, "publish_in_hub": "0"}):
|
||||
frappe.db.set_value("Item", item.name, "publish_in_hub", 1)
|
||||
|
||||
def register(self):
|
||||
|
||||
@@ -107,7 +107,7 @@ class BOM(Document):
|
||||
rate = 0
|
||||
if arg['bom_no']:
|
||||
rate = self.get_bom_unitcost(arg['bom_no'])
|
||||
elif arg and (arg['is_purchase_item'] == 'Yes' or arg['is_sub_contracted_item'] == 'Yes'):
|
||||
elif arg and (arg['is_purchase_item'] == 1 or arg['is_sub_contracted_item'] == 1):
|
||||
if self.rm_cost_as_per == 'Valuation Rate':
|
||||
rate = self.get_valuation_rate(arg)
|
||||
elif self.rm_cost_as_per == 'Last Purchase Rate':
|
||||
@@ -181,15 +181,12 @@ class BOM(Document):
|
||||
if item.default_bom != self.name:
|
||||
item.default_bom = self.name
|
||||
item.save()
|
||||
|
||||
else:
|
||||
if not self.is_active:
|
||||
frappe.db.set(self, "is_default", 0)
|
||||
|
||||
item = frappe.get_doc("Item", self.item)
|
||||
if item.default_bom == self.name:
|
||||
item.default_bom = None
|
||||
item.save()
|
||||
frappe.db.set(self, "is_default", 0)
|
||||
item = frappe.get_doc("Item", self.item)
|
||||
if item.default_bom == self.name:
|
||||
item.default_bom = None
|
||||
item.save()
|
||||
|
||||
def clear_operations(self):
|
||||
if not self.with_operations:
|
||||
@@ -367,7 +364,7 @@ class BOM(Document):
|
||||
if self.with_operations and not self.get('operations'):
|
||||
frappe.throw(_("Operations cannot be left blank."))
|
||||
|
||||
def get_bom_items_as_dict(bom, qty=1, fetch_exploded=1):
|
||||
def get_bom_items_as_dict(bom, company, qty=1, fetch_exploded=1):
|
||||
item_dict = {}
|
||||
|
||||
# Did not use qty_consumed_per_unit in the query, as it leads to rounding loss
|
||||
@@ -388,14 +385,14 @@ def get_bom_items_as_dict(bom, qty=1, fetch_exploded=1):
|
||||
and bom_item.docstatus < 2
|
||||
and bom_item.parent = %(bom)s
|
||||
and item.name = bom_item.item_code
|
||||
and ifnull(item.is_stock_item, 'No') = 'Yes'
|
||||
and is_stock_item = 1
|
||||
{conditions}
|
||||
group by item_code, stock_uom"""
|
||||
|
||||
if fetch_exploded:
|
||||
query = query.format(table="BOM Explosion Item",
|
||||
conditions="""and ifnull(item.is_pro_applicable, 'No') = 'No'
|
||||
and ifnull(item.is_sub_contracted_item, 'No') = 'No' """)
|
||||
conditions="""and item.is_pro_applicable = 0
|
||||
and item.is_sub_contracted_item = 0 """)
|
||||
items = frappe.db.sql(query, { "qty": qty, "bom": bom }, as_dict=True)
|
||||
else:
|
||||
query = query.format(table="BOM Item", conditions="")
|
||||
@@ -408,11 +405,18 @@ def get_bom_items_as_dict(bom, qty=1, fetch_exploded=1):
|
||||
else:
|
||||
item_dict[item.item_code] = item
|
||||
|
||||
for item, item_details in item_dict.items():
|
||||
for d in [["Account", "expense_account", "default_expense_account"],
|
||||
["Cost Center", "cost_center", "cost_center"], ["Warehouse", "default_warehouse", ""]]:
|
||||
company_in_record = frappe.db.get_value(d[0], item_details.get(d[1]), "company")
|
||||
if not item_details.get(d[1]) or (company_in_record and company != company_in_record):
|
||||
item_dict[item][d[1]] = frappe.db.get_value("Company", company, d[2]) if d[2] else None
|
||||
|
||||
return item_dict
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_bom_items(bom, qty=1, fetch_exploded=1):
|
||||
items = get_bom_items_as_dict(bom, qty, fetch_exploded).values()
|
||||
def get_bom_items(bom, company, qty=1, fetch_exploded=1):
|
||||
items = get_bom_items_as_dict(bom, company, qty, fetch_exploded).values()
|
||||
items.sort(lambda a, b: a.item_code > b.item_code and 1 or -1)
|
||||
return items
|
||||
|
||||
|
||||
@@ -12,14 +12,14 @@ test_records = frappe.get_test_records('BOM')
|
||||
class TestBOM(unittest.TestCase):
|
||||
def test_get_items(self):
|
||||
from erpnext.manufacturing.doctype.bom.bom import get_bom_items_as_dict
|
||||
items_dict = get_bom_items_as_dict(bom=get_default_bom(), qty=1, fetch_exploded=0)
|
||||
items_dict = get_bom_items_as_dict(bom=get_default_bom(), company="_Test Company", qty=1, fetch_exploded=0)
|
||||
self.assertTrue(test_records[2]["items"][0]["item_code"] in items_dict)
|
||||
self.assertTrue(test_records[2]["items"][1]["item_code"] in items_dict)
|
||||
self.assertEquals(len(items_dict.values()), 2)
|
||||
|
||||
def test_get_items_exploded(self):
|
||||
from erpnext.manufacturing.doctype.bom.bom import get_bom_items_as_dict
|
||||
items_dict = get_bom_items_as_dict(bom=get_default_bom(), qty=1, fetch_exploded=1)
|
||||
items_dict = get_bom_items_as_dict(bom=get_default_bom(), company="_Test Company", qty=1, fetch_exploded=1)
|
||||
self.assertTrue(test_records[2]["items"][0]["item_code"] in items_dict)
|
||||
self.assertFalse(test_records[2]["items"][1]["item_code"] in items_dict)
|
||||
self.assertTrue(test_records[0]["items"][0]["item_code"] in items_dict)
|
||||
@@ -28,7 +28,7 @@ class TestBOM(unittest.TestCase):
|
||||
|
||||
def test_get_items_list(self):
|
||||
from erpnext.manufacturing.doctype.bom.bom import get_bom_items
|
||||
self.assertEquals(len(get_bom_items(bom=get_default_bom())), 3)
|
||||
self.assertEquals(len(get_bom_items(bom=get_default_bom(), company="_Test Company")), 3)
|
||||
|
||||
def test_default_bom(self):
|
||||
def _get_default_bom_in_item():
|
||||
|
||||
@@ -15,6 +15,14 @@
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"description": "Disables creation of time logs against Production Orders.\nOperations shall not be tracked against Production Order",
|
||||
"fieldname": "disable_capacity_planning",
|
||||
"fieldtype": "Check",
|
||||
"label": "Disable Capacity Planning and Time Tracking",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"description": "Plan time logs outside Workstation Working Hours.",
|
||||
"fieldname": "allow_overtime",
|
||||
@@ -72,7 +80,7 @@
|
||||
"is_submittable": 0,
|
||||
"issingle": 1,
|
||||
"istable": 0,
|
||||
"modified": "2015-06-15 05:52:22.986958",
|
||||
"modified": "2015-07-23 08:12:33.889753",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Manufacturing Settings",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user