diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 00000000000..532485f21f9
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,25 @@
+name: Generate Semantic Release
+on:
+ push:
+ branches:
+ - version-13
+jobs:
+ release:
+ name: Release
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout Entire Repository
+ uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+ - name: Setup Node.js v14
+ uses: actions/setup-node@v2
+ with:
+ node-version: 14
+ - name: Setup dependencies
+ run: |
+ npm install @semantic-release/git @semantic-release/exec --no-save
+ - name: Create Release
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: npx semantic-release
\ No newline at end of file
diff --git a/.releaserc b/.releaserc
new file mode 100644
index 00000000000..8a758ed30a6
--- /dev/null
+++ b/.releaserc
@@ -0,0 +1,24 @@
+{
+ "branches": ["version-13"],
+ "plugins": [
+ "@semantic-release/commit-analyzer", {
+ "preset": "angular",
+ "releaseRules": [
+ {"breaking": true, "release": false}
+ ]
+ },
+ "@semantic-release/release-notes-generator",
+ [
+ "@semantic-release/exec", {
+ "prepareCmd": 'sed -ir "s/[0-9]*\.[0-9]*\.[0-9]*/${nextRelease.version}/" erpnext/__init__.py'
+ }
+ ],
+ [
+ "@semantic-release/git", {
+ "assets": ["erpnext/__init__.py"],
+ "message": "chore(release): Bumped to Version ${nextRelease.version}\n\n${nextRelease.notes}"
+ }
+ ],
+ "@semantic-release/github"
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
index 897151a97b7..445378300bb 100644
--- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
@@ -205,10 +205,16 @@ def get_doctypes_with_dimensions():
return frappe.get_hooks("accounting_dimension_doctypes")
-def get_accounting_dimensions(as_list=True):
+def get_accounting_dimensions(as_list=True, filters=None):
+
+ if not filters:
+ filters = {"disabled": 0}
+
if frappe.flags.accounting_dimensions is None:
frappe.flags.accounting_dimensions = frappe.get_all(
- "Accounting Dimension", fields=["label", "fieldname", "disabled", "document_type"]
+ "Accounting Dimension",
+ fields=["label", "fieldname", "disabled", "document_type"],
+ filters=filters,
)
if as_list:
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index bf399d1d1e8..8660c18bf95 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -19,7 +19,6 @@ from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category
)
from erpnext.accounts.party import get_party_account
from erpnext.accounts.utils import (
- check_if_stock_and_account_balance_synced,
get_account_currency,
get_balance_on,
get_stock_accounts,
@@ -88,9 +87,6 @@ class JournalEntry(AccountsController):
self.update_expense_claim()
self.update_inter_company_jv()
self.update_invoice_discounting()
- check_if_stock_and_account_balance_synced(
- self.posting_date, self.company, self.doctype, self.name
- )
def on_cancel(self):
from erpnext.accounts.utils import unlink_ref_doc_from_payment_entries
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
index 907b76915af..b596df92247 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
@@ -350,9 +350,13 @@ class PaymentReconciliation(Document):
)
if self.minimum_invoice_amount:
- condition += " and `{0}` >= {1}".format(dr_or_cr, flt(self.minimum_invoice_amount))
+ condition += " and {dr_or_cr} >= {amount}".format(
+ dr_or_cr=dr_or_cr, amount=flt(self.minimum_invoice_amount)
+ )
if self.maximum_invoice_amount:
- condition += " and `{0}` <= {1}".format(dr_or_cr, flt(self.maximum_invoice_amount))
+ condition += " and {dr_or_cr} <= {amount}".format(
+ dr_or_cr=dr_or_cr, amount=flt(self.maximum_invoice_amount)
+ )
elif get_return_invoices:
condition = " and doc.company = '{0}' ".format(self.company)
@@ -367,15 +371,19 @@ class PaymentReconciliation(Document):
else ""
)
dr_or_cr = (
- "gl.debit_in_account_currency"
+ "debit_in_account_currency"
if erpnext.get_party_account_type(self.party_type) == "Receivable"
- else "gl.credit_in_account_currency"
+ else "credit_in_account_currency"
)
if self.minimum_invoice_amount:
- condition += " and `{0}` >= {1}".format(dr_or_cr, flt(self.minimum_payment_amount))
+ condition += " and gl.{dr_or_cr} >= {amount}".format(
+ dr_or_cr=dr_or_cr, amount=flt(self.minimum_payment_amount)
+ )
if self.maximum_invoice_amount:
- condition += " and `{0}` <= {1}".format(dr_or_cr, flt(self.maximum_payment_amount))
+ condition += " and gl.{dr_or_cr} <= {amount}".format(
+ dr_or_cr=dr_or_cr, amount=flt(self.maximum_payment_amount)
+ )
else:
condition += (
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
index fea55a3f289..01f716daa21 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
@@ -34,8 +34,9 @@ class ProcessStatementOfAccounts(Document):
frappe.throw(_("Customers not selected."))
if self.enable_auto_email:
- self.to_date = self.start_date
- self.from_date = add_months(self.to_date, -1 * self.filter_duration)
+ if self.start_date and getdate(self.start_date) >= getdate(today()):
+ self.to_date = self.start_date
+ self.from_date = add_months(self.to_date, -1 * self.filter_duration)
def get_report_pdf(doc, consolidated=True):
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index 4e4e2154375..4f5640f9cb9 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -30,6 +30,9 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
onload: function() {
this._super();
+ // Ignore linked advances
+ this.frm.ignore_doctypes_on_cancel_all = ['Journal Entry', 'Payment Entry'];
+
if(!this.frm.doc.__islocal) {
// show credit_to in print format
if(!this.frm.doc.supplier && this.frm.doc.credit_to) {
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 8500d57f44b..a14ae251e01 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -801,7 +801,9 @@ class PurchaseInvoice(BuyingController):
if provisional_accounting_for_non_stock_items:
if item.purchase_receipt:
- provisional_account = self.get_company_default("default_provisional_account")
+ provisional_account = frappe.db.get_value(
+ "Purchase Receipt Item", item.pr_detail, "provisional_expense_account"
+ ) or self.get_company_default("default_provisional_account")
purchase_receipt_doc = purchase_receipt_doc_map.get(item.purchase_receipt)
if not purchase_receipt_doc:
@@ -824,7 +826,7 @@ class PurchaseInvoice(BuyingController):
if expense_booked_in_pr:
# Intentionally passing purchase invoice item to handle partial billing
purchase_receipt_doc.add_provisional_gl_entry(
- item, gl_entries, self.posting_date, reverse=1
+ item, gl_entries, self.posting_date, provisional_account, reverse=1
)
if not self.is_internal_transfer():
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index d1543fe10d2..15803b5bfe1 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -1449,7 +1449,8 @@ class TestPurchaseInvoice(unittest.TestCase):
self.assertEqual(payment_entry.taxes[0].allocated_amount, 0)
def test_provisional_accounting_entry(self):
- item = create_item("_Test Non Stock Item", is_stock_item=0)
+ create_item("_Test Non Stock Item", is_stock_item=0)
+
provisional_account = create_account(
account_name="Provision Account",
parent_account="Current Liabilities - _TC",
@@ -1472,6 +1473,8 @@ class TestPurchaseInvoice(unittest.TestCase):
pi.save()
pi.submit()
+ self.assertEquals(pr.items[0].provisional_expense_account, "Provision Account - _TC")
+
# Check GLE for Purchase Invoice
expected_gle = [
["Cost of Goods Sold - _TC", 250, 0, add_days(pr.posting_date, -1)],
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 50c94b419b6..c6a110dcab6 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -34,7 +34,9 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
var me = this;
this._super();
- this.frm.ignore_doctypes_on_cancel_all = ['POS Invoice', 'Timesheet', 'POS Invoice Merge Log', 'POS Closing Entry'];
+ this.frm.ignore_doctypes_on_cancel_all = ['POS Invoice', 'Timesheet', 'POS Invoice Merge Log',
+ 'POS Closing Entry', 'Journal Entry', 'Payment Entry'];
+
if(!this.frm.doc.__islocal && !this.frm.doc.customer && this.frm.doc.debit_to) {
// show debit_to in print format
this.frm.set_df_property("debit_to", "print_hide", 0);
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index da2fe1380e0..13ea13267e1 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -3062,6 +3062,62 @@ class TestSalesInvoice(unittest.TestCase):
si.reload()
self.assertTrue(si.items[0].serial_no)
+ def test_gain_loss_with_advance_entry(self):
+ from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
+
+ unlink_enabled = frappe.db.get_value(
+ "Accounts Settings", "Accounts Settings", "unlink_payment_on_cancel_of_invoice"
+ )
+
+ frappe.db.set_value(
+ "Accounts Settings", "Accounts Settings", "unlink_payment_on_cancel_of_invoice", 1
+ )
+
+ jv = make_journal_entry("_Test Receivable USD - _TC", "_Test Bank - _TC", -7000, save=False)
+
+ jv.accounts[0].exchange_rate = 70
+ jv.accounts[0].credit_in_account_currency = 100
+ jv.accounts[0].party_type = "Customer"
+ jv.accounts[0].party = "_Test Customer USD"
+
+ jv.save()
+ jv.submit()
+
+ si = create_sales_invoice(
+ customer="_Test Customer USD",
+ debit_to="_Test Receivable USD - _TC",
+ currency="USD",
+ conversion_rate=75,
+ do_not_save=1,
+ rate=100,
+ )
+
+ si.append(
+ "advances",
+ {
+ "reference_type": "Journal Entry",
+ "reference_name": jv.name,
+ "reference_row": jv.accounts[0].name,
+ "advance_amount": 100,
+ "allocated_amount": 100,
+ "ref_exchange_rate": 70,
+ },
+ )
+ si.save()
+ si.submit()
+
+ expected_gle = [
+ ["_Test Receivable USD - _TC", 7500.0, 500],
+ ["Exchange Gain/Loss - _TC", 500.0, 0.0],
+ ["Sales - _TC", 0.0, 7500.0],
+ ]
+
+ check_gl_entries(self, si.name, expected_gle, nowdate())
+
+ frappe.db.set_value(
+ "Accounts Settings", "Accounts Settings", "unlink_payment_on_cancel_of_invoice", unlink_enabled
+ )
+
def get_sales_invoice_for_e_invoice():
si = make_sales_invoice_for_ewaybill()
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index b58b53c1cb6..0d1d0dc031f 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -19,10 +19,6 @@ from erpnext.stock import get_warehouse_account_map
from erpnext.stock.utils import get_stock_value_on
-class StockValueAndAccountBalanceOutOfSync(frappe.ValidationError):
- pass
-
-
class FiscalYearError(frappe.ValidationError):
pass
@@ -1247,47 +1243,6 @@ def compare_existing_and_expected_gle(existing_gle, expected_gle, precision):
return matched
-def check_if_stock_and_account_balance_synced(
- posting_date, company, voucher_type=None, voucher_no=None
-):
- if not cint(erpnext.is_perpetual_inventory_enabled(company)):
- return
-
- accounts = get_stock_accounts(company, voucher_type, voucher_no)
- stock_adjustment_account = frappe.db.get_value("Company", company, "stock_adjustment_account")
-
- for account in accounts:
- account_bal, stock_bal, warehouse_list = get_stock_and_account_balance(
- account, posting_date, company
- )
-
- if abs(account_bal - stock_bal) > 0.1:
- precision = get_field_precision(
- frappe.get_meta("GL Entry").get_field("debit"),
- currency=frappe.get_cached_value("Company", company, "default_currency"),
- )
-
- diff = flt(stock_bal - account_bal, precision)
-
- error_reason = _(
- "Stock Value ({0}) and Account Balance ({1}) are out of sync for account {2} and it's linked warehouses as on {3}."
- ).format(stock_bal, account_bal, frappe.bold(account), posting_date)
- error_resolution = _("Please create an adjustment Journal Entry for amount {0} on {1}").format(
- frappe.bold(diff), frappe.bold(posting_date)
- )
-
- frappe.msgprint(
- msg="""{0}
{1}
""".format(error_reason, error_resolution),
- raise_exception=StockValueAndAccountBalanceOutOfSync,
- title=_("Values Out Of Sync"),
- primary_action={
- "label": _("Make Journal Entry"),
- "client_action": "erpnext.route_to_adjustment_jv",
- "args": get_journal_entry(account, stock_adjustment_account, diff),
- },
- )
-
-
def get_stock_accounts(company, voucher_type=None, voucher_no=None):
stock_accounts = [
d.name
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index a2ad2cf5bb2..21d90b5e48a 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -364,7 +364,7 @@ class Asset(AccountsController):
if has_pro_rata and n == 0:
# For first entry of monthly depr
if r == 0:
- days_until_first_depr = date_diff(monthly_schedule_date, self.available_for_use_date)
+ days_until_first_depr = date_diff(monthly_schedule_date, self.available_for_use_date) + 1
per_day_amt = depreciation_amount / days
depreciation_amount_for_current_month = per_day_amt * days_until_first_depr
depreciation_amount -= depreciation_amount_for_current_month
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 36887f444c8..49196dfe22e 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -2000,12 +2000,13 @@ def get_advance_journal_entries(
reference_condition = " and (" + " or ".join(conditions) + ")" if conditions else ""
+ # nosemgrep
journal_entries = frappe.db.sql(
"""
select
"Journal Entry" as reference_type, t1.name as reference_name,
t1.remark as remarks, t2.{0} as amount, t2.name as reference_row,
- t2.reference_name as against_order
+ t2.reference_name as against_order, t2.exchange_rate
from
`tabJournal Entry` t1, `tabJournal Entry Account` t2
where
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index 2139260df60..ff739e9d72b 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -462,6 +462,7 @@ class ProductionPlan(Document):
work_order_data = {
"wip_warehouse": default_warehouses.get("wip_warehouse"),
"fg_warehouse": default_warehouses.get("fg_warehouse"),
+ "company": self.get("company"),
}
self.prepare_data_for_sub_assembly_items(row, work_order_data)
@@ -499,6 +500,7 @@ class ProductionPlan(Document):
for supplier, po_list in subcontracted_po.items():
po = frappe.new_doc("Purchase Order")
+ po.company = self.company
po.supplier = supplier
po.schedule_date = getdate(po_list[0].schedule_date) if po_list[0].schedule_date else nowdate()
po.is_subcontracted = "Yes"
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 98e07783c11..b2d0871a17c 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -350,6 +350,7 @@ erpnext.patches.v13_0.enable_provisional_accounting
erpnext.patches.v13_0.update_disbursement_account
erpnext.patches.v13_0.update_reserved_qty_closed_wo
erpnext.patches.v13_0.amazon_mws_deprecation_warning
+erpnext.patches.v13_0.datev_deprecation_warning
erpnext.patches.v13_0.set_work_order_qty_in_so_from_mr
erpnext.patches.v13_0.update_accounts_in_loan_docs
erpnext.patches.v13_0.remove_unknown_links_to_prod_plan_items # 24-03-2022
diff --git a/erpnext/patches/v13_0/datev_deprecation_warning.py b/erpnext/patches/v13_0/datev_deprecation_warning.py
new file mode 100644
index 00000000000..bf58440a610
--- /dev/null
+++ b/erpnext/patches/v13_0/datev_deprecation_warning.py
@@ -0,0 +1,9 @@
+import click
+
+
+def execute():
+ click.secho(
+ "DATEV reports are moved to a separate app and will be removed from ERPNext in version-14.\n"
+ "Please install the app to continue using them: https://github.com/alyf-de/erpnext_datev",
+ fg="yellow",
+ )
diff --git a/erpnext/patches/v13_0/patch_to_fix_reverse_linking_in_additional_salary_encashment_and_incentive.py b/erpnext/patches/v13_0/patch_to_fix_reverse_linking_in_additional_salary_encashment_and_incentive.py
index edd0a9706b9..45acf49205b 100644
--- a/erpnext/patches/v13_0/patch_to_fix_reverse_linking_in_additional_salary_encashment_and_incentive.py
+++ b/erpnext/patches/v13_0/patch_to_fix_reverse_linking_in_additional_salary_encashment_and_incentive.py
@@ -10,54 +10,58 @@ def execute():
frappe.reload_doc("hr", "doctype", "Leave Encashment")
- additional_salaries = frappe.get_all(
- "Additional Salary",
- fields=["name", "salary_slip", "type", "salary_component"],
- filters={"salary_slip": ["!=", ""]},
- group_by="salary_slip",
- )
- leave_encashments = frappe.get_all(
- "Leave Encashment",
- fields=["name", "additional_salary"],
- filters={"additional_salary": ["!=", ""]},
- )
- employee_incentives = frappe.get_all(
- "Employee Incentive",
- fields=["name", "additional_salary"],
- filters={"additional_salary": ["!=", ""]},
- )
-
- for incentive in employee_incentives:
- frappe.db.sql(
- """ UPDATE `tabAdditional Salary`
- SET ref_doctype = 'Employee Incentive', ref_docname = %s
- WHERE name = %s
- """,
- (incentive["name"], incentive["additional_salary"]),
+ if frappe.db.has_column("Leave Encashment", "additional_salary"):
+ leave_encashments = frappe.get_all(
+ "Leave Encashment",
+ fields=["name", "additional_salary"],
+ filters={"additional_salary": ["!=", ""]},
)
-
- for leave_encashment in leave_encashments:
- frappe.db.sql(
- """ UPDATE `tabAdditional Salary`
- SET ref_doctype = 'Leave Encashment', ref_docname = %s
- WHERE name = %s
- """,
- (leave_encashment["name"], leave_encashment["additional_salary"]),
- )
-
- salary_slips = [sal["salary_slip"] for sal in additional_salaries]
-
- for salary in additional_salaries:
- comp_type = "earnings" if salary["type"] == "Earning" else "deductions"
- if salary["salary_slip"] and salary_slips.count(salary["salary_slip"]) == 1:
+ for leave_encashment in leave_encashments:
frappe.db.sql(
- """
- UPDATE `tabSalary Detail`
- SET additional_salary = %s
- WHERE parenttype = 'Salary Slip'
- and parentfield = %s
- and parent = %s
- and salary_component = %s
+ """ UPDATE `tabAdditional Salary`
+ SET ref_doctype = 'Leave Encashment', ref_docname = %s
+ WHERE name = %s
""",
- (salary["name"], comp_type, salary["salary_slip"], salary["salary_component"]),
+ (leave_encashment["name"], leave_encashment["additional_salary"]),
)
+
+ if frappe.db.has_column("Employee Incentive", "additional_salary"):
+ employee_incentives = frappe.get_all(
+ "Employee Incentive",
+ fields=["name", "additional_salary"],
+ filters={"additional_salary": ["!=", ""]},
+ )
+
+ for incentive in employee_incentives:
+ frappe.db.sql(
+ """ UPDATE `tabAdditional Salary`
+ SET ref_doctype = 'Employee Incentive', ref_docname = %s
+ WHERE name = %s
+ """,
+ (incentive["name"], incentive["additional_salary"]),
+ )
+
+ if frappe.db.has_column("Additional Salary", "salary_slip"):
+ additional_salaries = frappe.get_all(
+ "Additional Salary",
+ fields=["name", "salary_slip", "type", "salary_component"],
+ filters={"salary_slip": ["!=", ""]},
+ group_by="salary_slip",
+ )
+
+ salary_slips = [sal["salary_slip"] for sal in additional_salaries]
+
+ for salary in additional_salaries:
+ comp_type = "earnings" if salary["type"] == "Earning" else "deductions"
+ if salary["salary_slip"] and salary_slips.count(salary["salary_slip"]) == 1:
+ frappe.db.sql(
+ """
+ UPDATE `tabSalary Detail`
+ SET additional_salary = %s
+ WHERE parenttype = 'Salary Slip'
+ and parentfield = %s
+ and parent = %s
+ and salary_component = %s
+ """,
+ (salary["name"], comp_type, salary["salary_slip"], salary["salary_component"]),
+ )
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 9ed78a7fb69..fdc129b9116 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -1500,6 +1500,11 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
return;
}
+ // Target doc created from a mapped doc
+ if (this.frm.doc.__onload && this.frm.doc.__onload.ignore_price_list) {
+ return;
+ }
+
return this.frm.call({
method: "erpnext.accounts.doctype.pricing_rule.pricing_rule.apply_pricing_rule",
args: { args: args, doc: me.frm.doc },
@@ -1616,7 +1621,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
me.remove_pricing_rule(frappe.get_doc(d.doctype, d.name));
}
- if (d.free_item_data) {
+ if (d.free_item_data.length > 0) {
me.apply_product_discount(d);
}
diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js
index dd185fc6636..0de5b2d5a32 100644
--- a/erpnext/setup/doctype/company/company.js
+++ b/erpnext/setup/doctype/company/company.js
@@ -233,7 +233,8 @@ erpnext.company.setup_queries = function(frm) {
["expenses_included_in_asset_valuation", {"account_type": "Expenses Included In Asset Valuation"}],
["capital_work_in_progress_account", {"account_type": "Capital Work in Progress"}],
["asset_received_but_not_billed", {"account_type": "Asset Received But Not Billed"}],
- ["unrealized_profit_loss_account", {"root_type": ["in", ["Liability", "Asset"]]}]
+ ["unrealized_profit_loss_account", {"root_type": ["in", ["Liability", "Asset"]]}],
+ ["default_provisional_account", {"root_type": ["in", ["Liability", "Asset"]]}]
], function(i, v) {
erpnext.company.set_custom_query(frm, v);
});
diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js
index 8206e095797..de6316cc05d 100644
--- a/erpnext/stock/doctype/item/item.js
+++ b/erpnext/stock/doctype/item/item.js
@@ -377,6 +377,17 @@ $.extend(erpnext.item, {
}
}
+ frm.set_query('default_provisional_account', 'item_defaults', (doc, cdt, cdn) => {
+ let row = locals[cdt][cdn];
+ return {
+ filters: {
+ "company": row.company,
+ "root_type": ["in", ["Liability", "Asset"]],
+ "is_group": 0
+ }
+ };
+ });
+
},
make_dashboard: function(frm) {
diff --git a/erpnext/stock/doctype/item_default/item_default.json b/erpnext/stock/doctype/item_default/item_default.json
index bc171604f43..042d398256a 100644
--- a/erpnext/stock/doctype/item_default/item_default.json
+++ b/erpnext/stock/doctype/item_default/item_default.json
@@ -15,6 +15,7 @@
"default_supplier",
"column_break_8",
"expense_account",
+ "default_provisional_account",
"selling_defaults",
"selling_cost_center",
"column_break_12",
@@ -101,11 +102,17 @@
"fieldtype": "Link",
"label": "Default Discount Account",
"options": "Account"
+ },
+ {
+ "fieldname": "default_provisional_account",
+ "fieldtype": "Link",
+ "label": "Default Provisional Account",
+ "options": "Account"
}
],
"istable": 1,
"links": [],
- "modified": "2021-07-13 01:26:03.860065",
+ "modified": "2022-04-10 20:18:54.148195",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item Default",
@@ -114,5 +121,6 @@
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
+ "states": [],
"track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
index 6d4b4a19bd2..7c6189b1eb1 100755
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
@@ -106,8 +106,6 @@
"terms",
"bill_no",
"bill_date",
- "accounting_details_section",
- "provisional_expense_account",
"more_info",
"project",
"status",
@@ -1146,26 +1144,13 @@
"label": "Represents Company",
"options": "Company",
"read_only": 1
- },
- {
- "collapsible": 1,
- "fieldname": "accounting_details_section",
- "fieldtype": "Section Break",
- "label": "Accounting Details"
- },
- {
- "fieldname": "provisional_expense_account",
- "fieldtype": "Link",
- "hidden": 1,
- "label": "Provisional Expense Account",
- "options": "Account"
}
],
"icon": "fa fa-truck",
"idx": 261,
"is_submittable": 1,
"links": [],
- "modified": "2022-03-10 11:40:52.690984",
+ "modified": "2022-04-10 22:50:37.761362",
"modified_by": "Administrator",
"module": "Stock",
"name": "Purchase Receipt",
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index 37074a2f000..db94beccbcf 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -146,10 +146,13 @@ class PurchaseReceipt(BuyingController):
)
)
- if provisional_accounting_for_non_stock_items:
- default_provisional_account = self.get_company_default("default_provisional_account")
- if not self.provisional_expense_account:
- self.provisional_expense_account = default_provisional_account
+ if not provisional_accounting_for_non_stock_items:
+ return
+
+ default_provisional_account = self.get_company_default("default_provisional_account")
+ for item in self.get("items"):
+ if not item.get("provisional_expense_account"):
+ item.provisional_expense_account = default_provisional_account
def validate_with_previous_doc(self):
super(PurchaseReceipt, self).validate_with_previous_doc(
@@ -466,7 +469,9 @@ class PurchaseReceipt(BuyingController):
and flt(d.qty)
and provisional_accounting_for_non_stock_items
):
- self.add_provisional_gl_entry(d, gl_entries, self.posting_date)
+ self.add_provisional_gl_entry(
+ d, gl_entries, self.posting_date, d.get("provisional_expense_account")
+ )
if warehouse_with_no_account:
frappe.msgprint(
@@ -475,9 +480,10 @@ class PurchaseReceipt(BuyingController):
+ "\n".join(warehouse_with_no_account)
)
- def add_provisional_gl_entry(self, item, gl_entries, posting_date, reverse=0):
- provisional_expense_account = self.get("provisional_expense_account")
- credit_currency = get_account_currency(provisional_expense_account)
+ def add_provisional_gl_entry(
+ self, item, gl_entries, posting_date, provisional_account, reverse=0
+ ):
+ credit_currency = get_account_currency(provisional_account)
debit_currency = get_account_currency(item.expense_account)
expense_account = item.expense_account
remarks = self.get("remarks") or _("Accounting Entry for Service")
@@ -491,7 +497,7 @@ class PurchaseReceipt(BuyingController):
self.add_gl_entry(
gl_entries=gl_entries,
- account=provisional_expense_account,
+ account=provisional_account,
cost_center=item.cost_center,
debit=0.0,
credit=multiplication_factor * item.amount,
@@ -511,7 +517,7 @@ class PurchaseReceipt(BuyingController):
debit=multiplication_factor * item.amount,
credit=0.0,
remarks=remarks,
- against_account=provisional_expense_account,
+ against_account=provisional_account,
account_currency=debit_currency,
project=item.project,
voucher_detail_no=item.name,
diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
index e5994b2dd48..aa217441c0b 100644
--- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
+++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
@@ -96,7 +96,6 @@
"include_exploded_items",
"batch_no",
"rejected_serial_no",
- "expense_account",
"item_tax_rate",
"item_weight_details",
"weight_per_unit",
@@ -107,6 +106,10 @@
"manufacturer",
"column_break_16",
"manufacturer_part_no",
+ "accounting_details_section",
+ "expense_account",
+ "column_break_102",
+ "provisional_expense_account",
"accounting_dimensions_section",
"project",
"dimension_col_break",
@@ -971,12 +974,27 @@
"label": "Product Bundle",
"options": "Product Bundle",
"read_only": 1
+ },
+ {
+ "fieldname": "provisional_expense_account",
+ "fieldtype": "Link",
+ "label": "Provisional Expense Account",
+ "options": "Account"
+ },
+ {
+ "fieldname": "accounting_details_section",
+ "fieldtype": "Section Break",
+ "label": "Accounting Details"
+ },
+ {
+ "fieldname": "column_break_102",
+ "fieldtype": "Column Break"
}
],
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2022-02-01 11:32:27.980524",
+ "modified": "2022-04-11 13:07:32.061402",
"modified_by": "Administrator",
"module": "Stock",
"name": "Purchase Receipt Item",
diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
index 508f26b5f1d..173b9aa21e5 100644
--- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
+++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
@@ -4,15 +4,12 @@
import frappe
from frappe import _
from frappe.model.document import Document
-from frappe.utils import cint, get_link_to_form, get_weekday, now, nowtime, today
+from frappe.utils import cint, get_link_to_form, get_weekday, now, nowtime
from frappe.utils.user import get_users_with_role
from rq.timeouts import JobTimeoutException
import erpnext
-from erpnext.accounts.utils import (
- check_if_stock_and_account_balance_synced,
- update_gl_entries_after,
-)
+from erpnext.accounts.utils import update_gl_entries_after
from erpnext.stock.stock_ledger import get_items_to_be_repost, repost_future_sle
@@ -224,6 +221,10 @@ def notify_error_to_stock_managers(doc, traceback):
def repost_entries():
+ """
+ Reposts 'Repost Item Valuation' entries in queue.
+ Called hourly via hooks.py.
+ """
if not in_configured_timeslot():
return
@@ -239,9 +240,6 @@ def repost_entries():
if riv_entries:
return
- for d in frappe.get_all("Company", filters={"enable_perpetual_inventory": 1}):
- check_if_stock_and_account_balance_synced(today(), d.name)
-
def get_repost_item_valuation_entries():
return frappe.db.sql(
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index 19680f6286e..384dd7d94f4 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -335,6 +335,7 @@ def get_basic_details(args, item, overwrite_warehouse=True):
"expense_account": expense_account
or get_default_expense_account(args, item_defaults, item_group_defaults, brand_defaults),
"discount_account": get_default_discount_account(args, item_defaults),
+ "provisional_expense_account": get_provisional_account(args, item_defaults),
"cost_center": get_default_cost_center(
args, item_defaults, item_group_defaults, brand_defaults
),
@@ -689,6 +690,10 @@ def get_default_expense_account(args, item, item_group, brand):
)
+def get_provisional_account(args, item):
+ return item.get("default_provisional_account") or args.default_provisional_account
+
+
def get_default_discount_account(args, item):
return item.get("default_discount_account") or args.discount_account
diff --git a/erpnext/translations/fr.csv b/erpnext/translations/fr.csv
index 90456c5c4ee..03e8366a265 100644
--- a/erpnext/translations/fr.csv
+++ b/erpnext/translations/fr.csv
@@ -271,7 +271,7 @@ Assessment Report,Rapport d'Évaluation,
Assessment Reports,Rapports d'évaluation,
Assessment Result,Résultat de l'Évaluation,
Assessment Result record {0} already exists.,Le Résultat d'Évaluation {0} existe déjà.,
-Asset,Atout,
+Asset,Actif - Immo.,
Asset Category,Catégorie d'Actif,
Asset Category is mandatory for Fixed Asset item,Catégorie d'Actif est obligatoire pour l'article Immobilisé,
Asset Maintenance,Maintenance des actifs,
@@ -3037,6 +3037,7 @@ To Date must be greater than From Date,La date de fin doit être supérieure à
To Date should be within the Fiscal Year. Assuming To Date = {0},La Date Finale doit être dans l'exercice. En supposant Date Finale = {0},
To Datetime,À la Date,
To Deliver,À Livrer,
+{} To Deliver,{} à livrer
To Deliver and Bill,À Livrer et Facturer,
To Fiscal Year,À l'année fiscale,
To GSTIN,GSTIN (Destination),
@@ -9872,3 +9873,4 @@ Show Barcode Field in Stock Transactions,Afficher le champ Code Barre dans les t
Convert Item Description to Clean HTML in Transactions,Convertir les descriptions d'articles en HTML valide lors des transactions
Have Default Naming Series for Batch ID?,Nom de série par défaut pour les Lots ou Séries
"The percentage you are allowed to transfer more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed transfer 110 units","Le pourcentage de quantité que vous pourrez réceptionner en plus de la quantité commandée. Par exemple, vous avez commandé 100 unités, votre pourcentage de dépassement est de 10%, vous pourrez réceptionner 110 unités"
+Unit Of Measure (UOM),Unité de mesure (UDM),
diff --git a/erpnext/www/shop-by-category/__init__.py b/erpnext/www/shop-by-category/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d