Skip to content

Commit

Permalink
Merge branch 'version-13-pre-release' into version-13
Browse files Browse the repository at this point in the history
  • Loading branch information
rohitwaghchaure committed Jan 23, 2022
2 parents dfe2140 + f44d90e commit 5c8fc38
Show file tree
Hide file tree
Showing 95 changed files with 1,861 additions and 889 deletions.
2 changes: 1 addition & 1 deletion erpnext/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from erpnext.hooks import regional_overrides

__version__ = '13.18.0'
__version__ = '13.19.0'

def get_default_company(user=None):
'''Get default company for user'''
Expand Down
12 changes: 7 additions & 5 deletions erpnext/accounts/deferred_revenue.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,11 +255,13 @@ 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"

accounts_frozen_upto = frappe.get_cached_value('Accounts Settings', 'None', 'acc_frozen_upto')

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

account_currency = get_account_currency(item.expense_account)
account_currency = get_account_currency(item.expense_account or item.income_account)
if doc.doctype == "Sales Invoice":
against, project = doc.customer, doc.project
credit_account, debit_account = item.income_account, item.deferred_revenue_account
Expand All @@ -280,6 +282,10 @@ def _book_deferred_revenue_or_expense(item, via_journal_entry, submit_journal_en
if not amount:
return

# check if books nor frozen till endate:
if getdate(end_date) >= getdate(accounts_frozen_upto):
end_date = get_last_day(add_days(accounts_frozen_upto, 1))

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)
Expand Down Expand Up @@ -407,8 +413,6 @@ def book_revenue_via_journal_entry(doc, credit_account, debit_account, against,
'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,
Expand All @@ -421,8 +425,6 @@ def book_revenue_via_journal_entry(doc, credit_account, debit_account, against,
'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,
Expand Down
26 changes: 14 additions & 12 deletions erpnext/accounts/doctype/account/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ frappe.ui.form.on('Account', {
frm.trigger('add_toolbar_buttons');
}
if (frm.has_perm('write')) {
frm.add_custom_button(__('Update Account Name / Number'), function () {
frm.trigger("update_account_number");
});
frm.add_custom_button(__('Merge Account'), function () {
frm.trigger("merge_account");
});
}, __('Actions'));
frm.add_custom_button(__('Update Account Name / Number'), function () {
frm.trigger("update_account_number");
}, __('Actions'));
}
}
},
Expand All @@ -59,40 +59,42 @@ frappe.ui.form.on('Account', {
}
},
add_toolbar_buttons: function(frm) {
frm.add_custom_button(__('Chart of Accounts'),
function () { frappe.set_route("Tree", "Account"); });
frm.add_custom_button(__('Chart of Accounts'), () => {
frappe.set_route("Tree", "Account");
}, __('View'));

if (frm.doc.is_group == 1) {
frm.add_custom_button(__('Group to Non-Group'), function () {
frm.add_custom_button(__('Convert to Non-Group'), function () {
return frappe.call({
doc: frm.doc,
method: 'convert_group_to_ledger',
callback: function() {
frm.refresh();
}
});
});
}, __('Actions'));

} else if (cint(frm.doc.is_group) == 0
&& frappe.boot.user.can_read.indexOf("GL Entry") !== -1) {
frm.add_custom_button(__('Ledger'), function () {
frm.add_custom_button(__('General Ledger'), function () {
frappe.route_options = {
"account": frm.doc.name,
"from_date": frappe.sys_defaults.year_start_date,
"to_date": frappe.sys_defaults.year_end_date,
"company": frm.doc.company
};
frappe.set_route("query-report", "General Ledger");
});
}, __('View'));

frm.add_custom_button(__('Non-Group to Group'), function () {
frm.add_custom_button(__('Convert to Group'), function () {
return frappe.call({
doc: frm.doc,
method: 'convert_ledger_to_group',
callback: function() {
frm.refresh();
}
});
});
}, __('Actions'));
}
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,8 @@ frappe.ui.form.on("Bank Statement Import", {
"withdrawal",
"description",
"reference_number",
"bank_account"
"bank_account",
"currency"
],
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from openpyxl.utils import get_column_letter
from six import string_types

INVALID_VALUES = ("", None)

class BankStatementImport(DataImport):
def __init__(self, *args, **kwargs):
Expand Down Expand Up @@ -96,6 +97,18 @@ def download_errored_template(data_import_name):
data_import = frappe.get_doc("Bank Statement Import", data_import_name)
data_import.export_errored_rows()

def parse_data_from_template(raw_data):
data = []

for i, row in enumerate(raw_data):
if all(v in INVALID_VALUES for v in row):
# empty row
continue

data.append(row)

return data

def start_import(data_import, bank_account, import_file_path, google_sheets_url, bank, template_options):
"""This method runs in background job"""

Expand All @@ -105,7 +118,8 @@ def start_import(data_import, bank_account, import_file_path, google_sheets_url,
file = import_file_path if import_file_path else google_sheets_url

import_file = ImportFile("Bank Transaction", file = file, import_type="Insert New Records")
data = import_file.raw_data

data = parse_data_from_template(import_file.raw_data)

if import_file_path:
add_bank_account(data, bank_account)
Expand Down
2 changes: 1 addition & 1 deletion erpnext/accounts/doctype/journal_entry/journal_entry.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ frappe.ui.form.on("Journal Entry", {
if(frm.doc.docstatus==1) {
frm.add_custom_button(__('Reverse Journal Entry'), function() {
return erpnext.journal_entry.reverse_journal_entry(frm);
}, __('Make'));
}, __('Actions'));
}

if (frm.doc.__islocal) {
Expand Down
11 changes: 10 additions & 1 deletion erpnext/accounts/doctype/journal_entry/journal_entry.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"voucher_type",
"naming_series",
"finance_book",
"reversal_of",
"tax_withholding_category",
"column_break1",
"from_template",
Expand Down Expand Up @@ -515,13 +516,21 @@
"fieldname": "apply_tds",
"fieldtype": "Check",
"label": "Apply Tax Withholding Amount "
},
{
"depends_on": "eval:doc.docstatus",
"fieldname": "reversal_of",
"fieldtype": "Link",
"label": "Reversal Of",
"options": "Journal Entry",
"read_only": 1
}
],
"icon": "fa fa-file-text",
"idx": 176,
"is_submittable": 1,
"links": [],
"modified": "2021-09-09 15:31:14.484029",
"modified": "2022-01-04 13:39:36.485954",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry",
Expand Down
34 changes: 21 additions & 13 deletions erpnext/accounts/doctype/journal_entry/journal_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -397,13 +397,14 @@ def validate_reference_doc(self):
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)
against_voucher = ['', against_voucher[1]]
else:
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):
if (against_voucher[0] != cstr(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],
d.reference_type, d.reference_name))
Expand Down Expand Up @@ -468,13 +469,22 @@ def validate_invoices(self):

def set_against_account(self):
accounts_debited, accounts_credited = [], []
for d in self.get("accounts"):
if flt(d.debit > 0): accounts_debited.append(d.party or d.account)
if flt(d.credit) > 0: accounts_credited.append(d.party or d.account)
if self.voucher_type in ('Deferred Revenue', 'Deferred Expense'):
for d in self.get('accounts'):
if d.reference_type == 'Sales Invoice':
field = 'customer'
else:
field = 'supplier'

for d in self.get("accounts"):
if flt(d.debit > 0): d.against_account = ", ".join(list(set(accounts_credited)))
if flt(d.credit > 0): d.against_account = ", ".join(list(set(accounts_debited)))
d.against_account = frappe.db.get_value(d.reference_type, d.reference_name, field)
else:
for d in self.get("accounts"):
if flt(d.debit > 0): accounts_debited.append(d.party or d.account)
if flt(d.credit) > 0: accounts_credited.append(d.party or d.account)

for d in self.get("accounts"):
if flt(d.debit > 0): d.against_account = ", ".join(list(set(accounts_credited)))
if flt(d.credit > 0): d.against_account = ", ".join(list(set(accounts_debited)))

def validate_debit_credit_amount(self):
for d in self.get('accounts'):
Expand Down Expand Up @@ -1147,9 +1157,8 @@ def make_inter_company_journal_entry(name, voucher_type, company):
def make_reverse_journal_entry(source_name, target_doc=None):
from frappe.model.mapper import get_mapped_doc

def update_accounts(source, target, source_parent):
target.reference_type = "Journal Entry"
target.reference_name = source_parent.name
def post_process(source, target):
target.reversal_of = source.name

doclist = get_mapped_doc("Journal Entry", source_name, {
"Journal Entry": {
Expand All @@ -1167,9 +1176,8 @@ def update_accounts(source, target, source_parent):
"debit": "credit",
"credit_in_account_currency": "debit_in_account_currency",
"credit": "debit",
},
"postprocess": update_accounts,
}
},
}, target_doc)
}, target_doc, post_process)

return doclist
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
],
"hide_toolbar": 1,
"issingle": 1,
"modified": "2022-01-04 13:40:15.927675",
"modified": "2022-01-04 16:25:06.053187",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Opening Invoice Creation Tool",
Expand Down
10 changes: 9 additions & 1 deletion erpnext/accounts/doctype/payment_entry/payment_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@


import json
from functools import reduce

import frappe
from frappe import ValidationError, _, scrub, throw
Expand Down Expand Up @@ -1524,6 +1525,10 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
pe.received_amount = received_amount
pe.letter_head = doc.get("letter_head")

if dt in ['Purchase Order', 'Sales Order', 'Sales Invoice', 'Purchase Invoice']:
pe.project = (doc.get('project') or
reduce(lambda prev,cur: prev or cur, [x.get('project') for x in doc.get('items')], None)) # get first non-empty project from items

if pe.party_type in ["Customer", "Supplier"]:
bank_account = get_party_bank_account(pe.party_type, pe.party)
pe.set("bank_account", bank_account)
Expand Down Expand Up @@ -1709,7 +1714,10 @@ def set_paid_amount_and_received_amount(dt, party_account_currency, bank, outsta

def apply_early_payment_discount(paid_amount, received_amount, doc):
total_discount = 0
if doc.doctype in ['Sales Invoice', 'Purchase Invoice'] and doc.payment_schedule:
eligible_for_payments = ['Sales Order', 'Sales Invoice', 'Purchase Order', 'Purchase Invoice']
has_payment_schedule = hasattr(doc, 'payment_schedule') and doc.payment_schedule

if doc.doctype in eligible_for_payments and has_payment_schedule:
for term in doc.payment_schedule:
if not term.discounted_amount and term.discount and getdate(nowdate()) <= term.discount_date:
if term.discount_type == 'Percentage':
Expand Down
23 changes: 21 additions & 2 deletions erpnext/accounts/doctype/pos_invoice/pos_invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
update_multi_mode_option,
)
from erpnext.accounts.party import get_due_date, get_party_account
from erpnext.stock.doctype.batch.batch import get_batch_qty, get_pos_reserved_batch_qty
from erpnext.stock.doctype.serial_no.serial_no import get_pos_reserved_serial_nos, get_serial_nos


Expand Down Expand Up @@ -125,9 +126,26 @@ def validate_pos_reserved_serial_nos(self, item):
frappe.throw(_("Row #{}: Serial No. {} has already been transacted into another POS Invoice. Please select valid serial no.")
.format(item.idx, bold_invalid_serial_nos), title=_("Item Unavailable"))
elif invalid_serial_nos:
frappe.throw(_("Row #{}: Serial Nos. {} has already been transacted into another POS Invoice. Please select valid serial no.")
frappe.throw(_("Row #{}: Serial Nos. {} have already been transacted into another POS Invoice. Please select valid serial no.")
.format(item.idx, bold_invalid_serial_nos), title=_("Item Unavailable"))

def validate_pos_reserved_batch_qty(self, item):
filters = {"item_code": item.item_code, "warehouse": item.warehouse, "batch_no":item.batch_no}

available_batch_qty = get_batch_qty(item.batch_no, item.warehouse, item.item_code)
reserved_batch_qty = get_pos_reserved_batch_qty(filters)

bold_item_name = frappe.bold(item.item_name)
bold_extra_batch_qty_needed = frappe.bold(abs(available_batch_qty - reserved_batch_qty - item.qty))
bold_invalid_batch_no = frappe.bold(item.batch_no)

if (available_batch_qty - reserved_batch_qty) == 0:
frappe.throw(_("Row #{}: Batch No. {} of item {} has no stock available. Please select valid batch no.")
.format(item.idx, bold_invalid_batch_no, bold_item_name), title=_("Item Unavailable"))
elif (available_batch_qty - reserved_batch_qty - item.qty) < 0:
frappe.throw(_("Row #{}: Batch No. {} of item {} has less than required stock available, {} more required")
.format(item.idx, bold_invalid_batch_no, bold_item_name, bold_extra_batch_qty_needed), title=_("Item Unavailable"))

def validate_delivered_serial_nos(self, item):
serial_nos = get_serial_nos(item.serial_no)
delivered_serial_nos = frappe.db.get_list('Serial No', {
Expand All @@ -150,6 +168,8 @@ def validate_stock_availablility(self):
if d.serial_no:
self.validate_pos_reserved_serial_nos(d)
self.validate_delivered_serial_nos(d)
elif d.batch_no:
self.validate_pos_reserved_batch_qty(d)
else:
if allow_negative_stock:
return
Expand Down Expand Up @@ -334,7 +354,6 @@ def set_pos_fields(self, for_validate=False):
if not for_validate and not self.customer:
self.customer = profile.customer

self.ignore_pricing_rule = profile.ignore_pricing_rule
self.account_for_change_amount = profile.get('account_for_change_amount') or self.account_for_change_amount
self.set_warehouse = profile.get('warehouse') or self.set_warehouse

Expand Down
Loading

0 comments on commit 5c8fc38

Please sign in to comment.