Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext into e-commerce-refactor

This commit is contained in:
marination
2021-08-24 11:48:13 +05:30
1294 changed files with 3267 additions and 2749 deletions

View File

@@ -10,3 +10,6 @@
# This commit just changes spaces to tabs for indentation in some files # This commit just changes spaces to tabs for indentation in some files
5f473611bd6ed57703716244a054d3fb5ba9cd23 5f473611bd6ed57703716244a054d3fb5ba9cd23
# Whitespace trimming throughout codebase
9bb69e711a5da43aaf8c8ecb5601aeffd89dbe5a

View File

@@ -32,11 +32,15 @@ if __name__ == "__main__":
if response.ok: if response.ok:
payload = response.json() payload = response.json()
title = payload.get("title", "").lower() title = payload.get("title", "").lower().strip()
head_sha = payload.get("head", {}).get("sha") head_sha = payload.get("head", {}).get("sha")
body = payload.get("body", "").lower() body = payload.get("body", "").lower()
if title.startswith("feat") and head_sha and "no-docs" not in body: if (title.startswith("feat")
and head_sha
and "no-docs" not in body
and "backport" not in body
):
if docs_link_exists(body): if docs_link_exists(body):
print("Documentation Link Found. You're Awesome! 🎉") print("Documentation Link Found. You're Awesome! 🎉")

View File

@@ -1,6 +1,12 @@
name: Patch name: Patch
on: [pull_request, workflow_dispatch] on:
pull_request:
paths-ignore:
- '**.js'
- '**.md'
workflow_dispatch:
jobs: jobs:
test: test:

View File

@@ -1,6 +1,16 @@
name: Server name: Server
on: [pull_request, workflow_dispatch] on:
pull_request:
paths-ignore:
- '**.js'
- '**.md'
workflow_dispatch:
push:
branches: [ develop ]
paths-ignore:
- '**.js'
- '**.md'
jobs: jobs:
test: test:

View File

@@ -2,6 +2,8 @@ name: UI
on: on:
pull_request: pull_request:
paths-ignore:
- '**.md'
workflow_dispatch: workflow_dispatch:
jobs: jobs:

View File

@@ -450,5 +450,3 @@ def get_deferred_booking_accounts(doctype, voucher_detail_no, dr_or_cr):
return debit_account return debit_account
else: else:
return credit_account return credit_account

View File

@@ -113,5 +113,3 @@ def disable_dimension():
dimension2 = frappe.get_doc("Accounting Dimension", "Location") dimension2 = frappe.get_doc("Accounting Dimension", "Location")
dimension2.disabled = 1 dimension2.disabled = 1
dimension2.save() dimension2.save()

View File

@@ -105,4 +105,3 @@ def unclear_reference_payment(doctype, docname):
frappe.db.set_value(doc.payment_document, doc.payment_entry, "clearance_date", None) frappe.db.set_value(doc.payment_document, doc.payment_entry, "clearance_date", None)
return doc.payment_entry return doc.payment_entry

View File

@@ -18,5 +18,3 @@ class CashFlowMapping(Document):
frappe._('You can only select a maximum of one option from the list of check boxes.'), frappe._('You can only select a maximum of one option from the list of check boxes.'),
title='Error' title='Error'
) )

View File

@@ -62,6 +62,3 @@ def create_cost_center(**args):
cc.is_group = args.is_group or 0 cc.is_group = args.is_group or 0
cc.parent_cost_center = args.parent_cost_center or "_Test Company - _TC" cc.parent_cost_center = args.parent_cost_center or "_Test Company - _TC"
cc.insert() cc.insert()

View File

@@ -121,6 +121,3 @@ class TestCouponCode(unittest.TestCase):
so.submit() so.submit()
self.assertEqual(frappe.db.get_value("Coupon Code", "SAVE30", "used"), 1) self.assertEqual(frappe.db.get_value("Coupon Code", "SAVE30", "used"), 1)

View File

@@ -39,4 +39,3 @@ class ModeofPayment(Document):
message = "POS Profile " + frappe.bold(", ".join(pos_profiles)) + " contains \ message = "POS Profile " + frappe.bold(", ".join(pos_profiles)) + " contains \
Mode of Payment " + frappe.bold(str(self.name)) + ". Please remove them to disable this mode." Mode of Payment " + frappe.bold(str(self.name)) + ". Please remove them to disable this mode."
frappe.throw(_(message), title="Not Allowed") frappe.throw(_(message), title="Not Allowed")

View File

@@ -240,5 +240,3 @@ def get_temporary_opening_account(company=None):
frappe.throw(_("Please add a Temporary Opening account in Chart of Accounts")) frappe.throw(_("Please add a Temporary Opening account in Chart of Accounts"))
return accounts[0].name return accounts[0].name

View File

@@ -533,8 +533,8 @@ frappe.ui.form.on('Payment Entry', {
source_exchange_rate: function(frm) { source_exchange_rate: function(frm) {
if (frm.doc.paid_amount) { if (frm.doc.paid_amount) {
frm.set_value("base_paid_amount", flt(frm.doc.paid_amount) * flt(frm.doc.source_exchange_rate)); frm.set_value("base_paid_amount", flt(frm.doc.paid_amount) * flt(frm.doc.source_exchange_rate));
if(!frm.set_paid_amount_based_on_received_amount && // target exchange rate should always be same as source if both account currencies are same
(frm.doc.paid_from_account_currency == frm.doc.paid_to_account_currency)) { if(frm.doc.paid_from_account_currency == frm.doc.paid_to_account_currency) {
frm.set_value("target_exchange_rate", frm.doc.source_exchange_rate); frm.set_value("target_exchange_rate", frm.doc.source_exchange_rate);
frm.set_value("base_received_amount", frm.doc.base_paid_amount); frm.set_value("base_received_amount", frm.doc.base_paid_amount);
} }

View File

@@ -55,14 +55,17 @@ class PaymentEntry(AccountsController):
self.validate_mandatory() self.validate_mandatory()
self.validate_reference_documents() self.validate_reference_documents()
self.set_tax_withholding() self.set_tax_withholding()
self.apply_taxes()
self.set_amounts() self.set_amounts()
self.validate_amounts()
self.apply_taxes()
self.set_amounts_after_tax()
self.clear_unallocated_reference_document_rows() self.clear_unallocated_reference_document_rows()
self.validate_payment_against_negative_invoice() self.validate_payment_against_negative_invoice()
self.validate_transaction_reference() self.validate_transaction_reference()
self.set_title() self.set_title()
self.set_remarks() self.set_remarks()
self.validate_duplicate_entry() self.validate_duplicate_entry()
self.validate_payment_type_with_outstanding()
self.validate_allocated_amount() self.validate_allocated_amount()
self.validate_paid_invoices() self.validate_paid_invoices()
self.ensure_supplier_is_not_blocked() self.ensure_supplier_is_not_blocked()
@@ -118,6 +121,11 @@ class PaymentEntry(AccountsController):
if not self.get(field): if not self.get(field):
self.set(field, bank_data.account) self.set(field, bank_data.account)
def validate_payment_type_with_outstanding(self):
total_outstanding = sum(d.allocated_amount for d in self.get('references'))
if total_outstanding < 0 and self.party_type == 'Customer' and self.payment_type == 'Receive':
frappe.throw(_("Cannot receive from customer against negative outstanding"), title=_("Incorrect Payment Type"))
def validate_allocated_amount(self): def validate_allocated_amount(self):
for d in self.get("references"): for d in self.get("references"):
if (flt(d.allocated_amount))> 0: if (flt(d.allocated_amount))> 0:
@@ -236,7 +244,9 @@ class PaymentEntry(AccountsController):
self.company_currency, self.posting_date) self.company_currency, self.posting_date)
def set_target_exchange_rate(self, ref_doc=None): def set_target_exchange_rate(self, ref_doc=None):
if self.paid_to and not self.target_exchange_rate: if self.paid_from_account_currency == self.paid_to_account_currency:
self.target_exchange_rate = self.source_exchange_rate
elif self.paid_to and not self.target_exchange_rate:
if ref_doc: if ref_doc:
if self.paid_to_account_currency == ref_doc.currency: if self.paid_to_account_currency == ref_doc.currency:
self.target_exchange_rate = ref_doc.get("exchange_rate") self.target_exchange_rate = ref_doc.get("exchange_rate")
@@ -468,13 +478,22 @@ class PaymentEntry(AccountsController):
def set_amounts(self): def set_amounts(self):
self.set_received_amount() self.set_received_amount()
self.set_amounts_in_company_currency() self.set_amounts_in_company_currency()
self.set_amounts_after_tax()
self.set_total_allocated_amount() self.set_total_allocated_amount()
self.set_unallocated_amount() self.set_unallocated_amount()
self.set_difference_amount() self.set_difference_amount()
def validate_amounts(self):
self.validate_received_amount()
def validate_received_amount(self):
if self.paid_from_account_currency == self.paid_to_account_currency:
if self.paid_amount != self.received_amount:
frappe.throw(_("Received Amount should be same as Paid Amount"))
def set_received_amount(self): def set_received_amount(self):
self.base_received_amount = self.base_paid_amount self.base_received_amount = self.base_paid_amount
if self.paid_from_account_currency == self.paid_to_account_currency:
self.received_amount = self.paid_amount
def set_amounts_after_tax(self): def set_amounts_after_tax(self):
applicable_tax = 0 applicable_tax = 0
@@ -529,7 +548,7 @@ class PaymentEntry(AccountsController):
if self.payment_type == "Receive" \ if self.payment_type == "Receive" \
and self.base_total_allocated_amount < self.base_received_amount + total_deductions \ and self.base_total_allocated_amount < self.base_received_amount + total_deductions \
and self.total_allocated_amount < self.paid_amount + (total_deductions / self.source_exchange_rate): and self.total_allocated_amount < self.paid_amount + (total_deductions / self.source_exchange_rate):
self.unallocated_amount = (self.received_amount + total_deductions - self.unallocated_amount = (self.base_received_amount + total_deductions -
self.base_total_allocated_amount) / self.source_exchange_rate self.base_total_allocated_amount) / self.source_exchange_rate
self.unallocated_amount -= included_taxes self.unallocated_amount -= included_taxes
elif self.payment_type == "Pay" \ elif self.payment_type == "Pay" \

View File

@@ -107,7 +107,7 @@ class TestPaymentEntry(unittest.TestCase):
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank USD - _TC") pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank USD - _TC")
pe.reference_no = "1" pe.reference_no = "1"
pe.reference_date = "2016-01-01" pe.reference_date = "2016-01-01"
pe.target_exchange_rate = 50 pe.source_exchange_rate = 50
pe.insert() pe.insert()
pe.submit() pe.submit()
@@ -154,7 +154,7 @@ class TestPaymentEntry(unittest.TestCase):
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank USD - _TC") pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank USD - _TC")
pe.reference_no = "1" pe.reference_no = "1"
pe.reference_date = "2016-01-01" pe.reference_date = "2016-01-01"
pe.target_exchange_rate = 50 pe.source_exchange_rate = 50
pe.insert() pe.insert()
pe.submit() pe.submit()
@@ -295,6 +295,34 @@ class TestPaymentEntry(unittest.TestCase):
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount")) outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"))
self.assertEqual(outstanding_amount, 80) self.assertEqual(outstanding_amount, 80)
def test_payment_entry_against_si_usd_to_usd_with_deduction_in_base_currency (self):
si = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC",
currency="USD", conversion_rate=50, do_not_save=1)
si.plc_conversion_rate = 50
si.save()
si.submit()
pe = get_payment_entry("Sales Invoice", si.name, party_amount=20,
bank_account="_Test Bank USD - _TC", bank_amount=900)
pe.source_exchange_rate = 45.263
pe.target_exchange_rate = 45.263
pe.reference_no = "1"
pe.reference_date = "2016-01-01"
pe.append("deductions", {
"account": "_Test Exchange Gain/Loss - _TC",
"cost_center": "_Test Cost Center - _TC",
"amount": 94.80
})
pe.save()
self.assertEqual(flt(pe.difference_amount, 2), 0.0)
self.assertEqual(flt(pe.unallocated_amount, 2), 0.0)
def test_payment_entry_retrieves_last_exchange_rate(self): def test_payment_entry_retrieves_last_exchange_rate(self):
from erpnext.setup.doctype.currency_exchange.test_currency_exchange import test_records, save_new_records from erpnext.setup.doctype.currency_exchange.test_currency_exchange import test_records, save_new_records
@@ -463,7 +491,7 @@ class TestPaymentEntry(unittest.TestCase):
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank USD - _TC") pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank USD - _TC")
pe.reference_no = "1" pe.reference_no = "1"
pe.reference_date = "2016-01-01" pe.reference_date = "2016-01-01"
pe.target_exchange_rate = 55 pe.source_exchange_rate = 55
pe.append("deductions", { pe.append("deductions", {
"account": "_Test Exchange Gain/Loss - _TC", "account": "_Test Exchange Gain/Loss - _TC",

View File

@@ -595,7 +595,8 @@
{ {
"fieldname": "scan_barcode", "fieldname": "scan_barcode",
"fieldtype": "Data", "fieldtype": "Data",
"label": "Scan Barcode" "label": "Scan Barcode",
"options": "Barcode"
}, },
{ {
"allow_bulk_edit": 1, "allow_bulk_edit": 1,
@@ -1553,7 +1554,7 @@
"icon": "fa fa-file-text", "icon": "fa fa-file-text",
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2021-07-29 13:37:20.636171", "modified": "2021-08-17 20:13:44.255437",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "POS Invoice", "name": "POS Invoice",

View File

@@ -147,4 +147,3 @@ class TestPOSInvoiceMergeLog(unittest.TestCase):
frappe.set_user("Administrator") frappe.set_user("Administrator")
frappe.db.sql("delete from `tabPOS Profile`") frappe.db.sql("delete from `tabPOS Profile`")
frappe.db.sql("delete from `tabPOS Invoice`") frappe.db.sql("delete from `tabPOS Invoice`")

View File

@@ -26,4 +26,3 @@ QUnit.test("test pricing rule", function(assert) {
() => done() () => done()
]); ]);
}); });

View File

@@ -106,7 +106,6 @@
"depends_on": "eval:doc.rate_or_discount==\"Rate\"", "depends_on": "eval:doc.rate_or_discount==\"Rate\"",
"fieldname": "rate", "fieldname": "rate",
"fieldtype": "Currency", "fieldtype": "Currency",
"in_list_view": 1,
"label": "Rate" "label": "Rate"
}, },
{ {
@@ -170,7 +169,7 @@
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2021-03-07 11:56:23.424137", "modified": "2021-08-19 15:49:29.598727",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Promotional Scheme Price Discount", "name": "Promotional Scheme Price Discount",

View File

@@ -668,8 +668,7 @@
"fieldname": "scan_barcode", "fieldname": "scan_barcode",
"fieldtype": "Data", "fieldtype": "Data",
"label": "Scan Barcode", "label": "Scan Barcode",
"show_days": 1, "options": "Barcode"
"show_seconds": 1
}, },
{ {
"allow_bulk_edit": 1, "allow_bulk_edit": 1,
@@ -1715,7 +1714,7 @@
"idx": 204, "idx": 204,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2021-08-07 17:53:14.351439", "modified": "2021-08-17 20:16:12.737743",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Purchase Invoice", "name": "Purchase Invoice",

View File

@@ -519,8 +519,6 @@ class PurchaseInvoice(BuyingController):
if d.category in ('Valuation', 'Total and Valuation') if d.category in ('Valuation', 'Total and Valuation')
and flt(d.base_tax_amount_after_discount_amount)] and flt(d.base_tax_amount_after_discount_amount)]
enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))
for item in self.get("items"): for item in self.get("items"):
if flt(item.base_net_amount): if flt(item.base_net_amount):
account_currency = get_account_currency(item.expense_account) account_currency = get_account_currency(item.expense_account)
@@ -611,7 +609,7 @@ class PurchaseInvoice(BuyingController):
if (not item.enable_deferred_expense or self.is_return) else item.deferred_expense_account) if (not item.enable_deferred_expense or self.is_return) else item.deferred_expense_account)
if not item.is_fixed_asset: if not item.is_fixed_asset:
dummy, amount = self.get_amount_and_base_amount(item, enable_discount_accounting) dummy, amount = self.get_amount_and_base_amount(item, self.enable_discount_accounting)
else: else:
amount = flt(item.base_net_amount + item.item_tax_amount, item.precision("base_net_amount")) amount = flt(item.base_net_amount + item.item_tax_amount, item.precision("base_net_amount"))
@@ -825,10 +823,9 @@ class PurchaseInvoice(BuyingController):
def make_tax_gl_entries(self, gl_entries): def make_tax_gl_entries(self, gl_entries):
# tax table gl entries # tax table gl entries
valuation_tax = {} valuation_tax = {}
enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))
for tax in self.get("taxes"): for tax in self.get("taxes"):
amount, base_amount = self.get_tax_amounts(tax, enable_discount_accounting) amount, base_amount = self.get_tax_amounts(tax, self.enable_discount_accounting)
if tax.category in ("Total", "Valuation and Total") and flt(base_amount): if tax.category in ("Total", "Valuation and Total") and flt(base_amount):
account_currency = get_account_currency(tax.account_head) account_currency = get_account_currency(tax.account_head)
@@ -893,6 +890,13 @@ class PurchaseInvoice(BuyingController):
"remarks": self.remarks or "Accounting Entry for Stock" "remarks": self.remarks or "Accounting Entry for Stock"
}, item=tax)) }, item=tax))
@property
def enable_discount_accounting(self):
if not hasattr(self, "_enable_discount_accounting"):
self._enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))
return self._enable_discount_accounting
def make_internal_transfer_gl_entries(self, gl_entries): def make_internal_transfer_gl_entries(self, gl_entries):
if self.is_internal_transfer() and flt(self.base_total_taxes_and_charges): if self.is_internal_transfer() and flt(self.base_total_taxes_and_charges):
account_currency = get_account_currency(self.unrealized_profit_loss_account) account_currency = get_account_currency(self.unrealized_profit_loss_account)

View File

@@ -72,4 +72,3 @@ QUnit.test("test purchase invoice", function(assert) {
() => done() () => done()
]); ]);
}); });

View File

@@ -502,6 +502,7 @@
}, },
{ {
"collapsible": 1, "collapsible": 1,
"collapsible_depends_on": "enable_deferred_expense",
"fieldname": "deferred_expense_section", "fieldname": "deferred_expense_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Deferred Expense" "label": "Deferred Expense"
@@ -861,7 +862,7 @@
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2021-07-13 02:04:37.787882", "modified": "2021-08-12 20:14:45.506639",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Purchase Invoice Item", "name": "Purchase Invoice Item",

View File

@@ -22,7 +22,7 @@
"cost_center", "cost_center",
"dimension_col_break", "dimension_col_break",
"section_break_9", "section_break_9",
"currency", "account_currency",
"tax_amount", "tax_amount",
"tax_amount_after_discount_amount", "tax_amount_after_discount_amount",
"total", "total",
@@ -208,14 +208,6 @@
"fieldname": "dimension_col_break", "fieldname": "dimension_col_break",
"fieldtype": "Column Break" "fieldtype": "Column Break"
}, },
{
"fetch_from": "account_head.account_currency",
"fieldname": "currency",
"fieldtype": "Link",
"label": "Account Currency",
"options": "Currency",
"read_only": 1
},
{ {
"default": "0", "default": "0",
"depends_on": "eval:['Purchase Taxes and Charges Template', 'Payment Entry'].includes(parent.doctype)", "depends_on": "eval:['Purchase Taxes and Charges Template', 'Payment Entry'].includes(parent.doctype)",
@@ -223,12 +215,20 @@
"fieldname": "included_in_paid_amount", "fieldname": "included_in_paid_amount",
"fieldtype": "Check", "fieldtype": "Check",
"label": "Considered In Paid Amount" "label": "Considered In Paid Amount"
},
{
"fetch_from": "account_head.account_currency",
"fieldname": "account_currency",
"fieldtype": "Link",
"label": "Account Currency",
"options": "Currency",
"read_only": 1
} }
], ],
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2021-06-14 01:43:50.750455", "modified": "2021-08-05 20:04:36.618240",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Purchase Taxes and Charges", "name": "Purchase Taxes and Charges",

View File

@@ -26,4 +26,3 @@ QUnit.test("test sales taxes and charges template", function(assert) {
() => done() () => done()
]); ]);
}); });

File diff suppressed because it is too large Load Diff

View File

@@ -478,6 +478,9 @@ class SalesInvoice(SellingController):
if cint(self.is_pos) != 1: if cint(self.is_pos) != 1:
return return
if not self.account_for_change_amount:
self.account_for_change_amount = frappe.get_cached_value('Company', self.company, 'default_cash_account')
from erpnext.stock.get_item_details import get_pos_profile_item_details, get_pos_profile from erpnext.stock.get_item_details import get_pos_profile_item_details, get_pos_profile
if not self.pos_profile: if not self.pos_profile:
pos_profile = get_pos_profile(self.company) or {} pos_profile = get_pos_profile(self.company) or {}
@@ -492,9 +495,6 @@ class SalesInvoice(SellingController):
if not self.get('payments') and not for_validate: if not self.get('payments') and not for_validate:
update_multi_mode_option(self, pos) update_multi_mode_option(self, pos)
if not self.account_for_change_amount:
self.account_for_change_amount = frappe.get_cached_value('Company', self.company, 'default_cash_account')
if pos: if pos:
if not for_validate: if not for_validate:
self.tax_category = pos.get("tax_category") self.tax_category = pos.get("tax_category")
@@ -888,10 +888,8 @@ class SalesInvoice(SellingController):
) )
def make_tax_gl_entries(self, gl_entries): def make_tax_gl_entries(self, gl_entries):
enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))
for tax in self.get("taxes"): for tax in self.get("taxes"):
amount, base_amount = self.get_tax_amounts(tax, enable_discount_accounting) amount, base_amount = self.get_tax_amounts(tax, self.enable_discount_accounting)
if flt(tax.base_tax_amount_after_discount_amount): if flt(tax.base_tax_amount_after_discount_amount):
account_currency = get_account_currency(tax.account_head) account_currency = get_account_currency(tax.account_head)
@@ -922,8 +920,6 @@ class SalesInvoice(SellingController):
def make_item_gl_entries(self, gl_entries): def make_item_gl_entries(self, gl_entries):
# income account gl entries # income account gl entries
enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))
for item in self.get("items"): for item in self.get("items"):
if flt(item.base_net_amount, item.precision("base_net_amount")): if flt(item.base_net_amount, item.precision("base_net_amount")):
if item.is_fixed_asset: if item.is_fixed_asset:
@@ -949,7 +945,7 @@ class SalesInvoice(SellingController):
income_account = (item.income_account income_account = (item.income_account
if (not item.enable_deferred_revenue or self.is_return) else item.deferred_revenue_account) if (not item.enable_deferred_revenue or self.is_return) else item.deferred_revenue_account)
amount, base_amount = self.get_amount_and_base_amount(item, enable_discount_accounting) amount, base_amount = self.get_amount_and_base_amount(item, self.enable_discount_accounting)
account_currency = get_account_currency(income_account) account_currency = get_account_currency(income_account)
gl_entries.append( gl_entries.append(
@@ -970,6 +966,13 @@ class SalesInvoice(SellingController):
erpnext.is_perpetual_inventory_enabled(self.company): erpnext.is_perpetual_inventory_enabled(self.company):
gl_entries += super(SalesInvoice, self).get_gl_entries() gl_entries += super(SalesInvoice, self).get_gl_entries()
@property
def enable_discount_accounting(self):
if not hasattr(self, "_enable_discount_accounting"):
self._enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))
return self._enable_discount_accounting
def set_asset_status(self, asset): def set_asset_status(self, asset):
if self.is_return: if self.is_return:
asset.set_status() asset.set_status()
@@ -1365,7 +1368,7 @@ class SalesInvoice(SellingController):
discounting_status = None discounting_status = None
if self.is_discounted: if self.is_discounted:
discountng_status = get_discounting_status(self.name) discounting_status = get_discounting_status(self.name)
if not status: if not status:
if self.docstatus == 2: if self.docstatus == 2:
@@ -1373,11 +1376,11 @@ class SalesInvoice(SellingController):
elif self.docstatus == 1: elif self.docstatus == 1:
if self.is_internal_transfer(): if self.is_internal_transfer():
self.status = 'Internal Transfer' self.status = 'Internal Transfer'
elif outstanding_amount > 0 and due_date < nowdate and self.is_discounted and discountng_status=='Disbursed': elif outstanding_amount > 0 and due_date < nowdate and self.is_discounted and discounting_status=='Disbursed':
self.status = "Overdue and Discounted" self.status = "Overdue and Discounted"
elif outstanding_amount > 0 and due_date < nowdate: elif outstanding_amount > 0 and due_date < nowdate:
self.status = "Overdue" self.status = "Overdue"
elif outstanding_amount > 0 and due_date >= nowdate and self.is_discounted and discountng_status=='Disbursed': elif outstanding_amount > 0 and due_date >= nowdate and self.is_discounted and discounting_status=='Disbursed':
self.status = "Unpaid and Discounted" self.status = "Unpaid and Discounted"
elif outstanding_amount > 0 and due_date >= nowdate: elif outstanding_amount > 0 and due_date >= nowdate:
self.status = "Unpaid" self.status = "Unpaid"

View File

@@ -23,6 +23,7 @@ from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice
from erpnext.stock.utils import get_incoming_rate from erpnext.stock.utils import get_incoming_rate
from erpnext.accounts.utils import PaymentEntryUnlinkError
class TestSalesInvoice(unittest.TestCase): class TestSalesInvoice(unittest.TestCase):
def make(self): def make(self):
@@ -133,7 +134,7 @@ class TestSalesInvoice(unittest.TestCase):
pe.paid_to_account_currency = si.currency pe.paid_to_account_currency = si.currency
pe.source_exchange_rate = 1 pe.source_exchange_rate = 1
pe.target_exchange_rate = 1 pe.target_exchange_rate = 1
pe.paid_amount = si.grand_total pe.paid_amount = si.outstanding_amount
pe.insert() pe.insert()
pe.submit() pe.submit()
@@ -142,6 +143,42 @@ class TestSalesInvoice(unittest.TestCase):
self.assertRaises(frappe.LinkExistsError, si.cancel) self.assertRaises(frappe.LinkExistsError, si.cancel)
unlink_payment_on_cancel_of_invoice() unlink_payment_on_cancel_of_invoice()
def test_payment_entry_unlink_against_standalone_credit_note(self):
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
si1 = create_sales_invoice(rate=1000)
si2 = create_sales_invoice(rate=300)
si3 = create_sales_invoice(qty=-1, rate=300, is_return=1)
pe = get_payment_entry("Sales Invoice", si1.name, bank_account="_Test Bank - _TC")
pe.append('references', {
'reference_doctype': 'Sales Invoice',
'reference_name': si2.name,
'total_amount': si2.grand_total,
'outstanding_amount': si2.outstanding_amount,
'allocated_amount': si2.outstanding_amount
})
pe.append('references', {
'reference_doctype': 'Sales Invoice',
'reference_name': si3.name,
'total_amount': si3.grand_total,
'outstanding_amount': si3.outstanding_amount,
'allocated_amount': si3.outstanding_amount
})
pe.reference_no = 'Test001'
pe.reference_date = nowdate()
pe.save()
pe.submit()
si2.load_from_db()
si2.cancel()
si1.load_from_db()
self.assertRaises(PaymentEntryUnlinkError, si1.cancel)
def test_sales_invoice_calculation_export_currency(self): def test_sales_invoice_calculation_export_currency(self):
si = frappe.copy_doc(test_records[2]) si = frappe.copy_doc(test_records[2])
si.currency = "USD" si.currency = "USD"
@@ -1898,7 +1935,7 @@ class TestSalesInvoice(unittest.TestCase):
data = get_ewb_data("Sales Invoice", [si.name]) data = get_ewb_data("Sales Invoice", [si.name])
self.assertEqual(data['version'], '1.0.1118') self.assertEqual(data['version'], '1.0.0421')
self.assertEqual(data['billLists'][0]['fromGstin'], '27AAECE4835E1ZR') self.assertEqual(data['billLists'][0]['fromGstin'], '27AAECE4835E1ZR')
self.assertEqual(data['billLists'][0]['fromTrdName'], '_Test Company') self.assertEqual(data['billLists'][0]['fromTrdName'], '_Test Company')
self.assertEqual(data['billLists'][0]['toTrdName'], '_Test Customer') self.assertEqual(data['billLists'][0]['toTrdName'], '_Test Customer')

View File

@@ -40,4 +40,3 @@ QUnit.test("test sales Invoice", function(assert) {
() => done() () => done()
]); ]);
}); });

View File

@@ -33,4 +33,3 @@ QUnit.test("test sales invoice with margin", function(assert) {
() => done() () => done()
]); ]);
}); });

View File

@@ -54,4 +54,3 @@ QUnit.test("test sales Invoice with payment", function(assert) {
() => done() () => done()
]); ]);
}); });

View File

@@ -49,4 +49,3 @@ QUnit.test("test sales Invoice with payment request", function(assert) {
() => done() () => done()
]); ]);
}); });

View File

@@ -42,4 +42,3 @@ QUnit.test("test sales Invoice with serialize item", function(assert) {
() => done() () => done()
]); ]);
}); });

View File

@@ -474,6 +474,7 @@
}, },
{ {
"collapsible": 1, "collapsible": 1,
"collapsible_depends_on": "enable_deferred_revenue",
"fieldname": "deferred_revenue", "fieldname": "deferred_revenue",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Deferred Revenue" "label": "Deferred Revenue"
@@ -833,7 +834,7 @@
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2021-07-05 15:07:22.857128", "modified": "2021-08-12 20:15:42.668399",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Sales Invoice Item", "name": "Sales Invoice Item",

View File

@@ -19,7 +19,7 @@
"section_break_8", "section_break_8",
"rate", "rate",
"section_break_9", "section_break_9",
"currency", "account_currency",
"tax_amount", "tax_amount",
"total", "total",
"tax_amount_after_discount_amount", "tax_amount_after_discount_amount",
@@ -186,14 +186,6 @@
"fieldname": "dimension_col_break", "fieldname": "dimension_col_break",
"fieldtype": "Column Break" "fieldtype": "Column Break"
}, },
{
"fetch_from": "account_head.account_currency",
"fieldname": "currency",
"fieldtype": "Link",
"label": "Account Currency",
"options": "Currency",
"read_only": 1
},
{ {
"default": "0", "default": "0",
"depends_on": "eval:['Sales Taxes and Charges Template', 'Payment Entry'].includes(parent.doctype)", "depends_on": "eval:['Sales Taxes and Charges Template', 'Payment Entry'].includes(parent.doctype)",
@@ -210,13 +202,21 @@
"label": "Dont Recompute tax", "label": "Dont Recompute tax",
"print_hide": 1, "print_hide": 1,
"read_only": 1 "read_only": 1
},
{
"fetch_from": "account_head.account_currency",
"fieldname": "account_currency",
"fieldtype": "Link",
"label": "Account Currency",
"options": "Currency",
"read_only": 1
} }
], ],
"idx": 1, "idx": 1,
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2021-07-27 12:40:59.051803", "modified": "2021-08-05 20:04:01.726867",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Sales Taxes and Charges", "name": "Sales Taxes and Charges",

View File

@@ -26,4 +26,3 @@ QUnit.test("test sales taxes and charges template", function(assert) {
() => done() () => done()
]); ]);
}); });

View File

@@ -34,4 +34,3 @@ QUnit.test("test Shipping Rule", function(assert) {
() => done() () => done()
]); ]);
}); });

View File

@@ -34,4 +34,3 @@ QUnit.test("test Shipping Rule", function(assert) {
() => done() () => done()
]); ]);
}); });

View File

@@ -630,5 +630,3 @@ class TestSubscription(unittest.TestCase):
subscription.process() subscription.process()
self.assertEqual(len(subscription.invoices), 1) self.assertEqual(len(subscription.invoices), 1)

View File

@@ -286,6 +286,7 @@ def validate_party_gle_currency(party_type, party, company, party_account_curren
.format(frappe.bold(party_type), frappe.bold(party), frappe.bold(existing_gle_currency), frappe.bold(company)), InvalidAccountCurrency) .format(frappe.bold(party_type), frappe.bold(party), frappe.bold(existing_gle_currency), frappe.bold(company)), InvalidAccountCurrency)
def validate_party_accounts(doc): def validate_party_accounts(doc):
companies = [] companies = []
for account in doc.get("accounts"): for account in doc.get("accounts"):
@@ -446,6 +447,10 @@ def get_payment_terms_template(party_name, party_type, company=None):
return template return template
def validate_party_frozen_disabled(party_type, party_name): def validate_party_frozen_disabled(party_type, party_name):
if frappe.flags.ignore_party_validation:
return
if party_type and party_name: if party_type and party_name:
if party_type in ("Customer", "Supplier"): if party_type in ("Customer", "Supplier"):
party = frappe.get_cached_value(party_type, party_name, ["is_frozen", "disabled"], as_dict=True) party = frappe.get_cached_value(party_type, party_name, ["is_frozen", "disabled"], as_dict=True)

View File

@@ -16,7 +16,7 @@
"name": "Bank and Cash Payment Voucher", "name": "Bank and Cash Payment Voucher",
"owner": "Administrator", "owner": "Administrator",
"print_format_builder": 0, "print_format_builder": 0,
"print_format_type": "Server", "print_format_type": "Jinja",
"show_section_headings": 0, "show_section_headings": 0,
"standard": "Yes" "standard": "Yes"
} }

View File

@@ -10,6 +10,6 @@
"modified_by": "Administrator", "modified_by": "Administrator",
"name": "Cheque Printing Format", "name": "Cheque Printing Format",
"owner": "Administrator", "owner": "Administrator",
"print_format_type": "Server", "print_format_type": "Jinja",
"standard": "Yes" "standard": "Yes"
} }

View File

@@ -17,7 +17,7 @@
"owner": "Administrator", "owner": "Administrator",
"parentfield": "__print_formats", "parentfield": "__print_formats",
"print_format_builder": 0, "print_format_builder": 0,
"print_format_type": "Server", "print_format_type": "Jinja",
"show_section_headings": 0, "show_section_headings": 0,
"standard": "Yes" "standard": "Yes"
} }

View File

@@ -16,7 +16,7 @@
"name": "GST Purchase Invoice", "name": "GST Purchase Invoice",
"owner": "Administrator", "owner": "Administrator",
"print_format_builder": 1, "print_format_builder": 1,
"print_format_type": "Server", "print_format_type": "Jinja",
"show_section_headings": 0, "show_section_headings": 0,
"standard": "Yes" "standard": "Yes"
} }

View File

@@ -16,7 +16,7 @@
"name": "Journal Auditing Voucher", "name": "Journal Auditing Voucher",
"owner": "Administrator", "owner": "Administrator",
"print_format_builder": 0, "print_format_builder": 0,
"print_format_type": "Server", "print_format_type": "Jinja",
"show_section_headings": 0, "show_section_headings": 0,
"standard": "Yes" "standard": "Yes"
} }

View File

@@ -27,4 +27,3 @@
{{ _("Authorized Signatory") }} {{ _("Authorized Signatory") }}
</p> </p>
</div> </div>

View File

@@ -12,6 +12,6 @@
"name": "Payment Receipt Voucher", "name": "Payment Receipt Voucher",
"owner": "Administrator", "owner": "Administrator",
"print_format_builder": 0, "print_format_builder": 0,
"print_format_type": "Server", "print_format_type": "Jinja",
"standard": "Yes" "standard": "Yes"
} }

View File

@@ -16,7 +16,7 @@
"name": "Purchase Auditing Voucher", "name": "Purchase Auditing Voucher",
"owner": "Administrator", "owner": "Administrator",
"print_format_builder": 0, "print_format_builder": 0,
"print_format_type": "Server", "print_format_type": "Jinja",
"show_section_headings": 0, "show_section_headings": 0,
"standard": "Yes" "standard": "Yes"
} }

View File

@@ -16,7 +16,7 @@
"name": "Sales Auditing Voucher", "name": "Sales Auditing Voucher",
"owner": "Administrator", "owner": "Administrator",
"print_format_builder": 0, "print_format_builder": 0,
"print_format_type": "Server", "print_format_type": "Jinja",
"show_section_headings": 0, "show_section_headings": 0,
"standard": "Yes" "standard": "Yes"
} }

View File

@@ -62,8 +62,3 @@ def make_sales_invoice():
income_account = 'Sales - _TC2', income_account = 'Sales - _TC2',
expense_account = 'Cost of Goods Sold - _TC2', expense_account = 'Cost of Goods Sold - _TC2',
cost_center = 'Main - _TC2') cost_center = 'Main - _TC2')

View File

@@ -136,4 +136,3 @@ frappe.query_reports["Accounts Payable"] = {
} }
erpnext.utils.add_dimensions('Accounts Payable', 9); erpnext.utils.add_dimensions('Accounts Payable', 9);

View File

@@ -105,4 +105,3 @@ frappe.query_reports["Accounts Payable Summary"] = {
} }
erpnext.utils.add_dimensions('Accounts Payable Summary', 9); erpnext.utils.add_dimensions('Accounts Payable Summary', 9);

View File

@@ -12,4 +12,3 @@ def execute(filters=None):
"naming_by": ["Buying Settings", "supp_master_name"], "naming_by": ["Buying Settings", "supp_master_name"],
} }
return AccountsReceivableSummary(filters).run(args) return AccountsReceivableSummary(filters).run(args)

View File

@@ -200,4 +200,3 @@ frappe.query_reports["Accounts Receivable"] = {
} }
erpnext.utils.add_dimensions('Accounts Receivable', 9); erpnext.utils.add_dimensions('Accounts Receivable', 9);

View File

@@ -535,6 +535,8 @@ class ReceivablePayableReport(object):
if getdate(entry_date) > getdate(self.filters.report_date): if getdate(entry_date) > getdate(self.filters.report_date):
row.range1 = row.range2 = row.range3 = row.range4 = row.range5 = 0.0 row.range1 = row.range2 = row.range3 = row.range4 = row.range5 = 0.0
row.total_due = row.range1 + row.range2 + row.range3 + row.range4 + row.range5
def get_ageing_data(self, entry_date, row): def get_ageing_data(self, entry_date, row):
# [0-30, 30-60, 60-90, 90-120, 120-above] # [0-30, 30-60, 60-90, 90-120, 120-above]
row.range1 = row.range2 = row.range3 = row.range4 = row.range5 = 0.0 row.range1 = row.range2 = row.range3 = row.range4 = row.range5 = 0.0

View File

@@ -93,4 +93,3 @@ def make_credit_note(docname):
cost_center = 'Main - _TC2', cost_center = 'Main - _TC2',
is_return = 1, is_return = 1,
return_against = docname) return_against = docname)

View File

@@ -82,6 +82,7 @@ class AccountsReceivableSummary(ReceivablePayableReport):
"range3": 0.0, "range3": 0.0,
"range4": 0.0, "range4": 0.0,
"range5": 0.0, "range5": 0.0,
"total_due": 0.0,
"sales_person": [] "sales_person": []
})) }))
@@ -135,3 +136,6 @@ class AccountsReceivableSummary(ReceivablePayableReport):
"{range3}-{range4}".format(range3=cint(self.filters["range3"])+ 1, range4=self.filters["range4"]), "{range3}-{range4}".format(range3=cint(self.filters["range3"])+ 1, range4=self.filters["range4"]),
"{range4}-{above}".format(range4=cint(self.filters["range4"])+ 1, above=_("Above"))]): "{range4}-{above}".format(range4=cint(self.filters["range4"])+ 1, above=_("Above"))]):
self.add_column(label=label, fieldname='range' + str(i+1)) self.add_column(label=label, fieldname='range' + str(i+1))
# Add column for total due amount
self.add_column(label="Total Amount Due", fieldname='total_due')

View File

@@ -92,4 +92,3 @@ frappe.query_reports["Budget Variance Report"] = {
erpnext.dimension_filters.forEach((dimension) => { erpnext.dimension_filters.forEach((dimension) => {
frappe.query_reports["Budget Variance Report"].filters[4].options.push(dimension["document_type"]); frappe.query_reports["Budget Variance Report"].filters[4].options.push(dimension["document_type"]);
}); });

View File

@@ -38,8 +38,8 @@ def execute(filters=None):
GROUP BY parent''',{'dimension':[dimension]}) GROUP BY parent''',{'dimension':[dimension]})
if DCC_allocation: if DCC_allocation:
filters['budget_against_filter'] = [DCC_allocation[0][0]] filters['budget_against_filter'] = [DCC_allocation[0][0]]
cam_map = get_dimension_account_month_map(filters) ddc_cam_map = get_dimension_account_month_map(filters)
dimension_items = cam_map.get(DCC_allocation[0][0]) dimension_items = ddc_cam_map.get(DCC_allocation[0][0])
if dimension_items: if dimension_items:
data = get_final_data(dimension, dimension_items, filters, period_month_ranges, data, DCC_allocation[0][1]) data = get_final_data(dimension, dimension_items, filters, period_month_ranges, data, DCC_allocation[0][1])
@@ -48,7 +48,6 @@ def execute(filters=None):
return columns, data, None, chart return columns, data, None, chart
def get_final_data(dimension, dimension_items, filters, period_month_ranges, data, DCC_allocation): def get_final_data(dimension, dimension_items, filters, period_month_ranges, data, DCC_allocation):
for account, monthwise_data in iteritems(dimension_items): for account, monthwise_data in iteritems(dimension_items):
row = [dimension, account] row = [dimension, account]
totals = [0, 0, 0] totals = [0, 0, 0]
@@ -400,4 +399,3 @@ def get_chart_data(filters, columns, data):
}, },
'type' : 'bar' 'type' : 'bar'
} }

View File

@@ -210,10 +210,10 @@ def get_data(companies, root_type, balance_must_be, fiscal_year, filters=None, i
company_currency = get_company_currency(filters) company_currency = get_company_currency(filters)
if filters.filter_based_on == 'Fiscal Year': if filters.filter_based_on == 'Fiscal Year':
start_date = fiscal_year.year_start_date start_date = fiscal_year.year_start_date if filters.report != 'Balance Sheet' else None
end_date = fiscal_year.year_end_date end_date = fiscal_year.year_end_date
else: else:
start_date = filters.period_start_date start_date = filters.period_start_date if filters.report != 'Balance Sheet' else None
end_date = filters.period_end_date end_date = filters.period_end_date
gl_entries_by_account = {} gl_entries_by_account = {}

View File

@@ -176,4 +176,3 @@ frappe.query_reports["General Ledger"] = {
} }
erpnext.utils.add_dimensions('General Ledger', 15) erpnext.utils.add_dimensions('General Ledger', 15)

View File

@@ -76,7 +76,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
'company': d.company, 'company': d.company,
'sales_order': d.sales_order, 'sales_order': d.sales_order,
'delivery_note': d.delivery_note, 'delivery_note': d.delivery_note,
'income_account': d.unrealized_profit_loss_account or d.income_account, 'income_account': d.unrealized_profit_loss_account if d.is_internal_customer == 1 else d.income_account,
'cost_center': d.cost_center, 'cost_center': d.cost_center,
'stock_qty': d.stock_qty, 'stock_qty': d.stock_qty,
'stock_uom': d.stock_uom 'stock_uom': d.stock_uom
@@ -380,6 +380,7 @@ def get_items(filters, additional_query_columns):
`tabSales Invoice Item`.name, `tabSales Invoice Item`.parent, `tabSales Invoice Item`.name, `tabSales Invoice Item`.parent,
`tabSales Invoice`.posting_date, `tabSales Invoice`.debit_to, `tabSales Invoice`.posting_date, `tabSales Invoice`.debit_to,
`tabSales Invoice`.unrealized_profit_loss_account, `tabSales Invoice`.unrealized_profit_loss_account,
`tabSales Invoice`.is_internal_customer,
`tabSales Invoice`.project, `tabSales Invoice`.customer, `tabSales Invoice`.remarks, `tabSales Invoice`.project, `tabSales Invoice`.customer, `tabSales Invoice`.remarks,
`tabSales Invoice`.territory, `tabSales Invoice`.company, `tabSales Invoice`.base_net_total, `tabSales Invoice`.territory, `tabSales Invoice`.company, `tabSales Invoice`.base_net_total,
`tabSales Invoice Item`.item_code, `tabSales Invoice Item`.description, `tabSales Invoice Item`.item_code, `tabSales Invoice Item`.description,
@@ -625,7 +626,3 @@ def add_sub_total_row(item, total_row_map, group_by_value, tax_columns):
for tax in tax_columns: for tax in tax_columns:
total_row.setdefault(frappe.scrub(tax + ' Amount'), 0.0) total_row.setdefault(frappe.scrub(tax + ' Amount'), 0.0)
total_row[frappe.scrub(tax + ' Amount')] += flt(item[frappe.scrub(tax + ' Amount')]) total_row[frappe.scrub(tax + ' Amount')] += flt(item[frappe.scrub(tax + ' Amount')])

View File

@@ -69,4 +69,3 @@ frappe.query_reports["Sales Register"] = {
} }
erpnext.utils.add_dimensions('Sales Register', 7); erpnext.utils.add_dimensions('Sales Register', 7);

View File

@@ -84,7 +84,7 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No
# Add amount in unrealized account # Add amount in unrealized account
for account in unrealized_profit_loss_accounts: for account in unrealized_profit_loss_accounts:
row.update({ row.update({
frappe.scrub(account): flt(internal_invoice_map.get((inv.name, account))) frappe.scrub(account+"_unrealized"): flt(internal_invoice_map.get((inv.name, account)))
}) })
# net total # net total
@@ -258,6 +258,7 @@ def get_columns(invoice_list, additional_table_columns):
unrealized_profit_loss_accounts = frappe.db.sql_list("""SELECT distinct unrealized_profit_loss_account unrealized_profit_loss_accounts = frappe.db.sql_list("""SELECT distinct unrealized_profit_loss_account
from `tabSales Invoice` where docstatus = 1 and name in (%s) from `tabSales Invoice` where docstatus = 1 and name in (%s)
and is_internal_customer = 1
and ifnull(unrealized_profit_loss_account, '') != '' and ifnull(unrealized_profit_loss_account, '') != ''
order by unrealized_profit_loss_account""" % order by unrealized_profit_loss_account""" %
', '.join(['%s']*len(invoice_list)), tuple(inv.name for inv in invoice_list)) ', '.join(['%s']*len(invoice_list)), tuple(inv.name for inv in invoice_list))
@@ -284,7 +285,7 @@ def get_columns(invoice_list, additional_table_columns):
for account in unrealized_profit_loss_accounts: for account in unrealized_profit_loss_accounts:
unrealized_profit_loss_account_columns.append({ unrealized_profit_loss_account_columns.append({
"label": account, "label": account,
"fieldname": frappe.scrub(account), "fieldname": frappe.scrub(account+"_unrealized"),
"fieldtype": "Currency", "fieldtype": "Currency",
"options": "currency", "options": "currency",
"width": 120 "width": 120

View File

@@ -110,6 +110,3 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
erpnext.utils.add_dimensions('Trial Balance', 6); erpnext.utils.add_dimensions('Trial Balance', 6);
}); });

View File

@@ -19,6 +19,7 @@ from erpnext.stock import get_warehouse_account_map
class StockValueAndAccountBalanceOutOfSync(frappe.ValidationError): pass class StockValueAndAccountBalanceOutOfSync(frappe.ValidationError): pass
class FiscalYearError(frappe.ValidationError): pass class FiscalYearError(frappe.ValidationError): pass
class PaymentEntryUnlinkError(frappe.ValidationError): pass
@frappe.whitelist() @frappe.whitelist()
def get_fiscal_year(date=None, fiscal_year=None, label="Date", verbose=1, company=None, as_dict=False): def get_fiscal_year(date=None, fiscal_year=None, label="Date", verbose=1, company=None, as_dict=False):
@@ -350,6 +351,7 @@ def reconcile_against_document(args):
# cancel advance entry # cancel advance entry
doc = frappe.get_doc(d.voucher_type, d.voucher_no) doc = frappe.get_doc(d.voucher_type, d.voucher_no)
frappe.flags.ignore_party_validation = True
doc.make_gl_entries(cancel=1, adv_adj=1) doc.make_gl_entries(cancel=1, adv_adj=1)
# update ref in advance entry # update ref in advance entry
@@ -361,6 +363,7 @@ def reconcile_against_document(args):
# re-submit advance entry # re-submit advance entry
doc = frappe.get_doc(d.voucher_type, d.voucher_no) doc = frappe.get_doc(d.voucher_type, d.voucher_no)
doc.make_gl_entries(cancel = 0, adv_adj =1) doc.make_gl_entries(cancel = 0, adv_adj =1)
frappe.flags.ignore_party_validation = False
if d.voucher_type in ('Payment Entry', 'Journal Entry'): if d.voucher_type in ('Payment Entry', 'Journal Entry'):
doc.update_expense_claim() doc.update_expense_claim()
@@ -553,10 +556,16 @@ def remove_ref_doc_link_from_pe(ref_type, ref_no):
and docstatus < 2""", (now(), frappe.session.user, ref_type, ref_no)) and docstatus < 2""", (now(), frappe.session.user, ref_type, ref_no))
for pe in linked_pe: for pe in linked_pe:
pe_doc = frappe.get_doc("Payment Entry", pe) try:
pe_doc.set_total_allocated_amount() pe_doc = frappe.get_doc("Payment Entry", pe)
pe_doc.set_unallocated_amount() pe_doc.set_amounts()
pe_doc.clear_unallocated_reference_document_rows() pe_doc.clear_unallocated_reference_document_rows()
pe_doc.validate_payment_type_with_outstanding()
except Exception as e:
msg = _("There were issues unlinking payment entry {0}.").format(pe_doc.name)
msg += '<br>'
msg += _("Please cancel payment entry manually first")
frappe.throw(msg, exc=PaymentEntryUnlinkError, title=_("Payment Unlink Error"))
frappe.db.sql("""update `tabPayment Entry` set total_allocated_amount=%s, frappe.db.sql("""update `tabPayment Entry` set total_allocated_amount=%s,
base_total_allocated_amount=%s, unallocated_amount=%s, modified=%s, modified_by=%s base_total_allocated_amount=%s, unallocated_amount=%s, modified=%s, modified_by=%s

View File

@@ -36,4 +36,3 @@ QUnit.test("test: Disease", function (assert) {
]); ]);
}); });

View File

@@ -15,6 +15,7 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_pu
class TestAssetMovement(unittest.TestCase): class TestAssetMovement(unittest.TestCase):
def setUp(self): def setUp(self):
frappe.db.set_value("Company", "_Test Company", "capital_work_in_progress_account", "CWIP Account - _TC")
create_asset_data() create_asset_data()
make_location() make_location()
@@ -50,7 +51,7 @@ class TestAssetMovement(unittest.TestCase):
reference_doctype = 'Purchase Receipt', reference_name = pr.name) reference_doctype = 'Purchase Receipt', reference_name = pr.name)
self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location 2") self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location 2")
movement2 = create_asset_movement(purpose = 'Transfer', company = asset.company, create_asset_movement(purpose = 'Transfer', company = asset.company,
assets = [{ 'asset': asset.name , 'source_location': 'Test Location 2', 'target_location': 'Test Location'}], assets = [{ 'asset': asset.name , 'source_location': 'Test Location 2', 'target_location': 'Test Location'}],
reference_doctype = 'Purchase Receipt', reference_name = pr.name) reference_doctype = 'Purchase Receipt', reference_name = pr.name)
self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location") self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location")
@@ -59,7 +60,7 @@ class TestAssetMovement(unittest.TestCase):
self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location") self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location")
employee = make_employee("testassetmovemp@example.com", company="_Test Company") employee = make_employee("testassetmovemp@example.com", company="_Test Company")
movement3 = create_asset_movement(purpose = 'Issue', company = asset.company, create_asset_movement(purpose = 'Issue', company = asset.company,
assets = [{ 'asset': asset.name , 'source_location': 'Test Location', 'to_employee': employee}], assets = [{ 'asset': asset.name , 'source_location': 'Test Location', 'to_employee': employee}],
reference_doctype = 'Purchase Receipt', reference_name = pr.name) reference_doctype = 'Purchase Receipt', reference_name = pr.name)

View File

@@ -10,4 +10,3 @@ frappe.listview_settings['Asset Repair'] = {
} }
} }
}; };

View File

@@ -565,6 +565,7 @@
"fieldname": "scan_barcode", "fieldname": "scan_barcode",
"fieldtype": "Data", "fieldtype": "Data",
"label": "Scan Barcode", "label": "Scan Barcode",
"options": "Barcode",
"show_days": 1, "show_days": 1,
"show_seconds": 1 "show_seconds": 1
}, },
@@ -1378,7 +1379,7 @@
"idx": 105, "idx": 105,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2021-05-30 15:17:53.663648", "modified": "2021-08-17 20:16:12.737743",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Purchase Order", "name": "Purchase Order",

View File

@@ -65,3 +65,25 @@ class Supplier(TransactionBase):
def after_rename(self, olddn, newdn, merge=False): def after_rename(self, olddn, newdn, merge=False):
if frappe.defaults.get_global_default('supp_master_name') == 'Supplier Name': if frappe.defaults.get_global_default('supp_master_name') == 'Supplier Name':
frappe.db.set(self, "supplier_name", newdn) frappe.db.set(self, "supplier_name", newdn)
def create_onboarding_docs(self, args):
company = frappe.defaults.get_defaults().get('company') or \
frappe.db.get_single_value('Global Defaults', 'default_company')
for i in range(1, args.get('max_count')):
supplier = args.get('supplier_name_' + str(i))
if supplier:
try:
doc = frappe.get_doc({
'doctype': self.doctype,
'supplier_name': supplier,
'supplier_group': _('Local'),
'company': company
}).insert()
if args.get('supplier_email_' + str(i)):
from erpnext.selling.doctype.customer.customer import create_contact
create_contact(supplier, 'Supplier',
doc.name, args.get('supplier_email_' + str(i)))
except frappe.NameError:
pass

View File

@@ -93,5 +93,3 @@ var loadAllStandings = function(frm) {
} }
}); });
}; };

View File

@@ -128,4 +128,3 @@ valid_scorecard = [
"weighting_function":"{total_score} * max( 0, min ( 1 , (12 - {period_number}) / 12) )" "weighting_function":"{total_score} * max( 0, min ( 1 , (12 - {period_number}) / 12) )"
} }
] ]

View File

@@ -109,4 +109,3 @@ def make_supplier_scorecard(source_name, target_doc=None):
}, target_doc, post_process, ignore_permissions=True) }, target_doc, post_process, ignore_permissions=True)
return doc return doc

View File

@@ -13,6 +13,6 @@
"name": "Drop Shipping Format", "name": "Drop Shipping Format",
"owner": "Administrator", "owner": "Administrator",
"print_format_builder": 0, "print_format_builder": 0,
"print_format_type": "Server", "print_format_type": "Jinja",
"standard": "Yes" "standard": "Yes"
} }

View File

@@ -268,4 +268,3 @@ def get_columns(filters):
]) ])
return columns return columns

View File

@@ -102,4 +102,3 @@ def get_linked_material_requests(items):
mr_list.append(material_request) mr_list.append(material_request)
return mr_list return mr_list

View File

@@ -1863,7 +1863,7 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
qty_unchanged = prev_qty == new_qty qty_unchanged = prev_qty == new_qty
uom_unchanged = prev_uom == new_uom uom_unchanged = prev_uom == new_uom
conversion_factor_unchanged = prev_con_fac == new_con_fac conversion_factor_unchanged = prev_con_fac == new_con_fac
date_unchanged = prev_date == new_date if prev_date and new_date else False # in case of delivery note etc date_unchanged = prev_date == getdate(new_date) if prev_date and new_date else False # in case of delivery note etc
if rate_unchanged and qty_unchanged and conversion_factor_unchanged and uom_unchanged and date_unchanged: if rate_unchanged and qty_unchanged and conversion_factor_unchanged and uom_unchanged and date_unchanged:
continue continue

View File

@@ -343,4 +343,3 @@ def create_variant_doc_for_quick_entry(template, args):
variant.name = variant.item_code variant.name = variant.item_code
validate_item_variant_attributes(variant, args) validate_item_variant_attributes(variant, args)
return variant.as_dict() return variant.as_dict()

View File

@@ -526,6 +526,9 @@ def get_filtered_dimensions(doctype, txt, searchfield, start, page_len, filters)
if meta.is_tree: if meta.is_tree:
query_filters.append(['is_group', '=', 0]) query_filters.append(['is_group', '=', 0])
if meta.has_field('disabled'):
query_filters.append(['disabled', '!=', 1])
if meta.has_field('company'): if meta.has_field('company'):
query_filters.append(['company', '=', filters.get('company')]) query_filters.append(['company', '=', filters.get('company')])

View File

@@ -3,7 +3,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe.utils import flt, comma_or, nowdate, getdate from frappe.utils import flt, comma_or, nowdate, getdate, now
from frappe import _ from frappe import _
from frappe.model.document import Document from frappe.model.document import Document
@@ -336,10 +336,14 @@ class StatusUpdater(Document):
target.notify_update() target.notify_update()
def _update_modified(self, args, update_modified): def _update_modified(self, args, update_modified):
args['update_modified'] = '' if not update_modified:
if update_modified: args['update_modified'] = ''
args['update_modified'] = ', modified = now(), modified_by = {0}'\ return
.format(frappe.db.escape(frappe.session.user))
args['update_modified'] = ', modified = {0}, modified_by = {1}'.format(
frappe.db.escape(now()),
frappe.db.escape(frappe.session.user)
)
def update_billing_status_for_zero_amount_refdoc(self, ref_dt): def update_billing_status_for_zero_amount_refdoc(self, ref_dt):
ref_fieldname = frappe.scrub(ref_dt) ref_fieldname = frappe.scrub(ref_dt)

View File

@@ -235,4 +235,3 @@ def _get_employee_from_user(user):
# frappe.db.exists returns a tuple of a tuple # frappe.db.exists returns a tuple of a tuple
return frappe.get_doc('Employee', employee_docname[0][0]) return frappe.get_doc('Employee', employee_docname[0][0])
return None return None

View File

@@ -16,4 +16,3 @@ frappe.query_reports["Campaign Efficiency"] = {
} }
] ]
}; };

View File

@@ -20,5 +20,3 @@ frappe.query_reports["Lead Conversion Time"] = {
}, },
] ]
}; };

View File

@@ -155,4 +155,3 @@ def get_conditions(filters) :
conditions.append(" and `tabLead`.status=%(status)s") conditions.append(" and `tabLead`.status=%(status)s")
return " ".join(conditions) if conditions else "" return " ".join(conditions) if conditions else ""

View File

@@ -316,7 +316,7 @@ def update_party(fullname, company_name=None, mobile_no=None, phone=None):
party = get_party() party = get_party()
party.customer_name = company_name or fullname party.customer_name = company_name or fullname
party.customer_type == "Company" if company_name else "Individual" party.customer_type = "Company" if company_name else "Individual"
contact_name = frappe.db.get_value("Contact", {"email_id": frappe.session.user}) contact_name = frappe.db.get_value("Contact", {"email_id": frappe.session.user})
contact = frappe.get_doc("Contact", contact_name) contact = frappe.get_doc("Contact", contact_name)

View File

@@ -42,7 +42,3 @@ class AssessmentResult(Document):
"student":self.student, "assessment_plan":self.assessment_plan, "docstatus":("!=", 2)}) "student":self.student, "assessment_plan":self.assessment_plan, "docstatus":("!=", 2)})
if assessment_result: if assessment_result:
frappe.throw(_("Assessment Result record {0} already exists.").format(getlink("Assessment Result",assessment_result[0].name))) frappe.throw(_("Assessment Result record {0} already exists.").format(getlink("Assessment Result",assessment_result[0].name)))

View File

@@ -16,4 +16,3 @@ class TestAssessmentResult(unittest.TestCase):
grade = get_grade("_Test Grading Scale", 70) grade = get_grade("_Test Grading Scale", 70)
self.assertEqual("B", grade) self.assertEqual("B", grade)

View File

@@ -39,6 +39,3 @@ class TestCourseEnrollment(unittest.TestCase):
doc = frappe.get_doc("Program Enrollment", entry.name) doc = frappe.get_doc("Program Enrollment", entry.name)
doc.cancel() doc.cancel()
doc.delete() doc.delete()

View File

@@ -47,4 +47,3 @@ class CourseSchedule(Document):
validate_overlap_for(self, "Assessment Plan", "room") validate_overlap_for(self, "Assessment Plan", "room")
validate_overlap_for(self, "Assessment Plan", "supervisor", self.instructor) validate_overlap_for(self, "Assessment Plan", "supervisor", self.instructor)

View File

@@ -174,4 +174,3 @@ def get_students(doctype, txt, searchfield, start, page_len, filters):
tuple(students + ["%%%s%%" % txt, start, page_len] tuple(students + ["%%%s%%" % txt, start, page_len]
) )
) )

View File

@@ -128,4 +128,3 @@ def fetch_students(doctype, txt, searchfield, start, page_len, filters):
order by idx desc, name order by idx desc, name
limit %s, %s""".format(searchfield), limit %s, %s""".format(searchfield),
tuple(["%%%s%%" % txt, "%%%s%%" % txt, start, page_len])) tuple(["%%%s%%" % txt, "%%%s%%" % txt, start, page_len]))

View File

@@ -121,4 +121,3 @@ def get_chart_data(data):
}, },
'type': 'bar' 'type': 'bar'
} }

View File

@@ -350,4 +350,3 @@ def is_sync_complete(shopify_settings, order):
return getdate(shopify_settings.to_date) < getdate(order.get('created_at')) return getdate(shopify_settings.to_date) < getdate(order.get('created_at'))
else: else:
return cstr(order.get('id')) == cstr(shopify_settings.to_order_id) return cstr(order.get('id')) == cstr(shopify_settings.to_order_id)

View File

@@ -1,3 +1,2 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors // Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt // For license information, please see license.txt

View File

@@ -48,13 +48,13 @@
"fieldname": "inpatient_visit_charge", "fieldname": "inpatient_visit_charge",
"fieldtype": "Currency", "fieldtype": "Currency",
"in_list_view": 1, "in_list_view": 1,
"label": "Inpatient Visit Charge Item" "label": "Inpatient Visit Charge"
} }
], ],
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2021-01-22 09:35:26.503443", "modified": "2021-08-17 06:05:02.240812",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Healthcare", "module": "Healthcare",
"name": "Appointment Type Service Item", "name": "Appointment Type Service Item",

View File

@@ -11,7 +11,7 @@ test_dependencies = ['Item']
class TestClinicalProcedure(unittest.TestCase): class TestClinicalProcedure(unittest.TestCase):
def test_procedure_template_item(self): def test_procedure_template_item(self):
patient, medical_department, practitioner = create_healthcare_docs() patient, practitioner = create_healthcare_docs()
procedure_template = create_clinical_procedure_template() procedure_template = create_clinical_procedure_template()
self.assertTrue(frappe.db.exists('Item', procedure_template.item)) self.assertTrue(frappe.db.exists('Item', procedure_template.item))
@@ -20,7 +20,7 @@ class TestClinicalProcedure(unittest.TestCase):
self.assertEqual(frappe.db.get_value('Item', procedure_template.item, 'disabled'), 1) self.assertEqual(frappe.db.get_value('Item', procedure_template.item, 'disabled'), 1)
def test_consumables(self): def test_consumables(self):
patient, medical_department, practitioner = create_healthcare_docs() patient, practitioner = create_healthcare_docs()
procedure_template = create_clinical_procedure_template() procedure_template = create_clinical_procedure_template()
procedure_template.allow_stock_consumption = 1 procedure_template.allow_stock_consumption = 1
consumable = create_consumable() consumable = create_consumable()

View File

@@ -188,4 +188,3 @@ frappe.tour['Clinical Procedure Template'] = [
description: __('You can also set the Medical Department for the template. After saving the document, an Item will automatically be created for billing this Clinical Procedure. You can then use this template while creating Clinical Procedures for Patients. Templates save you from filling up redundant data every single time. You can also create templates for other operations like Lab Tests, Therapy Sessions, etc.') description: __('You can also set the Medical Department for the template. After saving the document, an Item will automatically be created for billing this Clinical Procedure. You can then use this template while creating Clinical Procedures for Patients. Templates save you from filling up redundant data every single time. You can also create templates for other operations like Lab Tests, Therapy Sessions, etc.')
} }
]; ];

View File

@@ -118,4 +118,3 @@ def change_item_code_from_template(item_code, doc):
rename_doc('Item', doc.item_code, item_code, ignore_permissions=True) rename_doc('Item', doc.item_code, item_code, ignore_permissions=True)
frappe.db.set_value('Clinical Procedure Template', doc.name, 'item_code', item_code) frappe.db.set_value('Clinical Procedure Template', doc.name, 'item_code', item_code)
return return

Some files were not shown because too many files have changed in this diff Show More