Merge branch 'develop' into invoice-sections

This commit is contained in:
Anuja Pawar 2021-10-12 21:32:01 +05:30 committed by GitHub
commit b7769c733e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 234 additions and 164 deletions

View File

@ -174,7 +174,7 @@
"default": "0", "default": "0",
"fieldname": "automatically_fetch_payment_terms", "fieldname": "automatically_fetch_payment_terms",
"fieldtype": "Check", "fieldtype": "Check",
"label": "Automatically Fetch Payment Terms" "label": "Automatically Fetch Payment Terms from Order"
}, },
{ {
"description": "The percentage you are allowed to bill more against the amount ordered. For example, if the order value is $100 for an item and tolerance is set as 10%, then you are allowed to bill up to $110 ", "description": "The percentage you are allowed to bill more against the amount ordered. For example, if the order value is $100 for an item and tolerance is set as 10%, then you are allowed to bill up to $110 ",
@ -282,7 +282,7 @@
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"issingle": 1, "issingle": 1,
"links": [], "links": [],
"modified": "2021-08-19 11:17:38.788054", "modified": "2021-10-11 17:42:36.427699",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Accounts Settings", "name": "Accounts Settings",

View File

@ -16,7 +16,7 @@ class LoyaltyPointEntry(Document):
def get_loyalty_point_entries(customer, loyalty_program, company, expiry_date=None): def get_loyalty_point_entries(customer, loyalty_program, company, expiry_date=None):
if not expiry_date: if not expiry_date:
date = today() expiry_date = today()
return frappe.db.sql(''' return frappe.db.sql('''
select name, loyalty_points, expiry_date, loyalty_program_tier, invoice_type, invoice select name, loyalty_points, expiry_date, loyalty_program_tier, invoice_type, invoice

View File

@ -712,10 +712,14 @@ class PaymentEntry(AccountsController):
dr_or_cr = "credit" if erpnext.get_party_account_type(self.party_type) == 'Receivable' else "debit" dr_or_cr = "credit" if erpnext.get_party_account_type(self.party_type) == 'Receivable' else "debit"
for d in self.get("references"): for d in self.get("references"):
cost_center = self.cost_center
if d.reference_doctype == "Sales Invoice" and not cost_center:
cost_center = frappe.db.get_value(d.reference_doctype, d.reference_name, "cost_center")
gle = party_gl_dict.copy() gle = party_gl_dict.copy()
gle.update({ gle.update({
"against_voucher_type": d.reference_doctype, "against_voucher_type": d.reference_doctype,
"against_voucher": d.reference_name "against_voucher": d.reference_name,
"cost_center": cost_center
}) })
allocated_amount_in_company_currency = flt(flt(d.allocated_amount) * flt(d.exchange_rate), allocated_amount_in_company_currency = flt(flt(d.allocated_amount) * flt(d.exchange_rate),

View File

@ -1087,8 +1087,6 @@ class TestSalesInvoice(unittest.TestCase):
actual_qty_1 = get_qty_after_transaction(item_code = "_Test Item", warehouse = "Stores - TCP1") actual_qty_1 = get_qty_after_transaction(item_code = "_Test Item", warehouse = "Stores - TCP1")
frappe.db.commit()
self.assertEqual(actual_qty_0 - 5, actual_qty_1) self.assertEqual(actual_qty_0 - 5, actual_qty_1)
# outgoing_rate # outgoing_rate

View File

@ -45,7 +45,6 @@ class TestProcurementTracker(unittest.TestCase):
pr = make_purchase_receipt(po.name) pr = make_purchase_receipt(po.name)
pr.get("items")[0].cost_center = "Main - _TPC" pr.get("items")[0].cost_center = "Main - _TPC"
pr.submit() pr.submit()
frappe.db.commit()
date_obj = datetime.date(datetime.now()) date_obj = datetime.date(datetime.now())
po.load_from_db() po.load_from_db()

View File

@ -591,7 +591,7 @@ def future_sle_exists(args, sl_entries=None):
data = frappe.db.sql(""" data = frappe.db.sql("""
select item_code, warehouse, count(name) as total_row select item_code, warehouse, count(name) as total_row
from `tabStock Ledger Entry` from `tabStock Ledger Entry` force index (item_warehouse)
where where
({}) ({})
and timestamp(posting_date, posting_time) and timestamp(posting_date, posting_time)

View File

@ -74,7 +74,6 @@ class TestDailyWorkSummary(unittest.TestCase):
from `tabEmail Queue` as q, `tabEmail Queue Recipient` as r \ from `tabEmail Queue` as q, `tabEmail Queue Recipient` as r \
where q.name = r.parent""", as_dict=1) where q.name = r.parent""", as_dict=1)
frappe.db.commit()
def setup_groups(self, hour=None): def setup_groups(self, hour=None):
# setup email to trigger at this hour # setup email to trigger at this hour

View File

@ -334,7 +334,6 @@
}, },
{ {
"depends_on": "eval:doc.is_secured_loan", "depends_on": "eval:doc.is_secured_loan",
"fetch_from": "loan_application.maximum_loan_amount",
"fieldname": "maximum_loan_amount", "fieldname": "maximum_loan_amount",
"fieldtype": "Currency", "fieldtype": "Currency",
"label": "Maximum Loan Amount", "label": "Maximum Loan Amount",
@ -360,7 +359,7 @@
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2021-04-19 18:10:32.360818", "modified": "2021-10-12 18:10:32.360818",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Loan Management", "module": "Loan Management",
"name": "Loan", "name": "Loan",

View File

@ -137,16 +137,23 @@ class Loan(AccountsController):
frappe.throw(_("Loan amount is mandatory")) frappe.throw(_("Loan amount is mandatory"))
def link_loan_security_pledge(self): def link_loan_security_pledge(self):
if self.is_secured_loan: if self.is_secured_loan and self.loan_application:
loan_security_pledge = frappe.db.get_value('Loan Security Pledge', {'loan_application': self.loan_application}, maximum_loan_value = frappe.db.get_value('Loan Security Pledge',
'name') {
'loan_application': self.loan_application,
'status': 'Requested'
},
'sum(maximum_loan_value)'
)
if loan_security_pledge: if maximum_loan_value:
frappe.db.set_value('Loan Security Pledge', loan_security_pledge, { frappe.db.sql("""
'loan': self.name, UPDATE `tabLoan Security Pledge`
'status': 'Pledged', SET loan = %s, pledge_time = %s, status = 'Pledged'
'pledge_time': now_datetime() WHERE status = 'Requested' and loan_application = %s
}) """, (self.name, now_datetime(), self.loan_application))
self.db_set('maximum_loan_amount', maximum_loan_value)
def unlink_loan_security_pledge(self): def unlink_loan_security_pledge(self):
pledges = frappe.get_all('Loan Security Pledge', fields=['name'], filters={'loan': self.name}) pledges = frappe.get_all('Loan Security Pledge', fields=['name'], filters={'loan': self.name})

View File

@ -131,9 +131,10 @@ def create_loan(source_name, target_doc=None, submit=0):
def update_accounts(source_doc, target_doc, source_parent): def update_accounts(source_doc, target_doc, source_parent):
account_details = frappe.get_all("Loan Type", account_details = frappe.get_all("Loan Type",
fields=["mode_of_payment", "payment_account","loan_account", "interest_income_account", "penalty_income_account"], fields=["mode_of_payment", "payment_account","loan_account", "interest_income_account", "penalty_income_account"],
filters = {'name': source_doc.loan_type} filters = {'name': source_doc.loan_type})[0]
)[0]
if source_doc.is_secured_loan:
target_doc.maximum_loan_amount = 0
target_doc.mode_of_payment = account_details.mode_of_payment target_doc.mode_of_payment = account_details.mode_of_payment
target_doc.payment_account = account_details.payment_account target_doc.payment_account = account_details.payment_account

View File

@ -198,7 +198,7 @@ def get_disbursal_amount(loan, on_current_security_price=0):
security_value = get_total_pledged_security_value(loan) security_value = get_total_pledged_security_value(loan)
if loan_details.is_secured_loan and not on_current_security_price: if loan_details.is_secured_loan and not on_current_security_price:
security_value = flt(loan_details.maximum_loan_amount) security_value = get_maximum_amount_as_per_pledged_security(loan)
if not security_value and not loan_details.is_secured_loan: if not security_value and not loan_details.is_secured_loan:
security_value = flt(loan_details.loan_amount) security_value = flt(loan_details.loan_amount)
@ -209,3 +209,6 @@ def get_disbursal_amount(loan, on_current_security_price=0):
disbursal_amount = loan_details.loan_amount - loan_details.disbursed_amount disbursal_amount = loan_details.loan_amount - loan_details.disbursed_amount
return disbursal_amount return disbursal_amount
def get_maximum_amount_as_per_pledged_security(loan):
return flt(frappe.db.get_value('Loan Security Pledge', {'loan': loan}, 'sum(maximum_loan_value)'))

View File

@ -411,7 +411,7 @@ def get_amounts(amounts, against_loan, posting_date):
if due_date and not final_due_date: if due_date and not final_due_date:
final_due_date = add_days(due_date, loan_type_details.grace_period_in_days) final_due_date = add_days(due_date, loan_type_details.grace_period_in_days)
if against_loan_doc.status in ('Disbursed', 'Loan Closure Requested', 'Closed'): if against_loan_doc.status in ('Disbursed', 'Closed') or against_loan_doc.disbursed_amount >= against_loan_doc.loan_amount:
pending_principal_amount = against_loan_doc.total_payment - against_loan_doc.total_principal_paid \ pending_principal_amount = against_loan_doc.total_payment - against_loan_doc.total_principal_paid \
- against_loan_doc.total_interest_payable - against_loan_doc.written_off_amount - against_loan_doc.total_interest_payable - against_loan_doc.written_off_amount
else: else:

View File

@ -299,7 +299,7 @@ erpnext.patches.v13_0.gst_fields_for_pos_invoice
erpnext.patches.v13_0.create_accounting_dimensions_in_pos_doctypes erpnext.patches.v13_0.create_accounting_dimensions_in_pos_doctypes
erpnext.patches.v13_0.trim_sales_invoice_custom_field_length erpnext.patches.v13_0.trim_sales_invoice_custom_field_length
erpnext.patches.v13_0.create_custom_field_for_finance_book erpnext.patches.v13_0.create_custom_field_for_finance_book
erpnext.patches.v13_0.modify_invalid_gain_loss_gl_entries erpnext.patches.v13_0.modify_invalid_gain_loss_gl_entries #2
erpnext.patches.v13_0.fix_additional_cost_in_mfg_stock_entry erpnext.patches.v13_0.fix_additional_cost_in_mfg_stock_entry
erpnext.patches.v13_0.set_status_in_maintenance_schedule_table erpnext.patches.v13_0.set_status_in_maintenance_schedule_table
erpnext.patches.v13_0.add_default_interview_notification_templates erpnext.patches.v13_0.add_default_interview_notification_templates

View File

@ -17,7 +17,7 @@ def execute():
where where
ref_exchange_rate = 1 ref_exchange_rate = 1
and docstatus = 1 and docstatus = 1
and ifnull(exchange_gain_loss, '') != '' and ifnull(exchange_gain_loss, 0) != 0
group by group by
parent parent
""", as_dict=1) """, as_dict=1)
@ -30,7 +30,7 @@ def execute():
where where
ref_exchange_rate = 1 ref_exchange_rate = 1
and docstatus = 1 and docstatus = 1
and ifnull(exchange_gain_loss, '') != '' and ifnull(exchange_gain_loss, 0) != 0
group by group by
parent parent
""", as_dict=1) """, as_dict=1)
@ -38,7 +38,12 @@ def execute():
if purchase_invoices + sales_invoices: if purchase_invoices + sales_invoices:
frappe.log_error(json.dumps(purchase_invoices + sales_invoices, indent=2), title="Patch Log") frappe.log_error(json.dumps(purchase_invoices + sales_invoices, indent=2), title="Patch Log")
acc_frozen_upto = frappe.db.get_value('Accounts Settings', None, 'acc_frozen_upto')
if acc_frozen_upto:
frappe.db.set_value('Accounts Settings', None, 'acc_frozen_upto', None)
for invoice in purchase_invoices + sales_invoices: for invoice in purchase_invoices + sales_invoices:
try:
doc = frappe.get_doc(invoice.type, invoice.name) doc = frappe.get_doc(invoice.type, invoice.name)
doc.docstatus = 2 doc.docstatus = 2
doc.make_gl_entries() doc.make_gl_entries()
@ -47,3 +52,10 @@ def execute():
advance.db_set('exchange_gain_loss', 0, False) advance.db_set('exchange_gain_loss', 0, False)
doc.docstatus = 1 doc.docstatus = 1
doc.make_gl_entries() doc.make_gl_entries()
frappe.db.commit()
except Exception:
frappe.db.rollback()
print(f'Failed to correct gl entries of {invoice.name}')
if acc_frozen_upto:
frappe.db.set_value('Accounts Settings', None, 'acc_frozen_upto', acc_frozen_upto)

View File

@ -2,7 +2,7 @@ import frappe
def execute(): def execute():
frappe.reload_doc('custom', 'doctype', 'custom_field') frappe.reload_doc('custom', 'doctype', 'custom_field', force=True)
company = frappe.get_all('Company', filters = {'country': 'India'}) company = frappe.get_all('Company', filters = {'country': 'India'})
if not company: if not company:
return return

View File

@ -1382,7 +1382,6 @@ def make_sales_order_workflow():
frappe.get_doc(dict(doctype='Role', role_name='Test Junior Approver')).insert(ignore_if_duplicate=True) frappe.get_doc(dict(doctype='Role', role_name='Test Junior Approver')).insert(ignore_if_duplicate=True)
frappe.get_doc(dict(doctype='Role', role_name='Test Approver')).insert(ignore_if_duplicate=True) frappe.get_doc(dict(doctype='Role', role_name='Test Approver')).insert(ignore_if_duplicate=True)
frappe.db.commit()
frappe.cache().hdel('roles', frappe.session.user) frappe.cache().hdel('roles', frappe.session.user)
workflow = frappe.get_doc({ workflow = frappe.get_doc({

View File

@ -44,7 +44,6 @@ class TestShoppingCartSettings(unittest.TestCase):
def test_tax_rule_validation(self): def test_tax_rule_validation(self):
frappe.db.sql("update `tabTax Rule` set use_for_shopping_cart = 0") frappe.db.sql("update `tabTax Rule` set use_for_shopping_cart = 0")
frappe.db.commit()
cart_settings = self.get_cart_settings() cart_settings = self.get_cart_settings()
cart_settings.enabled = 1 cart_settings.enabled = 1

View File

@ -1,8 +1,5 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe import frappe
from erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings import ( from erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings import (
@ -18,10 +15,19 @@ def show_cart_count():
return False return False
def set_cart_count(login_manager): def set_cart_count(login_manager):
role, parties = check_customer_or_supplier() # since this is run only on hooks login event
if role == 'Supplier': return # make sure user is already a customer
# before trying to set cart count
user_is_customer = is_customer()
if not user_is_customer:
return
if show_cart_count(): if show_cart_count():
from erpnext.shopping_cart.cart import set_cart_count from erpnext.shopping_cart.cart import set_cart_count
# set_cart_count will try to fetch existing cart quotation
# or create one if non existent (and create a customer too)
# cart count is calculated from this quotation's items
set_cart_count() set_cart_count()
def clear_cart_count(login_manager): def clear_cart_count(login_manager):
@ -32,13 +38,13 @@ def update_website_context(context):
cart_enabled = is_cart_enabled() cart_enabled = is_cart_enabled()
context["shopping_cart_enabled"] = cart_enabled context["shopping_cart_enabled"] = cart_enabled
def check_customer_or_supplier(): def is_customer():
if frappe.session.user: if frappe.session.user and frappe.session.user != "Guest":
contact_name = frappe.get_value("Contact", {"email_id": frappe.session.user}) contact_name = frappe.get_value("Contact", {"email_id": frappe.session.user})
if contact_name: if contact_name:
contact = frappe.get_doc('Contact', contact_name) contact = frappe.get_doc('Contact', contact_name)
for link in contact.links: for link in contact.links:
if link.link_doctype in ('Customer', 'Supplier'): if link.link_doctype == 'Customer':
return link.link_doctype, link.link_name return True
return 'Customer', None return False

View File

@ -1,8 +1,5 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import unittest
import frappe import frappe
from frappe.exceptions import ValidationError from frappe.exceptions import ValidationError
@ -11,9 +8,10 @@ from frappe.utils import cint, flt
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
from erpnext.stock.doctype.batch.batch import UnableToSelectBatchError, get_batch_no, get_batch_qty from erpnext.stock.doctype.batch.batch import UnableToSelectBatchError, get_batch_no, get_batch_qty
from erpnext.stock.get_item_details import get_item_details from erpnext.stock.get_item_details import get_item_details
from erpnext.tests.utils import ERPNextTestCase
class TestBatch(unittest.TestCase): class TestBatch(ERPNextTestCase):
def test_item_has_batch_enabled(self): def test_item_has_batch_enabled(self):
self.assertRaises(ValidationError, frappe.get_doc({ self.assertRaises(ValidationError, frappe.get_doc({
"doctype": "Batch", "doctype": "Batch",

View File

@ -14,51 +14,6 @@ class Bin(Document):
self.stock_uom = frappe.get_cached_value('Item', self.item_code, 'stock_uom') self.stock_uom = frappe.get_cached_value('Item', self.item_code, 'stock_uom')
self.set_projected_qty() self.set_projected_qty()
def update_stock(self, args, allow_negative_stock=False, via_landed_cost_voucher=False):
'''Called from erpnext.stock.utils.update_bin'''
self.update_qty(args)
if args.get("actual_qty") or args.get("voucher_type") == "Stock Reconciliation":
from erpnext.stock.stock_ledger import update_entries_after, update_qty_in_future_sle
if not args.get("posting_date"):
args["posting_date"] = nowdate()
if args.get("is_cancelled") and via_landed_cost_voucher:
return
# Reposts only current voucher SL Entries
# Updates valuation rate, stock value, stock queue for current transaction
update_entries_after({
"item_code": self.item_code,
"warehouse": self.warehouse,
"posting_date": args.get("posting_date"),
"posting_time": args.get("posting_time"),
"voucher_type": args.get("voucher_type"),
"voucher_no": args.get("voucher_no"),
"sle_id": args.name,
"creation": args.creation
}, allow_negative_stock=allow_negative_stock, via_landed_cost_voucher=via_landed_cost_voucher)
# update qty in future ale and Validate negative qty
update_qty_in_future_sle(args, allow_negative_stock)
def update_qty(self, args):
# update the stock values (for current quantities)
if args.get("voucher_type")=="Stock Reconciliation":
self.actual_qty = args.get("qty_after_transaction")
else:
self.actual_qty = flt(self.actual_qty) + flt(args.get("actual_qty"))
self.ordered_qty = flt(self.ordered_qty) + flt(args.get("ordered_qty"))
self.reserved_qty = flt(self.reserved_qty) + flt(args.get("reserved_qty"))
self.indented_qty = flt(self.indented_qty) + flt(args.get("indented_qty"))
self.planned_qty = flt(self.planned_qty) + flt(args.get("planned_qty"))
self.set_projected_qty()
self.db_update()
def set_projected_qty(self): def set_projected_qty(self):
self.projected_qty = (flt(self.actual_qty) + flt(self.ordered_qty) self.projected_qty = (flt(self.actual_qty) + flt(self.ordered_qty)
+ flt(self.indented_qty) + flt(self.planned_qty) - flt(self.reserved_qty) + flt(self.indented_qty) + flt(self.planned_qty) - flt(self.reserved_qty)
@ -143,3 +98,67 @@ class Bin(Document):
def on_doctype_update(): def on_doctype_update():
frappe.db.add_index("Bin", ["item_code", "warehouse"]) frappe.db.add_index("Bin", ["item_code", "warehouse"])
def update_stock(bin_name, args, allow_negative_stock=False, via_landed_cost_voucher=False):
'''Called from erpnext.stock.utils.update_bin'''
update_qty(bin_name, args)
if args.get("actual_qty") or args.get("voucher_type") == "Stock Reconciliation":
from erpnext.stock.stock_ledger import update_entries_after, update_qty_in_future_sle
if not args.get("posting_date"):
args["posting_date"] = nowdate()
if args.get("is_cancelled") and via_landed_cost_voucher:
return
# Reposts only current voucher SL Entries
# Updates valuation rate, stock value, stock queue for current transaction
update_entries_after({
"item_code": args.get('item_code'),
"warehouse": args.get('warehouse'),
"posting_date": args.get("posting_date"),
"posting_time": args.get("posting_time"),
"voucher_type": args.get("voucher_type"),
"voucher_no": args.get("voucher_no"),
"sle_id": args.get('name'),
"creation": args.get('creation')
}, allow_negative_stock=allow_negative_stock, via_landed_cost_voucher=via_landed_cost_voucher)
# update qty in future sle and Validate negative qty
update_qty_in_future_sle(args, allow_negative_stock)
def get_bin_details(bin_name):
return frappe.db.get_value('Bin', bin_name, ['actual_qty', 'ordered_qty',
'reserved_qty', 'indented_qty', 'planned_qty', 'reserved_qty_for_production',
'reserved_qty_for_sub_contract'], as_dict=1)
def update_qty(bin_name, args):
bin_details = get_bin_details(bin_name)
# update the stock values (for current quantities)
if args.get("voucher_type")=="Stock Reconciliation":
actual_qty = args.get('qty_after_transaction')
else:
actual_qty = bin_details.actual_qty + flt(args.get("actual_qty"))
ordered_qty = flt(bin_details.ordered_qty) + flt(args.get("ordered_qty"))
reserved_qty = flt(bin_details.reserved_qty) + flt(args.get("reserved_qty"))
indented_qty = flt(bin_details.indented_qty) + flt(args.get("indented_qty"))
planned_qty = flt(bin_details.planned_qty) + flt(args.get("planned_qty"))
# compute projected qty
projected_qty = (flt(actual_qty) + flt(ordered_qty)
+ flt(indented_qty) + flt(planned_qty) - flt(reserved_qty)
- flt(bin_details.reserved_qty_for_production) - flt(bin_details.reserved_qty_for_sub_contract))
frappe.db.set_value('Bin', bin_name, {
'actual_qty': actual_qty,
'ordered_qty': ordered_qty,
'reserved_qty': reserved_qty,
'indented_qty': indented_qty,
'planned_qty': planned_qty,
'projected_qty': projected_qty
})

View File

@ -5,7 +5,6 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import json import json
import unittest
import frappe import frappe
from frappe.utils import cstr, flt, nowdate, nowtime from frappe.utils import cstr, flt, nowdate, nowtime
@ -37,9 +36,10 @@ from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import
) )
from erpnext.stock.doctype.warehouse.test_warehouse import get_warehouse from erpnext.stock.doctype.warehouse.test_warehouse import get_warehouse
from erpnext.stock.stock_ledger import get_previous_sle from erpnext.stock.stock_ledger import get_previous_sle
from erpnext.tests.utils import ERPNextTestCase
class TestDeliveryNote(unittest.TestCase): class TestDeliveryNote(ERPNextTestCase):
def test_over_billing_against_dn(self): def test_over_billing_against_dn(self):
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1) frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)

View File

@ -14,11 +14,12 @@ from erpnext.stock.doctype.delivery_trip.delivery_trip import (
make_expense_claim, make_expense_claim,
notify_customers, notify_customers,
) )
from erpnext.tests.utils import create_test_contact_and_address from erpnext.tests.utils import ERPNextTestCase, create_test_contact_and_address
class TestDeliveryTrip(unittest.TestCase): class TestDeliveryTrip(ERPNextTestCase):
def setUp(self): def setUp(self):
super().setUp()
driver = create_driver() driver = create_driver()
create_vehicle() create_vehicle()
create_delivery_notification() create_delivery_notification()
@ -32,6 +33,7 @@ class TestDeliveryTrip(unittest.TestCase):
frappe.db.sql("delete from `tabVehicle`") frappe.db.sql("delete from `tabVehicle`")
frappe.db.sql("delete from `tabEmail Template`") frappe.db.sql("delete from `tabEmail Template`")
frappe.db.sql("delete from `tabDelivery Trip`") frappe.db.sql("delete from `tabDelivery Trip`")
return super().tearDown()
def test_expense_claim_fields_are_fetched_properly(self): def test_expense_claim_fields_are_fetched_properly(self):
expense_claim = make_expense_claim(self.delivery_trip.name) expense_claim = make_expense_claim(self.delivery_trip.name)

View File

@ -4,7 +4,6 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import json import json
import unittest
import frappe import frappe
from frappe.test_runner import make_test_objects from frappe.test_runner import make_test_objects
@ -25,7 +24,7 @@ from erpnext.stock.doctype.item.item import (
) )
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry 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.stock.get_item_details import get_item_details
from erpnext.tests.utils import change_settings from erpnext.tests.utils import ERPNextTestCase, change_settings
test_ignore = ["BOM"] test_ignore = ["BOM"]
test_dependencies = ["Warehouse", "Item Group", "Item Tax Template", "Brand", "Item Attribute"] test_dependencies = ["Warehouse", "Item Group", "Item Tax Template", "Brand", "Item Attribute"]
@ -53,8 +52,9 @@ def make_item(item_code, properties=None):
return item return item
class TestItem(unittest.TestCase): class TestItem(ERPNextTestCase):
def setUp(self): def setUp(self):
super().setUp()
frappe.flags.attribute_values = None frappe.flags.attribute_values = None
def get_item(self, idx): def get_item(self, idx):

View File

@ -4,7 +4,6 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import json import json
import unittest
import frappe import frappe
from frappe.utils import flt from frappe.utils import flt
@ -21,10 +20,12 @@ from erpnext.stock.doctype.item.test_item import create_item
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import ( from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import (
create_stock_reconciliation, create_stock_reconciliation,
) )
from erpnext.tests.utils import ERPNextTestCase
class TestItemAlternative(unittest.TestCase): class TestItemAlternative(ERPNextTestCase):
def setUp(self): def setUp(self):
super().setUp()
make_items() make_items()
def test_alternative_item_for_subcontract_rm(self): def test_alternative_item_for_subcontract_rm(self):

View File

@ -3,17 +3,17 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import unittest
import frappe import frappe
test_records = frappe.get_test_records('Item Attribute') test_records = frappe.get_test_records('Item Attribute')
from erpnext.stock.doctype.item_attribute.item_attribute import ItemAttributeIncrementError from erpnext.stock.doctype.item_attribute.item_attribute import ItemAttributeIncrementError
from erpnext.tests.utils import ERPNextTestCase
class TestItemAttribute(unittest.TestCase): class TestItemAttribute(ERPNextTestCase):
def setUp(self): def setUp(self):
super().setUp()
if frappe.db.exists("Item Attribute", "_Test_Length"): if frappe.db.exists("Item Attribute", "_Test_Length"):
frappe.delete_doc("Item Attribute", "_Test_Length") frappe.delete_doc("Item Attribute", "_Test_Length")

View File

@ -3,17 +3,17 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import unittest
import frappe import frappe
from frappe.test_runner import make_test_records_for_doctype from frappe.test_runner import make_test_records_for_doctype
from erpnext.stock.doctype.item_price.item_price import ItemPriceDuplicateItem 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.stock.get_item_details import get_price_list_rate_for, process_args
from erpnext.tests.utils import ERPNextTestCase
class TestItemPrice(unittest.TestCase): class TestItemPrice(ERPNextTestCase):
def setUp(self): def setUp(self):
super().setUp()
frappe.db.sql("delete from `tabItem Price`") frappe.db.sql("delete from `tabItem Price`")
make_test_records_for_doctype("Item Price", force=True) make_test_records_for_doctype("Item Price", force=True)

View File

@ -4,8 +4,6 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import unittest
import frappe import frappe
from frappe.utils import flt from frappe.utils import flt
@ -16,9 +14,10 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import (
get_gl_entries, get_gl_entries,
make_purchase_receipt, make_purchase_receipt,
) )
from erpnext.tests.utils import ERPNextTestCase
class TestLandedCostVoucher(unittest.TestCase): class TestLandedCostVoucher(ERPNextTestCase):
def test_landed_cost_voucher(self): def test_landed_cost_voucher(self):
frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1) frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1)

View File

@ -6,8 +6,6 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import unittest
import frappe import frappe
from frappe.utils import flt, today from frappe.utils import flt, today
@ -18,9 +16,10 @@ from erpnext.stock.doctype.material_request.material_request import (
make_supplier_quotation, make_supplier_quotation,
raise_work_orders, raise_work_orders,
) )
from erpnext.tests.utils import ERPNextTestCase
class TestMaterialRequest(unittest.TestCase): class TestMaterialRequest(ERPNextTestCase):
def test_make_purchase_order(self): def test_make_purchase_order(self):
mr = frappe.copy_doc(test_records[0]).insert() mr = frappe.copy_doc(test_records[0]).insert()

View File

@ -6,6 +6,8 @@ from __future__ import unicode_literals
import unittest import unittest
# test_records = frappe.get_test_records('Packing Slip') # test_records = frappe.get_test_records('Packing Slip')
from erpnext.tests.utils import ERPNextTestCase
class TestPackingSlip(unittest.TestCase): class TestPackingSlip(unittest.TestCase):
pass pass

View File

@ -3,8 +3,6 @@
# See license.txt # See license.txt
from __future__ import unicode_literals from __future__ import unicode_literals
import unittest
import frappe import frappe
test_dependencies = ['Item', 'Sales Invoice', 'Stock Entry', 'Batch'] test_dependencies = ['Item', 'Sales Invoice', 'Stock Entry', 'Batch']
@ -15,9 +13,10 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_pu
from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import ( from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import (
EmptyStockReconciliationItemsError, EmptyStockReconciliationItemsError,
) )
from erpnext.tests.utils import ERPNextTestCase
class TestPickList(unittest.TestCase): class TestPickList(ERPNextTestCase):
def test_pick_list_picks_warehouse_for_each_item(self): def test_pick_list_picks_warehouse_for_each_item(self):
try: try:

View File

@ -17,9 +17,10 @@ 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.serial_no.serial_no import SerialNoDuplicateError, get_serial_nos
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
from erpnext.stock.stock_ledger import SerialNoExistsInFutureTransaction from erpnext.stock.stock_ledger import SerialNoExistsInFutureTransaction
from erpnext.tests.utils import ERPNextTestCase
class TestPurchaseReceipt(unittest.TestCase): class TestPurchaseReceipt(ERPNextTestCase):
def setUp(self): def setUp(self):
frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1) frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1)

View File

@ -3,8 +3,6 @@
# See license.txt # See license.txt
from __future__ import unicode_literals from __future__ import unicode_literals
import unittest
import frappe import frappe
from erpnext.stock.doctype.batch.test_batch import make_new_batch from erpnext.stock.doctype.batch.test_batch import make_new_batch
@ -13,9 +11,10 @@ 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.stock_entry.test_stock_entry import make_stock_entry
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
from erpnext.stock.get_item_details import get_conversion_factor from erpnext.stock.get_item_details import get_conversion_factor
from erpnext.tests.utils import ERPNextTestCase
class TestPutawayRule(unittest.TestCase): class TestPutawayRule(ERPNextTestCase):
def setUp(self): def setUp(self):
if not frappe.db.exists("Item", "_Rice"): if not frappe.db.exists("Item", "_Rice"):
make_item("_Rice", { make_item("_Rice", {

View File

@ -1,8 +1,6 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and Contributors # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and Contributors
# See license.txt # See license.txt
import unittest
import frappe import frappe
from frappe.utils import nowdate from frappe.utils import nowdate
@ -15,12 +13,14 @@ from erpnext.controllers.stock_controller import (
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note 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.item.test_item import create_item
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry 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') # test_records = frappe.get_test_records('Quality Inspection')
class TestQualityInspection(unittest.TestCase): class TestQualityInspection(ERPNextTestCase):
def setUp(self): def setUp(self):
super().setUp()
create_item("_Test Item with QA") create_item("_Test Item with QA")
frappe.db.set_value( frappe.db.set_value(
"Item", "_Test Item with QA", "inspection_required_before_delivery", 1 "Item", "_Test Item with QA", "inspection_required_before_delivery", 1

View File

@ -6,8 +6,6 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import unittest
import frappe import frappe
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
@ -20,9 +18,10 @@ test_dependencies = ["Item"]
test_records = frappe.get_test_records('Serial No') test_records = frappe.get_test_records('Serial No')
from erpnext.stock.doctype.serial_no.serial_no import * from erpnext.stock.doctype.serial_no.serial_no import *
from erpnext.tests.utils import ERPNextTestCase
class TestSerialNo(unittest.TestCase): class TestSerialNo(ERPNextTestCase):
def test_cannot_create_direct(self): def test_cannot_create_direct(self):
frappe.delete_doc_if_exists("Serial No", "_TCSER0001") frappe.delete_doc_if_exists("Serial No", "_TCSER0001")

View File

@ -3,15 +3,15 @@
# See license.txt # See license.txt
from __future__ import unicode_literals from __future__ import unicode_literals
import unittest
from datetime import date, timedelta from datetime import date, timedelta
import frappe import frappe
from erpnext.stock.doctype.delivery_note.delivery_note import make_shipment from erpnext.stock.doctype.delivery_note.delivery_note import make_shipment
from erpnext.tests.utils import ERPNextTestCase
class TestShipment(unittest.TestCase): class TestShipment(ERPNextTestCase):
def test_shipment_from_delivery_note(self): def test_shipment_from_delivery_note(self):
delivery_note = create_test_delivery_note() delivery_note = create_test_delivery_note()
delivery_note.submit() delivery_note.submit()
@ -47,7 +47,6 @@ def create_test_delivery_note():
} }
) )
delivery_note.insert() delivery_note.insert()
frappe.db.commit()
return delivery_note return delivery_note
@ -91,7 +90,6 @@ def create_test_shipment(delivery_notes = None):
} }
) )
shipment.insert() shipment.insert()
frappe.db.commit()
return shipment return shipment

View File

@ -317,7 +317,7 @@
"in_create": 1, "in_create": 1,
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"links": [], "links": [],
"modified": "2021-10-08 12:42:51.857631", "modified": "2021-10-08 13:42:51.857631",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Stock Ledger Entry", "name": "Stock Ledger Entry",

View File

@ -181,3 +181,4 @@ def on_doctype_update():
frappe.db.add_index("Stock Ledger Entry", ["voucher_no", "voucher_type"]) frappe.db.add_index("Stock Ledger Entry", ["voucher_no", "voucher_type"])
frappe.db.add_index("Stock Ledger Entry", ["batch_no", "item_code", "warehouse"]) frappe.db.add_index("Stock Ledger Entry", ["batch_no", "item_code", "warehouse"])
frappe.db.add_index("Stock Ledger Entry", ["warehouse", "item_code"], "item_warehouse")

View File

@ -3,8 +3,6 @@
# See license.txt # See license.txt
from __future__ import unicode_literals from __future__ import unicode_literals
import unittest
import frappe import frappe
from frappe.core.page.permission_manager.permission_manager import reset from frappe.core.page.permission_manager.permission_manager import reset
from frappe.utils import add_days, today from frappe.utils import add_days, today
@ -21,9 +19,10 @@ from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import
create_stock_reconciliation, create_stock_reconciliation,
) )
from erpnext.stock.stock_ledger import get_previous_sle from erpnext.stock.stock_ledger import get_previous_sle
from erpnext.tests.utils import ERPNextTestCase
class TestStockLedgerEntry(unittest.TestCase): class TestStockLedgerEntry(ERPNextTestCase):
def setUp(self): def setUp(self):
items = create_items() items = create_items()
reset('Stock Entry') reset('Stock Entry')

View File

@ -6,8 +6,6 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import unittest
import frappe import frappe
from frappe.utils import add_days, flt, nowdate, nowtime, random_string from frappe.utils import add_days, flt, nowdate, nowtime, random_string
@ -22,12 +20,13 @@ from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import (
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse 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.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.stock.utils import get_incoming_rate, get_stock_value_on, get_valuation_method
from erpnext.tests.utils import change_settings from erpnext.tests.utils import ERPNextTestCase, change_settings
class TestStockReconciliation(unittest.TestCase): class TestStockReconciliation(ERPNextTestCase):
@classmethod @classmethod
def setUpClass(self): def setUpClass(self):
super().setUpClass()
create_batch_or_serial_no_items() create_batch_or_serial_no_items()
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1) frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
@ -372,7 +371,6 @@ class TestStockReconciliation(unittest.TestCase):
""" """
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
from erpnext.stock.stock_ledger import NegativeStockError from erpnext.stock.stock_ledger import NegativeStockError
frappe.db.commit()
item_code = "Backdated-Reco-Cancellation-Item" item_code = "Backdated-Reco-Cancellation-Item"
warehouse = "_Test Warehouse - _TC" warehouse = "_Test Warehouse - _TC"
@ -395,10 +393,6 @@ class TestStockReconciliation(unittest.TestCase):
repost_exists = bool(frappe.db.exists("Repost Item Valuation", {"voucher_no": sr.name})) repost_exists = bool(frappe.db.exists("Repost Item Valuation", {"voucher_no": sr.name}))
self.assertFalse(repost_exists, msg="Negative stock validation not working on reco cancellation") self.assertFalse(repost_exists, msg="Negative stock validation not working on reco cancellation")
# teardown
frappe.db.rollback()
def test_valid_batch(self): def test_valid_batch(self):
create_batch_item_with_batch("Testing Batch Item 1", "001") create_batch_item_with_batch("Testing Batch Item 1", "001")
create_batch_item_with_batch("Testing Batch Item 2", "002") create_batch_item_with_batch("Testing Batch Item 2", "002")

View File

@ -7,9 +7,12 @@ import unittest
import frappe import frappe
from erpnext.tests.utils import ERPNextTestCase
class TestStockSettings(unittest.TestCase):
class TestStockSettings(ERPNextTestCase):
def setUp(self): def setUp(self):
super().setUp()
frappe.db.set_value("Stock Settings", None, "clean_description_html", 0) frappe.db.set_value("Stock Settings", None, "clean_description_html", 0)
def test_settings(self): def test_settings(self):

View File

@ -2,8 +2,6 @@
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import unicode_literals
import unittest
import frappe import frappe
from frappe.test_runner import make_test_records from frappe.test_runner import make_test_records
from frappe.utils import cint from frappe.utils import cint
@ -12,11 +10,13 @@ import erpnext
from erpnext.accounts.doctype.account.test_account import create_account, get_inventory_account 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.item.test_item import create_item
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry 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') test_records = frappe.get_test_records('Warehouse')
class TestWarehouse(unittest.TestCase): class TestWarehouse(ERPNextTestCase):
def setUp(self): def setUp(self):
super().setUp()
if not frappe.get_value('Item', '_Test Item'): if not frappe.get_value('Item', '_Test Item'):
make_test_records('Item') make_test_records('Item')

View File

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

View File

@ -13,8 +13,8 @@ from six import iteritems
import erpnext import erpnext
from erpnext.stock.utils import ( from erpnext.stock.utils import (
get_bin,
get_incoming_outgoing_rate_for_cancel, get_incoming_outgoing_rate_for_cancel,
get_or_make_bin,
get_valuation_method, get_valuation_method,
) )
@ -805,14 +805,13 @@ class update_entries_after(object):
def update_bin(self): def update_bin(self):
# update bin for each warehouse # update bin for each warehouse
for warehouse, data in iteritems(self.data): for warehouse, data in iteritems(self.data):
bin_doc = get_bin(self.item_code, warehouse) bin_record = get_or_make_bin(self.item_code, warehouse)
bin_doc.update({
frappe.db.set_value('Bin', bin_record, {
"valuation_rate": data.valuation_rate, "valuation_rate": data.valuation_rate,
"actual_qty": data.qty_after_transaction, "actual_qty": data.qty_after_transaction,
"stock_value": data.stock_value "stock_value": data.stock_value
}) })
bin_doc.flags.via_stock_ledger_entry = True
bin_doc.save(ignore_permissions=True)
def get_previous_sle_of_current_voucher(args, exclude_current_voucher=False): def get_previous_sle_of_current_voucher(args, exclude_current_voucher=False):
@ -918,7 +917,7 @@ def get_valuation_rate(item_code, warehouse, voucher_type, voucher_no,
company = erpnext.get_default_company() company = erpnext.get_default_company()
last_valuation_rate = frappe.db.sql("""select valuation_rate last_valuation_rate = frappe.db.sql("""select valuation_rate
from `tabStock Ledger Entry` from `tabStock Ledger Entry` force index (item_warehouse)
where where
item_code = %s item_code = %s
AND warehouse = %s AND warehouse = %s
@ -929,7 +928,7 @@ def get_valuation_rate(item_code, warehouse, voucher_type, voucher_no,
if not last_valuation_rate: if not last_valuation_rate:
# Get valuation rate from last sle for the item against any warehouse # Get valuation rate from last sle for the item against any warehouse
last_valuation_rate = frappe.db.sql("""select valuation_rate last_valuation_rate = frappe.db.sql("""select valuation_rate
from `tabStock Ledger Entry` from `tabStock Ledger Entry` force index (item_code)
where where
item_code = %s item_code = %s
AND valuation_rate > 0 AND valuation_rate > 0

View File

@ -180,12 +180,27 @@ def get_bin(item_code, warehouse):
bin_obj.flags.ignore_permissions = True bin_obj.flags.ignore_permissions = True
return bin_obj return bin_obj
def get_or_make_bin(item_code, warehouse) -> str:
bin_record = frappe.db.get_value('Bin', {'item_code': item_code, 'warehouse': warehouse})
if not bin_record:
bin_obj = frappe.get_doc({
"doctype": "Bin",
"item_code": item_code,
"warehouse": warehouse,
})
bin_obj.flags.ignore_permissions = 1
bin_obj.insert()
bin_record = bin_obj.name
return bin_record
def update_bin(args, allow_negative_stock=False, via_landed_cost_voucher=False): def update_bin(args, allow_negative_stock=False, via_landed_cost_voucher=False):
from erpnext.stock.doctype.bin.bin import update_stock
is_stock_item = frappe.get_cached_value('Item', args.get("item_code"), 'is_stock_item') is_stock_item = frappe.get_cached_value('Item', args.get("item_code"), 'is_stock_item')
if is_stock_item: if is_stock_item:
bin = get_bin(args.get("item_code"), args.get("warehouse")) bin_record = get_or_make_bin(args.get("item_code"), args.get("warehouse"))
bin.update_stock(args, allow_negative_stock, via_landed_cost_voucher) update_stock(bin_record, args, allow_negative_stock, via_landed_cost_voucher)
return bin
else: else:
frappe.msgprint(_("Item {0} ignored since it is not a stock item").format(args.get("item_code"))) frappe.msgprint(_("Item {0} ignored since it is not a stock item").format(args.get("item_code")))

View File

@ -2,6 +2,7 @@
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
import copy import copy
import unittest
from contextlib import contextmanager from contextlib import contextmanager
from typing import Any, Dict, NewType, Optional from typing import Any, Dict, NewType, Optional
@ -12,6 +13,21 @@ ReportFilters = Dict[str, Any]
ReportName = NewType("ReportName", str) 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(): def create_test_contact_and_address():
frappe.db.sql('delete from tabContact') frappe.db.sql('delete from tabContact')
frappe.db.sql('delete from `tabContact Email`') frappe.db.sql('delete from `tabContact Email`')