mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-19 21:19:19 +00:00
Merge branch 'version-12-hotfix' into patch-3
This commit is contained in:
@@ -40,8 +40,7 @@ install:
|
|||||||
- cd ~
|
- cd ~
|
||||||
- nvm install 10
|
- nvm install 10
|
||||||
|
|
||||||
- git clone https://github.com/frappe/bench --depth 1
|
- pip install -U frappe-bench --only-binary='all'
|
||||||
- pip install -e ./bench
|
|
||||||
|
|
||||||
- git clone https://github.com/frappe/frappe --branch $TRAVIS_BRANCH --depth 1
|
- git clone https://github.com/frappe/frappe --branch $TRAVIS_BRANCH --depth 1
|
||||||
- bench init --skip-assets --frappe-path ~/frappe --python $(which python) frappe-bench
|
- bench init --skip-assets --frappe-path ~/frappe --python $(which python) frappe-bench
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import frappe
|
|||||||
from erpnext.hooks import regional_overrides
|
from erpnext.hooks import regional_overrides
|
||||||
from frappe.utils import getdate
|
from frappe.utils import getdate
|
||||||
|
|
||||||
__version__ = '12.21.0'
|
__version__ = '12.23.0'
|
||||||
|
|
||||||
def get_default_company(user=None):
|
def get_default_company(user=None):
|
||||||
'''Get default company for user'''
|
'''Get default company for user'''
|
||||||
|
|||||||
@@ -109,5 +109,4 @@ erpnext.integrations.refreshPlaidLink = class refreshPlaidLink {
|
|||||||
plaid_success(token, response) {
|
plaid_success(token, response) {
|
||||||
frappe.show_alert({ message: __('Plaid Link Updated'), indicator: 'green' });
|
frappe.show_alert({ message: __('Plaid Link Updated'), indicator: 'green' });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -7,19 +7,19 @@ DEFAULT_MAPPERS = [
|
|||||||
'section_header': 'Cash flows from operating activities',
|
'section_header': 'Cash flows from operating activities',
|
||||||
'section_leader': 'Adjustments for',
|
'section_leader': 'Adjustments for',
|
||||||
'section_name': 'Operating Activities',
|
'section_name': 'Operating Activities',
|
||||||
'position': 0,
|
'position': 1,
|
||||||
'section_subtotal': 'Cash generated from operations',
|
'section_subtotal': 'Cash generated from operations',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'doctype': 'Cash Flow Mapper',
|
'doctype': 'Cash Flow Mapper',
|
||||||
'position': 1,
|
'position': 2,
|
||||||
'section_footer': 'Net cash used in investing activities',
|
'section_footer': 'Net cash used in investing activities',
|
||||||
'section_header': 'Cash flows from investing activities',
|
'section_header': 'Cash flows from investing activities',
|
||||||
'section_name': 'Investing Activities'
|
'section_name': 'Investing Activities'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'doctype': 'Cash Flow Mapper',
|
'doctype': 'Cash Flow Mapper',
|
||||||
'position': 2,
|
'position': 3,
|
||||||
'section_footer': 'Net cash used in financing activites',
|
'section_footer': 'Net cash used in financing activites',
|
||||||
'section_header': 'Cash flows from financing activities',
|
'section_header': 'Cash flows from financing activities',
|
||||||
'section_name': 'Financing Activities',
|
'section_name': 'Financing Activities',
|
||||||
|
|||||||
@@ -81,10 +81,11 @@ class ExchangeRateRevaluation(Document):
|
|||||||
sum(debit) - sum(credit) as balance
|
sum(debit) - sum(credit) as balance
|
||||||
from `tabGL Entry`
|
from `tabGL Entry`
|
||||||
where account in (%s)
|
where account in (%s)
|
||||||
group by account, party_type, party
|
and posting_date <= %s
|
||||||
|
group by account, NULLIF(party_type,''), NULLIF(party,'')
|
||||||
having sum(debit) != sum(credit)
|
having sum(debit) != sum(credit)
|
||||||
order by account
|
order by account
|
||||||
""" % ', '.join(['%s']*len(accounts)), tuple(accounts), as_dict=1)
|
""" % (', '.join(['%s']*len(accounts)), '%s'), tuple(accounts + [self.posting_date]), as_dict=1)
|
||||||
|
|
||||||
return account_details
|
return account_details
|
||||||
|
|
||||||
@@ -124,9 +125,9 @@ class ExchangeRateRevaluation(Document):
|
|||||||
"party_type": d.get("party_type"),
|
"party_type": d.get("party_type"),
|
||||||
"party": d.get("party"),
|
"party": d.get("party"),
|
||||||
"account_currency": d.get("account_currency"),
|
"account_currency": d.get("account_currency"),
|
||||||
"balance": d.get("balance_in_account_currency"),
|
"balance": flt(d.get("balance_in_account_currency"), d.precision("balance_in_account_currency")),
|
||||||
dr_or_cr: abs(d.get("balance_in_account_currency")),
|
dr_or_cr: flt(abs(d.get("balance_in_account_currency")), d.precision("balance_in_account_currency")),
|
||||||
"exchange_rate":d.get("new_exchange_rate"),
|
"exchange_rate": flt(d.get("new_exchange_rate"), d.precision("new_exchange_rate")),
|
||||||
"reference_type": "Exchange Rate Revaluation",
|
"reference_type": "Exchange Rate Revaluation",
|
||||||
"reference_name": self.name,
|
"reference_name": self.name,
|
||||||
})
|
})
|
||||||
@@ -135,9 +136,9 @@ class ExchangeRateRevaluation(Document):
|
|||||||
"party_type": d.get("party_type"),
|
"party_type": d.get("party_type"),
|
||||||
"party": d.get("party"),
|
"party": d.get("party"),
|
||||||
"account_currency": d.get("account_currency"),
|
"account_currency": d.get("account_currency"),
|
||||||
"balance": d.get("balance_in_account_currency"),
|
"balance": flt(d.get("balance_in_account_currency"), d.precision("balance_in_account_currency")),
|
||||||
reverse_dr_or_cr: abs(d.get("balance_in_account_currency")),
|
reverse_dr_or_cr: flt(abs(d.get("balance_in_account_currency")), d.precision("balance_in_account_currency")),
|
||||||
"exchange_rate": d.get("current_exchange_rate"),
|
"exchange_rate": flt(d.get("current_exchange_rate"), d.precision("current_exchange_rate")),
|
||||||
"reference_type": "Exchange Rate Revaluation",
|
"reference_type": "Exchange Rate Revaluation",
|
||||||
"reference_name": self.name
|
"reference_name": self.name
|
||||||
})
|
})
|
||||||
@@ -166,9 +167,9 @@ def get_account_details(account, company, posting_date, party_type=None, party=N
|
|||||||
|
|
||||||
account_details = {}
|
account_details = {}
|
||||||
company_currency = erpnext.get_company_currency(company)
|
company_currency = erpnext.get_company_currency(company)
|
||||||
balance = get_balance_on(account, party_type=party_type, party=party, in_account_currency=False)
|
balance = get_balance_on(account, date=posting_date, party_type=party_type, party=party, in_account_currency=False)
|
||||||
if balance:
|
if balance:
|
||||||
balance_in_account_currency = get_balance_on(account, party_type=party_type, party=party)
|
balance_in_account_currency = get_balance_on(account, date=posting_date, party_type=party_type, party=party)
|
||||||
current_exchange_rate = balance / balance_in_account_currency if balance_in_account_currency else 0
|
current_exchange_rate = balance / balance_in_account_currency if balance_in_account_currency else 0
|
||||||
new_exchange_rate = get_exchange_rate(account_currency, company_currency, posting_date)
|
new_exchange_rate = get_exchange_rate(account_currency, company_currency, posting_date)
|
||||||
new_balance_in_base_currency = balance_in_account_currency * new_exchange_rate
|
new_balance_in_base_currency = balance_in_account_currency * new_exchange_rate
|
||||||
|
|||||||
@@ -97,8 +97,7 @@ class GLEntry(Document):
|
|||||||
|
|
||||||
def check_pl_account(self):
|
def check_pl_account(self):
|
||||||
if self.is_opening=='Yes' and \
|
if self.is_opening=='Yes' and \
|
||||||
frappe.db.get_value("Account", self.account, "report_type")=="Profit and Loss" and \
|
frappe.db.get_value("Account", self.account, "report_type")=="Profit and Loss":
|
||||||
self.voucher_type not in ['Purchase Invoice', 'Sales Invoice']:
|
|
||||||
frappe.throw(_("{0} {1}: 'Profit and Loss' type account {2} not allowed in Opening Entry")
|
frappe.throw(_("{0} {1}: 'Profit and Loss' type account {2} not allowed in Opening Entry")
|
||||||
.format(self.voucher_type, self.voucher_no, self.account))
|
.format(self.voucher_type, self.voucher_no, self.account))
|
||||||
|
|
||||||
|
|||||||
@@ -1041,18 +1041,10 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
},
|
},
|
||||||
callback: function(r, rt) {
|
callback: function(r, rt) {
|
||||||
if(r.message) {
|
if(r.message) {
|
||||||
frappe.run_serially([
|
|
||||||
() => {
|
|
||||||
frm.set_value("paid_from_account_balance", r.message.paid_from_account_balance);
|
frm.set_value("paid_from_account_balance", r.message.paid_from_account_balance);
|
||||||
frm.set_value("paid_to_account_balance", r.message.paid_to_account_balance);
|
frm.set_value("paid_to_account_balance", r.message.paid_to_account_balance);
|
||||||
frm.set_value("party_balance", r.message.party_balance);
|
frm.set_value("party_balance", r.message.party_balance);
|
||||||
},
|
|
||||||
() => {
|
|
||||||
if(frm.doc.payment_type != "Internal") {
|
|
||||||
frm.clear_table("references");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,283 +1,95 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"actions": [],
|
||||||
"allow_guest_to_view": 0,
|
"autoname": "ACC-PCV-.YYYY.-.#####",
|
||||||
"allow_import": 0,
|
"creation": "2013-01-10 16:34:07",
|
||||||
"allow_rename": 0,
|
"doctype": "DocType",
|
||||||
"autoname": "ACC-PCV-.YYYY.-.#####",
|
"engine": "InnoDB",
|
||||||
"beta": 0,
|
"field_order": [
|
||||||
"creation": "2013-01-10 16:34:07",
|
"transaction_date",
|
||||||
"custom": 0,
|
"posting_date",
|
||||||
"docstatus": 0,
|
"fiscal_year",
|
||||||
"doctype": "DocType",
|
"amended_from",
|
||||||
"editable_grid": 0,
|
"company",
|
||||||
"engine": "InnoDB",
|
"cost_center_wise_pnl",
|
||||||
|
"column_break1",
|
||||||
|
"closing_account_head",
|
||||||
|
"remarks"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "transaction_date",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Date",
|
||||||
"allow_on_submit": 0,
|
"label": "Transaction Date",
|
||||||
"bold": 0,
|
"oldfieldname": "transaction_date",
|
||||||
"collapsible": 0,
|
"oldfieldtype": "Date"
|
||||||
"columns": 0,
|
},
|
||||||
"fieldname": "transaction_date",
|
|
||||||
"fieldtype": "Date",
|
|
||||||
"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": "Transaction Date",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"oldfieldname": "transaction_date",
|
|
||||||
"oldfieldtype": "Date",
|
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "posting_date",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Date",
|
||||||
"allow_on_submit": 0,
|
"label": "Posting Date",
|
||||||
"bold": 0,
|
"oldfieldname": "posting_date",
|
||||||
"collapsible": 0,
|
"oldfieldtype": "Date",
|
||||||
"columns": 0,
|
"reqd": 1
|
||||||
"fieldname": "posting_date",
|
},
|
||||||
"fieldtype": "Date",
|
|
||||||
"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": "Posting Date",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"oldfieldname": "posting_date",
|
|
||||||
"oldfieldtype": "Date",
|
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "fiscal_year",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Link",
|
||||||
"allow_on_submit": 0,
|
"in_list_view": 1,
|
||||||
"bold": 0,
|
"in_standard_filter": 1,
|
||||||
"collapsible": 0,
|
"label": "Closing Fiscal Year",
|
||||||
"columns": 0,
|
"oldfieldname": "fiscal_year",
|
||||||
"fieldname": "fiscal_year",
|
"oldfieldtype": "Select",
|
||||||
"fieldtype": "Link",
|
"options": "Fiscal Year",
|
||||||
"hidden": 0,
|
"reqd": 1
|
||||||
"ignore_user_permissions": 0,
|
},
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 1,
|
|
||||||
"label": "Closing Fiscal Year",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"oldfieldname": "fiscal_year",
|
|
||||||
"oldfieldtype": "Select",
|
|
||||||
"options": "Fiscal Year",
|
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "amended_from",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Link",
|
||||||
"allow_on_submit": 0,
|
"ignore_user_permissions": 1,
|
||||||
"bold": 0,
|
"label": "Amended From",
|
||||||
"collapsible": 0,
|
"no_copy": 1,
|
||||||
"columns": 0,
|
"oldfieldname": "amended_from",
|
||||||
"fieldname": "amended_from",
|
"oldfieldtype": "Data",
|
||||||
"fieldtype": "Link",
|
"options": "Period Closing Voucher",
|
||||||
"hidden": 0,
|
"read_only": 1
|
||||||
"ignore_user_permissions": 1,
|
},
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Amended From",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
|
||||||
"oldfieldname": "amended_from",
|
|
||||||
"oldfieldtype": "Data",
|
|
||||||
"options": "Period Closing Voucher",
|
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "company",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Link",
|
||||||
"allow_on_submit": 0,
|
"label": "Company",
|
||||||
"bold": 0,
|
"oldfieldname": "company",
|
||||||
"collapsible": 0,
|
"oldfieldtype": "Select",
|
||||||
"columns": 0,
|
"options": "Company",
|
||||||
"fieldname": "company",
|
"reqd": 1
|
||||||
"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": "Company",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"oldfieldname": "company",
|
|
||||||
"oldfieldtype": "Select",
|
|
||||||
"options": "Company",
|
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "column_break1",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Column Break",
|
||||||
"allow_on_submit": 0,
|
"oldfieldtype": "Column Break"
|
||||||
"bold": 0,
|
},
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break1",
|
|
||||||
"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,
|
|
||||||
"oldfieldtype": "Column Break",
|
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"description": "The account head under Liability or Equity, in which Profit/Loss will be booked",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldname": "closing_account_head",
|
||||||
"allow_on_submit": 0,
|
"fieldtype": "Link",
|
||||||
"bold": 0,
|
"label": "Closing Account Head",
|
||||||
"collapsible": 0,
|
"oldfieldname": "closing_account_head",
|
||||||
"columns": 0,
|
"oldfieldtype": "Link",
|
||||||
"description": "The account head under Liability or Equity, in which Profit/Loss will be booked",
|
"options": "Account",
|
||||||
"fieldname": "closing_account_head",
|
"reqd": 1
|
||||||
"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": "Closing Account Head",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"oldfieldname": "closing_account_head",
|
|
||||||
"oldfieldtype": "Link",
|
|
||||||
"options": "Account",
|
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "remarks",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Small Text",
|
||||||
"allow_on_submit": 0,
|
"label": "Remarks",
|
||||||
"bold": 0,
|
"oldfieldname": "remarks",
|
||||||
"collapsible": 0,
|
"oldfieldtype": "Small Text",
|
||||||
"columns": 0,
|
"reqd": 1
|
||||||
"fieldname": "remarks",
|
},
|
||||||
"fieldtype": "Small Text",
|
{
|
||||||
"hidden": 0,
|
"default": "0",
|
||||||
"ignore_user_permissions": 0,
|
"fieldname": "cost_center_wise_pnl",
|
||||||
"ignore_xss_filter": 0,
|
"fieldtype": "Check",
|
||||||
"in_filter": 0,
|
"label": "Book Cost Center-Wise Profit/Loss"
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Remarks",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"oldfieldname": "remarks",
|
|
||||||
"oldfieldtype": "Small Text",
|
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
"has_web_view": 0,
|
||||||
@@ -291,60 +103,43 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2018-08-21 16:15:49.089450",
|
"modified": "2021-05-20 15:27:37.210458",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Period Closing Voucher",
|
"name": "Period Closing Voucher",
|
||||||
"owner": "jai@webnotestech.com",
|
"owner": "jai@webnotestech.com",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
"amend": 1,
|
"amend": 1,
|
||||||
"cancel": 1,
|
"cancel": 1,
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 0,
|
"print": 1,
|
||||||
"if_owner": 0,
|
"read": 1,
|
||||||
"import": 0,
|
"report": 1,
|
||||||
"permlevel": 0,
|
"role": "System Manager",
|
||||||
"print": 1,
|
"share": 1,
|
||||||
"read": 1,
|
"submit": 1,
|
||||||
"report": 1,
|
|
||||||
"role": "System Manager",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 1,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 1,
|
"amend": 1,
|
||||||
"cancel": 1,
|
"cancel": 1,
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 0,
|
"print": 1,
|
||||||
"if_owner": 0,
|
"read": 1,
|
||||||
"import": 0,
|
"report": 1,
|
||||||
"permlevel": 0,
|
"role": "Accounts Manager",
|
||||||
"print": 1,
|
"share": 1,
|
||||||
"read": 1,
|
"submit": 1,
|
||||||
"report": 1,
|
|
||||||
"role": "Accounts Manager",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 1,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 0,
|
"search_fields": "posting_date, fiscal_year",
|
||||||
"read_only": 0,
|
"sort_field": "modified",
|
||||||
"read_only_onload": 0,
|
"sort_order": "DESC",
|
||||||
"search_fields": "posting_date, fiscal_year",
|
"title_field": "closing_account_head"
|
||||||
"show_name_in_global_search": 0,
|
|
||||||
"sort_field": "modified",
|
|
||||||
"sort_order": "DESC",
|
|
||||||
"title_field": "closing_account_head",
|
|
||||||
"track_changes": 0,
|
|
||||||
"track_seen": 0,
|
|
||||||
"track_views": 0
|
|
||||||
}
|
}
|
||||||
@@ -50,63 +50,96 @@ class PeriodClosingVoucher(AccountsController):
|
|||||||
|
|
||||||
def make_gl_entries(self):
|
def make_gl_entries(self):
|
||||||
gl_entries = []
|
gl_entries = []
|
||||||
net_pl_balance = 0
|
net_pl_balance = 0
|
||||||
dimension_fields = ['t1.cost_center']
|
|
||||||
|
|
||||||
accounting_dimensions = get_accounting_dimensions()
|
pl_accounts = self.get_pl_balances()
|
||||||
for dimension in accounting_dimensions:
|
|
||||||
dimension_fields.append('t1.{0}'.format(dimension))
|
|
||||||
|
|
||||||
dimension_filters, default_dimensions = get_dimension_filters()
|
|
||||||
|
|
||||||
pl_accounts = self.get_pl_balances(dimension_fields)
|
|
||||||
|
|
||||||
for acc in pl_accounts:
|
for acc in pl_accounts:
|
||||||
if flt(acc.balance_in_company_currency):
|
if flt(acc.bal_in_company_currency):
|
||||||
gl_entries.append(self.get_gl_dict({
|
gl_entries.append(self.get_gl_dict({
|
||||||
"account": acc.account,
|
"account": acc.account,
|
||||||
"cost_center": acc.cost_center,
|
"cost_center": acc.cost_center,
|
||||||
"account_currency": acc.account_currency,
|
"account_currency": acc.account_currency,
|
||||||
"debit_in_account_currency": abs(flt(acc.balance_in_account_currency)) \
|
"debit_in_account_currency": abs(flt(acc.bal_in_account_currency)) if flt(acc.bal_in_account_currency) < 0 else 0,
|
||||||
if flt(acc.balance_in_account_currency) < 0 else 0,
|
"debit": abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) < 0 else 0,
|
||||||
"debit": abs(flt(acc.balance_in_company_currency)) \
|
"credit_in_account_currency": abs(flt(acc.bal_in_account_currency)) if flt(acc.bal_in_account_currency) > 0 else 0,
|
||||||
if flt(acc.balance_in_company_currency) < 0 else 0,
|
"credit": abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) > 0 else 0
|
||||||
"credit_in_account_currency": abs(flt(acc.balance_in_account_currency)) \
|
|
||||||
if flt(acc.balance_in_account_currency) > 0 else 0,
|
|
||||||
"credit": abs(flt(acc.balance_in_company_currency)) \
|
|
||||||
if flt(acc.balance_in_company_currency) > 0 else 0
|
|
||||||
}, item=acc))
|
}, item=acc))
|
||||||
|
|
||||||
net_pl_balance += flt(acc.balance_in_company_currency)
|
net_pl_balance += flt(acc.bal_in_company_currency)
|
||||||
|
|
||||||
if net_pl_balance:
|
if net_pl_balance:
|
||||||
cost_center = frappe.db.get_value("Company", self.company, "cost_center")
|
if self.cost_center_wise_pnl:
|
||||||
gl_entry = self.get_gl_dict({
|
costcenter_wise_gl_entries = self.get_costcenter_wise_pnl_gl_entries(pl_accounts)
|
||||||
"account": self.closing_account_head,
|
gl_entries += costcenter_wise_gl_entries
|
||||||
"debit_in_account_currency": abs(net_pl_balance) if net_pl_balance > 0 else 0,
|
else:
|
||||||
"debit": abs(net_pl_balance) if net_pl_balance > 0 else 0,
|
gl_entry = self.get_pnl_gl_entry(net_pl_balance)
|
||||||
"credit_in_account_currency": abs(net_pl_balance) if net_pl_balance < 0 else 0,
|
gl_entries.append(gl_entry)
|
||||||
"credit": abs(net_pl_balance) if net_pl_balance < 0 else 0,
|
|
||||||
"cost_center": cost_center
|
|
||||||
})
|
|
||||||
|
|
||||||
for dimension in accounting_dimensions:
|
|
||||||
gl_entry.update({
|
|
||||||
dimension: default_dimensions.get(self.company, {}).get(dimension)
|
|
||||||
})
|
|
||||||
|
|
||||||
gl_entries.append(gl_entry)
|
|
||||||
|
|
||||||
from erpnext.accounts.general_ledger import make_gl_entries
|
from erpnext.accounts.general_ledger import make_gl_entries
|
||||||
make_gl_entries(gl_entries)
|
make_gl_entries(gl_entries)
|
||||||
|
|
||||||
|
def get_pnl_gl_entry(self, net_pl_balance):
|
||||||
|
cost_center = frappe.db.get_value("Company", self.company, "cost_center")
|
||||||
|
gl_entry = self.get_gl_dict({
|
||||||
|
"account": self.closing_account_head,
|
||||||
|
"debit_in_account_currency": abs(net_pl_balance) if net_pl_balance > 0 else 0,
|
||||||
|
"debit": abs(net_pl_balance) if net_pl_balance > 0 else 0,
|
||||||
|
"credit_in_account_currency": abs(net_pl_balance) if net_pl_balance < 0 else 0,
|
||||||
|
"credit": abs(net_pl_balance) if net_pl_balance < 0 else 0,
|
||||||
|
"cost_center": cost_center
|
||||||
|
})
|
||||||
|
|
||||||
|
self.update_default_dimensions(gl_entry)
|
||||||
|
|
||||||
|
return gl_entry
|
||||||
|
|
||||||
|
def get_costcenter_wise_pnl_gl_entries(self, pl_accounts):
|
||||||
|
company_cost_center = frappe.db.get_value("Company", self.company, "cost_center")
|
||||||
|
gl_entries = []
|
||||||
|
|
||||||
|
for acc in pl_accounts:
|
||||||
|
if flt(acc.bal_in_company_currency):
|
||||||
|
gl_entry = self.get_gl_dict({
|
||||||
|
"account": self.closing_account_head,
|
||||||
|
"cost_center": acc.cost_center or company_cost_center,
|
||||||
|
"account_currency": acc.account_currency,
|
||||||
|
"debit_in_account_currency": abs(flt(acc.bal_in_account_currency)) if flt(acc.bal_in_account_currency) > 0 else 0,
|
||||||
|
"debit": abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) > 0 else 0,
|
||||||
|
"credit_in_account_currency": abs(flt(acc.bal_in_account_currency)) if flt(acc.bal_in_account_currency) < 0 else 0,
|
||||||
|
"credit": abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) < 0 else 0
|
||||||
|
}, item=acc)
|
||||||
|
|
||||||
|
self.update_default_dimensions(gl_entry)
|
||||||
|
|
||||||
|
gl_entries.append(gl_entry)
|
||||||
|
|
||||||
|
return gl_entries
|
||||||
|
|
||||||
|
def update_default_dimensions(self, gl_entry):
|
||||||
|
if not self.accounting_dimensions:
|
||||||
|
self.accounting_dimensions = get_accounting_dimensions()
|
||||||
|
|
||||||
|
_, default_dimensions = get_dimension_filters()
|
||||||
|
for dimension in self.accounting_dimensions:
|
||||||
|
gl_entry.update({
|
||||||
|
dimension: default_dimensions.get(self.company, {}).get(dimension)
|
||||||
|
})
|
||||||
|
|
||||||
|
def get_pl_balances(self):
|
||||||
|
"""Get balance for dimension-wise pl accounts"""
|
||||||
|
|
||||||
|
dimension_fields = ['t1.cost_center']
|
||||||
|
|
||||||
|
self.accounting_dimensions = get_accounting_dimensions()
|
||||||
|
for dimension in self.accounting_dimensions:
|
||||||
|
dimension_fields.append('t1.{0}'.format(dimension))
|
||||||
|
|
||||||
def get_pl_balances(self, dimension_fields):
|
|
||||||
"""Get balance for pl accounts"""
|
|
||||||
return frappe.db.sql("""
|
return frappe.db.sql("""
|
||||||
select
|
select
|
||||||
t1.account, t2.account_currency, {dimension_fields},
|
t1.account, t2.account_currency, {dimension_fields},
|
||||||
sum(t1.debit_in_account_currency) - sum(t1.credit_in_account_currency) as balance_in_account_currency,
|
sum(t1.debit_in_account_currency) - sum(t1.credit_in_account_currency) as bal_in_account_currency,
|
||||||
sum(t1.debit) - sum(t1.credit) as balance_in_company_currency
|
sum(t1.debit) - sum(t1.credit) as bal_in_company_currency
|
||||||
from `tabGL Entry` t1, `tabAccount` t2
|
from `tabGL Entry` t1, `tabAccount` t2
|
||||||
where t1.account = t2.name and t2.report_type = 'Profit and Loss'
|
where t1.account = t2.name and t2.report_type = 'Profit and Loss'
|
||||||
and t2.docstatus < 2 and t2.company = %s
|
and t2.docstatus < 2 and t2.company = %s
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import frappe
|
|||||||
from frappe.utils import flt, today
|
from frappe.utils import flt, today
|
||||||
from erpnext.accounts.utils import get_fiscal_year, now
|
from erpnext.accounts.utils import get_fiscal_year, now
|
||||||
from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
|
from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
|
||||||
|
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
||||||
|
|
||||||
class TestPeriodClosingVoucher(unittest.TestCase):
|
class TestPeriodClosingVoucher(unittest.TestCase):
|
||||||
def test_closing_entry(self):
|
def test_closing_entry(self):
|
||||||
@@ -65,6 +66,58 @@ class TestPeriodClosingVoucher(unittest.TestCase):
|
|||||||
self.assertEqual(gle_for_random_expense_account[0].amount_in_account_currency,
|
self.assertEqual(gle_for_random_expense_account[0].amount_in_account_currency,
|
||||||
-1*random_expense_account[0].balance_in_account_currency)
|
-1*random_expense_account[0].balance_in_account_currency)
|
||||||
|
|
||||||
|
def test_cost_center_wise_posting(self):
|
||||||
|
frappe.db.sql("delete from `tabGL Entry` where company='Test PCV Company'")
|
||||||
|
|
||||||
|
company = create_company()
|
||||||
|
surplus_account = create_account()
|
||||||
|
|
||||||
|
cost_center1 = create_cost_center("Test Cost Center 1")
|
||||||
|
cost_center2 = create_cost_center("Test Cost Center 2")
|
||||||
|
|
||||||
|
create_sales_invoice(
|
||||||
|
company=company,
|
||||||
|
cost_center=cost_center1,
|
||||||
|
income_account="Sales - TPC",
|
||||||
|
expense_account="Cost of Goods Sold - TPC",
|
||||||
|
rate=400,
|
||||||
|
debit_to="Debtors - TPC"
|
||||||
|
)
|
||||||
|
create_sales_invoice(
|
||||||
|
company=company,
|
||||||
|
cost_center=cost_center2,
|
||||||
|
income_account="Sales - TPC",
|
||||||
|
expense_account="Cost of Goods Sold - TPC",
|
||||||
|
rate=200,
|
||||||
|
debit_to="Debtors - TPC"
|
||||||
|
)
|
||||||
|
|
||||||
|
pcv = frappe.get_doc({
|
||||||
|
"transaction_date": today(),
|
||||||
|
"posting_date": today(),
|
||||||
|
"fiscal_year": get_fiscal_year(today())[0],
|
||||||
|
"company": "Test PCV Company",
|
||||||
|
"cost_center_wise_pnl": 1,
|
||||||
|
"closing_account_head": surplus_account,
|
||||||
|
"remarks": "Test",
|
||||||
|
"doctype": "Period Closing Voucher"
|
||||||
|
})
|
||||||
|
pcv.insert()
|
||||||
|
pcv.submit()
|
||||||
|
|
||||||
|
expected_gle = (
|
||||||
|
('Sales - TPC', 200.0, 0.0, cost_center2),
|
||||||
|
(surplus_account, 0.0, 200.0, cost_center2),
|
||||||
|
('Sales - TPC', 400.0, 0.0, cost_center1),
|
||||||
|
(surplus_account, 0.0, 400.0, cost_center1)
|
||||||
|
)
|
||||||
|
|
||||||
|
pcv_gle = frappe.db.sql("""
|
||||||
|
select account, debit, credit, cost_center from `tabGL Entry` where voucher_no=%s
|
||||||
|
""", (pcv.name))
|
||||||
|
|
||||||
|
self.assertTrue(pcv_gle, expected_gle)
|
||||||
|
|
||||||
def make_period_closing_voucher(self):
|
def make_period_closing_voucher(self):
|
||||||
pcv = frappe.get_doc({
|
pcv = frappe.get_doc({
|
||||||
"doctype": "Period Closing Voucher",
|
"doctype": "Period Closing Voucher",
|
||||||
@@ -80,6 +133,38 @@ class TestPeriodClosingVoucher(unittest.TestCase):
|
|||||||
|
|
||||||
return pcv
|
return pcv
|
||||||
|
|
||||||
|
def create_company():
|
||||||
|
company = frappe.get_doc({
|
||||||
|
'doctype': 'Company',
|
||||||
|
'company_name': "Test PCV Company",
|
||||||
|
'country': 'United States',
|
||||||
|
'default_currency': 'USD'
|
||||||
|
})
|
||||||
|
company.insert(ignore_if_duplicate = True)
|
||||||
|
return company.name
|
||||||
|
|
||||||
|
def create_account():
|
||||||
|
account = frappe.get_doc({
|
||||||
|
"account_name": "Reserve and Surplus",
|
||||||
|
"is_group": 0,
|
||||||
|
"company": "Test PCV Company",
|
||||||
|
"root_type": "Liability",
|
||||||
|
"report_type": "Balance Sheet",
|
||||||
|
"account_currency": "USD",
|
||||||
|
"parent_account": "Current Liabilities - TPC",
|
||||||
|
"doctype": "Account"
|
||||||
|
}).insert(ignore_if_duplicate = True)
|
||||||
|
return account.name
|
||||||
|
|
||||||
|
def create_cost_center(cc_name):
|
||||||
|
costcenter = frappe.get_doc({
|
||||||
|
"company": "Test PCV Company",
|
||||||
|
"cost_center_name": cc_name,
|
||||||
|
"doctype": "Cost Center",
|
||||||
|
"parent_cost_center": "Test PCV Company - TPC"
|
||||||
|
})
|
||||||
|
costcenter.insert(ignore_if_duplicate = True)
|
||||||
|
return costcenter.name
|
||||||
|
|
||||||
test_dependencies = ["Customer", "Cost Center"]
|
test_dependencies = ["Customer", "Cost Center"]
|
||||||
test_records = frappe.get_test_records("Period Closing Voucher")
|
test_records = frappe.get_test_records("Period Closing Voucher")
|
||||||
|
|||||||
@@ -450,7 +450,7 @@ class SalesInvoice(SellingController):
|
|||||||
# set pos values in items
|
# set pos values in items
|
||||||
for item in self.get("items"):
|
for item in self.get("items"):
|
||||||
if item.get('item_code'):
|
if item.get('item_code'):
|
||||||
profile_details = get_pos_profile_item_details(pos, frappe._dict(item.as_dict()), pos)
|
profile_details = get_pos_profile_item_details(pos, frappe._dict(item.as_dict()), pos, update_data=True)
|
||||||
for fname, val in iteritems(profile_details):
|
for fname, val in iteritems(profile_details):
|
||||||
if (not for_validate) or (for_validate and not item.get(fname)):
|
if (not for_validate) or (for_validate and not item.get(fname)):
|
||||||
item.set(fname, val)
|
item.set(fname, val)
|
||||||
@@ -539,7 +539,7 @@ class SalesInvoice(SellingController):
|
|||||||
def add_remarks(self):
|
def add_remarks(self):
|
||||||
if not self.remarks:
|
if not self.remarks:
|
||||||
if self.po_no and self.po_date:
|
if self.po_no and self.po_date:
|
||||||
self.remarks = _("Against Customer Order {0} dated {1}").format(self.po_no,
|
self.remarks = _("Against Customer Order {0} dated {1}").format(self.po_no,
|
||||||
formatdate(self.po_date))
|
formatdate(self.po_date))
|
||||||
else:
|
else:
|
||||||
self.remarks = _("No Remarks")
|
self.remarks = _("No Remarks")
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
"additional_discount_percentage",
|
"additional_discount_percentage",
|
||||||
"additional_discount_amount",
|
"additional_discount_amount",
|
||||||
"sb_3",
|
"sb_3",
|
||||||
|
"submit_invoice",
|
||||||
"invoices",
|
"invoices",
|
||||||
"accounting_dimensions_section",
|
"accounting_dimensions_section",
|
||||||
"dimension_col_break"
|
"dimension_col_break"
|
||||||
@@ -202,9 +203,15 @@
|
|||||||
"fieldname": "generate_new_invoices_past_due_date",
|
"fieldname": "generate_new_invoices_past_due_date",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Generate New Invoices Past Due Date"
|
"label": "Generate New Invoices Past Due Date"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "1",
|
||||||
|
"fieldname": "submit_invoice",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Submit Invoice Automatically"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"modified": "2020-11-29 22:46:14.879289",
|
"modified": "2021-05-03 13:35:21.422940",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Subscription",
|
"name": "Subscription",
|
||||||
|
|||||||
@@ -289,7 +289,9 @@ class Subscription(Document):
|
|||||||
|
|
||||||
invoice.flags.ignore_mandatory = True
|
invoice.flags.ignore_mandatory = True
|
||||||
invoice.save()
|
invoice.save()
|
||||||
invoice.submit()
|
|
||||||
|
if self.submit_invoice:
|
||||||
|
invoice.submit()
|
||||||
|
|
||||||
return invoice
|
return invoice
|
||||||
|
|
||||||
|
|||||||
@@ -240,10 +240,10 @@ def make_round_off_gle(gl_map, debit_credit_diff, precision):
|
|||||||
for d in gl_map:
|
for d in gl_map:
|
||||||
if d.account == round_off_account:
|
if d.account == round_off_account:
|
||||||
round_off_gle = d
|
round_off_gle = d
|
||||||
if d.debit_in_account_currency:
|
if d.debit:
|
||||||
debit_credit_diff -= flt(d.debit_in_account_currency)
|
debit_credit_diff -= flt(d.debit)
|
||||||
else:
|
else:
|
||||||
debit_credit_diff += flt(d.credit_in_account_currency)
|
debit_credit_diff += flt(d.credit)
|
||||||
round_off_account_exists = True
|
round_off_account_exists = True
|
||||||
|
|
||||||
if round_off_account_exists and abs(debit_credit_diff) <= (1.0 / (10**precision)):
|
if round_off_account_exists and abs(debit_credit_diff) <= (1.0 / (10**precision)):
|
||||||
|
|||||||
@@ -355,7 +355,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
|||||||
material_request_type: "Purchase",
|
material_request_type: "Purchase",
|
||||||
docstatus: 1,
|
docstatus: 1,
|
||||||
status: ["!=", "Stopped"],
|
status: ["!=", "Stopped"],
|
||||||
per_ordered: ["<", 99.99],
|
per_ordered: ["<", 100],
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, __("Get items from"));
|
}, __("Get items from"));
|
||||||
|
|||||||
@@ -271,7 +271,7 @@ erpnext.buying.RequestforQuotationController = erpnext.buying.BuyingController.e
|
|||||||
material_request_type: "Purchase",
|
material_request_type: "Purchase",
|
||||||
docstatus: 1,
|
docstatus: 1,
|
||||||
status: ["!=", "Stopped"],
|
status: ["!=", "Stopped"],
|
||||||
per_ordered: ["<", 99.99]
|
per_ordered: ["<", 100]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, __("Get items from"));
|
}, __("Get items from"));
|
||||||
@@ -316,7 +316,7 @@ erpnext.buying.RequestforQuotationController = erpnext.buying.BuyingController.e
|
|||||||
material_request_type: "Purchase",
|
material_request_type: "Purchase",
|
||||||
docstatus: 1,
|
docstatus: 1,
|
||||||
status: ["!=", "Stopped"],
|
status: ["!=", "Stopped"],
|
||||||
per_ordered: ["<", 99.99]
|
per_ordered: ["<", 100]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$(btn).done_working();
|
$(btn).done_working();
|
||||||
|
|||||||
@@ -279,19 +279,21 @@ def add_items(sq_doc, supplier, items):
|
|||||||
create_rfq_items(sq_doc, supplier, data)
|
create_rfq_items(sq_doc, supplier, data)
|
||||||
|
|
||||||
def create_rfq_items(sq_doc, supplier, data):
|
def create_rfq_items(sq_doc, supplier, data):
|
||||||
sq_doc.append('items', {
|
args = {}
|
||||||
"item_code": data.item_code,
|
|
||||||
"item_name": data.item_name,
|
for field in ['item_code', 'item_name', 'description', 'qty', 'rate', 'conversion_factor',
|
||||||
"description": data.description,
|
'warehouse', 'material_request', 'material_request_item', 'stock_qty']:
|
||||||
"qty": data.qty,
|
args[field] = data.get(field)
|
||||||
"rate": data.rate,
|
|
||||||
"conversion_factor": data.conversion_factor if data.conversion_factor else None,
|
args.update({
|
||||||
"supplier_part_no": frappe.db.get_value("Item Supplier", {'parent': data.item_code, 'supplier': supplier}, "supplier_part_no"),
|
|
||||||
"warehouse": data.warehouse or '',
|
|
||||||
"request_for_quotation_item": data.name,
|
"request_for_quotation_item": data.name,
|
||||||
"request_for_quotation": data.parent
|
"request_for_quotation": data.parent,
|
||||||
|
"supplier_part_no": frappe.db.get_value("Item Supplier",
|
||||||
|
{'parent': data.item_code, 'supplier': supplier}, "supplier_part_no")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
sq_doc.append('items', args)
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_pdf(doctype, name, supplier_idx):
|
def get_pdf(doctype, name, supplier_idx):
|
||||||
doc = get_rfq_doc(doctype, name, supplier_idx)
|
doc = get_rfq_doc(doctype, name, supplier_idx)
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ erpnext.buying.SupplierQuotationController = erpnext.buying.BuyingController.ext
|
|||||||
material_request_type: "Purchase",
|
material_request_type: "Purchase",
|
||||||
docstatus: 1,
|
docstatus: 1,
|
||||||
status: ["!=", "Stopped"],
|
status: ["!=", "Stopped"],
|
||||||
per_ordered: ["<", 99.99]
|
per_ordered: ["<", 100]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, __("Get items from"));
|
}, __("Get items from"));
|
||||||
|
|||||||
16
erpnext/change_log/v12/v12_22_0.md
Normal file
16
erpnext/change_log/v12/v12_22_0.md
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
## Version 12.22.0 Release Notes
|
||||||
|
|
||||||
|
### Fixes & Enhancements
|
||||||
|
|
||||||
|
- Cost-center wise period closing entry ([#25930](https://github.com/frappe/erpnext/pull/25930))
|
||||||
|
- Wrong round off gl entry posted in case of purchase invoice ([#25952](https://github.com/frappe/erpnext/pull/25952))
|
||||||
|
- Sync shopify customer addresses (#25481) ([#25937](https://github.com/frappe/erpnext/pull/25937))
|
||||||
|
- Plaid NoneType error ([#25662](https://github.com/frappe/erpnext/pull/25662))
|
||||||
|
- Cashlfow mapper not showing data ([#25739](https://github.com/frappe/erpnext/pull/25739))
|
||||||
|
- Update shopify api version (#25600) ([#25939](https://github.com/frappe/erpnext/pull/25939))
|
||||||
|
- Invalid 'depends_on' expression in opportunity ([#25954](https://github.com/frappe/erpnext/pull/25954))
|
||||||
|
- Ignore rounding diff while importing JV using data import ([#25715](https://github.com/frappe/erpnext/pull/25715))
|
||||||
|
- update cost center from POS ([#25972](https://github.com/frappe/erpnext/pull/25972))
|
||||||
|
- update employee field on renaming employee ([#25958](https://github.com/frappe/erpnext/pull/25958))
|
||||||
|
- student invalid password reset link ([#25827](https://github.com/frappe/erpnext/pull/25827))
|
||||||
|
- Backward compatibility for GSTR-1 report ([#25913](https://github.com/frappe/erpnext/pull/25913))
|
||||||
20
erpnext/change_log/v12/v12_23_0.md
Normal file
20
erpnext/change_log/v12/v12_23_0.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
## Version 12.23.0 Release Notes
|
||||||
|
|
||||||
|
### Fixes & Enhancements
|
||||||
|
- Added Permissions for employee to book an appointment ([#26246](https://github.com/frappe/erpnext/pull/26246))
|
||||||
|
- New check field in subscriptions for (not) submitting invoices (BP #25394) ([#25560](https://github.com/frappe/erpnext/pull/25560))
|
||||||
|
- fix(e-invoicing): allow export invoice even if no taxes applied (#26363) ([#26406](https://github.com/frappe/erpnext/pull/26406))
|
||||||
|
- Omit item discount amount for e-invoicing (#26353) ([#26408](https://github.com/frappe/erpnext/pull/26408))
|
||||||
|
- fix(plaid): cannot reset plaid link for a bank account ([#26282](https://github.com/frappe/erpnext/pull/26282))
|
||||||
|
- Job applicant link issue ([#25935](https://github.com/frappe/erpnext/pull/25935))
|
||||||
|
- LMS progress issue ([#26254](https://github.com/frappe/erpnext/pull/26254))
|
||||||
|
- Half day to be accounted in its leave type ([#26267](https://github.com/frappe/erpnext/pull/26267))
|
||||||
|
- Material request status issue ([#26089](https://github.com/frappe/erpnext/pull/26089))
|
||||||
|
- fix(e-invoicing): service item check ([#26141](https://github.com/frappe/erpnext/pull/26141))
|
||||||
|
- Invoices can alter profit and loss of a closed year ([#26161](https://github.com/frappe/erpnext/pull/26161))
|
||||||
|
- Material request and supplier quotation not linked if supplier quotation created from supplier portal ([#26117](https://github.com/frappe/erpnext/pull/26117))
|
||||||
|
- Update positions in default cashflow mappers ([#26091](https://github.com/frappe/erpnext/pull/26091))
|
||||||
|
- Staffing plan vacancies data type issue ([#25940](https://github.com/frappe/erpnext/pull/25940))
|
||||||
|
- Added company filter while fetching loans ([#26296](https://github.com/frappe/erpnext/pull/26296))
|
||||||
|
- Serial no issue in subcontract purchase receipt ([#26423](https://github.com/frappe/erpnext/pull/26423))
|
||||||
|
- Fixed rounding off ordered percent to 100 in condition ([#26153](https://github.com/frappe/erpnext/pull/26153))
|
||||||
@@ -981,8 +981,16 @@ def get_non_stock_items(purchase_order, fg_item_code):
|
|||||||
|
|
||||||
|
|
||||||
def set_serial_nos(raw_material, consumed_serial_nos, qty):
|
def set_serial_nos(raw_material, consumed_serial_nos, qty):
|
||||||
serial_nos = set(get_serial_nos(raw_material.serial_nos)) - \
|
consumed_serial_nos_list = []
|
||||||
set(get_serial_nos(consumed_serial_nos))
|
|
||||||
|
if isinstance(consumed_serial_nos, list):
|
||||||
|
for row in consumed_serial_nos:
|
||||||
|
consumed_serial_nos_list.extend(get_serial_nos(row))
|
||||||
|
else:
|
||||||
|
consumed_serial_nos_list = get_serial_nos(row)
|
||||||
|
|
||||||
|
serial_nos = set(get_serial_nos(raw_material.serial_nos)) - set(consumed_serial_nos_list)
|
||||||
|
|
||||||
if serial_nos and qty <= len(serial_nos):
|
if serial_nos and qty <= len(serial_nos):
|
||||||
raw_material.serial_no = '\n'.join(list(serial_nos)[0:frappe.utils.cint(qty)])
|
raw_material.serial_no = '\n'.join(list(serial_nos)[0:frappe.utils.cint(qty)])
|
||||||
|
|
||||||
|
|||||||
@@ -93,7 +93,7 @@
|
|||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"modified": "2019-10-14 15:23:54.630731",
|
"modified": "2021-06-28 16:27:53.235714",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "CRM",
|
"module": "CRM",
|
||||||
"name": "Appointment",
|
"name": "Appointment",
|
||||||
@@ -144,6 +144,18 @@
|
|||||||
"role": "Sales User",
|
"role": "Sales User",
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"write": 1
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Employee",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 1,
|
"quick_entry": 1,
|
||||||
|
|||||||
@@ -277,7 +277,6 @@
|
|||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:",
|
|
||||||
"fieldname": "territory",
|
"fieldname": "territory",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Territory",
|
"label": "Territory",
|
||||||
@@ -413,7 +412,7 @@
|
|||||||
],
|
],
|
||||||
"icon": "fa fa-info-sign",
|
"icon": "fa fa-info-sign",
|
||||||
"idx": 195,
|
"idx": 195,
|
||||||
"modified": "2020-08-12 23:34:39.665513",
|
"modified": "2021-06-04 10:11:22.831139",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "CRM",
|
"module": "CRM",
|
||||||
"name": "Opportunity",
|
"name": "Opportunity",
|
||||||
|
|||||||
@@ -345,11 +345,11 @@ def get_or_create_course_enrollment(course, program):
|
|||||||
student = get_current_student()
|
student = get_current_student()
|
||||||
course_enrollment = get_enrollment("course", course, student.name)
|
course_enrollment = get_enrollment("course", course, student.name)
|
||||||
if not course_enrollment:
|
if not course_enrollment:
|
||||||
program_enrollment = get_enrollment('program', program, student.name)
|
program_enrollment = get_enrollment('program', program.name, student.name)
|
||||||
if not program_enrollment:
|
if not program_enrollment:
|
||||||
frappe.throw(_("You are not enrolled in program {0}".format(program)))
|
frappe.throw(_("You are not enrolled in program {0}".format(program)))
|
||||||
return
|
return
|
||||||
return student.enroll_in_course(course_name=course, program_enrollment=get_enrollment('program', program, student.name))
|
return student.enroll_in_course(course_name=course, program_enrollment=get_enrollment('program', program.name, student.name))
|
||||||
else:
|
else:
|
||||||
return frappe.get_doc('Course Enrollment', course_enrollment)
|
return frappe.get_doc('Course Enrollment', course_enrollment)
|
||||||
|
|
||||||
|
|||||||
@@ -99,5 +99,7 @@ class PlaidConnector():
|
|||||||
response = self.client.Transactions.get(self.access_token, start_date=start_date, end_date=end_date, offset=len(transactions))
|
response = self.client.Transactions.get(self.access_token, start_date=start_date, end_date=end_date, offset=len(transactions))
|
||||||
transactions.extend(response["transactions"])
|
transactions.extend(response["transactions"])
|
||||||
return transactions
|
return transactions
|
||||||
|
except ItemError as e:
|
||||||
|
raise e
|
||||||
except Exception:
|
except Exception:
|
||||||
frappe.log_error(frappe.get_traceback(), _("Plaid transactions sync error"))
|
frappe.log_error(frappe.get_traceback(), _("Plaid transactions sync error"))
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ frappe.ui.form.on('Plaid Settings', {
|
|||||||
frm.add_custom_button(__('Link a new bank account'), () => {
|
frm.add_custom_button(__('Link a new bank account'), () => {
|
||||||
new erpnext.integrations.plaidLink(frm);
|
new erpnext.integrations.plaidLink(frm);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
frm.add_custom_button(__('Reset Plaid Link'), () => {
|
||||||
|
new erpnext.integrations.plaidLink(frm);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ from frappe.desk.doctype.tag.tag import add_tag
|
|||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import add_months, formatdate, getdate, today
|
from frappe.utils import add_months, formatdate, getdate, today
|
||||||
|
|
||||||
|
from plaid.errors import ItemError
|
||||||
|
|
||||||
class PlaidSettings(Document):
|
class PlaidSettings(Document):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -50,7 +51,7 @@ def add_institution(token, response):
|
|||||||
})
|
})
|
||||||
bank.insert()
|
bank.insert()
|
||||||
except Exception:
|
except Exception:
|
||||||
frappe.throw(frappe.get_traceback())
|
frappe.log_error(frappe.get_traceback(), title=_('Plaid Link Error'))
|
||||||
else:
|
else:
|
||||||
bank = frappe.get_doc("Bank", response["institution"]["name"])
|
bank = frappe.get_doc("Bank", response["institution"]["name"])
|
||||||
bank.plaid_access_token = access_token
|
bank.plaid_access_token = access_token
|
||||||
@@ -82,7 +83,12 @@ def add_bank_accounts(response, bank, company):
|
|||||||
if not acc_subtype:
|
if not acc_subtype:
|
||||||
add_account_subtype(account["subtype"])
|
add_account_subtype(account["subtype"])
|
||||||
|
|
||||||
if not frappe.db.exists("Bank Account", dict(integration_id=account["id"])):
|
existing_bank_account = frappe.db.exists("Bank Account", {
|
||||||
|
'account_name': account["name"],
|
||||||
|
'bank': bank["bank_name"]
|
||||||
|
})
|
||||||
|
|
||||||
|
if not existing_bank_account:
|
||||||
try:
|
try:
|
||||||
new_account = frappe.get_doc({
|
new_account = frappe.get_doc({
|
||||||
"doctype": "Bank Account",
|
"doctype": "Bank Account",
|
||||||
@@ -102,10 +108,27 @@ def add_bank_accounts(response, bank, company):
|
|||||||
except frappe.UniqueValidationError:
|
except frappe.UniqueValidationError:
|
||||||
frappe.msgprint(_("Bank account {0} already exists and could not be created again").format(account["name"]))
|
frappe.msgprint(_("Bank account {0} already exists and could not be created again").format(account["name"]))
|
||||||
except Exception:
|
except Exception:
|
||||||
frappe.throw(frappe.get_traceback())
|
frappe.log_error(frappe.get_traceback(), title=_("Plaid Link Error"))
|
||||||
|
frappe.throw(_("There was an error creating Bank Account while linking with Plaid."),
|
||||||
|
title=_("Plaid Link Failed"))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
result.append(frappe.db.get_value("Bank Account", dict(integration_id=account["id"]), "name"))
|
try:
|
||||||
|
existing_account = frappe.get_doc('Bank Account', existing_bank_account)
|
||||||
|
existing_account.update({
|
||||||
|
"bank": bank["bank_name"],
|
||||||
|
"account_name": account["name"],
|
||||||
|
"account_type": account.get("type", ""),
|
||||||
|
"account_subtype": account.get("subtype", ""),
|
||||||
|
"mask": account.get("mask", ""),
|
||||||
|
"integration_id": account["id"]
|
||||||
|
})
|
||||||
|
existing_account.save()
|
||||||
|
result.append(existing_bank_account)
|
||||||
|
except Exception:
|
||||||
|
frappe.log_error(frappe.get_traceback(), title=_("Plaid Link Error"))
|
||||||
|
frappe.throw(_("There was an error updating Bank Account {} while linking with Plaid.").format(
|
||||||
|
existing_bank_account), title=_("Plaid Link Failed"))
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@@ -174,9 +197,16 @@ def get_transactions(bank, bank_account=None, start_date=None, end_date=None):
|
|||||||
account_id = None
|
account_id = None
|
||||||
|
|
||||||
plaid = PlaidConnector(access_token)
|
plaid = PlaidConnector(access_token)
|
||||||
transactions = plaid.get_transactions(start_date=start_date, end_date=end_date, account_id=account_id)
|
|
||||||
|
|
||||||
return transactions
|
try:
|
||||||
|
transactions = plaid.get_transactions(start_date=start_date, end_date=end_date, account_id=account_id)
|
||||||
|
except ItemError as e:
|
||||||
|
if e.code == "ITEM_LOGIN_REQUIRED":
|
||||||
|
msg = _("There was an error syncing transactions.") + " "
|
||||||
|
msg += _("Please refresh or reset the Plaid linking of the Bank {}.").format(bank) + " "
|
||||||
|
frappe.log_error(msg, title=_("Plaid Link Refresh Required"))
|
||||||
|
|
||||||
|
return transactions or []
|
||||||
|
|
||||||
|
|
||||||
def new_bank_transaction(transaction):
|
def new_bank_transaction(transaction):
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class ShopifySettings(Document):
|
|||||||
webhooks = ["orders/create", "orders/paid", "orders/fulfilled"]
|
webhooks = ["orders/create", "orders/paid", "orders/fulfilled"]
|
||||||
# url = get_shopify_url('admin/webhooks.json', self)
|
# url = get_shopify_url('admin/webhooks.json', self)
|
||||||
created_webhooks = [d.method for d in self.webhooks]
|
created_webhooks = [d.method for d in self.webhooks]
|
||||||
url = get_shopify_url('admin/api/2020-04/webhooks.json', self)
|
url = get_shopify_url('admin/api/2021-04/webhooks.json', self)
|
||||||
for method in webhooks:
|
for method in webhooks:
|
||||||
session = get_request_session()
|
session = get_request_session()
|
||||||
try:
|
try:
|
||||||
@@ -56,7 +56,7 @@ class ShopifySettings(Document):
|
|||||||
deleted_webhooks = []
|
deleted_webhooks = []
|
||||||
|
|
||||||
for d in self.webhooks:
|
for d in self.webhooks:
|
||||||
url = get_shopify_url('admin/api/2020-04/webhooks/{0}.json'.format(d.webhook_id), self)
|
url = get_shopify_url('admin/api/2021-04/webhooks/{0}.json'.format(d.webhook_id), self)
|
||||||
try:
|
try:
|
||||||
res = session.delete(url, headers=get_header(self))
|
res = session.delete(url, headers=get_header(self))
|
||||||
res.raise_for_status()
|
res.raise_for_status()
|
||||||
|
|||||||
@@ -32,10 +32,12 @@ def create_customer(shopify_customer, shopify_settings):
|
|||||||
raise e
|
raise e
|
||||||
|
|
||||||
def create_customer_address(customer, shopify_customer):
|
def create_customer_address(customer, shopify_customer):
|
||||||
if not shopify_customer.get("addresses"):
|
addresses = shopify_customer.get("addresses", [])
|
||||||
return
|
|
||||||
|
|
||||||
for i, address in enumerate(shopify_customer.get("addresses")):
|
if not addresses and "default_address" in shopify_customer:
|
||||||
|
addresses.append(shopify_customer["default_address"])
|
||||||
|
|
||||||
|
for i, address in enumerate(addresses):
|
||||||
address_title, address_type = get_address_title_and_type(customer.customer_name, i)
|
address_title, address_type = get_address_title_and_type(customer.customer_name, i)
|
||||||
try :
|
try :
|
||||||
frappe.get_doc({
|
frappe.get_doc({
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from erpnext.erpnext_integrations.doctype.shopify_settings.shopify_settings impo
|
|||||||
shopify_variants_attr_list = ["option1", "option2", "option3"]
|
shopify_variants_attr_list = ["option1", "option2", "option3"]
|
||||||
|
|
||||||
def sync_item_from_shopify(shopify_settings, item):
|
def sync_item_from_shopify(shopify_settings, item):
|
||||||
url = get_shopify_url("admin/api/2020-04/products/{0}.json".format(item.get("product_id")), shopify_settings)
|
url = get_shopify_url("admin/api/2021-04/products/{0}.json".format(item.get("product_id")), shopify_settings)
|
||||||
session = get_request_session()
|
session = get_request_session()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -78,7 +78,7 @@
|
|||||||
"search_index": 1
|
"search_index": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:doc.status==\"On Leave\"",
|
"depends_on": "eval:doc.status==\"On Leave\" || doc.status==\"Half Day\"",
|
||||||
"fieldname": "leave_type",
|
"fieldname": "leave_type",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"in_standard_filter": 1,
|
"in_standard_filter": 1,
|
||||||
@@ -174,7 +174,7 @@
|
|||||||
"icon": "fa fa-ok",
|
"icon": "fa fa-ok",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"modified": "2020-02-19 14:25:32.945842",
|
"modified": "2021-06-30 14:42:39.162146",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Attendance",
|
"name": "Attendance",
|
||||||
|
|||||||
@@ -57,6 +57,9 @@ class Employee(NestedSet):
|
|||||||
remove_user_permission(
|
remove_user_permission(
|
||||||
"Employee", self.name, existing_user_id)
|
"Employee", self.name, existing_user_id)
|
||||||
|
|
||||||
|
def after_rename(self, old, new, merge):
|
||||||
|
self.db_set("employee", new)
|
||||||
|
|
||||||
def set_employee_name(self):
|
def set_employee_name(self):
|
||||||
self.employee_name = ' '.join(filter(lambda x: x, [self.first_name, self.middle_name, self.last_name]))
|
self.employee_name = ' '.join(filter(lambda x: x, [self.first_name, self.middle_name, self.last_name]))
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// MIT License. See license.txt
|
// MIT License. See license.txt
|
||||||
|
|
||||||
frappe.listview_settings['Job Applicant'] = {
|
frappe.listview_settings['Job Applicant'] = {
|
||||||
add_fields: ["company", "designation", "job_applicant", "status"],
|
add_fields: ["status"],
|
||||||
get_indicator: function (doc) {
|
get_indicator: function (doc) {
|
||||||
if (doc.status == "Accepted") {
|
if (doc.status == "Accepted") {
|
||||||
return [__(doc.status), "green", "status,=," + doc.status];
|
return [__(doc.status), "green", "status,=," + doc.status];
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
frappe.ui.form.on('Loan Application', {
|
frappe.ui.form.on('Loan Application', {
|
||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
frm.trigger("toggle_fields")
|
frm.trigger("toggle_fields");
|
||||||
frm.trigger("add_toolbar_buttons")
|
frm.trigger("add_toolbar_buttons");
|
||||||
},
|
},
|
||||||
repayment_method: function(frm) {
|
repayment_method: function(frm) {
|
||||||
frm.doc.repayment_amount = frm.doc.repayment_periods = ""
|
frm.doc.repayment_amount = frm.doc.repayment_periods = ""
|
||||||
|
|||||||
@@ -5,10 +5,17 @@ frappe.ui.form.on('Salary Component', {
|
|||||||
setup: function(frm) {
|
setup: function(frm) {
|
||||||
frm.set_query("default_account", "accounts", function(doc, cdt, cdn) {
|
frm.set_query("default_account", "accounts", function(doc, cdt, cdn) {
|
||||||
var d = locals[cdt][cdn];
|
var d = locals[cdt][cdn];
|
||||||
|
|
||||||
|
var root_type = "Liability";
|
||||||
|
if (frm.doc.type == "Deduction") {
|
||||||
|
root_type = "Expense";
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
filters: {
|
filters: {
|
||||||
"is_group": 0,
|
"is_group": 0,
|
||||||
"company": d.company
|
"company": d.company,
|
||||||
|
"root_type": root_type
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -869,8 +869,8 @@ class SalarySlip(TransactionBase):
|
|||||||
`tabRepayment Schedule` as rps, `tabLoan` as l
|
`tabRepayment Schedule` as rps, `tabLoan` as l
|
||||||
where
|
where
|
||||||
l.name = rps.parent and rps.payment_date between %s and %s and
|
l.name = rps.parent and rps.payment_date between %s and %s and
|
||||||
l.repay_from_salary = 1 and l.docstatus = 1 and l.applicant = %s""",
|
l.repay_from_salary = 1 and l.docstatus = 1 and l.applicant = %s and l.company = %s""",
|
||||||
(self.start_date, self.end_date, self.employee), as_dict=True) or []
|
(self.start_date, self.end_date, self.employee, self.company), as_dict=True) or []
|
||||||
|
|
||||||
def update_salary_slip_in_additional_salary(self):
|
def update_salary_slip_in_additional_salary(self):
|
||||||
salary_slip = self.name if self.docstatus==1 else None
|
salary_slip = self.name if self.docstatus==1 else None
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class StaffingPlan(Document):
|
|||||||
detail.current_openings = designation_counts['job_openings']
|
detail.current_openings = designation_counts['job_openings']
|
||||||
|
|
||||||
if detail.number_of_positions > 0:
|
if detail.number_of_positions > 0:
|
||||||
if detail.vacancies > 0 and detail.estimated_cost_per_position:
|
if detail.vacancies and detail.estimated_cost_per_position:
|
||||||
detail.total_estimated_cost = cint(detail.vacancies) * flt(detail.estimated_cost_per_position)
|
detail.total_estimated_cost = cint(detail.vacancies) * flt(detail.estimated_cost_per_position)
|
||||||
|
|
||||||
self.total_estimated_budget += detail.total_estimated_cost
|
self.total_estimated_budget += detail.total_estimated_cost
|
||||||
@@ -57,8 +57,7 @@ class StaffingPlan(Document):
|
|||||||
and sp.to_date >= %s and sp.from_date <= %s and sp.company = %s
|
and sp.to_date >= %s and sp.from_date <= %s and sp.company = %s
|
||||||
""", (staffing_plan_detail.designation, self.from_date, self.to_date, self.company))
|
""", (staffing_plan_detail.designation, self.from_date, self.to_date, self.company))
|
||||||
if overlap and overlap [0][0]:
|
if overlap and overlap [0][0]:
|
||||||
frappe.throw(_("Staffing Plan {0} already exist for designation {1}"
|
frappe.throw(_("Staffing Plan {0} already exist for designation {1}").format(overlap[0][0], staffing_plan_detail.designation))
|
||||||
.format(overlap[0][0], staffing_plan_detail.designation)))
|
|
||||||
|
|
||||||
def validate_with_parent_plan(self, staffing_plan_detail):
|
def validate_with_parent_plan(self, staffing_plan_detail):
|
||||||
if not frappe.get_cached_value('Company', self.company, "parent_company"):
|
if not frappe.get_cached_value('Company', self.company, "parent_company"):
|
||||||
@@ -75,12 +74,12 @@ class StaffingPlan(Document):
|
|||||||
if cint(staffing_plan_detail.vacancies) > cint(parent_plan_details[0].vacancies) or \
|
if cint(staffing_plan_detail.vacancies) > cint(parent_plan_details[0].vacancies) or \
|
||||||
flt(staffing_plan_detail.total_estimated_cost) > flt(parent_plan_details[0].total_estimated_cost):
|
flt(staffing_plan_detail.total_estimated_cost) > flt(parent_plan_details[0].total_estimated_cost):
|
||||||
frappe.throw(_("You can only plan for upto {0} vacancies and budget {1} \
|
frappe.throw(_("You can only plan for upto {0} vacancies and budget {1} \
|
||||||
for {2} as per staffing plan {3} for parent company {4}."
|
for {2} as per staffing plan {3} for parent company {4}.").format(
|
||||||
.format(cint(parent_plan_details[0].vacancies),
|
cint(parent_plan_details[0].vacancies),
|
||||||
parent_plan_details[0].total_estimated_cost,
|
parent_plan_details[0].total_estimated_cost,
|
||||||
frappe.bold(staffing_plan_detail.designation),
|
frappe.bold(staffing_plan_detail.designation),
|
||||||
parent_plan_details[0].name,
|
parent_plan_details[0].name,
|
||||||
parent_company)), ParentCompanyError)
|
parent_company), ParentCompanyError)
|
||||||
|
|
||||||
#Get vacanices already planned for all companies down the hierarchy of Parent Company
|
#Get vacanices already planned for all companies down the hierarchy of Parent Company
|
||||||
lft, rgt = frappe.get_cached_value('Company', parent_company, ["lft", "rgt"])
|
lft, rgt = frappe.get_cached_value('Company', parent_company, ["lft", "rgt"])
|
||||||
@@ -97,14 +96,14 @@ class StaffingPlan(Document):
|
|||||||
(flt(parent_plan_details[0].total_estimated_cost) < \
|
(flt(parent_plan_details[0].total_estimated_cost) < \
|
||||||
(flt(staffing_plan_detail.total_estimated_cost) + flt(all_sibling_details.total_estimated_cost))):
|
(flt(staffing_plan_detail.total_estimated_cost) + flt(all_sibling_details.total_estimated_cost))):
|
||||||
frappe.throw(_("{0} vacancies and {1} budget for {2} already planned for subsidiary companies of {3}. \
|
frappe.throw(_("{0} vacancies and {1} budget for {2} already planned for subsidiary companies of {3}. \
|
||||||
You can only plan for upto {4} vacancies and and budget {5} as per staffing plan {6} for parent company {3}."
|
You can only plan for upto {4} vacancies and and budget {5} as per staffing plan {6} for parent company {3}.").format(
|
||||||
.format(cint(all_sibling_details.vacancies),
|
cint(all_sibling_details.vacancies),
|
||||||
all_sibling_details.total_estimated_cost,
|
all_sibling_details.total_estimated_cost,
|
||||||
frappe.bold(staffing_plan_detail.designation),
|
frappe.bold(staffing_plan_detail.designation),
|
||||||
parent_company,
|
parent_company,
|
||||||
cint(parent_plan_details[0].vacancies),
|
cint(parent_plan_details[0].vacancies),
|
||||||
parent_plan_details[0].total_estimated_cost,
|
parent_plan_details[0].total_estimated_cost,
|
||||||
parent_plan_details[0].name)))
|
parent_plan_details[0].name))
|
||||||
|
|
||||||
def validate_with_subsidiary_plans(self, staffing_plan_detail):
|
def validate_with_subsidiary_plans(self, staffing_plan_detail):
|
||||||
#Valdate this plan with all child company plan
|
#Valdate this plan with all child company plan
|
||||||
@@ -120,11 +119,11 @@ class StaffingPlan(Document):
|
|||||||
cint(staffing_plan_detail.vacancies) < cint(children_details.vacancies) or \
|
cint(staffing_plan_detail.vacancies) < cint(children_details.vacancies) or \
|
||||||
flt(staffing_plan_detail.total_estimated_cost) < flt(children_details.total_estimated_cost):
|
flt(staffing_plan_detail.total_estimated_cost) < flt(children_details.total_estimated_cost):
|
||||||
frappe.throw(_("Subsidiary companies have already planned for {1} vacancies at a budget of {2}. \
|
frappe.throw(_("Subsidiary companies have already planned for {1} vacancies at a budget of {2}. \
|
||||||
Staffing Plan for {0} should allocate more vacancies and budget for {3} than planned for its subsidiary companies"
|
Staffing Plan for {0} should allocate more vacancies and budget for {3} than planned for its subsidiary companies").format(
|
||||||
.format(self.company,
|
self.company,
|
||||||
cint(children_details.vacancies),
|
cint(children_details.vacancies),
|
||||||
children_details.total_estimated_cost,
|
children_details.total_estimated_cost,
|
||||||
frappe.bold(staffing_plan_detail.designation))), SubsidiaryCompanyError)
|
frappe.bold(staffing_plan_detail.designation)), SubsidiaryCompanyError)
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_designation_counts(designation, company):
|
def get_designation_counts(designation, company):
|
||||||
|
|||||||
@@ -685,3 +685,4 @@ erpnext.patches.v12_0.create_taxable_value_field
|
|||||||
erpnext.patches.v12_0.purchase_receipt_status
|
erpnext.patches.v12_0.purchase_receipt_status
|
||||||
erpnext.patches.v12_0.add_company_link_to_einvoice_settings
|
erpnext.patches.v12_0.add_company_link_to_einvoice_settings
|
||||||
erpnext.patches.v12_0.add_document_type_field_for_italy_einvoicing
|
erpnext.patches.v12_0.add_document_type_field_for_italy_einvoicing
|
||||||
|
erpnext.patches.v12_0.create_taxable_value_field_in_purchase_invoice
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
company = frappe.get_all('Company', filters = {'country': 'India'})
|
||||||
|
if not company:
|
||||||
|
return
|
||||||
|
|
||||||
|
custom_fields = {
|
||||||
|
'Purchase Invoice Item': [
|
||||||
|
dict(fieldname='taxable_value', label='Taxable Value',
|
||||||
|
fieldtype='Currency', insert_after='base_net_amount', hidden=1, options="Company:company:default_currency",
|
||||||
|
print_hide=1)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
create_custom_fields(custom_fields, update=True)
|
||||||
@@ -73,9 +73,6 @@ class Task(NestedSet):
|
|||||||
if (self.progress or 0) > 100:
|
if (self.progress or 0) > 100:
|
||||||
frappe.throw(_("Progress % for a task cannot be more than 100."))
|
frappe.throw(_("Progress % for a task cannot be more than 100."))
|
||||||
|
|
||||||
if self.progress == 100:
|
|
||||||
self.status = 'Completed'
|
|
||||||
|
|
||||||
if self.status == 'Completed':
|
if self.status == 'Completed':
|
||||||
self.progress = 100
|
self.progress = 100
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
erpnext.setup_einvoice_actions = (doctype) => {
|
erpnext.setup_einvoice_actions = (doctype) => {
|
||||||
frappe.ui.form.on(doctype, {
|
frappe.ui.form.on(doctype, {
|
||||||
async refresh(frm) {
|
async refresh(frm) {
|
||||||
|
if (frm.doc.docstatus == 2) return;
|
||||||
|
|
||||||
const res = await frappe.call({
|
const res = await frappe.call({
|
||||||
method: 'erpnext.regional.india.e_invoice.utils.validate_eligibility',
|
method: 'erpnext.regional.india.e_invoice.utils.validate_eligibility',
|
||||||
args: { doc: frm.doc }
|
args: { doc: frm.doc }
|
||||||
@@ -115,7 +117,7 @@ erpnext.setup_einvoice_actions = (doctype) => {
|
|||||||
|
|
||||||
if (irn && ewaybill && !irn_cancelled && !eway_bill_cancelled) {
|
if (irn && ewaybill && !irn_cancelled && !eway_bill_cancelled) {
|
||||||
const action = () => {
|
const action = () => {
|
||||||
let message = __('Cancellation of e-way bill is currently not supported. ');
|
let message = __('Cancellation of e-way bill is currently not supported.') + ' ';
|
||||||
message += '<br><br>';
|
message += '<br><br>';
|
||||||
message += __('You must first use the portal to cancel the e-way bill and then update the cancelled status in the ERPNext system.');
|
message += __('You must first use the portal to cancel the e-way bill and then update the cancelled status in the ERPNext system.');
|
||||||
|
|
||||||
|
|||||||
@@ -38,9 +38,13 @@ def validate_eligibility(doc):
|
|||||||
invalid_company = not frappe.db.get_value('E Invoice User', { 'company': doc.get('company') })
|
invalid_company = not frappe.db.get_value('E Invoice User', { 'company': doc.get('company') })
|
||||||
invalid_supply_type = doc.get('gst_category') not in ['Registered Regular', 'SEZ', 'Overseas', 'Deemed Export']
|
invalid_supply_type = doc.get('gst_category') not in ['Registered Regular', 'SEZ', 'Overseas', 'Deemed Export']
|
||||||
company_transaction = doc.get('billing_address_gstin') == doc.get('company_gstin')
|
company_transaction = doc.get('billing_address_gstin') == doc.get('company_gstin')
|
||||||
no_taxes_applied = not doc.get('taxes')
|
|
||||||
|
|
||||||
if invalid_company or invalid_supply_type or company_transaction or no_taxes_applied:
|
# if export invoice, then taxes can be empty
|
||||||
|
# invoice can only be ineligible if no taxes applied and is not an export invoice
|
||||||
|
no_taxes_applied = not doc.get('taxes') and not doc.get('gst_category') == 'Overseas'
|
||||||
|
has_non_gst_item = any(d for d in doc.get('items', []) if d.get('is_non_gst'))
|
||||||
|
|
||||||
|
if invalid_company or invalid_supply_type or company_transaction or no_taxes_applied or has_non_gst_item:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
@@ -191,18 +195,14 @@ def get_item_list(invoice):
|
|||||||
|
|
||||||
item.qty = abs(item.qty)
|
item.qty = abs(item.qty)
|
||||||
|
|
||||||
if invoice.apply_discount_on == 'Net Total' and invoice.discount_amount:
|
item.unit_rate = abs(item.taxable_value / item.qty)
|
||||||
item.discount_amount = abs(item.base_amount - item.base_net_amount)
|
item.gross_amount = abs(item.taxable_value)
|
||||||
else:
|
|
||||||
item.discount_amount = 0
|
|
||||||
|
|
||||||
item.unit_rate = abs((abs(item.taxable_value) - item.discount_amount)/ item.qty)
|
|
||||||
item.gross_amount = abs(item.taxable_value) + item.discount_amount
|
|
||||||
item.taxable_value = abs(item.taxable_value)
|
item.taxable_value = abs(item.taxable_value)
|
||||||
|
item.discount_amount = 0
|
||||||
|
|
||||||
item.batch_expiry_date = frappe.db.get_value('Batch', d.batch_no, 'expiry_date') if d.batch_no else None
|
item.batch_expiry_date = frappe.db.get_value('Batch', d.batch_no, 'expiry_date') if d.batch_no else None
|
||||||
item.batch_expiry_date = format_date(item.batch_expiry_date, 'dd/mm/yyyy') if item.batch_expiry_date else None
|
item.batch_expiry_date = format_date(item.batch_expiry_date, 'dd/mm/yyyy') if item.batch_expiry_date else None
|
||||||
item.is_service_item = 'N' if frappe.db.get_value('Item', d.item_code, 'is_stock_item') else 'Y'
|
item.is_service_item = 'Y' if item.gst_hsn_code and item.gst_hsn_code[:2] == "99" else 'N'
|
||||||
item.serial_no = ""
|
item.serial_no = ""
|
||||||
|
|
||||||
item = update_item_taxes(invoice, item)
|
item = update_item_taxes(invoice, item)
|
||||||
@@ -254,18 +254,8 @@ def update_item_taxes(invoice, item):
|
|||||||
|
|
||||||
def get_invoice_value_details(invoice):
|
def get_invoice_value_details(invoice):
|
||||||
invoice_value_details = frappe._dict(dict())
|
invoice_value_details = frappe._dict(dict())
|
||||||
|
invoice_value_details.base_total = abs(sum([i.taxable_value for i in invoice.get('items')]))
|
||||||
if invoice.apply_discount_on == 'Net Total' and invoice.discount_amount:
|
invoice_value_details.invoice_discount_amt = 0
|
||||||
# Discount already applied on net total which means on items
|
|
||||||
invoice_value_details.base_total = abs(sum([i.taxable_value for i in invoice.get('items')]))
|
|
||||||
invoice_value_details.invoice_discount_amt = 0
|
|
||||||
elif invoice.apply_discount_on == 'Grand Total' and invoice.discount_amount:
|
|
||||||
invoice_value_details.invoice_discount_amt = invoice.base_discount_amount
|
|
||||||
invoice_value_details.base_total = abs(sum([i.taxable_value for i in invoice.get('items')]))
|
|
||||||
else:
|
|
||||||
invoice_value_details.base_total = abs(sum([i.taxable_value for i in invoice.get('items')]))
|
|
||||||
# since tax already considers discount amount
|
|
||||||
invoice_value_details.invoice_discount_amt = 0
|
|
||||||
|
|
||||||
invoice_value_details.round_off = invoice.base_rounding_adjustment
|
invoice_value_details.round_off = invoice.base_rounding_adjustment
|
||||||
invoice_value_details.base_grand_total = abs(invoice.base_rounded_total) or abs(invoice.base_grand_total)
|
invoice_value_details.base_grand_total = abs(invoice.base_rounded_total) or abs(invoice.base_grand_total)
|
||||||
@@ -287,8 +277,8 @@ def update_invoice_taxes(invoice, invoice_value_details):
|
|||||||
considered_rows = []
|
considered_rows = []
|
||||||
|
|
||||||
for t in invoice.taxes:
|
for t in invoice.taxes:
|
||||||
tax_amount = t.base_tax_amount if (invoice.apply_discount_on == 'Grand Total' and invoice.discount_amount) \
|
tax_amount = t.base_tax_amount_after_discount_amount
|
||||||
else t.base_tax_amount_after_discount_amount
|
|
||||||
if t.account_head in gst_accounts_list:
|
if t.account_head in gst_accounts_list:
|
||||||
if t.account_head in gst_accounts.cess_account:
|
if t.account_head in gst_accounts.cess_account:
|
||||||
# using after discount amt since item also uses after discount amt for cess calc
|
# using after discount amt since item also uses after discount amt for cess calc
|
||||||
|
|||||||
@@ -455,7 +455,7 @@ def make_custom_fields(update=True):
|
|||||||
'Sales Order Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
|
'Sales Order Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
|
||||||
'Delivery Note Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
|
'Delivery Note Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
|
||||||
'Sales Invoice Item': [hsn_sac_field, nil_rated_exempt, is_non_gst, taxable_value],
|
'Sales Invoice Item': [hsn_sac_field, nil_rated_exempt, is_non_gst, taxable_value],
|
||||||
'Purchase Order Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
|
'Purchase Order Item': [hsn_sac_field, nil_rated_exempt, is_non_gst, taxable_value],
|
||||||
'Purchase Receipt Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
|
'Purchase Receipt Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
|
||||||
'Purchase Invoice Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
|
'Purchase Invoice Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
|
||||||
'Material Request Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
|
'Material Request Item': [hsn_sac_field, nil_rated_exempt, is_non_gst],
|
||||||
|
|||||||
@@ -856,12 +856,8 @@ def update_taxable_values(doc, method):
|
|||||||
considered_rows.append(prev_row_id)
|
considered_rows.append(prev_row_id)
|
||||||
|
|
||||||
for item in doc.get('items'):
|
for item in doc.get('items'):
|
||||||
if doc.apply_discount_on == 'Grand Total' and doc.discount_amount:
|
proportionate_value = item.base_net_amount if doc.base_net_total else item.qty
|
||||||
proportionate_value = item.base_amount if doc.base_total else item.qty
|
total_value = doc.base_net_total if doc.base_net_total else doc.total_qty
|
||||||
total_value = doc.base_total if doc.base_total else doc.total_qty
|
|
||||||
else:
|
|
||||||
proportionate_value = item.base_net_amount if doc.base_net_total else item.qty
|
|
||||||
total_value = doc.base_net_total if doc.base_net_total else doc.total_qty
|
|
||||||
|
|
||||||
applicable_charges = flt(flt(proportionate_value * (flt(additional_taxes) / flt(total_value)),
|
applicable_charges = flt(flt(proportionate_value * (flt(additional_taxes) / flt(total_value)),
|
||||||
item.precision('taxable_value')))
|
item.precision('taxable_value')))
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ class Gstr1Report(object):
|
|||||||
self.item_tax_rate = frappe._dict()
|
self.item_tax_rate = frappe._dict()
|
||||||
|
|
||||||
items = frappe.db.sql("""
|
items = frappe.db.sql("""
|
||||||
select item_code, parent, base_net_amount, item_tax_rate
|
select item_code, parent, taxable_value, base_net_amount, item_tax_rate
|
||||||
from `tab%s Item`
|
from `tab%s Item`
|
||||||
where parent in (%s)
|
where parent in (%s)
|
||||||
""" % (self.doctype, ', '.join(['%s']*len(self.invoices))), tuple(self.invoices), as_dict=1)
|
""" % (self.doctype, ', '.join(['%s']*len(self.invoices))), tuple(self.invoices), as_dict=1)
|
||||||
@@ -207,7 +207,7 @@ class Gstr1Report(object):
|
|||||||
for d in items:
|
for d in items:
|
||||||
if d.item_code not in self.invoice_items.get(d.parent, {}):
|
if d.item_code not in self.invoice_items.get(d.parent, {}):
|
||||||
self.invoice_items.setdefault(d.parent, {}).setdefault(d.item_code,
|
self.invoice_items.setdefault(d.parent, {}).setdefault(d.item_code,
|
||||||
sum(i.get('base_net_amount', 0) for i in items
|
sum((i.get('taxable_value', 0) or i.get('base_net_amount', 0)) for i in items
|
||||||
if i.item_code == d.item_code and i.parent == d.parent))
|
if i.item_code == d.item_code and i.parent == d.parent))
|
||||||
|
|
||||||
item_tax_rate = {}
|
item_tax_rate = {}
|
||||||
|
|||||||
@@ -175,9 +175,9 @@ def install(country=None):
|
|||||||
]},
|
]},
|
||||||
|
|
||||||
# Issue Priority
|
# Issue Priority
|
||||||
{'doctype': 'Issue Priority', 'name': _('Low')},
|
{'doctype': 'Issue Priority', 'name': 'Low'},
|
||||||
{'doctype': 'Issue Priority', 'name': _('Medium')},
|
{'doctype': 'Issue Priority', 'name': 'Medium'},
|
||||||
{'doctype': 'Issue Priority', 'name': _('High')},
|
{'doctype': 'Issue Priority', 'name': 'High'},
|
||||||
|
|
||||||
#Job Applicant Source
|
#Job Applicant Source
|
||||||
{'doctype': 'Job Applicant Source', 'source_name': _('Website Listing')},
|
{'doctype': 'Job Applicant Source', 'source_name': _('Website Listing')},
|
||||||
|
|||||||
@@ -69,7 +69,8 @@ frappe.ui.form.on('Material Request', {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (frm.doc.docstatus == 1 && frm.doc.status != 'Stopped') {
|
if (frm.doc.docstatus == 1 && frm.doc.status != 'Stopped') {
|
||||||
if (flt(frm.doc.per_ordered, 2) < 100) {
|
let precision = frappe.defaults.get_default("float_precision");
|
||||||
|
if (flt(frm.doc.per_ordered, precision) < 100) {
|
||||||
let add_create_pick_list_button = () => {
|
let add_create_pick_list_button = () => {
|
||||||
frm.add_custom_button(__('Pick List'),
|
frm.add_custom_button(__('Pick List'),
|
||||||
() => frm.events.create_pick_list(frm), __('Create'));
|
() => frm.events.create_pick_list(frm), __('Create'));
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
frappe.listview_settings['Material Request'] = {
|
frappe.listview_settings['Material Request'] = {
|
||||||
add_fields: ["material_request_type", "status", "per_ordered", "per_received"],
|
add_fields: ["material_request_type", "status", "per_ordered", "per_received"],
|
||||||
get_indicator: function(doc) {
|
get_indicator: function(doc) {
|
||||||
if(doc.status=="Stopped") {
|
var precision = frappe.defaults.get_default("float_precision");
|
||||||
|
if (doc.status=="Stopped") {
|
||||||
return [__("Stopped"), "red", "status,=,Stopped"];
|
return [__("Stopped"), "red", "status,=,Stopped"];
|
||||||
} else if(doc.docstatus==1 && flt(doc.per_ordered, 2) == 0) {
|
} else if (doc.docstatus==1 && flt(doc.per_ordered, precision) == 0) {
|
||||||
return [__("Pending"), "orange", "per_ordered,=,0"];
|
return [__("Pending"), "orange", "per_ordered,=,0"];
|
||||||
} else if(doc.docstatus==1 && flt(doc.per_ordered, 2) < 100) {
|
} else if (doc.docstatus==1 && flt(doc.per_ordered, precision) < 100) {
|
||||||
return [__("Partially ordered"), "yellow", "per_ordered,<,100"];
|
return [__("Partially ordered"), "yellow", "per_ordered,<,100"];
|
||||||
} else if(doc.docstatus==1 && flt(doc.per_ordered, 2) == 100) {
|
} else if (doc.docstatus==1 && flt(doc.per_ordered, precision) == 100) {
|
||||||
if (doc.material_request_type == "Purchase" && flt(doc.per_received, 2) < 100 && flt(doc.per_received, 2) > 0) {
|
if (doc.material_request_type == "Purchase" && flt(doc.per_received, precision) < 100 && flt(doc.per_received, precision) > 0) {
|
||||||
return [__("Partially Received"), "yellow", "per_received,<,100"];
|
return [__("Partially Received"), "yellow", "per_received,<,100"];
|
||||||
} else if (doc.material_request_type == "Purchase" && flt(doc.per_received, 2) == 100) {
|
} else if (doc.material_request_type == "Purchase" && flt(doc.per_received, precision) == 100) {
|
||||||
return [__("Received"), "green", "per_received,=,100"];
|
return [__("Received"), "green", "per_received,=,100"];
|
||||||
} else if (doc.material_request_type == "Purchase") {
|
} else if (doc.material_request_type == "Purchase") {
|
||||||
return [__("Ordered"), "green", "per_ordered,=,100"];
|
return [__("Ordered"), "green", "per_ordered,=,100"];
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ frappe.ui.form.on("Purchase Receipt", {
|
|||||||
frappe.set_route("Form", lcv.doctype, lcv.name);
|
frappe.set_route("Form", lcv.doctype, lcv.name);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
frm.custom_make_buttons = {
|
frm.custom_make_buttons = {
|
||||||
'Stock Entry': 'Return',
|
'Stock Entry': 'Return',
|
||||||
'Purchase Invoice': 'Purchase Invoice'
|
'Purchase Invoice': 'Purchase Invoice'
|
||||||
@@ -34,7 +34,7 @@ frappe.ui.form.on("Purchase Receipt", {
|
|||||||
filters: {'company': frm.doc.company }
|
filters: {'company': frm.doc.company }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
},
|
},
|
||||||
onload: function(frm) {
|
onload: function(frm) {
|
||||||
erpnext.queries.setup_queries(frm, "Warehouse", function() {
|
erpnext.queries.setup_queries(frm, "Warehouse", function() {
|
||||||
@@ -107,6 +107,8 @@ erpnext.stock.PurchaseReceiptController = erpnext.buying.BuyingController.extend
|
|||||||
message: __("Please Select a Supplier")
|
message: __("Please Select a Supplier")
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
me.frm.doc.taxes = [];
|
||||||
erpnext.utils.map_current_doc({
|
erpnext.utils.map_current_doc({
|
||||||
method: "erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_receipt",
|
method: "erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_receipt",
|
||||||
source_doctype: "Purchase Order",
|
source_doctype: "Purchase Order",
|
||||||
|
|||||||
@@ -316,13 +316,16 @@ def update_included_uom_in_report(columns, result, include_uom, conversion_facto
|
|||||||
for row_idx, row in enumerate(result):
|
for row_idx, row in enumerate(result):
|
||||||
data = row.items() if is_dict_obj else enumerate(row)
|
data = row.items() if is_dict_obj else enumerate(row)
|
||||||
for key, value in data:
|
for key, value in data:
|
||||||
if key not in convertible_columns or not conversion_factors[row_idx-1]:
|
if key not in convertible_columns:
|
||||||
continue
|
continue
|
||||||
|
# If no conversion factor for the UOM, defaults to 1
|
||||||
|
if not conversion_factors[row_idx]:
|
||||||
|
conversion_factors[row_idx] = 1
|
||||||
|
|
||||||
if convertible_columns.get(key) == 'rate':
|
if convertible_columns.get(key) == 'rate':
|
||||||
new_value = flt(value) * conversion_factors[row_idx-1]
|
new_value = flt(value) * conversion_factors[row_idx]
|
||||||
else:
|
else:
|
||||||
new_value = flt(value) / conversion_factors[row_idx-1]
|
new_value = flt(value) / conversion_factors[row_idx]
|
||||||
|
|
||||||
if not is_dict_obj:
|
if not is_dict_obj:
|
||||||
row.insert(key+1, new_value)
|
row.insert(key+1, new_value)
|
||||||
@@ -370,4 +373,4 @@ def add_additional_uom_columns(columns, result, include_uom, conversion_factors)
|
|||||||
else:
|
else:
|
||||||
row[data.converted_col] = flt(value_before_conversion) / conversion_factor
|
row[data.converted_col] = flt(value_before_conversion) / conversion_factor
|
||||||
|
|
||||||
result[row_idx] = row
|
result[row_idx] = row
|
||||||
|
|||||||
@@ -13,9 +13,11 @@
|
|||||||
{{ doc.items_preview }}
|
{{ doc.items_preview }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-3 text-right bold">
|
{% if doc.get('grand_total') %}
|
||||||
{{ doc.get_formatted("grand_total") }}
|
<div class="col-sm-3 text-right bold">
|
||||||
</div>
|
{{ doc.get_formatted("grand_total") }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<a class="transaction-item-link" href="/{{ pathname }}/{{ doc.name }}">Link</a>
|
<a class="transaction-item-link" href="/{{ pathname }}/{{ doc.name }}">Link</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user