mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-17 20:19:20 +00:00
Compare commits
168 Commits
v11.1.66
...
v11-pre-re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
84c049071c | ||
|
|
8b819e3a7f | ||
|
|
7e4f8fa04d | ||
|
|
652181600d | ||
|
|
e4f300c903 | ||
|
|
d839c46f10 | ||
|
|
6d45dfd6e8 | ||
|
|
5caa40857d | ||
|
|
78b7f69e0c | ||
|
|
8d9b58d801 | ||
|
|
a611cc5916 | ||
|
|
c6466c7d97 | ||
|
|
b35db7e819 | ||
|
|
44875482ac | ||
|
|
f06cc233a8 | ||
|
|
fdd93cba03 | ||
|
|
10f53f04d7 | ||
|
|
884dc28af6 | ||
|
|
a506930b63 | ||
|
|
f6836c1d89 | ||
|
|
3e2fe12c9d | ||
|
|
5b2ca9e133 | ||
|
|
f8dc7b32d5 | ||
|
|
0393cb5c43 | ||
|
|
4206b52bdc | ||
|
|
9e66c86d6f | ||
|
|
ec46b4d4c6 | ||
|
|
39c71e26b9 | ||
|
|
77285317c0 | ||
|
|
a95c09bef6 | ||
|
|
6b901d0c1a | ||
|
|
8a7ccd9874 | ||
|
|
2f2e748b7a | ||
|
|
549ab68eb0 | ||
|
|
0b9bf4d0ac | ||
|
|
1c5df5dede | ||
|
|
41d2357dc4 | ||
|
|
af79714f40 | ||
|
|
8a5f31da34 | ||
|
|
47a7e3422b | ||
|
|
9efb087e22 | ||
|
|
3d58dd6aa5 | ||
|
|
ac7966cd7e | ||
|
|
61ddb508d4 | ||
|
|
d973fb8823 | ||
|
|
a649414419 | ||
|
|
270f23b966 | ||
|
|
4d745a39e0 | ||
|
|
5e0b5cb283 | ||
|
|
69358cfd40 | ||
|
|
ad1ba2bb76 | ||
|
|
c44abd2f78 | ||
|
|
0bcada8f3c | ||
|
|
a6b110a7d3 | ||
|
|
b4ce43306b | ||
|
|
85a9f55fa7 | ||
|
|
596c0d2060 | ||
|
|
723421f375 | ||
|
|
f9297416f2 | ||
|
|
a8d2916e61 | ||
|
|
0f70f20ec5 | ||
|
|
73d9d8fec9 | ||
|
|
c4756e938f | ||
|
|
faa5d90f1b | ||
|
|
3b37a109c5 | ||
|
|
ab4aa53f52 | ||
|
|
3483426fe7 | ||
|
|
3039094737 | ||
|
|
e21602d432 | ||
|
|
6067ef3c49 | ||
|
|
b78128a7fe | ||
|
|
c8cbb87168 | ||
|
|
aed8aeb83a | ||
|
|
fa47445e11 | ||
|
|
0220acf100 | ||
|
|
0fe8f8e6d9 | ||
|
|
f87b766a26 | ||
|
|
2262e5d443 | ||
|
|
b9cad8d891 | ||
|
|
dafdc6035a | ||
|
|
c8369c10ff | ||
|
|
08b8ed5ca6 | ||
|
|
6cefdb40d1 | ||
|
|
3ad65ec57d | ||
|
|
364332bcfe | ||
|
|
9965f443ee | ||
|
|
d87d644dc2 | ||
|
|
eeab3128aa | ||
|
|
7b2cec8da2 | ||
|
|
6e3cbd8698 | ||
|
|
b5e1f846ce | ||
|
|
f06b31aab4 | ||
|
|
f8502317a9 | ||
|
|
9c7a33405d | ||
|
|
0ee46a624c | ||
|
|
5485d4c435 | ||
|
|
fb2d4884b3 | ||
|
|
3b38a9e418 | ||
|
|
437d3e37d6 | ||
|
|
1b9a55e766 | ||
|
|
a5353a8d04 | ||
|
|
e1bc0a1028 | ||
|
|
92116abd92 | ||
|
|
e5731b3d0f | ||
|
|
a36c4326c3 | ||
|
|
5a0a4bdcff | ||
|
|
d2dc889849 | ||
|
|
dbcdf7e225 | ||
|
|
7fdef64152 | ||
|
|
b2be301988 | ||
|
|
68db5a6792 | ||
|
|
f232965392 | ||
|
|
2ff7197752 | ||
|
|
1d3b5b0437 | ||
|
|
8280d32967 | ||
|
|
4a79072c71 | ||
|
|
721a00cd22 | ||
|
|
8ce7893bf0 | ||
|
|
0f87282aef | ||
|
|
de51217a80 | ||
|
|
bc01dafbba | ||
|
|
a985bfc29a | ||
|
|
08dbb13451 | ||
|
|
170dd37b86 | ||
|
|
b1744972e0 | ||
|
|
7aa993b14b | ||
|
|
ad89cb0ef3 | ||
|
|
a185b51f0d | ||
|
|
1ff81bca7d | ||
|
|
b02db3c3e8 | ||
|
|
d1d835347e | ||
|
|
ba245553f0 | ||
|
|
112902a9c4 | ||
|
|
3f4cdcc7a4 | ||
|
|
91f81b07d9 | ||
|
|
66e92041b9 | ||
|
|
f2dc89c7a0 | ||
|
|
10b226af10 | ||
|
|
115887a886 | ||
|
|
a1f5c22da7 | ||
|
|
712c01d5bd | ||
|
|
bd4e296336 | ||
|
|
b52d81ef6a | ||
|
|
15432c76a4 | ||
|
|
dd3cd6e2ba | ||
|
|
5889a29656 | ||
|
|
0e7ca6ada7 | ||
|
|
5a2ea528e8 | ||
|
|
8957093439 | ||
|
|
507c435dee | ||
|
|
8889edad72 | ||
|
|
e27d1aebd5 | ||
|
|
ef567eac37 | ||
|
|
f8e0a2204e | ||
|
|
baecc7fd31 | ||
|
|
529b465337 | ||
|
|
675e2670b2 | ||
|
|
3919fd10ad | ||
|
|
b4e61e19bb | ||
|
|
85be3ec796 | ||
|
|
aa3d6ed11e | ||
|
|
382735ad2f | ||
|
|
8d42b75e29 | ||
|
|
7e03e046ec | ||
|
|
43a0161257 | ||
|
|
ce60dc3ea3 | ||
|
|
b23da53fee | ||
|
|
d37a30fc47 |
@@ -76,5 +76,6 @@ install:
|
||||
- bench --site test_site reinstall --yes
|
||||
|
||||
after_script:
|
||||
- pip install coverage==4.5.4
|
||||
- pip install python-coveralls
|
||||
- coveralls -b apps/erpnext -d ../../sites/.coverage
|
||||
|
||||
@@ -5,7 +5,7 @@ import frappe
|
||||
from erpnext.hooks import regional_overrides
|
||||
from frappe.utils import getdate
|
||||
|
||||
__version__ = '11.1.66'
|
||||
__version__ = '11.1.77'
|
||||
|
||||
def get_default_company(user=None):
|
||||
'''Get default company for user'''
|
||||
@@ -144,4 +144,4 @@ def is_member():
|
||||
last_membership = get_last_membership()
|
||||
if last_membership and getdate(last_membership.to_date) > getdate():
|
||||
return True
|
||||
return False
|
||||
return False
|
||||
|
||||
@@ -174,6 +174,8 @@ def make_gl_entries(doc, credit_account, debit_account, against,
|
||||
# GL Entry for crediting the amount in the deferred expense
|
||||
from erpnext.accounts.general_ledger import make_gl_entries
|
||||
|
||||
if amount == 0: return
|
||||
|
||||
gl_entries = []
|
||||
gl_entries.append(
|
||||
doc.get_gl_dict({
|
||||
|
||||
@@ -100,7 +100,10 @@ class Account(NestedSet):
|
||||
if ancestors:
|
||||
if frappe.get_value("Company", self.company, "allow_account_creation_against_child_company"):
|
||||
return
|
||||
frappe.throw(_("Please add the account to root level Company - %s" % ancestors[0]))
|
||||
|
||||
if not frappe.db.get_value("Account",
|
||||
{'account_name': self.account_name, 'company': ancestors[0]}, 'name'):
|
||||
frappe.throw(_("Please add the account to root level Company - %s" % ancestors[0]))
|
||||
else:
|
||||
descendants = get_descendants_of('Company', self.company)
|
||||
if not descendants: return
|
||||
@@ -114,21 +117,7 @@ class Account(NestedSet):
|
||||
|
||||
if not parent_acc_name_map: return
|
||||
|
||||
for company in descendants:
|
||||
if not parent_acc_name_map.get(company):
|
||||
frappe.throw(_("While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA")
|
||||
.format(company, parent_acc_name))
|
||||
|
||||
doc = frappe.copy_doc(self)
|
||||
doc.flags.ignore_root_company_validation = True
|
||||
doc.update({
|
||||
"company": company,
|
||||
"account_currency": None,
|
||||
"parent_account": parent_acc_name_map[company]
|
||||
})
|
||||
doc.save()
|
||||
frappe.msgprint(_("Account {0} is added in the child company {1}")
|
||||
.format(doc.name, company))
|
||||
self.create_account_for_child_company(parent_acc_name_map, descendants, parent_acc_name)
|
||||
|
||||
def validate_group_or_ledger(self):
|
||||
if self.get("__islocal"):
|
||||
@@ -170,6 +159,49 @@ class Account(NestedSet):
|
||||
if frappe.db.get_value("GL Entry", {"account": self.name}):
|
||||
frappe.throw(_("Currency can not be changed after making entries using some other currency"))
|
||||
|
||||
def create_account_for_child_company(self, parent_acc_name_map, descendants, parent_acc_name):
|
||||
for company in descendants:
|
||||
if not parent_acc_name_map.get(company):
|
||||
frappe.throw(_("While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA")
|
||||
.format(company, parent_acc_name))
|
||||
|
||||
filters = {
|
||||
"account_name": self.account_name,
|
||||
"company": company
|
||||
}
|
||||
|
||||
if self.account_number:
|
||||
filters["account_number"] = self.account_number
|
||||
|
||||
child_account = frappe.db.get_value("Account", filters, 'name')
|
||||
|
||||
if not child_account:
|
||||
doc = frappe.copy_doc(self)
|
||||
doc.flags.ignore_root_company_validation = True
|
||||
doc.update({
|
||||
"company": company,
|
||||
# parent account's currency should be passed down to child account's curreny
|
||||
# if it is None, it picks it up from default company currency, which might be unintended
|
||||
"account_currency": self.account_currency,
|
||||
"parent_account": parent_acc_name_map[company]
|
||||
})
|
||||
|
||||
doc.save()
|
||||
frappe.msgprint(_("Account {0} is added in the child company {1}")
|
||||
.format(doc.name, company))
|
||||
elif child_account:
|
||||
# update the parent company's value in child companies
|
||||
doc = frappe.get_doc("Account", child_account)
|
||||
parent_value_changed = False
|
||||
for field in ['account_type', 'account_currency',
|
||||
'freeze_account', 'balance_must_be']:
|
||||
if doc.get(field) != self.get(field):
|
||||
parent_value_changed = True
|
||||
doc.set(field, self.get(field))
|
||||
|
||||
if parent_value_changed:
|
||||
doc.save()
|
||||
|
||||
def convert_group_to_ledger(self):
|
||||
if self.check_if_child_exists():
|
||||
throw(_("Account with child nodes cannot be converted to ledger"))
|
||||
|
||||
@@ -1,465 +1,466 @@
|
||||
{
|
||||
"country_code": "ae",
|
||||
"name": "U.A.E - Chart of Accounts",
|
||||
"country_code": "ae",
|
||||
"name": "U.A.E - Chart of Accounts",
|
||||
"tree": {
|
||||
"Assets": {
|
||||
"Current Assets": {
|
||||
"Accounts Receivable": {
|
||||
"Corporate Credit Cards": {
|
||||
"account_type": "Receivable"
|
||||
},
|
||||
},
|
||||
"Other Receivable": {
|
||||
"Accrued Rebates Due from Suppliers": {
|
||||
"account_type": "Receivable"
|
||||
},
|
||||
"Accured Income from Suppliers": {
|
||||
},
|
||||
"Accrued Income from Suppliers": {
|
||||
"account_type": "Receivable"
|
||||
},
|
||||
},
|
||||
"Other Debtors": {
|
||||
"account_type": "Receivable"
|
||||
},
|
||||
},
|
||||
"account_type": "Receivable"
|
||||
},
|
||||
},
|
||||
"Post Dated Cheques Received": {
|
||||
"account_type": "Receivable"
|
||||
},
|
||||
},
|
||||
"Staff Receivable": {
|
||||
"account_type": "Receivable"
|
||||
},
|
||||
},
|
||||
"Trade Receivable": {
|
||||
"account_type": "Receivable"
|
||||
},
|
||||
},
|
||||
"Trade in Opening Fees": {
|
||||
"account_type": "Receivable"
|
||||
},
|
||||
},
|
||||
"account_type": "Receivable"
|
||||
},
|
||||
},
|
||||
"Cash in Hand & Banks": {
|
||||
"Banks": {
|
||||
"Bank Margin On LC & LG": {},
|
||||
"Banks Blocked Deposits": {},
|
||||
"Banks Call Deposit Accounts": {},
|
||||
"Bank Margin On LC & LG": {},
|
||||
"Banks Blocked Deposits": {},
|
||||
"Banks Call Deposit Accounts": {},
|
||||
"Banks Current Accounts": {
|
||||
"account_type": "Bank"
|
||||
},
|
||||
},
|
||||
"account_type": "Bank"
|
||||
},
|
||||
},
|
||||
"Cash in Hand": {
|
||||
"Cash in Safe": {
|
||||
"Main Safe": {
|
||||
"account_type": "Cash"
|
||||
},
|
||||
},
|
||||
"Main Safe - Foreign Currency": {
|
||||
"account_type": "Cash"
|
||||
}
|
||||
},
|
||||
},
|
||||
"Petty Cash": {
|
||||
"Petty Cash - Admininistration": {
|
||||
"account_type": "Cash"
|
||||
},
|
||||
},
|
||||
"Petty Cash - Others": {
|
||||
"account_type": "Cash"
|
||||
}
|
||||
},
|
||||
},
|
||||
"account_type": "Cash"
|
||||
},
|
||||
},
|
||||
"Cash in Transit": {
|
||||
"Credit Cards": {
|
||||
"Gateway Credit Cards": {
|
||||
"account_type": "Bank"
|
||||
},
|
||||
},
|
||||
"Manual Visa & Master Cards": {
|
||||
"account_type": "Bank"
|
||||
},
|
||||
},
|
||||
"PayPal Account": {
|
||||
"account_type": "Bank"
|
||||
},
|
||||
},
|
||||
"Visa & Master Credit Cards": {
|
||||
"account_type": "Bank"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
"Inventory": {
|
||||
"Consigned Stock": {
|
||||
"Handling Difference in Inventory": {
|
||||
"account_type": "Stock Adjustment"
|
||||
},
|
||||
"Items Delivered to Customs on temprary Base": {}
|
||||
},
|
||||
"Handling Difference in Inventory": {},
|
||||
"Items Delivered to Customs on temporary Base": {}
|
||||
},
|
||||
"Stock in Hand": {
|
||||
"account_type": "Stock"
|
||||
}
|
||||
},
|
||||
"Perliminary and Preoperating Expenses": {
|
||||
},
|
||||
"Preliminary and Preoperating Expenses": {
|
||||
"Preoperating Expenses": {}
|
||||
},
|
||||
},
|
||||
"Prepayments & Deposits": {
|
||||
"Deposits": {
|
||||
"Deposit - Office Rent": {},
|
||||
"Deposit Others": {},
|
||||
"Deposit to Immigration (Visa)": {},
|
||||
"Deposit - Office Rent": {},
|
||||
"Deposit Others": {},
|
||||
"Deposit to Immigration (Visa)": {},
|
||||
"Deposits - Customs": {}
|
||||
},
|
||||
},
|
||||
"Prepaid Taxes": {
|
||||
"Sales Taxes Receivables": {},
|
||||
"Sales Taxes Receivables": {},
|
||||
"Withholding Tax Receivables": {}
|
||||
},
|
||||
},
|
||||
"Prepayments": {
|
||||
"Other Prepayments": {},
|
||||
"PrePaid Advertisement Expenses": {},
|
||||
"Prepaid Bank Guarantee": {},
|
||||
"Prepaid Consultancy Fees": {},
|
||||
"Prepaid Employees Housing": {},
|
||||
"Prepaid Finance charge for Loans": {},
|
||||
"Prepaid Legal Fees": {},
|
||||
"Prepaid License Fees": {},
|
||||
"Prepaid Life Insurance": {},
|
||||
"Prepaid Maintenance": {},
|
||||
"Prepaid Medical Insurance": {},
|
||||
"Prepaid Office Rent": {},
|
||||
"Prepaid Other Insurance": {},
|
||||
"Prepaid Schooling Fees": {},
|
||||
"Prepaid Site Hosting Fees": {},
|
||||
"Other Prepayments": {},
|
||||
"PrePaid Advertisement Expenses": {},
|
||||
"Prepaid Bank Guarantee": {},
|
||||
"Prepaid Consultancy Fees": {},
|
||||
"Prepaid Employees Housing": {},
|
||||
"Prepaid Finance charge for Loans": {},
|
||||
"Prepaid Legal Fees": {},
|
||||
"Prepaid License Fees": {},
|
||||
"Prepaid Life Insurance": {},
|
||||
"Prepaid Maintenance": {},
|
||||
"Prepaid Medical Insurance": {},
|
||||
"Prepaid Office Rent": {},
|
||||
"Prepaid Other Insurance": {},
|
||||
"Prepaid Schooling Fees": {},
|
||||
"Prepaid Site Hosting Fees": {},
|
||||
"Prepaid Sponsorship Fees": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
"Long Term Assets": {
|
||||
"Fixed Assets": {
|
||||
"Accumulated Depreciation": {
|
||||
"Acc. Depreciation of Motor Vehicles": {
|
||||
"account_type": "Accumulated Depreciation"
|
||||
},
|
||||
},
|
||||
"Acc. Deprn.Computer Hardware & Software": {
|
||||
"account_type": "Accumulated Depreciation"
|
||||
},
|
||||
},
|
||||
"Acc.Deprn.of Furniture & Office Equipment": {
|
||||
"account_type": "Accumulated Depreciation"
|
||||
},
|
||||
},
|
||||
"Amortisation on Leasehold Improvement": {
|
||||
"account_type": "Accumulated Depreciation"
|
||||
},
|
||||
},
|
||||
"account_type": "Accumulated Depreciation"
|
||||
},
|
||||
},
|
||||
"Fixed Assets (Cost Price)": {
|
||||
"Computer Hardware & Software": {
|
||||
"account_type": "Fixed Asset"
|
||||
},
|
||||
},
|
||||
"Furniture and Equipment": {
|
||||
"account_type": "Fixed Asset"
|
||||
},
|
||||
"Leasehold Improvement": {},
|
||||
"Motor Vehicules": {
|
||||
},
|
||||
"Leasehold Improvement": {},
|
||||
"Motor Vehicles": {
|
||||
"account_type": "Fixed Asset"
|
||||
},
|
||||
"Work In Progrees": {},
|
||||
},
|
||||
"Work In Progress": {},
|
||||
"account_type": "Fixed Asset"
|
||||
}
|
||||
},
|
||||
},
|
||||
"Intangible Assets": {
|
||||
"Computer Card Renewal": {},
|
||||
"Dispoal of Outlets": {},
|
||||
"Computer Card Renewal": {},
|
||||
"Disposal of Outlets": {},
|
||||
"Registration of Trademarks": {}
|
||||
},
|
||||
"Intercompany Accounts": {},
|
||||
},
|
||||
"Intercompany Accounts": {},
|
||||
"Investments": {
|
||||
"Investments in Subsidiaries": {}
|
||||
}
|
||||
},
|
||||
},
|
||||
"root_type": "Asset"
|
||||
},
|
||||
},
|
||||
"Closing And Temporary Accounts": {
|
||||
"Closing Accounts": {
|
||||
"Closing Account": {}
|
||||
},
|
||||
},
|
||||
"root_type": "Liability"
|
||||
},
|
||||
},
|
||||
"Expenses": {
|
||||
"Commercial Expenses": {
|
||||
"Consultancy Fees": {},
|
||||
"Consultancy Fees": {},
|
||||
"Provision for Doubtful Debts": {}
|
||||
},
|
||||
},
|
||||
"Cost of Sale": {
|
||||
"Cost Of Goods Sold": {
|
||||
"Cost Of Goods Sold I/C Sales": {},
|
||||
"Cost Of Goods Sold I/C Sales": {},
|
||||
"Cost of Goods Sold in Trading": {
|
||||
"account_type": "Cost of Goods Sold"
|
||||
},
|
||||
},
|
||||
"account_type": "Cost of Goods Sold"
|
||||
},
|
||||
},
|
||||
"Expenses Included In Valuation": {
|
||||
"account_type": "Expenses Included In Valuation"
|
||||
},
|
||||
"Stock Adjustment": {
|
||||
"account_type": "Stock Adjustment"
|
||||
}
|
||||
},
|
||||
},
|
||||
"Depreciation": {
|
||||
"Depreciation & Amortization": {
|
||||
"Amortization on Leasehold Improvement": {},
|
||||
"Amortization on Leasehold Improvement": {},
|
||||
"Depreciation Of Computer Hard & Soft": {
|
||||
"account_type": "Depreciation"
|
||||
},
|
||||
},
|
||||
"Depreciation Of Furniture & Office Equipment\n\t\t\t": {
|
||||
"account_type": "Depreciation"
|
||||
},
|
||||
},
|
||||
"Depreciation Of Motor Vehicles": {
|
||||
"account_type": "Depreciation"
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
"Direct Expenses": {
|
||||
"Financial Charges": {
|
||||
"Air Miles Card Charges": {},
|
||||
"Amex Credit Cards Charges": {},
|
||||
"Bank Finance & Loan Charges": {},
|
||||
"Credit Card Charges": {},
|
||||
"Credit Card Swipe Charges": {},
|
||||
"Air Miles Card Charges": {},
|
||||
"Amex Credit Cards Charges": {},
|
||||
"Bank Finance & Loan Charges": {},
|
||||
"Credit Card Charges": {},
|
||||
"Credit Card Swipe Charges": {},
|
||||
"PayPal Charges": {}
|
||||
}
|
||||
},
|
||||
},
|
||||
"MISC Charges": {
|
||||
"Other Charges": {
|
||||
"Captial Loss": {
|
||||
"Disposal of Business Branch": {},
|
||||
"Loss On Fixed Assets Disposal": {},
|
||||
"Capital Loss": {
|
||||
"Disposal of Business Branch": {},
|
||||
"Loss On Fixed Assets Disposal": {},
|
||||
"Loss on Difference on Exchange": {}
|
||||
},
|
||||
},
|
||||
"Other Non Operating Exp": {
|
||||
"Other Non Operating Expenses": {}
|
||||
},
|
||||
},
|
||||
"Previous Year Adjustments": {
|
||||
"Previous Year Adjustments Account": {}
|
||||
},
|
||||
},
|
||||
"Royalty Fees": {
|
||||
"Royalty to Parent Co.": {}
|
||||
},
|
||||
},
|
||||
"Tax / Zakat Expenses": {
|
||||
"Income Tax": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Zakat": {},
|
||||
},
|
||||
"Zakat": {},
|
||||
"account_type": "Tax"
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
"Share Resources": {
|
||||
"Share Resource Expenses Account": {}
|
||||
},
|
||||
},
|
||||
"Store Operating Expenses": {
|
||||
"Selling, General & Admin Expenses": {
|
||||
"Advertising Expenses": {
|
||||
"Other - Advertising Expenses": {}
|
||||
},
|
||||
},
|
||||
"Bank & Finance Charges": {
|
||||
"Other Bank Charges": {}
|
||||
},
|
||||
},
|
||||
"Communications": {
|
||||
"Courrier": {},
|
||||
"Others - Communication": {},
|
||||
"Telephone": {},
|
||||
"Courier": {},
|
||||
"Others - Communication": {},
|
||||
"Telephone": {},
|
||||
"Web Site Hosting Fees": {}
|
||||
},
|
||||
},
|
||||
"Office & Various Expenses": {
|
||||
"Cleaning": {},
|
||||
"Convoyance Expenses": {},
|
||||
"Gifts & Donations": {},
|
||||
"Insurance": {},
|
||||
"Kitchen and Buffet Expenses": {},
|
||||
"Maintenance": {},
|
||||
"Others - Office Various Expenses": {},
|
||||
"Security & Guard": {},
|
||||
"Stationary From Suppliers": {},
|
||||
"Stationary Out Of Stock": {},
|
||||
"Subscriptions": {},
|
||||
"Training": {},
|
||||
"Cleaning": {},
|
||||
"Conveyance Expenses": {},
|
||||
"Gifts & Donations": {},
|
||||
"Insurance": {},
|
||||
"Kitchen and Buffet Expenses": {},
|
||||
"Maintenance": {},
|
||||
"Others - Office Various Expenses": {},
|
||||
"Security & Guard": {},
|
||||
"Stationary From Suppliers": {},
|
||||
"Stationary Out Of Stock": {},
|
||||
"Subscriptions": {},
|
||||
"Training": {},
|
||||
"Vehicle Expenses": {}
|
||||
},
|
||||
},
|
||||
"Personnel Cost": {
|
||||
"Basic Salary": {},
|
||||
"End Of Service Indemnity": {},
|
||||
"Housing Allowance": {},
|
||||
"Leave Salary": {},
|
||||
"Leave Ticket": {},
|
||||
"Life Insurance": {},
|
||||
"Medical Insurance": {},
|
||||
"Personnel Cost Others": {},
|
||||
"Sales Commission": {},
|
||||
"Staff School Allowances": {},
|
||||
"Transportation Allowance": {},
|
||||
"Uniform": {},
|
||||
"Basic Salary": {},
|
||||
"End Of Service Indemnity": {},
|
||||
"Housing Allowance": {},
|
||||
"Leave Salary": {},
|
||||
"Leave Ticket": {},
|
||||
"Life Insurance": {},
|
||||
"Medical Insurance": {},
|
||||
"Personnel Cost Others": {},
|
||||
"Sales Commission": {},
|
||||
"Staff School Allowances": {},
|
||||
"Transportation Allowance": {},
|
||||
"Uniform": {},
|
||||
"Visa Expenses": {}
|
||||
},
|
||||
},
|
||||
"Professional & Legal Fees": {
|
||||
"Audit Fees": {},
|
||||
"Legal fees": {},
|
||||
"Others - Professional Fees": {},
|
||||
"Sponsorship Fees": {},
|
||||
"Audit Fees": {},
|
||||
"Legal fees": {},
|
||||
"Others - Professional Fees": {},
|
||||
"Sponsorship Fees": {},
|
||||
"Trade License Fees": {}
|
||||
},
|
||||
},
|
||||
"Provision & Write Off": {
|
||||
"Amortisation of Preoperating Expenses": {},
|
||||
"Cash Shortage": {},
|
||||
"Others - Provision & Write off": {},
|
||||
"Write Off Inventory": {},
|
||||
"Amortisation of Preoperating Expenses": {},
|
||||
"Cash Shortage": {},
|
||||
"Others - Provision & Write off": {},
|
||||
"Write Off Inventory": {},
|
||||
"Write Off Receivables & Payables": {}
|
||||
},
|
||||
},
|
||||
"Rent Expenses": {
|
||||
"Office Rent": {},
|
||||
"Office Rent": {},
|
||||
"Warehouse Rent": {}
|
||||
},
|
||||
},
|
||||
"Travel Expenses": {
|
||||
"Air tickets": {},
|
||||
"Hotel": {},
|
||||
"Meals": {},
|
||||
"Others": {},
|
||||
"Air tickets": {},
|
||||
"Hotel": {},
|
||||
"Meals": {},
|
||||
"Others": {},
|
||||
"Per Diem": {}
|
||||
},
|
||||
},
|
||||
"Utilities": {
|
||||
"Other Utility Cahrges": {},
|
||||
"Other Utility Cahrges": {},
|
||||
"Water & Electricity": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
"root_type": "Expense"
|
||||
},
|
||||
},
|
||||
"Liabilities": {
|
||||
"Current Liabilities": {
|
||||
"Accounts Payable": {
|
||||
"Payables": {
|
||||
"Advance Paybale to Suppliers": {
|
||||
"account_type": "Payable"
|
||||
},
|
||||
},
|
||||
"Consigned Payable": {
|
||||
"account_type": "Payable"
|
||||
},
|
||||
},
|
||||
"Other Payable": {
|
||||
"account_type": "Payable"
|
||||
},
|
||||
},
|
||||
"Post Dated Cheques Paid": {
|
||||
"account_type": "Payable"
|
||||
},
|
||||
"Staff Payable": {},
|
||||
},
|
||||
"Staff Payable": {},
|
||||
"Suppliers Price Protection": {
|
||||
"account_type": "Payable"
|
||||
},
|
||||
},
|
||||
"Trade Payable": {
|
||||
"account_type": "Payable"
|
||||
},
|
||||
},
|
||||
"account_type": "Payable"
|
||||
}
|
||||
},
|
||||
},
|
||||
"Accruals & Provisions": {
|
||||
"Accruals": {
|
||||
"Accrued Personnel Cost": {
|
||||
"Accrued - Commissions": {},
|
||||
"Accrued - Leave Salary": {},
|
||||
"Accrued - Leave Tickets": {},
|
||||
"Accrued - Salaries": {},
|
||||
"Accrued Other Personnel Cost": {},
|
||||
"Accrued Salaries Increment": {},
|
||||
"Accrued - Commissions": {},
|
||||
"Accrued - Leave Salary": {},
|
||||
"Accrued - Leave Tickets": {},
|
||||
"Accrued - Salaries": {},
|
||||
"Accrued Other Personnel Cost": {},
|
||||
"Accrued Salaries Increment": {},
|
||||
"Accrued-Staff Bonus": {}
|
||||
}
|
||||
},
|
||||
},
|
||||
"Accrued Expenses": {
|
||||
"Accrued Other Expenses": {
|
||||
"Accrued - Audit Fees": {},
|
||||
"Accrued - Office Rent": {},
|
||||
"Accrued - Sponsorship": {},
|
||||
"Accrued - Telephone": {},
|
||||
"Accrued - Utilities": {},
|
||||
"Accrued - Audit Fees": {},
|
||||
"Accrued - Office Rent": {},
|
||||
"Accrued - Sponsorship": {},
|
||||
"Accrued - Telephone": {},
|
||||
"Accrued - Utilities": {},
|
||||
"Accrued Others": {}
|
||||
}
|
||||
},
|
||||
},
|
||||
"Other Current Liabilities": {
|
||||
"Accrued Dubai Customs": {},
|
||||
"Deferred income": {},
|
||||
"Accrued Dubai Customs": {},
|
||||
"Deferred income": {},
|
||||
"Shipping & Handling": {}
|
||||
},
|
||||
},
|
||||
"Provisions": {
|
||||
"Tax Payables": {
|
||||
"Income Tax Payable": {},
|
||||
"Sales Tax Payable": {},
|
||||
"Income Tax Payable": {},
|
||||
"Sales Tax Payable": {},
|
||||
"Withholding Tax Payable": {}
|
||||
}
|
||||
},
|
||||
},
|
||||
"Short Term Loan": {}
|
||||
},
|
||||
},
|
||||
"Duties and Taxes": {
|
||||
"account_type": "Tax",
|
||||
"account_type": "Tax",
|
||||
"is_group": 1
|
||||
},
|
||||
},
|
||||
"Reservations & Credit Notes": {
|
||||
"Credit Notes": {
|
||||
"Credit Notes to Customers": {},
|
||||
"Credit Notes to Customers": {},
|
||||
"Reservations": {}
|
||||
}
|
||||
},
|
||||
},
|
||||
"Stock Liabilities": {
|
||||
"Stock Received But Not Billed": {
|
||||
"account_type": "Stock Received But Not Billed"
|
||||
}
|
||||
},
|
||||
},
|
||||
"Unearned Income": {}
|
||||
},
|
||||
},
|
||||
"Long Term Liabilities": {
|
||||
"Long Term Loans & Provisions": {}
|
||||
},
|
||||
},
|
||||
"root_type": "Liability"
|
||||
},
|
||||
},
|
||||
"Revenue": {
|
||||
"Direct Revenue": {
|
||||
"Other Direct Revenue": {
|
||||
"Other Revenue - Operating": {
|
||||
"Advertising Income": {},
|
||||
"Branding Income": {},
|
||||
"Early Setmt Margin from Suppliers": {},
|
||||
"Marketing Rebate from Suppliers": {},
|
||||
"Rebate from Suppliers": {},
|
||||
"Service Income": {},
|
||||
"Advertising Income": {},
|
||||
"Branding Income": {},
|
||||
"Early Setmt Margin from Suppliers": {},
|
||||
"Marketing Rebate from Suppliers": {},
|
||||
"Rebate from Suppliers": {},
|
||||
"Service Income": {},
|
||||
"Space Rental Income": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
"Indirect Revenue": {
|
||||
"Other Indirect Revenue": {
|
||||
"Capital Gain": {},
|
||||
"Excess In Till": {},
|
||||
"Gain On Difference Of Exchange": {},
|
||||
"Management Consultancy Fees": {},
|
||||
"Capital Gain": {},
|
||||
"Excess In Till": {},
|
||||
"Gain On Difference Of Exchange": {},
|
||||
"Management Consultancy Fees": {},
|
||||
"Other Income": {}
|
||||
},
|
||||
},
|
||||
"Other Revenue - Non Operating": {
|
||||
"Interest Revenue": {},
|
||||
"Interest from FD": {},
|
||||
"Products Listing Fees from Suppliers": {},
|
||||
"Interest Revenue": {},
|
||||
"Interest from FD": {},
|
||||
"Products Listing Fees from Suppliers": {},
|
||||
"Trade Opening Fees from suppliers": {}
|
||||
}
|
||||
},
|
||||
},
|
||||
"Sales": {
|
||||
"Sales from Other Regions": {
|
||||
"Sales from Other Region": {}
|
||||
},
|
||||
},
|
||||
"Sales of same region": {
|
||||
"Management Consultancy Fees 1": {},
|
||||
"Sales Account": {},
|
||||
"Management Consultancy Fees 1": {},
|
||||
"Sales Account": {},
|
||||
"Sales of I/C": {}
|
||||
}
|
||||
},
|
||||
},
|
||||
"root_type": "Income"
|
||||
},
|
||||
},
|
||||
"Share Holder Equity": {
|
||||
"Capital": {
|
||||
"Contributed Capital": {},
|
||||
"Share Capital": {},
|
||||
"Shareholders Current A/c": {},
|
||||
"Sub Ordinated Loan": {},
|
||||
"Contributed Capital": {},
|
||||
"Share Capital": {},
|
||||
"Shareholders Current A/c": {},
|
||||
"Sub Ordinated Loan": {},
|
||||
"Treasury Stocks": {}
|
||||
},
|
||||
},
|
||||
"Retained Earnings": {
|
||||
"Current Year Results": {},
|
||||
"Dividends Paid": {},
|
||||
"Current Year Results": {},
|
||||
"Dividends Paid": {},
|
||||
"Previous Years Results": {}
|
||||
},
|
||||
"account_type": "Equity",
|
||||
},
|
||||
"account_type": "Equity",
|
||||
"root_type": "Equity"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ from __future__ import unicode_literals
|
||||
import frappe, json
|
||||
from frappe.model.document import Document
|
||||
from frappe import _
|
||||
from frappe.desk.search import sanitize_searchfield
|
||||
|
||||
class BankGuarantee(Document):
|
||||
def validate(self):
|
||||
@@ -22,5 +23,8 @@ class BankGuarantee(Document):
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_vouchar_detials(column_list, doctype, docname):
|
||||
column_list = json.loads(column_list)
|
||||
for col in column_list:
|
||||
sanitize_searchfield(col)
|
||||
return frappe.db.sql(''' select {columns} from `tab{doctype}` where name=%s'''
|
||||
.format(columns=", ".join(json.loads(column_list)), doctype=doctype), docname, as_dict=1)[0]
|
||||
|
||||
@@ -92,10 +92,10 @@ frappe.ui.form.on("Journal Entry", {
|
||||
multi_currency: function(frm) {
|
||||
erpnext.journal_entry.toggle_fields_based_on_currency(frm);
|
||||
},
|
||||
|
||||
|
||||
posting_date: function(frm) {
|
||||
if(!frm.doc.multi_currency || !frm.doc.posting_date) return;
|
||||
|
||||
|
||||
$.each(frm.doc.accounts || [], function(i, row) {
|
||||
erpnext.journal_entry.set_exchange_rate(frm, row.doctype, row.name);
|
||||
})
|
||||
@@ -234,7 +234,7 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
|
||||
|
||||
out.filters.push([jvd.reference_type, "per_billed", "<", 100]);
|
||||
}
|
||||
|
||||
|
||||
if(jvd.party_type && jvd.party) {
|
||||
var party_field = "";
|
||||
if(jvd.reference_type.indexOf("Sales")===0) {
|
||||
@@ -382,7 +382,7 @@ cur_frm.cscript.voucher_type = function(doc, cdt, cdn) {
|
||||
});
|
||||
refresh_field("accounts");
|
||||
}
|
||||
|
||||
|
||||
if((!(doc.accounts || []).length) || ((doc.accounts || []).length==1 && !doc.accounts[0].account)) {
|
||||
if(in_list(["Bank Entry", "Cash Entry"], doc.voucher_type)) {
|
||||
return frappe.call({
|
||||
@@ -390,7 +390,7 @@ cur_frm.cscript.voucher_type = function(doc, cdt, cdn) {
|
||||
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_default_bank_cash_account",
|
||||
args: {
|
||||
"account_type": (doc.voucher_type=="Bank Entry" ?
|
||||
"Bank" : (doc.voucher_type=="Cash" ? "Cash" : null)),
|
||||
"Bank" : (doc.voucher_type=="Cash Entry" ? "Cash" : null)),
|
||||
"company": doc.company
|
||||
},
|
||||
callback: function(r) {
|
||||
@@ -442,7 +442,7 @@ frappe.ui.form.on("Journal Entry Account", {
|
||||
account: function(frm, dt, dn) {
|
||||
erpnext.journal_entry.set_account_balance(frm, dt, dn);
|
||||
},
|
||||
|
||||
|
||||
debit_in_account_currency: function(frm, cdt, cdn) {
|
||||
erpnext.journal_entry.set_exchange_rate(frm, cdt, cdn);
|
||||
},
|
||||
|
||||
@@ -294,7 +294,7 @@ frappe.ui.form.on('Payment Entry', {
|
||||
() => {
|
||||
frm.set_party_account_based_on_party = false;
|
||||
if (r.message.bank_account) {
|
||||
frm.set_value("bank_account", r.message.bank_account);
|
||||
frm.set_value("party_bank_account", r.message.bank_account);
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
@@ -1791,6 +1791,41 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Draft",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Status",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "\nDraft\nSubmitted\nCancelled",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
@@ -2205,7 +2240,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2019-03-27 17:39:54.163016",
|
||||
"modified": "2019-11-06 15:15:45.223497",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Payment Entry",
|
||||
|
||||
@@ -60,6 +60,7 @@ class PaymentEntry(AccountsController):
|
||||
self.validate_duplicate_entry()
|
||||
self.validate_allocated_amount()
|
||||
self.ensure_supplier_is_not_blocked()
|
||||
self.set_status()
|
||||
|
||||
def on_submit(self):
|
||||
self.setup_party_account_field()
|
||||
@@ -69,6 +70,7 @@ class PaymentEntry(AccountsController):
|
||||
self.update_outstanding_amounts()
|
||||
self.update_advance_paid()
|
||||
self.update_expense_claim()
|
||||
self.set_status()
|
||||
|
||||
|
||||
def on_cancel(self):
|
||||
@@ -78,6 +80,7 @@ class PaymentEntry(AccountsController):
|
||||
self.update_advance_paid()
|
||||
self.update_expense_claim()
|
||||
self.delink_advance_entry_references()
|
||||
self.set_status()
|
||||
|
||||
def update_outstanding_amounts(self):
|
||||
self.set_missing_ref_details(force=True)
|
||||
@@ -274,6 +277,14 @@ class PaymentEntry(AccountsController):
|
||||
frappe.throw(_("Against Journal Entry {0} does not have any unmatched {1} entry")
|
||||
.format(d.reference_name, dr_or_cr))
|
||||
|
||||
def set_status(self):
|
||||
if self.docstatus == 2:
|
||||
self.status = 'Cancelled'
|
||||
elif self.docstatus == 1:
|
||||
self.status = 'Submitted'
|
||||
else:
|
||||
self.status = 'Draft'
|
||||
|
||||
def set_amounts(self):
|
||||
self.set_amounts_in_company_currency()
|
||||
self.set_total_allocated_amount()
|
||||
|
||||
@@ -2454,7 +2454,7 @@
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "other_charges_calculation",
|
||||
"fieldtype": "Text",
|
||||
"fieldtype": "Long Text",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
@@ -4903,7 +4903,7 @@
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2019-04-22 12:45:49.728359",
|
||||
"modified": "2020-04-16 19:04:18.599264",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Invoice",
|
||||
|
||||
@@ -250,7 +250,7 @@ class PurchaseInvoice(BuyingController):
|
||||
def set_against_expense_account(self):
|
||||
against_accounts = []
|
||||
for item in self.get("items"):
|
||||
if item.expense_account not in against_accounts:
|
||||
if item.expense_account and (item.expense_account not in against_accounts):
|
||||
against_accounts.append(item.expense_account)
|
||||
|
||||
self.against_expense_account = ",".join(against_accounts)
|
||||
@@ -750,7 +750,11 @@ class PurchaseInvoice(BuyingController):
|
||||
)
|
||||
|
||||
def make_gle_for_rounding_adjustment(self, gl_entries):
|
||||
if self.rounding_adjustment:
|
||||
# if rounding adjustment in small and conversion rate is also small then
|
||||
# base_rounding_adjustment may become zero due to small precision
|
||||
# eg: rounding_adjustment = 0.01 and exchange rate = 0.05 and precision of base_rounding_adjustment is 2
|
||||
# then base_rounding_adjustment becomes zero and error is thrown in GL Entry
|
||||
if self.rounding_adjustment and self.base_rounding_adjustment:
|
||||
round_off_account, round_off_cost_center = \
|
||||
get_round_off_account_and_cost_center(self.company)
|
||||
|
||||
|
||||
@@ -2544,7 +2544,7 @@
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "other_charges_calculation",
|
||||
"fieldtype": "Text",
|
||||
"fieldtype": "Long Text",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
@@ -5816,7 +5816,7 @@
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2019-04-22 12:45:41.109345",
|
||||
"modified": "2020-04-16 19:05:00.498772",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice",
|
||||
|
||||
@@ -350,7 +350,7 @@ class SalesInvoice(SellingController):
|
||||
timesheet.calculate_percentage_billed()
|
||||
timesheet.flags.ignore_validate_update_after_submit = True
|
||||
timesheet.set_status()
|
||||
timesheet.save()
|
||||
timesheet.save(ignore_permissions=True)
|
||||
|
||||
def update_time_sheet_detail(self, timesheet, args, sales_invoice):
|
||||
for data in timesheet.time_logs:
|
||||
@@ -944,7 +944,7 @@ class SalesInvoice(SellingController):
|
||||
)
|
||||
|
||||
def make_gle_for_rounding_adjustment(self, gl_entries):
|
||||
if flt(self.rounding_adjustment, self.precision("rounding_adjustment")):
|
||||
if flt(self.rounding_adjustment, self.precision("rounding_adjustment")) and self.base_rounding_adjustment:
|
||||
round_off_account, round_off_cost_center = \
|
||||
get_round_off_account_and_cost_center(self.company)
|
||||
|
||||
@@ -992,10 +992,8 @@ class SalesInvoice(SellingController):
|
||||
continue
|
||||
|
||||
for serial_no in item.serial_no.split("\n"):
|
||||
if serial_no and frappe.db.exists('Serial No', serial_no):
|
||||
sno = frappe.get_doc('Serial No', serial_no)
|
||||
sno.sales_invoice = invoice
|
||||
sno.db_update()
|
||||
if serial_no and frappe.db.get_value('Serial No', serial_no, 'item_code') == item.item_code:
|
||||
frappe.db.set_value('Serial No', serial_no, 'sales_invoice', invoice)
|
||||
|
||||
def validate_serial_numbers(self):
|
||||
"""
|
||||
@@ -1041,12 +1039,18 @@ class SalesInvoice(SellingController):
|
||||
continue
|
||||
|
||||
for serial_no in item.serial_no.split("\n"):
|
||||
sales_invoice = frappe.db.get_value("Serial No", serial_no, "sales_invoice")
|
||||
if sales_invoice and self.name != sales_invoice:
|
||||
sales_invoice_company = frappe.db.get_value("Sales Invoice", sales_invoice, "company")
|
||||
serial_no_details = frappe.db.get_value("Serial No", serial_no,
|
||||
["sales_invoice", "item_code"], as_dict=1)
|
||||
|
||||
if not serial_no_details:
|
||||
continue
|
||||
|
||||
if serial_no_details.sales_invoice and serial_no_details.item_code == item.item_code \
|
||||
and self.name != serial_no_details.sales_invoice:
|
||||
sales_invoice_company = frappe.db.get_value("Sales Invoice", serial_no_details.sales_invoice, "company")
|
||||
if sales_invoice_company == self.company:
|
||||
frappe.throw(_("Serial Number: {0} is already referenced in Sales Invoice: {1}"
|
||||
.format(serial_no, sales_invoice)))
|
||||
.format(serial_no, serial_no_details.sales_invoice)))
|
||||
|
||||
def update_project(self):
|
||||
if self.project:
|
||||
|
||||
@@ -16,7 +16,7 @@ frappe.ui.form.on('Share Transfer', {
|
||||
};
|
||||
};
|
||||
});
|
||||
if (frm.doc.docstatus == 1) {
|
||||
if (frm.doc.docstatus == 1 && frm.doc.equity_or_liability_account && frm.doc.asset_account ) {
|
||||
frm.add_custom_button(__('Make Journal Entry'), function () {
|
||||
erpnext.share_transfer.make_jv(frm);
|
||||
});
|
||||
@@ -92,6 +92,7 @@ erpnext.share_transfer.make_jv = function (frm) {
|
||||
debit_applicant_type = "Shareholder";
|
||||
debit_applicant = frm.doc.from_shareholder;
|
||||
}
|
||||
|
||||
frappe.call({
|
||||
args: {
|
||||
"company": frm.doc.company,
|
||||
|
||||
@@ -292,11 +292,14 @@ def make_jv_entry( company, account, amount, payment_account,\
|
||||
"party_type": debit_applicant_type,
|
||||
"party": debit_applicant,
|
||||
})
|
||||
|
||||
account_amt_list.append({
|
||||
"account": payment_account,
|
||||
"credit_in_account_currency": amount,
|
||||
"party_type": credit_applicant_type,
|
||||
"party": credit_applicant,
|
||||
})
|
||||
|
||||
journal_entry.set("accounts", account_amt_list)
|
||||
|
||||
return journal_entry.as_dict()
|
||||
@@ -9,7 +9,7 @@
|
||||
</div>
|
||||
<div class="col-xs-{{ "3" if df.fieldtype=="Check" else "7" }} value">
|
||||
{% if doc.get(df.fieldname) != None -%}
|
||||
{{ frappe.utils.fmt_money((doc[df.fieldname])|int|abs, currency=doc.currency) }}
|
||||
{{ frappe.utils.fmt_money((doc[df.fieldname])|abs, currency=doc.currency) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
@@ -26,7 +26,7 @@
|
||||
<div class="col-xs-5 {%- if doc.align_labels_right %} text-right{%- endif -%}">
|
||||
<label>{{ charge.get_formatted("description") }}</label></div>
|
||||
<div class="col-xs-7 text-right">
|
||||
{{ frappe.utils.fmt_money((charge.tax_amount)|int|abs, currency=doc.currency) }}
|
||||
{{ frappe.utils.fmt_money((charge.tax_amount)|abs, currency=doc.currency) }}
|
||||
</div>
|
||||
</div>
|
||||
{%- endif -%}
|
||||
@@ -65,8 +65,10 @@
|
||||
{% for tdf in visible_columns %}
|
||||
{% if not d.flags.compact_item_print or tdf.fieldname in doc.get(df.fieldname)[0].flags.compact_item_fields %}
|
||||
<td class="{{ get_align_class(tdf) }}" {{ fieldmeta(df) }}>
|
||||
{% if tdf.fieldtype == 'Currency' %}
|
||||
<div class="value">{{ frappe.utils.fmt_money((d[tdf.fieldname])|int|abs, currency=doc.currency) }}</div></td>
|
||||
{% if tdf.fieldname == 'qty' %}
|
||||
<div class="value">{{ (d[tdf.fieldname])|abs }}</div></td>
|
||||
{% elif tdf.fieldtype == 'Currency' %}
|
||||
<div class="value">{{ frappe.utils.fmt_money((d[tdf.fieldname])|abs, currency=doc.currency) }}</div></td>
|
||||
{% else %}
|
||||
<div class="value">{{ print_value(tdf, d, doc, visible_columns) }}</div></td>
|
||||
{% endif %}
|
||||
@@ -117,7 +119,7 @@
|
||||
{{ render_currency(df, doc) }}
|
||||
{% elif df.fieldtype =='Table' %}
|
||||
{{ render_table(df, doc)}}
|
||||
{% elif doc[df.fieldname] %}
|
||||
{% elif doc[df.fieldname] and df.fieldname != 'total_qty' %}
|
||||
{{ render_field(df, doc) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
@@ -59,6 +59,7 @@ class ReceivablePayableReport(object):
|
||||
|
||||
def get_data(self):
|
||||
self.get_gl_entries()
|
||||
self.get_sales_invoices_or_customers_based_on_sales_person()
|
||||
self.voucher_balance = OrderedDict()
|
||||
self.init_voucher_balance() # invoiced, paid, credit_note, outstanding
|
||||
|
||||
@@ -102,12 +103,18 @@ class ReceivablePayableReport(object):
|
||||
|
||||
def get_invoices(self, gle):
|
||||
if gle.voucher_type in ('Sales Invoice', 'Purchase Invoice'):
|
||||
self.invoices.add(gle.voucher_no)
|
||||
if self.filters.get("sales_person"):
|
||||
if gle.voucher_no in self.sales_person_records.get("Sales Invoice", []) \
|
||||
or gle.party in self.sales_person_records.get("Customer", []):
|
||||
self.invoices.add(gle.voucher_no)
|
||||
else:
|
||||
self.invoices.add(gle.voucher_no)
|
||||
|
||||
def update_voucher_balance(self, gle):
|
||||
# get the row where this balance needs to be updated
|
||||
# if its a payment, it will return the linked invoice or will be considered as advance
|
||||
row = self.get_voucher_balance(gle)
|
||||
if not row: return
|
||||
# gle_balance will be the total "debit - credit" for receivable type reports and
|
||||
# and vice-versa for payable type reports
|
||||
gle_balance = self.get_gle_balance(gle)
|
||||
@@ -128,8 +135,13 @@ class ReceivablePayableReport(object):
|
||||
row.paid -= gle_balance
|
||||
|
||||
def get_voucher_balance(self, gle):
|
||||
voucher_balance = None
|
||||
if self.filters.get("sales_person"):
|
||||
against_voucher = gle.against_voucher or gle.voucher_no
|
||||
if not (gle.party in self.sales_person_records.get("Customer", []) or \
|
||||
against_voucher in self.sales_person_records.get("Sales Invoice", [])):
|
||||
return
|
||||
|
||||
voucher_balance = None
|
||||
if gle.against_voucher:
|
||||
# find invoice
|
||||
against_voucher = gle.against_voucher
|
||||
@@ -187,7 +199,11 @@ class ReceivablePayableReport(object):
|
||||
self.data.append(row)
|
||||
|
||||
def set_invoice_details(self, row):
|
||||
row.update(self.invoice_details.get(row.voucher_no, {}))
|
||||
invoice_details = self.invoice_details.get(row.voucher_no, {})
|
||||
if row.due_date:
|
||||
invoice_details.pop("due_date", None)
|
||||
row.update(invoice_details)
|
||||
|
||||
if row.voucher_type == 'Sales Invoice':
|
||||
if self.filters.show_delivery_notes:
|
||||
self.set_delivery_notes(row)
|
||||
@@ -507,6 +523,22 @@ class ReceivablePayableReport(object):
|
||||
order by posting_date, party"""
|
||||
.format(select_fields, conditions), values, as_dict=True)
|
||||
|
||||
def get_sales_invoices_or_customers_based_on_sales_person(self):
|
||||
if self.filters.get("sales_person"):
|
||||
lft, rgt = frappe.db.get_value("Sales Person",
|
||||
self.filters.get("sales_person"), ["lft", "rgt"])
|
||||
|
||||
records = frappe.db.sql("""
|
||||
select distinct parent, parenttype
|
||||
from `tabSales Team` steam
|
||||
where parenttype in ('Customer', 'Sales Invoice')
|
||||
and exists(select name from `tabSales Person` where lft >= %s and rgt <= %s and name = steam.sales_person)
|
||||
""", (lft, rgt), as_dict=1)
|
||||
|
||||
self.sales_person_records = frappe._dict()
|
||||
for d in records:
|
||||
self.sales_person_records.setdefault(d.parenttype, set()).add(d.parent)
|
||||
|
||||
def prepare_conditions(self):
|
||||
conditions = [""]
|
||||
values = [self.party_type, self.filters.report_date]
|
||||
@@ -557,16 +589,6 @@ class ReceivablePayableReport(object):
|
||||
conditions.append("party in (select name from tabCustomer where default_sales_partner=%s)")
|
||||
values.append(self.filters.get("sales_partner"))
|
||||
|
||||
if self.filters.get("sales_person"):
|
||||
lft, rgt = frappe.db.get_value("Sales Person",
|
||||
self.filters.get("sales_person"), ["lft", "rgt"])
|
||||
|
||||
conditions.append("""exists(select name from `tabSales Team` steam where
|
||||
steam.sales_person in (select name from `tabSales Person` where lft >= {0} and rgt <= {1})
|
||||
and ((steam.parent = voucher_no and steam.parenttype = voucher_type)
|
||||
or (steam.parent = against_voucher and steam.parenttype = against_voucher_type)
|
||||
or (steam.parent = party and steam.parenttype = 'Customer')))""".format(lft, rgt))
|
||||
|
||||
def add_supplier_filters(self, conditions, values):
|
||||
if self.filters.get("supplier_group"):
|
||||
conditions.append("""party in (select name from tabSupplier
|
||||
|
||||
@@ -36,6 +36,9 @@ class AccountsReceivableSummary(ReceivablePayableReport):
|
||||
self.filters.report_date) or {}
|
||||
|
||||
for party, party_dict in iteritems(self.party_total):
|
||||
if party_dict.outstanding == 0:
|
||||
continue
|
||||
|
||||
row = frappe._dict()
|
||||
|
||||
row.party = party
|
||||
@@ -132,4 +135,4 @@ class AccountsReceivableSummary(ReceivablePayableReport):
|
||||
"{range2}-{range3}".format(range2=cint(self.filters["range2"])+ 1, range3=self.filters["range3"]),
|
||||
"{range3}-{range4}".format(range3=cint(self.filters["range3"])+ 1, range4=self.filters["range4"]),
|
||||
"{range4}-{above}".format(range4=cint(self.filters["range4"])+ 1, above=_("Above"))]):
|
||||
self.add_column(label=label, fieldname='range' + str(i+1))
|
||||
self.add_column(label=label, fieldname='range' + str(i+1))
|
||||
|
||||
@@ -4,126 +4,141 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import formatdate, getdate, flt, add_days
|
||||
from frappe.utils import formatdate, flt, add_days
|
||||
|
||||
|
||||
def execute(filters=None):
|
||||
filters.day_before_from_date = add_days(filters.from_date, -1)
|
||||
columns, data = get_columns(filters), get_data(filters)
|
||||
return columns, data
|
||||
|
||||
|
||||
|
||||
def get_data(filters):
|
||||
data = []
|
||||
|
||||
|
||||
asset_categories = get_asset_categories(filters)
|
||||
assets = get_assets(filters)
|
||||
asset_costs = get_asset_costs(assets, filters)
|
||||
asset_depreciations = get_accumulated_depreciations(assets, filters)
|
||||
|
||||
|
||||
for asset_category in asset_categories:
|
||||
row = frappe._dict()
|
||||
row.asset_category = asset_category
|
||||
row.update(asset_costs.get(asset_category))
|
||||
# row.asset_category = asset_category
|
||||
row.update(asset_category)
|
||||
|
||||
row.cost_as_on_to_date = (flt(row.cost_as_on_from_date) + flt(row.cost_of_new_purchase) -
|
||||
flt(row.cost_of_sold_asset) - flt(row.cost_of_scrapped_asset))
|
||||
|
||||
row.update(next(asset for asset in assets if asset["asset_category"] == asset_category.get("asset_category", "")))
|
||||
row.accumulated_depreciation_as_on_to_date = (flt(row.accumulated_depreciation_as_on_from_date) +
|
||||
flt(row.depreciation_amount_during_the_period) - flt(row.depreciation_eliminated))
|
||||
|
||||
row.net_asset_value_as_on_from_date = (flt(row.cost_as_on_from_date) -
|
||||
flt(row.accumulated_depreciation_as_on_from_date))
|
||||
|
||||
row.net_asset_value_as_on_to_date = (flt(row.cost_as_on_to_date) -
|
||||
flt(row.accumulated_depreciation_as_on_to_date))
|
||||
|
||||
row.cost_as_on_to_date = (flt(row.cost_as_on_from_date) + flt(row.cost_of_new_purchase)
|
||||
- flt(row.cost_of_sold_asset) - flt(row.cost_of_scrapped_asset))
|
||||
|
||||
row.update(asset_depreciations.get(asset_category))
|
||||
row.accumulated_depreciation_as_on_to_date = (flt(row.accumulated_depreciation_as_on_from_date) +
|
||||
flt(row.depreciation_amount_during_the_period) - flt(row.depreciation_eliminated))
|
||||
|
||||
row.net_asset_value_as_on_from_date = (flt(row.cost_as_on_from_date) -
|
||||
flt(row.accumulated_depreciation_as_on_from_date))
|
||||
|
||||
row.net_asset_value_as_on_to_date = (flt(row.cost_as_on_to_date) -
|
||||
flt(row.accumulated_depreciation_as_on_to_date))
|
||||
|
||||
data.append(row)
|
||||
|
||||
|
||||
return data
|
||||
|
||||
|
||||
|
||||
def get_asset_categories(filters):
|
||||
return frappe.db.sql_list("""
|
||||
select distinct asset_category from `tabAsset`
|
||||
where docstatus=1 and company=%s and purchase_date <= %s
|
||||
""", (filters.company, filters.to_date))
|
||||
|
||||
return frappe.db.sql("""
|
||||
SELECT asset_category,
|
||||
ifnull(sum(case when purchase_date < %(from_date)s then
|
||||
case when ifnull(disposal_date, 0) = 0 or disposal_date >= %(from_date)s then
|
||||
gross_purchase_amount
|
||||
else
|
||||
0
|
||||
end
|
||||
else
|
||||
0
|
||||
end), 0) as cost_as_on_from_date,
|
||||
ifnull(sum(case when purchase_date >= %(from_date)s then
|
||||
gross_purchase_amount
|
||||
else
|
||||
0
|
||||
end), 0) as cost_of_new_purchase,
|
||||
ifnull(sum(case when ifnull(disposal_date, 0) != 0
|
||||
and disposal_date >= %(from_date)s
|
||||
and disposal_date <= %(to_date)s then
|
||||
case when status = "Sold" then
|
||||
gross_purchase_amount
|
||||
else
|
||||
0
|
||||
end
|
||||
else
|
||||
0
|
||||
end), 0) as cost_of_sold_asset,
|
||||
ifnull(sum(case when ifnull(disposal_date, 0) != 0
|
||||
and disposal_date >= %(from_date)s
|
||||
and disposal_date <= %(to_date)s then
|
||||
case when status = "Scrapped" then
|
||||
gross_purchase_amount
|
||||
else
|
||||
0
|
||||
end
|
||||
else
|
||||
0
|
||||
end), 0) as cost_of_scrapped_asset
|
||||
from `tabAsset`
|
||||
where docstatus=1 and company=%(company)s and purchase_date <= %(to_date)s
|
||||
group by asset_category
|
||||
""", {"to_date": filters.to_date, "from_date": filters.from_date, "company": filters.company}, as_dict=1)
|
||||
|
||||
|
||||
def get_assets(filters):
|
||||
return frappe.db.sql("""
|
||||
select name, asset_category, purchase_date, gross_purchase_amount, disposal_date, status
|
||||
from `tabAsset`
|
||||
where docstatus=1 and company=%s and purchase_date <= %s""",
|
||||
(filters.company, filters.to_date), as_dict=1)
|
||||
|
||||
def get_asset_costs(assets, filters):
|
||||
asset_costs = frappe._dict()
|
||||
for d in assets:
|
||||
asset_costs.setdefault(d.asset_category, frappe._dict({
|
||||
"cost_as_on_from_date": 0,
|
||||
"cost_of_new_purchase": 0,
|
||||
"cost_of_sold_asset": 0,
|
||||
"cost_of_scrapped_asset": 0
|
||||
}))
|
||||
|
||||
costs = asset_costs[d.asset_category]
|
||||
|
||||
if getdate(d.purchase_date) < getdate(filters.from_date):
|
||||
if not d.disposal_date or getdate(d.disposal_date) >= getdate(filters.from_date):
|
||||
costs.cost_as_on_from_date += flt(d.gross_purchase_amount)
|
||||
else:
|
||||
costs.cost_of_new_purchase += flt(d.gross_purchase_amount)
|
||||
|
||||
if d.disposal_date and getdate(d.disposal_date) >= getdate(filters.from_date) \
|
||||
and getdate(d.disposal_date) <= getdate(filters.to_date):
|
||||
if d.status == "Sold":
|
||||
costs.cost_of_sold_asset += flt(d.gross_purchase_amount)
|
||||
elif d.status == "Scrapped":
|
||||
costs.cost_of_scrapped_asset += flt(d.gross_purchase_amount)
|
||||
|
||||
return asset_costs
|
||||
|
||||
def get_accumulated_depreciations(assets, filters):
|
||||
asset_depreciations = frappe._dict()
|
||||
for d in assets:
|
||||
asset = frappe.get_doc("Asset", d.name)
|
||||
|
||||
if d.asset_category in asset_depreciations:
|
||||
asset_depreciations[d.asset_category]['accumulated_depreciation_as_on_from_date'] += asset.opening_accumulated_depreciation
|
||||
else:
|
||||
asset_depreciations.setdefault(d.asset_category, frappe._dict({
|
||||
"accumulated_depreciation_as_on_from_date": asset.opening_accumulated_depreciation,
|
||||
"depreciation_amount_during_the_period": 0,
|
||||
"depreciation_eliminated_during_the_period": 0
|
||||
}))
|
||||
SELECT results.asset_category,
|
||||
sum(results.accumulated_depreciation_as_on_from_date) as accumulated_depreciation_as_on_from_date,
|
||||
sum(results.depreciation_eliminated_during_the_period) as depreciation_eliminated_during_the_period,
|
||||
sum(results.depreciation_amount_during_the_period) as depreciation_amount_during_the_period
|
||||
from (SELECT a.asset_category,
|
||||
ifnull(sum(a.opening_accumulated_depreciation +
|
||||
case when ds.schedule_date < %(from_date)s and
|
||||
(ifnull(a.disposal_date, 0) = 0 or a.disposal_date >= %(from_date)s) then
|
||||
ds.depreciation_amount
|
||||
else
|
||||
0
|
||||
end), 0) as accumulated_depreciation_as_on_from_date,
|
||||
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and a.disposal_date >= %(from_date)s
|
||||
and a.disposal_date <= %(to_date)s and ds.schedule_date <= a.disposal_date then
|
||||
ds.depreciation_amount
|
||||
else
|
||||
0
|
||||
end), 0) as depreciation_eliminated_during_the_period,
|
||||
|
||||
depr = asset_depreciations[d.asset_category]
|
||||
ifnull(sum(case when ds.schedule_date >= %(from_date)s and ds.schedule_date <= %(to_date)s
|
||||
and (ifnull(a.disposal_date, 0) = 0 or ds.schedule_date <= a.disposal_date) then
|
||||
ds.depreciation_amount
|
||||
else
|
||||
0
|
||||
end), 0) as depreciation_amount_during_the_period
|
||||
from `tabAsset` a, `tabDepreciation Schedule` ds
|
||||
where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s and a.name = ds.parent
|
||||
group by a.asset_category
|
||||
union
|
||||
SELECT a.asset_category,
|
||||
ifnull(sum(case when ifnull(a.disposal_date, 0) != 0
|
||||
and (a.disposal_date < %(from_date)s or a.disposal_date > %(to_date)s) then
|
||||
0
|
||||
else
|
||||
a.opening_accumulated_depreciation
|
||||
end), 0) as accumulated_depreciation_as_on_from_date,
|
||||
ifnull(sum(case when a.disposal_date >= %(from_date)s and a.disposal_date <= %(to_date)s then
|
||||
a.opening_accumulated_depreciation
|
||||
else
|
||||
0
|
||||
end), 0) as depreciation_eliminated_during_the_period,
|
||||
0 as depreciation_amount_during_the_period
|
||||
from `tabAsset` a
|
||||
where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s
|
||||
and not exists(select * from `tabDepreciation Schedule` ds where a.name = ds.parent)
|
||||
group by a.asset_category) as results
|
||||
group by results.asset_category
|
||||
""", {"to_date": filters.to_date, "from_date": filters.from_date, "company": filters.company}, as_dict=1)
|
||||
|
||||
if not asset.schedules: # if no schedule,
|
||||
if asset.disposal_date:
|
||||
# and disposal is NOT within the period, then opening accumulated depreciation not included
|
||||
if getdate(asset.disposal_date) < getdate(filters.from_date) or getdate(asset.disposal_date) > getdate(filters.to_date):
|
||||
asset_depreciations[d.asset_category]['accumulated_depreciation_as_on_from_date'] = 0
|
||||
|
||||
# if no schedule, and disposal is within period, accumulated dep is the amount eliminated
|
||||
if getdate(asset.disposal_date) >= getdate(filters.from_date) and getdate(asset.disposal_date) <= getdate(filters.to_date):
|
||||
depr.depreciation_eliminated_during_the_period += asset.opening_accumulated_depreciation
|
||||
|
||||
for schedule in asset.get("schedules"):
|
||||
if getdate(schedule.schedule_date) < getdate(filters.from_date):
|
||||
if not asset.disposal_date or getdate(asset.disposal_date) >= getdate(filters.from_date):
|
||||
depr.accumulated_depreciation_as_on_from_date += flt(schedule.depreciation_amount)
|
||||
elif getdate(schedule.schedule_date) <= getdate(filters.to_date):
|
||||
if not asset.disposal_date:
|
||||
depr.depreciation_amount_during_the_period += flt(schedule.depreciation_amount)
|
||||
else:
|
||||
if getdate(schedule.schedule_date) <= getdate(asset.disposal_date):
|
||||
depr.depreciation_amount_during_the_period += flt(schedule.depreciation_amount)
|
||||
|
||||
if asset.disposal_date and getdate(asset.disposal_date) >= getdate(filters.from_date) and getdate(asset.disposal_date) <= getdate(filters.to_date):
|
||||
if getdate(schedule.schedule_date) <= getdate(asset.disposal_date):
|
||||
depr.depreciation_eliminated_during_the_period += flt(schedule.depreciation_amount)
|
||||
|
||||
return asset_depreciations
|
||||
|
||||
def get_columns(filters):
|
||||
return [
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// License: GNU General Public License v3. See license.txt
|
||||
|
||||
frappe.require("assets/erpnext/js/financial_statements.js", function() {
|
||||
frappe.query_reports["Balance Sheet"] = erpnext.financial_statements;
|
||||
frappe.query_reports["Balance Sheet"] = $.extend({}, erpnext.financial_statements);
|
||||
|
||||
frappe.query_reports["Balance Sheet"]["filters"].push({
|
||||
"fieldname": "accumulated_values",
|
||||
|
||||
@@ -70,6 +70,7 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No
|
||||
if tax_acc not in income_accounts:
|
||||
tax_amount_precision = get_field_precision(frappe.get_meta("Sales Taxes and Charges").get_field("tax_amount"), currency=company_currency) or 2
|
||||
tax_amount = flt(invoice_tax_map.get(inv.name, {}).get(tax_acc), tax_amount_precision)
|
||||
total_tax += tax_amount
|
||||
row.append(tax_amount)
|
||||
|
||||
# total tax, grand total, outstanding amount & rounded total
|
||||
|
||||
@@ -75,8 +75,7 @@ def get_data(filters):
|
||||
accumulate_values_into_parents(accounts, accounts_by_name)
|
||||
|
||||
data = prepare_data(accounts, filters, total_row, parent_children_map, company_currency)
|
||||
data = filter_out_zero_value_rows(data, parent_children_map,
|
||||
show_zero_values=filters.get("show_zero_values"))
|
||||
data = filter_out_zero_value_rows(data, parent_children_map, show_zero_values=filters.get("show_zero_values"))
|
||||
|
||||
return data
|
||||
|
||||
@@ -175,33 +174,11 @@ def calculate_values(accounts, gl_entries_by_account, opening_balances, filters,
|
||||
|
||||
d["closing_debit"] = d["opening_debit"] + d["debit"]
|
||||
d["closing_credit"] = d["opening_credit"] + d["credit"]
|
||||
total_row["debit"] += d["debit"]
|
||||
total_row["credit"] += d["credit"]
|
||||
|
||||
if d["root_type"] == "Asset" or d["root_type"] == "Equity" or d["root_type"] == "Expense":
|
||||
d["opening_debit"] -= d["opening_credit"]
|
||||
d["closing_debit"] -= d["closing_credit"]
|
||||
prepare_opening_closing(d)
|
||||
|
||||
# For opening
|
||||
check_opening_closing_has_negative_value(d, "opening_debit", "opening_credit")
|
||||
|
||||
# For closing
|
||||
check_opening_closing_has_negative_value(d, "closing_debit", "closing_credit")
|
||||
|
||||
if d["root_type"] == "Liability" or d["root_type"] == "Income":
|
||||
d["opening_credit"] -= d["opening_debit"]
|
||||
d["closing_credit"] -= d["closing_debit"]
|
||||
|
||||
# For opening
|
||||
check_opening_closing_has_negative_value(d, "opening_credit", "opening_debit")
|
||||
|
||||
# For closing
|
||||
check_opening_closing_has_negative_value(d, "closing_credit", "closing_debit")
|
||||
|
||||
total_row["opening_debit"] += d["opening_debit"]
|
||||
total_row["closing_debit"] += d["closing_debit"]
|
||||
total_row["opening_credit"] += d["opening_credit"]
|
||||
total_row["closing_credit"] += d["closing_credit"]
|
||||
for field in value_fields:
|
||||
total_row[field] += d[field]
|
||||
|
||||
return total_row
|
||||
|
||||
@@ -215,6 +192,10 @@ def prepare_data(accounts, filters, total_row, parent_children_map, company_curr
|
||||
data = []
|
||||
|
||||
for d in accounts:
|
||||
# Prepare opening closing for group account
|
||||
if parent_children_map.get(d.account):
|
||||
prepare_opening_closing(d)
|
||||
|
||||
has_value = False
|
||||
row = {
|
||||
"account": d.name,
|
||||
@@ -301,11 +282,16 @@ def get_columns():
|
||||
}
|
||||
]
|
||||
|
||||
def check_opening_closing_has_negative_value(d, dr_or_cr, switch_to_column):
|
||||
# If opening debit has negetive value then move it to opening credit and vice versa.
|
||||
def prepare_opening_closing(row):
|
||||
dr_or_cr = "debit" if row["root_type"] in ["Asset", "Equity", "Expense"] else "credit"
|
||||
reverse_dr_or_cr = "credit" if dr_or_cr == "debit" else "debit"
|
||||
|
||||
if d[dr_or_cr] < 0:
|
||||
d[switch_to_column] = abs(d[dr_or_cr])
|
||||
d[dr_or_cr] = 0.0
|
||||
else:
|
||||
d[switch_to_column] = 0.0
|
||||
for col_type in ["opening", "closing"]:
|
||||
valid_col = col_type + "_" + dr_or_cr
|
||||
reverse_col = col_type + "_" + reverse_dr_or_cr
|
||||
row[valid_col] -= row[reverse_col]
|
||||
if row[valid_col] < 0:
|
||||
row[reverse_col] = abs(row[valid_col])
|
||||
row[valid_col] = 0.0
|
||||
else:
|
||||
row[reverse_col] = 0.0
|
||||
@@ -18,14 +18,17 @@ def execute(filters=None):
|
||||
return columns, data
|
||||
|
||||
def get_data(filters, show_party_name):
|
||||
party_name_field = "{0}_name".format(frappe.scrub(filters.get('party_type')))
|
||||
if filters.get('party_type') in ('Customer', 'Supplier', 'Employee', 'Member'):
|
||||
party_name_field = "{0}_name".format(frappe.scrub(filters.get('party_type')))
|
||||
if filters.get('party_type') == 'Student':
|
||||
party_name_field = 'first_name'
|
||||
elif filters.get('party_type') == 'Shareholder':
|
||||
party_name_field = 'title'
|
||||
else:
|
||||
party_name_field = 'name'
|
||||
|
||||
party_filters = {"name": filters.get("party")} if filters.get("party") else {}
|
||||
parties = frappe.get_all(filters.get("party_type"), fields = ["name", party_name_field],
|
||||
parties = frappe.get_all(filters.get("party_type"), fields = ["name", party_name_field],
|
||||
filters = party_filters, order_by="name")
|
||||
company_currency = frappe.get_cached_value('Company', filters.company, "default_currency")
|
||||
opening_balances = get_opening_balances(filters)
|
||||
@@ -70,7 +73,7 @@ def get_data(filters, show_party_name):
|
||||
# totals
|
||||
for col in total_row:
|
||||
total_row[col] += row.get(col)
|
||||
|
||||
|
||||
row.update({
|
||||
"currency": company_currency
|
||||
})
|
||||
@@ -78,7 +81,7 @@ def get_data(filters, show_party_name):
|
||||
has_value = False
|
||||
if (opening_debit or opening_credit or debit or credit or closing_debit or closing_credit):
|
||||
has_value =True
|
||||
|
||||
|
||||
if cint(filters.show_zero_values) or has_value:
|
||||
data.append(row)
|
||||
|
||||
@@ -94,9 +97,9 @@ def get_data(filters, show_party_name):
|
||||
|
||||
def get_opening_balances(filters):
|
||||
gle = frappe.db.sql("""
|
||||
select party, sum(debit) as opening_debit, sum(credit) as opening_credit
|
||||
select party, sum(debit) as opening_debit, sum(credit) as opening_credit
|
||||
from `tabGL Entry`
|
||||
where company=%(company)s
|
||||
where company=%(company)s
|
||||
and ifnull(party_type, '') = %(party_type)s and ifnull(party, '') != ''
|
||||
and (posting_date < %(from_date)s or ifnull(is_opening, 'No') = 'Yes')
|
||||
group by party""", {
|
||||
@@ -114,11 +117,11 @@ def get_opening_balances(filters):
|
||||
|
||||
def get_balances_within_period(filters):
|
||||
gle = frappe.db.sql("""
|
||||
select party, sum(debit) as debit, sum(credit) as credit
|
||||
select party, sum(debit) as debit, sum(credit) as credit
|
||||
from `tabGL Entry`
|
||||
where company=%(company)s
|
||||
where company=%(company)s
|
||||
and ifnull(party_type, '') = %(party_type)s and ifnull(party, '') != ''
|
||||
and posting_date >= %(from_date)s and posting_date <= %(to_date)s
|
||||
and posting_date >= %(from_date)s and posting_date <= %(to_date)s
|
||||
and ifnull(is_opening, 'No') = 'No'
|
||||
group by party""", {
|
||||
"company": filters.company,
|
||||
|
||||
@@ -2176,7 +2176,7 @@
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "other_charges_calculation",
|
||||
"fieldtype": "Text",
|
||||
"fieldtype": "Long Text",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
@@ -3948,7 +3948,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2019-06-24 20:55:03.466766",
|
||||
"modified": "2020-04-16 18:54:54.840653",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Purchase Order",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1395,7 +1395,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "other_charges_calculation",
|
||||
"fieldtype": "Text",
|
||||
"fieldtype": "Long Text",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
@@ -2845,7 +2845,7 @@
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2019-01-07 16:52:01.505553",
|
||||
"modified": "2020-04-16 19:05:41.924303",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Supplier Quotation",
|
||||
|
||||
@@ -138,7 +138,7 @@ def refresh_scorecards():
|
||||
# Check to see if any new scorecard periods are created
|
||||
if make_all_scorecards(sc.name) > 0:
|
||||
# Save the scorecard to update the score and standings
|
||||
sc.save()
|
||||
frappe.get_doc('Supplier Scorecard', sc.name).save()
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
|
||||
@@ -375,9 +375,10 @@ class AccountsController(TransactionBase):
|
||||
return gl_dict
|
||||
|
||||
def validate_qty_is_not_zero(self):
|
||||
for item in self.items:
|
||||
if not item.qty:
|
||||
frappe.throw(_("Item quantity can not be zero"))
|
||||
if self.doctype != "Purchase Receipt":
|
||||
for item in self.items:
|
||||
if not item.qty:
|
||||
frappe.throw(_("Item quantity can not be zero"))
|
||||
|
||||
def validate_account_currency(self, account, account_currency=None):
|
||||
valid_currency = [self.company_currency]
|
||||
@@ -1097,6 +1098,8 @@ def get_supplier_block_status(party_name):
|
||||
@frappe.whitelist()
|
||||
def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name):
|
||||
data = json.loads(trans_items)
|
||||
sales_doctypes = ['Sales Order', 'Sales Invoice', 'Delivery Note', 'Quotation']
|
||||
|
||||
for d in data:
|
||||
child_item = frappe.get_doc(parent_doctype + ' Item', d.get("docname"))
|
||||
|
||||
@@ -1114,8 +1117,26 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name):
|
||||
else:
|
||||
child_item.rate = flt(d.get("rate"))
|
||||
if flt(child_item.price_list_rate):
|
||||
child_item.discount_percentage = flt((1 - flt(child_item.rate) / flt(child_item.price_list_rate)) * 100.0, \
|
||||
child_item.precision("discount_percentage"))
|
||||
if flt(child_item.rate) > flt(child_item.price_list_rate):
|
||||
# if rate is greater than price_list_rate, set margin
|
||||
# or set discount
|
||||
child_item.discount_percentage = 0
|
||||
|
||||
if parent_doctype in sales_doctypes:
|
||||
child_item.margin_type = "Amount"
|
||||
child_item.margin_rate_or_amount = flt(child_item.rate - child_item.price_list_rate,
|
||||
child_item.precision("margin_rate_or_amount"))
|
||||
child_item.rate_with_margin = child_item.rate
|
||||
else:
|
||||
child_item.discount_percentage = flt((1 - flt(child_item.rate) / flt(child_item.price_list_rate)) * 100.0,
|
||||
child_item.precision("discount_percentage"))
|
||||
child_item.discount_amount = flt(
|
||||
child_item.price_list_rate) - flt(child_item.rate)
|
||||
|
||||
if parent_doctype in sales_doctypes:
|
||||
child_item.margin_type = ""
|
||||
child_item.margin_rate_or_amount = 0
|
||||
child_item.rate_with_margin = 0
|
||||
|
||||
child_item.flags.ignore_validate_update_after_submit = True
|
||||
child_item.save()
|
||||
|
||||
@@ -152,6 +152,24 @@ def tax_account_query(doctype, txt, searchfield, start, page_len, filters):
|
||||
def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=False):
|
||||
conditions = []
|
||||
|
||||
#Get searchfields from meta and use in Item Link field query
|
||||
meta = frappe.get_meta("Item", cached=True)
|
||||
searchfields = meta.get_search_fields()
|
||||
|
||||
if "description" in searchfields:
|
||||
searchfields.remove("description")
|
||||
|
||||
columns = ''
|
||||
extra_searchfields = [field for field in searchfields
|
||||
if field not in ["name", "item_group", "description"]]
|
||||
|
||||
if extra_searchfields:
|
||||
columns = ", " + ", ".join(extra_searchfields)
|
||||
|
||||
searchfields = searchfields + [field for field in[searchfield or "name", "item_code", "item_group", "item_name"]
|
||||
if not field in searchfields]
|
||||
searchfields = " or ".join([field + " like %(txt)s" for field in searchfields])
|
||||
|
||||
description_cond = ''
|
||||
if frappe.db.count('Item', cache=True) < 50000:
|
||||
# scan description only if items are less than 50000
|
||||
@@ -162,17 +180,14 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals
|
||||
concat(substr(tabItem.item_name, 1, 40), "..."), item_name) as item_name,
|
||||
tabItem.item_group,
|
||||
if(length(tabItem.description) > 40, \
|
||||
concat(substr(tabItem.description, 1, 40), "..."), description) as decription
|
||||
concat(substr(tabItem.description, 1, 40), "..."), description) as description
|
||||
{columns}
|
||||
from tabItem
|
||||
where tabItem.docstatus < 2
|
||||
and tabItem.has_variants=0
|
||||
and tabItem.disabled=0
|
||||
and (tabItem.end_of_life > %(today)s or ifnull(tabItem.end_of_life, '0000-00-00')='0000-00-00')
|
||||
and (tabItem.`{key}` LIKE %(txt)s
|
||||
or tabItem.item_code LIKE %(txt)s
|
||||
or tabItem.item_group LIKE %(txt)s
|
||||
or tabItem.item_name LIKE %(txt)s
|
||||
or tabItem.item_code IN (select parent from `tabItem Barcode` where barcode LIKE %(txt)s)
|
||||
and ({scond} or tabItem.item_code IN (select parent from `tabItem Barcode` where barcode LIKE %(txt)s)
|
||||
{description_cond})
|
||||
{fcond} {mcond}
|
||||
order by
|
||||
@@ -182,6 +197,8 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals
|
||||
name, item_name
|
||||
limit %(start)s, %(page_len)s """.format(
|
||||
key=searchfield,
|
||||
columns=columns,
|
||||
scond=searchfields,
|
||||
fcond=get_filters_cond(doctype, filters, conditions).replace('%', '%%'),
|
||||
mcond=get_match_cond(doctype).replace('%', '%%'),
|
||||
description_cond = description_cond),
|
||||
@@ -280,22 +297,32 @@ def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
|
||||
"page_len": page_len
|
||||
}
|
||||
|
||||
having_clause = "having sum(sle.actual_qty) > 0"
|
||||
if filters.get("is_return"):
|
||||
having_clause = ""
|
||||
|
||||
if args.get('warehouse'):
|
||||
batch_nos = frappe.db.sql("""select sle.batch_no, round(sum(sle.actual_qty),2), sle.stock_uom, concat('MFG-',batch.manufacturing_date), concat('EXP-',batch.expiry_date)
|
||||
from `tabStock Ledger Entry` sle
|
||||
INNER JOIN `tabBatch` batch on sle.batch_no = batch.name
|
||||
where
|
||||
batch.disabled = 0
|
||||
and sle.item_code = %(item_code)s
|
||||
and sle.warehouse = %(warehouse)s
|
||||
and (sle.batch_no like %(txt)s
|
||||
or batch.manufacturing_date like %(txt)s)
|
||||
and batch.docstatus < 2
|
||||
{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(cond, match_conditions=get_match_cond(doctype)), args)
|
||||
batch_nos = frappe.db.sql("""select sle.batch_no, round(sum(sle.actual_qty),2), sle.stock_uom,
|
||||
concat('MFG-',batch.manufacturing_date), concat('EXP-',batch.expiry_date)
|
||||
from `tabStock Ledger Entry` sle
|
||||
INNER JOIN `tabBatch` batch on sle.batch_no = batch.name
|
||||
where
|
||||
batch.disabled = 0
|
||||
and sle.item_code = %(item_code)s
|
||||
and sle.warehouse = %(warehouse)s
|
||||
and (sle.batch_no like %(txt)s
|
||||
or batch.expiry_date like %(txt)s
|
||||
or batch.manufacturing_date like %(txt)s)
|
||||
and batch.docstatus < 2
|
||||
{cond}
|
||||
{match_conditions}
|
||||
group by batch_no {having_clause}
|
||||
order by batch.expiry_date, sle.batch_no desc
|
||||
limit %(start)s, %(page_len)s""".format(
|
||||
cond=cond,
|
||||
match_conditions=get_match_cond(doctype),
|
||||
having_clause = having_clause
|
||||
), args)
|
||||
|
||||
return batch_nos
|
||||
else:
|
||||
@@ -303,6 +330,7 @@ def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
|
||||
where batch.disabled = 0
|
||||
and item = %(item_code)s
|
||||
and (name like %(txt)s
|
||||
or expiry_date like %(txt)s
|
||||
or manufacturing_date like %(txt)s)
|
||||
and docstatus < 2
|
||||
{0}
|
||||
|
||||
@@ -72,7 +72,7 @@ def validate_returned_items(doc):
|
||||
|
||||
items_returned = False
|
||||
for d in doc.get("items"):
|
||||
if d.item_code and (flt(d.qty) < 0 or d.get('received_qty') < 0):
|
||||
if d.item_code and (flt(d.qty) < 0 or flt(d.get('received_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))
|
||||
|
||||
@@ -306,8 +306,9 @@ class SellingController(StockController):
|
||||
if flt(d.conversion_factor)==0.0:
|
||||
d.conversion_factor = get_conversion_factor(d.item_code, d.uom).get("conversion_factor") or 1.0
|
||||
return_rate = 0
|
||||
if cint(self.is_return) and self.return_against and self.docstatus==1:
|
||||
return_rate = self.get_incoming_rate_for_sales_return(d.item_code, self.return_against)
|
||||
if cint(self.is_return) and self.docstatus==1:
|
||||
return_rate = self.get_incoming_rate_for_sales_return(d.item_code,
|
||||
d.warehouse, self.return_against)
|
||||
|
||||
# On cancellation or if return entry submission, make stock ledger entry for
|
||||
# target warehouse first, to update serial no values properly
|
||||
|
||||
@@ -299,7 +299,7 @@ class StockController(AccountsController):
|
||||
|
||||
return serialized_items
|
||||
|
||||
def get_incoming_rate_for_sales_return(self, item_code, against_document):
|
||||
def get_incoming_rate_for_sales_return(self, item_code, warehouse, against_document):
|
||||
incoming_rate = 0.0
|
||||
if against_document and item_code:
|
||||
incoming_rate = frappe.db.sql("""select abs(stock_value_difference / actual_qty)
|
||||
@@ -308,6 +308,9 @@ class StockController(AccountsController):
|
||||
and item_code = %s limit 1""",
|
||||
(self.doctype, against_document, item_code))
|
||||
incoming_rate = incoming_rate[0][0] if incoming_rate else 0.0
|
||||
else:
|
||||
incoming_rate = get_valuation_rate(item_code, warehouse,
|
||||
self.doctype, against_document, company=self.company, currency=self.currency)
|
||||
|
||||
return incoming_rate
|
||||
|
||||
|
||||
@@ -305,11 +305,19 @@ class calculate_taxes_and_totals(object):
|
||||
last_tax = self.doc.get("taxes")[-1]
|
||||
non_inclusive_tax_amount = sum([flt(d.tax_amount_after_discount_amount)
|
||||
for d in self.doc.get("taxes") if not d.included_in_print_rate])
|
||||
|
||||
diff = self.doc.total + non_inclusive_tax_amount \
|
||||
- flt(last_tax.total, last_tax.precision("total"))
|
||||
|
||||
# If discount amount applied, deduct the discount amount
|
||||
# because self.doc.total is always without discount, but last_tax.total is after discount
|
||||
if self.discount_amount_applied and self.doc.discount_amount:
|
||||
diff -= flt(self.doc.discount_amount)
|
||||
|
||||
diff = flt(diff, self.doc.precision("rounding_adjustment"))
|
||||
|
||||
if diff and abs(diff) <= (5.0 / 10**last_tax.precision("tax_amount")):
|
||||
self.doc.rounding_adjustment = flt(flt(self.doc.rounding_adjustment) +
|
||||
flt(diff), self.doc.precision("rounding_adjustment"))
|
||||
self.doc.rounding_adjustment = diff
|
||||
|
||||
def calculate_totals(self):
|
||||
self.doc.grand_total = flt(self.doc.get("taxes")[-1].total) + flt(self.doc.rounding_adjustment) \
|
||||
|
||||
@@ -1468,7 +1468,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2019-05-17 19:03:32.740910",
|
||||
"modified": "2019-10-22 11:11:32.740910",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "Opportunity",
|
||||
|
||||
@@ -114,10 +114,11 @@ def add_account_subtype(account_subtype):
|
||||
|
||||
@frappe.whitelist()
|
||||
def sync_transactions(bank, bank_account):
|
||||
|
||||
last_sync_date = frappe.db.get_value("Bank Account", bank_account, "last_integration_date")
|
||||
if last_sync_date:
|
||||
start_date = formatdate(last_sync_date, "YYYY-MM-dd")
|
||||
'''Sync transactions based on the last integration date as the start date, after sync is completed
|
||||
add the transaction date of the oldest transaction as the last integration date'''
|
||||
last_transaction_date = frappe.db.get_value("Bank Account", bank_account, "last_integration_date")
|
||||
if last_transaction_date:
|
||||
start_date = formatdate(last_transaction_date, "YYYY-MM-dd")
|
||||
else:
|
||||
start_date = formatdate(add_months(today(), -12), "YYYY-MM-dd")
|
||||
end_date = formatdate(today(), "YYYY-MM-dd")
|
||||
@@ -125,13 +126,17 @@ def sync_transactions(bank, bank_account):
|
||||
try:
|
||||
transactions = get_transactions(bank=bank, bank_account=bank_account, start_date=start_date, end_date=end_date)
|
||||
result = []
|
||||
if transactions:
|
||||
for transaction in transactions:
|
||||
result.append(new_bank_transaction(transaction))
|
||||
for transaction in reversed(transactions):
|
||||
result += new_bank_transaction(transaction)
|
||||
|
||||
frappe.db.set_value("Bank Account", bank_account, "last_integration_date", getdate(end_date))
|
||||
if result:
|
||||
last_transaction_date = frappe.db.get_value('Bank Transaction', result.pop(), 'date')
|
||||
|
||||
frappe.logger().info("Plaid added {} new Bank Transactions from '{}' between {} and {}".format(
|
||||
len(result), bank_account, start_date, end_date))
|
||||
|
||||
frappe.db.set_value("Bank Account", bank_account, "last_integration_date", last_transaction_date)
|
||||
|
||||
return result
|
||||
except Exception:
|
||||
frappe.log_error(frappe.get_traceback(), _("Plaid transactions sync error"))
|
||||
|
||||
|
||||
@@ -386,5 +386,5 @@ def get_procedure_prescribed(patient):
|
||||
return frappe.db.sql("""select pp.name, pp.procedure, pp.parent, ct.practitioner,
|
||||
ct.encounter_date, pp.practitioner, pp.date, pp.department
|
||||
from `tabPatient Encounter` ct, `tabProcedure Prescription` pp
|
||||
where ct.patient='{0}' and pp.parent=ct.name and pp.appointment_booked=0
|
||||
order by ct.creation desc""".format(patient))
|
||||
where ct.patient=%(patient)s and pp.parent=ct.name and pp.appointment_booked=0
|
||||
order by ct.creation desc""", {"patient": patient})
|
||||
|
||||
@@ -233,7 +233,6 @@ scheduler_events = {
|
||||
],
|
||||
"daily": [
|
||||
"erpnext.stock.reorder_item.reorder_item",
|
||||
"erpnext.setup.doctype.email_digest.email_digest.send",
|
||||
"erpnext.support.doctype.issue.issue.auto_close_tickets",
|
||||
"erpnext.crm.doctype.opportunity.opportunity.auto_close_opportunity",
|
||||
"erpnext.controllers.accounts_controller.update_invoice_status",
|
||||
@@ -252,6 +251,7 @@ scheduler_events = {
|
||||
"erpnext.projects.doctype.project.project.send_project_status_email_to_users"
|
||||
],
|
||||
"daily_long": [
|
||||
"erpnext.setup.doctype.email_digest.email_digest.send",
|
||||
"erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.update_latest_price_in_all_boms"
|
||||
],
|
||||
"monthly_long": [
|
||||
|
||||
@@ -48,12 +48,17 @@ def get_abbreviated_name(name, company):
|
||||
@frappe.whitelist()
|
||||
def get_children(doctype, parent=None, company=None, is_root=False):
|
||||
condition = ''
|
||||
var_dict = {
|
||||
"name": get_root_of("Department"),
|
||||
"parent": parent,
|
||||
"company": company,
|
||||
}
|
||||
if company == parent:
|
||||
condition = "name='{0}'".format(get_root_of("Department"))
|
||||
condition = "name=%(name)s"
|
||||
elif company:
|
||||
condition = "parent_department='{0}' and company='{1}'".format(parent, company)
|
||||
condition = "parent_department=%(parent)s and company=%(company)s"
|
||||
else:
|
||||
condition = "parent_department = '{0}'".format(parent)
|
||||
condition = "parent_department = %(parent)s"
|
||||
|
||||
return frappe.db.sql("""
|
||||
select
|
||||
@@ -62,7 +67,7 @@ def get_children(doctype, parent=None, company=None, is_root=False):
|
||||
from `tab{doctype}`
|
||||
where
|
||||
{condition}
|
||||
order by name""".format(doctype=doctype, condition=condition), as_dict=1)
|
||||
order by name""".format(doctype=doctype, condition=condition), var_dict, as_dict=1)
|
||||
|
||||
@frappe.whitelist()
|
||||
def add_node():
|
||||
|
||||
@@ -157,10 +157,11 @@ class Employee(NestedSet):
|
||||
def validate_status(self):
|
||||
if self.status == 'Left':
|
||||
reports_to = frappe.db.get_all('Employee',
|
||||
filters={'reports_to': self.name}
|
||||
filters={'reports_to': self.name, 'status': "Active"},
|
||||
fields = ['name','employee_name']
|
||||
)
|
||||
if reports_to:
|
||||
link_to_employees = [frappe.utils.get_link_to_form('Employee', employee.name) for employee in reports_to]
|
||||
link_to_employees = [frappe.utils.get_link_to_form('Employee', employee.name, label=employee.employee_name) for employee in reports_to]
|
||||
throw(_("Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ")
|
||||
+ ', '.join(link_to_employees), EmployeeLeftValidationError)
|
||||
if not self.relieving_date:
|
||||
|
||||
@@ -7,6 +7,14 @@ frappe.ui.form.on('Employee Onboarding', {
|
||||
frm.add_fetch("employee_onboarding_template", "department", "department");
|
||||
frm.add_fetch("employee_onboarding_template", "designation", "designation");
|
||||
frm.add_fetch("employee_onboarding_template", "employee_grade", "employee_grade");
|
||||
|
||||
frm.set_query('job_offer', function () {
|
||||
return {
|
||||
filters: {
|
||||
'job_applicant': frm.doc.job_applicant
|
||||
}
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
refresh: function(frm) {
|
||||
|
||||
@@ -13,6 +13,7 @@ class Loan(AccountsController):
|
||||
def validate(self):
|
||||
validate_repayment_method(self.repayment_method, self.loan_amount, self.monthly_repayment_amount, self.repayment_periods)
|
||||
self.set_missing_fields()
|
||||
self.validate_loan_application()
|
||||
self.make_repayment_schedule()
|
||||
self.set_repayment_period()
|
||||
self.calculate_totals()
|
||||
@@ -33,6 +34,13 @@ class Loan(AccountsController):
|
||||
if self.status == "Repaid/Closed":
|
||||
self.total_amount_paid = self.total_payment
|
||||
|
||||
def validate_loan_application(self):
|
||||
if self.loan_application:
|
||||
loan = frappe.db.get_value("Loan", {"loan_application": self.loan_application}, "name")
|
||||
|
||||
if loan and loan != self.name:
|
||||
frappe.throw(_("Loan {0} already created for Loan Application {1}").format(frappe.bold(loan),
|
||||
frappe.bold(self.loan_application)))
|
||||
|
||||
def make_jv_entry(self):
|
||||
self.check_permission('write')
|
||||
@@ -116,6 +124,7 @@ def update_disbursement_status(doc):
|
||||
""", (doc.payment_account, doc.name), as_dict=1)[0]
|
||||
|
||||
disbursement_date = None
|
||||
status = ''
|
||||
if not disbursement or disbursement.disbursed_amount == 0:
|
||||
status = "Sanctioned"
|
||||
elif disbursement.disbursed_amount == doc.loan_amount:
|
||||
|
||||
@@ -23,20 +23,25 @@ frappe.ui.form.on('Loan Application', {
|
||||
},
|
||||
add_toolbar_buttons: function(frm) {
|
||||
if (frm.doc.status == "Approved") {
|
||||
frm.add_custom_button(__('Create Loan'), function() {
|
||||
frappe.call({
|
||||
method: "erpnext.hr.doctype.loan_application.loan_application.make_loan",
|
||||
args: {
|
||||
"source_name": frm.doc.name
|
||||
},
|
||||
callback: function(r) {
|
||||
if(!r.exc) {
|
||||
var doc = frappe.model.sync(r.message);
|
||||
frappe.set_route("Form", r.message.doctype, r.message.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
}).addClass("btn-primary");
|
||||
// show create loan button if loan not created against loan aplication
|
||||
frappe.db.get_value("Loan", {"loan_application": frm.doc.name}, "name", (r) => {
|
||||
if (!r) {
|
||||
frm.add_custom_button(__('Create Loan'), function() {
|
||||
frappe.call({
|
||||
method: "erpnext.hr.doctype.loan_application.loan_application.make_loan",
|
||||
args: {
|
||||
"source_name": frm.doc.name
|
||||
},
|
||||
callback: function(r) {
|
||||
if(!r.exc) {
|
||||
var doc = frappe.model.sync(r.message);
|
||||
frappe.set_route("Form", r.message.doctype, r.message.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
}).addClass("btn-primary");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -117,7 +117,7 @@ frappe.ui.form.on("BOM", {
|
||||
args: {
|
||||
update_parent: true,
|
||||
from_child_bom:false,
|
||||
save: false
|
||||
save: frm.doc.docstatus === 1 ? true : false
|
||||
},
|
||||
callback: function(r) {
|
||||
refresh_field("items");
|
||||
|
||||
@@ -34,12 +34,15 @@ class BOM(WebsiteGenerator):
|
||||
# name can be BOM/ITEM/001, BOM/ITEM/001-1, BOM-ITEM-001, BOM-ITEM-001-1
|
||||
|
||||
# split by item
|
||||
names = [name.split(self.item)[-1][1:] for name in names]
|
||||
names = [name.split(self.item, 1) for name in names]
|
||||
names = [d[-1][1:] for d in filter(lambda x: len(x) > 1 and x[-1], names)]
|
||||
|
||||
# split by (-) if cancelled
|
||||
names = [cint(name.split('-')[-1]) for name in names]
|
||||
|
||||
idx = max(names) + 1
|
||||
if names:
|
||||
names = [cint(name.split('-')[-1]) for name in names]
|
||||
idx = max(names) + 1
|
||||
else:
|
||||
idx = 1
|
||||
else:
|
||||
idx = 1
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
@@ -14,10 +15,12 @@
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "item_code",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -41,14 +44,17 @@
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "item_name",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
@@ -72,14 +78,17 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "warehouse",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -103,14 +112,17 @@
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
@@ -132,14 +144,17 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "quantity",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
@@ -162,14 +177,51 @@
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "uom",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "UOM",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "UOM",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "actual_qty",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
@@ -192,14 +244,86 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "item_details",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Item Description",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Text Editor",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Description",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "description",
|
||||
"oldfieldtype": "Small Text",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"print_width": "300px",
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0,
|
||||
"width": "300px"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "min_order_qty",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
@@ -222,14 +346,17 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "section_break_8",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@@ -252,14 +379,17 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "sales_order",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -283,14 +413,17 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "requested_qty",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
@@ -313,6 +446,7 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
@@ -326,7 +460,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-02-15 13:08:30.535963",
|
||||
"modified": "2019-11-08 14:59:58.805613",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Material Request Plan Item",
|
||||
@@ -340,5 +474,6 @@
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
}
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
}
|
||||
|
||||
@@ -122,6 +122,8 @@ frappe.ui.form.on('Production Plan', {
|
||||
item.quantity = d.quantity;
|
||||
item.sales_order = d.sales_order;
|
||||
item.warehouse = d.warehouse;
|
||||
item.description = d.description;
|
||||
item.uom = d.uom;
|
||||
});
|
||||
}
|
||||
refresh_field('mr_items');
|
||||
|
||||
@@ -472,7 +472,9 @@ def get_material_request_items(row, sales_order, company, ignore_existing_ordere
|
||||
or row.get('default_warehouse') or item_group_defaults.get("default_warehouse"),
|
||||
'actual_qty': actual_qty,
|
||||
'min_order_qty': row['min_order_qty'],
|
||||
'sales_order': sales_order
|
||||
'sales_order': sales_order,
|
||||
'description': row.get("description"),
|
||||
'uom': row.get("purchase_uom") or row.get("stock_uom")
|
||||
}
|
||||
|
||||
def get_sales_orders(self):
|
||||
|
||||
@@ -318,7 +318,7 @@ frappe.ui.form.on("Work Order", {
|
||||
},
|
||||
|
||||
project: function(frm) {
|
||||
if(!erpnext.in_production_item_onchange) {
|
||||
if(!erpnext.in_production_item_onchange && !frm.doc.bom_no) {
|
||||
frm.trigger("production_item");
|
||||
}
|
||||
},
|
||||
@@ -371,6 +371,11 @@ frappe.ui.form.on("Work Order", {
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
additional_operating_cost: function(frm) {
|
||||
erpnext.work_order.calculate_cost(frm.doc);
|
||||
erpnext.work_order.calculate_total_cost(frm);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -507,8 +512,7 @@ erpnext.work_order = {
|
||||
},
|
||||
|
||||
calculate_total_cost: function(frm) {
|
||||
var variable_cost = frm.doc.actual_operating_cost ?
|
||||
flt(frm.doc.actual_operating_cost) : flt(frm.doc.planned_operating_cost)
|
||||
let variable_cost = flt(frm.doc.actual_operating_cost) || flt(frm.doc.planned_operating_cost);
|
||||
frm.set_value("total_operating_cost", (flt(frm.doc.additional_operating_cost) + variable_cost))
|
||||
},
|
||||
|
||||
|
||||
@@ -496,6 +496,7 @@ erpnext.patches.v10_0.rename_offer_letter_to_job_offer
|
||||
execute:frappe.delete_doc('DocType', 'Production Planning Tool', ignore_missing=True)
|
||||
erpnext.patches.v10_0.migrate_daily_work_summary_settings_to_daily_work_summary_group # 24-12-2018
|
||||
erpnext.patches.v10_0.add_default_cash_flow_mappers
|
||||
erpnext.patches.v11_0.rename_duplicate_item_code_values
|
||||
erpnext.patches.v11_0.make_quality_inspection_template
|
||||
erpnext.patches.v10_0.update_status_for_multiple_source_in_po
|
||||
erpnext.patches.v10_0.set_auto_created_serial_no_in_stock_entry
|
||||
@@ -607,3 +608,4 @@ erpnext.patches.v11_1.set_quotation_status
|
||||
erpnext.patches.v11_1.update_default_supplier_in_item_defaults
|
||||
erpnext.patches.v11_1.set_status_for_material_request_type_manufacture
|
||||
erpnext.patches.v11_1.set_produced_qty_field_in_sales_order_for_work_order
|
||||
erpnext.patches.v11_1.set_payment_entry_status
|
||||
@@ -0,0 +1,8 @@
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
items = []
|
||||
items = frappe.db.sql("""select item_code from `tabItem` group by item_code having count(*) > 1""", as_dict=True)
|
||||
if items:
|
||||
for item in items:
|
||||
frappe.db.sql("""update `tabItem` set item_code=name where item_code = %s""", (item.item_code))
|
||||
@@ -1,9 +1,10 @@
|
||||
from __future__ import unicode_literals
|
||||
from frappe import _
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
|
||||
hr_settings = frappe.get_single("HR Settings")
|
||||
hr_settings.leave_approval_notification_template = "Leave Approval Notification"
|
||||
hr_settings.leave_status_notification_template = "Leave Status Notification"
|
||||
hr_settings.save()
|
||||
hr_settings.leave_approval_notification_template = _("Leave Approval Notification")
|
||||
hr_settings.leave_status_notification_template = _("Leave Status Notification")
|
||||
hr_settings.save()
|
||||
|
||||
9
erpnext/patches/v11_1/set_payment_entry_status.py
Normal file
9
erpnext/patches/v11_1/set_payment_entry_status.py
Normal file
@@ -0,0 +1,9 @@
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
frappe.reload_doctype("Payment Entry")
|
||||
frappe.db.sql("""update `tabPayment Entry` set status = CASE
|
||||
WHEN docstatus = 1 THEN 'Submitted'
|
||||
WHEN docstatus = 2 THEN 'Cancelled'
|
||||
ELSE 'Draft'
|
||||
END;""")
|
||||
@@ -713,7 +713,7 @@
|
||||
"depends_on": "",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "depends_on_tasks",
|
||||
"fieldtype": "Data",
|
||||
"fieldtype": "Long Text",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
@@ -1433,4 +1433,4 @@
|
||||
"track_changes": 0,
|
||||
"track_seen": 1,
|
||||
"track_views": 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import json
|
||||
|
||||
import frappe
|
||||
from frappe import _, throw
|
||||
from frappe.utils import add_days, cstr, date_diff, get_link_to_form, getdate
|
||||
from frappe.utils import add_days, cstr, date_diff, get_link_to_form, getdate, today
|
||||
from frappe.utils.nestedset import NestedSet
|
||||
|
||||
|
||||
@@ -47,8 +47,8 @@ class Task(NestedSet):
|
||||
def validate_status(self):
|
||||
if self.status!=self.get_db_value("status") and self.status == "Closed":
|
||||
for d in self.depends_on:
|
||||
if frappe.db.get_value("Task", d.task, "status") != "Closed":
|
||||
frappe.throw(_("Cannot close task as its dependant task {0} is not closed.").format(d.task))
|
||||
if frappe.db.get_value("Task", d.task, "status") not in ("Closed", "Cancelled"):
|
||||
frappe.throw(_("Cannot close task as its dependant task {0} is not closed/cancelled.").format(d.task))
|
||||
|
||||
from frappe.desk.form.assign_to import clear
|
||||
clear(self.doctype, self.name)
|
||||
@@ -199,8 +199,11 @@ def set_multiple_status(names, status):
|
||||
task.save()
|
||||
|
||||
def set_tasks_as_overdue():
|
||||
tasks = frappe.get_all("Task", filters={'status':['not in',['Cancelled', 'Closed']]})
|
||||
tasks = frappe.get_all("Task", filters={"status": ["not in", ["Cancelled", "Closed"]]}, fields=["name", "status", "review_date"])
|
||||
for task in tasks:
|
||||
if task.status == "Pending Review":
|
||||
if getdate(task.review_date) > getdate(today()):
|
||||
continue
|
||||
frappe.get_doc("Task", task.name).update_status()
|
||||
|
||||
@frappe.whitelist()
|
||||
|
||||
@@ -191,6 +191,9 @@ class Timesheet(Document):
|
||||
}, as_dict=True)
|
||||
# check internal overlap
|
||||
for time_log in self.time_logs:
|
||||
if not (time_log.from_time and time_log.to_time
|
||||
and args.from_time and args.to_time): continue
|
||||
|
||||
if (fieldname != 'workstation' or args.get(fieldname) == time_log.get(fieldname)) and \
|
||||
args.idx != time_log.idx and ((args.from_time > time_log.from_time and args.from_time < time_log.to_time) or
|
||||
(args.to_time > time_log.from_time and args.to_time < time_log.to_time) or
|
||||
|
||||
@@ -387,9 +387,14 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
|
||||
var diff = me.frm.doc.total + non_inclusive_tax_amount
|
||||
- flt(last_tax.total, precision("grand_total"));
|
||||
|
||||
if(me.discount_amount_applied && me.frm.doc.discount_amount) {
|
||||
diff -= flt(me.frm.doc.discount_amount);
|
||||
}
|
||||
|
||||
diff = flt(diff, precision("rounding_adjustment"));
|
||||
|
||||
if ( diff && Math.abs(diff) <= (5.0 / Math.pow(10, precision("tax_amount", last_tax))) ) {
|
||||
this.frm.doc.rounding_adjustment = flt(flt(this.frm.doc.rounding_adjustment) + diff,
|
||||
precision("rounding_adjustment"));
|
||||
me.frm.doc.rounding_adjustment = diff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -853,15 +853,19 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
},
|
||||
|
||||
conversion_factor: function(doc, cdt, cdn, dont_fetch_price_list_rate) {
|
||||
if(doc.doctype != 'Material Request' && frappe.meta.get_docfield(cdt, "stock_qty", cdn)) {
|
||||
if(frappe.meta.get_docfield(cdt, "stock_qty", cdn)) {
|
||||
var item = frappe.get_doc(cdt, cdn);
|
||||
frappe.model.round_floats_in(item, ["qty", "conversion_factor"]);
|
||||
item.stock_qty = flt(item.qty * item.conversion_factor, precision("stock_qty", item));
|
||||
item.total_weight = flt(item.stock_qty * item.weight_per_unit);
|
||||
refresh_field("stock_qty", item.name, item.parentfield);
|
||||
refresh_field("total_weight", item.name, item.parentfield);
|
||||
this.toggle_conversion_factor(item);
|
||||
this.calculate_net_weight();
|
||||
|
||||
if(doc.doctype != "Material Request") {
|
||||
item.total_weight = flt(item.stock_qty * item.weight_per_unit);
|
||||
refresh_field("total_weight", item.name, item.parentfield);
|
||||
this.calculate_net_weight();
|
||||
}
|
||||
|
||||
if (!dont_fetch_price_list_rate &&
|
||||
frappe.meta.has_field(doc.doctype, "price_list_currency")) {
|
||||
this.apply_price_list(item, true);
|
||||
@@ -1422,6 +1426,11 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
'item_code': item.item_code,
|
||||
'posting_date': me.frm.doc.posting_date || frappe.datetime.nowdate(),
|
||||
}
|
||||
|
||||
if (doc.is_return) {
|
||||
filters["is_return"] = 1;
|
||||
}
|
||||
|
||||
if (item.warehouse) filters["warehouse"] = item.warehouse;
|
||||
|
||||
return {
|
||||
|
||||
@@ -60,8 +60,8 @@ def validate_gstin_check_digit(gstin, label='GSTIN'):
|
||||
total += digit
|
||||
factor = 2 if factor == 1 else 1
|
||||
if gstin[-1] != code_point_chars[((mod - (total % mod)) % mod)]:
|
||||
frappe.throw(_("Invalid {0}! The check digit validation has failed. " +
|
||||
"Please ensure you've typed the {0} correctly.".format(label)))
|
||||
frappe.throw(_("""Invalid {0}! The check digit validation has failed.
|
||||
Please ensure you've typed the {0} correctly.""".format(label)))
|
||||
|
||||
def get_itemised_tax_breakup_header(item_doctype, tax_accounts):
|
||||
if frappe.get_meta(item_doctype).has_field('gst_hsn_code'):
|
||||
@@ -379,7 +379,7 @@ def get_gstins_for_company(company):
|
||||
`tabDynamic Link`.parent = `tabAddress`.name and
|
||||
`tabDynamic Link`.parenttype = 'Address' and
|
||||
`tabDynamic Link`.link_doctype = 'Company' and
|
||||
`tabDynamic Link`.link_name = '{0}'""".format(company))
|
||||
`tabDynamic Link`.link_name = %(company)s""", {"company": company})
|
||||
return company_gstins
|
||||
|
||||
def get_address_details(data, doc, company_address, billing_address):
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
{%- endmacro %}
|
||||
|
||||
{%- macro render_discount_or_margin(item) -%}
|
||||
{%- if item.discount_percentage > 0.0 or item.margin_type %}
|
||||
{%- if (item.discount_percentage and item.discount_percentage > 0.0) or item.margin_type %}
|
||||
<ScontoMaggiorazione>
|
||||
{%- if item.discount_percentage > 0.0 %}
|
||||
<Tipo>SC</Tipo>
|
||||
|
||||
@@ -1687,7 +1687,7 @@
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "other_charges_calculation",
|
||||
"fieldtype": "Text",
|
||||
"fieldtype": "Long Text",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
@@ -3224,7 +3224,7 @@
|
||||
"istable": 0,
|
||||
"max_attachments": 1,
|
||||
"menu_index": 0,
|
||||
"modified": "2019-06-25 15:31:04.724730",
|
||||
"modified": "2020-04-16 19:05:32.197858",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Quotation",
|
||||
|
||||
@@ -142,7 +142,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
|
||||
// delivery note
|
||||
if(flt(doc.per_delivered, 6) < 100 && allow_delivery) {
|
||||
this.frm.add_custom_button(__('Delivery'),
|
||||
this.frm.add_custom_button(__('Delivery Note'),
|
||||
function() { me.make_delivery_note_based_on_delivery_date(); }, __("Make"));
|
||||
|
||||
if(["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1){
|
||||
|
||||
@@ -1981,7 +1981,7 @@
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "other_charges_calculation",
|
||||
"fieldtype": "Text",
|
||||
"fieldtype": "Long Text",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
@@ -4204,7 +4204,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2019-04-05 03:44:46.037178",
|
||||
"modified": "2020-04-16 19:05:14.867404",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Sales Order",
|
||||
|
||||
@@ -622,7 +622,6 @@ def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False):
|
||||
target.set_advances()
|
||||
|
||||
def set_missing_values(source, target):
|
||||
target.is_pos = 0
|
||||
target.ignore_pricing_rule = 1
|
||||
target.flags.ignore_permissions = True
|
||||
target.run_method("set_missing_values")
|
||||
@@ -645,12 +644,15 @@ def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False):
|
||||
|
||||
if source_parent.project:
|
||||
target.cost_center = frappe.db.get_value("Project", source_parent.project, "cost_center")
|
||||
if not target.cost_center and target.item_code:
|
||||
if target.item_code:
|
||||
item = get_item_defaults(target.item_code, source_parent.company)
|
||||
item_group = get_item_group_defaults(target.item_code, source_parent.company)
|
||||
target.cost_center = item.get("selling_cost_center") \
|
||||
cost_center = item.get("selling_cost_center") \
|
||||
or item_group.get("selling_cost_center")
|
||||
|
||||
if cost_center:
|
||||
target.cost_center = cost_center
|
||||
|
||||
doclist = get_mapped_doc("Sales Order", source_name, {
|
||||
"Sales Order": {
|
||||
"doctype": "Sales Invoice",
|
||||
|
||||
@@ -7,7 +7,7 @@ from frappe.utils import flt
|
||||
|
||||
def execute(filters=None):
|
||||
if not filters: filters = {}
|
||||
|
||||
|
||||
columns = get_columns()
|
||||
iwq_map = get_item_warehouse_quantity_map()
|
||||
item_map = get_item_details()
|
||||
@@ -15,22 +15,23 @@ def execute(filters=None):
|
||||
for sbom, warehouse in iwq_map.items():
|
||||
total = 0
|
||||
total_qty = 0
|
||||
|
||||
|
||||
for wh, item_qty in warehouse.items():
|
||||
total += 1
|
||||
row = [sbom, item_map.get(sbom).item_name, item_map.get(sbom).description,
|
||||
item_map.get(sbom).stock_uom, wh]
|
||||
available_qty = item_qty
|
||||
total_qty += flt(available_qty)
|
||||
row += [available_qty]
|
||||
|
||||
if available_qty:
|
||||
data.append(row)
|
||||
if (total == len(warehouse)):
|
||||
row = ["", "", "Total", "", "", total_qty]
|
||||
if item_map.get(sbom):
|
||||
row = [sbom, item_map.get(sbom).item_name, item_map.get(sbom).description,
|
||||
item_map.get(sbom).stock_uom, wh]
|
||||
available_qty = item_qty
|
||||
total_qty += flt(available_qty)
|
||||
row += [available_qty]
|
||||
|
||||
if available_qty:
|
||||
data.append(row)
|
||||
if (total == len(warehouse)):
|
||||
row = ["", "", "Total", "", "", total_qty]
|
||||
data.append(row)
|
||||
return columns, data
|
||||
|
||||
|
||||
def get_columns():
|
||||
columns = ["Item Code:Link/Item:100", "Item Name::100", "Description::120", \
|
||||
"UOM:Link/UOM:80", "Warehouse:Link/Warehouse:100", "Quantity::100"]
|
||||
|
||||
@@ -80,10 +80,14 @@ frappe.query_reports["Sales Analytics"] = {
|
||||
|
||||
var tree_type = frappe.query_report.filters[0].value;
|
||||
|
||||
if(tree_type == "Customer" || tree_type == "Item") {
|
||||
if(tree_type == "Customer") {
|
||||
row_values = data.slice(4,length-1).map(function (column) {
|
||||
return column.content;
|
||||
})
|
||||
} else if (tree_type == "Item") {
|
||||
row_values = data.slice(5,length-1).map(function (column) {
|
||||
return column.content;
|
||||
})
|
||||
}
|
||||
else {
|
||||
row_values = data.slice(3,length-1).map(function (column) {
|
||||
|
||||
@@ -114,7 +114,7 @@ class Analytics(object):
|
||||
if self.filters["value_quantity"] == 'Value':
|
||||
value_field = 'base_amount'
|
||||
else:
|
||||
value_field = 'qty'
|
||||
value_field = 'stock_qty'
|
||||
|
||||
self.entries = frappe.db.sql("""
|
||||
select i.item_code as entity, i.item_name as entity_name, i.stock_uom, i.{value_field} as value_field, s.{date_field}
|
||||
@@ -301,8 +301,10 @@ class Analytics(object):
|
||||
def get_chart_data(self):
|
||||
length = len(self.columns)
|
||||
|
||||
if self.filters.tree_type in ["Customer", "Supplier", "Item"]:
|
||||
labels = [d.get("label") for d in self.columns[2:length-1]]
|
||||
if self.filters.tree_type in ["Customer", "Supplier"]:
|
||||
labels = [d.get("label") for d in self.columns[2:length - 1]]
|
||||
elif self.filters.tree_type == "Item":
|
||||
labels = [d.get("label") for d in self.columns[3:length - 1]]
|
||||
else:
|
||||
labels = [d.get("label") for d in self.columns[1:length-1]]
|
||||
self.chart = {
|
||||
|
||||
@@ -284,7 +284,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
|
||||
child: item,
|
||||
args: {
|
||||
"batch_no": item.batch_no,
|
||||
"stock_qty": item.stock_qty,
|
||||
"stock_qty": item.stock_qty || item.qty, //if stock_qty field is not available, fetch qty (in case of Packed Items table)
|
||||
"warehouse": item.warehouse,
|
||||
"item_code": item.item_code,
|
||||
"has_serial_no": has_serial_no
|
||||
|
||||
@@ -109,7 +109,7 @@ def get_product_list_for_group(product_group=None, start=0, limit=10, search=Non
|
||||
or I.name like %(search)s)"""
|
||||
search = "%" + cstr(search) + "%"
|
||||
|
||||
query += """order by I.weightage desc, in_stock desc, I.modified desc limit %s, %s""" % (start, limit)
|
||||
query += """order by I.weightage desc, in_stock desc, I.modified desc limit %s, %s""" % (cint(start), cint(limit))
|
||||
|
||||
data = frappe.db.sql(query, {"product_group": product_group,"search": search, "today": nowdate()}, as_dict=1)
|
||||
data = adjust_qty_for_expired_items(data)
|
||||
|
||||
@@ -141,6 +141,6 @@ def insert_record(records):
|
||||
raise
|
||||
|
||||
def welcome_email():
|
||||
site_name = get_default_company()
|
||||
title = _("Welcome to {0}".format(site_name))
|
||||
return title
|
||||
site_name = get_default_company() or "ERPNext"
|
||||
title = _("Welcome to {0}").format(site_name)
|
||||
return title
|
||||
|
||||
@@ -66,6 +66,7 @@ def place_order():
|
||||
|
||||
from erpnext.selling.doctype.quotation.quotation import _make_sales_order
|
||||
sales_order = frappe.get_doc(_make_sales_order(quotation.name, ignore_permissions=True))
|
||||
sales_order.payment_schedule = []
|
||||
|
||||
if not cart_settings.allow_items_not_in_stock:
|
||||
for item in sales_order.get("items"):
|
||||
@@ -454,9 +455,8 @@ def get_applicable_shipping_rules(party=None, quotation=None):
|
||||
shipping_rules = get_shipping_rules(quotation)
|
||||
|
||||
if shipping_rules:
|
||||
rule_label_map = frappe.db.get_values("Shipping Rule", shipping_rules, "label")
|
||||
# we need this in sorted order as per the position of the rule in the settings page
|
||||
return [[rule, rule_label_map.get(rule)] for rule in shipping_rules]
|
||||
return [[rule, rule] for rule in shipping_rules]
|
||||
|
||||
def get_shipping_rules(quotation=None, cart_settings=None):
|
||||
if not quotation:
|
||||
|
||||
@@ -2156,7 +2156,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "other_charges_calculation",
|
||||
"fieldtype": "Text",
|
||||
"fieldtype": "Long Text",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
@@ -4296,7 +4296,7 @@
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2019-01-07 16:51:52.357859",
|
||||
"modified": "2020-04-16 19:05:56.439204",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Delivery Note",
|
||||
|
||||
@@ -400,7 +400,6 @@ def make_sales_invoice(source_name, target_doc=None):
|
||||
invoiced_qty_map = get_invoiced_qty_map(source_name)
|
||||
|
||||
def set_missing_values(source, target):
|
||||
target.is_pos = 0
|
||||
target.ignore_pricing_rule = 1
|
||||
target.run_method("set_missing_values")
|
||||
target.run_method("set_po_nos")
|
||||
|
||||
@@ -6,9 +6,9 @@ frappe.listview_settings['Delivery Note'] = {
|
||||
return [__("Return"), "darkgrey", "is_return,=,Yes"];
|
||||
} else if (doc.status === "Closed") {
|
||||
return [__("Closed"), "green", "status,=,Closed"];
|
||||
} else if (doc.grand_total !== 0 && flt(doc.per_billed, 2) < 100) {
|
||||
} else if (flt(doc.per_billed, 2) < 100) {
|
||||
return [__("To Bill"), "orange", "per_billed,<,100"];
|
||||
} else if (doc.grand_total === 0 || flt(doc.per_billed, 2) == 100) {
|
||||
} else if (flt(doc.per_billed, 2) == 100) {
|
||||
return [__("Completed"), "green", "per_billed,=,100"];
|
||||
}
|
||||
},
|
||||
|
||||
@@ -518,7 +518,7 @@ class Item(WebsiteGenerator):
|
||||
"""select parent from `tabItem Barcode` where barcode = %s and parent != %s""", (item_barcode.barcode, self.name))
|
||||
if duplicate:
|
||||
frappe.throw(_("Barcode {0} already used in Item {1}").format(
|
||||
item_barcode.barcode, duplicate[0][0]), frappe.DuplicateEntryError)
|
||||
item_barcode.barcode, duplicate[0][0]))
|
||||
|
||||
item_barcode.barcode_type = "" if item_barcode.barcode_type not in options else item_barcode.barcode_type
|
||||
if item_barcode.barcode_type and item_barcode.barcode_type.upper() in ('EAN', 'UPC-A', 'EAN-13', 'EAN-8'):
|
||||
|
||||
@@ -124,7 +124,7 @@ class LandedCostVoucher(Document):
|
||||
|
||||
# update stock & gl entries for submit state of PR
|
||||
doc.docstatus = 1
|
||||
doc.update_stock_ledger(via_landed_cost_voucher=True)
|
||||
doc.update_stock_ledger(allow_negative_stock=True, via_landed_cost_voucher=True)
|
||||
doc.make_gl_entries()
|
||||
|
||||
def update_rate_in_serial_no(self, receipt_document):
|
||||
|
||||
@@ -217,7 +217,19 @@ frappe.ui.form.on('Material Request', {
|
||||
|
||||
make_purchase_order: function(frm) {
|
||||
frappe.prompt(
|
||||
{fieldname:'default_supplier', label: __('For Default Supplier (optional)'), fieldtype: 'Link', options: 'Supplier'},
|
||||
{
|
||||
label: __('For Default Supplier (optional)'),
|
||||
fieldname:'default_supplier',
|
||||
fieldtype: 'Link',
|
||||
options: 'Supplier',
|
||||
description: __('Select a Supplier from the Default Supplier List of the items below.'),
|
||||
get_query: () => {
|
||||
return {
|
||||
query: "erpnext.stock.doctype.material_request.material_request.get_default_supplier_query",
|
||||
filters: {'doc': frm.doc.name}
|
||||
}
|
||||
}
|
||||
},
|
||||
(values) => {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order",
|
||||
@@ -225,7 +237,8 @@ frappe.ui.form.on('Material Request', {
|
||||
args: { default_supplier: values.default_supplier },
|
||||
run_link_triggers: true
|
||||
});
|
||||
}
|
||||
},
|
||||
__('Enter Supplier')
|
||||
)
|
||||
},
|
||||
|
||||
|
||||
@@ -371,6 +371,18 @@ def get_material_requests_based_on_supplier(supplier):
|
||||
material_requests = []
|
||||
return material_requests, supplier_items
|
||||
|
||||
def get_default_supplier_query(doctype, txt, searchfield, start, page_len, filters):
|
||||
doc = frappe.get_doc("Material Request", filters.get("doc"))
|
||||
item_list = []
|
||||
for d in doc.items:
|
||||
item_list.append(d.item_code)
|
||||
|
||||
return frappe.db.sql("""select default_supplier
|
||||
from `tabItem Default`
|
||||
where parent in ({0}) and
|
||||
default_supplier IS NOT NULL
|
||||
""".format(', '.join(['%s']*len(item_list))),tuple(item_list))
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_supplier_quotation(source_name, target_doc=None):
|
||||
def postprocess(source, target_doc):
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
@@ -11,10 +13,13 @@
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "parent_item",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -39,13 +44,17 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "item_code",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -70,13 +79,17 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "item_name",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
@@ -100,13 +113,17 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_5",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
@@ -128,13 +145,17 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Text Editor",
|
||||
"hidden": 0,
|
||||
@@ -159,14 +180,18 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0,
|
||||
"width": "300px"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "section_break_6",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@@ -188,13 +213,17 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "warehouse",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -219,13 +248,17 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "target_warehouse",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -249,13 +282,17 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_9",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
@@ -277,13 +314,17 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "qty",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
@@ -307,13 +348,17 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "section_break_9",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@@ -335,13 +380,17 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "serial_no",
|
||||
"fieldtype": "Text",
|
||||
"hidden": 0,
|
||||
@@ -363,13 +412,17 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_11",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
@@ -391,13 +444,17 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "batch_no",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -420,13 +477,51 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "batch_no",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "actual_batch_qty",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Actual Batch Quantity",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "section_break_13",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@@ -448,13 +543,17 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 1,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "actual_qty",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
@@ -478,13 +577,17 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 1,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "projected_qty",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
@@ -508,13 +611,17 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_16",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
@@ -536,13 +643,17 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "uom",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@@ -567,13 +678,17 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 1,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "page_break",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
@@ -597,13 +712,17 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "prevdoc_doctype",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
@@ -627,13 +746,17 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "parent_detail_docname",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
@@ -657,20 +780,21 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 1,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-02-20 13:27:37.569945",
|
||||
"modified": "2019-11-27 11:18:18.598759",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Packed Item",
|
||||
@@ -681,5 +805,6 @@
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
}
|
||||
@@ -7,7 +7,6 @@ from __future__ import unicode_literals
|
||||
import frappe, json
|
||||
from frappe.utils import cstr, flt
|
||||
from erpnext.stock.get_item_details import get_item_details
|
||||
|
||||
from frappe.model.document import Document
|
||||
|
||||
class PackedItem(Document):
|
||||
@@ -31,8 +30,11 @@ def get_bin_qty(item, warehouse):
|
||||
return det and det[0] or frappe._dict()
|
||||
|
||||
def update_packing_list_item(doc, packing_item_code, qty, main_item_row, description):
|
||||
if doc.amended_from:
|
||||
old_packed_items_map = get_old_packed_item_details(doc.packed_items)
|
||||
else:
|
||||
old_packed_items_map = False
|
||||
item = get_packing_item_details(packing_item_code, doc.company)
|
||||
|
||||
# check if exists
|
||||
exists = 0
|
||||
for d in doc.get("packed_items"):
|
||||
@@ -52,11 +54,10 @@ def update_packing_list_item(doc, packing_item_code, qty, main_item_row, descrip
|
||||
pi.uom = item.stock_uom
|
||||
pi.qty = flt(qty)
|
||||
pi.description = description
|
||||
if not pi.warehouse:
|
||||
if not pi.warehouse and not doc.amended_from:
|
||||
pi.warehouse = (main_item_row.warehouse if ((doc.get('is_pos')
|
||||
or not item.default_warehouse) and main_item_row.warehouse) else item.default_warehouse)
|
||||
|
||||
if not pi.batch_no:
|
||||
if not pi.batch_no and not doc.amended_from:
|
||||
pi.batch_no = cstr(main_item_row.get("batch_no"))
|
||||
if not pi.target_warehouse:
|
||||
pi.target_warehouse = main_item_row.get("target_warehouse")
|
||||
@@ -64,9 +65,13 @@ def update_packing_list_item(doc, packing_item_code, qty, main_item_row, descrip
|
||||
pi.actual_qty = flt(bin.get("actual_qty"))
|
||||
pi.projected_qty = flt(bin.get("projected_qty"))
|
||||
|
||||
if old_packed_items_map and old_packed_items_map.get((packing_item_code, main_item_row.item_code)):
|
||||
pi.batch_no = old_packed_items_map.get((packing_item_code, main_item_row.item_code))[0].batch_no
|
||||
pi.serial_no = old_packed_items_map.get((packing_item_code, main_item_row.item_code))[0].serial_no
|
||||
pi.warehouse = old_packed_items_map.get((packing_item_code, main_item_row.item_code))[0].warehouse
|
||||
|
||||
def make_packing_list(doc):
|
||||
"""make packing list for Product Bundle item"""
|
||||
|
||||
if doc.get("_action") and doc._action == "update_after_submit": return
|
||||
|
||||
parent_items = []
|
||||
@@ -108,8 +113,14 @@ def get_items_from_product_bundle(args):
|
||||
"qty": flt(args["quantity"]) * flt(item.qty)
|
||||
})
|
||||
items.append(get_item_details(args))
|
||||
|
||||
|
||||
return items
|
||||
|
||||
|
||||
def on_doctype_update():
|
||||
frappe.db.add_index("Packed Item", ["item_code", "warehouse"])
|
||||
frappe.db.add_index("Packed Item", ["item_code", "warehouse"])
|
||||
|
||||
def get_old_packed_item_details(old_packed_items):
|
||||
old_packed_items_map = {}
|
||||
for items in old_packed_items:
|
||||
old_packed_items_map.setdefault((items.item_code ,items.parent_item), []).append(items.as_dict())
|
||||
return old_packed_items_map
|
||||
@@ -27,6 +27,12 @@ frappe.ui.form.on("Purchase Receipt", {
|
||||
}
|
||||
});
|
||||
|
||||
frm.set_query("taxes_and_charges", function() {
|
||||
return {
|
||||
filters: {'company': frm.doc.company }
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
onload: function(frm) {
|
||||
erpnext.queries.setup_queries(frm, "Warehouse", function() {
|
||||
|
||||
@@ -1945,7 +1945,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "other_charges_calculation",
|
||||
"fieldtype": "Text",
|
||||
"fieldtype": "Long Text",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
@@ -3708,7 +3708,7 @@
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2018-11-02 19:59:01.423485",
|
||||
"modified": "2020-04-16 19:06:51.546358",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Purchase Receipt",
|
||||
|
||||
@@ -227,7 +227,9 @@ class StockEntry(StockController):
|
||||
|
||||
for d in self.get("items"):
|
||||
if not d.expense_account:
|
||||
frappe.throw(_("Please enter Difference Account"))
|
||||
frappe.throw(_("Please enter <b>Difference Account</b> or set default <b>Stock Adjustment Account</b> for company {0}")
|
||||
.format(frappe.bold(self.company)))
|
||||
|
||||
elif self.is_opening == "Yes" and frappe.db.get_value("Account", d.expense_account, "report_type") == "Profit and Loss":
|
||||
frappe.throw(_("Difference Account must be a Asset/Liability type account, since this Stock Entry is an Opening Entry"), OpeningEntryAccountError)
|
||||
|
||||
@@ -346,7 +348,7 @@ class StockEntry(StockController):
|
||||
elif d.t_warehouse and not d.basic_rate:
|
||||
d.basic_rate = get_valuation_rate(d.item_code, d.t_warehouse,
|
||||
self.doctype, d.name, d.allow_zero_valuation_rate,
|
||||
currency=erpnext.get_company_currency(self.company))
|
||||
currency=erpnext.get_company_currency(self.company), company=self.company)
|
||||
|
||||
def set_actual_qty(self):
|
||||
allow_negative_stock = cint(frappe.db.get_value("Stock Settings", None, "allow_negative_stock"))
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,15 @@
|
||||
|
||||
frappe.ui.form.on('Stock Settings', {
|
||||
refresh: function(frm) {
|
||||
let filters = function() {
|
||||
return {
|
||||
filters : {
|
||||
is_group : 0
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
frm.set_query("default_warehouse", filters);
|
||||
frm.set_query("sample_retention_warehouse", filters);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -30,9 +30,17 @@ class StockSettings(Document):
|
||||
frappe.make_property_setter({'fieldname': name, 'property': 'hidden',
|
||||
'value': 0 if self.show_barcode_field else 1})
|
||||
|
||||
self.validate_warehouses()
|
||||
self.cant_change_valuation_method()
|
||||
self.validate_clean_description_html()
|
||||
|
||||
def validate_warehouses(self):
|
||||
warehouse_fields = ["default_warehouse", "sample_retention_warehouse"]
|
||||
for field in warehouse_fields:
|
||||
if frappe.db.get_value("Warehouse", self.get(field), "is_group"):
|
||||
frappe.throw(_("Group Warehouses cannot be used in transactions. Please change the value of {0}") \
|
||||
.format(frappe.bold(self.meta.get_field(field).label)), title =_("Incorrect Warehouse"))
|
||||
|
||||
def cant_change_valuation_method(self):
|
||||
db_valuation_method = frappe.db.get_single_value("Stock Settings", "valuation_method")
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ def execute(filters=None):
|
||||
|
||||
data = []
|
||||
for item in items:
|
||||
total_outgoing = consumed_item_map.get(item.name, 0) + delivered_item_map.get(item.name,0)
|
||||
total_outgoing = flt(consumed_item_map.get(item.name, 0)) + flt(delivered_item_map.get(item.name,0))
|
||||
avg_daily_outgoing = flt(total_outgoing / diff, float_preceision)
|
||||
reorder_level = (avg_daily_outgoing * flt(item.lead_time_days)) + flt(item.safety_stock)
|
||||
|
||||
@@ -55,18 +55,20 @@ def get_item_info(filters):
|
||||
|
||||
|
||||
def get_consumed_items(condition):
|
||||
cn_items = frappe.db.sql("""select se_item.item_code,
|
||||
sum(se_item.transfer_qty) as 'consume_qty'
|
||||
from `tabStock Entry` se, `tabStock Entry Detail` se_item
|
||||
where se.name = se_item.parent and se.docstatus = 1
|
||||
and (ifnull(se_item.t_warehouse, '') = '' or se.purpose = 'Subcontract') %s
|
||||
group by se_item.item_code""" % (condition), as_dict=1)
|
||||
consumed_items = frappe.db.sql("""
|
||||
select item_code, abs(sum(actual_qty)) as consumed_qty
|
||||
from `tabStock Ledger Entry`
|
||||
where actual_qty < 0
|
||||
and voucher_type not in ('Delivery Note', 'Sales Invoice')
|
||||
%s
|
||||
group by item_code
|
||||
""" % condition, as_dict=1)
|
||||
|
||||
cn_items_map = {}
|
||||
for item in cn_items:
|
||||
cn_items_map.setdefault(item.item_code, item.consume_qty)
|
||||
consumed_items_map = {}
|
||||
for item in consumed_items:
|
||||
consumed_items_map.setdefault(item.item_code, item.consumed_qty)
|
||||
|
||||
return cn_items_map
|
||||
return consumed_items_map
|
||||
|
||||
def get_delivered_items(condition):
|
||||
dn_items = frappe.db.sql("""select dn_item.item_code, sum(dn_item.stock_qty) as dn_qty
|
||||
|
||||
@@ -233,7 +233,7 @@ def get_item_details(items, sle, filters):
|
||||
`tabItem` item
|
||||
{cf_join}
|
||||
where
|
||||
item.name in ({item_codes}) and ifnull(item.disabled, 0) = 0
|
||||
item.name in ({item_codes})
|
||||
""".format(cf_field=cf_field, cf_join=cf_join, item_codes=item_codes), as_dict=1)
|
||||
|
||||
for item in res:
|
||||
@@ -261,7 +261,7 @@ def validate_filters(filters):
|
||||
if not (filters.get("item_code") or filters.get("warehouse")):
|
||||
sle_count = flt(frappe.db.sql("""select count(name) from `tabStock Ledger Entry`""")[0][0])
|
||||
if sle_count > 500000:
|
||||
frappe.throw(_("Please set filter based on Item or Warehouse"))
|
||||
frappe.throw(_("Please set filter based on Item or Warehouse due to a large amount of entries."))
|
||||
|
||||
def get_variants_attributes():
|
||||
'''Return all item variant attributes.'''
|
||||
|
||||
@@ -19,10 +19,26 @@ def execute(filters=None):
|
||||
if opening_row:
|
||||
data.append(opening_row)
|
||||
|
||||
actual_qty = stock_value = 0
|
||||
|
||||
for sle in sl_entries:
|
||||
item_detail = item_details[sle.item_code]
|
||||
|
||||
sle.update(item_detail)
|
||||
|
||||
if filters.get("batch_no"):
|
||||
actual_qty += sle.actual_qty
|
||||
stock_value += sle.stock_value_difference
|
||||
|
||||
if sle.voucher_type == 'Stock Reconciliation':
|
||||
actual_qty = sle.qty_after_transaction
|
||||
stock_value = sle.stock_value
|
||||
|
||||
sle.update({
|
||||
"qty_after_transaction": actual_qty,
|
||||
"stock_value": stock_value
|
||||
})
|
||||
|
||||
data.append(sle)
|
||||
|
||||
if include_uom:
|
||||
@@ -67,7 +83,7 @@ def get_stock_ledger_entries(filters, items):
|
||||
|
||||
return frappe.db.sql("""select concat_ws(" ", posting_date, posting_time) as date,
|
||||
item_code, warehouse, actual_qty, qty_after_transaction, incoming_rate, valuation_rate,
|
||||
stock_value, voucher_type, voucher_no, batch_no, serial_no, company, project
|
||||
stock_value, voucher_type, voucher_no, batch_no, serial_no, company, project, stock_value_difference
|
||||
from `tabStock Ledger Entry` sle
|
||||
where company = %(company)s and
|
||||
posting_date between %(from_date)s and %(to_date)s
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
frappe
|
||||
unidecode
|
||||
pygithub
|
||||
googlemaps
|
||||
python-stdnum
|
||||
braintree
|
||||
gocardless_pro
|
||||
woocommerce
|
||||
pandas
|
||||
plaid-python
|
||||
Unidecode==1.1.1
|
||||
PyGithub==1.45
|
||||
googlemaps==4.2.0
|
||||
python-stdnum==1.13
|
||||
braintree==3.59.0;python_version<"3.6"
|
||||
braintree==4.0.0;python_version>="3.6"
|
||||
gocardless-pro==1.16.0
|
||||
WooCommerce==2.1.1
|
||||
pandas==0.24.2
|
||||
plaid-python==3.7.0
|
||||
|
||||
Reference in New Issue
Block a user