Merge branch 'develop' into ordered-qty-for-packed-items

This commit is contained in:
Saqib Ansari 2022-03-02 12:13:56 +05:30 committed by GitHub
commit 89f87cee87
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
85 changed files with 660 additions and 345 deletions

View File

@ -120,6 +120,7 @@ def get_booking_dates(doc, item, posting_date=None):
prev_gl_entry = frappe.db.sql('''
select name, posting_date from `tabGL Entry` where company=%s and account=%s and
voucher_type=%s and voucher_no=%s and voucher_detail_no=%s
and is_cancelled = 0
order by posting_date desc limit 1
''', (doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name), as_dict=True)
@ -227,6 +228,7 @@ def get_already_booked_amount(doc, item):
gl_entries_details = frappe.db.sql('''
select sum({0}) as total_credit, sum({1}) as total_credit_in_account_currency, voucher_detail_no
from `tabGL Entry` where company=%s and account=%s and voucher_type=%s and voucher_no=%s and voucher_detail_no=%s
and is_cancelled = 0
group by voucher_detail_no
'''.format(total_credit_debit, total_credit_debit_currency),
(doc.company, item.get(deferred_account), doc.doctype, doc.name, item.name), as_dict=True)
@ -282,7 +284,7 @@ def book_deferred_income_or_expense(doc, deferred_process, posting_date=None):
return
# check if books nor frozen till endate:
if getdate(end_date) >= getdate(accounts_frozen_upto):
if accounts_frozen_upto and (end_date) <= getdate(accounts_frozen_upto):
end_date = get_last_day(add_days(accounts_frozen_upto, 1))
if via_journal_entry:

View File

@ -2,6 +2,7 @@
# See license.txt
import frappe
from frappe.tests.utils import FrappeTestCase
from erpnext.accounts.doctype.accounting_dimension.test_accounting_dimension import (
create_dimension,
@ -10,11 +11,10 @@ from erpnext.accounts.doctype.accounting_dimension.test_accounting_dimension imp
from erpnext.accounts.doctype.opening_invoice_creation_tool.opening_invoice_creation_tool import (
get_temporary_opening_account,
)
from erpnext.tests.utils import ERPNextTestCase
test_dependencies = ["Customer", "Supplier", "Accounting Dimension"]
class TestOpeningInvoiceCreationTool(ERPNextTestCase):
class TestOpeningInvoiceCreationTool(FrappeTestCase):
@classmethod
def setUpClass(self):
if not frappe.db.exists("Company", "_Test Opening Invoice Company"):

View File

@ -194,8 +194,14 @@ frappe.ui.form.on('Payment Entry', {
frm.doc.paid_from_account_currency != frm.doc.paid_to_account_currency));
frm.toggle_display("base_paid_amount", frm.doc.paid_from_account_currency != company_currency);
frm.toggle_display("base_total_taxes_and_charges", frm.doc.total_taxes_and_charges &&
(frm.doc.paid_from_account_currency != company_currency));
if (frm.doc.payment_type == "Pay") {
frm.toggle_display("base_total_taxes_and_charges", frm.doc.total_taxes_and_charges &&
(frm.doc.paid_to_account_currency != company_currency));
} else {
frm.toggle_display("base_total_taxes_and_charges", frm.doc.total_taxes_and_charges &&
(frm.doc.paid_from_account_currency != company_currency));
}
frm.toggle_display("base_received_amount", (
frm.doc.paid_to_account_currency != company_currency
@ -230,7 +236,8 @@ frappe.ui.form.on('Payment Entry', {
var company_currency = frm.doc.company? frappe.get_doc(":Company", frm.doc.company).default_currency: "";
frm.set_currency_labels(["base_paid_amount", "base_received_amount", "base_total_allocated_amount",
"difference_amount", "base_paid_amount_after_tax", "base_received_amount_after_tax"], company_currency);
"difference_amount", "base_paid_amount_after_tax", "base_received_amount_after_tax",
"base_total_taxes_and_charges"], company_currency);
frm.set_currency_labels(["paid_amount"], frm.doc.paid_from_account_currency);
frm.set_currency_labels(["received_amount"], frm.doc.paid_to_account_currency);

View File

@ -66,7 +66,9 @@
"tax_withholding_category",
"section_break_56",
"taxes",
"section_break_60",
"base_total_taxes_and_charges",
"column_break_61",
"total_taxes_and_charges",
"deductions_or_loss_section",
"deductions",
@ -715,12 +717,21 @@
"fieldtype": "Data",
"hidden": 1,
"label": "Paid To Account Type"
},
{
"fieldname": "column_break_61",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_60",
"fieldtype": "Section Break",
"hide_border": 1
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2021-11-24 18:58:24.919764",
"modified": "2022-02-23 20:08:39.559814",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry",
@ -763,6 +774,7 @@
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"title_field": "title",
"track_changes": 1
}

View File

@ -934,8 +934,12 @@ class PaymentEntry(AccountsController):
tax.base_total = tax.total * self.source_exchange_rate
self.total_taxes_and_charges += current_tax_amount
self.base_total_taxes_and_charges += current_tax_amount * self.source_exchange_rate
if self.payment_type == 'Pay':
self.base_total_taxes_and_charges += flt(current_tax_amount / self.source_exchange_rate)
self.total_taxes_and_charges += flt(current_tax_amount / self.target_exchange_rate)
else:
self.base_total_taxes_and_charges += flt(current_tax_amount / self.target_exchange_rate)
self.total_taxes_and_charges += flt(current_tax_amount / self.source_exchange_rate)
if self.get('taxes'):
self.paid_amount_after_tax = self.get('taxes')[-1].base_total

View File

@ -633,6 +633,45 @@ class TestPaymentEntry(unittest.TestCase):
self.assertEqual(flt(expected_party_balance), party_balance)
self.assertEqual(flt(expected_party_account_balance), party_account_balance)
def test_multi_currency_payment_entry_with_taxes(self):
payment_entry = create_payment_entry(party='_Test Supplier USD', paid_to = '_Test Payable USD - _TC',
save=True)
payment_entry.append('taxes', {
'account_head': '_Test Account Service Tax - _TC',
'charge_type': 'Actual',
'tax_amount': 10,
'add_deduct_tax': 'Add',
'description': 'Test'
})
payment_entry.save()
self.assertEqual(payment_entry.base_total_taxes_and_charges, 10)
self.assertEqual(flt(payment_entry.total_taxes_and_charges, 2), flt(10 / payment_entry.target_exchange_rate, 2))
def create_payment_entry(**args):
payment_entry = frappe.new_doc('Payment Entry')
payment_entry.company = args.get('company') or '_Test Company'
payment_entry.payment_type = args.get('payment_type') or 'Pay'
payment_entry.party_type = args.get('party_type') or 'Supplier'
payment_entry.party = args.get('party') or '_Test Supplier'
payment_entry.paid_from = args.get('paid_from') or '_Test Bank - _TC'
payment_entry.paid_to = args.get('paid_to') or 'Creditors - _TC'
payment_entry.paid_amount = args.get('paid_amount') or 1000
payment_entry.setup_party_account_field()
payment_entry.set_missing_values()
payment_entry.set_exchange_rate()
payment_entry.received_amount = payment_entry.paid_amount / payment_entry.target_exchange_rate
payment_entry.reference_no = 'Test001'
payment_entry.reference_date = nowdate()
if args.get('save'):
payment_entry.save()
if args.get('submit'):
payment_entry.submit()
return payment_entry
def create_payment_terms_template():
create_payment_term('Basic Amount Receivable')

View File

@ -73,7 +73,7 @@ def get_report_pdf(doc, consolidated=True):
'to_date': doc.to_date,
'company': doc.company,
'finance_book': doc.finance_book if doc.finance_book else None,
'account': doc.account if doc.account else None,
'account': [doc.account] if doc.account else None,
'party_type': 'Customer',
'party': [entry.customer],
'presentation_currency': presentation_currency,

View File

@ -1595,6 +1595,56 @@ class TestSalesInvoice(unittest.TestCase):
self.assertEqual(expected_values[gle.account][1], gle.debit)
self.assertEqual(expected_values[gle.account][2], gle.credit)
def test_rounding_adjustment_3(self):
si = create_sales_invoice(do_not_save=True)
si.items = []
for d in [(1122, 2), (1122.01, 1), (1122.01, 1)]:
si.append("items", {
"item_code": "_Test Item",
"gst_hsn_code": "999800",
"warehouse": "_Test Warehouse - _TC",
"qty": d[1],
"rate": d[0],
"income_account": "Sales - _TC",
"cost_center": "_Test Cost Center - _TC"
})
for tax_account in ["_Test Account VAT - _TC", "_Test Account Service Tax - _TC"]:
si.append("taxes", {
"charge_type": "On Net Total",
"account_head": tax_account,
"description": tax_account,
"rate": 6,
"cost_center": "_Test Cost Center - _TC",
"included_in_print_rate": 1
})
si.save()
si.submit()
self.assertEqual(si.net_total, 4007.16)
self.assertEqual(si.grand_total, 4488.02)
self.assertEqual(si.total_taxes_and_charges, 480.86)
self.assertEqual(si.rounding_adjustment, -0.02)
expected_values = dict((d[0], d) for d in [
[si.debit_to, 4488.0, 0.0],
["_Test Account Service Tax - _TC", 0.0, 240.43],
["_Test Account VAT - _TC", 0.0, 240.43],
["Sales - _TC", 0.0, 4007.15],
["Round Off - _TC", 0.01, 0]
])
gl_entries = frappe.db.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
order by account asc""", si.name, as_dict=1)
debit_credit_diff = 0
for gle in gl_entries:
self.assertEqual(expected_values[gle.account][0], gle.account)
self.assertEqual(expected_values[gle.account][1], gle.debit)
self.assertEqual(expected_values[gle.account][2], gle.credit)
debit_credit_diff += (gle.debit - gle.credit)
self.assertEqual(debit_credit_diff, 0)
def test_sales_invoice_with_shipping_rule(self):
from erpnext.accounts.doctype.shipping_rule.test_shipping_rule import create_shipping_rule
@ -2429,14 +2479,22 @@ class TestSalesInvoice(unittest.TestCase):
def test_sales_commission(self):
si = frappe.copy_doc(test_records[0])
si = frappe.copy_doc(test_records[2])
frappe.db.set_value('Item', si.get('items')[0].item_code, 'grant_commission', 1)
frappe.db.set_value('Item', si.get('items')[1].item_code, 'grant_commission', 0)
item = copy.deepcopy(si.get('items')[0])
item.update({
"qty": 1,
"rate": 500,
"grant_commission": 1
})
si.append("items", item)
item = copy.deepcopy(si.get('items')[1])
item.update({
"qty": 1,
"rate": 500,
})
# Test valid values
for commission_rate, total_commission in ((0, 0), (10, 50), (100, 500)):

View File

@ -832,6 +832,7 @@
},
{
"default": "0",
"fetch_from": "item_code.grant_commission",
"fieldname": "grant_commission",
"fieldtype": "Check",
"label": "Grant Commission",
@ -841,7 +842,7 @@
"idx": 1,
"istable": 1,
"links": [],
"modified": "2021-10-05 12:24:54.968907",
"modified": "2022-02-24 14:41:36.392560",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Item",
@ -849,5 +850,6 @@
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC"
"sort_order": "DESC",
"states": []
}

View File

@ -55,5 +55,8 @@ def validate_disabled(doc):
frappe.throw(_("Disabled template must not be default template"))
def validate_for_tax_category(doc):
if not doc.tax_category:
return
if frappe.db.exists(doc.doctype, {"company": doc.company, "tax_category": doc.tax_category, "disabled": 0, "name": ["!=", doc.name]}):
frappe.throw(_("A template with tax category {0} already exists. Only one template is allowed with each tax category").format(frappe.bold(doc.tax_category)))

View File

@ -274,7 +274,7 @@ def make_round_off_gle(gl_map, debit_credit_diff, precision):
debit_credit_diff += flt(d.credit)
round_off_account_exists = True
if round_off_account_exists and abs(debit_credit_diff) <= (1.0 / (10**precision)):
if round_off_account_exists and abs(debit_credit_diff) < (1.0 / (10**precision)):
gl_map.remove(round_off_gle)
return

View File

@ -3,9 +3,9 @@
import json
import unittest
import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.utils import add_days, flt, getdate, nowdate
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
@ -27,7 +27,7 @@ from erpnext.stock.doctype.purchase_receipt.purchase_receipt import (
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
class TestPurchaseOrder(unittest.TestCase):
class TestPurchaseOrder(FrappeTestCase):
def test_make_purchase_receipt(self):
po = create_purchase_order(do_not_submit=True)
self.assertRaises(frappe.ValidationError, make_purchase_receipt, po.name)

View File

@ -1,9 +1,9 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.utils import nowdate
from erpnext.buying.doctype.request_for_quotation.request_for_quotation import (
@ -16,7 +16,7 @@ from erpnext.stock.doctype.item.test_item import make_item
from erpnext.templates.pages.rfq import check_supplier_has_docname_access
class TestRequestforQuotation(unittest.TestCase):
class TestRequestforQuotation(FrappeTestCase):
def test_quote_status(self):
rfq = make_request_for_quotation()

View File

@ -1,7 +1,6 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
import unittest
import frappe
from frappe.test_runner import make_test_records
@ -12,8 +11,10 @@ from erpnext.exceptions import PartyDisabled
test_dependencies = ['Payment Term', 'Payment Terms Template']
test_records = frappe.get_test_records('Supplier')
from frappe.tests.utils import FrappeTestCase
class TestSupplier(unittest.TestCase):
class TestSupplier(FrappeTestCase):
def test_get_supplier_group_details(self):
doc = frappe.new_doc("Supplier Group")
doc.supplier_group_name = "_Testing Supplier Group"

View File

@ -3,12 +3,12 @@
import unittest
import frappe
from frappe.tests.utils import FrappeTestCase
class TestPurchaseOrder(unittest.TestCase):
class TestPurchaseOrder(FrappeTestCase):
def test_make_purchase_order(self):
from erpnext.buying.doctype.supplier_quotation.supplier_quotation import make_purchase_order

View File

@ -1,12 +1,12 @@
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
import frappe
from frappe.tests.utils import FrappeTestCase
class TestSupplierScorecard(unittest.TestCase):
class TestSupplierScorecard(FrappeTestCase):
def test_create_scorecard(self):
doc = make_supplier_scorecard().insert()

View File

@ -1,12 +1,12 @@
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
import frappe
from frappe.tests.utils import FrappeTestCase
class TestSupplierScorecardCriteria(unittest.TestCase):
class TestSupplierScorecardCriteria(FrappeTestCase):
def test_variables_exist(self):
delete_test_scorecards()
for d in test_good_criteria:

View File

@ -1,16 +1,16 @@
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
import frappe
from frappe.tests.utils import FrappeTestCase
from erpnext.buying.doctype.supplier_scorecard_variable.supplier_scorecard_variable import (
VariablePathNotFound,
)
class TestSupplierScorecardVariable(unittest.TestCase):
class TestSupplierScorecardVariable(FrappeTestCase):
def test_variable_exist(self):
for d in test_existing_variables:
my_doc = frappe.get_doc("Supplier Scorecard Variable", d.get("name"))

View File

@ -2,10 +2,10 @@
# For license information, please see license.txt
import unittest
from datetime import datetime
import frappe
from frappe.tests.utils import FrappeTestCase
from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_receipt
from erpnext.buying.report.procurement_tracker.procurement_tracker import execute
@ -14,7 +14,7 @@ from erpnext.stock.doctype.material_request.test_material_request import make_ma
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
class TestProcurementTracker(unittest.TestCase):
class TestProcurementTracker(FrappeTestCase):
def test_result_for_procurement_tracker(self):
filters = {
'company': '_Test Procurement Company',

View File

@ -3,9 +3,9 @@
# Compiled at: 2019-05-06 09:51:46
# Decompiled by https://python-decompiler.com
import unittest
import frappe
from frappe.tests.utils import FrappeTestCase
from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_receipt
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
@ -15,7 +15,7 @@ from erpnext.buying.report.subcontracted_item_to_be_received.subcontracted_item_
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
class TestSubcontractedItemToBeReceived(unittest.TestCase):
class TestSubcontractedItemToBeReceived(FrappeTestCase):
def test_pending_and_received_qty(self):
po = create_purchase_order(item_code='_Test FG Item', is_subcontracted='Yes')

View File

@ -4,9 +4,9 @@
# Decompiled by https://python-decompiler.com
import json
import unittest
import frappe
from frappe.tests.utils import FrappeTestCase
from erpnext.buying.doctype.purchase_order.purchase_order import make_rm_stock_entry
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
@ -16,7 +16,7 @@ from erpnext.buying.report.subcontracted_raw_materials_to_be_transferred.subcont
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
class TestSubcontractedItemToBeTransferred(unittest.TestCase):
class TestSubcontractedItemToBeTransferred(FrappeTestCase):
def test_pending_and_transferred_qty(self):
po = create_purchase_order(item_code='_Test FG Item', is_subcontracted='Yes', supplier_warehouse="_Test Warehouse 1 - _TC")

View File

@ -363,8 +363,6 @@ class Subcontracting():
return
for row in self.get(self.raw_material_table):
self.__validate_consumed_qty(row)
key = (row.rm_item_code, row.main_item_code, row.purchase_order)
if not self.__transferred_items or not self.__transferred_items.get(key):
return
@ -372,12 +370,6 @@ class Subcontracting():
self.__validate_batch_no(row, key)
self.__validate_serial_no(row, key)
def __validate_consumed_qty(self, row):
if self.backflush_based_on != 'BOM' and flt(row.consumed_qty) == 0.0:
msg = f'Row {row.idx}: the consumed qty cannot be zero for the item {frappe.bold(row.rm_item_code)}'
frappe.throw(_(msg),title=_('Consumed Items Qty Check'))
def __validate_batch_no(self, row, key):
if row.get('batch_no') and row.get('batch_no') not in self.__transferred_items.get(key).get('batch_no'):
link = get_link_to_form('Purchase Order', row.purchase_order)

View File

@ -5,6 +5,7 @@
import unittest
import frappe
from frappe.tests.utils import change_settings
from frappe.utils import add_months, nowdate
from erpnext.accounts.doctype.tax_rule.tax_rule import ConflictingTaxRule
@ -15,7 +16,7 @@ from erpnext.e_commerce.shopping_cart.cart import (
get_party,
update_cart,
)
from erpnext.tests.utils import change_settings, create_test_contact_and_address
from erpnext.tests.utils import create_test_contact_and_address
# test_dependencies = ['Payment Terms Template']

View File

@ -1,4 +1,5 @@
import frappe
from frappe.tests.utils import FrappeTestCase
from erpnext.controllers.item_variant import create_variant
from erpnext.e_commerce.doctype.e_commerce_settings.test_e_commerce_settings import (
@ -7,11 +8,10 @@ from erpnext.e_commerce.doctype.e_commerce_settings.test_e_commerce_settings imp
from erpnext.e_commerce.doctype.website_item.website_item import make_website_item
from erpnext.e_commerce.variant_selector.utils import get_next_attribute_and_values
from erpnext.stock.doctype.item.test_item import make_item
from erpnext.tests.utils import ERPNextTestCase
test_dependencies = ["Item"]
class TestVariantSelector(ERPNextTestCase):
class TestVariantSelector(FrappeTestCase):
@classmethod
def setUpClass(cls):
@ -116,4 +116,4 @@ class TestVariantSelector(ERPNextTestCase):
self.assertEqual(next_values["exact_match"][0],"Test-Tshirt-Temp-S-R")
self.assertEqual(next_values["exact_match"][0],"Test-Tshirt-Temp-S-R")
self.assertEqual(price_info["price_list_rate"], 100.0)
self.assertEqual(price_info["formatted_price_sales_uom"], "₹ 100.00")
self.assertEqual(price_info["formatted_price_sales_uom"], "₹ 100.00")

View File

@ -2,7 +2,7 @@
"actions": [],
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2017-10-09 14:26:29.612365",
"creation": "2022-01-17 18:36:51.450395",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
@ -121,7 +121,7 @@
"fieldtype": "Select",
"label": "Status",
"no_copy": 1,
"options": "Draft\nPaid\nUnpaid\nClaimed\nCancelled",
"options": "Draft\nPaid\nUnpaid\nClaimed\nReturned\nPartly Claimed and Returned\nCancelled",
"read_only": 1
},
{
@ -200,7 +200,7 @@
],
"is_submittable": 1,
"links": [],
"modified": "2021-09-11 18:38:38.617478",
"modified": "2022-01-17 19:33:52.345823",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee Advance",
@ -237,5 +237,41 @@
"search_fields": "employee,employee_name",
"sort_field": "modified",
"sort_order": "DESC",
"states": [
{
"color": "Red",
"custom": 1,
"title": "Draft"
},
{
"color": "Green",
"custom": 1,
"title": "Paid"
},
{
"color": "Orange",
"custom": 1,
"title": "Unpaid"
},
{
"color": "Blue",
"custom": 1,
"title": "Claimed"
},
{
"color": "Gray",
"title": "Returned"
},
{
"color": "Yellow",
"title": "Partly Claimed and Returned"
},
{
"color": "Red",
"custom": 1,
"title": "Cancelled"
}
],
"title_field": "employee_name",
"track_changes": 1
}

View File

@ -27,19 +27,33 @@ class EmployeeAdvance(Document):
def on_cancel(self):
self.ignore_linked_doctypes = ('GL Entry')
self.set_status(update=True)
def set_status(self, update=False):
precision = self.precision("paid_amount")
total_amount = flt(flt(self.claimed_amount) + flt(self.return_amount), precision)
status = None
def set_status(self):
if self.docstatus == 0:
self.status = "Draft"
if self.docstatus == 1:
if self.claimed_amount and flt(self.claimed_amount) == flt(self.paid_amount):
self.status = "Claimed"
elif self.paid_amount and self.advance_amount == flt(self.paid_amount):
self.status = "Paid"
status = "Draft"
elif self.docstatus == 1:
if flt(self.claimed_amount) > 0 and flt(self.claimed_amount, precision) == flt(self.paid_amount, precision):
status = "Claimed"
elif flt(self.return_amount) > 0 and flt(self.return_amount, precision) == flt(self.paid_amount, precision):
status = "Returned"
elif flt(self.claimed_amount) > 0 and (flt(self.return_amount) > 0) and total_amount == flt(self.paid_amount, precision):
status = "Partly Claimed and Returned"
elif flt(self.paid_amount) > 0 and flt(self.advance_amount, precision) == flt(self.paid_amount, precision):
status = "Paid"
else:
self.status = "Unpaid"
status = "Unpaid"
elif self.docstatus == 2:
self.status = "Cancelled"
status = "Cancelled"
if update:
self.db_set("status", status)
else:
self.status = status
def set_total_advance_paid(self):
gle = frappe.qb.DocType("GL Entry")
@ -85,9 +99,7 @@ class EmployeeAdvance(Document):
self.db_set("paid_amount", paid_amount)
self.db_set("return_amount", return_amount)
self.set_status()
frappe.db.set_value("Employee Advance", self.name , "status", self.status)
self.set_status(update=True)
def update_claimed_amount(self):
claimed_amount = frappe.db.sql("""
@ -103,8 +115,8 @@ class EmployeeAdvance(Document):
frappe.db.set_value("Employee Advance", self.name, "claimed_amount", flt(claimed_amount))
self.reload()
self.set_status()
frappe.db.set_value("Employee Advance", self.name, "status", self.status)
self.set_status(update=True)
@frappe.whitelist()
def get_pending_amount(employee, posting_date):
@ -222,7 +234,8 @@ def make_return_entry(employee, company, employee_advance_name, return_amount,
'reference_name': employee_advance_name,
'party_type': 'Employee',
'party': employee,
'is_advance': 'Yes'
'is_advance': 'Yes',
'cost_center': erpnext.get_default_cost_center(company)
})
bank_amount = flt(return_amount) if bank_cash_account.account_currency==currency \
@ -233,7 +246,8 @@ def make_return_entry(employee, company, employee_advance_name, return_amount,
"debit_in_account_currency": bank_amount,
"account_currency": bank_cash_account.account_currency,
"account_type": bank_cash_account.account_type,
"exchange_rate": flt(exchange_rate) if bank_cash_account.account_currency == currency else 1
"exchange_rate": flt(exchange_rate) if bank_cash_account.account_currency == currency else 1,
"cost_center": erpnext.get_default_cost_center(company)
})
return je.as_dict()

View File

@ -4,7 +4,7 @@
import unittest
import frappe
from frappe.utils import nowdate
from frappe.utils import flt, nowdate
import erpnext
from erpnext.hr.doctype.employee.test_employee import make_employee
@ -12,12 +12,21 @@ from erpnext.hr.doctype.employee_advance.employee_advance import (
EmployeeAdvanceOverPayment,
create_return_through_additional_salary,
make_bank_entry,
make_return_entry,
)
from erpnext.hr.doctype.expense_claim.expense_claim import get_advances
from erpnext.hr.doctype.expense_claim.test_expense_claim import (
get_payable_account,
make_expense_claim,
)
from erpnext.payroll.doctype.salary_component.test_salary_component import create_salary_component
from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure
class TestEmployeeAdvance(unittest.TestCase):
def setUp(self):
frappe.db.delete("Employee Advance")
def test_paid_amount_and_status(self):
employee_name = make_employee("_T@employe.advance")
advance = make_employee_advance(employee_name)
@ -52,9 +61,102 @@ class TestEmployeeAdvance(unittest.TestCase):
self.assertEqual(advance.paid_amount, 0)
self.assertEqual(advance.status, "Unpaid")
advance.cancel()
advance.reload()
self.assertEqual(advance.status, "Cancelled")
def test_claimed_status(self):
# CLAIMED Status check, full amount claimed
payable_account = get_payable_account("_Test Company")
claim = make_expense_claim(payable_account, 1000, 1000, "_Test Company", "Travel Expenses - _TC", do_not_submit=True)
advance = make_employee_advance(claim.employee)
pe = make_payment_entry(advance)
pe.submit()
claim = get_advances_for_claim(claim, advance.name)
claim.save()
claim.submit()
advance.reload()
self.assertEqual(advance.claimed_amount, 1000)
self.assertEqual(advance.status, "Claimed")
# advance should not be shown in claims
advances = get_advances(claim.employee)
advances = [entry.name for entry in advances]
self.assertTrue(advance.name not in advances)
# cancel claim; status should be Paid
claim.cancel()
advance.reload()
self.assertEqual(advance.claimed_amount, 0)
self.assertEqual(advance.status, "Paid")
def test_partly_claimed_and_returned_status(self):
payable_account = get_payable_account("_Test Company")
claim = make_expense_claim(payable_account, 1000, 1000, "_Test Company", "Travel Expenses - _TC", do_not_submit=True)
advance = make_employee_advance(claim.employee)
pe = make_payment_entry(advance)
pe.submit()
# PARTLY CLAIMED AND RETURNED status check
# 500 Claimed, 500 Returned
claim = make_expense_claim(payable_account, 500, 500, "_Test Company", "Travel Expenses - _TC", do_not_submit=True)
advance = make_employee_advance(claim.employee)
pe = make_payment_entry(advance)
pe.submit()
claim = get_advances_for_claim(claim, advance.name, amount=500)
claim.save()
claim.submit()
advance.reload()
self.assertEqual(advance.claimed_amount, 500)
self.assertEqual(advance.status, "Paid")
entry = make_return_entry(
employee=advance.employee,
company=advance.company,
employee_advance_name=advance.name,
return_amount=flt(advance.paid_amount - advance.claimed_amount),
advance_account=advance.advance_account,
mode_of_payment=advance.mode_of_payment,
currency=advance.currency,
exchange_rate=advance.exchange_rate
)
entry = frappe.get_doc(entry)
entry.insert()
entry.submit()
advance.reload()
self.assertEqual(advance.return_amount, 500)
self.assertEqual(advance.status, "Partly Claimed and Returned")
# advance should not be shown in claims
advances = get_advances(claim.employee)
advances = [entry.name for entry in advances]
self.assertTrue(advance.name not in advances)
# Cancel return entry; status should change to PAID
entry.cancel()
advance.reload()
self.assertEqual(advance.return_amount, 0)
self.assertEqual(advance.status, "Paid")
# advance should be shown in claims
advances = get_advances(claim.employee)
advances = [entry.name for entry in advances]
self.assertTrue(advance.name in advances)
def test_repay_unclaimed_amount_from_salary(self):
employee_name = make_employee("_T@employe.advance")
advance = make_employee_advance(employee_name, {"repay_unclaimed_amount_from_salary": 1})
pe = make_payment_entry(advance)
pe.submit()
args = {"type": "Deduction"}
create_salary_component("Advance Salary - Deduction", **args)
@ -82,11 +184,13 @@ class TestEmployeeAdvance(unittest.TestCase):
advance.reload()
self.assertEqual(advance.return_amount, 1000)
self.assertEqual(advance.status, "Returned")
# update advance return amount on additional salary cancellation
additional_salary.cancel()
advance.reload()
self.assertEqual(advance.return_amount, 700)
self.assertEqual(advance.status, "Paid")
def tearDown(self):
frappe.db.rollback()
@ -118,3 +222,24 @@ def make_employee_advance(employee_name, args=None):
doc.submit()
return doc
def get_advances_for_claim(claim, advance_name, amount=None):
advances = get_advances(claim.employee, advance_name)
for entry in advances:
if amount:
allocated_amount = amount
else:
allocated_amount = flt(entry.paid_amount) - flt(entry.claimed_amount)
claim.append("advances", {
"employee_advance": entry.name,
"posting_date": entry.posting_date,
"advance_account": entry.advance_account,
"advance_paid": entry.paid_amount,
"unclaimed_amount": allocated_amount,
"allocated_amount": allocated_amount
})
return claim

View File

@ -171,7 +171,7 @@ frappe.ui.form.on("Expense Claim", {
['docstatus', '=', 1],
['employee', '=', frm.doc.employee],
['paid_amount', '>', 0],
['status', '!=', 'Claimed']
['status', 'not in', ['Claimed', 'Returned', 'Partly Claimed and Returned']]
]
};
});

View File

@ -23,10 +23,10 @@ class ExpenseClaim(AccountsController):
def validate(self):
validate_active_employee(self.employee)
self.validate_advances()
set_employee_name(self)
self.validate_sanctioned_amount()
self.calculate_total_amount()
set_employee_name(self)
self.validate_advances()
self.set_expense_account(validate=True)
self.set_payable_account()
self.set_cost_center()
@ -341,18 +341,27 @@ def get_expense_claim_account(expense_claim_type, company):
@frappe.whitelist()
def get_advances(employee, advance_id=None):
if not advance_id:
condition = 'docstatus=1 and employee={0} and paid_amount > 0 and paid_amount > claimed_amount + return_amount'.format(frappe.db.escape(employee))
else:
condition = 'name={0}'.format(frappe.db.escape(advance_id))
advance = frappe.qb.DocType("Employee Advance")
return frappe.db.sql("""
select
name, posting_date, paid_amount, claimed_amount, advance_account
from
`tabEmployee Advance`
where {0}
""".format(condition), as_dict=1)
query = (
frappe.qb.from_(advance)
.select(
advance.name, advance.posting_date, advance.paid_amount,
advance.claimed_amount, advance.advance_account
)
)
if not advance_id:
query = query.where(
(advance.docstatus == 1)
& (advance.employee == employee)
& (advance.paid_amount > 0)
& (advance.status.notin(["Claimed", "Returned", "Partly Claimed and Returned"]))
)
else:
query = query.where(advance.name == advance_id)
return query.run(as_dict=True)
@frappe.whitelist()

View File

@ -1,15 +1,15 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.utils import add_months, today
from erpnext import get_company_currency
from erpnext.tests.utils import ERPNextTestCase
from .blanket_order import make_order
class TestBlanketOrder(ERPNextTestCase):
class TestBlanketOrder(FrappeTestCase):
def setUp(self):
frappe.flags.args = frappe._dict()

View File

@ -918,7 +918,7 @@ def validate_bom_no(item, bom_no):
frappe.throw(_("BOM {0} does not belong to Item {1}").format(bom_no, item))
@frappe.whitelist()
def get_children(doctype, parent=None, is_root=False, **filters):
def get_children(parent=None, is_root=False, **filters):
if not parent or parent=="BOM":
frappe.msgprint(_('Please select a BOM'))
return

View File

@ -7,6 +7,7 @@ from functools import partial
import frappe
from frappe.test_runner import make_test_records
from frappe.tests.utils import FrappeTestCase
from frappe.utils import cstr, flt
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
@ -17,11 +18,10 @@ from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import
create_stock_reconciliation,
)
from erpnext.tests.test_subcontracting import set_backflush_based_on
from erpnext.tests.utils import ERPNextTestCase
test_records = frappe.get_test_records('BOM')
class TestBOM(ERPNextTestCase):
class TestBOM(FrappeTestCase):
def setUp(self):
if not frappe.get_value('Item', '_Test Item'):
make_test_records('Item')

View File

@ -2,15 +2,15 @@
# License: GNU General Public License v3. See license.txt
import frappe
from frappe.tests.utils import FrappeTestCase
from erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool import update_cost
from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
from erpnext.stock.doctype.item.test_item import create_item
from erpnext.tests.utils import ERPNextTestCase
test_records = frappe.get_test_records('BOM')
class TestBOMUpdateTool(ERPNextTestCase):
class TestBOMUpdateTool(FrappeTestCase):
def test_replace_bom(self):
current_bom = "BOM-_Test Item Home Desktop Manufactured-001"

View File

@ -2,6 +2,7 @@
# See license.txt
import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.utils import random_string
from erpnext.manufacturing.doctype.job_card.job_card import OperationMismatchError, OverlapError
@ -11,10 +12,9 @@ from erpnext.manufacturing.doctype.job_card.job_card import (
from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record
from erpnext.manufacturing.doctype.workstation.test_workstation import make_workstation
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
from erpnext.tests.utils import ERPNextTestCase
class TestJobCard(ERPNextTestCase):
class TestJobCard(FrappeTestCase):
def setUp(self):
make_bom_for_jc_tests()

View File

@ -49,7 +49,7 @@ frappe.ui.form.on('Production Plan', {
if (d.item_code) {
return {
query: "erpnext.controllers.queries.bom",
filters:{'item': cstr(d.item_code)}
filters:{'item': cstr(d.item_code), 'docstatus': 1}
}
} else frappe.msgprint(__("Please enter Item first"));
}
@ -232,7 +232,7 @@ frappe.ui.form.on('Production Plan', {
});
},
combine_items: function (frm) {
frm.clear_table('prod_plan_references');
frm.clear_table("prod_plan_references");
frappe.call({
method: "get_items",
@ -247,6 +247,13 @@ frappe.ui.form.on('Production Plan', {
});
},
combine_sub_items: (frm) => {
if (frm.doc.sub_assembly_items.length > 0) {
frm.clear_table("sub_assembly_items");
frm.trigger("get_sub_assembly_items");
}
},
get_sub_assembly_items: function(frm) {
frm.dirty();

View File

@ -36,6 +36,7 @@
"prod_plan_references",
"section_break_24",
"get_sub_assembly_items",
"combine_sub_items",
"sub_assembly_items",
"material_request_planning",
"include_non_stock_items",
@ -340,7 +341,6 @@
{
"fieldname": "prod_plan_references",
"fieldtype": "Table",
"hidden": 1,
"label": "Production Plan Item Reference",
"options": "Production Plan Item Reference"
},
@ -370,16 +370,23 @@
"fieldname": "to_delivery_date",
"fieldtype": "Date",
"label": "To Delivery Date"
},
{
"default": "0",
"fieldname": "combine_sub_items",
"fieldtype": "Check",
"label": "Consolidate Sub Assembly Items"
}
],
"icon": "fa fa-calendar",
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2021-09-06 18:35:59.642232",
"modified": "2022-02-23 17:16:10.629378",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Production Plan",
"naming_rule": "By \"Naming Series\" field",
"owner": "Administrator",
"permissions": [
{

View File

@ -21,7 +21,8 @@ from frappe.utils import (
)
from frappe.utils.csvutils import build_csv_response
from erpnext.manufacturing.doctype.bom.bom import get_children, validate_bom_no
from erpnext.manufacturing.doctype.bom.bom import get_children as get_bom_children
from erpnext.manufacturing.doctype.bom.bom import validate_bom_no
from erpnext.manufacturing.doctype.work_order.work_order import get_item_details
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
@ -570,17 +571,28 @@ class ProductionPlan(Document):
@frappe.whitelist()
def get_sub_assembly_items(self, manufacturing_type=None):
"Fetch sub assembly items and optionally combine them."
self.sub_assembly_items = []
sub_assembly_items_store = [] # temporary store to process all subassembly items
for row in self.po_items:
bom_data = []
get_sub_assembly_items(row.bom_no, bom_data, row.planned_qty)
self.set_sub_assembly_items_based_on_level(row, bom_data, manufacturing_type)
sub_assembly_items_store.extend(bom_data)
self.sub_assembly_items.sort(key= lambda d: d.bom_level, reverse=True)
for idx, row in enumerate(self.sub_assembly_items, start=1):
row.idx = idx
if self.combine_sub_items:
# Combine subassembly items
sub_assembly_items_store = self.combine_subassembly_items(sub_assembly_items_store)
sub_assembly_items_store.sort(key= lambda d: d.bom_level, reverse=True) # sort by bom level
for idx, row in enumerate(sub_assembly_items_store):
row.idx = idx + 1
self.append("sub_assembly_items", row)
def set_sub_assembly_items_based_on_level(self, row, bom_data, manufacturing_type=None):
"Modify bom_data, set additional details."
for data in bom_data:
data.qty = data.stock_qty
data.production_plan_item = row.name
@ -589,7 +601,32 @@ class ProductionPlan(Document):
data.type_of_manufacturing = manufacturing_type or ("Subcontract" if data.is_sub_contracted_item
else "In House")
self.append("sub_assembly_items", data)
def combine_subassembly_items(self, sub_assembly_items_store):
"Aggregate if same: Item, Warehouse, Inhouse/Outhouse Manu.g, BOM No."
key_wise_data = {}
for row in sub_assembly_items_store:
key = (
row.get("production_item"), row.get("fg_warehouse"),
row.get("bom_no"), row.get("type_of_manufacturing")
)
if key not in key_wise_data:
# intialise (item, wh, bom no, man.g type) wise dict
key_wise_data[key] = row
continue
existing_row = key_wise_data[key]
if existing_row:
# if row with same (item, wh, bom no, man.g type) key, merge
existing_row.qty += flt(row.qty)
existing_row.stock_qty += flt(row.stock_qty)
existing_row.bom_level = max(existing_row.bom_level, row.bom_level)
continue
else:
# add row with key
key_wise_data[key] = row
sub_assembly_items_store = [key_wise_data[key] for key in key_wise_data] # unpack into single level list
return sub_assembly_items_store
def all_items_completed(self):
all_items_produced = all(flt(d.planned_qty) - flt(d.produced_qty) < 0.000001
@ -1031,7 +1068,7 @@ def get_item_data(item_code):
}
def get_sub_assembly_items(bom_no, bom_data, to_produce_qty, indent=0):
data = get_children('BOM', parent = bom_no)
data = get_bom_children(parent=bom_no)
for d in data:
if d.expandable:
parent_item_code = frappe.get_cached_value("BOM", bom_no, "item")

View File

@ -1,6 +1,7 @@
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.utils import add_to_date, flt, now_datetime, nowdate
from erpnext.controllers.item_variant import create_variant
@ -16,10 +17,9 @@ from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import (
create_stock_reconciliation,
)
from erpnext.tests.utils import ERPNextTestCase
class TestProductionPlan(ERPNextTestCase):
class TestProductionPlan(FrappeTestCase):
def setUp(self):
for item in ['Test Production Item 1', 'Subassembly Item 1',
'Raw Material Item 1', 'Raw Material Item 2']:
@ -38,6 +38,9 @@ class TestProductionPlan(ERPNextTestCase):
if not frappe.db.get_value('BOM', {'item': item}):
make_bom(item = item, raw_materials = raw_materials)
def tearDown(self) -> None:
frappe.db.rollback()
def test_production_plan_mr_creation(self):
"Test if MRs are created for unavailable raw materials."
pln = create_production_plan(item_code='Test Production Item 1')
@ -110,7 +113,7 @@ class TestProductionPlan(ERPNextTestCase):
item_code='Test Production Item 1',
ignore_existing_ordered_qty=1
)
self.assertTrue(len(pln.mr_items), 1)
self.assertTrue(len(pln.mr_items))
self.assertTrue(flt(pln.mr_items[0].quantity), 1.0)
sr1.cancel()
@ -151,7 +154,7 @@ class TestProductionPlan(ERPNextTestCase):
use_multi_level_bom=0,
ignore_existing_ordered_qty=0
)
self.assertTrue(len(pln.mr_items), 0)
self.assertFalse(len(pln.mr_items))
sr1.cancel()
sr2.cancel()
@ -258,6 +261,51 @@ class TestProductionPlan(ERPNextTestCase):
pln.reload()
pln.cancel()
def test_production_plan_combine_subassembly(self):
"""
Test combining Sub assembly items belonging to the same BOM in Prod Plan.
1) Red-Car -> Wheel (sub assembly) > BOM-WHEEL-001
2) Green-Car -> Wheel (sub assembly) > BOM-WHEEL-001
"""
from erpnext.manufacturing.doctype.bom.test_bom import create_nested_bom
bom_tree_1 = {
"Red-Car": {"Wheel": {"Rubber": {}}}
}
bom_tree_2 = {
"Green-Car": {"Wheel": {"Rubber": {}}}
}
parent_bom_1 = create_nested_bom(bom_tree_1, prefix="")
parent_bom_2 = create_nested_bom(bom_tree_2, prefix="")
# make sure both boms use same subassembly bom
subassembly_bom = parent_bom_1.items[0].bom_no
frappe.db.set_value("BOM Item", parent_bom_2.items[0].name, "bom_no", subassembly_bom)
plan = create_production_plan(item_code="Red-Car", use_multi_level_bom=1, do_not_save=True)
plan.append("po_items", { # Add Green-Car to Prod Plan
'use_multi_level_bom': 1,
'item_code': "Green-Car",
'bom_no': frappe.db.get_value('Item', "Green-Car", 'default_bom'),
'planned_qty': 1,
'planned_start_date': now_datetime()
})
plan.get_sub_assembly_items()
self.assertTrue(len(plan.sub_assembly_items), 2)
plan.combine_sub_items = 1
plan.get_sub_assembly_items()
self.assertTrue(len(plan.sub_assembly_items), 1) # check if sub-assembly items merged
self.assertEqual(plan.sub_assembly_items[0].qty, 2.0)
self.assertEqual(plan.sub_assembly_items[0].stock_qty, 2.0)
# change warehouse in one row, sub-assemblies should not merge
plan.po_items[0].warehouse = "Finished Goods - _TC"
plan.get_sub_assembly_items()
self.assertTrue(len(plan.sub_assembly_items), 2)
def test_pp_to_mr_customer_provided(self):
" Test Material Request from Production Plan for Customer Provided Item."
create_item('CUST-0987', is_customer_provided_item = 1, customer = '_Test Customer', is_purchase_item = 0)
@ -532,6 +580,7 @@ class TestProductionPlan(ERPNextTestCase):
wip_warehouse='Work In Progress - _TC',
fg_warehouse='Finished Goods - _TC',
skip_transfer=1,
use_multi_level_bom=1,
do_not_submit=True
)
wo.production_plan = pln.name
@ -576,6 +625,7 @@ class TestProductionPlan(ERPNextTestCase):
wip_warehouse='Work In Progress - _TC',
fg_warehouse='Finished Goods - _TC',
skip_transfer=1,
use_multi_level_bom=1,
do_not_submit=True
)
wo.production_plan = pln.name

View File

@ -2,14 +2,14 @@
# See license.txt
import frappe
from frappe.test_runner import make_test_records
from frappe.tests.utils import FrappeTestCase
from erpnext.manufacturing.doctype.job_card.job_card import OperationSequenceError
from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record
from erpnext.stock.doctype.item.test_item import make_item
from erpnext.tests.utils import ERPNextTestCase
class TestRouting(ERPNextTestCase):
class TestRouting(FrappeTestCase):
@classmethod
def setUpClass(cls):
cls.item_code = "Test Routing Item - A"

View File

@ -2,6 +2,7 @@
# License: GNU General Public License v3. See license.txt
import frappe
from frappe.tests.utils import FrappeTestCase, timeout
from frappe.utils import add_days, add_months, cint, flt, now, today
from erpnext.manufacturing.doctype.job_card.job_card import JobCardCancelError
@ -21,10 +22,9 @@ from erpnext.stock.doctype.item.test_item import create_item, make_item
from erpnext.stock.doctype.stock_entry import test_stock_entry
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
from erpnext.stock.utils import get_bin
from erpnext.tests.utils import ERPNextTestCase, timeout
class TestWorkOrder(ERPNextTestCase):
class TestWorkOrder(FrappeTestCase):
def setUp(self):
self.warehouse = '_Test Warehouse 2 - _TC'
self.item = '_Test Item'
@ -1040,7 +1040,7 @@ def make_wo_order_test_record(**args):
wo_order.scrap_warehouse = args.fg_warehouse or "_Test Scrap Warehouse - _TC"
wo_order.company = args.company or "_Test Company"
wo_order.stock_uom = args.stock_uom or "_Test UOM"
wo_order.use_multi_level_bom=0
wo_order.use_multi_level_bom= args.use_multi_level_bom or 0
wo_order.skip_transfer=args.skip_transfer or 0
wo_order.get_items_and_operations_from_bom()
wo_order.sales_order = args.sales_order or None

View File

@ -854,7 +854,7 @@ def get_item_details(item, project = None, skip_bom_info=False):
res = res[0]
if skip_bom_info: return res
filters = {"item": item, "is_default": 1}
filters = {"item": item, "is_default": 1, "docstatus": 1}
if project:
filters = {"item": item, "project": project}

View File

@ -2,6 +2,7 @@
# See license.txt
import frappe
from frappe.test_runner import make_test_records
from frappe.tests.utils import FrappeTestCase
from erpnext.manufacturing.doctype.operation.test_operation import make_operation
from erpnext.manufacturing.doctype.routing.test_routing import create_routing, setup_bom
@ -10,13 +11,12 @@ from erpnext.manufacturing.doctype.workstation.workstation import (
WorkstationHolidayError,
check_if_within_operating_hours,
)
from erpnext.tests.utils import ERPNextTestCase
test_dependencies = ["Warehouse"]
test_records = frappe.get_test_records('Workstation')
make_test_records('Workstation')
class TestWorkstation(ERPNextTestCase):
class TestWorkstation(FrappeTestCase):
def test_validate_timings(self):
check_if_within_operating_hours("_Test Workstation 1", "Operation 1", "2013-02-02 11:00:00", "2013-02-02 19:00:00")
check_if_within_operating_hours("_Test Workstation 1", "Operation 1", "2013-02-02 10:00:00", "2013-02-02 20:00:00")

View File

@ -356,4 +356,5 @@ erpnext.patches.v14_0.delete_amazon_mws_doctype
erpnext.patches.v13_0.set_work_order_qty_in_so_from_mr
erpnext.patches.v13_0.update_accounts_in_loan_docs
erpnext.patches.v14_0.update_batch_valuation_flag
erpnext.patches.v14_0.delete_non_profit_doctypes
erpnext.patches.v14_0.delete_non_profit_doctypes
erpnext.patches.v14_0.update_employee_advance_status

View File

@ -0,0 +1,26 @@
import frappe
def execute():
frappe.reload_doc('hr', 'doctype', 'employee_advance')
advance = frappe.qb.DocType('Employee Advance')
(frappe.qb
.update(advance)
.set(advance.status, 'Returned')
.where(
(advance.docstatus == 1)
& ((advance.return_amount) & (advance.paid_amount == advance.return_amount))
& (advance.status == 'Paid')
)
).run()
(frappe.qb
.update(advance)
.set(advance.status, 'Partly Claimed and Returned')
.where(
(advance.docstatus == 1)
& ((advance.claimed_amount & advance.return_amount) & (advance.paid_amount == (advance.return_amount + advance.claimed_amount)))
& (advance.status == 'Paid')
)
).run()

View File

@ -105,6 +105,8 @@ class AdditionalSalary(Document):
return_amount += self.amount
frappe.db.set_value("Employee Advance", self.ref_docname, "return_amount", return_amount)
advance = frappe.get_doc("Employee Advance", self.ref_docname)
advance.set_status(update=True)
def update_employee_referral(self, cancel=False):
if self.ref_doctype == "Employee Referral":

View File

@ -4,12 +4,13 @@
import frappe
from frappe.test_runner import make_test_records
from frappe.tests.utils import FrappeTestCase
from frappe.utils import flt
from erpnext.accounts.party import get_due_date
from erpnext.exceptions import PartyDisabled, PartyFrozen
from erpnext.selling.doctype.customer.customer import get_credit_limit, get_customer_outstanding
from erpnext.tests.utils import ERPNextTestCase, create_test_contact_and_address
from erpnext.tests.utils import create_test_contact_and_address
test_ignore = ["Price List"]
test_dependencies = ['Payment Term', 'Payment Terms Template']
@ -17,7 +18,7 @@ test_records = frappe.get_test_records('Customer')
class TestCustomer(ERPNextTestCase):
class TestCustomer(FrappeTestCase):
def setUp(self):
if not frappe.get_value('Item', '_Test Item'):
make_test_records('Item')

View File

@ -1,12 +1,10 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import unittest
import frappe
from frappe.tests.utils import FrappeTestCase
from erpnext.controllers.queries import item_query
from erpnext.tests.utils import ERPNextTestCase
test_dependencies = ['Item', 'Customer', 'Supplier']
@ -18,7 +16,7 @@ def create_party_specific_item(**args):
psi.based_on_value = args.get('based_on_value')
psi.insert()
class TestPartySpecificItem(ERPNextTestCase):
class TestPartySpecificItem(FrappeTestCase):
def setUp(self):
self.customer = frappe.get_last_doc("Customer")
self.supplier = frappe.get_last_doc("Supplier")

View File

@ -2,14 +2,13 @@
# License: GNU General Public License v3. See license.txt
import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.utils import add_days, add_months, flt, getdate, nowdate
from erpnext.tests.utils import ERPNextTestCase
test_dependencies = ["Product Bundle"]
class TestQuotation(ERPNextTestCase):
class TestQuotation(FrappeTestCase):
def test_make_quotation_without_terms(self):
quotation = make_quotation(do_not_save=1)
self.assertFalse(quotation.get('payment_schedule'))

View File

@ -6,6 +6,7 @@ import json
import frappe
import frappe.permissions
from frappe.core.doctype.user_permission.test_user_permission import create_user
from frappe.tests.utils import FrappeTestCase
from frappe.utils import add_days, flt, getdate, nowdate, today
from erpnext.controllers.accounts_controller import update_child_qty_rate
@ -27,10 +28,9 @@ from erpnext.selling.doctype.sales_order.sales_order import (
)
from erpnext.stock.doctype.item.test_item import make_item
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
from erpnext.tests.utils import ERPNextTestCase
class TestSalesOrder(ERPNextTestCase):
class TestSalesOrder(FrappeTestCase):
@classmethod
def setUpClass(cls):

View File

@ -83,8 +83,8 @@
"planned_qty",
"column_break_69",
"work_order_qty",
"produced_qty",
"delivered_qty",
"produced_qty",
"returned_qty",
"shopping_cart_section",
"additional_notes",
@ -701,8 +701,10 @@
"width": "50px"
},
{
"description": "For Production",
"fieldname": "produced_qty",
"fieldtype": "Float",
"hidden": 1,
"label": "Produced Quantity",
"oldfieldname": "produced_qty",
"oldfieldtype": "Currency",
@ -791,6 +793,7 @@
},
{
"default": "0",
"fetch_from": "item_code.grant_commission",
"fieldname": "grant_commission",
"fieldtype": "Check",
"label": "Grant Commission",
@ -800,7 +803,7 @@
"idx": 1,
"istable": 1,
"links": [],
"modified": "2022-02-21 13:55:08.883104",
"modified": "2022-02-24 14:41:57.325799",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order Item",

View File

@ -1,6 +1,7 @@
import datetime
import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.utils import add_days
from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice
@ -9,12 +10,11 @@ from erpnext.selling.report.payment_terms_status_for_sales_order.payment_terms_s
execute,
)
from erpnext.stock.doctype.item.test_item import create_item
from erpnext.tests.utils import ERPNextTestCase
test_dependencies = ["Sales Order", "Item", "Sales Invoice", "Payment Terms Template"]
class TestPaymentTermsStatusForSalesOrder(ERPNextTestCase):
class TestPaymentTermsStatusForSalesOrder(FrappeTestCase):
def create_payment_terms_template(self):
# create template for 50-50 payments
template = None

View File

@ -2,6 +2,7 @@
# For license information, please see license.txt
from frappe.tests.utils import FrappeTestCase
from frappe.utils import add_months, nowdate
from erpnext.selling.doctype.sales_order.sales_order import make_material_request
@ -9,10 +10,9 @@ from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_orde
from erpnext.selling.report.pending_so_items_for_purchase_request.pending_so_items_for_purchase_request import (
execute,
)
from erpnext.tests.utils import ERPNextTestCase
class TestPendingSOItemsForPurchaseRequest(ERPNextTestCase):
class TestPendingSOItemsForPurchaseRequest(FrappeTestCase):
def test_result_for_partial_material_request(self):
so = make_sales_order()
mr=make_material_request(so.name)

View File

@ -3,13 +3,13 @@
import frappe
from frappe.tests.utils import FrappeTestCase
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
from erpnext.selling.report.sales_analytics.sales_analytics import execute
from erpnext.tests.utils import ERPNextTestCase
class TestAnalytics(ERPNextTestCase):
class TestAnalytics(FrappeTestCase):
def test_sales_analytics(self):
frappe.db.sql("delete from `tabSales Order` where company='_Test Company 2'")

View File

@ -213,7 +213,14 @@ erpnext.stock.move_item = function (item, source, target, actual_qty, rate, call
label: __('Target Warehouse'),
fieldtype: 'Link',
options: 'Warehouse',
reqd: 1
reqd: 1,
get_query() {
return {
filters: {
is_group: 0
}
}
}
},
{
fieldname: 'qty',
@ -252,52 +259,21 @@ erpnext.stock.move_item = function (item, source, target, actual_qty, rate, call
dialog.get_field('target').refresh();
}
dialog.set_primary_action(__('Submit'), function () {
var values = dialog.get_values();
if (!values) {
return;
}
if (source && values.qty > actual_qty) {
frappe.msgprint(__('Quantity must be less than or equal to {0}', [actual_qty]));
return;
}
if (values.source === values.target) {
frappe.msgprint(__('Source and target warehouse must be different'));
}
frappe.call({
method: 'erpnext.stock.doctype.stock_entry.stock_entry_utils.make_stock_entry',
args: values,
btn: dialog.get_primary_btn(),
freeze: true,
freeze_message: __('Creating Stock Entry'),
callback: function (r) {
frappe.show_alert(__('Stock Entry {0} created',
['<a href="/app/stock-entry/' + r.message.name + '">' + r.message.name + '</a>']));
dialog.hide();
callback(r);
},
dialog.set_primary_action(__('Create Stock Entry'), function () {
frappe.model.with_doctype('Stock Entry', function () {
let doc = frappe.model.get_new_doc('Stock Entry');
doc.from_warehouse = dialog.get_value('source');
doc.to_warehouse = dialog.get_value('target');
doc.stock_entry_type = doc.from_warehouse ? "Material Transfer" : "Material Receipt";
let row = frappe.model.add_child(doc, 'items');
row.item_code = dialog.get_value('item_code');
row.s_warehouse = dialog.get_value('source');
row.t_warehouse = dialog.get_value('target');
row.qty = dialog.get_value('qty');
row.conversion_factor = 1;
row.transfer_qty = dialog.get_value('qty');
row.basic_rate = dialog.get_value('rate');
frappe.set_route('Form', doc.doctype, doc.name);
});
});
$('<p style="margin-left: 10px;"><a class="link-open text-muted small">' +
__("Add more items or open full form") + '</a></p>')
.appendTo(dialog.body)
.find('.link-open')
.on('click', function () {
frappe.model.with_doctype('Stock Entry', function () {
var doc = frappe.model.get_new_doc('Stock Entry');
doc.from_warehouse = dialog.get_value('source');
doc.to_warehouse = dialog.get_value('target');
var row = frappe.model.add_child(doc, 'items');
row.item_code = dialog.get_value('item_code');
row.f_warehouse = dialog.get_value('target');
row.t_warehouse = dialog.get_value('target');
row.qty = dialog.get_value('qty');
row.conversion_factor = 1;
row.transfer_qty = dialog.get_value('qty');
row.basic_rate = dialog.get_value('rate');
frappe.set_route('Form', doc.doctype, doc.name);
});
});
};

View File

@ -5,6 +5,7 @@ import json
import frappe
from frappe.exceptions import ValidationError
from frappe.tests.utils import FrappeTestCase
from frappe.utils import cint, flt
from frappe.utils.data import add_to_date, getdate
@ -16,10 +17,9 @@ from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import
)
from erpnext.stock.get_item_details import get_item_details
from erpnext.stock.stock_ledger import get_valuation_rate
from erpnext.tests.utils import ERPNextTestCase
class TestBatch(ERPNextTestCase):
class TestBatch(FrappeTestCase):
def test_item_has_batch_enabled(self):
self.assertRaises(ValidationError, frappe.get_doc({
"doctype": "Batch",

View File

@ -2,13 +2,13 @@
# See license.txt
import frappe
from frappe.tests.utils import FrappeTestCase
from erpnext.stock.doctype.item.test_item import make_item
from erpnext.stock.utils import _create_bin
from erpnext.tests.utils import ERPNextTestCase
class TestBin(ERPNextTestCase):
class TestBin(FrappeTestCase):
def test_concurrent_inserts(self):

View File

@ -6,6 +6,7 @@
import json
import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.utils import cstr, flt, nowdate, nowtime
from erpnext.accounts.doctype.account.test_account import get_inventory_account
@ -35,10 +36,9 @@ from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import
)
from erpnext.stock.doctype.warehouse.test_warehouse import get_warehouse
from erpnext.stock.stock_ledger import get_previous_sle
from erpnext.tests.utils import ERPNextTestCase
class TestDeliveryNote(ERPNextTestCase):
class TestDeliveryNote(FrappeTestCase):
def test_over_billing_against_dn(self):
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)

View File

@ -757,6 +757,7 @@
},
{
"default": "0",
"fetch_from": "item_code.grant_commission",
"fieldname": "grant_commission",
"fieldtype": "Check",
"label": "Grant Commission",
@ -767,12 +768,14 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2021-10-06 12:12:44.018872",
"modified": "2022-02-24 14:42:20.211085",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note Item",
"naming_rule": "Random",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC"
}
"sort_order": "DESC",
"states": []
}

View File

@ -4,6 +4,7 @@
import unittest
import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.utils import add_days, flt, now_datetime, nowdate
import erpnext
@ -12,10 +13,10 @@ from erpnext.stock.doctype.delivery_trip.delivery_trip import (
make_expense_claim,
notify_customers,
)
from erpnext.tests.utils import ERPNextTestCase, create_test_contact_and_address
from erpnext.tests.utils import create_test_contact_and_address
class TestDeliveryTrip(ERPNextTestCase):
class TestDeliveryTrip(FrappeTestCase):
def setUp(self):
super().setUp()
driver = create_driver()

View File

@ -6,6 +6,7 @@ import json
import frappe
from frappe.test_runner import make_test_objects
from frappe.tests.utils import FrappeTestCase, change_settings
from frappe.utils import add_days, today
from erpnext.controllers.item_variant import (
@ -25,7 +26,6 @@ from erpnext.stock.doctype.item.item import (
)
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
from erpnext.stock.get_item_details import get_item_details
from erpnext.tests.utils import ERPNextTestCase, change_settings
test_ignore = ["BOM"]
test_dependencies = ["Warehouse", "Item Group", "Item Tax Template", "Brand", "Item Attribute"]
@ -53,7 +53,7 @@ def make_item(item_code, properties=None):
return item
class TestItem(ERPNextTestCase):
class TestItem(FrappeTestCase):
def setUp(self):
super().setUp()
frappe.flags.attribute_values = None

View File

@ -4,6 +4,7 @@
import json
import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.utils import flt
from erpnext.buying.doctype.purchase_order.purchase_order import (
@ -18,10 +19,9 @@ from erpnext.stock.doctype.item.test_item import create_item
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import (
create_stock_reconciliation,
)
from erpnext.tests.utils import ERPNextTestCase
class TestItemAlternative(ERPNextTestCase):
class TestItemAlternative(FrappeTestCase):
def setUp(self):
super().setUp()
make_items()

View File

@ -6,11 +6,12 @@ import frappe
test_records = frappe.get_test_records('Item Attribute')
from frappe.tests.utils import FrappeTestCase
from erpnext.stock.doctype.item_attribute.item_attribute import ItemAttributeIncrementError
from erpnext.tests.utils import ERPNextTestCase
class TestItemAttribute(ERPNextTestCase):
class TestItemAttribute(FrappeTestCase):
def setUp(self):
super().setUp()
if frappe.db.exists("Item Attribute", "_Test_Length"):

View File

@ -4,13 +4,13 @@
import frappe
from frappe.test_runner import make_test_records_for_doctype
from frappe.tests.utils import FrappeTestCase
from erpnext.stock.doctype.item_price.item_price import ItemPriceDuplicateItem
from erpnext.stock.get_item_details import get_price_list_rate_for, process_args
from erpnext.tests.utils import ERPNextTestCase
class TestItemPrice(ERPNextTestCase):
class TestItemPrice(FrappeTestCase):
def setUp(self):
super().setUp()
frappe.db.sql("delete from `tabItem Price`")

View File

@ -4,6 +4,7 @@
import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.utils import add_to_date, flt, now
from erpnext.accounts.doctype.account.test_account import create_account, get_inventory_account
@ -14,10 +15,9 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import (
get_gl_entries,
make_purchase_receipt,
)
from erpnext.tests.utils import ERPNextTestCase
class TestLandedCostVoucher(ERPNextTestCase):
class TestLandedCostVoucher(FrappeTestCase):
def test_landed_cost_voucher(self):
frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1)

View File

@ -6,6 +6,7 @@
import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.utils import flt, today
from erpnext.stock.doctype.item.test_item import create_item
@ -15,10 +16,9 @@ from erpnext.stock.doctype.material_request.material_request import (
make_supplier_quotation,
raise_work_orders,
)
from erpnext.tests.utils import ERPNextTestCase
class TestMaterialRequest(ERPNextTestCase):
class TestMaterialRequest(FrappeTestCase):
def test_make_purchase_order(self):
mr = frappe.copy_doc(test_records[0]).insert()

View File

@ -1,6 +1,7 @@
# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from frappe.tests.utils import FrappeTestCase, change_settings
from frappe.utils import add_to_date, nowdate
from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle
@ -9,10 +10,9 @@ from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_orde
from erpnext.stock.doctype.item.test_item import make_item
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import get_gl_entries
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
from erpnext.tests.utils import ERPNextTestCase, change_settings
class TestPackedItem(ERPNextTestCase):
class TestPackedItem(FrappeTestCase):
"Test impact on Packed Items table in various scenarios."
@classmethod
def setUpClass(cls) -> None:

View File

@ -4,7 +4,7 @@
import unittest
# test_records = frappe.get_test_records('Packing Slip')
from erpnext.tests.utils import ERPNextTestCase
from frappe.tests.utils import FrappeTestCase
class TestPackingSlip(unittest.TestCase):

View File

@ -6,16 +6,17 @@ from frappe import _dict
test_dependencies = ['Item', 'Sales Invoice', 'Stock Entry', 'Batch']
from frappe.tests.utils import FrappeTestCase
from erpnext.stock.doctype.item.test_item import create_item
from erpnext.stock.doctype.pick_list.pick_list import create_delivery_note
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import (
EmptyStockReconciliationItemsError,
)
from erpnext.tests.utils import ERPNextTestCase
class TestPickList(ERPNextTestCase):
class TestPickList(FrappeTestCase):
def test_pick_list_picks_warehouse_for_each_item(self):
try:

View File

@ -7,6 +7,7 @@ import unittest
from collections import defaultdict
import frappe
from frappe.tests.utils import FrappeTestCase, change_settings
from frappe.utils import add_days, cint, cstr, flt, today
import erpnext
@ -17,10 +18,9 @@ from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchas
from erpnext.stock.doctype.serial_no.serial_no import SerialNoDuplicateError, get_serial_nos
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
from erpnext.stock.stock_ledger import SerialNoExistsInFutureTransaction
from erpnext.tests.utils import ERPNextTestCase, change_settings
class TestPurchaseReceipt(ERPNextTestCase):
class TestPurchaseReceipt(FrappeTestCase):
def setUp(self):
frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1)

View File

@ -2,6 +2,7 @@
# See license.txt
import frappe
from frappe.tests.utils import FrappeTestCase
from erpnext.stock.doctype.batch.test_batch import make_new_batch
from erpnext.stock.doctype.item.test_item import make_item
@ -9,10 +10,9 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_pu
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
from erpnext.stock.get_item_details import get_conversion_factor
from erpnext.tests.utils import ERPNextTestCase
class TestPutawayRule(ERPNextTestCase):
class TestPutawayRule(FrappeTestCase):
def setUp(self):
if not frappe.db.exists("Item", "_Rice"):
make_item("_Rice", {

View File

@ -2,6 +2,7 @@
# See license.txt
import frappe
from frappe.tests.utils import FrappeTestCase
from frappe.utils import nowdate
from erpnext.controllers.stock_controller import (
@ -13,12 +14,11 @@ from erpnext.controllers.stock_controller import (
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
from erpnext.stock.doctype.item.test_item import create_item
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
from erpnext.tests.utils import ERPNextTestCase
# test_records = frappe.get_test_records('Quality Inspection')
class TestQualityInspection(ERPNextTestCase):
class TestQualityInspection(FrappeTestCase):
def setUp(self):
super().setUp()
create_item("_Test Item with QA")

View File

@ -18,11 +18,12 @@ from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
test_dependencies = ["Item"]
test_records = frappe.get_test_records('Serial No')
from frappe.tests.utils import FrappeTestCase
from erpnext.stock.doctype.serial_no.serial_no import *
from erpnext.tests.utils import ERPNextTestCase
class TestSerialNo(ERPNextTestCase):
class TestSerialNo(FrappeTestCase):
def tearDown(self):
frappe.db.rollback()

View File

@ -4,12 +4,12 @@
from datetime import date, timedelta
import frappe
from frappe.tests.utils import FrappeTestCase
from erpnext.stock.doctype.delivery_note.delivery_note import make_shipment
from erpnext.tests.utils import ERPNextTestCase
class TestShipment(ERPNextTestCase):
class TestShipment(FrappeTestCase):
def test_shipment_from_delivery_note(self):
delivery_note = create_test_delivery_note()
delivery_note.submit()

View File

@ -6,6 +6,7 @@ import unittest
import frappe
from frappe.permissions import add_user_permission, remove_user_permission
from frappe.tests.utils import FrappeTestCase, change_settings
from frappe.utils import flt, nowdate, nowtime
from erpnext.accounts.doctype.account.test_account import get_inventory_account
@ -28,7 +29,6 @@ from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import
create_stock_reconciliation,
)
from erpnext.stock.stock_ledger import NegativeStockError, get_previous_sle
from erpnext.tests.utils import ERPNextTestCase, change_settings
def get_sle(**args):
@ -42,7 +42,7 @@ def get_sle(**args):
order by timestamp(posting_date, posting_time) desc, creation desc limit 1"""% condition,
values, as_dict=1)
class TestStockEntry(ERPNextTestCase):
class TestStockEntry(FrappeTestCase):
def tearDown(self):
frappe.db.rollback()
frappe.set_user("Administrator")

View File

@ -7,6 +7,7 @@ from uuid import uuid4
import frappe
from frappe.core.page.permission_manager.permission_manager import reset
from frappe.tests.utils import FrappeTestCase
from frappe.utils import add_days, today
from erpnext.stock.doctype.delivery_note.test_delivery_note import (
@ -24,10 +25,9 @@ from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import
create_stock_reconciliation,
)
from erpnext.stock.stock_ledger import get_previous_sle
from erpnext.tests.utils import ERPNextTestCase
class TestStockLedgerEntry(ERPNextTestCase):
class TestStockLedgerEntry(FrappeTestCase):
def setUp(self):
items = create_items()
reset('Stock Entry')

View File

@ -6,6 +6,7 @@
import frappe
from frappe.tests.utils import FrappeTestCase, change_settings
from frappe.utils import add_days, cstr, flt, nowdate, nowtime, random_string
from erpnext.accounts.utils import get_stock_and_account_balance
@ -19,10 +20,9 @@ from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import (
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
from erpnext.stock.stock_ledger import get_previous_sle, update_entries_after
from erpnext.stock.utils import get_incoming_rate, get_stock_value_on, get_valuation_method
from erpnext.tests.utils import ERPNextTestCase, change_settings
class TestStockReconciliation(ERPNextTestCase):
class TestStockReconciliation(FrappeTestCase):
@classmethod
def setUpClass(cls):
create_batch_or_serial_no_items()

View File

@ -4,11 +4,10 @@
import unittest
import frappe
from erpnext.tests.utils import ERPNextTestCase
from frappe.tests.utils import FrappeTestCase
class TestStockSettings(ERPNextTestCase):
class TestStockSettings(FrappeTestCase):
def setUp(self):
super().setUp()
frappe.db.set_value("Stock Settings", None, "clean_description_html", 0)

View File

@ -3,17 +3,17 @@
import frappe
from frappe.test_runner import make_test_records
from frappe.tests.utils import FrappeTestCase
from frappe.utils import cint
import erpnext
from erpnext.accounts.doctype.account.test_account import create_account, get_inventory_account
from erpnext.stock.doctype.item.test_item import create_item
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
from erpnext.tests.utils import ERPNextTestCase
test_records = frappe.get_test_records('Warehouse')
class TestWarehouse(ERPNextTestCase):
class TestWarehouse(FrappeTestCase):
def setUp(self):
super().setUp()
if not frappe.get_value('Item', '_Test Item'):

View File

@ -244,7 +244,7 @@
"idx": 1,
"is_tree": 1,
"links": [],
"modified": "2021-12-03 04:40:06.414630",
"modified": "2022-03-01 02:37:48.034944",
"modified_by": "Administrator",
"module": "Stock",
"name": "Warehouse",
@ -301,5 +301,7 @@
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "warehouse_name"
"states": [],
"title_field": "warehouse_name",
"track_changes": 1
}

View File

@ -2,12 +2,12 @@
# See license.txt
import frappe
from frappe.tests.utils import FrappeTestCase
from erpnext.stock.report.stock_ageing.stock_ageing import FIFOSlots, format_report_data
from erpnext.tests.utils import ERPNextTestCase
class TestStockAgeing(ERPNextTestCase):
class TestStockAgeing(FrappeTestCase):
def setUp(self) -> None:
self.filters = frappe._dict(
company="_Test Company",
@ -610,4 +610,4 @@ def generate_item_and_item_wh_wise_slots(filters, sle):
item_wh_wise_slots = FIFOSlots(filters, sle).generate()
filters.show_warehouse_wise_stock = False
return item_wise_slots, item_wh_wise_slots
return item_wise_slots, item_wh_wise_slots

View File

@ -1,14 +1,13 @@
import datetime
import unittest
from frappe import _dict
from frappe.tests.utils import FrappeTestCase
from erpnext.accounts.utils import get_fiscal_year
from erpnext.stock.report.stock_analytics.stock_analytics import get_period_date_ranges
from erpnext.tests.utils import ERPNextTestCase
class TestStockAnalyticsReport(ERPNextTestCase):
class TestStockAnalyticsReport(FrappeTestCase):
def test_get_period_date_ranges(self):
filters = _dict(range="Monthly", from_date="2020-12-28", to_date="2021-02-06")

View File

@ -2,13 +2,13 @@ import json
import unittest
import frappe
from frappe.tests.utils import FrappeTestCase
from hypothesis import given
from hypothesis import strategies as st
from erpnext.stock.doctype.item.test_item import make_item
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
from erpnext.stock.valuation import FIFOValuation, LIFOValuation, round_off_if_near_zero
from erpnext.tests.utils import ERPNextTestCase
qty_gen = st.floats(min_value=-1e6, max_value=1e6)
value_gen = st.floats(min_value=1, max_value=1e6)
@ -290,7 +290,7 @@ class TestLIFOValuation(unittest.TestCase):
self.assertTotalQty(total_qty)
self.assertTotalValue(total_value)
class TestLIFOValuationSLE(ERPNextTestCase):
class TestLIFOValuationSLE(FrappeTestCase):
ITEM_CODE = "_Test LIFO item"
WAREHOUSE = "_Test Warehouse - _TC"

View File

@ -1,27 +1 @@
{% set domains = frappe.get_doc("Domain Settings").active_domains %}
{% set links = {
'Manufacturing': '/manufacturing',
'Services': '/services',
'Retail': '/retail',
'Distribution': '/distribution',
'Non Profit': '/non-profit',
'Education': '/education',
'Healthcare': '/healthcare',
'Agriculture': '/agriculture',
'Hospitality': ''
} %}
{% set link = '' %}
{% set label = '' %}
{% if domains %}
{% set label = domains[0].domain %}
{% set link = links[label] %}
{% endif %}
{% if label == "Services" %}
{% set label = "Service" %}
{% endif %}
<a href="https://erpnext.com{{ link }}?source=website_footer" target="_blank" class="text-muted">Powered by ERPNext - {{ '' if domains else 'Open Source' }} ERP Software {{ ('for ' + label + ' Companies') if domains else '' }}</a>
<a href="https://erpnext.com?source=website_footer" target="_blank" class="text-muted">Powered by ERPNext</a>

View File

@ -25,7 +25,7 @@ class TestPointOfSale(unittest.TestCase):
Test Stock and Service Item Search.
"""
pos_profile = make_pos_profile()
pos_profile = make_pos_profile(name="Test POS Profile for Search")
item1 = make_item("Test Search Stock Item", {"is_stock_item": 1})
make_stock_entry(
item_code="Test Search Stock Item",

View File

@ -1,10 +1,6 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
import copy
import signal
import unittest
from contextlib import contextmanager
from typing import Any, Dict, NewType, Optional
import frappe
@ -13,22 +9,6 @@ from frappe.core.doctype.report.report import get_report_module_dotted_path
ReportFilters = Dict[str, Any]
ReportName = NewType("ReportName", str)
class ERPNextTestCase(unittest.TestCase):
"""A sane default test class for ERPNext tests."""
@classmethod
def setUpClass(cls) -> None:
frappe.db.commit()
return super().setUpClass()
@classmethod
def tearDownClass(cls) -> None:
frappe.db.rollback()
return super().tearDownClass()
def create_test_contact_and_address():
frappe.db.sql('delete from tabContact')
frappe.db.sql('delete from `tabContact Email`')
@ -81,43 +61,6 @@ def create_test_contact_and_address():
contact_two.insert()
@contextmanager
def change_settings(doctype, settings_dict):
""" A context manager to ensure that settings are changed before running
function and restored after running it regardless of exceptions occured.
This is useful in tests where you want to make changes in a function but
don't retain those changes.
import and use as decorator to cover full function or using `with` statement.
example:
@change_settings("Stock Settings", {"item_naming_by": "Naming Series"})
def test_case(self):
...
"""
try:
settings = frappe.get_doc(doctype)
# remember setting
previous_settings = copy.deepcopy(settings_dict)
for key in previous_settings:
previous_settings[key] = getattr(settings, key)
# change setting
for key, value in settings_dict.items():
setattr(settings, key, value)
settings.save()
# singles are cached by default, clear to avoid flake
frappe.db.value_cache[settings] = {}
yield # yield control to calling function
finally:
# restore settings
settings = frappe.get_doc(doctype)
for key, value in previous_settings.items():
setattr(settings, key, value)
settings.save()
def execute_script_report(
report_name: ReportName,
module: str,
@ -157,24 +100,3 @@ def execute_script_report(
except Exception:
print(f"Report failed to execute with filters: {test_filter}")
raise
def timeout(seconds=30, error_message="Test timed out."):
""" Timeout decorator to ensure a test doesn't run for too long.
adapted from https://stackoverflow.com/a/2282656"""
def decorator(func):
def _handle_timeout(signum, frame):
raise Exception(error_message)
def wrapper(*args, **kwargs):
signal.signal(signal.SIGALRM, _handle_timeout)
signal.alarm(seconds)
try:
result = func(*args, **kwargs)
finally:
signal.alarm(0)
return result
return wrapper
return decorator