Compare commits
128 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d12a4f5e8c | ||
|
|
ad65be8250 | ||
|
|
ae30026005 | ||
|
|
54c4240d9c | ||
|
|
79683d0871 | ||
|
|
a6d1876958 | ||
|
|
346928f2bc | ||
|
|
310d238d17 | ||
|
|
5e25731188 | ||
|
|
83ca262e38 | ||
|
|
8a2e6f427b | ||
|
|
8371c1c4cd | ||
|
|
361e7f6ddc | ||
|
|
798fd3484f | ||
|
|
22cedeb006 | ||
|
|
e3c117e32c | ||
|
|
68a8b0c2a9 | ||
|
|
307543f968 | ||
|
|
6681b0d2aa | ||
|
|
54d9c9eaf4 | ||
|
|
9b11d9b45d | ||
|
|
cca55ddc33 | ||
|
|
1c68509426 | ||
|
|
1e05077b1f | ||
|
|
b81244342f | ||
|
|
8e92250798 | ||
|
|
d20ec25c92 | ||
|
|
25bcb14c1d | ||
|
|
f6149f1507 | ||
|
|
2f3585f949 | ||
|
|
ed8ad9cfee | ||
|
|
3a2727c9eb | ||
|
|
16d92e7270 | ||
|
|
8c7eb444ef | ||
|
|
9a0efc7710 | ||
|
|
3ddfce4f17 | ||
|
|
a236f4e586 | ||
|
|
0b62c6ebd4 | ||
|
|
40ca4c3bbb | ||
|
|
c454dc7af5 | ||
|
|
994cef5ee3 | ||
|
|
185762aeeb | ||
|
|
1b32d913a2 | ||
|
|
64f29f819a | ||
|
|
2efe05c1ce | ||
|
|
17c675547d | ||
|
|
a220e96867 | ||
|
|
e471b02172 | ||
|
|
19f90e984e | ||
|
|
b5608f9b14 | ||
|
|
5adce495aa | ||
|
|
66272a168d | ||
|
|
2192c244c0 | ||
|
|
141c244ece | ||
|
|
a57b020620 | ||
|
|
d1fda1ff2b | ||
|
|
b9d0e7622a | ||
|
|
2f9703c20e | ||
|
|
46b6d4ea47 | ||
|
|
417145bec5 | ||
|
|
1ff1368280 | ||
|
|
768a888bf2 | ||
|
|
8037a0e3d5 | ||
|
|
0b665ac791 | ||
|
|
87ad6d074a | ||
|
|
95108ac80b | ||
|
|
9b9777be3f | ||
|
|
075b299673 | ||
|
|
e0271a8331 | ||
|
|
236f7aac7f | ||
|
|
29ee263093 | ||
|
|
4782e8b751 | ||
|
|
b58979fd3e | ||
|
|
9365641777 | ||
|
|
5e9d72d57b | ||
|
|
0d230afd22 | ||
|
|
a906b3f11c | ||
|
|
aa6f00c403 | ||
|
|
d681c88d79 | ||
|
|
fc11fce990 | ||
|
|
faf51d91b6 | ||
|
|
08a42e00ae | ||
|
|
549a2827e5 | ||
|
|
9264313f0e | ||
|
|
8013d1813a | ||
|
|
ffc807cd57 | ||
|
|
ba6559c2e9 | ||
|
|
7eea52d4e9 | ||
|
|
93a990f006 | ||
|
|
2861955632 | ||
|
|
099163b16d | ||
|
|
0d114b4c31 | ||
|
|
fcf34dc570 | ||
|
|
6f038bc1f3 | ||
|
|
9300013acc | ||
|
|
8d8cba7faa | ||
|
|
2d132e32aa | ||
|
|
2e47654f43 | ||
|
|
9bfa0ab7eb | ||
|
|
17ddd8f389 | ||
|
|
c469f2c954 | ||
|
|
731efe3a95 | ||
|
|
2c892c7e7f | ||
|
|
e6b5843a1f | ||
|
|
31334328ed | ||
|
|
0d6db6c42c | ||
|
|
ed0422a8d9 | ||
|
|
d991c8666c | ||
|
|
85d1c07519 | ||
|
|
04ab7dfd2f | ||
|
|
eae30e5642 | ||
|
|
065302298f | ||
|
|
9f84a99158 | ||
|
|
b15d999147 | ||
|
|
4b0381c820 | ||
|
|
f0b4562a95 | ||
|
|
cc8b2b2fdb | ||
|
|
67a3e65f08 | ||
|
|
dc89916aa9 | ||
|
|
9d9cb8b7b1 | ||
|
|
e7c0188732 | ||
|
|
34b1dba9aa | ||
|
|
c040015bb5 | ||
|
|
b66edd19ca | ||
|
|
b596deb57d | ||
|
|
79fddcfac1 | ||
|
|
3d5bdeb90d | ||
|
|
d07c041125 |
@@ -38,6 +38,14 @@ The ERPNext code is licensed as GNU General Public License (v3) and the Document
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
1. [Pull Request Requirements](https://github.com/frappe/erpnext/wiki/Pull-Request-Guidelines)
|
||||||
|
1. [Translations](https://translate.erpnext.com)
|
||||||
|
1. [Chart of Accounts](https://charts.erpnext.com)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Logo and Trademark
|
## Logo and Trademark
|
||||||
|
|
||||||
The brand name ERPNext and the logo are trademarks of Frappe Technologies Pvt. Ltd.
|
The brand name ERPNext and the logo are trademarks of Frappe Technologies Pvt. Ltd.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
|
|
||||||
__version__ = '8.0.2'
|
__version__ = '8.0.12'
|
||||||
|
|
||||||
def get_default_company(user=None):
|
def get_default_company(user=None):
|
||||||
'''Get default company for user'''
|
'''Get default company for user'''
|
||||||
@@ -25,6 +25,14 @@ def get_default_currency():
|
|||||||
if company:
|
if company:
|
||||||
return frappe.db.get_value('Company', company, 'default_currency')
|
return frappe.db.get_value('Company', company, 'default_currency')
|
||||||
|
|
||||||
|
def get_company_currency(company):
|
||||||
|
'''Returns the default company currency'''
|
||||||
|
if not frappe.flags.company_currency:
|
||||||
|
frappe.flags.company_currency = {}
|
||||||
|
if not company in frappe.flags.company_currency:
|
||||||
|
frappe.flags.company_currency[company] = frappe.db.get_value('Company', company, 'default_currency')
|
||||||
|
return frappe.flags.company_currency[company]
|
||||||
|
|
||||||
def set_perpetual_inventory(enable=1):
|
def set_perpetual_inventory(enable=1):
|
||||||
accounts_settings = frappe.get_doc("Accounts Settings")
|
accounts_settings = frappe.get_doc("Accounts Settings")
|
||||||
accounts_settings.auto_accounting_for_stock = enable
|
accounts_settings.auto_accounting_for_stock = enable
|
||||||
|
|||||||
@@ -2,13 +2,12 @@
|
|||||||
# License: GNU General Public License v3. See license.txt
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe, erpnext
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import flt, fmt_money, getdate, formatdate
|
from frappe.utils import flt, fmt_money, getdate, formatdate
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from erpnext.accounts.party import validate_party_gle_currency, validate_party_frozen_disabled
|
from erpnext.accounts.party import validate_party_gle_currency, validate_party_frozen_disabled
|
||||||
from erpnext.accounts.utils import get_account_currency
|
from erpnext.accounts.utils import get_account_currency
|
||||||
from erpnext.setup.doctype.company.company import get_company_currency
|
|
||||||
from erpnext.accounts.utils import get_fiscal_year
|
from erpnext.accounts.utils import get_fiscal_year
|
||||||
from erpnext.exceptions import InvalidAccountCurrency
|
from erpnext.exceptions import InvalidAccountCurrency
|
||||||
|
|
||||||
@@ -19,7 +18,7 @@ class GLEntry(Document):
|
|||||||
self.flags.ignore_submit_comment = True
|
self.flags.ignore_submit_comment = True
|
||||||
self.check_mandatory()
|
self.check_mandatory()
|
||||||
self.validate_and_set_fiscal_year()
|
self.validate_and_set_fiscal_year()
|
||||||
|
|
||||||
if not self.flags.from_repost:
|
if not self.flags.from_repost:
|
||||||
self.pl_must_have_cost_center()
|
self.pl_must_have_cost_center()
|
||||||
self.check_pl_account()
|
self.check_pl_account()
|
||||||
@@ -32,7 +31,7 @@ class GLEntry(Document):
|
|||||||
if not from_repost:
|
if not from_repost:
|
||||||
self.validate_account_details(adv_adj)
|
self.validate_account_details(adv_adj)
|
||||||
check_freezing_date(self.posting_date, adv_adj)
|
check_freezing_date(self.posting_date, adv_adj)
|
||||||
|
|
||||||
validate_frozen_account(self.account, adv_adj)
|
validate_frozen_account(self.account, adv_adj)
|
||||||
validate_balance_type(self.account, adv_adj)
|
validate_balance_type(self.account, adv_adj)
|
||||||
|
|
||||||
@@ -56,7 +55,7 @@ class GLEntry(Document):
|
|||||||
elif account_type == "Payable":
|
elif account_type == "Payable":
|
||||||
frappe.throw(_("{0} {1}: Supplier is required against Payable account {2}")
|
frappe.throw(_("{0} {1}: Supplier is required against Payable account {2}")
|
||||||
.format(self.voucher_type, self.voucher_no, self.account))
|
.format(self.voucher_type, self.voucher_no, self.account))
|
||||||
|
|
||||||
# Zero value transaction is not allowed
|
# Zero value transaction is not allowed
|
||||||
if not (flt(self.debit) or flt(self.credit)):
|
if not (flt(self.debit) or flt(self.credit)):
|
||||||
frappe.throw(_("{0} {1}: Either debit or credit amount is required for {2}")
|
frappe.throw(_("{0} {1}: Either debit or credit amount is required for {2}")
|
||||||
@@ -116,7 +115,7 @@ class GLEntry(Document):
|
|||||||
validate_party_frozen_disabled(self.party_type, self.party)
|
validate_party_frozen_disabled(self.party_type, self.party)
|
||||||
|
|
||||||
def validate_currency(self):
|
def validate_currency(self):
|
||||||
company_currency = get_company_currency(self.company)
|
company_currency = erpnext.get_company_currency(self.company)
|
||||||
account_currency = get_account_currency(self.account)
|
account_currency = get_account_currency(self.account)
|
||||||
|
|
||||||
if not self.account_currency:
|
if not self.account_currency:
|
||||||
@@ -124,7 +123,7 @@ class GLEntry(Document):
|
|||||||
|
|
||||||
if account_currency != self.account_currency:
|
if account_currency != self.account_currency:
|
||||||
frappe.throw(_("{0} {1}: Accounting Entry for {2} can only be made in currency: {3}")
|
frappe.throw(_("{0} {1}: Accounting Entry for {2} can only be made in currency: {3}")
|
||||||
.format(self.voucher_type, self.voucher_no, self.account,
|
.format(self.voucher_type, self.voucher_no, self.account,
|
||||||
(account_currency or company_currency)), InvalidAccountCurrency)
|
(account_currency or company_currency)), InvalidAccountCurrency)
|
||||||
|
|
||||||
if self.party_type and self.party:
|
if self.party_type and self.party:
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"allow_copy": 0,
|
||||||
|
"allow_guest_to_view": 0,
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"allow_rename": 0,
|
"allow_rename": 0,
|
||||||
"autoname": "naming_series:",
|
"autoname": "naming_series:",
|
||||||
@@ -1325,19 +1326,19 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"has_web_view": 0,
|
||||||
"hide_heading": 0,
|
"hide_heading": 0,
|
||||||
"hide_toolbar": 0,
|
"hide_toolbar": 0,
|
||||||
"icon": "fa fa-file-text",
|
"icon": "fa fa-file-text",
|
||||||
"idx": 176,
|
"idx": 176,
|
||||||
"image_view": 0,
|
"image_view": 0,
|
||||||
"in_create": 0,
|
"in_create": 0,
|
||||||
"in_dialog": 0,
|
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"menu_index": 0,
|
"menu_index": 0,
|
||||||
"modified": "2017-02-17 16:17:48.991851",
|
"modified": "2017-04-10 12:07:44.599804",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Journal Entry",
|
"name": "Journal Entry",
|
||||||
@@ -1412,6 +1413,6 @@
|
|||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"title_field": "title",
|
"title_field": "title",
|
||||||
"track_changes": 0,
|
"track_changes": 1,
|
||||||
"track_seen": 0
|
"track_seen": 0
|
||||||
}
|
}
|
||||||
@@ -2,12 +2,11 @@
|
|||||||
# License: GNU General Public License v3. See license.txt
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe, json
|
import frappe, erpnext, json
|
||||||
from frappe.utils import cstr, flt, fmt_money, formatdate
|
from frappe.utils import cstr, flt, fmt_money, formatdate
|
||||||
from frappe import msgprint, _, scrub
|
from frappe import msgprint, _, scrub
|
||||||
from erpnext.controllers.accounts_controller import AccountsController
|
from erpnext.controllers.accounts_controller import AccountsController
|
||||||
from erpnext.accounts.utils import get_balance_on, get_account_currency
|
from erpnext.accounts.utils import get_balance_on, get_account_currency
|
||||||
from erpnext.setup.utils import get_company_currency
|
|
||||||
from erpnext.accounts.party import get_party_account
|
from erpnext.accounts.party import get_party_account
|
||||||
from erpnext.hr.doctype.expense_claim.expense_claim import update_reimbursed_amount
|
from erpnext.hr.doctype.expense_claim.expense_claim import update_reimbursed_amount
|
||||||
from erpnext.hr.doctype.employee_loan.employee_loan import update_disbursement_status
|
from erpnext.hr.doctype.employee_loan.employee_loan import update_disbursement_status
|
||||||
@@ -325,11 +324,11 @@ class JournalEntry(AccountsController):
|
|||||||
if d.account_currency == self.company_currency:
|
if d.account_currency == self.company_currency:
|
||||||
d.exchange_rate = 1
|
d.exchange_rate = 1
|
||||||
elif not d.exchange_rate or d.exchange_rate == 1 or \
|
elif not d.exchange_rate or d.exchange_rate == 1 or \
|
||||||
(d.reference_type in ("Sales Invoice", "Purchase Invoice")
|
(d.reference_type in ("Sales Invoice", "Purchase Invoice")
|
||||||
and d.reference_name and self.posting_date):
|
and d.reference_name and self.posting_date):
|
||||||
|
|
||||||
# Modified to include the posting date for which to retreive the exchange rate
|
# Modified to include the posting date for which to retreive the exchange rate
|
||||||
d.exchange_rate = get_exchange_rate(self.posting_date, d.account, d.account_currency,
|
d.exchange_rate = get_exchange_rate(self.posting_date, d.account, d.account_currency,
|
||||||
self.company, d.reference_type, d.reference_name, d.debit, d.credit, d.exchange_rate)
|
self.company, d.reference_type, d.reference_name, d.debit, d.credit, d.exchange_rate)
|
||||||
|
|
||||||
if not d.exchange_rate:
|
if not d.exchange_rate:
|
||||||
@@ -656,7 +655,7 @@ def get_payment_entry(ref_doc, args):
|
|||||||
if args.get("party_account"):
|
if args.get("party_account"):
|
||||||
# Modified to include the posting date for which the exchange rate is required.
|
# Modified to include the posting date for which the exchange rate is required.
|
||||||
# Assumed to be the posting date in the reference document
|
# Assumed to be the posting date in the reference document
|
||||||
exchange_rate = get_exchange_rate(ref_doc.get("posting_date") or ref_doc.get("transaction_date"),
|
exchange_rate = get_exchange_rate(ref_doc.get("posting_date") or ref_doc.get("transaction_date"),
|
||||||
args.get("party_account"), args.get("party_account_currency"),
|
args.get("party_account"), args.get("party_account_currency"),
|
||||||
ref_doc.company, ref_doc.doctype, ref_doc.name)
|
ref_doc.company, ref_doc.doctype, ref_doc.name)
|
||||||
|
|
||||||
@@ -692,8 +691,8 @@ def get_payment_entry(ref_doc, args):
|
|||||||
bank_row.update(bank_account)
|
bank_row.update(bank_account)
|
||||||
# Modified to include the posting date for which the exchange rate is required.
|
# Modified to include the posting date for which the exchange rate is required.
|
||||||
# Assumed to be the posting date of the reference date
|
# Assumed to be the posting date of the reference date
|
||||||
bank_row.exchange_rate = get_exchange_rate(ref_doc.get("posting_date")
|
bank_row.exchange_rate = get_exchange_rate(ref_doc.get("posting_date")
|
||||||
or ref_doc.get("transaction_date"), bank_account["account"],
|
or ref_doc.get("transaction_date"), bank_account["account"],
|
||||||
bank_account["account_currency"], ref_doc.company)
|
bank_account["account_currency"], ref_doc.company)
|
||||||
|
|
||||||
bank_row.cost_center = cost_center
|
bank_row.cost_center = cost_center
|
||||||
@@ -746,7 +745,7 @@ def get_outstanding(args):
|
|||||||
if isinstance(args, basestring):
|
if isinstance(args, basestring):
|
||||||
args = json.loads(args)
|
args = json.loads(args)
|
||||||
|
|
||||||
company_currency = get_company_currency(args.get("company"))
|
company_currency = erpnext.get_company_currency(args.get("company"))
|
||||||
|
|
||||||
if args.get("doctype") == "Journal Entry":
|
if args.get("doctype") == "Journal Entry":
|
||||||
condition = " and party=%(party)s" if args.get("party") else ""
|
condition = " and party=%(party)s" if args.get("party") else ""
|
||||||
@@ -805,7 +804,7 @@ def get_account_balance_and_party_type(account, date, company, debit=None, credi
|
|||||||
if not frappe.has_permission("Account"):
|
if not frappe.has_permission("Account"):
|
||||||
frappe.msgprint(_("No Permission"), raise_exception=1)
|
frappe.msgprint(_("No Permission"), raise_exception=1)
|
||||||
|
|
||||||
company_currency = get_company_currency(company)
|
company_currency = erpnext.get_company_currency(company)
|
||||||
account_details = frappe.db.get_value("Account", account, ["account_type", "account_currency"], as_dict=1)
|
account_details = frappe.db.get_value("Account", account, ["account_type", "account_currency"], as_dict=1)
|
||||||
|
|
||||||
if not account_details:
|
if not account_details:
|
||||||
@@ -853,7 +852,7 @@ def get_exchange_rate(posting_date, account=None, account_currency=None, company
|
|||||||
if not account_currency:
|
if not account_currency:
|
||||||
account_currency = account_details.account_currency
|
account_currency = account_details.account_currency
|
||||||
|
|
||||||
company_currency = get_company_currency(company)
|
company_currency = erpnext.get_company_currency(company)
|
||||||
|
|
||||||
if account_currency != company_currency:
|
if account_currency != company_currency:
|
||||||
if reference_type in ("Sales Invoice", "Purchase Invoice") and reference_name:
|
if reference_type in ("Sales Invoice", "Purchase Invoice") and reference_name:
|
||||||
|
|||||||
@@ -1675,7 +1675,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2017-03-14 17:12:48.816644",
|
"modified": "2017-04-10 12:06:22.176045",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Payment Entry",
|
"name": "Payment Entry",
|
||||||
@@ -1730,6 +1730,6 @@
|
|||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"title_field": "title",
|
"title_field": "title",
|
||||||
"track_changes": 0,
|
"track_changes": 1,
|
||||||
"track_seen": 0
|
"track_seen": 0
|
||||||
}
|
}
|
||||||
@@ -2,8 +2,7 @@
|
|||||||
// License: GNU General Public License v3. See license.txt
|
// License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
frappe.provide("erpnext.accounts");
|
frappe.provide("erpnext.accounts");
|
||||||
{% include 'erpnext/buying/doctype/purchase_common/purchase_common.js' %};
|
{% include 'erpnext/public/js/controllers/buying.js' %};
|
||||||
|
|
||||||
|
|
||||||
erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
|
erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
|
||||||
setup: function(doc) {
|
setup: function(doc) {
|
||||||
|
|||||||
@@ -3646,7 +3646,7 @@
|
|||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"menu_index": 0,
|
"menu_index": 0,
|
||||||
"modified": "2017-03-15 14:29:51.957287",
|
"modified": "2017-04-10 12:05:28.082020",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Purchase Invoice",
|
"name": "Purchase Invoice",
|
||||||
@@ -3762,6 +3762,6 @@
|
|||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"timeline_field": "supplier",
|
"timeline_field": "supplier",
|
||||||
"title_field": "title",
|
"title_field": "title",
|
||||||
"track_changes": 0,
|
"track_changes": 1,
|
||||||
"track_seen": 0
|
"track_seen": 0
|
||||||
}
|
}
|
||||||
@@ -2,10 +2,9 @@
|
|||||||
# License: GNU General Public License v3. See license.txt
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe, erpnext
|
||||||
from frappe.utils import cint, formatdate, flt, getdate
|
from frappe.utils import cint, formatdate, flt, getdate
|
||||||
from frappe import _, throw
|
from frappe import _, throw
|
||||||
from erpnext.setup.utils import get_company_currency
|
|
||||||
import frappe.defaults
|
import frappe.defaults
|
||||||
|
|
||||||
from erpnext.controllers.buying_controller import BuyingController
|
from erpnext.controllers.buying_controller import BuyingController
|
||||||
@@ -15,6 +14,7 @@ from erpnext.stock.doctype.purchase_receipt.purchase_receipt import update_bille
|
|||||||
from erpnext.controllers.stock_controller import get_warehouse_account
|
from erpnext.controllers.stock_controller import get_warehouse_account
|
||||||
from erpnext.accounts.general_ledger import make_gl_entries, merge_similar_entries, delete_gl_entries
|
from erpnext.accounts.general_ledger import make_gl_entries, merge_similar_entries, delete_gl_entries
|
||||||
from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
|
from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
|
||||||
|
from erpnext.buying.utils import check_for_closed_status
|
||||||
|
|
||||||
form_grid_templates = {
|
form_grid_templates = {
|
||||||
"items": "templates/form_grid/item_grid.html"
|
"items": "templates/form_grid/item_grid.html"
|
||||||
@@ -93,7 +93,7 @@ class PurchaseInvoice(BuyingController):
|
|||||||
super(PurchaseInvoice, self).set_missing_values(for_validate)
|
super(PurchaseInvoice, self).set_missing_values(for_validate)
|
||||||
|
|
||||||
def check_conversion_rate(self):
|
def check_conversion_rate(self):
|
||||||
default_currency = get_company_currency(self.company)
|
default_currency = erpnext.get_company_currency(self.company)
|
||||||
if not default_currency:
|
if not default_currency:
|
||||||
throw(_('Please enter default currency in Company Master'))
|
throw(_('Please enter default currency in Company Master'))
|
||||||
if (self.currency == default_currency and flt(self.conversion_rate) != 1.00) or not self.conversion_rate or (self.currency != default_currency and flt(self.conversion_rate) == 1.00):
|
if (self.currency == default_currency and flt(self.conversion_rate) != 1.00) or not self.conversion_rate or (self.currency != default_currency and flt(self.conversion_rate) == 1.00):
|
||||||
@@ -113,12 +113,11 @@ class PurchaseInvoice(BuyingController):
|
|||||||
|
|
||||||
def check_for_closed_status(self):
|
def check_for_closed_status(self):
|
||||||
check_list = []
|
check_list = []
|
||||||
pc_obj = frappe.get_doc('Purchase Common')
|
|
||||||
|
|
||||||
for d in self.get('items'):
|
for d in self.get('items'):
|
||||||
if d.purchase_order and not d.purchase_order in check_list and not d.purchase_receipt:
|
if d.purchase_order and not d.purchase_order in check_list and not d.purchase_receipt:
|
||||||
check_list.append(d.purchase_order)
|
check_list.append(d.purchase_order)
|
||||||
pc_obj.check_for_closed_status('Purchase Order', d.purchase_order)
|
check_for_closed_status('Purchase Order', d.purchase_order)
|
||||||
|
|
||||||
def validate_with_previous_doc(self):
|
def validate_with_previous_doc(self):
|
||||||
super(PurchaseInvoice, self).validate_with_previous_doc({
|
super(PurchaseInvoice, self).validate_with_previous_doc({
|
||||||
@@ -629,10 +628,12 @@ class PurchaseInvoice(BuyingController):
|
|||||||
pi = frappe.db.sql('''select name from `tabPurchase Invoice`
|
pi = frappe.db.sql('''select name from `tabPurchase Invoice`
|
||||||
where
|
where
|
||||||
bill_no = %(bill_no)s
|
bill_no = %(bill_no)s
|
||||||
|
and supplier = %(supplier)s
|
||||||
and name != %(name)s
|
and name != %(name)s
|
||||||
and docstatus < 2
|
and docstatus < 2
|
||||||
and posting_date between %(year_start_date)s and %(year_end_date)s''', {
|
and posting_date between %(year_start_date)s and %(year_end_date)s''', {
|
||||||
"bill_no": self.bill_no,
|
"bill_no": self.bill_no,
|
||||||
|
"supplier": self.supplier,
|
||||||
"name": self.name,
|
"name": self.name,
|
||||||
"year_start_date": fiscal_year.year_start_date,
|
"year_start_date": fiscal_year.year_start_date,
|
||||||
"year_end_date": fiscal_year.year_end_date
|
"year_end_date": fiscal_year.year_end_date
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"allow_copy": 0,
|
||||||
|
"allow_guest_to_view": 0,
|
||||||
"allow_import": 0,
|
"allow_import": 0,
|
||||||
"allow_rename": 0,
|
"allow_rename": 0,
|
||||||
"autoname": "hash",
|
"autoname": "hash",
|
||||||
@@ -335,6 +336,36 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"columns": 0,
|
||||||
|
"fieldname": "stock_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": "Stock 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": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
@@ -419,6 +450,35 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"columns": 0,
|
||||||
|
"fieldname": "stock_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": "Stock Qty",
|
||||||
|
"length": 0,
|
||||||
|
"no_copy": 0,
|
||||||
|
"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,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
@@ -1366,7 +1426,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fieldname": "is_sample_item",
|
"fieldname": "allow_zero_valuation_rate",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
@@ -1375,7 +1435,7 @@
|
|||||||
"in_global_search": 0,
|
"in_global_search": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"in_standard_filter": 0,
|
"in_standard_filter": 0,
|
||||||
"label": "Is Sample Item",
|
"label": "Allow Zero Valuation Rate",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
@@ -1869,17 +1929,17 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"has_web_view": 0,
|
||||||
"hide_heading": 0,
|
"hide_heading": 0,
|
||||||
"hide_toolbar": 0,
|
"hide_toolbar": 0,
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"image_view": 0,
|
"image_view": 0,
|
||||||
"in_create": 0,
|
"in_create": 0,
|
||||||
"in_dialog": 0,
|
|
||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2017-02-17 16:28:26.719053",
|
"modified": "2017-04-11 13:44:17.460674",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Purchase Invoice Item",
|
"name": "Purchase Invoice Item",
|
||||||
|
|||||||
@@ -182,6 +182,7 @@ def get_customers_address(customers):
|
|||||||
address_data = address[0]
|
address_data = address[0]
|
||||||
address_data.update({'full_name': data.customer_name})
|
address_data.update({'full_name': data.customer_name})
|
||||||
customer_address[data.name] = address_data
|
customer_address[data.name] = address_data
|
||||||
|
|
||||||
return customer_address
|
return customer_address
|
||||||
|
|
||||||
def get_child_nodes(group_type, root):
|
def get_child_nodes(group_type, root):
|
||||||
@@ -295,9 +296,9 @@ def make_invoice(doc_list={}, email_queue_list={}, customers_list={}):
|
|||||||
if not frappe.db.exists('Sales Invoice', {'offline_pos_name': name}):
|
if not frappe.db.exists('Sales Invoice', {'offline_pos_name': name}):
|
||||||
validate_records(doc)
|
validate_records(doc)
|
||||||
si_doc = frappe.new_doc('Sales Invoice')
|
si_doc = frappe.new_doc('Sales Invoice')
|
||||||
si_doc.due_date = doc.get('posting_date')
|
|
||||||
si_doc.offline_pos_name = name
|
si_doc.offline_pos_name = name
|
||||||
si_doc.update(doc)
|
si_doc.update(doc)
|
||||||
|
si_doc.due_date = doc.get('posting_date')
|
||||||
submit_invoice(si_doc, name, doc)
|
submit_invoice(si_doc, name, doc)
|
||||||
name_list.append(name)
|
name_list.append(name)
|
||||||
else:
|
else:
|
||||||
@@ -337,11 +338,14 @@ def add_customer(name):
|
|||||||
def make_address(args, customer):
|
def make_address(args, customer):
|
||||||
if not args.get('address_line1'): return
|
if not args.get('address_line1'): return
|
||||||
|
|
||||||
name = args.get('name') or get_customers_address(customer)[customer].get("name")
|
name = args.get('name')
|
||||||
|
|
||||||
|
if not name:
|
||||||
|
data = get_customers_address(customer)
|
||||||
|
name = data[customer].get('name') if data else None
|
||||||
|
|
||||||
if name:
|
if name:
|
||||||
address = frappe.get_doc('Address', name)
|
address = frappe.get_doc('Address', name)
|
||||||
frappe.errprint(address)
|
|
||||||
else:
|
else:
|
||||||
address = frappe.new_doc('Address')
|
address = frappe.new_doc('Address')
|
||||||
address.country = frappe.db.get_value('Company', args.get('company'), 'country')
|
address.country = frappe.db.get_value('Company', args.get('company'), 'country')
|
||||||
@@ -400,4 +404,5 @@ def save_invoice(e, si_doc, name):
|
|||||||
if not frappe.db.exists('Sales Invoice', {'offline_pos_name': name}):
|
if not frappe.db.exists('Sales Invoice', {'offline_pos_name': name}):
|
||||||
si_doc.docstatus = 0
|
si_doc.docstatus = 0
|
||||||
si_doc.flags.ignore_mandatory = True
|
si_doc.flags.ignore_mandatory = True
|
||||||
|
si_doc.due_date = si_doc.posting_date
|
||||||
si_doc.insert()
|
si_doc.insert()
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
"beta": 0,
|
"beta": 0,
|
||||||
"creation": "2013-05-24 19:29:05",
|
"creation": "2013-05-24 19:29:05",
|
||||||
"custom": 0,
|
"custom": 0,
|
||||||
"default_print_format": "Sample Print",
|
"default_print_format": "",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "",
|
"document_type": "",
|
||||||
@@ -4417,8 +4417,8 @@
|
|||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"menu_index": 0,
|
"menu_index": 0,
|
||||||
"modified": "2017-03-29 05:09:56.656338",
|
"modified": "2017-04-12 15:11:45.931485",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "faris@erpnext.com",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Sales Invoice",
|
"name": "Sales Invoice",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
@@ -4513,6 +4513,6 @@
|
|||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"timeline_field": "customer",
|
"timeline_field": "customer",
|
||||||
"title_field": "title",
|
"title_field": "title",
|
||||||
"track_changes": 0,
|
"track_changes": 1,
|
||||||
"track_seen": 0
|
"track_seen": 0
|
||||||
}
|
}
|
||||||
@@ -1552,7 +1552,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fieldname": "is_sample_item",
|
"fieldname": "allow_zero_valuation_rate",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
@@ -1561,7 +1561,7 @@
|
|||||||
"in_global_search": 0,
|
"in_global_search": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"in_standard_filter": 0,
|
"in_standard_filter": 0,
|
||||||
"label": "Is Sample Item",
|
"label": "Allow Zero Valuation Rate",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
@@ -2094,7 +2094,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2017-03-30 16:26:36.507924",
|
"modified": "2017-04-05 23:28:13.520429",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Sales Invoice Item",
|
"name": "Sales Invoice Item",
|
||||||
|
|||||||
@@ -4,11 +4,10 @@
|
|||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe, erpnext
|
||||||
from frappe import _, msgprint, throw
|
from frappe import _, msgprint, throw
|
||||||
from frappe.utils import flt, fmt_money
|
from frappe.utils import flt, fmt_money
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from erpnext.setup.utils import get_company_currency
|
|
||||||
|
|
||||||
class OverlappingConditionError(frappe.ValidationError): pass
|
class OverlappingConditionError(frappe.ValidationError): pass
|
||||||
class FromGreaterThanToError(frappe.ValidationError): pass
|
class FromGreaterThanToError(frappe.ValidationError): pass
|
||||||
@@ -77,7 +76,7 @@ class ShippingRule(Document):
|
|||||||
overlaps.append([d1, d2])
|
overlaps.append([d1, d2])
|
||||||
|
|
||||||
if overlaps:
|
if overlaps:
|
||||||
company_currency = get_company_currency(self.company)
|
company_currency = erpnext.get_company_currency(self.company)
|
||||||
msgprint(_("Overlapping conditions found between:"))
|
msgprint(_("Overlapping conditions found between:"))
|
||||||
messages = []
|
messages = []
|
||||||
for d1, d2 in overlaps:
|
for d1, d2 in overlaps:
|
||||||
|
|||||||
@@ -951,6 +951,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
|||||||
item_price: format_currency(me.price_list_data[obj.name], me.frm.doc.currency),
|
item_price: format_currency(me.price_list_data[obj.name], me.frm.doc.currency),
|
||||||
item_name: obj.name === obj.item_name ? "" : obj.item_name,
|
item_name: obj.name === obj.item_name ? "" : obj.item_name,
|
||||||
item_image: obj.image,
|
item_image: obj.image,
|
||||||
|
item_stock: __('Stock Qty') + ": " + me.get_actual_qty(obj),
|
||||||
color: frappe.get_palette(obj.item_name),
|
color: frappe.get_palette(obj.item_name),
|
||||||
abbr: frappe.get_abbr(obj.item_name)
|
abbr: frappe.get_abbr(obj.item_name)
|
||||||
})).tooltip().appendTo($wrap);
|
})).tooltip().appendTo($wrap);
|
||||||
@@ -1355,7 +1356,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
|||||||
discount_percentage: d.discount_percentage || 0.0,
|
discount_percentage: d.discount_percentage || 0.0,
|
||||||
actual_qty: me.actual_qty_dict[d.item_code] || 0.0,
|
actual_qty: me.actual_qty_dict[d.item_code] || 0.0,
|
||||||
projected_qty: d.projected_qty,
|
projected_qty: d.projected_qty,
|
||||||
rate: format_number(d.rate, me.frm.doc.currency),
|
rate: format_currency(d.rate, me.frm.doc.currency),
|
||||||
enabled: me.pos_profile_data["allow_user_to_edit_rate"] ? true : false,
|
enabled: me.pos_profile_data["allow_user_to_edit_rate"] ? true : false,
|
||||||
amount: format_currency(d.amount, me.frm.doc.currency),
|
amount: format_currency(d.amount, me.frm.doc.currency),
|
||||||
selected_class: (me.item_code == d.item_code) ? "active" : ""
|
selected_class: (me.item_code == d.item_code) ? "active" : ""
|
||||||
@@ -1856,4 +1857,4 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
|||||||
frappe.throw(__("LocalStorage is full , did not save"))
|
frappe.throw(__("LocalStorage is full , did not save"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -151,13 +151,6 @@ def set_account_and_due_date(party, account, party_type, company, posting_date,
|
|||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
|
|
||||||
def get_company_currency():
|
|
||||||
company_currency = frappe._dict()
|
|
||||||
for d in frappe.get_all("Company", fields=["name", "default_currency"]):
|
|
||||||
company_currency.setdefault(d.name, d.default_currency)
|
|
||||||
|
|
||||||
return company_currency
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_party_account(party_type, party, company):
|
def get_party_account(party_type, party, company):
|
||||||
"""Returns the account for the given `party`.
|
"""Returns the account for the given `party`.
|
||||||
@@ -348,7 +341,7 @@ def validate_party_frozen_disabled(party_type, party_name):
|
|||||||
|
|
||||||
elif party_type == "Employee":
|
elif party_type == "Employee":
|
||||||
if frappe.db.get_value("Employee", party_name, "status") == "Left":
|
if frappe.db.get_value("Employee", party_name, "status") == "Left":
|
||||||
frappe.msgprint(_("{0} {1} is not active").format(party_type, party_name), PartyDisabled, alert=True)
|
frappe.msgprint(_("{0} {1} is not active").format(party_type, party_name), alert=True)
|
||||||
|
|
||||||
def get_timeline_data(doctype, name):
|
def get_timeline_data(doctype, name):
|
||||||
'''returns timeline data for the past one year'''
|
'''returns timeline data for the past one year'''
|
||||||
|
|||||||
@@ -7,10 +7,10 @@
|
|||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "Print Format",
|
"doctype": "Print Format",
|
||||||
"font": "Default",
|
"font": "Default",
|
||||||
"html": "<style>\n\t.print-format table, .print-format tr, \n\t.print-format td, .print-format div, .print-format p {\n\t\tfont-family: Monospace;\n\t\tline-height: 200%;\n\t\tvertical-align: middle;\n\t}\n\t@media screen {\n\t\t.print-format {\n\t\t\twidth: 4in;\n\t\t\tpadding: 0.25in;\n\t\t\tmin-height: 8in;\n\t\t}\n\t}\n</style>\n\n<p class=\"text-center\">\n\t{{ company }}<br>\n\t{{ __(\"POS No : \") }}{{offline_pos_name}}<br>\n</p>\n<p>\n\t<b>{{ __(\"Date\") }}:</b> {{ dateutil.global_date_format(posting_date) }}<br>\n</p>\n\n<hr>\n<table class=\"table table-condensed cart no-border\">\n\t<thead>\n\t\t<tr>\n\t\t\t<th width=\"50%\">{{ __(\"Item\") }}</b></th>\n\t\t\t<th width=\"25%\" class=\"text-right\">{{ __(\"Qty\") }}</th>\n\t\t\t<th width=\"25%\" class=\"text-right\">{{ __(\"Amount\") }}</th>\n\t\t</tr>\n\t</thead>\n\t<tbody>\n\t\t{% for item in items %}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t{{ item.item_name }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">{{ format_number(item.qty, precision(\"difference\")) }}<br>@ {{ format_currency(item.rate, currency) }}</td>\n\t\t\t<td class=\"text-right\">{{ format_currency(item.amount, currency) }}</td>\n\t\t</tr>\n\t\t{% endfor %}\n\t</tbody>\n</table>\n\n<table class=\"table table-condensed no-border\">\n\t<tbody>\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ __(\"Net Total\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(total, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{% for row in taxes %}\n\t\t{% if not row.included_in_print_rate %}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ row.description }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(row.tax_amount, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{% endif %}\n\t\t{% endfor %}\n\t\t{% if discount_amount %}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t{{ __(\"Discount\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(discount_amount, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{% endif %}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ __(\"Grand Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(grand_total, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ __(\"Paid Amount\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(paid_amount, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t</tbody>\n</table>\n\n\n<hr>\n<p>{{ terms }}</p>\n<p class=\"text-center\">{{ __(\"Thank you, please visit again.\") }}</p>",
|
"html": "<style>\n\t.print-format table, .print-format tr, \n\t.print-format td, .print-format div, .print-format p {\n\t\tfont-family: Monospace;\n\t\tline-height: 200%;\n\t\tvertical-align: middle;\n\t}\n\t@media screen {\n\t\t.print-format {\n\t\t\twidth: 4in;\n\t\t\tpadding: 0.25in;\n\t\t\tmin-height: 8in;\n\t\t}\n\t}\n</style>\n\n<p class=\"text-center\">\n\t{{ company }}<br>\n\t{{ __(\"POS No : \") }}{{offline_pos_name}}<br>\n</p>\n<p>\n\t<b>{{ __(\"Date\") }}:</b> {{ dateutil.global_date_format(posting_date) }}<br>\n</p>\n\n<hr>\n<table class=\"table table-condensed cart no-border\">\n\t<thead>\n\t\t<tr>\n\t\t\t<th width=\"50%\">{{ __(\"Item\") }}</b></th>\n\t\t\t<th width=\"25%\" class=\"text-right\">{{ __(\"Qty\") }}</th>\n\t\t\t<th width=\"25%\" class=\"text-right\">{{ __(\"Amount\") }}</th>\n\t\t</tr>\n\t</thead>\n\t<tbody>\n\t\t{% for item in items %}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t{{ item.item_name }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">{{ format_number(item.qty, null,precision(\"difference\")) }}<br>@ {{ format_currency(item.rate, currency) }}</td>\n\t\t\t<td class=\"text-right\">{{ format_currency(item.amount, currency) }}</td>\n\t\t</tr>\n\t\t{% endfor %}\n\t</tbody>\n</table>\n\n<table class=\"table table-condensed no-border\">\n\t<tbody>\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ __(\"Net Total\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(total, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{% for row in taxes %}\n\t\t{% if not row.included_in_print_rate %}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ row.description }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(row.tax_amount, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{% endif %}\n\t\t{% endfor %}\n\t\t{% if discount_amount %}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t{{ __(\"Discount\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(discount_amount, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{% endif %}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ __(\"Grand Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(grand_total, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ __(\"Paid Amount\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(paid_amount, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t</tbody>\n</table>\n\n\n<hr>\n<p>{{ terms }}</p>\n<p class=\"text-center\">{{ __(\"Thank you, please visit again.\") }}</p>",
|
||||||
"idx": 0,
|
"idx": 0,
|
||||||
"line_breaks": 0,
|
"line_breaks": 0,
|
||||||
"modified": "2017-01-12 14:56:12.571032",
|
"modified": "2017-04-17 12:12:00.153763",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Point of Sale",
|
"name": "Point of Sale",
|
||||||
|
|||||||
@@ -66,7 +66,8 @@ def set_account_currency(filters):
|
|||||||
if gle_currency:
|
if gle_currency:
|
||||||
account_currency = gle_currency
|
account_currency = gle_currency
|
||||||
else:
|
else:
|
||||||
account_currency = frappe.db.get_value(filters.party_type, filters.party, "default_currency")
|
account_currency = None if filters.party_type == "Employee" else \
|
||||||
|
frappe.db.get_value(filters.party_type, filters.party, "default_currency")
|
||||||
|
|
||||||
filters["account_currency"] = account_currency or filters.company_currency
|
filters["account_currency"] = account_currency or filters.company_currency
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ from frappe.utils import flt
|
|||||||
|
|
||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
if not filters: filters = frappe._dict()
|
if not filters: filters = frappe._dict()
|
||||||
company_currency = frappe.db.get_value("Company", filters.company, "default_currency")
|
filters.currency = frappe.db.get_value("Company", filters.company, "default_currency")
|
||||||
|
|
||||||
gross_profit_data = GrossProfitGenerator(filters)
|
gross_profit_data = GrossProfitGenerator(filters)
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ def execute(filters=None):
|
|||||||
for col in group_wise_columns.get(scrub(filters.group_by)):
|
for col in group_wise_columns.get(scrub(filters.group_by)):
|
||||||
row.append(src.get(col))
|
row.append(src.get(col))
|
||||||
|
|
||||||
row.append(company_currency)
|
row.append(filters.currency)
|
||||||
data.append(row)
|
data.append(row)
|
||||||
|
|
||||||
return columns, data
|
return columns, data
|
||||||
@@ -218,14 +218,18 @@ class GrossProfitGenerator(object):
|
|||||||
def get_average_buying_rate(self, row, item_code):
|
def get_average_buying_rate(self, row, item_code):
|
||||||
if not item_code in self.average_buying_rate:
|
if not item_code in self.average_buying_rate:
|
||||||
if item_code in self.non_stock_items:
|
if item_code in self.non_stock_items:
|
||||||
self.average_buying_rate[item_code] = flt(frappe.db.sql("""select sum(base_net_amount) / sum(qty * conversion_factor)
|
self.average_buying_rate[item_code] = flt(frappe.db.sql("""
|
||||||
|
select sum(base_net_amount) / sum(qty * conversion_factor)
|
||||||
from `tabPurchase Invoice Item`
|
from `tabPurchase Invoice Item`
|
||||||
where item_code = %s and docstatus=1""", item_code)[0][0])
|
where item_code = %s and docstatus=1""", item_code)[0][0])
|
||||||
else:
|
else:
|
||||||
average_buying_rate = get_incoming_rate(row)
|
average_buying_rate = get_incoming_rate(row)
|
||||||
if not average_buying_rate:
|
if not average_buying_rate:
|
||||||
average_buying_rate = get_valuation_rate(item_code, row.warehouse, allow_zero_rate=True)
|
average_buying_rate = get_valuation_rate(item_code, row.warehouse,
|
||||||
self.average_buying_rate[item_code] = average_buying_rate
|
row.parenttype, row.parent, allow_zero_rate=True,
|
||||||
|
currency=self.filters.currency)
|
||||||
|
|
||||||
|
self.average_buying_rate[item_code] = flt(average_buying_rate)
|
||||||
|
|
||||||
return self.average_buying_rate[item_code]
|
return self.average_buying_rate[item_code]
|
||||||
|
|
||||||
@@ -235,7 +239,7 @@ class GrossProfitGenerator(object):
|
|||||||
select (a.base_rate / a.conversion_factor)
|
select (a.base_rate / a.conversion_factor)
|
||||||
from `tabPurchase Invoice Item` a
|
from `tabPurchase Invoice Item` a
|
||||||
where a.item_code = %s and a.docstatus=1
|
where a.item_code = %s and a.docstatus=1
|
||||||
and modified <= %s
|
and modified <= %s
|
||||||
order by a.modified desc limit 1""", (item_code,self.filters.to_date))
|
order by a.modified desc limit 1""", (item_code,self.filters.to_date))
|
||||||
else:
|
else:
|
||||||
last_purchase_rate = frappe.db.sql("""
|
last_purchase_rate = frappe.db.sql("""
|
||||||
@@ -253,7 +257,7 @@ class GrossProfitGenerator(object):
|
|||||||
conditions += " and posting_date >= %(from_date)s"
|
conditions += " and posting_date >= %(from_date)s"
|
||||||
if self.filters.to_date:
|
if self.filters.to_date:
|
||||||
conditions += " and posting_date <= %(to_date)s"
|
conditions += " and posting_date <= %(to_date)s"
|
||||||
|
|
||||||
if self.filters.group_by=="Sales Person":
|
if self.filters.group_by=="Sales Person":
|
||||||
sales_person_cols = ", sales.sales_person, sales.allocated_amount, sales.incentives"
|
sales_person_cols = ", sales.sales_person, sales.allocated_amount, sales.incentives"
|
||||||
sales_team_table = "left join `tabSales Team` sales on sales.parent = `tabSales Invoice`.name"
|
sales_team_table = "left join `tabSales Team` sales on sales.parent = `tabSales Invoice`.name"
|
||||||
@@ -269,7 +273,7 @@ class GrossProfitGenerator(object):
|
|||||||
`tabSales Invoice Item`.dn_detail, `tabSales Invoice Item`.delivery_note, `tabSales Invoice Item`.stock_qty as qty,
|
`tabSales Invoice Item`.dn_detail, `tabSales Invoice Item`.delivery_note, `tabSales Invoice Item`.stock_qty as qty,
|
||||||
`tabSales Invoice Item`.base_net_rate, `tabSales Invoice Item`.base_net_amount, `tabSales Invoice Item`.name as "item_row"
|
`tabSales Invoice Item`.base_net_rate, `tabSales Invoice Item`.base_net_amount, `tabSales Invoice Item`.name as "item_row"
|
||||||
{sales_person_cols}
|
{sales_person_cols}
|
||||||
from
|
from
|
||||||
`tabSales Invoice`
|
`tabSales Invoice`
|
||||||
inner join `tabSales Invoice Item` on `tabSales Invoice Item`.parent = `tabSales Invoice`.name
|
inner join `tabSales Invoice Item` on `tabSales Invoice Item`.parent = `tabSales Invoice`.name
|
||||||
{sales_team_table}
|
{sales_team_table}
|
||||||
@@ -277,7 +281,7 @@ class GrossProfitGenerator(object):
|
|||||||
`tabSales Invoice`.docstatus = 1 and `tabSales Invoice`.is_return != 1 {conditions} {match_cond}
|
`tabSales Invoice`.docstatus = 1 and `tabSales Invoice`.is_return != 1 {conditions} {match_cond}
|
||||||
order by
|
order by
|
||||||
`tabSales Invoice`.posting_date desc, `tabSales Invoice`.posting_time desc"""
|
`tabSales Invoice`.posting_date desc, `tabSales Invoice`.posting_time desc"""
|
||||||
.format(conditions=conditions, sales_person_cols=sales_person_cols,
|
.format(conditions=conditions, sales_person_cols=sales_person_cols,
|
||||||
sales_team_table=sales_team_table, match_cond = get_match_cond('Sales Invoice')), self.filters, as_dict=1)
|
sales_team_table=sales_team_table, match_cond = get_match_cond('Sales Invoice')), self.filters, as_dict=1)
|
||||||
|
|
||||||
def load_stock_ledger_entries(self):
|
def load_stock_ledger_entries(self):
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from frappe.utils import flt
|
|||||||
from frappe import msgprint, _
|
from frappe import msgprint, _
|
||||||
|
|
||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
if not filters: filters = {}
|
if not filters: filters = frappe._dict({})
|
||||||
|
|
||||||
invoice_list = get_invoices(filters)
|
invoice_list = get_invoices(filters)
|
||||||
columns, income_accounts, tax_accounts = get_columns(invoice_list)
|
columns, income_accounts, tax_accounts = get_columns(invoice_list)
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
Common scripts for purchase transactions.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
from __future__ import unicode_literals
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
{
|
|
||||||
"allow_copy": 0,
|
|
||||||
"allow_import": 0,
|
|
||||||
"allow_rename": 0,
|
|
||||||
"creation": "2012-03-27 14:35:51",
|
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
|
||||||
"fields": [],
|
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
|
||||||
"idx": 1,
|
|
||||||
"in_create": 0,
|
|
||||||
"in_dialog": 0,
|
|
||||||
"is_submittable": 0,
|
|
||||||
"issingle": 1,
|
|
||||||
"istable": 0,
|
|
||||||
"modified": "2013-12-20 19:23:27",
|
|
||||||
"modified_by": "Administrator",
|
|
||||||
"module": "Buying",
|
|
||||||
"name": "Purchase Common",
|
|
||||||
"owner": "Administrator",
|
|
||||||
"permissions": [],
|
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 0
|
|
||||||
}
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
|
||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe, json
|
|
||||||
from frappe.utils import flt, cstr, cint
|
|
||||||
from frappe import _
|
|
||||||
|
|
||||||
from erpnext.stock.doctype.item.item import get_last_purchase_details
|
|
||||||
from erpnext.controllers.buying_controller import BuyingController
|
|
||||||
|
|
||||||
class PurchaseCommon(BuyingController):
|
|
||||||
def update_last_purchase_rate(self, obj, is_submit):
|
|
||||||
"""updates last_purchase_rate in item table for each item"""
|
|
||||||
|
|
||||||
import frappe.utils
|
|
||||||
this_purchase_date = frappe.utils.getdate(obj.get('posting_date') or obj.get('transaction_date'))
|
|
||||||
|
|
||||||
for d in obj.get("items"):
|
|
||||||
# get last purchase details
|
|
||||||
last_purchase_details = get_last_purchase_details(d.item_code, obj.name)
|
|
||||||
|
|
||||||
# compare last purchase date and this transaction's date
|
|
||||||
last_purchase_rate = None
|
|
||||||
if last_purchase_details and \
|
|
||||||
(last_purchase_details.purchase_date > this_purchase_date):
|
|
||||||
last_purchase_rate = last_purchase_details['base_rate']
|
|
||||||
elif is_submit == 1:
|
|
||||||
# even if this transaction is the latest one, it should be submitted
|
|
||||||
# for it to be considered for latest purchase rate
|
|
||||||
if flt(d.conversion_factor):
|
|
||||||
last_purchase_rate = flt(d.base_rate) / flt(d.conversion_factor)
|
|
||||||
else:
|
|
||||||
frappe.throw(_("UOM Conversion factor is required in row {0}").format(d.idx))
|
|
||||||
|
|
||||||
# update last purchsae rate
|
|
||||||
if last_purchase_rate:
|
|
||||||
frappe.db.sql("""update `tabItem` set last_purchase_rate = %s where name = %s""",
|
|
||||||
(flt(last_purchase_rate), d.item_code))
|
|
||||||
|
|
||||||
def validate_for_items(self, obj):
|
|
||||||
items = []
|
|
||||||
for d in obj.get("items"):
|
|
||||||
if not d.qty:
|
|
||||||
if obj.doctype == "Purchase Receipt" and d.rejected_qty:
|
|
||||||
continue
|
|
||||||
frappe.throw(_("Please enter quantity for Item {0}").format(d.item_code))
|
|
||||||
|
|
||||||
# udpate with latest quantities
|
|
||||||
bin = frappe.db.sql("""select projected_qty from `tabBin` where
|
|
||||||
item_code = %s and warehouse = %s""", (d.item_code, d.warehouse), as_dict=1)
|
|
||||||
|
|
||||||
f_lst ={'projected_qty': bin and flt(bin[0]['projected_qty']) or 0, 'ordered_qty': 0, 'received_qty' : 0}
|
|
||||||
if d.doctype in ('Purchase Receipt Item', 'Purchase Invoice Item'):
|
|
||||||
f_lst.pop('received_qty')
|
|
||||||
for x in f_lst :
|
|
||||||
if d.meta.get_field(x):
|
|
||||||
d.set(x, f_lst[x])
|
|
||||||
|
|
||||||
item = frappe.db.sql("""select is_stock_item,
|
|
||||||
is_sub_contracted_item, end_of_life, disabled from `tabItem` where name=%s""",
|
|
||||||
d.item_code, as_dict=1)[0]
|
|
||||||
|
|
||||||
from erpnext.stock.doctype.item.item import validate_end_of_life
|
|
||||||
validate_end_of_life(d.item_code, item.end_of_life, item.disabled)
|
|
||||||
|
|
||||||
# validate stock item
|
|
||||||
if item.is_stock_item==1 and d.qty and not d.warehouse and not d.delivered_by_supplier:
|
|
||||||
frappe.throw(_("Warehouse is mandatory for stock Item {0} in row {1}").format(d.item_code, d.idx))
|
|
||||||
|
|
||||||
items.append(cstr(d.item_code))
|
|
||||||
|
|
||||||
if items and len(items) != len(set(items)) and \
|
|
||||||
not cint(frappe.db.get_single_value("Buying Settings", "allow_multiple_items") or 0):
|
|
||||||
frappe.throw(_("Same item cannot be entered multiple times."))
|
|
||||||
|
|
||||||
def check_for_closed_status(self, doctype, docname):
|
|
||||||
status = frappe.db.get_value(doctype, docname, "status")
|
|
||||||
|
|
||||||
if status == "Closed":
|
|
||||||
frappe.throw(_("{0} {1} status is {2}").format(doctype, docname, status), frappe.InvalidStatusError)
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
|
||||||
def get_linked_material_requests(items):
|
|
||||||
items = json.loads(items)
|
|
||||||
mr_list = []
|
|
||||||
for item in items:
|
|
||||||
material_request = frappe.db.sql("""SELECT distinct mr.name AS mr_name,
|
|
||||||
(mr_item.qty - mr_item.ordered_qty) AS qty,
|
|
||||||
mr_item.item_code AS item_code,
|
|
||||||
mr_item.name AS mr_item
|
|
||||||
FROM `tabMaterial Request` mr, `tabMaterial Request Item` mr_item
|
|
||||||
WHERE mr.name = mr_item.parent
|
|
||||||
AND mr_item.item_code = %(item)s
|
|
||||||
AND mr.material_request_type = 'Purchase'
|
|
||||||
AND mr.per_ordered < 99.99
|
|
||||||
AND mr.docstatus = 1
|
|
||||||
AND mr.status != 'Stopped'
|
|
||||||
ORDER BY mr_item.item_code ASC""",{"item": item}, as_dict=1)
|
|
||||||
if material_request:
|
|
||||||
mr_list.append(material_request)
|
|
||||||
|
|
||||||
return mr_list
|
|
||||||
|
|
||||||
|
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
frappe.provide("erpnext.buying");
|
frappe.provide("erpnext.buying");
|
||||||
|
|
||||||
{% include 'erpnext/buying/doctype/purchase_common/purchase_common.js' %};
|
{% include 'erpnext/public/js/controllers/buying.js' %};
|
||||||
|
|
||||||
frappe.ui.form.on("Purchase Order", {
|
frappe.ui.form.on("Purchase Order", {
|
||||||
setup: function(frm) {
|
setup: function(frm) {
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ from erpnext.controllers.buying_controller import BuyingController
|
|||||||
from erpnext.stock.doctype.item.item import get_last_purchase_details
|
from erpnext.stock.doctype.item.item import get_last_purchase_details
|
||||||
from erpnext.stock.stock_balance import update_bin_qty, get_ordered_qty
|
from erpnext.stock.stock_balance import update_bin_qty, get_ordered_qty
|
||||||
from frappe.desk.notifications import clear_doctype_notifications
|
from frappe.desk.notifications import clear_doctype_notifications
|
||||||
|
from erpnext.buying.utils import (validate_for_items, check_for_closed_status,
|
||||||
|
update_last_purchase_rate)
|
||||||
|
|
||||||
|
|
||||||
form_grid_templates = {
|
form_grid_templates = {
|
||||||
@@ -37,9 +39,8 @@ class PurchaseOrder(BuyingController):
|
|||||||
super(PurchaseOrder, self).validate()
|
super(PurchaseOrder, self).validate()
|
||||||
|
|
||||||
self.set_status()
|
self.set_status()
|
||||||
pc_obj = frappe.get_doc('Purchase Common')
|
validate_for_items(self)
|
||||||
pc_obj.validate_for_items(self)
|
self.check_for_closed_status()
|
||||||
self.check_for_closed_status(pc_obj)
|
|
||||||
|
|
||||||
self.validate_uom_is_integer("uom", "qty")
|
self.validate_uom_is_integer("uom", "qty")
|
||||||
self.validate_uom_is_integer("stock_uom", ["qty", "required_qty"])
|
self.validate_uom_is_integer("stock_uom", ["qty", "required_qty"])
|
||||||
@@ -111,12 +112,12 @@ class PurchaseOrder(BuyingController):
|
|||||||
= d.rate = item_last_purchase_rate
|
= d.rate = item_last_purchase_rate
|
||||||
|
|
||||||
# Check for Closed status
|
# Check for Closed status
|
||||||
def check_for_closed_status(self, pc_obj):
|
def check_for_closed_status(self):
|
||||||
check_list =[]
|
check_list =[]
|
||||||
for d in self.get('items'):
|
for d in self.get('items'):
|
||||||
if d.meta.get_field('material_request') and d.material_request and d.material_request not in check_list:
|
if d.meta.get_field('material_request') and d.material_request and d.material_request not in check_list:
|
||||||
check_list.append(d.material_request)
|
check_list.append(d.material_request)
|
||||||
pc_obj.check_for_closed_status('Material Request', d.material_request)
|
check_for_closed_status('Material Request', d.material_request)
|
||||||
|
|
||||||
def update_requested_qty(self):
|
def update_requested_qty(self):
|
||||||
material_request_map = {}
|
material_request_map = {}
|
||||||
@@ -155,7 +156,7 @@ class PurchaseOrder(BuyingController):
|
|||||||
if date_diff and date_diff[0][0]:
|
if date_diff and date_diff[0][0]:
|
||||||
msgprint(_("{0} {1} has been modified. Please refresh.").format(self.doctype, self.name),
|
msgprint(_("{0} {1} has been modified. Please refresh.").format(self.doctype, self.name),
|
||||||
raise_exception=True)
|
raise_exception=True)
|
||||||
|
|
||||||
def update_status(self, status):
|
def update_status(self, status):
|
||||||
self.check_modified_date()
|
self.check_modified_date()
|
||||||
self.set_status(update=True, status=status)
|
self.set_status(update=True, status=status)
|
||||||
@@ -168,8 +169,6 @@ class PurchaseOrder(BuyingController):
|
|||||||
if self.is_against_so():
|
if self.is_against_so():
|
||||||
self.update_status_updater()
|
self.update_status_updater()
|
||||||
|
|
||||||
purchase_controller = frappe.get_doc("Purchase Common")
|
|
||||||
|
|
||||||
self.update_prevdoc_status()
|
self.update_prevdoc_status()
|
||||||
self.update_requested_qty()
|
self.update_requested_qty()
|
||||||
self.update_ordered_qty()
|
self.update_ordered_qty()
|
||||||
@@ -177,7 +176,7 @@ class PurchaseOrder(BuyingController):
|
|||||||
frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype,
|
frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype,
|
||||||
self.company, self.base_grand_total)
|
self.company, self.base_grand_total)
|
||||||
|
|
||||||
purchase_controller.update_last_purchase_rate(self, is_submit = 1)
|
update_last_purchase_rate(self, is_submit = 1)
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
if self.is_against_so():
|
if self.is_against_so():
|
||||||
@@ -186,8 +185,7 @@ class PurchaseOrder(BuyingController):
|
|||||||
if self.has_drop_ship_item():
|
if self.has_drop_ship_item():
|
||||||
self.update_delivered_qty_in_sales_order()
|
self.update_delivered_qty_in_sales_order()
|
||||||
|
|
||||||
pc_obj = frappe.get_doc('Purchase Common')
|
self.check_for_closed_status()
|
||||||
self.check_for_closed_status(pc_obj)
|
|
||||||
|
|
||||||
frappe.db.set(self,'status','Cancelled')
|
frappe.db.set(self,'status','Cancelled')
|
||||||
|
|
||||||
@@ -197,7 +195,7 @@ class PurchaseOrder(BuyingController):
|
|||||||
self.update_requested_qty()
|
self.update_requested_qty()
|
||||||
self.update_ordered_qty()
|
self.update_ordered_qty()
|
||||||
|
|
||||||
pc_obj.update_last_purchase_rate(self, is_submit = 0)
|
update_last_purchase_rate(self, is_submit = 0)
|
||||||
|
|
||||||
def on_update(self):
|
def on_update(self):
|
||||||
pass
|
pass
|
||||||
@@ -303,7 +301,7 @@ def make_purchase_invoice(source_name, target_doc=None):
|
|||||||
target.amount = flt(obj.amount) - flt(obj.billed_amt)
|
target.amount = flt(obj.amount) - flt(obj.billed_amt)
|
||||||
target.base_amount = target.amount * flt(source_parent.conversion_rate)
|
target.base_amount = target.amount * flt(source_parent.conversion_rate)
|
||||||
target.qty = target.amount / flt(obj.rate) if (flt(obj.rate) and flt(obj.billed_amt)) else flt(obj.qty)
|
target.qty = target.amount / flt(obj.rate) if (flt(obj.rate) and flt(obj.billed_amt)) else flt(obj.qty)
|
||||||
|
|
||||||
item = frappe.db.get_value("Item", target.item_code, ["item_group", "buying_cost_center"], as_dict=1)
|
item = frappe.db.get_value("Item", target.item_code, ["item_group", "buying_cost_center"], as_dict=1)
|
||||||
target.cost_center = frappe.db.get_value("Project", obj.project, "cost_center") \
|
target.cost_center = frappe.db.get_value("Project", obj.project, "cost_center") \
|
||||||
or item.buying_cost_center \
|
or item.buying_cost_center \
|
||||||
@@ -342,7 +340,8 @@ def make_stock_entry(purchase_order, item_code):
|
|||||||
stock_entry.purchase_order = purchase_order.name
|
stock_entry.purchase_order = purchase_order.name
|
||||||
stock_entry.supplier = purchase_order.supplier
|
stock_entry.supplier = purchase_order.supplier
|
||||||
stock_entry.supplier_name = purchase_order.supplier_name
|
stock_entry.supplier_name = purchase_order.supplier_name
|
||||||
stock_entry.supplier_address = purchase_order.address_display
|
stock_entry.supplier_address = purchase_order.supplier_address
|
||||||
|
stock_entry.address_display = purchase_order.address_display
|
||||||
stock_entry.company = purchase_order.company
|
stock_entry.company = purchase_order.company
|
||||||
stock_entry.from_bom = 1
|
stock_entry.from_bom = 1
|
||||||
po_item = [d for d in purchase_order.items if d.item_code == item_code][0]
|
po_item = [d for d in purchase_order.items if d.item_code == item_code][0]
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// License: GNU General Public License v3. See license.txt
|
// License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
|
||||||
{% include 'erpnext/buying/doctype/purchase_common/purchase_common.js' %};
|
{% include 'erpnext/public/js/controllers/buying.js' %};
|
||||||
|
|
||||||
cur_frm.add_fetch('contact', 'email_id', 'email_id')
|
cur_frm.add_fetch('contact', 'email_id', 'email_id')
|
||||||
|
|
||||||
|
|||||||
@@ -14,13 +14,14 @@ from frappe.core.doctype.communication.email import make
|
|||||||
from erpnext.accounts.party import get_party_account_currency, get_party_details
|
from erpnext.accounts.party import get_party_account_currency, get_party_details
|
||||||
from erpnext.stock.doctype.material_request.material_request import set_missing_values
|
from erpnext.stock.doctype.material_request.material_request import set_missing_values
|
||||||
from erpnext.controllers.buying_controller import BuyingController
|
from erpnext.controllers.buying_controller import BuyingController
|
||||||
|
from erpnext.buying.utils import validate_for_items
|
||||||
|
|
||||||
STANDARD_USERS = ("Guest", "Administrator")
|
STANDARD_USERS = ("Guest", "Administrator")
|
||||||
|
|
||||||
class RequestforQuotation(BuyingController):
|
class RequestforQuotation(BuyingController):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.validate_duplicate_supplier()
|
self.validate_duplicate_supplier()
|
||||||
self.validate_common()
|
validate_for_items(self)
|
||||||
self.update_email_id()
|
self.update_email_id()
|
||||||
|
|
||||||
def validate_duplicate_supplier(self):
|
def validate_duplicate_supplier(self):
|
||||||
@@ -28,10 +29,6 @@ class RequestforQuotation(BuyingController):
|
|||||||
if len(supplier_list) != len(set(supplier_list)):
|
if len(supplier_list) != len(set(supplier_list)):
|
||||||
frappe.throw(_("Same supplier has been entered multiple times"))
|
frappe.throw(_("Same supplier has been entered multiple times"))
|
||||||
|
|
||||||
def validate_common(self):
|
|
||||||
pc = frappe.get_doc('Purchase Common')
|
|
||||||
pc.validate_for_items(self)
|
|
||||||
|
|
||||||
def update_email_id(self):
|
def update_email_id(self):
|
||||||
for rfq_supplier in self.suppliers:
|
for rfq_supplier in self.suppliers:
|
||||||
if not rfq_supplier.email_id:
|
if not rfq_supplier.email_id:
|
||||||
@@ -130,7 +127,7 @@ class RequestforQuotation(BuyingController):
|
|||||||
self.send_email(data, sender, subject, message, attachments)
|
self.send_email(data, sender, subject, message, attachments)
|
||||||
|
|
||||||
def send_email(self, data, sender, subject, message, attachments):
|
def send_email(self, data, sender, subject, message, attachments):
|
||||||
make(subject = subject, content=message,recipients=data.email_id,
|
make(subject = subject, content=message,recipients=data.email_id,
|
||||||
sender=sender,attachments = attachments, send_email=True,
|
sender=sender,attachments = attachments, send_email=True,
|
||||||
doctype=self.doctype, name=self.name)["name"]
|
doctype=self.doctype, name=self.name)["name"]
|
||||||
|
|
||||||
@@ -250,26 +247,26 @@ def get_rfq_doc(doctype, name, supplier_idx):
|
|||||||
args = doc.get('suppliers')[cint(supplier_idx) - 1]
|
args = doc.get('suppliers')[cint(supplier_idx) - 1]
|
||||||
doc.update_supplier_part_no(args)
|
doc.update_supplier_part_no(args)
|
||||||
return doc
|
return doc
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_item_from_material_requests_based_on_supplier(source_name, target_doc = None):
|
def get_item_from_material_requests_based_on_supplier(source_name, target_doc = None):
|
||||||
mr_items_list = frappe.db.sql("""
|
mr_items_list = frappe.db.sql("""
|
||||||
SELECT
|
SELECT
|
||||||
mr.name, mr_item.item_code
|
mr.name, mr_item.item_code
|
||||||
FROM
|
FROM
|
||||||
`tabItem` as item,
|
`tabItem` as item,
|
||||||
`tabItem Supplier` as item_supp,
|
`tabItem Supplier` as item_supp,
|
||||||
`tabMaterial Request Item` as mr_item,
|
`tabMaterial Request Item` as mr_item,
|
||||||
`tabMaterial Request` as mr
|
`tabMaterial Request` as mr
|
||||||
WHERE item_supp.supplier = %(supplier)s
|
WHERE item_supp.supplier = %(supplier)s
|
||||||
AND item.name = item_supp.parent
|
AND item.name = item_supp.parent
|
||||||
AND mr_item.parent = mr.name
|
AND mr_item.parent = mr.name
|
||||||
AND mr_item.item_code = item.name
|
AND mr_item.item_code = item.name
|
||||||
AND mr.status != "Stopped"
|
AND mr.status != "Stopped"
|
||||||
AND mr.material_request_type = "Purchase"
|
AND mr.material_request_type = "Purchase"
|
||||||
AND mr.docstatus = 1
|
AND mr.docstatus = 1
|
||||||
AND mr.per_ordered < 99.99""", {"supplier": source_name}, as_dict=1)
|
AND mr.per_ordered < 99.99""", {"supplier": source_name}, as_dict=1)
|
||||||
|
|
||||||
material_requests = {}
|
material_requests = {}
|
||||||
for d in mr_items_list:
|
for d in mr_items_list:
|
||||||
material_requests.setdefault(d.name, []).append(d.item_code)
|
material_requests.setdefault(d.name, []).append(d.item_code)
|
||||||
@@ -293,5 +290,5 @@ def get_item_from_material_requests_based_on_supplier(source_name, target_doc =
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
}, target_doc)
|
}, target_doc)
|
||||||
|
|
||||||
return target_doc
|
return target_doc
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// License: GNU General Public License v3. See license.txt
|
// License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
// attach required files
|
// attach required files
|
||||||
{% include 'erpnext/buying/doctype/purchase_common/purchase_common.js' %};
|
{% include 'erpnext/public/js/controllers/buying.js' %};
|
||||||
|
|
||||||
frappe.ui.form.on('Suppier Quotation', {
|
frappe.ui.form.on('Suppier Quotation', {
|
||||||
setup: function() {
|
setup: function() {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ from frappe.utils import flt
|
|||||||
from frappe.model.mapper import get_mapped_doc
|
from frappe.model.mapper import get_mapped_doc
|
||||||
|
|
||||||
from erpnext.controllers.buying_controller import BuyingController
|
from erpnext.controllers.buying_controller import BuyingController
|
||||||
|
from erpnext.buying.utils import validate_for_items
|
||||||
|
|
||||||
form_grid_templates = {
|
form_grid_templates = {
|
||||||
"items": "templates/form_grid/item_grid.html"
|
"items": "templates/form_grid/item_grid.html"
|
||||||
@@ -24,7 +25,7 @@ class SupplierQuotation(BuyingController):
|
|||||||
validate_status(self.status, ["Draft", "Submitted", "Stopped",
|
validate_status(self.status, ["Draft", "Submitted", "Stopped",
|
||||||
"Cancelled"])
|
"Cancelled"])
|
||||||
|
|
||||||
self.validate_common()
|
validate_for_items(self)
|
||||||
self.validate_with_previous_doc()
|
self.validate_with_previous_doc()
|
||||||
self.validate_uom_is_integer("uom", "qty")
|
self.validate_uom_is_integer("uom", "qty")
|
||||||
|
|
||||||
@@ -50,11 +51,6 @@ class SupplierQuotation(BuyingController):
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
def validate_common(self):
|
|
||||||
pc = frappe.get_doc('Purchase Common')
|
|
||||||
pc.validate_for_items(self)
|
|
||||||
|
|
||||||
def get_list_context(context=None):
|
def get_list_context(context=None):
|
||||||
from erpnext.controllers.website_list_for_contact import get_list_context
|
from erpnext.controllers.website_list_for_contact import get_list_context
|
||||||
list_context = get_list_context(context)
|
list_context = get_list_context(context)
|
||||||
|
|||||||
80
erpnext/buying/utils.py
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
from frappe.utils import flt, cstr, cint
|
||||||
|
from frappe import _
|
||||||
|
|
||||||
|
from erpnext.stock.doctype.item.item import get_last_purchase_details
|
||||||
|
from erpnext.stock.doctype.item.item import validate_end_of_life
|
||||||
|
|
||||||
|
def update_last_purchase_rate(doc, is_submit):
|
||||||
|
"""updates last_purchase_rate in item table for each item"""
|
||||||
|
|
||||||
|
import frappe.utils
|
||||||
|
this_purchase_date = frappe.utils.getdate(doc.get('posting_date') or doc.get('transaction_date'))
|
||||||
|
|
||||||
|
for d in doc.get("items"):
|
||||||
|
# get last purchase details
|
||||||
|
last_purchase_details = get_last_purchase_details(d.item_code, doc.name)
|
||||||
|
|
||||||
|
# compare last purchase date and this transaction's date
|
||||||
|
last_purchase_rate = None
|
||||||
|
if last_purchase_details and \
|
||||||
|
(last_purchase_details.purchase_date > this_purchase_date):
|
||||||
|
last_purchase_rate = last_purchase_details['base_rate']
|
||||||
|
elif is_submit == 1:
|
||||||
|
# even if this transaction is the latest one, it should be submitted
|
||||||
|
# for it to be considered for latest purchase rate
|
||||||
|
if flt(d.conversion_factor):
|
||||||
|
last_purchase_rate = flt(d.base_rate) / flt(d.conversion_factor)
|
||||||
|
else:
|
||||||
|
frappe.throw(_("UOM Conversion factor is required in row {0}").format(d.idx))
|
||||||
|
|
||||||
|
# update last purchsae rate
|
||||||
|
if last_purchase_rate:
|
||||||
|
frappe.db.sql("""update `tabItem` set last_purchase_rate = %s where name = %s""",
|
||||||
|
(flt(last_purchase_rate), d.item_code))
|
||||||
|
|
||||||
|
def validate_for_items(doc):
|
||||||
|
items = []
|
||||||
|
for d in doc.get("items"):
|
||||||
|
if not d.qty:
|
||||||
|
if doc.doctype == "Purchase Receipt" and d.rejected_qty:
|
||||||
|
continue
|
||||||
|
frappe.throw(_("Please enter quantity for Item {0}").format(d.item_code))
|
||||||
|
|
||||||
|
# update with latest quantities
|
||||||
|
bin = frappe.db.sql("""select projected_qty from `tabBin` where
|
||||||
|
item_code = %s and warehouse = %s""", (d.item_code, d.warehouse), as_dict=1)
|
||||||
|
|
||||||
|
f_lst ={'projected_qty': bin and flt(bin[0]['projected_qty']) or 0, 'ordered_qty': 0, 'received_qty' : 0}
|
||||||
|
if d.doctype in ('Purchase Receipt Item', 'Purchase Invoice Item'):
|
||||||
|
f_lst.pop('received_qty')
|
||||||
|
for x in f_lst :
|
||||||
|
if d.meta.get_field(x):
|
||||||
|
d.set(x, f_lst[x])
|
||||||
|
|
||||||
|
item = frappe.db.sql("""select is_stock_item,
|
||||||
|
is_sub_contracted_item, end_of_life, disabled from `tabItem` where name=%s""",
|
||||||
|
d.item_code, as_dict=1)[0]
|
||||||
|
|
||||||
|
validate_end_of_life(d.item_code, item.end_of_life, item.disabled)
|
||||||
|
|
||||||
|
# validate stock item
|
||||||
|
if item.is_stock_item==1 and d.qty and not d.warehouse and not d.delivered_by_supplier:
|
||||||
|
frappe.throw(_("Warehouse is mandatory for stock Item {0} in row {1}").format(d.item_code, d.idx))
|
||||||
|
|
||||||
|
items.append(cstr(d.item_code))
|
||||||
|
|
||||||
|
if items and len(items) != len(set(items)) and \
|
||||||
|
not cint(frappe.db.get_single_value("Buying Settings", "allow_multiple_items") or 0):
|
||||||
|
frappe.throw(_("Same item cannot be entered multiple times."))
|
||||||
|
|
||||||
|
def check_for_closed_status(doctype, docname):
|
||||||
|
status = frappe.db.get_value(doctype, docname, "status")
|
||||||
|
|
||||||
|
if status == "Closed":
|
||||||
|
frappe.throw(_("{0} {1} status is {2}").format(doctype, docname, status), frappe.InvalidStatusError)
|
||||||
|
|
||||||
@@ -32,6 +32,12 @@ def get_data():
|
|||||||
"label": _("Reports"),
|
"label": _("Reports"),
|
||||||
"icon": "fa fa-list",
|
"icon": "fa fa-list",
|
||||||
"items": [
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "report",
|
||||||
|
"is_query_report": True,
|
||||||
|
"name": "Lead Details",
|
||||||
|
"doctype": "Lead"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "page",
|
"type": "page",
|
||||||
"name": "sales-funnel",
|
"name": "sales-funnel",
|
||||||
@@ -40,15 +46,15 @@ def get_data():
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "report",
|
"type": "report",
|
||||||
"name": "Minutes to First Response for Opportunity",
|
"name": "Prospects Engaged But Not Converted",
|
||||||
"doctype": "Opportunity",
|
"doctype": "Lead",
|
||||||
"is_query_report": True
|
"is_query_report": True
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "report",
|
"type": "report",
|
||||||
"is_query_report": True,
|
"name": "Minutes to First Response for Opportunity",
|
||||||
"name": "Lead Details",
|
"doctype": "Opportunity",
|
||||||
"doctype": "Lead"
|
"is_query_report": True
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "report",
|
"type": "report",
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ def get_data():
|
|||||||
{
|
{
|
||||||
"type": "doctype",
|
"type": "doctype",
|
||||||
"name": "Course Schedule",
|
"name": "Course Schedule",
|
||||||
"route": "Calendar/Course Schedule"
|
"route": "List/Course Schedule/Calendar"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "doctype",
|
"type": "doctype",
|
||||||
@@ -205,6 +205,10 @@ def get_data():
|
|||||||
{
|
{
|
||||||
"type": "doctype",
|
"type": "doctype",
|
||||||
"name": "Academic Year"
|
"name": "Academic Year"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "School Settings"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
# License: GNU General Public License v3. See license.txt
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe, erpnext
|
||||||
from frappe import _, throw
|
from frappe import _, throw
|
||||||
from frappe.utils import today, flt, cint, fmt_money, formatdate, getdate
|
from frappe.utils import today, flt, cint, fmt_money, formatdate, getdate
|
||||||
from erpnext.setup.utils import get_company_currency, get_exchange_rate
|
from erpnext.setup.utils import get_exchange_rate
|
||||||
from erpnext.accounts.utils import get_fiscal_years, validate_fiscal_year, get_account_currency
|
from erpnext.accounts.utils import get_fiscal_years, validate_fiscal_year, get_account_currency
|
||||||
from erpnext.utilities.transaction_base import TransactionBase
|
from erpnext.utilities.transaction_base import TransactionBase
|
||||||
from erpnext.controllers.recurring_document import convert_to_recurring, validate_recurring_document
|
from erpnext.controllers.recurring_document import convert_to_recurring, validate_recurring_document
|
||||||
@@ -22,7 +22,7 @@ class AccountsController(TransactionBase):
|
|||||||
@property
|
@property
|
||||||
def company_currency(self):
|
def company_currency(self):
|
||||||
if not hasattr(self, "__company_currency"):
|
if not hasattr(self, "__company_currency"):
|
||||||
self.__company_currency = get_company_currency(self.company)
|
self.__company_currency = erpnext.get_company_currency(self.company)
|
||||||
|
|
||||||
return self.__company_currency
|
return self.__company_currency
|
||||||
|
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ import frappe
|
|||||||
from frappe import _, msgprint
|
from frappe import _, msgprint
|
||||||
from frappe.utils import flt,cint, cstr
|
from frappe.utils import flt,cint, cstr
|
||||||
|
|
||||||
from erpnext.setup.utils import get_company_currency
|
|
||||||
from erpnext.accounts.party import get_party_details
|
from erpnext.accounts.party import get_party_details
|
||||||
from erpnext.stock.get_item_details import get_conversion_factor
|
from erpnext.stock.get_item_details import get_conversion_factor
|
||||||
|
from erpnext.buying.utils import validate_for_items
|
||||||
|
from erpnext.stock.stock_ledger import get_valuation_rate
|
||||||
|
|
||||||
from erpnext.controllers.stock_controller import StockController
|
from erpnext.controllers.stock_controller import StockController
|
||||||
|
|
||||||
@@ -40,9 +41,7 @@ class BuyingController(StockController):
|
|||||||
# self.validate_purchase_return()
|
# self.validate_purchase_return()
|
||||||
self.validate_rejected_warehouse()
|
self.validate_rejected_warehouse()
|
||||||
self.validate_accepted_rejected_qty()
|
self.validate_accepted_rejected_qty()
|
||||||
|
validate_for_items(self)
|
||||||
pc_obj = frappe.get_doc('Purchase Common')
|
|
||||||
pc_obj.validate_for_items(self)
|
|
||||||
|
|
||||||
#sub-contracting
|
#sub-contracting
|
||||||
self.validate_for_subcontracting()
|
self.validate_for_subcontracting()
|
||||||
@@ -88,9 +87,8 @@ class BuyingController(StockController):
|
|||||||
|
|
||||||
def set_total_in_words(self):
|
def set_total_in_words(self):
|
||||||
from frappe.utils import money_in_words
|
from frappe.utils import money_in_words
|
||||||
company_currency = get_company_currency(self.company)
|
|
||||||
if self.meta.get_field("base_in_words"):
|
if self.meta.get_field("base_in_words"):
|
||||||
self.base_in_words = money_in_words(self.base_grand_total, company_currency)
|
self.base_in_words = money_in_words(self.base_grand_total, self.company_currency)
|
||||||
if self.meta.get_field("in_words"):
|
if self.meta.get_field("in_words"):
|
||||||
self.in_words = money_in_words(self.grand_total, self.currency)
|
self.in_words = money_in_words(self.grand_total, self.currency)
|
||||||
|
|
||||||
@@ -225,9 +223,8 @@ class BuyingController(StockController):
|
|||||||
"serial_no": rm.serial_no
|
"serial_no": rm.serial_no
|
||||||
})
|
})
|
||||||
if not rm.rate:
|
if not rm.rate:
|
||||||
from erpnext.stock.stock_ledger import get_valuation_rate
|
rm.rate = get_valuation_rate(bom_item.item_code, self.supplier_warehouse,
|
||||||
rm.rate = get_valuation_rate(bom_item.item_code, self.supplier_warehouse,
|
self.doctype, self.name, currency=self.company_currency)
|
||||||
self.doctype, self.name)
|
|
||||||
else:
|
else:
|
||||||
rm.rate = bom_item.rate
|
rm.rate = bom_item.rate
|
||||||
|
|
||||||
|
|||||||
@@ -106,24 +106,25 @@ def validate_returned_items(doc):
|
|||||||
|
|
||||||
def validate_quantity(doc, args, ref, valid_items, already_returned_items):
|
def validate_quantity(doc, args, ref, valid_items, already_returned_items):
|
||||||
fields = ['qty']
|
fields = ['qty']
|
||||||
if doc.doctype in ['Purchase Invoice', 'Purchase Receipt']:
|
if doc.doctype in ['Purchase Receipt', 'Purchase Invoice']:
|
||||||
fields.extend(['received_qty', 'rejected_qty'])
|
fields.extend(['received_qty', 'rejected_qty'])
|
||||||
|
|
||||||
already_returned_data = already_returned_items.get(args.item_code) or {}
|
already_returned_data = already_returned_items.get(args.item_code) or {}
|
||||||
|
|
||||||
for column in fields:
|
for column in fields:
|
||||||
return_qty = flt(already_returned_data.get(column, 0)) if len(already_returned_data) > 0 else 0
|
returned_qty = flt(already_returned_data.get(column, 0)) if len(already_returned_data) > 0 else 0
|
||||||
referenced_qty = ref.get(column)
|
reference_qty = ref.get(column)
|
||||||
max_return_qty = flt(referenced_qty) - return_qty
|
max_returnable_qty = flt(reference_qty) - returned_qty
|
||||||
label = column.replace('_', ' ').title()
|
label = column.replace('_', ' ').title()
|
||||||
|
if reference_qty:
|
||||||
if flt(args.get(column)) > 0:
|
if flt(args.get(column)) > 0:
|
||||||
frappe.throw(_("{0} must be negative in return document").format(label))
|
frappe.throw(_("{0} must be negative in return document").format(label))
|
||||||
elif return_qty >= referenced_qty and flt(args.get(column)) != 0:
|
elif returned_qty >= reference_qty and args.get(column):
|
||||||
frappe.throw(_("Item {0} has already been returned").format(args.item_code), StockOverReturnError)
|
frappe.throw(_("Item {0} has already been returned")
|
||||||
elif abs(args.get(column)) > max_return_qty:
|
.format(args.item_code), StockOverReturnError)
|
||||||
frappe.throw(_("Row # {0}: Cannot return more than {1} for Item {2}")
|
elif abs(args.get(column)) > max_returnable_qty:
|
||||||
.format(args.idx, referenced_qty, args.item_code), StockOverReturnError)
|
frappe.throw(_("Row # {0}: Cannot return more than {1} for Item {2}")
|
||||||
|
.format(args.idx, reference_qty, args.item_code), StockOverReturnError)
|
||||||
|
|
||||||
def get_ref_item_dict(valid_items, ref_item_row):
|
def get_ref_item_dict(valid_items, ref_item_row):
|
||||||
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||||
|
|||||||
@@ -4,11 +4,9 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.utils import cint, flt, cstr, comma_or
|
from frappe.utils import cint, flt, cstr, comma_or
|
||||||
from erpnext.setup.utils import get_company_currency
|
|
||||||
from frappe import _, throw
|
from frappe import _, throw
|
||||||
from erpnext.stock.get_item_details import get_bin_details
|
from erpnext.stock.get_item_details import get_bin_details
|
||||||
from erpnext.stock.utils import get_incoming_rate
|
from erpnext.stock.utils import get_incoming_rate
|
||||||
from erpnext.stock.stock_ledger import get_valuation_rate
|
|
||||||
from erpnext.stock.get_item_details import get_conversion_factor
|
from erpnext.stock.get_item_details import get_conversion_factor
|
||||||
|
|
||||||
from erpnext.controllers.stock_controller import StockController
|
from erpnext.controllers.stock_controller import StockController
|
||||||
@@ -113,13 +111,11 @@ class SellingController(StockController):
|
|||||||
|
|
||||||
def set_total_in_words(self):
|
def set_total_in_words(self):
|
||||||
from frappe.utils import money_in_words
|
from frappe.utils import money_in_words
|
||||||
company_currency = get_company_currency(self.company)
|
|
||||||
|
|
||||||
disable_rounded_total = cint(frappe.db.get_value("Global Defaults", None, "disable_rounded_total"))
|
disable_rounded_total = cint(frappe.db.get_value("Global Defaults", None, "disable_rounded_total"))
|
||||||
|
|
||||||
if self.meta.get_field("base_in_words"):
|
if self.meta.get_field("base_in_words"):
|
||||||
self.base_in_words = money_in_words(disable_rounded_total and
|
self.base_in_words = money_in_words(disable_rounded_total and
|
||||||
abs(self.base_grand_total) or abs(self.base_rounded_total), company_currency)
|
abs(self.base_grand_total) or abs(self.base_rounded_total), self.company_currency)
|
||||||
if self.meta.get_field("in_words"):
|
if self.meta.get_field("in_words"):
|
||||||
self.in_words = money_in_words(disable_rounded_total and
|
self.in_words = money_in_words(disable_rounded_total and
|
||||||
abs(self.grand_total) or abs(self.rounded_total), self.currency)
|
abs(self.grand_total) or abs(self.rounded_total), self.currency)
|
||||||
@@ -170,7 +166,7 @@ class SellingController(StockController):
|
|||||||
if d.meta.get_field("stock_qty"):
|
if d.meta.get_field("stock_qty"):
|
||||||
if not d.conversion_factor:
|
if not d.conversion_factor:
|
||||||
frappe.throw(_("Row {0}: Conversion Factor is mandatory").format(d.idx))
|
frappe.throw(_("Row {0}: Conversion Factor is mandatory").format(d.idx))
|
||||||
d.stock_qty = flt(d.qty) * flt(d.conversion_factor)
|
d.stock_qty = flt(d.qty) * flt(d.conversion_factor)
|
||||||
|
|
||||||
def validate_selling_price(self):
|
def validate_selling_price(self):
|
||||||
def throw_message(item_name, rate, ref_rate_field):
|
def throw_message(item_name, rate, ref_rate_field):
|
||||||
@@ -207,7 +203,7 @@ class SellingController(StockController):
|
|||||||
if p.parent_detail_docname == d.name and p.parent_item == d.item_code:
|
if p.parent_detail_docname == d.name and p.parent_item == d.item_code:
|
||||||
# the packing details table's qty is already multiplied with parent's qty
|
# the packing details table's qty is already multiplied with parent's qty
|
||||||
il.append(frappe._dict({
|
il.append(frappe._dict({
|
||||||
'warehouse': p.warehouse,
|
'warehouse': p.warehouse or d.warehouse,
|
||||||
'item_code': p.item_code,
|
'item_code': p.item_code,
|
||||||
'qty': flt(p.qty),
|
'qty': flt(p.qty),
|
||||||
'uom': p.uom,
|
'uom': p.uom,
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ class StatusUpdater(Document):
|
|||||||
self.status = s[0]
|
self.status = s[0]
|
||||||
break
|
break
|
||||||
elif s[1].startswith("eval:"):
|
elif s[1].startswith("eval:"):
|
||||||
if eval(s[1][5:]):
|
if frappe.safe_eval(s[1][5:], None, { "self": self.as_dict(), "getdate": getdate, "nowdate": nowdate }):
|
||||||
self.status = s[0]
|
self.status = s[0]
|
||||||
break
|
break
|
||||||
elif getattr(self, s[1])():
|
elif getattr(self, s[1])():
|
||||||
|
|||||||
@@ -54,14 +54,14 @@ class StockController(AccountsController):
|
|||||||
|
|
||||||
self.check_expense_account(item_row)
|
self.check_expense_account(item_row)
|
||||||
|
|
||||||
# If item is not a sample item
|
# If the item does not have the allow zero valuation rate flag set
|
||||||
# and ( valuation rate not mentioned in an incoming entry
|
# and ( valuation rate not mentioned in an incoming entry
|
||||||
# or incoming entry not found while delivering the item),
|
# or incoming entry not found while delivering the item),
|
||||||
# try to pick valuation rate from previous sle or Item master and update in SLE
|
# try to pick valuation rate from previous sle or Item master and update in SLE
|
||||||
# Otherwise, throw an exception
|
# Otherwise, throw an exception
|
||||||
|
|
||||||
if not sle.stock_value_difference and self.doctype != "Stock Reconciliation" \
|
if not sle.stock_value_difference and self.doctype != "Stock Reconciliation" \
|
||||||
and not item_row.get("is_sample_item"):
|
and not item_row.get("allow_zero_valuation_rate"):
|
||||||
|
|
||||||
sle = self.update_stock_ledger_entries(sle)
|
sle = self.update_stock_ledger_entries(sle)
|
||||||
|
|
||||||
@@ -96,25 +96,25 @@ class StockController(AccountsController):
|
|||||||
return process_gl_map(gl_list)
|
return process_gl_map(gl_list)
|
||||||
|
|
||||||
def update_stock_ledger_entries(self, sle):
|
def update_stock_ledger_entries(self, sle):
|
||||||
sle.valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse,
|
sle.valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse,
|
||||||
self.doctype, self.name)
|
self.doctype, self.name, currency=self.company_currency)
|
||||||
|
|
||||||
sle.stock_value = flt(sle.qty_after_transaction) * flt(sle.valuation_rate)
|
sle.stock_value = flt(sle.qty_after_transaction) * flt(sle.valuation_rate)
|
||||||
sle.stock_value_difference = flt(sle.actual_qty) * flt(sle.valuation_rate)
|
sle.stock_value_difference = flt(sle.actual_qty) * flt(sle.valuation_rate)
|
||||||
|
|
||||||
if sle.name:
|
if sle.name:
|
||||||
frappe.db.sql("""
|
frappe.db.sql("""
|
||||||
update
|
update
|
||||||
`tabStock Ledger Entry`
|
`tabStock Ledger Entry`
|
||||||
set
|
set
|
||||||
stock_value = %(stock_value)s,
|
stock_value = %(stock_value)s,
|
||||||
valuation_rate = %(valuation_rate)s,
|
valuation_rate = %(valuation_rate)s,
|
||||||
stock_value_difference = %(stock_value_difference)s
|
stock_value_difference = %(stock_value_difference)s
|
||||||
where
|
where
|
||||||
name = %(name)s""", (sle))
|
name = %(name)s""", (sle))
|
||||||
|
|
||||||
return sle
|
return sle
|
||||||
|
|
||||||
def get_voucher_details(self, default_expense_account, default_cost_center, sle_map):
|
def get_voucher_details(self, default_expense_account, default_cost_center, sle_map):
|
||||||
if self.doctype == "Stock Reconciliation":
|
if self.doctype == "Stock Reconciliation":
|
||||||
return [frappe._dict({ "name": voucher_detail_no, "expense_account": default_expense_account,
|
return [frappe._dict({ "name": voucher_detail_no, "expense_account": default_expense_account,
|
||||||
@@ -163,9 +163,9 @@ class StockController(AccountsController):
|
|||||||
def get_stock_ledger_details(self):
|
def get_stock_ledger_details(self):
|
||||||
stock_ledger = {}
|
stock_ledger = {}
|
||||||
stock_ledger_entries = frappe.db.sql("""
|
stock_ledger_entries = frappe.db.sql("""
|
||||||
select
|
select
|
||||||
name, warehouse, stock_value_difference, valuation_rate,
|
name, warehouse, stock_value_difference, valuation_rate,
|
||||||
voucher_detail_no, item_code, posting_date, posting_time,
|
voucher_detail_no, item_code, posting_date, posting_time,
|
||||||
actual_qty, qty_after_transaction
|
actual_qty, qty_after_transaction
|
||||||
from
|
from
|
||||||
`tabStock Ledger Entry`
|
`tabStock Ledger Entry`
|
||||||
|
|||||||
@@ -3,10 +3,9 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import json
|
import json
|
||||||
import frappe
|
import frappe, erpnext
|
||||||
from frappe import _, scrub
|
from frappe import _, scrub
|
||||||
from frappe.utils import cint, flt, round_based_on_smallest_currency_fraction
|
from frappe.utils import cint, flt, round_based_on_smallest_currency_fraction
|
||||||
from erpnext.setup.utils import get_company_currency
|
|
||||||
from erpnext.controllers.accounts_controller import validate_conversion_rate, \
|
from erpnext.controllers.accounts_controller import validate_conversion_rate, \
|
||||||
validate_taxes_and_charges, validate_inclusive_tax
|
validate_taxes_and_charges, validate_inclusive_tax
|
||||||
|
|
||||||
@@ -38,7 +37,7 @@ class calculate_taxes_and_totals(object):
|
|||||||
|
|
||||||
def validate_conversion_rate(self):
|
def validate_conversion_rate(self):
|
||||||
# validate conversion rate
|
# validate conversion rate
|
||||||
company_currency = get_company_currency(self.doc.company)
|
company_currency = erpnext.get_company_currency(self.doc.company)
|
||||||
if not self.doc.currency or self.doc.currency == company_currency:
|
if not self.doc.currency or self.doc.currency == company_currency:
|
||||||
self.doc.currency = company_currency
|
self.doc.currency = company_currency
|
||||||
self.doc.conversion_rate = 1.0
|
self.doc.conversion_rate = 1.0
|
||||||
@@ -327,7 +326,7 @@ class calculate_taxes_and_totals(object):
|
|||||||
self.doc.rounded_total = round_based_on_smallest_currency_fraction(self.doc.grand_total,
|
self.doc.rounded_total = round_based_on_smallest_currency_fraction(self.doc.grand_total,
|
||||||
self.doc.currency, self.doc.precision("rounded_total"))
|
self.doc.currency, self.doc.precision("rounded_total"))
|
||||||
if self.doc.meta.get_field("base_rounded_total"):
|
if self.doc.meta.get_field("base_rounded_total"):
|
||||||
company_currency = get_company_currency(self.doc.company)
|
company_currency = erpnext.get_company_currency(self.doc.company)
|
||||||
|
|
||||||
self.doc.base_rounded_total = \
|
self.doc.base_rounded_total = \
|
||||||
round_based_on_smallest_currency_fraction(self.doc.base_grand_total,
|
round_based_on_smallest_currency_fraction(self.doc.base_grand_total,
|
||||||
@@ -405,11 +404,14 @@ class calculate_taxes_and_totals(object):
|
|||||||
self.doc.total_advance = flt(total_allocated_amount, self.doc.precision("total_advance"))
|
self.doc.total_advance = flt(total_allocated_amount, self.doc.precision("total_advance"))
|
||||||
|
|
||||||
if self.doc.party_account_currency == self.doc.currency:
|
if self.doc.party_account_currency == self.doc.currency:
|
||||||
invoice_total = self.doc.grand_total
|
invoice_total = flt(self.doc.grand_total - flt(self.doc.write_off_amount),
|
||||||
else:
|
|
||||||
invoice_total = flt(self.doc.grand_total * self.doc.conversion_rate,
|
|
||||||
self.doc.precision("grand_total"))
|
self.doc.precision("grand_total"))
|
||||||
|
else:
|
||||||
|
base_write_off_amount = flt(flt(self.doc.write_off_amount) * self.doc.conversion_rate,
|
||||||
|
self.doc.precision("base_write_off_amount"))
|
||||||
|
invoice_total = flt(self.doc.grand_total * self.doc.conversion_rate,
|
||||||
|
self.doc.precision("grand_total")) - base_write_off_amount
|
||||||
|
|
||||||
if invoice_total > 0 and self.doc.total_advance > invoice_total:
|
if invoice_total > 0 and self.doc.total_advance > invoice_total:
|
||||||
frappe.throw(_("Advance amount cannot be greater than {0} {1}")
|
frappe.throw(_("Advance amount cannot be greater than {0} {1}")
|
||||||
.format(self.doc.party_account_currency, invoice_total))
|
.format(self.doc.party_account_currency, invoice_total))
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ def get_list_context(context=None):
|
|||||||
"get_list": get_transaction_list
|
"get_list": get_transaction_list
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_transaction_list(doctype, txt=None, filters=None, limit_start=0, limit_page_length=20):
|
def get_transaction_list(doctype, txt=None, filters=None, limit_start=0, limit_page_length=20, order_by="modified"):
|
||||||
from frappe.www.list import get_list
|
from frappe.www.list import get_list
|
||||||
user = frappe.session.user
|
user = frappe.session.user
|
||||||
key = None
|
key = None
|
||||||
|
|||||||
@@ -574,7 +574,7 @@
|
|||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_global_search": 0,
|
"in_global_search": 0,
|
||||||
"in_list_view": 1,
|
"in_list_view": 0,
|
||||||
"in_standard_filter": 0,
|
"in_standard_filter": 0,
|
||||||
"label": "Territory",
|
"label": "Territory",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
@@ -1152,7 +1152,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2017-03-12 21:55:21.598112",
|
"modified": "2017-04-04 01:21:02.165730",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "CRM",
|
"module": "CRM",
|
||||||
"name": "Opportunity",
|
"name": "Opportunity",
|
||||||
|
|||||||
@@ -194,11 +194,12 @@ def make_quotation(source_name, target_doc=None):
|
|||||||
quotation.transaction_date)
|
quotation.transaction_date)
|
||||||
|
|
||||||
quotation.conversion_rate = exchange_rate
|
quotation.conversion_rate = exchange_rate
|
||||||
|
|
||||||
# get default taxes
|
# get default taxes
|
||||||
taxes = get_default_taxes_and_charges("Sales Taxes and Charges Template")
|
taxes = get_default_taxes_and_charges("Sales Taxes and Charges Template")
|
||||||
quotation.extend("taxes", taxes)
|
if taxes:
|
||||||
|
quotation.extend("taxes", taxes)
|
||||||
|
|
||||||
quotation.run_method("set_missing_values")
|
quotation.run_method("set_missing_values")
|
||||||
quotation.run_method("calculate_taxes_and_totals")
|
quotation.run_method("calculate_taxes_and_totals")
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
|
||||||
|
frappe.query_reports["Prospects Engaged But Not Converted"] = {
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"fieldname": "lead",
|
||||||
|
"label": __("Lead"),
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Lead"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "no_of_interaction",
|
||||||
|
"label": __("Number of Interaction"),
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"default": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "lead_age",
|
||||||
|
"label": __("Minimum Lead Age (Days)"),
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"default": 60
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"add_total_row": 0,
|
||||||
|
"apply_user_permissions": 1,
|
||||||
|
"creation": "2017-04-04 08:25:40.491063",
|
||||||
|
"disabled": 0,
|
||||||
|
"docstatus": 0,
|
||||||
|
"doctype": "Report",
|
||||||
|
"idx": 0,
|
||||||
|
"is_standard": "Yes",
|
||||||
|
"modified": "2017-04-04 10:00:10.253224",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "CRM",
|
||||||
|
"name": "Prospects Engaged But Not Converted",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"ref_doctype": "Lead",
|
||||||
|
"report_name": "Prospects Engaged But Not Converted",
|
||||||
|
"report_type": "Script Report",
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"role": "Sales User"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "Sales Manager"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "System Manager"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
from frappe import _
|
||||||
|
from frappe.utils import add_days, now
|
||||||
|
|
||||||
|
def execute(filters=None):
|
||||||
|
columns, data = [], []
|
||||||
|
set_defaut_value_for_filters(filters)
|
||||||
|
columns = get_columns()
|
||||||
|
data = get_data(filters)
|
||||||
|
|
||||||
|
return columns, data
|
||||||
|
|
||||||
|
def set_defaut_value_for_filters(filters):
|
||||||
|
if not filters.get('no_of_interaction'): filters["no_of_interaction"] = 1
|
||||||
|
if not filters.get('lead_age'): filters["lead_age"] = 60
|
||||||
|
|
||||||
|
def get_columns():
|
||||||
|
return [
|
||||||
|
_("Lead") + ":Link/Lead:100",
|
||||||
|
_("Name") + "::100",
|
||||||
|
_("Organization") + "::100",
|
||||||
|
_("Reference Document") + "::150",
|
||||||
|
_("Reference Name") + ":Dynamic Link/"+_("Reference Document")+":120",
|
||||||
|
_("Last Communication") + ":Data:200",
|
||||||
|
_("Last Communication Date") + ":Date:180"
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_data(filters):
|
||||||
|
lead_details = []
|
||||||
|
lead_filters = get_lead_filters(filters)
|
||||||
|
|
||||||
|
for lead in frappe.get_all('Lead', fields = ['name', 'lead_name', 'company_name'], filters=lead_filters):
|
||||||
|
data = frappe.db.sql("""
|
||||||
|
select
|
||||||
|
`tabCommunication`.reference_doctype, `tabCommunication`.reference_name,
|
||||||
|
`tabCommunication`.content, `tabCommunication`.communication_date
|
||||||
|
from
|
||||||
|
(
|
||||||
|
(select name, lead from `tabOpportunity` where lead = %(lead)s)
|
||||||
|
union
|
||||||
|
(select name, lead from `tabQuotation` where lead = %(lead)s)
|
||||||
|
union
|
||||||
|
(select name, lead from `tabIssue` where lead = %(lead)s and status!='Closed')
|
||||||
|
union
|
||||||
|
(select %(lead)s, %(lead)s)
|
||||||
|
)
|
||||||
|
as ref_document, `tabCommunication`
|
||||||
|
where
|
||||||
|
`tabCommunication`.reference_name = ref_document.name and
|
||||||
|
`tabCommunication`.sent_or_received = 'Received'
|
||||||
|
order by
|
||||||
|
ref_document.lead, `tabCommunication`.creation desc limit %(limit)s""",
|
||||||
|
{'lead': lead.name, 'limit': filters.get('no_of_interaction')})
|
||||||
|
|
||||||
|
for lead_info in data:
|
||||||
|
lead_data = [lead.name, lead.lead_name, lead.company_name] + list(lead_info)
|
||||||
|
lead_details.append(lead_data)
|
||||||
|
|
||||||
|
return lead_details
|
||||||
|
|
||||||
|
def get_lead_filters(filters):
|
||||||
|
lead_creation_date = get_creation_date_based_on_lead_age(filters)
|
||||||
|
lead_filters = [["status", "!=", "Converted"], ["creation", ">", lead_creation_date]]
|
||||||
|
|
||||||
|
if filters.get('lead'):
|
||||||
|
lead_filters.append(["name", "=", filters.get('lead')])
|
||||||
|
return lead_filters
|
||||||
|
|
||||||
|
def get_creation_date_based_on_lead_age(filters):
|
||||||
|
return add_days(now(), (filters.get('lead_age') * -1))
|
||||||
@@ -63,6 +63,13 @@ def complete_setup(domain='Manufacturing'):
|
|||||||
"language": "english"
|
"language": "english"
|
||||||
})
|
})
|
||||||
|
|
||||||
|
company = erpnext.get_default_company()
|
||||||
|
|
||||||
|
if company:
|
||||||
|
company_doc = frappe.get_doc("Company", company)
|
||||||
|
company_doc.db_set('default_payroll_payable_account',
|
||||||
|
frappe.db.get_value('Account', dict(account_name='Payroll Payable')))
|
||||||
|
|
||||||
def setup_demo_page():
|
def setup_demo_page():
|
||||||
# home page should always be "start"
|
# home page should always be "start"
|
||||||
website_settings = frappe.get_doc("Website Settings", "Website Settings")
|
website_settings = frappe.get_doc("Website Settings", "Website Settings")
|
||||||
|
|||||||
@@ -34,14 +34,16 @@ def work():
|
|||||||
process_payroll.salary_slip_based_on_timesheet = 0
|
process_payroll.salary_slip_based_on_timesheet = 0
|
||||||
process_payroll.create_salary_slips()
|
process_payroll.create_salary_slips()
|
||||||
process_payroll.submit_salary_slips()
|
process_payroll.submit_salary_slips()
|
||||||
process_payroll.make_journal_entry(reference_date=frappe.flags.current_date,
|
process_payroll.make_accural_jv_entry()
|
||||||
reference_number=random_string(10))
|
# process_payroll.make_journal_entry(reference_date=frappe.flags.current_date,
|
||||||
|
# reference_number=random_string(10))
|
||||||
|
|
||||||
process_payroll.salary_slip_based_on_timesheet = 1
|
process_payroll.salary_slip_based_on_timesheet = 1
|
||||||
process_payroll.create_salary_slips()
|
process_payroll.create_salary_slips()
|
||||||
process_payroll.submit_salary_slips()
|
process_payroll.submit_salary_slips()
|
||||||
process_payroll.make_journal_entry(reference_date=frappe.flags.current_date,
|
process_payroll.make_accural_jv_entry()
|
||||||
reference_number=random_string(10))
|
# process_payroll.make_journal_entry(reference_date=frappe.flags.current_date,
|
||||||
|
# reference_number=random_string(10))
|
||||||
|
|
||||||
if frappe.db.get_global('demo_hr_user'):
|
if frappe.db.get_global('demo_hr_user'):
|
||||||
make_timesheet_records()
|
make_timesheet_records()
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 62 KiB |
BIN
erpnext/docs/assets/img/accounts/pos-email.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
0
erpnext/docs/assets/img/crm/report/__init__.py
Normal file
|
After Width: | Height: | Size: 76 KiB |
BIN
erpnext/docs/assets/img/crm/report/inactive_customers.png
Normal file
|
After Width: | Height: | Size: 57 KiB |
BIN
erpnext/docs/assets/img/crm/report/lead.png
Normal file
|
After Width: | Height: | Size: 81 KiB |
BIN
erpnext/docs/assets/img/crm/report/minutes_to_first_response.png
Normal file
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 77 KiB |
BIN
erpnext/docs/assets/img/crm/report/sales_funnel.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 570 KiB After Width: | Height: | Size: 570 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 110 KiB |
BIN
erpnext/docs/assets/img/users-and-permissions/roles-for-page.png
Normal file
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 79 KiB |
@@ -640,8 +640,8 @@ attach them to the start of each source file to most effectively state
|
|||||||
the exclusion of warranty; and each file should have at least the
|
the exclusion of warranty; and each file should have at least the
|
||||||
"copyright" line and a pointer to where the full notice is found.</p>
|
"copyright" line and a pointer to where the full notice is found.</p>
|
||||||
|
|
||||||
<pre><code> <one line="" to="" give="" the="" program's="" name="" and="" a="" brief="" idea="" of="" what="" it="" does.="">
|
<pre><code> <one line to give the program's name and a brief idea of what it does.>
|
||||||
Copyright (C) <year> <name of="" author="">
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
40
erpnext/docs/user/manual/en/CRM/crm_reports.md
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
CRM module's reports helps users to get the information about the prospects. Using Following reports, user can analyze the data about prospect's history with a company and will helps user to build strong relationships with them.
|
||||||
|
|
||||||
|
###Lead Details
|
||||||
|
It has data about the leads and their contact and address details.
|
||||||
|
<img alt="Lead Details" class="screenshot"
|
||||||
|
src="{{docs_base_url}}/assets/img/crm/report/lead.png">
|
||||||
|
|
||||||
|
###Sales Funnel
|
||||||
|
By using the sales funnel report, and by quantifying the number of prospects at each stage of the process, you can get an idea of your potential customers.
|
||||||
|
|
||||||
|
More than this, by looking at the way these numbers change over time, you can identify problems in the sales pipeline and take any corrective action at the early stage.
|
||||||
|
|
||||||
|
For example, if you notice that very few communications with the prospects has taken place in a month which might indicate a decrease in the sales. From the next month, organization should make sure that more communications has to take place with the prospects.
|
||||||
|
|
||||||
|
<img alt="Lead Details" class="screenshot"
|
||||||
|
src="{{docs_base_url}}/assets/img/crm/report/sales_funnel.png">
|
||||||
|
|
||||||
|
###Prospects Engaged But Not Converted
|
||||||
|
Using this report, user gets the information about the leads who has shown interest in the business with you but due to some reason they were not converted into the customers.
|
||||||
|
|
||||||
|
<img alt="Lead Details" class="screenshot"
|
||||||
|
src="{{docs_base_url}}/assets/img/crm/report/prospects_engaged_but_not_converted.png">
|
||||||
|
|
||||||
|
###Minutes to First Response for Opportunity
|
||||||
|
Immediacy is so important – and so valued
|
||||||
|
In this internet area, we all expect a quicker response time to any of our query. This report gives you the information about the first response time given to an opportunities or issues. Using this report, the organization can improve their first response time to the prospects which can help to the better sales in the future.
|
||||||
|
|
||||||
|
<img alt="Lead Details" class="screenshot"
|
||||||
|
src="{{docs_base_url}}/assets/img/crm/report/minutes_to_first_response.png">
|
||||||
|
|
||||||
|
###Customer Addresses And Contacts
|
||||||
|
It has data about the customers and their contact and address details.
|
||||||
|
<img alt="Lead Details" class="screenshot"
|
||||||
|
src="{{docs_base_url}}/assets/img/crm/report/customer_address_and_contact.png">
|
||||||
|
|
||||||
|
###Inactive Customers
|
||||||
|
This report shows the list of customers who has not purchased since long time.
|
||||||
|
|
||||||
|
<img alt="Lead Details" class="screenshot"
|
||||||
|
src="{{docs_base_url}}/assets/img/crm/report/inactive_customers.png">
|
||||||
@@ -3,4 +3,5 @@ customer
|
|||||||
opportunity
|
opportunity
|
||||||
contact
|
contact
|
||||||
newsletter
|
newsletter
|
||||||
|
crm_reports
|
||||||
setup
|
setup
|
||||||
@@ -27,7 +27,7 @@ In ERPNext all Sales and Purchase transactions, like Sales Invoice, Quotation, S
|
|||||||
|
|
||||||
### Customer
|
### Customer
|
||||||
|
|
||||||
You can select one of the existing Customer from the Customer master. If Customer doesn't exist in the Customer master, enter Customer Name in the POS Invoice view itself. On creation of POS Invoice, Customer will be auto-created in the Customer master.
|
In POS, user can select the existing customer during making an order or create the new customer. This features works in the offline mode also. User can also add the customer details like contact number, address details etc on the form. The customer which has been created from the POS will be synced when the internet connection is active.
|
||||||
|
|
||||||
<img class="screenshot" alt="POS Customer" src="{{docs_base_url}}/assets/img/accounts/pos-customer.png">
|
<img class="screenshot" alt="POS Customer" src="{{docs_base_url}}/assets/img/accounts/pos-customer.png">
|
||||||
|
|
||||||
@@ -105,4 +105,9 @@ Credits:
|
|||||||
|
|
||||||
To see entries after “Submit”, click on “View Ledger”.
|
To see entries after “Submit”, click on “View Ledger”.
|
||||||
|
|
||||||
|
### Email
|
||||||
|
User can send email from the POS, after submission of an order, user has to click on menu > email
|
||||||
|
<img class="screenshot" alt="POS Payment" src="{{docs_base_url}}/assets/img/accounts/pos-email.png">
|
||||||
|
After sync of an order, email sent to the customer with the print of the bill in the attachment
|
||||||
|
|
||||||
{next}
|
{next}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<img class="screenshot" alt="Production Order" src="{{docs_base_url}}/assets/img/manufacturing/manufacturing-flow.png">
|
<img class="screenshot" alt="Production Order" src="{{docs_base_url}}/assets/img/manufacturing/manufacturing-flow.png">
|
||||||
Production Order (also called as Work Order) is a document that is given to
|
A Production Order (also known as a Work Order) is a document that is given to
|
||||||
the manufacturing shop floor by the Production Planner as a signal to produce
|
the manufacturing shop floor by the Production Planner as a signal to produce
|
||||||
a certain quantity of a certain Item. Production Order also helps to generate
|
a certain quantity of a certain Item. The Production Order also helps to generate
|
||||||
the material requirements (Stock Entry) for the Item to be produced from its
|
the material requirements (Stock Entry) for the Item to be produced from its
|
||||||
**Bill of Materials**.
|
**Bill of Materials**.
|
||||||
|
|
||||||
@@ -66,8 +66,8 @@ by:
|
|||||||
|
|
||||||
* Progress in the Production Order can be tracked using [Timesheet]({{docs_base_url}}/user/manual/en/projects/timesheet/timesheet-against-production-order.html)
|
* Progress in the Production Order can be tracked using [Timesheet]({{docs_base_url}}/user/manual/en/projects/timesheet/timesheet-against-production-order.html)
|
||||||
* Timesheet's time slots are created against Production Order Operations.
|
* Timesheet's time slots are created against Production Order Operations.
|
||||||
* Drafts of Timesheet is created based on the scheduled operations when an Production Order is Submitted.
|
* Drafts of Timesheet are created based on the scheduled operations when an Production Order is Submitted.
|
||||||
* To create more Timesheet against an operation click 'Make Timesheet' button.
|
* To create more Timesheets against an operation click 'Make Timesheet' button.
|
||||||
|
|
||||||
<img class="screenshot" alt="Make timesheet against PO" src="{{docs_base_url}}/assets/img/manufacturing/PO-operations-make-ts.png">
|
<img class="screenshot" alt="Make timesheet against PO" src="{{docs_base_url}}/assets/img/manufacturing/PO-operations-make-ts.png">
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ by:
|
|||||||
### Stopping a Production Order
|
### Stopping a Production Order
|
||||||
|
|
||||||
* When you stop a Production Order its status is changed to Stop indicating that all production process against that Production Order is to be ceased.
|
* When you stop a Production Order its status is changed to Stop indicating that all production process against that Production Order is to be ceased.
|
||||||
* To stop the Production Order click on the 'stop' Button
|
* To stop the Production Order click on the 'Stop' Button
|
||||||
|
|
||||||
1. On Submitting the Production Order, the system will reserve a slot for each of the Production Order Operations serially after the planned start date based on the workstation availability. The Workstation availability depends on the Workstation timings, holiday list and if some other Production Order Operation was scheduled in that slot. You can mention the number of days for the system to try scheduling the operations in the Manufacturing Settings. This is set to 30 Days by default. If the operation requires time exceeding the available slot, system shall ask you to break the operations. Once the scheduling is done system shall create Time Logs and save them. You can Modify them and submit them later.
|
1. On Submitting the Production Order, the system will reserve a slot for each of the Production Order Operations serially after the planned start date based on the workstation availability. The Workstation availability depends on the Workstation timings, holiday list and if some other Production Order Operation was scheduled in that slot. You can mention the number of days for the system to try scheduling the operations in the Manufacturing Settings. This is set to 30 Days by default. If the operation requires time exceeding the available slot, system shall ask you to break the operations. Once the scheduling is done system shall create Time Logs and save them. You can Modify them and submit them later.
|
||||||
2. You can also create additional time logs against an Operation. For doing so select the respective operation and click on 'Make Time Log'
|
2. You can also create additional time logs against an Operation. For doing so select the respective operation and click on 'Make Time Log'
|
||||||
@@ -98,7 +98,7 @@ by:
|
|||||||
|
|
||||||
<img class="screenshot" alt="PO - stop" src="{{docs_base_url}}/assets/img/manufacturing/PO-stop.png">
|
<img class="screenshot" alt="PO - stop" src="{{docs_base_url}}/assets/img/manufacturing/PO-stop.png">
|
||||||
|
|
||||||
* You can Also re-start a stopped Production Order.
|
* You can also re-start a stopped Production Order.
|
||||||
|
|
||||||
> Note : In order to make a Production Order against an Item you must specify 'Yes' to "Allow Production Order" on the Item form.
|
> Note : In order to make a Production Order against an Item you must specify 'Yes' to "Allow Production Order" on the Item form.
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
adding-users
|
adding-users
|
||||||
role-based-permissions
|
role-based-permissions
|
||||||
user-permissions
|
user-permissions
|
||||||
|
role-permisison-for-page-and-report
|
||||||
sharing
|
sharing
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# Role Permission for Page and Report
|
||||||
|
|
||||||
|
In ERPNext, user can make his custom user interface using Page and the custom report using Report Builder or Query Report. ERPNext has role-based-permission system where user can assign roles to the user. And the same role can be assigned to the page and report, to access them.
|
||||||
|
|
||||||
|
If user has enabled the developer mode, then they can add the roles directly in the page and report record. But in that case, the permissions will also be reflected in the json file for the page / report.
|
||||||
|
|
||||||
|
### For Page
|
||||||
|
<img alt="Assign roles to the page" class="screenshot" src="{{docs_base_url}}/assets/img/users-and-permissions/roles-for-page.png">
|
||||||
|
|
||||||
|
### For Report
|
||||||
|
<img alt="Assign roles to the report" class="screenshot" src="{{docs_base_url}}/assets/img/users-and-permissions/roles-for-report.png">
|
||||||
|
|
||||||
|
## Tool for custom roles assignment
|
||||||
|
|
||||||
|
If developer mode is disabled, then user can assign the roles to the page and report, using "Role Permission for Page and Report" page.
|
||||||
|
|
||||||
|
To access, goto Setup > Permissions > Role Permission for Page and Report
|
||||||
|
|
||||||
|
<img alt="Tools to assign custom roles to the page" class="screenshot" src="{{docs_base_url}}/assets/img/users-and-permissions/role-permission-for-page-and-report.png">
|
||||||
|
|
||||||
|
### Reset to defaults
|
||||||
|
|
||||||
|
Using "Reset to Default" button, user can remove the custom permissions applied on a page or report. Then default permissions will be applicable on that page or report.
|
||||||
|
|
||||||
|
<img alt="Reset the default roles" class="screenshot" src="{{docs_base_url}}/assets/img/users-and-permissions/reset-roles-permisison-for-page-report.png">
|
||||||
@@ -22,7 +22,7 @@ With assignment, you can also leave a comment for the review of assignee.
|
|||||||
|
|
||||||
####ToDo List of Assignee
|
####ToDo List of Assignee
|
||||||
|
|
||||||
This transaction will appear in the To-do list of the ser in “Todo” section.
|
This transaction will appear in the To-do list of the user in “Todo” section.
|
||||||
|
|
||||||
<img class="screenshot" alt="Assign" src="{{docs_base_url}}/assets/img/collaboration-tools/assign-3.png">
|
<img class="screenshot" alt="Assign" src="{{docs_base_url}}/assets/img/collaboration-tools/assign-3.png">
|
||||||
|
|
||||||
@@ -32,6 +32,6 @@ User will be able to remove assignment by clicking on "Assignment Completed" but
|
|||||||
|
|
||||||
<img class="screenshot" alt="Assign" src="{{docs_base_url}}/assets/img/collaboration-tools/assign-4.png">
|
<img class="screenshot" alt="Assign" src="{{docs_base_url}}/assets/img/collaboration-tools/assign-4.png">
|
||||||
|
|
||||||
Once assignment is set as completed, Status of its ToDo record will be set as Closed.
|
Once assignment is set as completed, the Status of its ToDo record will be set as Closed.
|
||||||
|
|
||||||
{next}
|
{next}
|
||||||
|
|||||||
@@ -148,8 +148,8 @@ doc_events = {
|
|||||||
"User": {
|
"User": {
|
||||||
"after_insert": "frappe.email.doctype.contact.contact.update_contact",
|
"after_insert": "frappe.email.doctype.contact.contact.update_contact",
|
||||||
"validate": "erpnext.hr.doctype.employee.employee.validate_employee_role",
|
"validate": "erpnext.hr.doctype.employee.employee.validate_employee_role",
|
||||||
"on_update": "erpnext.hr.doctype.employee.employee.update_user_permissions",
|
"on_update": ["erpnext.hr.doctype.employee.employee.update_user_permissions",
|
||||||
"on_update": "frappe.geo.address_and_contact.set_default_role"
|
"erpnext.portal.utils.set_default_role"]
|
||||||
},
|
},
|
||||||
("Sales Taxes and Charges Template", 'Price List'): {
|
("Sales Taxes and Charges Template", 'Price List'): {
|
||||||
"on_update": "erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings.validate_cart_settings"
|
"on_update": "erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings.validate_cart_settings"
|
||||||
|
|||||||
@@ -417,7 +417,7 @@
|
|||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"oldfieldname": "gender",
|
"oldfieldname": "gender",
|
||||||
"oldfieldtype": "Select",
|
"oldfieldtype": "Select",
|
||||||
"options": "\nMale\nFemale",
|
"options": "\nMale\nFemale\nOther",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide_if_no_value": 0,
|
||||||
@@ -2431,4 +2431,4 @@
|
|||||||
"title_field": "employee_name",
|
"title_field": "employee_name",
|
||||||
"track_changes": 1,
|
"track_changes": 1,
|
||||||
"track_seen": 0
|
"track_seen": 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ class Employee(Document):
|
|||||||
delete_events(self.doctype, self.name)
|
delete_events(self.doctype, self.name)
|
||||||
|
|
||||||
def validate_prefered_email(self):
|
def validate_prefered_email(self):
|
||||||
if not self.get(scrub(self.prefered_contact_email)):
|
if self.prefered_contact_email and not self.get(scrub(self.prefered_contact_email)):
|
||||||
frappe.msgprint(_("Please enter " + self.prefered_contact_email))
|
frappe.msgprint(_("Please enter " + self.prefered_contact_email))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ frappe.ui.form.on("Employee Attendance Tool", {
|
|||||||
},
|
},
|
||||||
|
|
||||||
onload: function(frm) {
|
onload: function(frm) {
|
||||||
|
frm.doc.department = frm.doc.branch = frm.doc.company = "All";
|
||||||
frm.set_value("date", get_today());
|
frm.set_value("date", get_today());
|
||||||
erpnext.employee_attendance_tool.load_employees(frm);
|
erpnext.employee_attendance_tool.load_employees(frm);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -13,11 +13,18 @@ class EmployeeAttendanceTool(Document):
|
|||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_employees(date, department=None, branch=None, company=None):
|
def get_employees(date, department = None, branch = None, company = None):
|
||||||
attendance_not_marked = []
|
attendance_not_marked = []
|
||||||
attendance_marked = []
|
attendance_marked = []
|
||||||
employee_list = frappe.get_list("Employee", fields=["employee", "employee_name"], filters={
|
filters = {"status": "Active"}
|
||||||
"status": "Active", "department": department, "branch": branch, "company": company}, order_by="employee_name")
|
if department != "All":
|
||||||
|
filters["department"] = department
|
||||||
|
if branch != "All":
|
||||||
|
filters["branch"] = branch
|
||||||
|
if company != "All":
|
||||||
|
filters["company"] = company
|
||||||
|
|
||||||
|
employee_list = frappe.get_list("Employee", fields=["employee", "employee_name"], filters=filters, order_by="employee_name")
|
||||||
marked_employee = {}
|
marked_employee = {}
|
||||||
for emp in frappe.get_list("Attendance", fields=["employee", "status"],
|
for emp in frappe.get_list("Attendance", fields=["employee", "status"],
|
||||||
filters={"attendance_date": date}):
|
filters={"attendance_date": date}):
|
||||||
|
|||||||
@@ -934,7 +934,7 @@
|
|||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"menu_index": 0,
|
"menu_index": 0,
|
||||||
"modified": "2017-03-08 06:28:46.142302",
|
"modified": "2017-04-10 12:15:20.363859",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Expense Claim",
|
"name": "Expense Claim",
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe import _
|
from frappe.model.naming import append_number_if_name_exists
|
||||||
|
|
||||||
class SalaryComponent(Document):
|
class SalaryComponent(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
@@ -13,12 +13,10 @@ class SalaryComponent(Document):
|
|||||||
|
|
||||||
def validate_abbr(self):
|
def validate_abbr(self):
|
||||||
if not self.salary_component_abbr:
|
if not self.salary_component_abbr:
|
||||||
self.salary_component_abbr = ''.join([c[0] for c in self.salary_component.split()]).upper()
|
self.salary_component_abbr = ''.join([c[0] for c in
|
||||||
|
self.salary_component.split()]).upper()
|
||||||
|
|
||||||
self.salary_component_abbr = self.salary_component_abbr.strip()
|
self.salary_component_abbr = self.salary_component_abbr.strip()
|
||||||
|
|
||||||
if self.get('__islocal') and len(self.salary_component_abbr) > 5:
|
self.salary_component_abbr = append_number_if_name_exists('Salary Component',
|
||||||
frappe.throw(_("Abbreviation cannot have more than 5 characters"))
|
self.salary_component_abbr, 'salary_component_abbr', separator='_')
|
||||||
|
|
||||||
if frappe.db.sql("select salary_component_abbr from `tabSalary Component` where name!=%s and salary_component_abbr=%s", (self.name, self.salary_component_abbr)):
|
|
||||||
frappe.throw(_("Abbreviation {0} already used for another salary component").format(self.salary_component_abbr))
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"allow_copy": 0,
|
||||||
|
"allow_guest_to_view": 0,
|
||||||
"allow_import": 0,
|
"allow_import": 0,
|
||||||
"allow_rename": 0,
|
"allow_rename": 0,
|
||||||
"beta": 0,
|
"beta": 0,
|
||||||
@@ -21,7 +22,9 @@
|
|||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
|
"in_standard_filter": 0,
|
||||||
"label": "Component",
|
"label": "Component",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
@@ -31,6 +34,7 @@
|
|||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide_if_no_value": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
|
"remember_last_selected_value": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
@@ -49,7 +53,9 @@
|
|||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
|
"in_standard_filter": 0,
|
||||||
"label": "Abbr",
|
"label": "Abbr",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
@@ -59,6 +65,65 @@
|
|||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide_if_no_value": 0,
|
||||||
"read_only": 1,
|
"read_only": 1,
|
||||||
|
"remember_last_selected_value": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"columns": 0,
|
||||||
|
"fieldname": "column_break_3",
|
||||||
|
"fieldtype": "Column Break",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"in_standard_filter": 0,
|
||||||
|
"length": 0,
|
||||||
|
"no_copy": 0,
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 0,
|
||||||
|
"print_hide_if_no_value": 0,
|
||||||
|
"read_only": 0,
|
||||||
|
"remember_last_selected_value": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"columns": 0,
|
||||||
|
"description": "If selected, the value specified or calculated in this component will not contribute to the earnings or deductions. However, it's value can be referenced by other components that can be added or deducted. ",
|
||||||
|
"fieldname": "statistical_component",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
|
"in_list_view": 1,
|
||||||
|
"in_standard_filter": 0,
|
||||||
|
"label": "Statistical Component",
|
||||||
|
"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,
|
"report_hide": 0,
|
||||||
"reqd": 0,
|
"reqd": 0,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
@@ -76,7 +141,9 @@
|
|||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
|
"in_standard_filter": 0,
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
@@ -84,6 +151,7 @@
|
|||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide_if_no_value": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
|
"remember_last_selected_value": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 0,
|
"reqd": 0,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
@@ -102,7 +170,9 @@
|
|||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
|
"in_standard_filter": 0,
|
||||||
"label": "Condition",
|
"label": "Condition",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
@@ -111,6 +181,7 @@
|
|||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide_if_no_value": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
|
"remember_last_selected_value": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 0,
|
"reqd": 0,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
@@ -130,7 +201,9 @@
|
|||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
|
"in_standard_filter": 0,
|
||||||
"label": "Amount based on formula",
|
"label": "Amount based on formula",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
@@ -140,6 +213,7 @@
|
|||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide_if_no_value": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
|
"remember_last_selected_value": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 0,
|
"reqd": 0,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
@@ -160,7 +234,9 @@
|
|||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
|
"in_standard_filter": 0,
|
||||||
"label": "Formula",
|
"label": "Formula",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
@@ -169,6 +245,7 @@
|
|||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide_if_no_value": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
|
"remember_last_selected_value": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 0,
|
"reqd": 0,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
@@ -187,7 +264,9 @@
|
|||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
|
"in_standard_filter": 0,
|
||||||
"label": "Amount",
|
"label": "Amount",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
@@ -197,6 +276,7 @@
|
|||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide_if_no_value": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
|
"remember_last_selected_value": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 0,
|
"reqd": 0,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
@@ -215,7 +295,9 @@
|
|||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
|
"in_standard_filter": 0,
|
||||||
"label": "Depends on Leave Without Pay",
|
"label": "Depends on Leave Without Pay",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
@@ -224,6 +306,7 @@
|
|||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide_if_no_value": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
|
"remember_last_selected_value": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 0,
|
"reqd": 0,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
@@ -242,7 +325,9 @@
|
|||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
|
"in_standard_filter": 0,
|
||||||
"label": "Default Amount",
|
"label": "Default Amount",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
@@ -252,6 +337,7 @@
|
|||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide_if_no_value": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
|
"remember_last_selected_value": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 0,
|
"reqd": 0,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
@@ -270,7 +356,9 @@
|
|||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
|
"in_standard_filter": 0,
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
@@ -278,6 +366,7 @@
|
|||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide_if_no_value": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
|
"remember_last_selected_value": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 0,
|
"reqd": 0,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
@@ -296,7 +385,9 @@
|
|||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
|
"in_standard_filter": 0,
|
||||||
"label": "Condition and Formula Help",
|
"label": "Condition and Formula Help",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
@@ -306,6 +397,7 @@
|
|||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide_if_no_value": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
|
"remember_last_selected_value": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 0,
|
"reqd": 0,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
@@ -313,18 +405,18 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"has_web_view": 0,
|
||||||
"hide_heading": 0,
|
"hide_heading": 0,
|
||||||
"hide_toolbar": 0,
|
"hide_toolbar": 0,
|
||||||
"idx": 0,
|
"idx": 0,
|
||||||
"image_view": 0,
|
"image_view": 0,
|
||||||
"in_create": 0,
|
"in_create": 0,
|
||||||
"in_dialog": 0,
|
|
||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2016-09-20 05:29:26.373992",
|
"modified": "2017-04-13 00:47:33.980646",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "chude.osiegbu@manqala.com",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Salary Detail",
|
"name": "Salary Detail",
|
||||||
"name_case": "",
|
"name_case": "",
|
||||||
@@ -333,7 +425,9 @@
|
|||||||
"quick_entry": 1,
|
"quick_entry": 1,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"read_only_onload": 0,
|
"read_only_onload": 0,
|
||||||
|
"show_name_in_global_search": 0,
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
|
"track_changes": 0,
|
||||||
"track_seen": 0
|
"track_seen": 0
|
||||||
}
|
}
|
||||||
@@ -39,7 +39,7 @@ frappe.ui.form.on("Salary Slip", {
|
|||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
frm.trigger("toggle_fields")
|
frm.trigger("toggle_fields")
|
||||||
frm.trigger("toggle_reqd_fields")
|
frm.trigger("toggle_reqd_fields")
|
||||||
salary_detail_fields = ['formula', 'abbr']
|
salary_detail_fields = ['formula', 'abbr', 'statistical_component']
|
||||||
cur_frm.fields_dict['earnings'].grid.set_column_disp(salary_detail_fields,false);
|
cur_frm.fields_dict['earnings'].grid.set_column_disp(salary_detail_fields,false);
|
||||||
cur_frm.fields_dict['deductions'].grid.set_column_disp(salary_detail_fields,false);
|
cur_frm.fields_dict['deductions'].grid.set_column_disp(salary_detail_fields,false);
|
||||||
},
|
},
|
||||||
@@ -138,7 +138,6 @@ var calculate_earning_total = function(doc, dt, dn, reset_amount) {
|
|||||||
refresh_field('amount', tbl[i].name, 'earnings');
|
refresh_field('amount', tbl[i].name, 'earnings');
|
||||||
}
|
}
|
||||||
total_earn += flt(tbl[i].amount);
|
total_earn += flt(tbl[i].amount);
|
||||||
|
|
||||||
}
|
}
|
||||||
doc.gross_pay = total_earn;
|
doc.gross_pay = total_earn;
|
||||||
refresh_many(['amount','gross_pay']);
|
refresh_many(['amount','gross_pay']);
|
||||||
|
|||||||
@@ -2,13 +2,12 @@
|
|||||||
# License: GNU General Public License v3. See license.txt
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe, erpnext
|
||||||
|
|
||||||
from frappe.utils import add_days, cint, cstr, flt, getdate, rounded, date_diff, money_in_words
|
from frappe.utils import add_days, cint, cstr, flt, getdate, rounded, date_diff, money_in_words
|
||||||
from frappe.model.naming import make_autoname
|
from frappe.model.naming import make_autoname
|
||||||
|
|
||||||
from frappe import msgprint, _
|
from frappe import msgprint, _
|
||||||
from erpnext.setup.utils import get_company_currency
|
|
||||||
from erpnext.hr.doctype.process_payroll.process_payroll import get_start_end_dates
|
from erpnext.hr.doctype.process_payroll.process_payroll import get_start_end_dates
|
||||||
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
|
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
|
||||||
from erpnext.utilities.transaction_base import TransactionBase
|
from erpnext.utilities.transaction_base import TransactionBase
|
||||||
@@ -33,7 +32,7 @@ class SalarySlip(TransactionBase):
|
|||||||
# if self.salary_slip_based_on_timesheet or not self.net_pay:
|
# if self.salary_slip_based_on_timesheet or not self.net_pay:
|
||||||
self.calculate_net_pay()
|
self.calculate_net_pay()
|
||||||
|
|
||||||
company_currency = get_company_currency(self.company)
|
company_currency = erpnext.get_company_currency(self.company)
|
||||||
self.total_in_words = money_in_words(self.rounded_total, company_currency)
|
self.total_in_words = money_in_words(self.rounded_total, company_currency)
|
||||||
|
|
||||||
if frappe.db.get_single_value("HR Settings", "max_working_hours_against_timesheet"):
|
if frappe.db.get_single_value("HR Settings", "max_working_hours_against_timesheet"):
|
||||||
@@ -55,7 +54,7 @@ class SalarySlip(TransactionBase):
|
|||||||
for key in ('earnings', 'deductions'):
|
for key in ('earnings', 'deductions'):
|
||||||
for struct_row in self._salary_structure_doc.get(key):
|
for struct_row in self._salary_structure_doc.get(key):
|
||||||
amount = self.eval_condition_and_formula(struct_row, data)
|
amount = self.eval_condition_and_formula(struct_row, data)
|
||||||
if amount:
|
if amount and struct_row.statistical_component == 0:
|
||||||
self.update_component_row(struct_row, amount, key)
|
self.update_component_row(struct_row, amount, key)
|
||||||
|
|
||||||
def update_component_row(self, struct_row, amount, key):
|
def update_component_row(self, struct_row, amount, key):
|
||||||
@@ -77,24 +76,24 @@ class SalarySlip(TransactionBase):
|
|||||||
def eval_condition_and_formula(self, d, data):
|
def eval_condition_and_formula(self, d, data):
|
||||||
try:
|
try:
|
||||||
if d.condition:
|
if d.condition:
|
||||||
if not eval(d.condition, None, data):
|
if not frappe.safe_eval(d.condition, None, data):
|
||||||
return None
|
return None
|
||||||
amount = d.amount
|
amount = d.amount
|
||||||
if d.amount_based_on_formula:
|
if d.amount_based_on_formula:
|
||||||
if d.formula:
|
if d.formula:
|
||||||
amount = eval(d.formula, None, data)
|
amount = frappe.safe_eval(d.formula, None, data)
|
||||||
if amount:
|
if amount:
|
||||||
data[d.abbr] = amount
|
data[d.abbr] = amount
|
||||||
|
|
||||||
return amount
|
return amount
|
||||||
|
|
||||||
except NameError as err:
|
except NameError as err:
|
||||||
frappe.throw(_("Name error: {0}".format(err)))
|
frappe.throw(_("Name error: {0}".format(err)))
|
||||||
except SyntaxError as err:
|
except SyntaxError as err:
|
||||||
frappe.throw(_("Syntax error in formula or condition: {0}".format(err)))
|
frappe.throw(_("Syntax error in formula or condition: {0}".format(err)))
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
frappe.throw(_("Error in formula or condition: {0}".format(e)))
|
frappe.throw(_("Error in formula or condition: {0}".format(e)))
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def get_data_for_eval(self):
|
def get_data_for_eval(self):
|
||||||
'''Returns data for evaluating formula'''
|
'''Returns data for evaluating formula'''
|
||||||
@@ -348,7 +347,7 @@ class SalarySlip(TransactionBase):
|
|||||||
|
|
||||||
self.sum_components('earnings', 'gross_pay')
|
self.sum_components('earnings', 'gross_pay')
|
||||||
self.sum_components('deductions', 'total_deduction')
|
self.sum_components('deductions', 'total_deduction')
|
||||||
|
|
||||||
self.set_loan_repayment()
|
self.set_loan_repayment()
|
||||||
|
|
||||||
self.net_pay = flt(self.gross_pay) - (flt(self.total_deduction) + flt(self.total_loan_repayment))
|
self.net_pay = flt(self.gross_pay) - (flt(self.total_deduction) + flt(self.total_loan_repayment))
|
||||||
@@ -356,11 +355,11 @@ class SalarySlip(TransactionBase):
|
|||||||
self.precision("net_pay") if disable_rounded_total else 0)
|
self.precision("net_pay") if disable_rounded_total else 0)
|
||||||
|
|
||||||
def set_loan_repayment(self):
|
def set_loan_repayment(self):
|
||||||
employee_loan = frappe.db.sql("""select sum(principal_amount) as principal_amount, sum(interest_amount) as interest_amount,
|
employee_loan = frappe.db.sql("""select sum(principal_amount) as principal_amount, sum(interest_amount) as interest_amount,
|
||||||
sum(total_payment) as total_loan_repayment from `tabRepayment Schedule`
|
sum(total_payment) as total_loan_repayment from `tabRepayment Schedule`
|
||||||
where payment_date between %s and %s and parent in (select name from `tabEmployee Loan`
|
where payment_date between %s and %s and parent in (select name from `tabEmployee Loan`
|
||||||
where employee = %s and repay_from_salary = 1 and docstatus = 1)""",
|
where employee = %s and repay_from_salary = 1 and docstatus = 1)""",
|
||||||
(self.start_date, self.end_date, self.employee), as_dict=True)
|
(self.start_date, self.end_date, self.employee), as_dict=True)
|
||||||
if employee_loan:
|
if employee_loan:
|
||||||
self.principal_amount = employee_loan[0].principal_amount
|
self.principal_amount = employee_loan[0].principal_amount
|
||||||
self.interest_amount = employee_loan[0].interest_amount
|
self.interest_amount = employee_loan[0].interest_amount
|
||||||
|
|||||||
@@ -22,18 +22,6 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
|
|||||||
query_report.trigger_refresh();
|
query_report.trigger_refresh();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldname": "from_date",
|
|
||||||
"label": __("From Date"),
|
|
||||||
"fieldtype": "Date",
|
|
||||||
"default": frappe.defaults.get_user_default("year_start_date"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldname": "to_date",
|
|
||||||
"label": __("To Date"),
|
|
||||||
"fieldtype": "Date",
|
|
||||||
"default": frappe.defaults.get_user_default("year_end_date"),
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,41 +3,41 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
|
import erpnext
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import flt,cstr
|
from frappe.utils import flt,cstr
|
||||||
from erpnext.accounts.report.financial_statements import get_period_list
|
from erpnext.accounts.report.financial_statements import get_period_list
|
||||||
|
|
||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
period_list = get_period_list(2016, 2016,"Monthly")
|
|
||||||
for period in period_list:
|
|
||||||
pass
|
|
||||||
columns, data = [], []
|
columns, data = [], []
|
||||||
columns=get_columns()
|
if filters.get('fiscal_year'):
|
||||||
data=get_log_data(filters)
|
company = erpnext.get_default_company()
|
||||||
chart=get_chart_data(data,period_list)
|
period_list = get_period_list(filters.get('fiscal_year'), filters.get('fiscal_year'),"Monthly", company)
|
||||||
|
columns=get_columns()
|
||||||
|
data=get_log_data(filters)
|
||||||
|
chart=get_chart_data(data,period_list)
|
||||||
return columns, data, None, chart
|
return columns, data, None, chart
|
||||||
|
|
||||||
def get_columns():
|
def get_columns():
|
||||||
columns = [_("License") + ":Link/Vehicle:100", _("Make") + ":data:50",
|
columns = [_("License") + ":Link/Vehicle:100", _("Make") + ":data:50",
|
||||||
_("Model") + ":data:50", _("Location") + ":data:100",
|
_("Model") + ":data:50", _("Location") + ":data:100",
|
||||||
_("Log") + ":Link/Vehicle Log:100", _("Odometer") + ":Int:80",
|
_("Log") + ":Link/Vehicle Log:100", _("Odometer") + ":Int:80",
|
||||||
_("Date") + ":Date:100", _("Fuel Qty") + ":Float:80",
|
_("Date") + ":Date:100", _("Fuel Qty") + ":Float:80",
|
||||||
_("Fuel Price") + ":Float:100",_("Service Expense") + ":Float:100"
|
_("Fuel Price") + ":Float:100",_("Service Expense") + ":Float:100"
|
||||||
]
|
]
|
||||||
return columns
|
return columns
|
||||||
|
|
||||||
def get_log_data(filters):
|
def get_log_data(filters):
|
||||||
conditions=""
|
fy = frappe.db.get_value('Fiscal Year', filters.get('fiscal_year'), ['year_start_date', 'year_end_date'], as_dict=True)
|
||||||
if filters.from_date:
|
data = frappe.db.sql("""select
|
||||||
conditions += " and date >= %(from_date)s"
|
vhcl.license_plate as "License", vhcl.make as "Make", vhcl.model as "Model",
|
||||||
if filters.to_date:
|
vhcl.location as "Location", log.name as "Log", log.odometer as "Odometer",
|
||||||
conditions += " and date <= %(to_date)s"
|
log.date as "Date", log.fuel_qty as "Fuel Qty", log.price as "Fuel Price"
|
||||||
data = frappe.db.sql("""select vhcl.license_plate as "License",vhcl.make as "Make",vhcl.model as "Model",
|
from
|
||||||
vhcl.location as "Location",log.name as "Log",log.odometer as "Odometer",log.date as "Date",
|
`tabVehicle` vhcl,`tabVehicle Log` log
|
||||||
log.fuel_qty as "Fuel Qty",log.price as "Fuel Price"
|
where
|
||||||
from `tabVehicle` vhcl,`tabVehicle Log` log
|
vhcl.license_plate = log.license_plate and log.docstatus = 1 and date between %s and %s
|
||||||
where vhcl.license_plate = log.license_plate and log.docstatus = 1 %s
|
order by date""" ,(fy.year_start_date, fy.year_end_date), as_dict=1)
|
||||||
order by date""" % (conditions,),filters, as_dict=1)
|
|
||||||
dl=list(data)
|
dl=list(data)
|
||||||
for row in dl:
|
for row in dl:
|
||||||
row["Service Expense"]= get_service_expense(row["Log"])
|
row["Service Expense"]= get_service_expense(row["Log"])
|
||||||
@@ -45,8 +45,8 @@ def get_log_data(filters):
|
|||||||
|
|
||||||
def get_service_expense(logname):
|
def get_service_expense(logname):
|
||||||
expense_amount = frappe.db.sql("""select sum(expense_amount)
|
expense_amount = frappe.db.sql("""select sum(expense_amount)
|
||||||
from `tabVehicle Log` log,`tabVehicle Service` ser
|
from `tabVehicle Log` log,`tabVehicle Service` ser
|
||||||
where ser.parent=log.name and log.name=%s""",logname)
|
where ser.parent=log.name and log.name=%s""",logname)
|
||||||
return flt(expense_amount[0][0]) if expense_amount else 0
|
return flt(expense_amount[0][0]) if expense_amount else 0
|
||||||
|
|
||||||
def get_chart_data(data,period_list):
|
def get_chart_data(data,period_list):
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"allow_copy": 0,
|
||||||
|
"allow_guest_to_view": 0,
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"allow_rename": 0,
|
"allow_rename": 0,
|
||||||
"beta": 0,
|
"beta": 0,
|
||||||
@@ -1574,18 +1575,18 @@
|
|||||||
"unique": 0
|
"unique": 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"has_web_view": 0,
|
||||||
"hide_heading": 0,
|
"hide_heading": 0,
|
||||||
"hide_toolbar": 0,
|
"hide_toolbar": 0,
|
||||||
"icon": "fa fa-sitemap",
|
"icon": "fa fa-sitemap",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"image_view": 0,
|
"image_view": 0,
|
||||||
"in_create": 0,
|
"in_create": 0,
|
||||||
"in_dialog": 0,
|
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2017-02-21 13:10:27.394012",
|
"modified": "2017-04-10 12:13:59.630780",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Manufacturing",
|
"module": "Manufacturing",
|
||||||
"name": "BOM",
|
"name": "BOM",
|
||||||
@@ -1659,6 +1660,6 @@
|
|||||||
"show_name_in_global_search": 1,
|
"show_name_in_global_search": 1,
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"track_changes": 0,
|
"track_changes": 1,
|
||||||
"track_seen": 0
|
"track_seen": 0
|
||||||
}
|
}
|
||||||
@@ -281,12 +281,15 @@ class BOM(WebsiteGenerator):
|
|||||||
|
|
||||||
return bom_list
|
return bom_list
|
||||||
|
|
||||||
def traverse_tree(self, bom_list=[]):
|
def traverse_tree(self, bom_list=None):
|
||||||
def _get_children(bom_no):
|
def _get_children(bom_no):
|
||||||
return [cstr(d[0]) for d in frappe.db.sql("""select bom_no from `tabBOM Item`
|
return [cstr(d[0]) for d in frappe.db.sql("""select bom_no from `tabBOM Item`
|
||||||
where parent = %s and ifnull(bom_no, '') != ''""", bom_no)]
|
where parent = %s and ifnull(bom_no, '') != ''""", bom_no)]
|
||||||
|
|
||||||
count = 0
|
count = 0
|
||||||
|
if not bom_list:
|
||||||
|
bom_list = []
|
||||||
|
|
||||||
if self.name not in bom_list:
|
if self.name not in bom_list:
|
||||||
bom_list.append(self.name)
|
bom_list.append(self.name)
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,9 @@
|
|||||||
<a style="margin-right: 7px; margin-bottom: 7px" class="btn btn-default btn-xs" href="#Form/BOM/{{ data.value }}">
|
<a style="margin-right: 7px; margin-bottom: 7px" class="btn btn-default btn-xs" href="#Form/BOM/{{ data.value }}">
|
||||||
{{ __("Open BOM {0}", [data.value.bold()]) }}</a>
|
{{ __("Open BOM {0}", [data.value.bold()]) }}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if data.item_code %}
|
||||||
<a class="btn btn-default btn-xs" href="#Form/Item/{{ data.item_code }}">
|
<a class="btn btn-default btn-xs" href="#Form/Item/{{ data.item_code }}">
|
||||||
{{ __("Open Item {0}", [data.item_code.bold()]) }}</a>
|
{{ __("Open Item {0}", [data.item_code.bold()]) }}</a>
|
||||||
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -218,7 +218,7 @@ $.extend(cur_frm.cscript, {
|
|||||||
project: doc.project
|
project: doc.project
|
||||||
},
|
},
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
$.each(["description", "stock_uom", "bom_no"], function(i, field) {
|
$.each(["description", "stock_uom", "project", "bom_no"], function(i, field) {
|
||||||
cur_frm.set_value(field, r.message[field]);
|
cur_frm.set_value(field, r.message[field]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1316,7 +1316,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2017-03-28 19:19:08.559879",
|
"modified": "2017-04-10 12:13:09.312186",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Manufacturing",
|
"module": "Manufacturing",
|
||||||
"name": "Production Order",
|
"name": "Production Order",
|
||||||
@@ -1369,6 +1369,6 @@
|
|||||||
"show_name_in_global_search": 0,
|
"show_name_in_global_search": 0,
|
||||||
"sort_order": "ASC",
|
"sort_order": "ASC",
|
||||||
"title_field": "production_item",
|
"title_field": "production_item",
|
||||||
"track_changes": 0,
|
"track_changes": 1,
|
||||||
"track_seen": 0
|
"track_seen": 0
|
||||||
}
|
}
|
||||||
@@ -498,6 +498,7 @@ def get_item_details(item, project = None):
|
|||||||
frappe.throw(_("Default BOM for {0} not found for Project {1}").format(item, project))
|
frappe.throw(_("Default BOM for {0} not found for Project {1}").format(item, project))
|
||||||
frappe.throw(_("Default BOM for {0} not found").format(item))
|
frappe.throw(_("Default BOM for {0} not found").format(item))
|
||||||
|
|
||||||
|
res['project'] = frappe.db.get_value('BOM', res['bom_no'], 'project')
|
||||||
res.update(check_if_scrap_warehouse_mandatory(res["bom_no"]))
|
res.update(check_if_scrap_warehouse_mandatory(res["bom_no"]))
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|||||||
@@ -380,4 +380,9 @@ erpnext.patches.v7_2.update_attendance_docstatus
|
|||||||
erpnext.patches.v7_2.move_dates_from_salary_structure_to_employee
|
erpnext.patches.v7_2.move_dates_from_salary_structure_to_employee
|
||||||
erpnext.patches.v7_2.make_all_assessment_group
|
erpnext.patches.v7_2.make_all_assessment_group
|
||||||
erpnext.patches.v8_0.manufacturer_childtable_migrate
|
erpnext.patches.v8_0.manufacturer_childtable_migrate
|
||||||
erpnext.patches.v8_0.repost_reserved_qty_for_multiple_sales_uom
|
erpnext.patches.v8_0.repost_reserved_qty_for_multiple_sales_uom
|
||||||
|
erpnext.patches.v8_0.addresses_linked_to_lead
|
||||||
|
execute:frappe.delete_doc('DocType', 'Purchase Common')
|
||||||
|
erpnext.patches.v8_0.update_stock_qty_value_in_purchase_invoice
|
||||||
|
erpnext.patches.v8_0.update_supplier_address_in_stock_entry
|
||||||
|
erpnext.patches.v8_0.rename_is_sample_item_to_allow_zero_valuation_rate
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.geo.country_info import get_all
|
from frappe.geo.country_info import get_all
|
||||||
from erpnext.setup.install import import_country_and_currency
|
from frappe.utils.install import import_country_and_currency
|
||||||
|
|
||||||
def execute():
|
def execute():
|
||||||
frappe.reload_doc("setup", "doctype", "country")
|
frappe.reload_doc("setup", "doctype", "country")
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from frappe.model import update_users_report_view_settings
|
from frappe.model.utils.rename_field import update_users_report_view_settings
|
||||||
from erpnext.patches.v4_0.fields_to_be_renamed import rename_map
|
from erpnext.patches.v4_0.fields_to_be_renamed import rename_map
|
||||||
|
|
||||||
def execute():
|
def execute():
|
||||||
|
|||||||
@@ -3,9 +3,8 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.geo.country_info import get_country_info
|
|
||||||
from erpnext.setup.install import add_country_and_currency
|
|
||||||
|
|
||||||
def execute():
|
def execute():
|
||||||
|
return
|
||||||
country = get_country_info(country="Turkey")
|
country = get_country_info(country="Turkey")
|
||||||
add_country_and_currency("Turkey", country)
|
add_country_and_currency("Turkey", country)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.www.style_settings import default_properties
|
|
||||||
|
|
||||||
def execute():
|
def execute():
|
||||||
|
return
|
||||||
frappe.reload_doc('website', 'doctype', 'style_settings')
|
frappe.reload_doc('website', 'doctype', 'style_settings')
|
||||||
style_settings = frappe.get_doc("Style Settings", "Style Settings")
|
style_settings = frappe.get_doc("Style Settings", "Style Settings")
|
||||||
if not style_settings.apply_style:
|
if not style_settings.apply_style:
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ def execute():
|
|||||||
map_fields = (
|
map_fields = (
|
||||||
('Customer', 'customer'),
|
('Customer', 'customer'),
|
||||||
('Supplier', 'supplier'),
|
('Supplier', 'supplier'),
|
||||||
('Load', 'lead'),
|
('Lead', 'lead'),
|
||||||
('Sales Partner', 'sales_partner')
|
('Sales Partner', 'sales_partner')
|
||||||
)
|
)
|
||||||
for doctype in ('Contact', 'Address'):
|
for doctype in ('Contact', 'Address'):
|
||||||
|
|||||||
4
erpnext/patches/v8_0/addresses_linked_to_lead.py
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import frappe
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
frappe.db.sql("""UPDATE `tabDynamic Link` SET link_doctype = 'Lead' WHERE link_doctype = 'Load'""")
|
||||||
@@ -6,20 +6,19 @@ import frappe
|
|||||||
|
|
||||||
def execute():
|
def execute():
|
||||||
|
|
||||||
# reading from json and writing it to mariadb
|
# reading from json and writing it to mariadb
|
||||||
# reload_doc needed here with information because new table introduced
|
# reload_doc needed here with information because new table introduced
|
||||||
frappe.reload_doc('stock', 'doctype', 'item_manufacturer')
|
frappe.reload_doc('stock', 'doctype', 'item_manufacturer')
|
||||||
# reload_doctype is a simpler concept of reload_doc
|
# reload_doctype is a simpler concept of reload_doc
|
||||||
frappe.reload_doctype('Item')
|
frappe.reload_doctype('Item')
|
||||||
|
|
||||||
item_manufacturers = frappe.get_all("Item", fields=["name", "manufacturer", "manufacturer_part_no"])
|
item_manufacturers = frappe.get_all("Item", fields=["name", "manufacturer", "manufacturer_part_no"])
|
||||||
for item in item_manufacturers:
|
for item in item_manufacturers:
|
||||||
if item.manufacturer or item.manufacturer_part_no:
|
if item.manufacturer or item.manufacturer_part_no:
|
||||||
item_doc = frappe.get_doc("Item", item.name)
|
item_doc = frappe.get_doc("Item", item.name)
|
||||||
item_doc.append("manufacturers", {
|
item_doc.append("manufacturers", {
|
||||||
"manufacturer": item.manufacturer,
|
"manufacturer": item.manufacturer,
|
||||||
"manufacturer_part_no": item.manufacturer_part_no
|
"manufacturer_part_no": item.manufacturer_part_no
|
||||||
})
|
})
|
||||||
item_doc.flags.ignore_validate = True
|
|
||||||
item_doc.flags.ignore_mandatory = True
|
item_doc.get("manufacturers")[0].db_update()
|
||||||
item_doc.save()
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
from frappe.model.utils.rename_field import rename_field
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
|
||||||
|
doc_list = ["Purchase Invoice Item", "Stock Entry Detail", "Delivery Note Item",
|
||||||
|
"Purchase Receipt Item", "Sales Invoice Item"]
|
||||||
|
|
||||||
|
for doctype in doc_list:
|
||||||
|
frappe.reload_doctype(doctype)
|
||||||
|
rename_field(doctype, "is_sample_item", "allow_zero_valuation_rate")
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Copyright (c) 2017, Frappe and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
frappe.reload_doc('accounts', 'doctype', 'purchase_invoice_item')
|
||||||
|
frappe.db.sql("update `tabPurchase Invoice Item` set stock_qty = qty, stock_uom = uom")
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# Copyright (c) 2017, Frappe and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
# copy supplier_address to address_display, and set supplier_address to blank
|
||||||
|
|
||||||
|
stock_entries = frappe.db.sql(""" select name, purchase_order, supplier_address from `tabStock Entry`
|
||||||
|
where ifnull(supplier_address, '') <> ''""", as_dict=True)
|
||||||
|
|
||||||
|
frappe.reload_doc('stock', 'doctype', 'stock_entry')
|
||||||
|
|
||||||
|
for stock_entry in stock_entries:
|
||||||
|
# move supplier address to address_display, and fetch the supplier address from purchase order
|
||||||
|
|
||||||
|
se = frappe.get_doc("Stock Entry", stock_entry.get("name"))
|
||||||
|
se.address_display = stock_entry.get("supplier_address")
|
||||||
|
se.supplier_address = frappe.db.get_value("Purchase Order", stock_entry.get("purchase_order"),"supplier_address") or None
|
||||||
|
|
||||||
|
se.db_update()
|
||||||