Merge branch 'develop' into grn_posting
This commit is contained in:
commit
d63c59ced4
@ -2,10 +2,11 @@ from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import date_diff, add_months, today, getdate, add_days, flt, get_last_day, cint, get_link_to_form
|
||||
from frappe.utils import date_diff, add_months, today, getdate, add_days, flt, get_last_day, get_first_day, cint, get_link_to_form, rounded
|
||||
from erpnext.accounts.utils import get_account_currency
|
||||
from frappe.email import sendmail_to_system_managers
|
||||
from frappe.utils.background_jobs import enqueue
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
|
||||
|
||||
def validate_service_stop_date(doc):
|
||||
''' Validates service_stop_date for Purchase Invoice and Sales Invoice '''
|
||||
@ -109,6 +110,18 @@ def get_booking_dates(doc, item, posting_date=None):
|
||||
order by posting_date desc limit 1
|
||||
''', (doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name), as_dict=True)
|
||||
|
||||
prev_gl_via_je = frappe.db.sql('''
|
||||
SELECT p.name, p.posting_date FROM `tabJournal Entry` p, `tabJournal Entry Account` c
|
||||
WHERE p.name = c.parent and p.company=%s and c.account=%s
|
||||
and c.reference_type=%s and c.reference_name=%s
|
||||
and c.reference_detail_no=%s and c.docstatus < 2 order by posting_date desc limit 1
|
||||
''', (doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name), as_dict=True)
|
||||
|
||||
if prev_gl_via_je:
|
||||
if (not prev_gl_entry) or (prev_gl_entry and
|
||||
prev_gl_entry[0].posting_date < prev_gl_via_je[0].posting_date):
|
||||
prev_gl_entry = prev_gl_via_je
|
||||
|
||||
if prev_gl_entry:
|
||||
start_date = getdate(add_days(prev_gl_entry[0].posting_date, 1))
|
||||
else:
|
||||
@ -130,14 +143,48 @@ def get_booking_dates(doc, item, posting_date=None):
|
||||
else:
|
||||
return None, None, None
|
||||
|
||||
def calculate_amount(doc, item, last_gl_entry, total_days, total_booking_days, account_currency):
|
||||
if doc.doctype == "Sales Invoice":
|
||||
total_credit_debit, total_credit_debit_currency = "debit", "debit_in_account_currency"
|
||||
deferred_account = "deferred_revenue_account"
|
||||
else:
|
||||
total_credit_debit, total_credit_debit_currency = "credit", "credit_in_account_currency"
|
||||
deferred_account = "deferred_expense_account"
|
||||
def calculate_monthly_amount(doc, item, last_gl_entry, start_date, end_date, total_days, total_booking_days, account_currency):
|
||||
amount, base_amount = 0, 0
|
||||
|
||||
if not last_gl_entry:
|
||||
total_months = (item.service_end_date.year - item.service_start_date.year) * 12 + \
|
||||
(item.service_end_date.month - item.service_start_date.month) + 1
|
||||
|
||||
prorate_factor = flt(date_diff(item.service_end_date, item.service_start_date)) \
|
||||
/ flt(date_diff(get_last_day(item.service_end_date), get_first_day(item.service_start_date)))
|
||||
|
||||
actual_months = rounded(total_months * prorate_factor, 1)
|
||||
|
||||
already_booked_amount, already_booked_amount_in_account_currency = get_already_booked_amount(doc, item)
|
||||
base_amount = flt(item.base_net_amount / actual_months, item.precision("base_net_amount"))
|
||||
|
||||
if base_amount + already_booked_amount > item.base_net_amount:
|
||||
base_amount = item.base_net_amount - already_booked_amount
|
||||
|
||||
if account_currency==doc.company_currency:
|
||||
amount = base_amount
|
||||
else:
|
||||
amount = flt(item.net_amount/actual_months, item.precision("net_amount"))
|
||||
if amount + already_booked_amount_in_account_currency > item.net_amount:
|
||||
amount = item.net_amount - already_booked_amount_in_account_currency
|
||||
|
||||
if not (get_first_day(start_date) == start_date and get_last_day(end_date) == end_date):
|
||||
partial_month = flt(date_diff(end_date, start_date)) \
|
||||
/ flt(date_diff(get_last_day(end_date), get_first_day(start_date)))
|
||||
|
||||
base_amount = rounded(partial_month, 1) * base_amount
|
||||
amount = rounded(partial_month, 1) * amount
|
||||
else:
|
||||
already_booked_amount, already_booked_amount_in_account_currency = get_already_booked_amount(doc, item)
|
||||
base_amount = flt(item.base_net_amount - already_booked_amount, item.precision("base_net_amount"))
|
||||
if account_currency==doc.company_currency:
|
||||
amount = base_amount
|
||||
else:
|
||||
amount = flt(item.net_amount - already_booked_amount_in_account_currency, item.precision("net_amount"))
|
||||
|
||||
return amount, base_amount
|
||||
|
||||
def calculate_amount(doc, item, last_gl_entry, total_days, total_booking_days, account_currency):
|
||||
amount, base_amount = 0, 0
|
||||
if not last_gl_entry:
|
||||
base_amount = flt(item.base_net_amount*total_booking_days/flt(total_days), item.precision("base_net_amount"))
|
||||
@ -146,27 +193,55 @@ def calculate_amount(doc, item, last_gl_entry, total_days, total_booking_days, a
|
||||
else:
|
||||
amount = flt(item.net_amount*total_booking_days/flt(total_days), item.precision("net_amount"))
|
||||
else:
|
||||
gl_entries_details = frappe.db.sql('''
|
||||
select sum({0}) as total_credit, sum({1}) as total_credit_in_account_currency, voucher_detail_no
|
||||
from `tabGL Entry` where company=%s and account=%s and voucher_type=%s and voucher_no=%s and voucher_detail_no=%s
|
||||
group by voucher_detail_no
|
||||
'''.format(total_credit_debit, total_credit_debit_currency),
|
||||
(doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name), as_dict=True)
|
||||
already_booked_amount = gl_entries_details[0].total_credit if gl_entries_details else 0
|
||||
already_booked_amount, already_booked_amount_in_account_currency = get_already_booked_amount(doc, item)
|
||||
|
||||
base_amount = flt(item.base_net_amount - already_booked_amount, item.precision("base_net_amount"))
|
||||
if account_currency==doc.company_currency:
|
||||
amount = base_amount
|
||||
else:
|
||||
already_booked_amount_in_account_currency = gl_entries_details[0].total_credit_in_account_currency if gl_entries_details else 0
|
||||
amount = flt(item.net_amount - already_booked_amount_in_account_currency, item.precision("net_amount"))
|
||||
|
||||
return amount, base_amount
|
||||
|
||||
def get_already_booked_amount(doc, item):
|
||||
if doc.doctype == "Sales Invoice":
|
||||
total_credit_debit, total_credit_debit_currency = "debit", "debit_in_account_currency"
|
||||
deferred_account = "deferred_revenue_account"
|
||||
else:
|
||||
total_credit_debit, total_credit_debit_currency = "credit", "credit_in_account_currency"
|
||||
deferred_account = "deferred_expense_account"
|
||||
|
||||
gl_entries_details = frappe.db.sql('''
|
||||
select sum({0}) as total_credit, sum({1}) as total_credit_in_account_currency, voucher_detail_no
|
||||
from `tabGL Entry` where company=%s and account=%s and voucher_type=%s and voucher_no=%s and voucher_detail_no=%s
|
||||
group by voucher_detail_no
|
||||
'''.format(total_credit_debit, total_credit_debit_currency),
|
||||
(doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name), as_dict=True)
|
||||
|
||||
journal_entry_details = frappe.db.sql('''
|
||||
SELECT sum(c.{0}) as total_credit, sum(c.{1}) as total_credit_in_account_currency, reference_detail_no
|
||||
FROM `tabJournal Entry` p , `tabJournal Entry Account` c WHERE p.name = c.parent and
|
||||
p.company = %s and c.account=%s and c.reference_type=%s and c.reference_name=%s and c.reference_detail_no=%s
|
||||
and p.docstatus < 2 group by reference_detail_no
|
||||
'''.format(total_credit_debit, total_credit_debit_currency),
|
||||
(doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name), as_dict=True)
|
||||
|
||||
already_booked_amount = gl_entries_details[0].total_credit if gl_entries_details else 0
|
||||
already_booked_amount += journal_entry_details[0].total_credit if journal_entry_details else 0
|
||||
|
||||
if doc.currency == doc.company_currency:
|
||||
already_booked_amount_in_account_currency = already_booked_amount
|
||||
else:
|
||||
already_booked_amount_in_account_currency = gl_entries_details[0].total_credit_in_account_currency if gl_entries_details else 0
|
||||
already_booked_amount_in_account_currency += journal_entry_details[0].total_credit_in_account_currency if journal_entry_details else 0
|
||||
|
||||
return already_booked_amount, already_booked_amount_in_account_currency
|
||||
|
||||
def book_deferred_income_or_expense(doc, deferred_process, posting_date=None):
|
||||
enable_check = "enable_deferred_revenue" \
|
||||
if doc.doctype=="Sales Invoice" else "enable_deferred_expense"
|
||||
|
||||
def _book_deferred_revenue_or_expense(item):
|
||||
def _book_deferred_revenue_or_expense(item, via_journal_entry, submit_journal_entry, book_deferred_entries_based_on):
|
||||
start_date, end_date, last_gl_entry = get_booking_dates(doc, item, posting_date=posting_date)
|
||||
if not (start_date and end_date): return
|
||||
|
||||
@ -181,23 +256,34 @@ def book_deferred_income_or_expense(doc, deferred_process, posting_date=None):
|
||||
total_days = date_diff(item.service_end_date, item.service_start_date) + 1
|
||||
total_booking_days = date_diff(end_date, start_date) + 1
|
||||
|
||||
amount, base_amount = calculate_amount(doc, item, last_gl_entry,
|
||||
total_days, total_booking_days, account_currency)
|
||||
if book_deferred_entries_based_on == 'Months':
|
||||
amount, base_amount = calculate_monthly_amount(doc, item, last_gl_entry,
|
||||
start_date, end_date, total_days, total_booking_days, account_currency)
|
||||
else:
|
||||
amount, base_amount = calculate_amount(doc, item, last_gl_entry,
|
||||
total_days, total_booking_days, account_currency)
|
||||
|
||||
make_gl_entries(doc, credit_account, debit_account, against,
|
||||
amount, base_amount, end_date, project, account_currency, item.cost_center, item, deferred_process)
|
||||
if via_journal_entry:
|
||||
book_revenue_via_journal_entry(doc, credit_account, debit_account, against, amount,
|
||||
base_amount, end_date, project, account_currency, item.cost_center, item, deferred_process, submit_journal_entry)
|
||||
else:
|
||||
make_gl_entries(doc, credit_account, debit_account, against,
|
||||
amount, base_amount, end_date, project, account_currency, item.cost_center, item, deferred_process)
|
||||
|
||||
# Returned in case of any errors because it tries to submit the same record again and again in case of errors
|
||||
if frappe.flags.deferred_accounting_error:
|
||||
return
|
||||
|
||||
if getdate(end_date) < getdate(posting_date) and not last_gl_entry:
|
||||
_book_deferred_revenue_or_expense(item)
|
||||
_book_deferred_revenue_or_expense(item, via_journal_entry, submit_journal_entry, book_deferred_entries_based_on)
|
||||
|
||||
via_journal_entry = cint(frappe.db.get_singles_value('Accounts Settings', 'book_deferred_entries_via_journal_entry'))
|
||||
submit_journal_entry = cint(frappe.db.get_singles_value('Accounts Settings', 'submit_journal_entries'))
|
||||
book_deferred_entries_based_on = frappe.db.get_singles_value('Accounts Settings', 'book_deferred_entries_based_on')
|
||||
|
||||
for item in doc.get('items'):
|
||||
if item.get(enable_check):
|
||||
_book_deferred_revenue_or_expense(item)
|
||||
_book_deferred_revenue_or_expense(item, via_journal_entry, submit_journal_entry, book_deferred_entries_based_on)
|
||||
|
||||
def process_deferred_accounting(posting_date=None):
|
||||
''' Converts deferred income/expense into income/expense
|
||||
@ -281,3 +367,83 @@ def send_mail(deferred_process):
|
||||
and submit manually after resolving errors
|
||||
""").format(get_link_to_form('Process Deferred Accounting', deferred_process))
|
||||
sendmail_to_system_managers(title, content)
|
||||
|
||||
def book_revenue_via_journal_entry(doc, credit_account, debit_account, against,
|
||||
amount, base_amount, posting_date, project, account_currency, cost_center, item,
|
||||
deferred_process=None, submit='No'):
|
||||
|
||||
if amount == 0: return
|
||||
|
||||
journal_entry = frappe.new_doc('Journal Entry')
|
||||
journal_entry.posting_date = posting_date
|
||||
journal_entry.company = doc.company
|
||||
journal_entry.voucher_type = 'Deferred Revenue' if doc.doctype == 'Sales Invoice' \
|
||||
else 'Deferred Expense'
|
||||
|
||||
debit_entry = {
|
||||
'account': credit_account,
|
||||
'credit': base_amount,
|
||||
'credit_in_account_currency': amount,
|
||||
'party_type': 'Customer' if doc.doctype == 'Sales Invoice' else 'Supplier',
|
||||
'party': against,
|
||||
'account_currency': account_currency,
|
||||
'reference_name': doc.name,
|
||||
'reference_type': doc.doctype,
|
||||
'reference_detail_no': item.name,
|
||||
'cost_center': cost_center,
|
||||
'project': project,
|
||||
}
|
||||
|
||||
credit_entry = {
|
||||
'account': debit_account,
|
||||
'debit': base_amount,
|
||||
'debit_in_account_currency': amount,
|
||||
'party_type': 'Customer' if doc.doctype == 'Sales Invoice' else 'Supplier',
|
||||
'party': against,
|
||||
'account_currency': account_currency,
|
||||
'reference_name': doc.name,
|
||||
'reference_type': doc.doctype,
|
||||
'reference_detail_no': item.name,
|
||||
'cost_center': cost_center,
|
||||
'project': project,
|
||||
}
|
||||
|
||||
for dimension in get_accounting_dimensions():
|
||||
debit_entry.update({
|
||||
dimension: item.get(dimension)
|
||||
})
|
||||
|
||||
credit_entry.update({
|
||||
dimension: item.get(dimension)
|
||||
})
|
||||
|
||||
journal_entry.append('accounts', debit_entry)
|
||||
journal_entry.append('accounts', credit_entry)
|
||||
|
||||
try:
|
||||
journal_entry.save()
|
||||
|
||||
if submit:
|
||||
journal_entry.submit()
|
||||
except:
|
||||
frappe.db.rollback()
|
||||
traceback = frappe.get_traceback()
|
||||
frappe.log_error(message=traceback)
|
||||
|
||||
frappe.flags.deferred_accounting_error = True
|
||||
|
||||
def get_deferred_booking_accounts(doctype, voucher_detail_no, dr_or_cr):
|
||||
|
||||
if doctype == 'Sales Invoice':
|
||||
credit_account, debit_account = frappe.db.get_value('Sales Invoice Item', {'name': voucher_detail_no},
|
||||
['income_account', 'deferred_revenue_account'])
|
||||
else:
|
||||
credit_account, debit_account = frappe.db.get_value('Purchase Invoice Item', {'name': voucher_detail_no},
|
||||
['deferred_expense_account', 'expense_account'])
|
||||
|
||||
if dr_or_cr == 'Debit':
|
||||
return debit_account
|
||||
else:
|
||||
return credit_account
|
||||
|
||||
|
||||
|
@ -22,7 +22,12 @@
|
||||
"allow_cost_center_in_entry_of_bs_account",
|
||||
"add_taxes_from_item_tax_template",
|
||||
"automatically_fetch_payment_terms",
|
||||
"deferred_accounting_settings_section",
|
||||
"automatically_process_deferred_accounting_entry",
|
||||
"book_deferred_entries_based_on",
|
||||
"column_break_18",
|
||||
"book_deferred_entries_via_journal_entry",
|
||||
"submit_journal_entries",
|
||||
"print_settings",
|
||||
"show_inclusive_tax_in_print",
|
||||
"column_break_12",
|
||||
@ -189,13 +194,45 @@
|
||||
"fieldname": "automatically_process_deferred_accounting_entry",
|
||||
"fieldtype": "Check",
|
||||
"label": "Automatically Process Deferred Accounting Entry"
|
||||
},
|
||||
{
|
||||
"fieldname": "deferred_accounting_settings_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Deferred Accounting Settings"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_18",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"description": "If this is unchecked direct GL Entries will be created to book Deferred Revenue/Expense",
|
||||
"fieldname": "book_deferred_entries_via_journal_entry",
|
||||
"fieldtype": "Check",
|
||||
"label": "Book Deferred Entries Via Journal Entry"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.book_deferred_entries_via_journal_entry",
|
||||
"description": "If this is unchecked Journal Entries will be saved in a Draft state and will have to be submitted manually",
|
||||
"fieldname": "submit_journal_entries",
|
||||
"fieldtype": "Check",
|
||||
"label": "Submit Journal Entries"
|
||||
},
|
||||
{
|
||||
"default": "Days",
|
||||
"description": "If \"Months\" is selected then fixed amount will be booked as deferred revenue or expense for each month irrespective of number of days in a month. Will be prorated if deferred revenue or expense is not booked for an entire month.",
|
||||
"fieldname": "book_deferred_entries_based_on",
|
||||
"fieldtype": "Select",
|
||||
"label": "Book Deferred Entries Based On",
|
||||
"options": "Days\nMonths"
|
||||
}
|
||||
],
|
||||
"icon": "icon-cog",
|
||||
"idx": 1,
|
||||
"issingle": 1,
|
||||
"links": [],
|
||||
"modified": "2019-12-19 16:58:17.395595",
|
||||
"modified": "2020-06-22 20:13:26.043092",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Accounts Settings",
|
||||
|
@ -71,8 +71,13 @@ frappe.ui.form.on('Cost Center', {
|
||||
"label": "Cost Center Number",
|
||||
"fieldname": "cost_center_number",
|
||||
"fieldtype": "Data",
|
||||
"reqd": 1,
|
||||
"default": frm.doc.cost_center_number
|
||||
},
|
||||
{
|
||||
"label": __("Merge with existing"),
|
||||
"fieldname": "merge",
|
||||
"fieldtype": "Check",
|
||||
"default": 0
|
||||
}
|
||||
],
|
||||
primary_action: function() {
|
||||
@ -87,8 +92,9 @@ frappe.ui.form.on('Cost Center', {
|
||||
args: {
|
||||
docname: frm.doc.name,
|
||||
cost_center_name: data.cost_center_name,
|
||||
cost_center_number: data.cost_center_number,
|
||||
company: frm.doc.company
|
||||
cost_center_number: cstr(data.cost_center_number),
|
||||
company: frm.doc.company,
|
||||
merge: data.merge
|
||||
},
|
||||
callback: function(r) {
|
||||
frappe.dom.unfreeze();
|
||||
|
@ -4,7 +4,7 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe, erpnext
|
||||
from frappe import _
|
||||
from frappe.utils import flt, fmt_money, getdate, formatdate
|
||||
from frappe.utils import flt, fmt_money, getdate, formatdate, cint
|
||||
from frappe.model.document import Document
|
||||
from frappe.model.naming import set_name_from_naming_options
|
||||
from frappe.model.meta import get_field_precision
|
||||
@ -134,10 +134,17 @@ class GLEntry(Document):
|
||||
|
||||
return self.cost_center_company[self.cost_center]
|
||||
|
||||
def _check_is_group():
|
||||
return cint(frappe.get_cached_value('Cost Center', self.cost_center, 'is_group'))
|
||||
|
||||
if self.cost_center and _get_cost_center_company() != self.company:
|
||||
frappe.throw(_("{0} {1}: Cost Center {2} does not belong to Company {3}")
|
||||
.format(self.voucher_type, self.voucher_no, self.cost_center, self.company))
|
||||
|
||||
if self.cost_center and _check_is_group():
|
||||
frappe.throw(_("""{0} {1}: Cost Center {2} is a group cost center and group cost centers cannot
|
||||
be used in transactions""").format(self.voucher_type, self.voucher_no, frappe.bold(self.cost_center)))
|
||||
|
||||
def validate_party(self):
|
||||
validate_party_frozen_disabled(self.party_type, self.party)
|
||||
|
||||
|
@ -83,7 +83,7 @@
|
||||
"label": "Entry Type",
|
||||
"oldfieldname": "voucher_type",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "Journal Entry\nInter Company Journal Entry\nBank Entry\nCash Entry\nCredit Card Entry\nDebit Note\nCredit Note\nContra Entry\nExcise Entry\nWrite Off Entry\nOpening Entry\nDepreciation Entry\nExchange Rate Revaluation",
|
||||
"options": "Journal Entry\nInter Company Journal Entry\nBank Entry\nCash Entry\nCredit Card Entry\nDebit Note\nCredit Note\nContra Entry\nExcise Entry\nWrite Off Entry\nOpening Entry\nDepreciation Entry\nExchange Rate Revaluation\nDeferred Revenue\nDeferred Expense",
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
|
@ -10,6 +10,7 @@ from erpnext.accounts.utils import get_balance_on, get_account_currency
|
||||
from erpnext.accounts.party import get_party_account
|
||||
from erpnext.hr.doctype.expense_claim.expense_claim import update_reimbursed_amount
|
||||
from erpnext.accounts.doctype.invoice_discounting.invoice_discounting import get_party_account_based_on_invoice_discounting
|
||||
from erpnext.accounts.deferred_revenue import get_deferred_booking_accounts
|
||||
|
||||
from six import string_types, iteritems
|
||||
|
||||
@ -265,7 +266,10 @@ class JournalEntry(AccountsController):
|
||||
# set totals
|
||||
if not d.reference_name in self.reference_totals:
|
||||
self.reference_totals[d.reference_name] = 0.0
|
||||
self.reference_totals[d.reference_name] += flt(d.get(dr_or_cr))
|
||||
|
||||
if self.voucher_type not in ('Deferred Revenue', 'Deferred Expense'):
|
||||
self.reference_totals[d.reference_name] += flt(d.get(dr_or_cr))
|
||||
|
||||
self.reference_types[d.reference_name] = d.reference_type
|
||||
self.reference_accounts[d.reference_name] = d.account
|
||||
|
||||
@ -277,10 +281,16 @@ class JournalEntry(AccountsController):
|
||||
|
||||
# check if party and account match
|
||||
if d.reference_type in ("Sales Invoice", "Purchase Invoice"):
|
||||
if d.reference_type == "Sales Invoice":
|
||||
party_account = get_party_account_based_on_invoice_discounting(d.reference_name) or against_voucher[1]
|
||||
if self.voucher_type in ('Deferred Revenue', 'Deferred Expense') and d.reference_detail_no:
|
||||
debit_or_credit = 'Debit' if d.debit else 'Credit'
|
||||
party_account = get_deferred_booking_accounts(d.reference_type, d.reference_detail_no,
|
||||
debit_or_credit)
|
||||
else:
|
||||
party_account = against_voucher[1]
|
||||
if d.reference_type == "Sales Invoice":
|
||||
party_account = get_party_account_based_on_invoice_discounting(d.reference_name) or against_voucher[1]
|
||||
else:
|
||||
party_account = against_voucher[1]
|
||||
|
||||
if (against_voucher[0] != d.party or party_account != d.account):
|
||||
frappe.throw(_("Row {0}: Party / Account does not match with {1} / {2} in {3} {4}")
|
||||
.format(d.idx, field_dict.get(d.reference_type)[0], field_dict.get(d.reference_type)[1],
|
||||
@ -513,14 +523,20 @@ class JournalEntry(AccountsController):
|
||||
"against_voucher_type": d.reference_type,
|
||||
"against_voucher": d.reference_name,
|
||||
"remarks": remarks,
|
||||
"voucher_detail_no": d.reference_detail_no,
|
||||
"cost_center": d.cost_center,
|
||||
"project": d.project,
|
||||
"finance_book": self.finance_book
|
||||
}, item=d)
|
||||
)
|
||||
|
||||
if self.voucher_type in ('Deferred Revenue', 'Deferred Expense'):
|
||||
update_outstanding = 'No'
|
||||
else:
|
||||
update_outstanding = 'Yes'
|
||||
|
||||
if gl_map:
|
||||
make_gl_entries(gl_map, cancel=cancel, adv_adj=adv_adj)
|
||||
make_gl_entries(gl_map, cancel=cancel, adv_adj=adv_adj, update_outstanding=update_outstanding)
|
||||
|
||||
def get_balance(self):
|
||||
if not self.get('accounts'):
|
||||
|
@ -33,6 +33,7 @@
|
||||
"reference_type",
|
||||
"reference_name",
|
||||
"reference_due_date",
|
||||
"reference_detail_no",
|
||||
"col_break3",
|
||||
"is_advance",
|
||||
"user_remark",
|
||||
@ -268,6 +269,12 @@
|
||||
"fieldtype": "Link",
|
||||
"label": "Bank Account",
|
||||
"options": "Bank Account"
|
||||
},
|
||||
{
|
||||
"fieldname": "reference_detail_no",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "Reference Detail No"
|
||||
}
|
||||
],
|
||||
"idx": 1,
|
||||
|
@ -17,6 +17,8 @@ from six import string_types
|
||||
apply_on_dict = {"Item Code": "items",
|
||||
"Item Group": "item_groups", "Brand": "brands"}
|
||||
|
||||
other_fields = ["other_item_code", "other_item_group", "other_brand"]
|
||||
|
||||
class PricingRule(Document):
|
||||
def validate(self):
|
||||
self.validate_mandatory()
|
||||
@ -47,6 +49,13 @@ class PricingRule(Document):
|
||||
if tocheck and not self.get(tocheck):
|
||||
throw(_("{0} is required").format(self.meta.get_label(tocheck)), frappe.MandatoryError)
|
||||
|
||||
if self.apply_rule_on_other:
|
||||
o_field = 'other_' + frappe.scrub(self.apply_rule_on_other)
|
||||
if not self.get(o_field) and o_field in other_fields:
|
||||
frappe.throw(_("For the 'Apply Rule On Other' condition the field {0} is mandatory")
|
||||
.format(frappe.bold(self.apply_rule_on_other)))
|
||||
|
||||
|
||||
if self.price_or_product_discount == 'Price' and not self.rate_or_discount:
|
||||
throw(_("Rate or Discount is required for the price discount."), frappe.MandatoryError)
|
||||
|
||||
@ -80,13 +89,27 @@ class PricingRule(Document):
|
||||
for f in options:
|
||||
if not f: continue
|
||||
|
||||
f = frappe.scrub(f)
|
||||
if f!=fieldname:
|
||||
self.set(f, None)
|
||||
scrubbed_f = frappe.scrub(f)
|
||||
|
||||
if logic_field == 'apply_on':
|
||||
apply_on_f = apply_on_dict.get(f, f)
|
||||
else:
|
||||
apply_on_f = scrubbed_f
|
||||
|
||||
if scrubbed_f != fieldname:
|
||||
self.set(apply_on_f, None)
|
||||
|
||||
if self.mixed_conditions and self.get("same_item"):
|
||||
self.same_item = 0
|
||||
|
||||
apply_rule_on_other = frappe.scrub(self.apply_rule_on_other or "")
|
||||
|
||||
cleanup_other_fields = (other_fields if not apply_rule_on_other
|
||||
else [o_field for o_field in other_fields if o_field != 'other_' + apply_rule_on_other])
|
||||
|
||||
for other_field in cleanup_other_fields:
|
||||
self.set(other_field, None)
|
||||
|
||||
def validate_rate_or_discount(self):
|
||||
for field in ["Rate"]:
|
||||
if flt(self.get(frappe.scrub(field))) < 0:
|
||||
|
@ -10,6 +10,18 @@ frappe.ui.form.on('Process Deferred Accounting', {
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
if (frm.doc.company) {
|
||||
frm.set_query("account", function() {
|
||||
return {
|
||||
filters: {
|
||||
'company': frm.doc.company,
|
||||
'root_type': 'Liability',
|
||||
'is_group': 0
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
validate: function() {
|
||||
|
@ -238,6 +238,12 @@ class PurchaseInvoice(BuyingController):
|
||||
not frappe.db.get_value("Purchase Order Item", item.po_detail, "delivered_by_supplier")):
|
||||
|
||||
if self.update_stock and (not item.from_warehouse):
|
||||
if for_validate and item.expense_account and item.expense_account != warehouse_account[item.warehouse]["account"]:
|
||||
frappe.msgprint(_('''Row {0}: Expense Head changed to {1} because account {2}
|
||||
is not linked to warehouse {3} or it is not the default inventory account'''.format(
|
||||
item.idx, frappe.bold(warehouse_account[item.warehouse]["account"]),
|
||||
frappe.bold(item.expense_account), frappe.bold(item.warehouse))))
|
||||
|
||||
item.expense_account = warehouse_account[item.warehouse]["account"]
|
||||
else:
|
||||
# check if 'Stock Received But Not Billed' account is credited in Purchase receipt or not
|
||||
@ -247,10 +253,21 @@ class PurchaseInvoice(BuyingController):
|
||||
(item.purchase_receipt, stock_not_billed_account))
|
||||
|
||||
if negative_expense_booked_in_pr:
|
||||
if for_validate and item.expense_account and item.expense_account != stock_not_billed_account:
|
||||
frappe.msgprint(_('''Row {0}: Expense Head changed to {1} because
|
||||
expense is booked against this account in Purchase Receipt {2}'''.format(
|
||||
item.idx, frappe.bold(stock_not_billed_account), frappe.bold(item.purchase_receipt))))
|
||||
|
||||
item.expense_account = stock_not_billed_account
|
||||
else:
|
||||
# If no purchase receipt present then book expense in 'Stock Received But Not Billed'
|
||||
# This is done in cases when Purchase Invoice is created before Purchase Receipt
|
||||
if for_validate and item.expense_account and item.expense_account != stock_not_billed_account:
|
||||
frappe.msgprint(_('''Row {0}: Expense Head changed to {1} as no Purchase
|
||||
Receipt is created against Item {2}. This is done to handle accounting for cases
|
||||
when Purchase Receipt is created after Purchase Invoice'''.format(
|
||||
item.idx, frappe.bold(stock_not_billed_account), frappe.bold(item.item_code))))
|
||||
|
||||
item.expense_account = stock_not_billed_account
|
||||
|
||||
elif item.is_fixed_asset and not is_cwip_accounting_enabled(asset_category):
|
||||
|
@ -16,7 +16,7 @@ frappe.listview_settings['Purchase Invoice'] = {
|
||||
} else if(frappe.datetime.get_diff(doc.due_date) < 0) {
|
||||
return [__("Overdue"), "red", "outstanding_amount,>,0|due_date,<,Today"];
|
||||
} else {
|
||||
return [__("Unpaid"), "orange", "outstanding_amount,>,0|due,>=,Today"];
|
||||
return [__("Unpaid"), "orange", "outstanding_amount,>,0|due_date,>=,Today"];
|
||||
}
|
||||
} else if(cint(doc.is_return)) {
|
||||
return [__("Return"), "darkgrey", "is_return,=,Yes"];
|
||||
@ -24,4 +24,4 @@ frappe.listview_settings['Purchase Invoice'] = {
|
||||
return [__("Paid"), "green", "outstanding_amount,=,0"];
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
@ -7,14 +7,15 @@ import unittest
|
||||
import frappe, erpnext
|
||||
import frappe.model
|
||||
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
|
||||
from frappe.utils import cint, flt, today, nowdate, add_days
|
||||
from frappe.utils import cint, flt, today, nowdate, add_days, getdate
|
||||
import frappe.defaults
|
||||
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory, \
|
||||
test_records as pr_test_records, make_purchase_receipt, get_taxes
|
||||
from erpnext.controllers.accounts_controller import get_payment_terms
|
||||
from erpnext.exceptions import InvalidCurrency
|
||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import get_qty_after_transaction
|
||||
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
||||
from erpnext.accounts.doctype.account.test_account import get_inventory_account, create_account
|
||||
from erpnext.stock.doctype.item.test_item import create_item
|
||||
|
||||
test_dependencies = ["Item", "Cost Center", "Payment Term", "Payment Terms Template"]
|
||||
test_ignore = ["Serial No"]
|
||||
@ -866,6 +867,67 @@ class TestPurchaseInvoice(unittest.TestCase):
|
||||
for gle in gl_entries:
|
||||
self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
|
||||
|
||||
def test_deferred_expense_via_journal_entry(self):
|
||||
deferred_account = create_account(account_name="Deferred Expense",
|
||||
parent_account="Current Assets - _TC", company="_Test Company")
|
||||
|
||||
acc_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
|
||||
acc_settings.book_deferred_entries_via_journal_entry = 1
|
||||
acc_settings.submit_journal_entries = 1
|
||||
acc_settings.save()
|
||||
|
||||
item = create_item("_Test Item for Deferred Accounting")
|
||||
item.enable_deferred_expense = 1
|
||||
item.deferred_expense_account = deferred_account
|
||||
item.save()
|
||||
|
||||
pi = make_purchase_invoice(item=item.name, qty=1, rate=100, do_not_save=True)
|
||||
pi.set_posting_time = 1
|
||||
pi.posting_date = '2019-03-15'
|
||||
pi.items[0].enable_deferred_expense = 1
|
||||
pi.items[0].service_start_date = "2019-01-10"
|
||||
pi.items[0].service_end_date = "2019-03-15"
|
||||
pi.items[0].deferred_expense_account = deferred_account
|
||||
pi.save()
|
||||
pi.submit()
|
||||
|
||||
pda1 = frappe.get_doc(dict(
|
||||
doctype='Process Deferred Accounting',
|
||||
posting_date=nowdate(),
|
||||
start_date="2019-01-01",
|
||||
end_date="2019-03-31",
|
||||
type="Expense",
|
||||
company="_Test Company"
|
||||
))
|
||||
|
||||
pda1.insert()
|
||||
pda1.submit()
|
||||
|
||||
expected_gle = [
|
||||
["_Test Account Cost for Goods Sold - _TC", 0.0, 33.85, "2019-01-31"],
|
||||
[deferred_account, 33.85, 0.0, "2019-01-31"],
|
||||
["_Test Account Cost for Goods Sold - _TC", 0.0, 43.08, "2019-02-28"],
|
||||
[deferred_account, 43.08, 0.0, "2019-02-28"],
|
||||
["_Test Account Cost for Goods Sold - _TC", 0.0, 23.07, "2019-03-15"],
|
||||
[deferred_account, 23.07, 0.0, "2019-03-15"]
|
||||
]
|
||||
|
||||
gl_entries = gl_entries = frappe.db.sql("""select account, debit, credit, posting_date
|
||||
from `tabGL Entry`
|
||||
where voucher_type='Journal Entry' and voucher_detail_no=%s and posting_date <= %s
|
||||
order by posting_date asc, account asc""", (pi.items[0].name, pi.posting_date), as_dict=1)
|
||||
|
||||
for i, gle in enumerate(gl_entries):
|
||||
self.assertEqual(expected_gle[i][0], gle.account)
|
||||
self.assertEqual(expected_gle[i][1], gle.credit)
|
||||
self.assertEqual(expected_gle[i][2], gle.debit)
|
||||
self.assertEqual(getdate(expected_gle[i][3]), gle.posting_date)
|
||||
|
||||
acc_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
|
||||
acc_settings.book_deferred_entries_via_journal_entry = 0
|
||||
acc_settings.submit_journal_entriessubmit_journal_entries = 0
|
||||
acc_settings.save()
|
||||
|
||||
|
||||
def unlink_payment_on_cancel_of_invoice(enable=1):
|
||||
accounts_settings = frappe.get_doc("Accounts Settings")
|
||||
|
@ -1720,8 +1720,6 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
si.save()
|
||||
si.submit()
|
||||
|
||||
from erpnext.accounts.deferred_revenue import convert_deferred_revenue_to_income
|
||||
|
||||
pda1 = frappe.get_doc(dict(
|
||||
doctype='Process Deferred Accounting',
|
||||
posting_date=nowdate(),
|
||||
@ -1745,6 +1743,55 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
|
||||
check_gl_entries(self, si.name, expected_gle, "2019-01-30")
|
||||
|
||||
def test_fixed_deferred_revenue(self):
|
||||
deferred_account = create_account(account_name="Deferred Revenue",
|
||||
parent_account="Current Liabilities - _TC", company="_Test Company")
|
||||
|
||||
acc_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
|
||||
acc_settings.book_deferred_entries_based_on = 'Months'
|
||||
acc_settings.save()
|
||||
|
||||
item = create_item("_Test Item for Deferred Accounting")
|
||||
item.enable_deferred_revenue = 1
|
||||
item.deferred_revenue_account = deferred_account
|
||||
item.no_of_months = 12
|
||||
item.save()
|
||||
|
||||
si = create_sales_invoice(item=item.name, posting_date="2019-01-16", rate=50000, do_not_submit=True)
|
||||
si.items[0].enable_deferred_revenue = 1
|
||||
si.items[0].service_start_date = "2019-01-16"
|
||||
si.items[0].service_end_date = "2019-03-31"
|
||||
si.items[0].deferred_revenue_account = deferred_account
|
||||
si.save()
|
||||
si.submit()
|
||||
|
||||
pda1 = frappe.get_doc(dict(
|
||||
doctype='Process Deferred Accounting',
|
||||
posting_date='2019-03-31',
|
||||
start_date="2019-01-01",
|
||||
end_date="2019-03-31",
|
||||
type="Income",
|
||||
company="_Test Company"
|
||||
))
|
||||
|
||||
pda1.insert()
|
||||
pda1.submit()
|
||||
|
||||
expected_gle = [
|
||||
[deferred_account, 10000.0, 0.0, "2019-01-31"],
|
||||
["Sales - _TC", 0.0, 10000.0, "2019-01-31"],
|
||||
[deferred_account, 20000.0, 0.0, "2019-02-28"],
|
||||
["Sales - _TC", 0.0, 20000.0, "2019-02-28"],
|
||||
[deferred_account, 20000.0, 0.0, "2019-03-31"],
|
||||
["Sales - _TC", 0.0, 20000.0, "2019-03-31"]
|
||||
]
|
||||
|
||||
check_gl_entries(self, si.name, expected_gle, "2019-01-30")
|
||||
|
||||
acc_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
|
||||
acc_settings.book_deferred_entries_based_on = 'Days'
|
||||
acc_settings.save()
|
||||
|
||||
def test_inter_company_transaction(self):
|
||||
|
||||
if not frappe.db.exists("Customer", "_Test Internal Customer"):
|
||||
|
@ -61,7 +61,7 @@ def make_sales_invoice():
|
||||
debit_to = 'Debtors - _TC2',
|
||||
income_account = 'Sales - _TC2',
|
||||
expense_account = 'Cost of Goods Sold - _TC2',
|
||||
cost_center = '_Test Company 2 - _TC2')
|
||||
cost_center = 'Main - _TC2')
|
||||
|
||||
|
||||
|
||||
|
@ -63,7 +63,7 @@ def make_sales_invoice():
|
||||
debit_to = 'Debtors - _TC2',
|
||||
income_account = 'Sales - _TC2',
|
||||
expense_account = 'Cost of Goods Sold - _TC2',
|
||||
cost_center = '_Test Company 2 - _TC2',
|
||||
cost_center = 'Main - _TC2',
|
||||
do_not_save=1)
|
||||
|
||||
si.append('payment_schedule', dict(due_date=getdate(add_days(today(), 30)), invoice_portion=30.00, payment_amount=30))
|
||||
@ -83,14 +83,14 @@ def make_payment(docname):
|
||||
|
||||
def make_credit_note(docname):
|
||||
create_sales_invoice(company="_Test Company 2",
|
||||
customer = '_Test Customer 2',
|
||||
currency = 'EUR',
|
||||
qty = -1,
|
||||
warehouse = 'Finished Goods - _TC2',
|
||||
debit_to = 'Debtors - _TC2',
|
||||
income_account = 'Sales - _TC2',
|
||||
expense_account = 'Cost of Goods Sold - _TC2',
|
||||
cost_center = '_Test Company 2 - _TC2',
|
||||
is_return = 1,
|
||||
return_against = docname)
|
||||
customer = '_Test Customer 2',
|
||||
currency = 'EUR',
|
||||
qty = -1,
|
||||
warehouse = 'Finished Goods - _TC2',
|
||||
debit_to = 'Debtors - _TC2',
|
||||
income_account = 'Sales - _TC2',
|
||||
expense_account = 'Cost of Goods Sold - _TC2',
|
||||
cost_center = 'Main - _TC2',
|
||||
is_return = 1,
|
||||
return_against = docname)
|
||||
|
||||
|
@ -837,7 +837,7 @@ def create_payment_gateway_account(gateway):
|
||||
pass
|
||||
|
||||
@frappe.whitelist()
|
||||
def update_cost_center(docname, cost_center_name, cost_center_number, company):
|
||||
def update_cost_center(docname, cost_center_name, cost_center_number, company, merge):
|
||||
'''
|
||||
Renames the document by adding the number as a prefix to the current name and updates
|
||||
all transaction where it was present.
|
||||
@ -853,7 +853,7 @@ def update_cost_center(docname, cost_center_name, cost_center_number, company):
|
||||
|
||||
new_name = get_autoname_with_number(cost_center_number, cost_center_name, docname, company)
|
||||
if docname != new_name:
|
||||
frappe.rename_doc("Cost Center", docname, new_name, force=1)
|
||||
frappe.rename_doc("Cost Center", docname, new_name, force=1, merge=merge)
|
||||
return new_name
|
||||
|
||||
def validate_field_number(doctype_name, docname, number_value, company, field_name):
|
||||
|
@ -20,6 +20,7 @@ from erpnext.exceptions import InvalidCurrency
|
||||
from six import text_type
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
|
||||
from erpnext.stock.get_item_details import get_item_warehouse
|
||||
from erpnext.stock.doctype.packed_item.packed_item import make_packing_list
|
||||
|
||||
force_item_fields = ("item_group", "brand", "stock_uom", "is_fixed_asset", "item_tax_rate", "pricing_rules")
|
||||
|
||||
@ -1301,6 +1302,7 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
|
||||
parent.set_qty_as_per_stock_uom()
|
||||
parent.calculate_taxes_and_totals()
|
||||
if parent_doctype == "Sales Order":
|
||||
make_packing_list(parent)
|
||||
parent.set_gross_profit()
|
||||
frappe.get_doc('Authorization Control').validate_approving_authority(parent.doctype,
|
||||
parent.company, parent.base_grand_total)
|
||||
|
@ -29,6 +29,9 @@
|
||||
"requires_fulfilment",
|
||||
"fulfilment_deadline",
|
||||
"fulfilment_terms",
|
||||
"authorised_by_section",
|
||||
"signee_company",
|
||||
"signed_by_company",
|
||||
"sb_references",
|
||||
"document_type",
|
||||
"cb_links",
|
||||
@ -223,10 +226,28 @@
|
||||
"options": "Contract",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "signee_company",
|
||||
"fieldtype": "Signature",
|
||||
"label": "Signee (Company)"
|
||||
},
|
||||
{
|
||||
"fieldname": "signed_by_company",
|
||||
"fieldtype": "Link",
|
||||
"label": "Signed By (Company)",
|
||||
"options": "User",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "authorised_by_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Authorised By"
|
||||
}
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"modified": "2019-09-30 00:56:41.559681",
|
||||
"links": [],
|
||||
"modified": "2020-03-30 06:56:07.257932",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "Contract",
|
||||
|
@ -29,6 +29,9 @@ class Contract(Document):
|
||||
self.update_contract_status()
|
||||
self.update_fulfilment_status()
|
||||
|
||||
def before_submit(self):
|
||||
self.signed_by_company = frappe.session.user
|
||||
|
||||
def before_update_after_submit(self):
|
||||
self.update_contract_status()
|
||||
self.update_fulfilment_status()
|
||||
|
@ -1,306 +1,106 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "field:title",
|
||||
"beta": 0,
|
||||
"creation": "2018-04-16 06:44:48.791312",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"actions": [],
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:title",
|
||||
"creation": "2018-04-16 06:44:48.791312",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"title",
|
||||
"contract_terms",
|
||||
"sb_fulfilment",
|
||||
"requires_fulfilment",
|
||||
"fulfilment_terms"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "title",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Title",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "title",
|
||||
"fieldtype": "Data",
|
||||
"label": "Title",
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "sb_terms",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "",
|
||||
"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
|
||||
},
|
||||
"fieldname": "contract_terms",
|
||||
"fieldtype": "Text Editor",
|
||||
"label": "Contract Terms and Conditions",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "contract_terms",
|
||||
"fieldtype": "Text Editor",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Contract Terms and Conditions",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "",
|
||||
"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
|
||||
},
|
||||
"fieldname": "sb_fulfilment",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "sb_fulfilment",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "",
|
||||
"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
|
||||
},
|
||||
"default": "0",
|
||||
"fieldname": "requires_fulfilment",
|
||||
"fieldtype": "Check",
|
||||
"label": "Requires Fulfilment"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "requires_fulfilment",
|
||||
"fieldtype": "Check",
|
||||
"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": "Requires Fulfilment",
|
||||
"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_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.requires_fulfilment==1",
|
||||
"fieldname": "fulfilment_terms",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Fulfilment Terms and Conditions",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Contract Template Fulfilment Terms",
|
||||
"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
|
||||
"depends_on": "eval:doc.requires_fulfilment==1",
|
||||
"fieldname": "fulfilment_terms",
|
||||
"fieldtype": "Table",
|
||||
"label": "Fulfilment Terms and Conditions",
|
||||
"options": "Contract Template Fulfilment Terms"
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-04-17 07:36:05.217599",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "Contract Template",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2020-06-03 00:24:58.179816",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "Contract Template",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Sales Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Sales Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Purchase Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Purchase Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
@ -96,6 +96,7 @@ frappe.ui.form.on("Opportunity", {
|
||||
});
|
||||
} else {
|
||||
frm.add_custom_button(__("Reopen"), function() {
|
||||
frm.set_value("lost_reasons",[])
|
||||
frm.set_value("status", "Open");
|
||||
frm.save();
|
||||
});
|
||||
|
@ -22,6 +22,7 @@ class EmployeeAdvance(Document):
|
||||
self.validate_employee_advance_account()
|
||||
|
||||
def on_cancel(self):
|
||||
self.ignore_linked_doctypes = ('GL Entry')
|
||||
self.set_status()
|
||||
|
||||
def set_status(self):
|
||||
|
@ -20,10 +20,9 @@ class JobOffer(Document):
|
||||
staffing_plan = get_staffing_plan_detail(self.designation, self.company, self.offer_date)
|
||||
check_vacancies = frappe.get_single("HR Settings").check_vacancies
|
||||
if staffing_plan and check_vacancies:
|
||||
vacancies = frappe.db.get_value("Staffing Plan Detail", filters={"name": staffing_plan.name}, fieldname=['vacancies'])
|
||||
job_offers = len(self.get_job_offer(staffing_plan.from_date, staffing_plan.to_date))
|
||||
if vacancies - job_offers <= 0:
|
||||
frappe.throw(_("There are no vacancies under staffing plan {0}").format(get_link_to_form("Staffing Plan", staffing_plan.parent)))
|
||||
job_offers = self.get_job_offer(staffing_plan.from_date, staffing_plan.to_date)
|
||||
if staffing_plan.vacancies - len(job_offers) <= 0:
|
||||
frappe.throw(_("There are no vacancies under staffing plan {0}").format(frappe.bold(get_link_to_form("Staffing Plan", staffing_plan.parent))))
|
||||
|
||||
def on_change(self):
|
||||
update_job_applicant(self.status, self.job_applicant)
|
||||
@ -42,18 +41,22 @@ def update_job_applicant(status, job_applicant):
|
||||
|
||||
def get_staffing_plan_detail(designation, company, offer_date):
|
||||
detail = frappe.db.sql("""
|
||||
SELECT spd.name as name,
|
||||
SELECT DISTINCT spd.parent,
|
||||
sp.from_date as from_date,
|
||||
sp.to_date as to_date,
|
||||
sp.name as parent
|
||||
sp.name,
|
||||
sum(spd.vacancies) as vacancies,
|
||||
spd.designation
|
||||
FROM `tabStaffing Plan Detail` spd, `tabStaffing Plan` sp
|
||||
WHERE
|
||||
sp.docstatus=1
|
||||
AND spd.designation=%s
|
||||
AND sp.company=%s
|
||||
AND spd.parent = sp.name
|
||||
AND %s between sp.from_date and sp.to_date
|
||||
""", (designation, company, offer_date), as_dict=1)
|
||||
return detail[0] if detail else None
|
||||
|
||||
return frappe._dict(detail[0]) if detail else None
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_employee(source_name, target_doc=None):
|
||||
|
@ -699,9 +699,10 @@ erpnext.patches.v13_0.delete_old_purchase_reports
|
||||
erpnext.patches.v12_0.set_italian_import_supplier_invoice_permissions
|
||||
erpnext.patches.v13_0.update_sla_enhancements
|
||||
erpnext.patches.v12_0.update_address_template_for_india
|
||||
erpnext.patches.v13_0.update_deferred_settings
|
||||
erpnext.patches.v12_0.set_multi_uom_in_rfq
|
||||
erpnext.patches.v13_0.delete_old_sales_reports
|
||||
execute:frappe.delete_doc_if_exists("DocType", "Bank Reconciliation")
|
||||
erpnext.patches.v13_0.move_doctype_reports_and_notification_from_hr_to_payroll
|
||||
erpnext.patches.v13_0.move_payroll_setting_separately_from_hr_settings
|
||||
erpnext.patches.v13_0.check_is_income_tax_component
|
||||
erpnext.patches.v13_0.move_doctype_reports_and_notification_from_hr_to_payroll #22-06-2020
|
||||
erpnext.patches.v13_0.move_payroll_setting_separately_from_hr_settings #22-06-2020
|
||||
erpnext.patches.v13_0.check_is_income_tax_component #22-06-2020
|
||||
|
@ -4,9 +4,28 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe, erpnext
|
||||
from erpnext.regional.india.setup import setup
|
||||
|
||||
def execute():
|
||||
frappe.reload_doc('Payroll', 'doctype', 'salary_structure')
|
||||
|
||||
doctypes = ['salary_component',
|
||||
'Employee Tax Exemption Declaration',
|
||||
'Employee Tax Exemption Proof Submission',
|
||||
'Employee Tax Exemption Declaration Category',
|
||||
'Employee Tax Exemption Proof Submission Detail'
|
||||
]
|
||||
|
||||
for doctype in doctypes:
|
||||
frappe.reload_doc('Payroll', 'doctype', doctype)
|
||||
|
||||
|
||||
reports = ['Professional Tax Deductions', 'Provident Fund Deductions']
|
||||
for report in reports:
|
||||
frappe.reload_doc('Regional', 'Report', report)
|
||||
frappe.reload_doc('Regional', 'Report', report)
|
||||
|
||||
if erpnext.get_region() == "India":
|
||||
setup(patch=True)
|
||||
|
||||
if frappe.db.exists("Salary Component", "Income Tax"):
|
||||
frappe.db.set_value("Salary Component", "Income Tax", "is_income_tax_component", 1)
|
||||
|
11
erpnext/patches/v13_0/update_deferred_settings.py
Normal file
11
erpnext/patches/v13_0/update_deferred_settings.py
Normal file
@ -0,0 +1,11 @@
|
||||
# Copyright (c) 2019, Frappe and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
|
||||
accounts_settings.book_deferred_entries_based_on = 'Days'
|
||||
accounts_settings.book_deferred_entries_via_journal_entry = 0
|
||||
accounts_settings.submit_journal_entries = 0
|
||||
accounts_settings.save()
|
@ -163,7 +163,7 @@
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-05-27 21:10:50.374063",
|
||||
"modified": "2020-06-22 21:10:50.374063",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Additional Salary",
|
||||
|
@ -119,7 +119,7 @@
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-05-27 22:58:31.271922",
|
||||
"modified": "2020-06-22 22:58:31.271922",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Employee Benefit Application",
|
||||
|
@ -45,7 +45,7 @@
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-05-27 23:45:00.519134",
|
||||
"modified": "2020-06-22 23:45:00.519134",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Employee Benefit Application Detail",
|
||||
|
@ -123,7 +123,7 @@
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-05-27 23:01:50.791676",
|
||||
"modified": "2020-06-22 23:01:50.791676",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Employee Benefit Claim",
|
||||
|
@ -74,7 +74,7 @@
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-05-27 22:42:51.209630",
|
||||
"modified": "2020-06-22 22:42:51.209630",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Employee Incentive",
|
||||
|
@ -76,7 +76,7 @@
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-05-27 22:55:17.604688",
|
||||
"modified": "2020-06-22 22:55:17.604688",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Employee Other Income",
|
||||
|
@ -26,7 +26,7 @@
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2020-05-27 23:16:47.472910",
|
||||
"modified": "2020-06-22 23:16:47.472910",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Employee Tax Exemption Category",
|
||||
|
@ -107,7 +107,7 @@
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-05-27 22:49:43.829892",
|
||||
"modified": "2020-06-22 22:49:43.829892",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Employee Tax Exemption Declaration",
|
||||
|
@ -48,7 +48,7 @@
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-05-27 23:41:03.638739",
|
||||
"modified": "2020-06-22 23:41:03.638739",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Employee Tax Exemption Declaration Category",
|
||||
|
@ -130,7 +130,7 @@
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-05-27 22:53:10.412321",
|
||||
"modified": "2020-06-22 22:53:10.412321",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Employee Tax Exemption Proof Submission",
|
||||
|
@ -53,7 +53,7 @@
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-05-27 23:37:08.265600",
|
||||
"modified": "2020-06-22 23:37:08.265600",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Employee Tax Exemption Proof Submission Detail",
|
||||
|
@ -38,7 +38,7 @@
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2020-05-27 23:18:08.254645",
|
||||
"modified": "2020-06-22 23:18:08.254645",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Employee Tax Exemption Sub Category",
|
||||
|
@ -94,7 +94,7 @@
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-05-27 20:27:13.425084",
|
||||
"modified": "2020-06-22 20:27:13.425084",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Income Tax Slab",
|
||||
|
@ -62,7 +62,7 @@
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-05-27 23:33:17.931912",
|
||||
"modified": "2020-06-22 23:33:17.931912",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Income Tax Slab Other Charges",
|
||||
|
@ -52,7 +52,7 @@
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-05-27 23:25:13.779032",
|
||||
"modified": "2020-06-22 23:25:13.779032",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Payroll Employee Detail",
|
||||
|
@ -262,7 +262,7 @@
|
||||
"icon": "fa fa-cog",
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-05-27 20:06:06.953904",
|
||||
"modified": "2020-06-22 20:06:06.953904",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Payroll Entry",
|
||||
|
@ -53,7 +53,7 @@
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2020-05-27 20:12:32.684189",
|
||||
"modified": "2020-06-22 20:12:32.684189",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Payroll Period",
|
||||
|
@ -26,7 +26,7 @@
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-05-27 23:30:15.943356",
|
||||
"modified": "2020-06-22 23:30:15.943356",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Payroll Period Date",
|
||||
|
@ -63,7 +63,7 @@
|
||||
"description": "The fraction of daily wages to be paid for half-day attendance",
|
||||
"fieldname": "daily_wages_fraction_for_half_day",
|
||||
"fieldtype": "Float",
|
||||
"label": "Daily Wages Fraction for Half Day",
|
||||
"label": "Fraction of Daily Salary for Half Day",
|
||||
"show_days": 1,
|
||||
"show_seconds": 1
|
||||
},
|
||||
@ -109,7 +109,7 @@
|
||||
"icon": "fa fa-cog",
|
||||
"issingle": 1,
|
||||
"links": [],
|
||||
"modified": "2020-06-05 12:35:34.861674",
|
||||
"modified": "2020-06-22 17:00:58.408030",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Payroll Settings",
|
||||
|
@ -93,7 +93,7 @@
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-05-27 22:42:05.251951",
|
||||
"modified": "2020-06-22 22:42:05.251951",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Retention Bonus",
|
||||
|
@ -245,7 +245,7 @@
|
||||
],
|
||||
"icon": "fa fa-flag",
|
||||
"links": [],
|
||||
"modified": "2020-06-01 15:39:20.826565",
|
||||
"modified": "2020-06-22 15:39:20.826565",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Salary Component",
|
||||
|
@ -211,7 +211,7 @@
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-05-27 23:21:26.300951",
|
||||
"modified": "2020-06-22 23:21:26.300951",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Salary Detail",
|
||||
|
@ -616,7 +616,7 @@
|
||||
"idx": 9,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-06-05 14:42:43.921828",
|
||||
"modified": "2020-06-22 14:42:43.921828",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Salary Slip",
|
||||
|
@ -28,7 +28,7 @@
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-05-27 23:27:43.463532",
|
||||
"modified": "2020-06-22 23:27:43.463532",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Salary Slip Timesheet",
|
||||
|
@ -8,7 +8,7 @@
|
||||
Variables from Employee:<br> <code>Employment Type = employment_type</code>, <code>Branch = branch</code> etc.
|
||||
</li>
|
||||
<li>
|
||||
Variables Salary Slip:<br>
|
||||
Variables from Salary Slip:<br>
|
||||
<code>Payment Days = payment_days</code>, <code>Leave without pay = leave_without_pay</code> etc.
|
||||
</li>
|
||||
<li>
|
||||
|
@ -282,7 +282,7 @@
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-06-05 17:07:26.129355",
|
||||
"modified": "2020-06-22 17:07:26.129355",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Salary Structure",
|
||||
|
@ -124,7 +124,7 @@
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-05-27 19:58:09.964692",
|
||||
"modified": "2020-06-22 19:58:09.964692",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Salary Structure Assignment",
|
||||
|
@ -14,6 +14,7 @@
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "from_amount",
|
||||
"fieldtype": "Currency",
|
||||
"in_list_view": 1,
|
||||
@ -27,6 +28,7 @@
|
||||
"label": "To Amount"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "percent_deduction",
|
||||
"fieldtype": "Percent",
|
||||
"in_list_view": 1,
|
||||
@ -51,7 +53,7 @@
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-05-27 23:32:47.253106",
|
||||
"modified": "2020-06-22 18:16:07.596493",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Taxable Salary Slab",
|
||||
|
@ -86,6 +86,7 @@ def get_conditions(filters):
|
||||
|
||||
if filters.get("period"):
|
||||
conditions.append("month(start_date) = '%s' " % (filters["period"]))
|
||||
conditions.append("year(start_date) = '%s' " % (frappe.utils.getdate().year))
|
||||
|
||||
return " and ".join(conditions)
|
||||
|
||||
|
@ -335,6 +335,16 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
|
||||
var tax_rate = this._get_tax_rate(tax, item_tax_map);
|
||||
var current_tax_amount = 0.0;
|
||||
|
||||
// To set row_id by default as previous row.
|
||||
if(["On Previous Row Amount", "On Previous Row Total"].includes(tax.charge_type)) {
|
||||
if (tax.idx === 1) {
|
||||
frappe.throw(
|
||||
__("Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row"));
|
||||
}
|
||||
if (!tax.row_id) {
|
||||
tax.row_id = tax.idx - 1;
|
||||
}
|
||||
}
|
||||
if(tax.charge_type == "Actual") {
|
||||
// distribute the tax amount proportionally to each item row
|
||||
var actual = flt(tax.tax_amount, precision("tax_amount", tax));
|
||||
|
@ -7,7 +7,7 @@ from __future__ import unicode_literals
|
||||
import frappe
|
||||
test_records = frappe.get_test_records('Product Bundle')
|
||||
|
||||
def make_product_bundle(parent, items):
|
||||
def make_product_bundle(parent, items, qty=None):
|
||||
if frappe.db.exists("Product Bundle", parent):
|
||||
return frappe.get_doc("Product Bundle", parent)
|
||||
|
||||
@ -17,7 +17,7 @@ def make_product_bundle(parent, items):
|
||||
})
|
||||
|
||||
for item in items:
|
||||
product_bundle.append("items", {"item_code": item, "qty": 1})
|
||||
product_bundle.append("items", {"item_code": item, "qty": qty or 1})
|
||||
|
||||
product_bundle.insert()
|
||||
|
||||
|
@ -99,6 +99,8 @@ class Quotation(SellingController):
|
||||
self.update_lead()
|
||||
|
||||
def on_cancel(self):
|
||||
if self.lost_reasons:
|
||||
self.lost_reasons = []
|
||||
super(Quotation, self).on_cancel()
|
||||
|
||||
#update enquiry status
|
||||
|
@ -2,6 +2,7 @@
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
import json
|
||||
from frappe.utils import flt, add_days, nowdate
|
||||
import frappe.permissions
|
||||
import unittest
|
||||
@ -10,9 +11,10 @@ from erpnext.selling.doctype.sales_order.sales_order \
|
||||
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
|
||||
from erpnext.selling.doctype.sales_order.sales_order import make_work_orders
|
||||
from erpnext.controllers.accounts_controller import update_child_qty_rate
|
||||
import json
|
||||
from erpnext.selling.doctype.sales_order.sales_order import make_raw_material_request
|
||||
from erpnext.manufacturing.doctype.blanket_order.test_blanket_order import make_blanket_order
|
||||
from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
|
||||
class TestSalesOrder(unittest.TestCase):
|
||||
def tearDown(self):
|
||||
@ -417,6 +419,26 @@ class TestSalesOrder(unittest.TestCase):
|
||||
self.assertRaises(frappe.ValidationError, update_child_qty_rate,'Sales Order', trans_item, so.name)
|
||||
frappe.set_user("Administrator")
|
||||
|
||||
def test_update_child_qty_rate_product_bundle(self):
|
||||
# test Update Items with product bundle
|
||||
if not frappe.db.exists("Item", "_Product Bundle Item"):
|
||||
bundle_item = make_item("_Product Bundle Item", {"is_stock_item": 0})
|
||||
bundle_item.append("item_defaults", {
|
||||
"company": "_Test Company",
|
||||
"default_warehouse": "_Test Warehouse - _TC"})
|
||||
bundle_item.save(ignore_permissions=True)
|
||||
|
||||
make_item("_Packed Item", {"is_stock_item": 1})
|
||||
make_product_bundle("_Product Bundle Item", ["_Packed Item"], 2)
|
||||
|
||||
so = make_sales_order(item_code = "_Test Item", warehouse=None)
|
||||
|
||||
added_item = json.dumps([{"item_code" : "_Product Bundle Item", "rate" : 200, 'qty' : 2}])
|
||||
update_child_qty_rate('Sales Order', added_item, so.name)
|
||||
|
||||
so.reload()
|
||||
self.assertEqual(so.packed_items[0].qty, 4)
|
||||
|
||||
def test_warehouse_user(self):
|
||||
frappe.permissions.add_user_permission("Warehouse", "_Test Warehouse 1 - _TC", "test@example.com")
|
||||
frappe.permissions.add_user_permission("Warehouse", "_Test Warehouse 2 - _TC1", "test2@example.com")
|
||||
@ -457,8 +479,6 @@ class TestSalesOrder(unittest.TestCase):
|
||||
self.assertRaises(frappe.CancelledLinkError, dn.submit)
|
||||
|
||||
def test_service_type_product_bundle(self):
|
||||
from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
make_item("_Test Service Product Bundle", {"is_stock_item": 0})
|
||||
make_item("_Test Service Product Bundle Item 1", {"is_stock_item": 0})
|
||||
make_item("_Test Service Product Bundle Item 2", {"is_stock_item": 0})
|
||||
@ -472,8 +492,6 @@ class TestSalesOrder(unittest.TestCase):
|
||||
self.assertTrue("_Test Service Product Bundle Item 2" in [d.item_code for d in so.packed_items])
|
||||
|
||||
def test_mix_type_product_bundle(self):
|
||||
from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
make_item("_Test Mix Product Bundle", {"is_stock_item": 0})
|
||||
make_item("_Test Mix Product Bundle Item 1", {"is_stock_item": 1})
|
||||
make_item("_Test Mix Product Bundle Item 2", {"is_stock_item": 0})
|
||||
@ -484,7 +502,6 @@ class TestSalesOrder(unittest.TestCase):
|
||||
self.assertRaises(WarehouseRequired, make_sales_order, item_code = "_Test Mix Product Bundle", warehouse="")
|
||||
|
||||
def test_auto_insert_price(self):
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
make_item("_Test Item for Auto Price List", {"is_stock_item": 0})
|
||||
frappe.db.set_value("Stock Settings", None, "auto_insert_price_list_rate_if_missing", 1)
|
||||
|
||||
@ -519,7 +536,6 @@ class TestSalesOrder(unittest.TestCase):
|
||||
from erpnext.buying.doctype.purchase_order.purchase_order import update_status
|
||||
|
||||
make_stock_entry(target="_Test Warehouse - _TC", qty=10, rate=100)
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
po_item = make_item("_Test Item for Drop Shipping", {"is_stock_item": 1, "delivered_by_supplier": 1})
|
||||
|
||||
dn_item = make_item("_Test Regular Item", {"is_stock_item": 1})
|
||||
@ -714,7 +730,6 @@ class TestSalesOrder(unittest.TestCase):
|
||||
|
||||
def test_serial_no_based_delivery(self):
|
||||
frappe.set_value("Stock Settings", None, "automatically_set_serial_nos_based_on_fifo", 1)
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
item = make_item("_Reserved_Serialized_Item", {"is_stock_item": 1,
|
||||
"maintain_stock": 1,
|
||||
"has_serial_no": 1,
|
||||
@ -835,7 +850,6 @@ class TestSalesOrder(unittest.TestCase):
|
||||
self.assertRaises(frappe.LinkExistsError, so_doc.cancel)
|
||||
|
||||
def test_request_for_raw_materials(self):
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
item = make_item("_Test Finished Item", {"is_stock_item": 1,
|
||||
"maintain_stock": 1,
|
||||
"valuation_rate": 500,
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"add_total_row": 0,
|
||||
"add_total_row": 1,
|
||||
"creation": "2018-09-21 12:46:29.451048",
|
||||
"disable_prepared_report": 0,
|
||||
"disabled": 0,
|
||||
@ -7,7 +7,7 @@
|
||||
"doctype": "Report",
|
||||
"idx": 0,
|
||||
"is_standard": "Yes",
|
||||
"modified": "2020-04-30 19:49:02.303320",
|
||||
"modified": "2020-06-19 17:41:03.132101",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Sales Analytics",
|
||||
|
@ -23,7 +23,14 @@ class Analytics(object):
|
||||
self.get_columns()
|
||||
self.get_data()
|
||||
self.get_chart_data()
|
||||
return self.columns, self.data, None, self.chart
|
||||
|
||||
# Skipping total row for tree-view reports
|
||||
skip_total_row = 0
|
||||
|
||||
if self.filters.tree_type in ["Supplier Group", "Item Group", "Customer Group", "Territory"]:
|
||||
skip_total_row = 1
|
||||
|
||||
return self.columns, self.data, None, self.chart, None, skip_total_row
|
||||
|
||||
def get_columns(self):
|
||||
self.columns = [{
|
||||
@ -194,9 +201,6 @@ class Analytics(object):
|
||||
def get_rows(self):
|
||||
self.data = []
|
||||
self.get_periodic_data()
|
||||
total_row = {
|
||||
"entity": "Total",
|
||||
}
|
||||
|
||||
for entity, period_data in iteritems(self.entity_periodic_data):
|
||||
row = {
|
||||
@ -210,9 +214,6 @@ class Analytics(object):
|
||||
row[scrub(period)] = amount
|
||||
total += amount
|
||||
|
||||
if not total_row.get(scrub(period)): total_row[scrub(period)] = 0
|
||||
total_row[scrub(period)] += amount
|
||||
|
||||
row["total"] = total
|
||||
|
||||
if self.filters.tree_type == "Item":
|
||||
@ -220,8 +221,6 @@ class Analytics(object):
|
||||
|
||||
self.data.append(row)
|
||||
|
||||
self.data.append(total_row)
|
||||
|
||||
def get_rows_by_group(self):
|
||||
self.get_periodic_data()
|
||||
out = []
|
||||
|
@ -33,21 +33,6 @@ class TestAnalytics(unittest.TestCase):
|
||||
report = execute(filters)
|
||||
|
||||
expected_data = [
|
||||
{
|
||||
'entity': 'Total',
|
||||
'apr_2017': 0.0,
|
||||
'may_2017': 0.0,
|
||||
'jun_2017': 2000.0,
|
||||
'jul_2017': 1000.0,
|
||||
'aug_2017': 0.0,
|
||||
'sep_2017': 1500.0,
|
||||
'oct_2017': 1000.0,
|
||||
'nov_2017': 0.0,
|
||||
'dec_2017': 0.0,
|
||||
'jan_2018': 0.0,
|
||||
'feb_2018': 2000.0,
|
||||
'mar_2018': 0.0
|
||||
},
|
||||
{
|
||||
"entity": "_Test Customer 1",
|
||||
"entity_name": "_Test Customer 1",
|
||||
@ -149,21 +134,6 @@ class TestAnalytics(unittest.TestCase):
|
||||
report = execute(filters)
|
||||
|
||||
expected_data = [
|
||||
{
|
||||
'entity': 'Total',
|
||||
'apr_2017': 0.0,
|
||||
'may_2017': 0.0,
|
||||
'jun_2017': 20.0,
|
||||
'jul_2017': 10.0,
|
||||
'aug_2017': 0.0,
|
||||
'sep_2017': 15.0,
|
||||
'oct_2017': 10.0,
|
||||
'nov_2017': 0.0,
|
||||
'dec_2017': 0.0,
|
||||
'jan_2018': 0.0,
|
||||
'feb_2018': 20.0,
|
||||
'mar_2018': 0.0
|
||||
},
|
||||
{
|
||||
"entity": "_Test Customer 1",
|
||||
"entity_name": "_Test Customer 1",
|
||||
|
@ -8,7 +8,7 @@ cur_frm.cscript.refresh = function(doc, cdt, cdn) {
|
||||
|
||||
cur_frm.cscript.set_root_readonly = function(doc) {
|
||||
// read-only for root customer group
|
||||
if(!doc.parent_customer_group) {
|
||||
if(!doc.parent_customer_group && !doc.__islocal) {
|
||||
cur_frm.set_read_only();
|
||||
cur_frm.set_intro(__("This is a root customer group and cannot be edited."));
|
||||
} else {
|
||||
@ -20,7 +20,8 @@ cur_frm.cscript.set_root_readonly = function(doc) {
|
||||
cur_frm.fields_dict['parent_customer_group'].get_query = function(doc,cdt,cdn) {
|
||||
return {
|
||||
filters: {
|
||||
'is_group': 1
|
||||
'is_group': 1,
|
||||
'name': ['!=', cur_frm.doc.customer_group_name]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ frappe.ui.form.on("Item Group", {
|
||||
set_root_readonly: function(frm) {
|
||||
// read-only for root item group
|
||||
frm.set_intro("");
|
||||
if(!frm.doc.parent_item_group) {
|
||||
if(!frm.doc.parent_item_group && !frm.doc.__islocal) {
|
||||
frm.set_read_only();
|
||||
frm.set_intro(__("This is a root item group and cannot be edited."), true);
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ frappe.ui.form.on('Sales Person', {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
frm.make_methods = {
|
||||
'Sales Order': () => frappe.new_doc("Sales Order")
|
||||
.then(() => frm.add_child("sales_team", {"sales_person": frm.doc.name}))
|
||||
@ -33,7 +33,7 @@ cur_frm.cscript.refresh = function(doc, cdt, cdn) {
|
||||
|
||||
cur_frm.cscript.set_root_readonly = function(doc) {
|
||||
// read-only for root
|
||||
if(!doc.parent_sales_person) {
|
||||
if(!doc.parent_sales_person && !doc.__islocal) {
|
||||
cur_frm.set_read_only();
|
||||
cur_frm.set_intro(__("This is a root sales person and cannot be edited."));
|
||||
} else {
|
||||
|
@ -8,7 +8,7 @@ cur_frm.cscript.refresh = function(doc) {
|
||||
|
||||
cur_frm.cscript.set_root_readonly = function(doc) {
|
||||
// read-only for root customer group
|
||||
if(!doc.parent_supplier_group) {
|
||||
if(!doc.parent_supplier_group && !doc.__islocal) {
|
||||
cur_frm.set_read_only();
|
||||
cur_frm.set_intro(__("This is a root supplier group and cannot be edited."));
|
||||
} else {
|
||||
@ -20,7 +20,8 @@ cur_frm.cscript.set_root_readonly = function(doc) {
|
||||
cur_frm.fields_dict['parent_supplier_group'].get_query = function() {
|
||||
return {
|
||||
filters: {
|
||||
'is_group': 1
|
||||
'is_group': 1,
|
||||
'name': ['!=', cur_frm.doc.supplier_group_name]
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -20,7 +20,7 @@ cur_frm.cscript.refresh = function(doc, cdt, cdn) {
|
||||
|
||||
cur_frm.cscript.set_root_readonly = function(doc) {
|
||||
// read-only for root territory
|
||||
if(!doc.parent_territory) {
|
||||
if(!doc.parent_territory && !doc.__islocal) {
|
||||
cur_frm.set_read_only();
|
||||
cur_frm.set_intro(__("This is a root territory and cannot be edited."));
|
||||
} else {
|
||||
|
@ -597,7 +597,7 @@ class Item(WebsiteGenerator):
|
||||
def stock_ledger_created(self):
|
||||
if not hasattr(self, '_stock_ledger_created'):
|
||||
self._stock_ledger_created = len(frappe.db.sql("""select name from `tabStock Ledger Entry`
|
||||
where item_code = %s limit 1""", self.name))
|
||||
where item_code = %s and is_cancelled = 0 limit 1""", self.name))
|
||||
return self._stock_ledger_created
|
||||
|
||||
def validate_name_with_item_group(self):
|
||||
@ -883,7 +883,12 @@ class Item(WebsiteGenerator):
|
||||
linked_doctypes += ["Sales Order Item", "Purchase Order Item", "Material Request Item"]
|
||||
|
||||
for doctype in linked_doctypes:
|
||||
if frappe.db.get_value(doctype, filters={"item_code": self.name, "docstatus": 1}) or \
|
||||
if doctype in ("Purchase Invoice Item", "Sales Invoice Item",):
|
||||
# If Invoice has Stock impact, only then consider it.
|
||||
if self.stock_ledger_created():
|
||||
return True
|
||||
|
||||
elif frappe.db.get_value(doctype, filters={"item_code": self.name, "docstatus": 1}) or \
|
||||
frappe.db.get_value("Production Order",
|
||||
filters={"production_item": self.name, "docstatus": 1}):
|
||||
return True
|
||||
|
@ -574,9 +574,7 @@ class StockEntry(StockController):
|
||||
{"parent": self.purchase_order, "item_code": se_item.subcontracted_item},
|
||||
"bom")
|
||||
|
||||
allow_alternative_item = frappe.get_value("BOM", bom_no, "allow_alternative_item")
|
||||
|
||||
if allow_alternative_item:
|
||||
if se_item.allow_alternative_item:
|
||||
original_item_code = frappe.get_value("Item Alternative", {"alternative_item_code": item_code}, "item_code")
|
||||
|
||||
required_qty = sum([flt(d.required_qty) for d in purchase_order.supplied_items \
|
||||
@ -743,7 +741,7 @@ class StockEntry(StockController):
|
||||
|
||||
def get_item_details(self, args=None, for_update=False):
|
||||
item = frappe.db.sql("""select i.name, i.stock_uom, i.description, i.image, i.item_name, i.item_group,
|
||||
i.has_batch_no, i.sample_quantity, i.has_serial_no,
|
||||
i.has_batch_no, i.sample_quantity, i.has_serial_no, i.allow_alternative_item,
|
||||
id.expense_account, id.buying_cost_center
|
||||
from `tabItem` i LEFT JOIN `tabItem Default` id ON i.name=id.parent and id.company=%s
|
||||
where i.name=%s
|
||||
@ -778,6 +776,9 @@ class StockEntry(StockController):
|
||||
'expense_account' : item.expense_account
|
||||
})
|
||||
|
||||
if self.purpose == 'Send to Subcontractor':
|
||||
ret["allow_alternative_item"] = item.allow_alternative_item
|
||||
|
||||
# update uom
|
||||
if args.get("uom") and for_update:
|
||||
ret.update(get_uom_details(args.get('item_code'), args.get('uom'), args.get('qty')))
|
||||
|
@ -12,8 +12,9 @@
|
||||
} %}
|
||||
|
||||
{% set link = '' %}
|
||||
{% set label = domains[0].domain %}
|
||||
{% set label = '' %}
|
||||
{% if domains %}
|
||||
{% set label = domains[0].domain %}
|
||||
{% set link = links[label] %}
|
||||
{% endif %}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -161,19 +161,19 @@ class TransactionBase(StatusUpdater):
|
||||
if not (self.get("update_stock") or self.get("is_pos")):
|
||||
return
|
||||
|
||||
fiscal_year = get_fiscal_year(self.get('posting_date'), as_dict=True).name
|
||||
for item in self.get('items'):
|
||||
last_transaction_time = frappe.db.sql("""
|
||||
select MAX(timestamp(posting_date, posting_time)) as posting_time
|
||||
from `tabStock Ledger Entry`
|
||||
where docstatus = 1 and item_code = %s """, (item.item_code))[0][0]
|
||||
|
||||
last_transaction_time = frappe.db.sql("""
|
||||
select MAX(timestamp(posting_date, posting_time)) as posting_time
|
||||
from `tabStock Ledger Entry`
|
||||
where docstatus = 1""")[0][0]
|
||||
cur_doc_posting_datetime = "%s %s" % (self.posting_date, self.get("posting_time") or "00:00:00")
|
||||
|
||||
cur_doc_posting_datetime = "%s %s" % (self.posting_date, self.get("posting_time") or "00:00:00")
|
||||
|
||||
if last_transaction_time and get_datetime(cur_doc_posting_datetime) < get_datetime(last_transaction_time):
|
||||
frappe.throw(_("""Posting timestamp of current transaction
|
||||
must be after last Stock transaction's timestamp which is {0}""").format(frappe.bold(last_transaction_time)),
|
||||
title=_("Backdated Stock Entry"))
|
||||
if last_transaction_time and get_datetime(cur_doc_posting_datetime) < get_datetime(last_transaction_time):
|
||||
msg = _("Last Stock Transaction for item {0} was on {1}.").format(frappe.bold(item.item_code), frappe.bold(last_transaction_time))
|
||||
msg += "<br><br>" + _("Stock Transactions for Item {0} cannot be posted before this time.").format(frappe.bold(item.item_code))
|
||||
msg += "<br><br>" + _("Please remove this item and try to submit again or update the posting time.")
|
||||
frappe.throw(msg, title=_("Backdated Stock Entry"))
|
||||
|
||||
def delete_events(ref_type, ref_name):
|
||||
events = frappe.db.sql_list(""" SELECT
|
||||
|
@ -59,7 +59,7 @@
|
||||
{% macro title() %}
|
||||
<div class="mb-3">
|
||||
<a href="/lms/course?name={{ course }}&program={{ program }}" class="text-muted">
|
||||
Back to Course
|
||||
{{_('Back to Course')}}
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
@ -69,15 +69,15 @@
|
||||
|
||||
{% macro navigation() %}
|
||||
{% if previous %}
|
||||
<a href="/lms/content?program={{ program }}&course={{ course }}&topic={{ topic }}&type={{ previous.content_type }}&content={{ previous.content }}" class='btn text-muted' style="box-shadow: none;">Previous</a>
|
||||
<a href="/lms/content?program={{ program }}&course={{ course }}&topic={{ topic }}&type={{ previous.content_type }}&content={{ previous.content }}" class='btn text-muted' style="box-shadow: none;">{{_('Previous')}}</a>
|
||||
{% else %}
|
||||
<a href="/lms/course?name={{ course }}&program={{ program }}" class='btn text-muted' style="box-shadow: none;">Back to Course</a>
|
||||
<a href="/lms/course?name={{ course }}&program={{ program }}" class='btn text-muted' style="box-shadow: none;">{{ _('Back to Course') }}</a>
|
||||
{% endif %}
|
||||
|
||||
{% if next %}
|
||||
<button id="nextButton" onclick="handle('/lms/content?program={{ program }}&course={{ course }}&topic={{ topic }}&type={{ next.content_type }}&content={{ next.content }}')" class='btn btn-primary' disabled="true">Next</button>
|
||||
<button id="nextButton" onclick="handle('/lms/content?program={{ program }}&course={{ course }}&topic={{ topic }}&type={{ next.content_type }}&content={{ next.content }}')" class='btn btn-primary' disabled="true">{{_('Next')}}</button>
|
||||
{% else %}
|
||||
<button id="nextButton" onclick="handle('/lms/course?name={{ course }}&program={{ program }}')" class='btn btn-primary' disabled="true">Finish Topic</button>
|
||||
<button id="nextButton" onclick="handle('/lms/course?name={{ course }}&program={{ program }}')" class='btn btn-primary' disabled="true">{{_('Finish Topic')}}</button>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
@ -86,7 +86,7 @@
|
||||
{{ title() }}
|
||||
<div class="text-muted">
|
||||
{% if content.duration %}
|
||||
{{ content.duration }} Mins
|
||||
{{ content.duration }} {{_('Mins')}}
|
||||
{% endif %}
|
||||
|
||||
{% if content.publish_date and content.duration%}
|
||||
@ -94,7 +94,7 @@
|
||||
{% endif %}
|
||||
|
||||
{% if content.publish_date %}
|
||||
Published on {{ content.publish_date.strftime('%d, %b %Y') }}
|
||||
{{_('Published on')}} {{ content.publish_date.strftime('%d, %b %Y') }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
@ -109,13 +109,13 @@
|
||||
{{ title() }}
|
||||
<div class="text-muted">
|
||||
{% if content.author or content.publish_date %}
|
||||
Published
|
||||
{{_('Published')}}
|
||||
{% endif %}
|
||||
{% if content.author %}
|
||||
by {{ content.author }}
|
||||
{{_('by')}} {{ content.author }}
|
||||
{% endif %}
|
||||
{% if content.publish_date %}
|
||||
on {{ content.publish_date.strftime('%d, %b %Y') }}
|
||||
{{_('on')}} {{ content.publish_date.strftime('%d, %b %Y') }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
@ -205,4 +205,4 @@
|
||||
|
||||
{% endif %}
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
@ -72,11 +72,11 @@
|
||||
{% if has_access %}
|
||||
<div class='card-footer'>
|
||||
{% if progress[topic.name].completed %}
|
||||
<span class="indicator green">Completed</span>
|
||||
<span class="indicator green">{{_('Completed')}}</span>
|
||||
{% elif progress[topic.name].started %}
|
||||
<span class="indicator orange">In Progress</span>
|
||||
<span class="indicator orange">{{_('In Progress')}}</span>
|
||||
{% else %}
|
||||
<span class="indicator blue">Start</span>
|
||||
<span class="indicator blue">{{_('Start')}}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</a>
|
||||
|
@ -45,7 +45,7 @@
|
||||
<p class='lead'>{{ education_settings.description }}</p>
|
||||
<p class="mt-4">
|
||||
{% if frappe.session.user == 'Guest' %}
|
||||
<a class="btn btn-primary btn-lg" href="'/login#signup'">Sign Up</a>
|
||||
<a class="btn btn-primary btn-lg" href="'/login#signup'">{{_('Sign Up')}}</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
|
@ -15,8 +15,8 @@
|
||||
</div>
|
||||
{% if has_access or program.intro_video%}
|
||||
<div class='card-footer'>
|
||||
{% if has_access %} <span class="indicator green">Enrolled</span>
|
||||
{% elif program.intro_video %} <span><a href="{{ program.intro_video }}" target="blank">Watch Intro</a></span>
|
||||
{% if has_access %} <span class="indicator green">{{_('Enrolled')}}</span>
|
||||
{% elif program.intro_video %} <span><a href="{{ program.intro_video }}" target="blank">{{_('Watch Intro')}}</a></span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
@ -2,16 +2,16 @@
|
||||
<div class='container pb-5'>
|
||||
<div class="mb-3">
|
||||
<a href="{{ back.url }}" class="text-muted">
|
||||
Back to {{ back.name }}
|
||||
{{_('Back to')}} {{ _(back.name) }}
|
||||
</a>
|
||||
</div>
|
||||
<h1>{{ title }}</h1>
|
||||
<p class='lead' style="max-width: 100%;">{{ description or ''}}</p>
|
||||
<p class="mt-4">
|
||||
{% if frappe.session.user == 'Guest' %}
|
||||
<a id="signup" class="btn btn-primary btn-lg" href="/login#signup">Sign Up</a>
|
||||
<a id="signup" class="btn btn-primary btn-lg" href="/login#signup">{{_('Sign Up')}}</a>
|
||||
{% elif not has_access %}
|
||||
<button id="enroll" class="btn btn-primary btn-lg" onclick="enroll()" disabled>Enroll</button>
|
||||
<button id="enroll" class="btn btn-primary btn-lg" onclick="enroll()" disabled>{{_('Enroll')}}</button>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
@ -28,7 +28,7 @@
|
||||
|
||||
let btn = document.getElementById('enroll');
|
||||
btn.disbaled = true;
|
||||
btn.innerText = 'Enrolling...'
|
||||
btn.innerText = __('Enrolling...')
|
||||
|
||||
let opts = {
|
||||
method: 'erpnext.education.utils.enroll_in_program',
|
||||
@ -44,7 +44,7 @@
|
||||
window.location.reload()
|
||||
}
|
||||
})
|
||||
success_dialog.set_message('You have successfully enrolled for the program ');
|
||||
success_dialog.set_message(__('You have successfully enrolled for the program '));
|
||||
success_dialog.$message.show()
|
||||
success_dialog.show();
|
||||
btn.disbaled = false;
|
||||
|
@ -30,7 +30,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
<div class='card-footer'>
|
||||
<span class="small">{{ program.completion }}% Complete</span>
|
||||
<span class="small">{{ program.completion }}{{_('% Complete')}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
@ -43,11 +43,11 @@
|
||||
<div class="mb-3 row">
|
||||
<div class="col-md-7">
|
||||
<a href="/lms" class="text-muted">
|
||||
Back to Home
|
||||
{{_('Back to Home')}}
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-5 text-right">
|
||||
<a href="/update-profile?name={{ frappe.session.user }}" target="blank" class="mt-0 text-muted">Edit Profile</a>
|
||||
<a href="/update-profile?name={{ frappe.session.user }}" target="blank" class="mt-0 text-muted">{{_('Edit Profile')}}</a>
|
||||
</div>
|
||||
</div>
|
||||
<h1>{{ student.first_name }} {{ student.last_name or '' }}</h1>
|
||||
@ -61,4 +61,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
@ -55,11 +55,11 @@
|
||||
{% if has_access and progress[course.name] %}
|
||||
<div class='card-footer'>
|
||||
{% if progress[course.name].completed %}
|
||||
<span class="indicator green">Completed</span>
|
||||
<span class="indicator green">{{_('Completed')}}</span>
|
||||
{% elif progress[course.name].started %}
|
||||
<span class="indicator orange">In Progress</span>
|
||||
<span class="indicator orange">{{_('In Progress')}}</span>
|
||||
{% else %}
|
||||
<span class="indicator blue">Start</span>
|
||||
<span class="indicator blue">{{_('Start')}}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
@ -23,13 +23,13 @@
|
||||
{% if has_access %}
|
||||
<div class='card-footer'>
|
||||
{% if content.content_type == 'Quiz' %}
|
||||
{% if content.result == 'Fail' %} <span class="indicator red">Fail <span class="text-muted">({{ content.score }}/100)</span></span>
|
||||
{% elif content.result == 'Pass' %} <span class="indicator green">Pass <span class="text-muted">({{ content.score }}/100)</span>
|
||||
{% else %} <span class="indicator blue">Start</span>
|
||||
{% if content.result == 'Fail' %} <span class="indicator red">{{_('Fail')}} <span class="text-muted">({{ content.score }}/100)</span></span>
|
||||
{% elif content.result == 'Pass' %} <span class="indicator green">{{_('Pass')}} <span class="text-muted">({{ content.score }}/100)</span>
|
||||
{% else %} <span class="indicator blue">{{_('Start')}}</span>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if content.completed %} <span class="indicator green">Completed</span>
|
||||
{% else %} <span class="indicator blue">Start</span>
|
||||
{% if content.completed %} <span class="indicator green">{{_('Completed')}}</span>
|
||||
{% else %} <span class="indicator blue">{{_('Start')}}</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user