Merge branch 'develop' of https://github.com/frappe/erpnext into opening_entry
This commit is contained in:
commit
91f7b0bbd6
1
.github/workflows/server-tests-mariadb.yml
vendored
1
.github/workflows/server-tests-mariadb.yml
vendored
@ -7,7 +7,6 @@ on:
|
|||||||
- '**.css'
|
- '**.css'
|
||||||
- '**.md'
|
- '**.md'
|
||||||
- '**.html'
|
- '**.html'
|
||||||
- '**.csv'
|
|
||||||
push:
|
push:
|
||||||
branches: [ develop ]
|
branches: [ develop ]
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
|
|||||||
@ -217,7 +217,6 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
frm.toggle_display("set_exchange_gain_loss",
|
frm.toggle_display("set_exchange_gain_loss",
|
||||||
frm.doc.paid_amount && frm.doc.received_amount && frm.doc.difference_amount);
|
frm.doc.paid_amount && frm.doc.received_amount && frm.doc.difference_amount);
|
||||||
|
|
||||||
frm.refresh_fields();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
set_dynamic_labels: function(frm) {
|
set_dynamic_labels: function(frm) {
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<h2 class="text-center">{{ _("STATEMENTS OF ACCOUNTS") }}</h2>
|
<h2 class="text-center">{{ _("STATEMENTS OF ACCOUNTS") }}</h2>
|
||||||
<div>
|
<div>
|
||||||
<h5 style="float: left;">{{ _("Customer: ") }} <b>{{filters.party[0] }}</b></h5>
|
<h5 style="float: left;">{{ _("Customer: ") }} <b>{{filters.party_name[0] }}</b></h5>
|
||||||
<h5 style="float: right;">
|
<h5 style="float: right;">
|
||||||
{{ _("Date: ") }}
|
{{ _("Date: ") }}
|
||||||
<b>{{ frappe.format(filters.from_date, 'Date')}}
|
<b>{{ frappe.format(filters.from_date, 'Date')}}
|
||||||
|
|||||||
@ -24,7 +24,7 @@ from erpnext.accounts.report.general_ledger.general_ledger import execute as get
|
|||||||
class ProcessStatementOfAccounts(Document):
|
class ProcessStatementOfAccounts(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
if not self.subject:
|
if not self.subject:
|
||||||
self.subject = "Statement Of Accounts for {{ customer.name }}"
|
self.subject = "Statement Of Accounts for {{ customer.customer_name }}"
|
||||||
if not self.body:
|
if not self.body:
|
||||||
self.body = "Hello {{ customer.name }},<br>PFA your Statement Of Accounts from {{ doc.from_date }} to {{ doc.to_date }}."
|
self.body = "Hello {{ customer.name }},<br>PFA your Statement Of Accounts from {{ doc.from_date }} to {{ doc.to_date }}."
|
||||||
|
|
||||||
@ -87,6 +87,7 @@ def get_report_pdf(doc, consolidated=True):
|
|||||||
"account": [doc.account] if doc.account else None,
|
"account": [doc.account] if doc.account else None,
|
||||||
"party_type": "Customer",
|
"party_type": "Customer",
|
||||||
"party": [entry.customer],
|
"party": [entry.customer],
|
||||||
|
"party_name": [entry.customer_name] if entry.customer_name else None,
|
||||||
"presentation_currency": presentation_currency,
|
"presentation_currency": presentation_currency,
|
||||||
"group_by": doc.group_by,
|
"group_by": doc.group_by,
|
||||||
"currency": doc.currency,
|
"currency": doc.currency,
|
||||||
@ -156,7 +157,7 @@ def get_customers_based_on_territory_or_customer_group(customer_collection, coll
|
|||||||
]
|
]
|
||||||
return frappe.get_list(
|
return frappe.get_list(
|
||||||
"Customer",
|
"Customer",
|
||||||
fields=["name", "email_id"],
|
fields=["name", "customer_name", "email_id"],
|
||||||
filters=[[fields_dict[customer_collection], "IN", selected]],
|
filters=[[fields_dict[customer_collection], "IN", selected]],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -179,7 +180,7 @@ def get_customers_based_on_sales_person(sales_person):
|
|||||||
if sales_person_records.get("Customer"):
|
if sales_person_records.get("Customer"):
|
||||||
return frappe.get_list(
|
return frappe.get_list(
|
||||||
"Customer",
|
"Customer",
|
||||||
fields=["name", "email_id"],
|
fields=["name", "customer_name", "email_id"],
|
||||||
filters=[["name", "in", list(sales_person_records["Customer"])]],
|
filters=[["name", "in", list(sales_person_records["Customer"])]],
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -228,7 +229,7 @@ def fetch_customers(customer_collection, collection_name, primary_mandatory):
|
|||||||
if customer_collection == "Sales Partner":
|
if customer_collection == "Sales Partner":
|
||||||
customers = frappe.get_list(
|
customers = frappe.get_list(
|
||||||
"Customer",
|
"Customer",
|
||||||
fields=["name", "email_id"],
|
fields=["name", "customer_name", "email_id"],
|
||||||
filters=[["default_sales_partner", "=", collection_name]],
|
filters=[["default_sales_partner", "=", collection_name]],
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -245,7 +246,12 @@ def fetch_customers(customer_collection, collection_name, primary_mandatory):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
customer_list.append(
|
customer_list.append(
|
||||||
{"name": customer.name, "primary_email": primary_email, "billing_email": billing_email}
|
{
|
||||||
|
"name": customer.name,
|
||||||
|
"customer_name": customer.customer_name,
|
||||||
|
"primary_email": primary_email,
|
||||||
|
"billing_email": billing_email,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
return customer_list
|
return customer_list
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"actions": [],
|
"actions": [],
|
||||||
"allow_workflow": 1,
|
|
||||||
"creation": "2020-08-03 16:35:21.852178",
|
"creation": "2020-08-03 16:35:21.852178",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
"field_order": [
|
"field_order": [
|
||||||
"customer",
|
"customer",
|
||||||
|
"customer_name",
|
||||||
"billing_email",
|
"billing_email",
|
||||||
"primary_email"
|
"primary_email"
|
||||||
],
|
],
|
||||||
@ -30,11 +30,18 @@
|
|||||||
"fieldtype": "Read Only",
|
"fieldtype": "Read Only",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Billing Email"
|
"label": "Billing Email"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fetch_from": "customer.customer_name",
|
||||||
|
"fieldname": "customer_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Customer Name",
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-08-03 22:55:38.875601",
|
"modified": "2023-03-13 00:12:34.508086",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Process Statement Of Accounts Customer",
|
"name": "Process Statement Of Accounts Customer",
|
||||||
@ -43,5 +50,6 @@
|
|||||||
"quick_entry": 1,
|
"quick_entry": 1,
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
|
"states": [],
|
||||||
"track_changes": 1
|
"track_changes": 1
|
||||||
}
|
}
|
||||||
@ -32,9 +32,6 @@
|
|||||||
"cost_center",
|
"cost_center",
|
||||||
"dimension_col_break",
|
"dimension_col_break",
|
||||||
"project",
|
"project",
|
||||||
"column_break_27",
|
|
||||||
"campaign",
|
|
||||||
"source",
|
|
||||||
"currency_and_price_list",
|
"currency_and_price_list",
|
||||||
"currency",
|
"currency",
|
||||||
"conversion_rate",
|
"conversion_rate",
|
||||||
@ -203,7 +200,9 @@
|
|||||||
"more_information",
|
"more_information",
|
||||||
"status",
|
"status",
|
||||||
"inter_company_invoice_reference",
|
"inter_company_invoice_reference",
|
||||||
|
"campaign",
|
||||||
"represents_company",
|
"represents_company",
|
||||||
|
"source",
|
||||||
"customer_group",
|
"customer_group",
|
||||||
"col_break23",
|
"col_break23",
|
||||||
"is_internal_customer",
|
"is_internal_customer",
|
||||||
@ -2083,10 +2082,6 @@
|
|||||||
"fieldname": "company_addr_col_break",
|
"fieldname": "company_addr_col_break",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "column_break_27",
|
|
||||||
"fieldtype": "Column Break"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"fieldname": "column_break_52",
|
"fieldname": "column_break_52",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
@ -2143,11 +2138,10 @@
|
|||||||
"link_fieldname": "consolidated_invoice"
|
"link_fieldname": "consolidated_invoice"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"modified": "2023-01-28 19:45:47.538163",
|
"modified": "2023-03-13 11:43:15.883055",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Sales Invoice",
|
"name": "Sales Invoice",
|
||||||
"name_case": "Title Case",
|
|
||||||
"naming_rule": "By \"Naming Series\" field",
|
"naming_rule": "By \"Naming Series\" field",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
|
|||||||
@ -266,16 +266,16 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
"_Test Account Education Cess - _TC": [3, 1618, 0.06, 32.36],
|
"_Test Account Education Cess - _TC": [3, 1618, 0.06, 32.36],
|
||||||
"_Test Account S&H Education Cess - _TC": [1.5, 1619.5, 0.03, 32.39],
|
"_Test Account S&H Education Cess - _TC": [1.5, 1619.5, 0.03, 32.39],
|
||||||
"_Test Account CST - _TC": [32.5, 1652, 0.65, 33.04],
|
"_Test Account CST - _TC": [32.5, 1652, 0.65, 33.04],
|
||||||
"_Test Account VAT - _TC": [156.5, 1808.5, 3.13, 36.17],
|
"_Test Account VAT - _TC": [156.0, 1808.0, 3.12, 36.16],
|
||||||
"_Test Account Discount - _TC": [-181.0, 1627.5, -3.62, 32.55],
|
"_Test Account Discount - _TC": [-181.0, 1627.0, -3.62, 32.54],
|
||||||
}
|
}
|
||||||
|
|
||||||
for d in si.get("taxes"):
|
for d in si.get("taxes"):
|
||||||
for i, k in enumerate(expected_values["keys"]):
|
for i, k in enumerate(expected_values["keys"]):
|
||||||
self.assertEqual(d.get(k), expected_values[d.account_head][i])
|
self.assertEqual(d.get(k), expected_values[d.account_head][i])
|
||||||
|
|
||||||
self.assertEqual(si.base_grand_total, 1627.5)
|
self.assertEqual(si.base_grand_total, 1627.0)
|
||||||
self.assertEqual(si.grand_total, 32.55)
|
self.assertEqual(si.grand_total, 32.54)
|
||||||
|
|
||||||
def test_sales_invoice_with_discount_and_inclusive_tax(self):
|
def test_sales_invoice_with_discount_and_inclusive_tax(self):
|
||||||
si = create_sales_invoice(qty=100, rate=50, do_not_save=True)
|
si = create_sales_invoice(qty=100, rate=50, do_not_save=True)
|
||||||
@ -401,10 +401,10 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
"_Test Account S&H Education Cess - _TC": [1.4, 1.30, 1297.67],
|
"_Test Account S&H Education Cess - _TC": [1.4, 1.30, 1297.67],
|
||||||
"_Test Account CST - _TC": [27.88, 25.95, 1323.62],
|
"_Test Account CST - _TC": [27.88, 25.95, 1323.62],
|
||||||
"_Test Account VAT - _TC": [156.25, 145.43, 1469.05],
|
"_Test Account VAT - _TC": [156.25, 145.43, 1469.05],
|
||||||
"_Test Account Customs Duty - _TC": [125, 116.35, 1585.40],
|
"_Test Account Customs Duty - _TC": [125, 116.34, 1585.39],
|
||||||
"_Test Account Shipping Charges - _TC": [100, 100, 1685.40],
|
"_Test Account Shipping Charges - _TC": [100, 100, 1685.39],
|
||||||
"_Test Account Discount - _TC": [-180.33, -168.54, 1516.86],
|
"_Test Account Discount - _TC": [-180.33, -168.54, 1516.85],
|
||||||
"_Test Account Service Tax - _TC": [-18.03, -16.85, 1500.01],
|
"_Test Account Service Tax - _TC": [-18.03, -16.85, 1500.00],
|
||||||
}
|
}
|
||||||
|
|
||||||
for d in si.get("taxes"):
|
for d in si.get("taxes"):
|
||||||
@ -413,7 +413,7 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertEqual(si.base_grand_total, 1500)
|
self.assertEqual(si.base_grand_total, 1500)
|
||||||
self.assertEqual(si.grand_total, 1500)
|
self.assertEqual(si.grand_total, 1500)
|
||||||
self.assertEqual(si.rounding_adjustment, -0.01)
|
self.assertEqual(si.rounding_adjustment, 0.0)
|
||||||
|
|
||||||
def test_discount_amount_gl_entry(self):
|
def test_discount_amount_gl_entry(self):
|
||||||
frappe.db.set_value("Company", "_Test Company", "round_off_account", "Round Off - _TC")
|
frappe.db.set_value("Company", "_Test Company", "round_off_account", "Round Off - _TC")
|
||||||
@ -454,7 +454,7 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
[test_records[3]["taxes"][2]["account_head"], 0.0, 1.30],
|
[test_records[3]["taxes"][2]["account_head"], 0.0, 1.30],
|
||||||
[test_records[3]["taxes"][3]["account_head"], 0.0, 25.95],
|
[test_records[3]["taxes"][3]["account_head"], 0.0, 25.95],
|
||||||
[test_records[3]["taxes"][4]["account_head"], 0.0, 145.43],
|
[test_records[3]["taxes"][4]["account_head"], 0.0, 145.43],
|
||||||
[test_records[3]["taxes"][5]["account_head"], 0.0, 116.35],
|
[test_records[3]["taxes"][5]["account_head"], 0.0, 116.34],
|
||||||
[test_records[3]["taxes"][6]["account_head"], 0.0, 100],
|
[test_records[3]["taxes"][6]["account_head"], 0.0, 100],
|
||||||
[test_records[3]["taxes"][7]["account_head"], 168.54, 0.0],
|
[test_records[3]["taxes"][7]["account_head"], 168.54, 0.0],
|
||||||
["_Test Account Service Tax - _TC", 16.85, 0.0],
|
["_Test Account Service Tax - _TC", 16.85, 0.0],
|
||||||
@ -1614,7 +1614,7 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
"_Test Account Education Cess - _TC": [1.4, 1.4, 1.4],
|
"_Test Account Education Cess - _TC": [1.4, 1.4, 1.4],
|
||||||
"_Test Account S&H Education Cess - _TC": [0.7, 0.7, 0.7],
|
"_Test Account S&H Education Cess - _TC": [0.7, 0.7, 0.7],
|
||||||
"_Test Account CST - _TC": [17.19, 17.19, 17.19],
|
"_Test Account CST - _TC": [17.19, 17.19, 17.19],
|
||||||
"_Test Account VAT - _TC": [78.13, 78.13, 78.13],
|
"_Test Account VAT - _TC": [78.12, 78.12, 78.12],
|
||||||
"_Test Account Discount - _TC": [-95.49, -95.49, -95.49],
|
"_Test Account Discount - _TC": [-95.49, -95.49, -95.49],
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1623,9 +1623,9 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
if expected_values.get(d.account_head):
|
if expected_values.get(d.account_head):
|
||||||
self.assertEqual(d.get(k), expected_values[d.account_head][i])
|
self.assertEqual(d.get(k), expected_values[d.account_head][i])
|
||||||
|
|
||||||
self.assertEqual(si.total_taxes_and_charges, 234.43)
|
self.assertEqual(si.total_taxes_and_charges, 234.42)
|
||||||
self.assertEqual(si.base_grand_total, 859.43)
|
self.assertEqual(si.base_grand_total, 859.42)
|
||||||
self.assertEqual(si.grand_total, 859.43)
|
self.assertEqual(si.grand_total, 859.42)
|
||||||
|
|
||||||
def test_multi_currency_gle(self):
|
def test_multi_currency_gle(self):
|
||||||
si = create_sales_invoice(
|
si = create_sales_invoice(
|
||||||
@ -1985,17 +1985,17 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
si.save()
|
si.save()
|
||||||
si.submit()
|
si.submit()
|
||||||
self.assertEqual(si.net_total, 19453.13)
|
self.assertEqual(si.net_total, 19453.12)
|
||||||
self.assertEqual(si.grand_total, 24900)
|
self.assertEqual(si.grand_total, 24900)
|
||||||
self.assertEqual(si.total_taxes_and_charges, 5446.88)
|
self.assertEqual(si.total_taxes_and_charges, 5446.88)
|
||||||
self.assertEqual(si.rounding_adjustment, -0.01)
|
self.assertEqual(si.rounding_adjustment, 0.0)
|
||||||
|
|
||||||
expected_values = dict(
|
expected_values = dict(
|
||||||
(d[0], d)
|
(d[0], d)
|
||||||
for d in [
|
for d in [
|
||||||
[si.debit_to, 24900, 0.0],
|
[si.debit_to, 24900, 0.0],
|
||||||
["_Test Account Service Tax - _TC", 0.0, 5446.88],
|
["_Test Account Service Tax - _TC", 0.0, 5446.88],
|
||||||
["Sales - _TC", 0.0, 19453.13],
|
["Sales - _TC", 0.0, 19453.12],
|
||||||
["Round Off - _TC", 0.01, 0.0],
|
["Round Off - _TC", 0.01, 0.0],
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|||||||
@ -32,6 +32,16 @@ from erpnext import get_company_currency
|
|||||||
from erpnext.accounts.utils import get_fiscal_year
|
from erpnext.accounts.utils import get_fiscal_year
|
||||||
from erpnext.exceptions import InvalidAccountCurrency, PartyDisabled, PartyFrozen
|
from erpnext.exceptions import InvalidAccountCurrency, PartyDisabled, PartyFrozen
|
||||||
|
|
||||||
|
PURCHASE_TRANSACTION_TYPES = {"Purchase Order", "Purchase Receipt", "Purchase Invoice"}
|
||||||
|
SALES_TRANSACTION_TYPES = {
|
||||||
|
"Quotation",
|
||||||
|
"Sales Order",
|
||||||
|
"Delivery Note",
|
||||||
|
"Sales Invoice",
|
||||||
|
"POS Invoice",
|
||||||
|
}
|
||||||
|
TRANSACTION_TYPES = PURCHASE_TRANSACTION_TYPES | SALES_TRANSACTION_TYPES
|
||||||
|
|
||||||
|
|
||||||
class DuplicatePartyAccountError(frappe.ValidationError):
|
class DuplicatePartyAccountError(frappe.ValidationError):
|
||||||
pass
|
pass
|
||||||
@ -124,12 +134,6 @@ def _get_party_details(
|
|||||||
set_other_values(party_details, party, party_type)
|
set_other_values(party_details, party, party_type)
|
||||||
set_price_list(party_details, party, party_type, price_list, pos_profile)
|
set_price_list(party_details, party, party_type, price_list, pos_profile)
|
||||||
|
|
||||||
party_details["tax_category"] = get_address_tax_category(
|
|
||||||
party.get("tax_category"),
|
|
||||||
party_address,
|
|
||||||
shipping_address if party_type != "Supplier" else party_address,
|
|
||||||
)
|
|
||||||
|
|
||||||
tax_template = set_taxes(
|
tax_template = set_taxes(
|
||||||
party.name,
|
party.name,
|
||||||
party_type,
|
party_type,
|
||||||
@ -211,20 +215,10 @@ def set_address_details(
|
|||||||
else:
|
else:
|
||||||
party_details.update(get_company_address(company))
|
party_details.update(get_company_address(company))
|
||||||
|
|
||||||
if doctype and doctype in [
|
if doctype in SALES_TRANSACTION_TYPES and party_details.company_address:
|
||||||
"Delivery Note",
|
party_details.update(get_fetch_values(doctype, "company_address", party_details.company_address))
|
||||||
"Sales Invoice",
|
|
||||||
"Sales Order",
|
|
||||||
"Quotation",
|
|
||||||
"POS Invoice",
|
|
||||||
]:
|
|
||||||
if party_details.company_address:
|
|
||||||
party_details.update(
|
|
||||||
get_fetch_values(doctype, "company_address", party_details.company_address)
|
|
||||||
)
|
|
||||||
get_regional_address_details(party_details, doctype, company)
|
|
||||||
|
|
||||||
elif doctype and doctype in ["Purchase Invoice", "Purchase Order", "Purchase Receipt"]:
|
if doctype in PURCHASE_TRANSACTION_TYPES:
|
||||||
if shipping_address:
|
if shipping_address:
|
||||||
party_details.update(
|
party_details.update(
|
||||||
shipping_address=shipping_address,
|
shipping_address=shipping_address,
|
||||||
@ -250,9 +244,21 @@ def set_address_details(
|
|||||||
**get_fetch_values(doctype, "shipping_address", party_details.billing_address)
|
**get_fetch_values(doctype, "shipping_address", party_details.billing_address)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
party_address, shipping_address = (
|
||||||
|
party_details.get(billing_address_field),
|
||||||
|
party_details.shipping_address_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
party_details["tax_category"] = get_address_tax_category(
|
||||||
|
party.get("tax_category"),
|
||||||
|
party_address,
|
||||||
|
shipping_address if party_type != "Supplier" else party_address,
|
||||||
|
)
|
||||||
|
|
||||||
|
if doctype in TRANSACTION_TYPES:
|
||||||
get_regional_address_details(party_details, doctype, company)
|
get_regional_address_details(party_details, doctype, company)
|
||||||
|
|
||||||
return party_details.get(billing_address_field), party_details.shipping_address_name
|
return party_address, shipping_address
|
||||||
|
|
||||||
|
|
||||||
@erpnext.allow_regional
|
@erpnext.allow_regional
|
||||||
|
|||||||
@ -138,7 +138,8 @@ def prepare_companywise_opening_balance(asset_data, liability_data, equity_data,
|
|||||||
for data in [asset_data, liability_data, equity_data]:
|
for data in [asset_data, liability_data, equity_data]:
|
||||||
if data:
|
if data:
|
||||||
account_name = get_root_account_name(data[0].root_type, company)
|
account_name = get_root_account_name(data[0].root_type, company)
|
||||||
opening_value += get_opening_balance(account_name, data, company) or 0.0
|
if account_name:
|
||||||
|
opening_value += get_opening_balance(account_name, data, company) or 0.0
|
||||||
|
|
||||||
opening_balance[company] = opening_value
|
opening_balance[company] = opening_value
|
||||||
|
|
||||||
@ -155,7 +156,7 @@ def get_opening_balance(account_name, data, company):
|
|||||||
|
|
||||||
|
|
||||||
def get_root_account_name(root_type, company):
|
def get_root_account_name(root_type, company):
|
||||||
return frappe.get_all(
|
root_account = frappe.get_all(
|
||||||
"Account",
|
"Account",
|
||||||
fields=["account_name"],
|
fields=["account_name"],
|
||||||
filters={
|
filters={
|
||||||
@ -165,7 +166,10 @@ def get_root_account_name(root_type, company):
|
|||||||
"parent_account": ("is", "not set"),
|
"parent_account": ("is", "not set"),
|
||||||
},
|
},
|
||||||
as_list=1,
|
as_list=1,
|
||||||
)[0][0]
|
)
|
||||||
|
|
||||||
|
if root_account:
|
||||||
|
return root_account[0][0]
|
||||||
|
|
||||||
|
|
||||||
def get_profit_loss_data(fiscal_year, companies, columns, filters):
|
def get_profit_loss_data(fiscal_year, companies, columns, filters):
|
||||||
|
|||||||
@ -84,9 +84,6 @@ class SellingController(StockController):
|
|||||||
)
|
)
|
||||||
if not self.meta.get_field("sales_team"):
|
if not self.meta.get_field("sales_team"):
|
||||||
party_details.pop("sales_team")
|
party_details.pop("sales_team")
|
||||||
else:
|
|
||||||
self.set("sales_team", party_details.get("sales_team"))
|
|
||||||
|
|
||||||
self.update_if_missing(party_details)
|
self.update_if_missing(party_details)
|
||||||
|
|
||||||
elif lead:
|
elif lead:
|
||||||
|
|||||||
@ -76,12 +76,9 @@ def get_transaction_list(
|
|||||||
ignore_permissions = False
|
ignore_permissions = False
|
||||||
|
|
||||||
if not filters:
|
if not filters:
|
||||||
filters = []
|
filters = {}
|
||||||
|
|
||||||
if doctype in ["Supplier Quotation", "Purchase Invoice"]:
|
filters["docstatus"] = ["<", "2"] if doctype in ["Supplier Quotation", "Purchase Invoice"] else 1
|
||||||
filters.append((doctype, "docstatus", "<", 2))
|
|
||||||
else:
|
|
||||||
filters.append((doctype, "docstatus", "=", 1))
|
|
||||||
|
|
||||||
if (user != "Guest" and is_website_user()) or doctype == "Request for Quotation":
|
if (user != "Guest" and is_website_user()) or doctype == "Request for Quotation":
|
||||||
parties_doctype = (
|
parties_doctype = (
|
||||||
@ -92,12 +89,12 @@ def get_transaction_list(
|
|||||||
|
|
||||||
if customers:
|
if customers:
|
||||||
if doctype == "Quotation":
|
if doctype == "Quotation":
|
||||||
filters.append(("quotation_to", "=", "Customer"))
|
filters["quotation_to"] = "Customer"
|
||||||
filters.append(("party_name", "in", customers))
|
filters["party_name"] = ["in", customers]
|
||||||
else:
|
else:
|
||||||
filters.append(("customer", "in", customers))
|
filters["customer"] = ["in", customers]
|
||||||
elif suppliers:
|
elif suppliers:
|
||||||
filters.append(("supplier", "in", suppliers))
|
filters["supplier"] = ["in", suppliers]
|
||||||
elif not custom:
|
elif not custom:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
@ -110,7 +107,7 @@ def get_transaction_list(
|
|||||||
|
|
||||||
if not customers and not suppliers and custom:
|
if not customers and not suppliers and custom:
|
||||||
ignore_permissions = False
|
ignore_permissions = False
|
||||||
filters = []
|
filters = {}
|
||||||
|
|
||||||
transactions = get_list_for_transactions(
|
transactions = get_list_for_transactions(
|
||||||
doctype,
|
doctype,
|
||||||
|
|||||||
@ -506,7 +506,7 @@ frappe.ui.form.on("Work Order Item", {
|
|||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
if (r.message) {
|
if (r.message) {
|
||||||
frappe.model.set_value(cdt, cdn, {
|
frappe.model.set_value(cdt, cdn, {
|
||||||
"required_qty": 1,
|
"required_qty": row.required_qty || 1,
|
||||||
"item_name": r.message.item_name,
|
"item_name": r.message.item_name,
|
||||||
"description": r.message.description,
|
"description": r.message.description,
|
||||||
"source_warehouse": r.message.default_warehouse,
|
"source_warehouse": r.message.default_warehouse,
|
||||||
|
|||||||
@ -327,4 +327,3 @@ erpnext.patches.v14_0.create_accounting_dimensions_for_closing_balance
|
|||||||
erpnext.patches.v14_0.update_closing_balances
|
erpnext.patches.v14_0.update_closing_balances
|
||||||
# below 2 migration patches should always run last
|
# below 2 migration patches should always run last
|
||||||
erpnext.patches.v14_0.migrate_gl_to_payment_ledger
|
erpnext.patches.v14_0.migrate_gl_to_payment_ledger
|
||||||
erpnext.patches.v14_0.migrate_remarks_from_gl_to_payment_ledger
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import qb
|
from frappe import qb
|
||||||
from frappe.query_builder import Case, CustomFunction
|
from frappe.query_builder import CustomFunction
|
||||||
from frappe.query_builder.custom import ConstantColumn
|
from frappe.query_builder.custom import ConstantColumn
|
||||||
from frappe.query_builder.functions import Count, IfNull
|
from frappe.query_builder.functions import Count, IfNull
|
||||||
from frappe.utils import flt
|
from frappe.utils import flt
|
||||||
@ -18,9 +18,21 @@ def create_accounting_dimension_fields():
|
|||||||
make_dimension_in_accounting_doctypes(dimension, ["Payment Ledger Entry"])
|
make_dimension_in_accounting_doctypes(dimension, ["Payment Ledger Entry"])
|
||||||
|
|
||||||
|
|
||||||
def generate_name_for_payment_ledger_entries(gl_entries, start):
|
def generate_name_and_calculate_amount(gl_entries, start, receivable_accounts):
|
||||||
for index, entry in enumerate(gl_entries, 0):
|
for index, entry in enumerate(gl_entries, 0):
|
||||||
entry.name = start + index
|
entry.name = start + index
|
||||||
|
if entry.account in receivable_accounts:
|
||||||
|
entry.account_type = "Receivable"
|
||||||
|
entry.amount = entry.debit - entry.credit
|
||||||
|
entry.amount_in_account_currency = (
|
||||||
|
entry.debit_in_account_currency - entry.credit_in_account_currency
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
entry.account_type = "Payable"
|
||||||
|
entry.amount = entry.credit - entry.debit
|
||||||
|
entry.amount_in_account_currency = (
|
||||||
|
entry.credit_in_account_currency - entry.debit_in_account_currency
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_columns():
|
def get_columns():
|
||||||
@ -49,6 +61,9 @@ def get_columns():
|
|||||||
"finance_book",
|
"finance_book",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if frappe.db.has_column("Payment Ledger Entry", "remarks"):
|
||||||
|
columns.append("remarks")
|
||||||
|
|
||||||
dimensions_and_defaults = get_dimensions()
|
dimensions_and_defaults = get_dimensions()
|
||||||
if dimensions_and_defaults:
|
if dimensions_and_defaults:
|
||||||
for dimension in dimensions_and_defaults[0]:
|
for dimension in dimensions_and_defaults[0]:
|
||||||
@ -99,12 +114,17 @@ def execute():
|
|||||||
ifelse = CustomFunction("IF", ["condition", "then", "else"])
|
ifelse = CustomFunction("IF", ["condition", "then", "else"])
|
||||||
|
|
||||||
# Get Records Count
|
# Get Records Count
|
||||||
accounts = (
|
relavant_accounts = (
|
||||||
qb.from_(account)
|
qb.from_(account)
|
||||||
.select(account.name)
|
.select(account.name, account.account_type)
|
||||||
.where((account.account_type == "Receivable") | (account.account_type == "Payable"))
|
.where((account.account_type == "Receivable") | (account.account_type == "Payable"))
|
||||||
.orderby(account.name)
|
.orderby(account.name)
|
||||||
|
.run(as_dict=True)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
receivable_accounts = [x.name for x in relavant_accounts if x.account_type == "Receivable"]
|
||||||
|
accounts = [x.name for x in relavant_accounts]
|
||||||
|
|
||||||
un_processed = (
|
un_processed = (
|
||||||
qb.from_(gl)
|
qb.from_(gl)
|
||||||
.select(Count(gl.name))
|
.select(Count(gl.name))
|
||||||
@ -122,37 +142,21 @@ def execute():
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
if last_name:
|
if last_name:
|
||||||
where_clause = gl.name.gt(last_name) & (gl.is_cancelled == 0)
|
where_clause = gl.name.gt(last_name) & gl.account.isin(accounts) & gl.is_cancelled == 0
|
||||||
else:
|
else:
|
||||||
where_clause = gl.is_cancelled == 0
|
where_clause = gl.account.isin(accounts) & gl.is_cancelled == 0
|
||||||
|
|
||||||
gl_entries = (
|
gl_entries = (
|
||||||
qb.from_(gl)
|
qb.from_(gl)
|
||||||
.inner_join(account)
|
|
||||||
.on((gl.account == account.name) & (account.account_type.isin(["Receivable", "Payable"])))
|
|
||||||
.select(
|
.select(
|
||||||
gl.star,
|
gl.star,
|
||||||
ConstantColumn(1).as_("docstatus"),
|
ConstantColumn(1).as_("docstatus"),
|
||||||
account.account_type.as_("account_type"),
|
|
||||||
IfNull(
|
IfNull(
|
||||||
ifelse(gl.against_voucher_type == "", None, gl.against_voucher_type), gl.voucher_type
|
ifelse(gl.against_voucher_type == "", None, gl.against_voucher_type), gl.voucher_type
|
||||||
).as_("against_voucher_type"),
|
).as_("against_voucher_type"),
|
||||||
IfNull(ifelse(gl.against_voucher == "", None, gl.against_voucher), gl.voucher_no).as_(
|
IfNull(ifelse(gl.against_voucher == "", None, gl.against_voucher), gl.voucher_no).as_(
|
||||||
"against_voucher_no"
|
"against_voucher_no"
|
||||||
),
|
),
|
||||||
# convert debit/credit to amount
|
|
||||||
Case()
|
|
||||||
.when(account.account_type == "Receivable", gl.debit - gl.credit)
|
|
||||||
.else_(gl.credit - gl.debit)
|
|
||||||
.as_("amount"),
|
|
||||||
# convert debit/credit in account currency to amount in account currency
|
|
||||||
Case()
|
|
||||||
.when(
|
|
||||||
account.account_type == "Receivable",
|
|
||||||
gl.debit_in_account_currency - gl.credit_in_account_currency,
|
|
||||||
)
|
|
||||||
.else_(gl.credit_in_account_currency - gl.debit_in_account_currency)
|
|
||||||
.as_("amount_in_account_currency"),
|
|
||||||
)
|
)
|
||||||
.where(where_clause)
|
.where(where_clause)
|
||||||
.orderby(gl.name)
|
.orderby(gl.name)
|
||||||
@ -163,8 +167,8 @@ def execute():
|
|||||||
if gl_entries:
|
if gl_entries:
|
||||||
last_name = gl_entries[-1].name
|
last_name = gl_entries[-1].name
|
||||||
|
|
||||||
# primary key(name) for payment ledger records
|
# add primary key(name) and calculate based on debit and credit
|
||||||
generate_name_for_payment_ledger_entries(gl_entries, processed)
|
generate_name_and_calculate_amount(gl_entries, processed, receivable_accounts)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
insert_query = build_insert_query()
|
insert_query = build_insert_query()
|
||||||
|
|||||||
@ -1,98 +0,0 @@
|
|||||||
import frappe
|
|
||||||
from frappe import qb
|
|
||||||
from frappe.query_builder import CustomFunction
|
|
||||||
from frappe.query_builder.functions import Count, IfNull
|
|
||||||
from frappe.utils import flt
|
|
||||||
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
"""
|
|
||||||
Migrate 'remarks' field from 'tabGL Entry' to 'tabPayment Ledger Entry'
|
|
||||||
"""
|
|
||||||
|
|
||||||
if frappe.reload_doc("accounts", "doctype", "payment_ledger_entry"):
|
|
||||||
|
|
||||||
gle = qb.DocType("GL Entry")
|
|
||||||
ple = qb.DocType("Payment Ledger Entry")
|
|
||||||
|
|
||||||
# Get empty PLE records
|
|
||||||
un_processed = (
|
|
||||||
qb.from_(ple).select(Count(ple.name)).where((ple.remarks.isnull()) & (ple.delinked == 0)).run()
|
|
||||||
)[0][0]
|
|
||||||
|
|
||||||
if un_processed:
|
|
||||||
print(f"Remarks for {un_processed} Payment Ledger records will be updated from GL Entry")
|
|
||||||
|
|
||||||
ifelse = CustomFunction("IF", ["condition", "then", "else"])
|
|
||||||
|
|
||||||
processed = 0
|
|
||||||
last_percent_update = 0
|
|
||||||
batch_size = 1000
|
|
||||||
last_name = None
|
|
||||||
|
|
||||||
while True:
|
|
||||||
if last_name:
|
|
||||||
where_clause = (ple.name.gt(last_name)) & (ple.remarks.isnull()) & (ple.delinked == 0)
|
|
||||||
else:
|
|
||||||
where_clause = (ple.remarks.isnull()) & (ple.delinked == 0)
|
|
||||||
|
|
||||||
# results are deterministic
|
|
||||||
names = (
|
|
||||||
qb.from_(ple).select(ple.name).where(where_clause).orderby(ple.name).limit(batch_size).run()
|
|
||||||
)
|
|
||||||
|
|
||||||
if names:
|
|
||||||
last_name = names[-1][0]
|
|
||||||
|
|
||||||
pl_entries = (
|
|
||||||
qb.from_(ple)
|
|
||||||
.left_join(gle)
|
|
||||||
.on(
|
|
||||||
(ple.account == gle.account)
|
|
||||||
& (ple.party_type == gle.party_type)
|
|
||||||
& (ple.party == gle.party)
|
|
||||||
& (ple.voucher_type == gle.voucher_type)
|
|
||||||
& (ple.voucher_no == gle.voucher_no)
|
|
||||||
& (
|
|
||||||
ple.against_voucher_type
|
|
||||||
== IfNull(
|
|
||||||
ifelse(gle.against_voucher_type == "", None, gle.against_voucher_type), gle.voucher_type
|
|
||||||
)
|
|
||||||
)
|
|
||||||
& (
|
|
||||||
ple.against_voucher_no
|
|
||||||
== IfNull(ifelse(gle.against_voucher == "", None, gle.against_voucher), gle.voucher_no)
|
|
||||||
)
|
|
||||||
& (ple.company == gle.company)
|
|
||||||
& (
|
|
||||||
((ple.account_type == "Receivable") & (ple.amount == (gle.debit - gle.credit)))
|
|
||||||
| (ple.account_type == "Payable") & (ple.amount == (gle.credit - gle.debit))
|
|
||||||
)
|
|
||||||
& (gle.remarks.notnull())
|
|
||||||
& (gle.is_cancelled == 0)
|
|
||||||
)
|
|
||||||
.select(ple.name)
|
|
||||||
.distinct()
|
|
||||||
.select(
|
|
||||||
gle.remarks.as_("gle_remarks"),
|
|
||||||
)
|
|
||||||
.where(ple.name.isin(names))
|
|
||||||
.run(as_dict=True)
|
|
||||||
)
|
|
||||||
|
|
||||||
if pl_entries:
|
|
||||||
for entry in pl_entries:
|
|
||||||
query = qb.update(ple).set(ple.remarks, entry.gle_remarks).where((ple.name == entry.name))
|
|
||||||
query.run()
|
|
||||||
|
|
||||||
frappe.db.commit()
|
|
||||||
|
|
||||||
processed += len(pl_entries)
|
|
||||||
percentage = flt((processed / un_processed) * 100, 2)
|
|
||||||
if percentage - last_percent_update > 1:
|
|
||||||
print(f"{percentage}% ({processed}) PLE records updated")
|
|
||||||
last_percent_update = percentage
|
|
||||||
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
print("Remarks succesfully migrated")
|
|
||||||
@ -5,6 +5,8 @@ frappe.ui.form.on("Timesheet", {
|
|||||||
setup: function(frm) {
|
setup: function(frm) {
|
||||||
frappe.require("/assets/erpnext/js/projects/timer.js");
|
frappe.require("/assets/erpnext/js/projects/timer.js");
|
||||||
|
|
||||||
|
frm.ignore_doctypes_on_cancel_all = ['Sales Invoice'];
|
||||||
|
|
||||||
frm.fields_dict.employee.get_query = function() {
|
frm.fields_dict.employee.get_query = function() {
|
||||||
return {
|
return {
|
||||||
filters:{
|
filters:{
|
||||||
|
|||||||
@ -46,6 +46,9 @@ def get_data(filters):
|
|||||||
# task has no end date, hence no delay
|
# task has no end date, hence no delay
|
||||||
task.delay = 0
|
task.delay = 0
|
||||||
|
|
||||||
|
task.status = _(task.status)
|
||||||
|
task.priority = _(task.priority)
|
||||||
|
|
||||||
# Sort by descending order of delay
|
# Sort by descending order of delay
|
||||||
tasks.sort(key=lambda x: x["delay"], reverse=True)
|
tasks.sort(key=lambda x: x["delay"], reverse=True)
|
||||||
return tasks
|
return tasks
|
||||||
@ -73,7 +76,7 @@ def get_chart_data(data):
|
|||||||
on_track = on_track + 1
|
on_track = on_track + 1
|
||||||
charts = {
|
charts = {
|
||||||
"data": {
|
"data": {
|
||||||
"labels": ["On Track", "Delayed"],
|
"labels": [_("On Track"), _("Delayed")],
|
||||||
"datasets": [{"name": "Delayed", "values": [on_track, delay]}],
|
"datasets": [{"name": "Delayed", "values": [on_track, delay]}],
|
||||||
},
|
},
|
||||||
"type": "percentage",
|
"type": "percentage",
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import datetime
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.tests.utils import FrappeTestCase
|
from frappe.tests.utils import FrappeTestCase
|
||||||
from frappe.utils import add_days, nowdate
|
from frappe.utils import add_days, add_months, nowdate
|
||||||
|
|
||||||
from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice
|
from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice
|
||||||
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
|
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
|
||||||
@ -15,9 +15,16 @@ test_dependencies = ["Sales Order", "Item", "Sales Invoice", "Payment Terms Temp
|
|||||||
|
|
||||||
|
|
||||||
class TestPaymentTermsStatusForSalesOrder(FrappeTestCase):
|
class TestPaymentTermsStatusForSalesOrder(FrappeTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.cleanup_old_entries()
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
frappe.db.rollback()
|
frappe.db.rollback()
|
||||||
|
|
||||||
|
def cleanup_old_entries(self):
|
||||||
|
frappe.db.delete("Sales Invoice", filters={"company": "_Test Company"})
|
||||||
|
frappe.db.delete("Sales Order", filters={"company": "_Test Company"})
|
||||||
|
|
||||||
def create_payment_terms_template(self):
|
def create_payment_terms_template(self):
|
||||||
# create template for 50-50 payments
|
# create template for 50-50 payments
|
||||||
template = None
|
template = None
|
||||||
@ -348,7 +355,7 @@ class TestPaymentTermsStatusForSalesOrder(FrappeTestCase):
|
|||||||
item = create_item(item_code="_Test Excavator 1", is_stock_item=0)
|
item = create_item(item_code="_Test Excavator 1", is_stock_item=0)
|
||||||
transaction_date = nowdate()
|
transaction_date = nowdate()
|
||||||
so = make_sales_order(
|
so = make_sales_order(
|
||||||
transaction_date=add_days(transaction_date, -30),
|
transaction_date=add_months(transaction_date, -1),
|
||||||
delivery_date=add_days(transaction_date, -15),
|
delivery_date=add_days(transaction_date, -15),
|
||||||
item=item.item_code,
|
item=item.item_code,
|
||||||
qty=10,
|
qty=10,
|
||||||
@ -369,13 +376,15 @@ class TestPaymentTermsStatusForSalesOrder(FrappeTestCase):
|
|||||||
sinv.items[0].qty = 6
|
sinv.items[0].qty = 6
|
||||||
sinv.insert()
|
sinv.insert()
|
||||||
sinv.submit()
|
sinv.submit()
|
||||||
|
|
||||||
|
first_due_date = add_days(add_months(transaction_date, -1), 15)
|
||||||
columns, data, message, chart = execute(
|
columns, data, message, chart = execute(
|
||||||
frappe._dict(
|
frappe._dict(
|
||||||
{
|
{
|
||||||
"company": "_Test Company",
|
"company": "_Test Company",
|
||||||
"item": item.item_code,
|
"item": item.item_code,
|
||||||
"from_due_date": add_days(transaction_date, -30),
|
"from_due_date": add_months(transaction_date, -1),
|
||||||
"to_due_date": add_days(transaction_date, -15),
|
"to_due_date": first_due_date,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -384,11 +393,11 @@ class TestPaymentTermsStatusForSalesOrder(FrappeTestCase):
|
|||||||
{
|
{
|
||||||
"name": so.name,
|
"name": so.name,
|
||||||
"customer": so.customer,
|
"customer": so.customer,
|
||||||
"submitted": datetime.date.fromisoformat(add_days(transaction_date, -30)),
|
"submitted": datetime.date.fromisoformat(add_months(transaction_date, -1)),
|
||||||
"status": "Completed",
|
"status": "Completed",
|
||||||
"payment_term": None,
|
"payment_term": None,
|
||||||
"description": "_Test 50-50",
|
"description": "_Test 50-50",
|
||||||
"due_date": datetime.date.fromisoformat(add_days(transaction_date, -15)),
|
"due_date": datetime.date.fromisoformat(first_due_date),
|
||||||
"invoice_portion": 50.0,
|
"invoice_portion": 50.0,
|
||||||
"currency": "INR",
|
"currency": "INR",
|
||||||
"base_payment_amount": 500000.0,
|
"base_payment_amount": 500000.0,
|
||||||
|
|||||||
@ -54,7 +54,7 @@ class ItemAlternative(Document):
|
|||||||
if not item_data.allow_alternative_item:
|
if not item_data.allow_alternative_item:
|
||||||
frappe.throw(alternate_item_check_msg.format(self.item_code))
|
frappe.throw(alternate_item_check_msg.format(self.item_code))
|
||||||
if self.two_way and not alternative_item_data.allow_alternative_item:
|
if self.two_way and not alternative_item_data.allow_alternative_item:
|
||||||
frappe.throw(alternate_item_check_msg.format(self.item_code))
|
frappe.throw(alternate_item_check_msg.format(self.alternative_item_code))
|
||||||
|
|
||||||
def validate_duplicate(self):
|
def validate_duplicate(self):
|
||||||
if frappe.db.get_value(
|
if frappe.db.get_value(
|
||||||
|
|||||||
@ -132,7 +132,7 @@ class TestFIFOValuation(unittest.TestCase):
|
|||||||
total_qty = 0
|
total_qty = 0
|
||||||
|
|
||||||
for qty, rate in stock_queue:
|
for qty, rate in stock_queue:
|
||||||
if qty == 0:
|
if round_off_if_near_zero(qty) == 0:
|
||||||
continue
|
continue
|
||||||
if qty > 0:
|
if qty > 0:
|
||||||
self.queue.add_stock(qty, rate)
|
self.queue.add_stock(qty, rate)
|
||||||
@ -154,7 +154,7 @@ class TestFIFOValuation(unittest.TestCase):
|
|||||||
|
|
||||||
for qty, rate in stock_queue:
|
for qty, rate in stock_queue:
|
||||||
# don't allow negative stock
|
# don't allow negative stock
|
||||||
if qty == 0 or total_qty + qty < 0 or abs(qty) < 0.1:
|
if round_off_if_near_zero(qty) == 0 or total_qty + qty < 0 or abs(qty) < 0.1:
|
||||||
continue
|
continue
|
||||||
if qty > 0:
|
if qty > 0:
|
||||||
self.queue.add_stock(qty, rate)
|
self.queue.add_stock(qty, rate)
|
||||||
@ -179,7 +179,7 @@ class TestFIFOValuation(unittest.TestCase):
|
|||||||
|
|
||||||
for qty, rate in stock_queue:
|
for qty, rate in stock_queue:
|
||||||
# don't allow negative stock
|
# don't allow negative stock
|
||||||
if qty == 0 or total_qty + qty < 0 or abs(qty) < 0.1:
|
if round_off_if_near_zero(qty) == 0 or total_qty + qty < 0 or abs(qty) < 0.1:
|
||||||
continue
|
continue
|
||||||
if qty > 0:
|
if qty > 0:
|
||||||
self.queue.add_stock(qty, rate)
|
self.queue.add_stock(qty, rate)
|
||||||
@ -282,7 +282,7 @@ class TestLIFOValuation(unittest.TestCase):
|
|||||||
total_qty = 0
|
total_qty = 0
|
||||||
|
|
||||||
for qty, rate in stock_stack:
|
for qty, rate in stock_stack:
|
||||||
if qty == 0:
|
if round_off_if_near_zero(qty) == 0:
|
||||||
continue
|
continue
|
||||||
if qty > 0:
|
if qty > 0:
|
||||||
self.stack.add_stock(qty, rate)
|
self.stack.add_stock(qty, rate)
|
||||||
@ -304,7 +304,7 @@ class TestLIFOValuation(unittest.TestCase):
|
|||||||
|
|
||||||
for qty, rate in stock_stack:
|
for qty, rate in stock_stack:
|
||||||
# don't allow negative stock
|
# don't allow negative stock
|
||||||
if qty == 0 or total_qty + qty < 0 or abs(qty) < 0.1:
|
if round_off_if_near_zero(qty) == 0 or total_qty + qty < 0 or abs(qty) < 0.1:
|
||||||
continue
|
continue
|
||||||
if qty > 0:
|
if qty > 0:
|
||||||
self.stack.add_stock(qty, rate)
|
self.stack.add_stock(qty, rate)
|
||||||
|
|||||||
@ -2801,7 +2801,7 @@ Stock Ledger Entries and GL Entries are reposted for the selected Purchase Recei
|
|||||||
Stock Levels,Niveaux du Stocks,
|
Stock Levels,Niveaux du Stocks,
|
||||||
Stock Liabilities,Passif du Stock,
|
Stock Liabilities,Passif du Stock,
|
||||||
Stock Options,Options du Stock,
|
Stock Options,Options du Stock,
|
||||||
Stock Qty,Qté en Stock,
|
Stock Qty,Qté en unité de stock,
|
||||||
Stock Received But Not Billed,Stock Reçus Mais Non Facturés,
|
Stock Received But Not Billed,Stock Reçus Mais Non Facturés,
|
||||||
Stock Reports,Rapports de stock,
|
Stock Reports,Rapports de stock,
|
||||||
Stock Summary,Résumé du Stock,
|
Stock Summary,Résumé du Stock,
|
||||||
|
|||||||
|
Can't render this file because it is too large.
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user