Compare commits

..

1 Commits

Author SHA1 Message Date
Ankush Menat
565542be20 ci: disable test orchestrator v13 2022-10-12 11:02:17 +05:30
61 changed files with 566 additions and 1386 deletions

View File

@@ -495,67 +495,6 @@ class TestPOSInvoice(unittest.TestCase):
self.assertRaises(frappe.ValidationError, pos.submit)
def test_value_error_on_serial_no_validation(self):
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
se = make_serialized_item(
company="_Test Company",
target_warehouse="Stores - _TC",
cost_center="Main - _TC",
expense_account="Cost of Goods Sold - _TC",
)
serial_nos = se.get("items")[0].serial_no
# make a pos invoice
pos = create_pos_invoice(
company="_Test Company",
debit_to="Debtors - _TC",
account_for_change_amount="Cash - _TC",
warehouse="Stores - _TC",
income_account="Sales - _TC",
expense_account="Cost of Goods Sold - _TC",
cost_center="Main - _TC",
item=se.get("items")[0].item_code,
rate=1000,
qty=1,
do_not_save=1,
)
pos.get("items")[0].has_serial_no = 1
pos.get("items")[0].serial_no = serial_nos.split("\n")[0]
pos.set("payments", [])
pos.append(
"payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 1000, "default": 1}
)
pos = pos.save().submit()
# make a return
pos_return = make_sales_return(pos.name)
pos_return.paid_amount = pos_return.grand_total
pos_return.save()
pos_return.submit()
# set docstatus to 2 for pos to trigger this issue
frappe.db.set_value("POS Invoice", pos.name, "docstatus", 2)
pos2 = create_pos_invoice(
company="_Test Company",
debit_to="Debtors - _TC",
account_for_change_amount="Cash - _TC",
warehouse="Stores - _TC",
income_account="Sales - _TC",
expense_account="Cost of Goods Sold - _TC",
cost_center="Main - _TC",
item=se.get("items")[0].item_code,
rate=1000,
qty=1,
do_not_save=1,
)
pos2.get("items")[0].has_serial_no = 1
pos2.get("items")[0].serial_no = serial_nos.split("\n")[0]
# Value error should not be triggered on validation
pos2.save()
def test_loyalty_points(self):
from erpnext.accounts.doctype.loyalty_program.loyalty_program import (
get_loyalty_program_details_with_points,

View File

@@ -269,18 +269,6 @@ def get_serial_no_for_item(args):
return item_details
def update_pricing_rule_uom(pricing_rule, args):
child_doc = {"Item Code": "items", "Item Group": "item_groups", "Brand": "brands"}.get(
pricing_rule.apply_on
)
apply_on_field = frappe.scrub(pricing_rule.apply_on)
for row in pricing_rule.get(child_doc):
if row.get(apply_on_field) == args.get(apply_on_field):
pricing_rule.uom = row.uom
def get_pricing_rule_for_item(args, price_list_rate=0, doc=None, for_validate=False):
from erpnext.accounts.doctype.pricing_rule.utils import (
get_applied_pricing_rules,
@@ -337,8 +325,7 @@ def get_pricing_rule_for_item(args, price_list_rate=0, doc=None, for_validate=Fa
if isinstance(pricing_rule, string_types):
pricing_rule = frappe.get_cached_doc("Pricing Rule", pricing_rule)
update_pricing_rule_uom(pricing_rule, args)
pricing_rule.apply_rule_on_other_items = get_pricing_rule_items(pricing_rule) or []
pricing_rule.apply_rule_on_other_items = get_pricing_rule_items(pricing_rule)
if pricing_rule.get("suggestion"):
continue
@@ -452,15 +439,12 @@ def apply_price_discount_rule(pricing_rule, item_details, args):
if pricing_rule.currency == args.currency:
pricing_rule_rate = pricing_rule.rate
# TODO https://github.com/frappe/erpnext/pull/23636 solve this in some other way.
if pricing_rule_rate:
is_blank_uom = pricing_rule.get("uom") != args.get("uom")
# Override already set price list rate (from item price)
# if pricing_rule_rate > 0
item_details.update(
{
"price_list_rate": pricing_rule_rate
* (args.get("conversion_factor", 1) if is_blank_uom else 1),
"price_list_rate": pricing_rule_rate * args.get("conversion_factor", 1),
}
)
item_details.update({"discount_percentage": 0.0})

View File

@@ -597,121 +597,6 @@ class TestPricingRule(unittest.TestCase):
frappe.get_doc("Item Price", {"item_code": "Water Flask"}).delete()
item.delete()
def test_item_price_with_blank_uom_pricing_rule(self):
properties = {
"item_code": "Item Blank UOM",
"stock_uom": "Nos",
"sales_uom": "Box",
"uoms": [dict(uom="Box", conversion_factor=10)],
}
item = make_item(properties=properties)
make_item_price("Item Blank UOM", "_Test Price List", 100)
pricing_rule_record = {
"doctype": "Pricing Rule",
"title": "_Test Item Blank UOM Rule",
"apply_on": "Item Code",
"items": [
{
"item_code": "Item Blank UOM",
}
],
"selling": 1,
"currency": "INR",
"rate_or_discount": "Rate",
"rate": 101,
"company": "_Test Company",
}
rule = frappe.get_doc(pricing_rule_record)
rule.insert()
si = create_sales_invoice(
do_not_save=True, item_code="Item Blank UOM", uom="Box", conversion_factor=10
)
si.selling_price_list = "_Test Price List"
si.save()
# If UOM is blank consider it as stock UOM and apply pricing_rule on all UOM.
# rate is 101, Selling UOM is Box that have conversion_factor of 10 so 101 * 10 = 1010
self.assertEqual(si.items[0].price_list_rate, 1010)
self.assertEqual(si.items[0].rate, 1010)
si.delete()
si = create_sales_invoice(do_not_save=True, item_code="Item Blank UOM", uom="Nos")
si.selling_price_list = "_Test Price List"
si.save()
# UOM is blank so consider it as stock UOM and apply pricing_rule on all UOM.
# rate is 101, Selling UOM is Nos that have conversion_factor of 1 so 101 * 1 = 101
self.assertEqual(si.items[0].price_list_rate, 101)
self.assertEqual(si.items[0].rate, 101)
si.delete()
rule.delete()
frappe.get_doc("Item Price", {"item_code": "Item Blank UOM"}).delete()
item.delete()
def test_item_price_with_selling_uom_pricing_rule(self):
properties = {
"item_code": "Item UOM other than Stock",
"stock_uom": "Nos",
"sales_uom": "Box",
"uoms": [dict(uom="Box", conversion_factor=10)],
}
item = make_item(properties=properties)
make_item_price("Item UOM other than Stock", "_Test Price List", 100)
pricing_rule_record = {
"doctype": "Pricing Rule",
"title": "_Test Item UOM other than Stock Rule",
"apply_on": "Item Code",
"items": [
{
"item_code": "Item UOM other than Stock",
"uom": "Box",
}
],
"selling": 1,
"currency": "INR",
"rate_or_discount": "Rate",
"rate": 101,
"company": "_Test Company",
}
rule = frappe.get_doc(pricing_rule_record)
rule.insert()
si = create_sales_invoice(
do_not_save=True, item_code="Item UOM other than Stock", uom="Box", conversion_factor=10
)
si.selling_price_list = "_Test Price List"
si.save()
# UOM is Box so apply pricing_rule only on Box UOM.
# Selling UOM is Box and as both UOM are same no need to multiply by conversion_factor.
self.assertEqual(si.items[0].price_list_rate, 101)
self.assertEqual(si.items[0].rate, 101)
si.delete()
si = create_sales_invoice(do_not_save=True, item_code="Item UOM other than Stock", uom="Nos")
si.selling_price_list = "_Test Price List"
si.save()
# UOM is Box so pricing_rule won't apply as selling_uom is Nos.
# As Pricing Rule is not applied price of 100 will be fetched from Item Price List.
self.assertEqual(si.items[0].price_list_rate, 100)
self.assertEqual(si.items[0].rate, 100)
si.delete()
rule.delete()
frappe.get_doc("Item Price", {"item_code": "Item UOM other than Stock"}).delete()
item.delete()
def test_pricing_rule_for_different_currency(self):
make_item("Test Sanitizer Item")

View File

@@ -111,12 +111,6 @@ def _get_pricing_rules(apply_on, args, values):
)
if apply_on_field == "item_code":
if args.get("uom", None):
item_conditions += (
" and ({child_doc}.uom='{item_uom}' or IFNULL({child_doc}.uom, '')='')".format(
child_doc=child_doc, item_uom=args.get("uom")
)
)
if "variant_of" not in args:
args.variant_of = frappe.get_cached_value("Item", args.item_code, "variant_of")

View File

@@ -31,7 +31,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
this._super();
// Ignore linked advances
this.frm.ignore_doctypes_on_cancel_all = ['Journal Entry', 'Payment Entry', 'Purchase Invoice'];
this.frm.ignore_doctypes_on_cancel_all = ['Journal Entry', 'Payment Entry'];
if(!this.frm.doc.__islocal) {
// show credit_to in print format
@@ -569,10 +569,6 @@ frappe.ui.form.on("Purchase Invoice", {
erpnext.queries.setup_queries(frm, "Warehouse", function() {
return erpnext.queries.warehouse(frm.doc);
});
if (frm.is_new()) {
frm.clear_table("tax_withheld_vouchers");
}
},
is_subcontracted: function(frm) {

View File

@@ -67,9 +67,6 @@ class PurchaseInvoice(BuyingController):
supplier_tds = frappe.db.get_value("Supplier", self.supplier, "tax_withholding_category")
self.set_onload("supplier_tds", supplier_tds)
if self.is_new():
self.set("tax_withheld_vouchers", [])
def before_save(self):
if not self.on_hold:
self.release_date = ""
@@ -698,10 +695,6 @@ class PurchaseInvoice(BuyingController):
)
)
credit_amount = item.base_net_amount
if self.is_internal_supplier and item.valuation_rate:
credit_amount = flt(item.valuation_rate * item.stock_qty)
# Intentionally passed negative debit amount to avoid incorrect GL Entry validation
gl_entries.append(
self.get_gl_dict(
@@ -711,7 +704,7 @@ class PurchaseInvoice(BuyingController):
"cost_center": item.cost_center,
"project": item.project or self.project,
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
"debit": -1 * flt(credit_amount, item.precision("base_net_amount")),
"debit": -1 * flt(item.base_net_amount, item.precision("base_net_amount")),
},
warehouse_account[item.from_warehouse]["account_currency"],
item=item,
@@ -1371,14 +1364,7 @@ class PurchaseInvoice(BuyingController):
frappe.db.set(self, "status", "Cancelled")
unlink_inter_company_doc(self.doctype, self.name, self.inter_company_invoice_reference)
self.ignore_linked_doctypes = (
"GL Entry",
"Stock Ledger Entry",
"Repost Item Valuation",
"Tax Withheld Vouchers",
)
self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry", "Repost Item Valuation")
self.update_advance_tax_references(cancel=1)
def update_project(self):

View File

@@ -706,7 +706,6 @@
"label": "Valuation Rate",
"no_copy": 1,
"options": "Company:company:default_currency",
"precision": "6",
"print_hide": 1,
"read_only": 1
},
@@ -872,7 +871,7 @@
"idx": 1,
"istable": 1,
"links": [],
"modified": "2022-10-12 03:37:29.032732",
"modified": "2021-11-15 17:04:07.191013",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice Item",

View File

@@ -2187,9 +2187,6 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None):
update_address(
target_doc, "shipping_address", "shipping_address_display", source_doc.customer_address
)
update_address(
target_doc, "billing_address", "billing_address_display", source_doc.customer_address
)
if currency:
target_doc.currency = currency

View File

@@ -31,20 +31,10 @@ from erpnext.stock.doctype.stock_entry.test_stock_entry import (
get_qty_after_transaction,
make_stock_entry,
)
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import (
create_stock_reconciliation,
)
from erpnext.stock.utils import get_incoming_rate, get_stock_balance
from erpnext.stock.utils import get_incoming_rate
class TestSalesInvoice(unittest.TestCase):
def setUp(self):
from erpnext.stock.doctype.stock_ledger_entry.test_stock_ledger_entry import create_items
create_items(["_Test Internal Transfer Item"], uoms=[{"uom": "Box", "conversion_factor": 10}])
create_internal_parties()
setup_accounts()
def make(self):
w = frappe.copy_doc(test_records[0])
w.is_pos = 0
@@ -916,8 +906,7 @@ class TestSalesInvoice(unittest.TestCase):
pos_return.insert()
pos_return.submit()
self.assertEqual(pos_return.get("payments")[0].amount, -500)
self.assertEqual(pos_return.get("payments")[1].amount, -500)
self.assertEqual(pos_return.get("payments")[0].amount, -1000)
def test_pos_change_amount(self):
make_pos_profile(
@@ -1698,7 +1687,7 @@ class TestSalesInvoice(unittest.TestCase):
si.save()
self.assertEqual(si.get("items")[0].rate, flt((price_list_rate * 25) / 100 + price_list_rate))
def test_outstanding_amount_after_advance_jv_cancellation(self):
def test_outstanding_amount_after_advance_jv_cancelation(self):
from erpnext.accounts.doctype.journal_entry.test_journal_entry import (
test_records as jv_test_records,
)
@@ -1742,7 +1731,7 @@ class TestSalesInvoice(unittest.TestCase):
flt(si.rounded_total + si.total_advance, si.precision("outstanding_amount")),
)
def test_outstanding_amount_after_advance_payment_entry_cancellation(self):
def test_outstanding_amount_after_advance_payment_entry_cancelation(self):
pe = frappe.get_doc(
{
"doctype": "Payment Entry",
@@ -2380,6 +2369,29 @@ class TestSalesInvoice(unittest.TestCase):
acc_settings.save()
def test_inter_company_transaction(self):
from erpnext.selling.doctype.customer.test_customer import create_internal_customer
create_internal_customer(
customer_name="_Test Internal Customer",
represents_company="_Test Company 1",
allowed_to_interact_with="Wind Power LLC",
)
if not frappe.db.exists("Supplier", "_Test Internal Supplier"):
supplier = frappe.get_doc(
{
"supplier_group": "_Test Supplier Group",
"supplier_name": "_Test Internal Supplier",
"doctype": "Supplier",
"is_internal_supplier": 1,
"represents_company": "Wind Power LLC",
}
)
supplier.append("companies", {"company": "_Test Company 1"})
supplier.insert()
si = create_sales_invoice(
company="Wind Power LLC",
customer="_Test Internal Customer",
@@ -2439,9 +2451,34 @@ class TestSalesInvoice(unittest.TestCase):
se.cancel()
def test_internal_transfer_gl_entry(self):
## Create internal transfer account
from erpnext.selling.doctype.customer.test_customer import create_internal_customer
account = create_account(
account_name="Unrealized Profit",
parent_account="Current Liabilities - TCP1",
company="_Test Company with perpetual inventory",
)
frappe.db.set_value(
"Company", "_Test Company with perpetual inventory", "unrealized_profit_loss_account", account
)
customer = create_internal_customer(
"_Test Internal Customer 2",
"_Test Company with perpetual inventory",
"_Test Company with perpetual inventory",
)
create_internal_supplier(
"_Test Internal Supplier 2",
"_Test Company with perpetual inventory",
"_Test Company with perpetual inventory",
)
si = create_sales_invoice(
company="_Test Company with perpetual inventory",
customer="_Test Internal Customer 2",
customer=customer,
debit_to="Debtors - TCP1",
warehouse="Stores - TCP1",
income_account="Sales - TCP1",
@@ -2455,7 +2492,7 @@ class TestSalesInvoice(unittest.TestCase):
si.update_stock = 1
si.items[0].target_warehouse = "Work In Progress - TCP1"
# Add stock to stores for successful stock transfer
# Add stock to stores for succesful stock transfer
make_stock_entry(
target="Stores - TCP1", company="_Test Company with perpetual inventory", qty=1, basic_rate=100
)
@@ -2793,77 +2830,6 @@ class TestSalesInvoice(unittest.TestCase):
self.assertEqual(einvoice["ItemList"][1]["Discount"], 0)
self.assertEqual(einvoice["ItemList"][1]["UnitPrice"], 20)
def test_internal_transfer_gl_precision_issues(self):
# Make a stock queue of an item with two valuations
# Remove all existing stock for this
if get_stock_balance("_Test Internal Transfer Item", "Stores - TCP1", "2022-04-10"):
create_stock_reconciliation(
item_code="_Test Internal Transfer Item",
warehouse="Stores - TCP1",
qty=0,
rate=0,
company="_Test Company with perpetual inventory",
expense_account="Stock Adjustment - TCP1"
if frappe.get_all("Stock Ledger Entry")
else "Temporary Opening - TCP1",
posting_date="2020-04-10",
posting_time="14:00",
)
make_stock_entry(
item_code="_Test Internal Transfer Item",
target="Stores - TCP1",
qty=9000000,
basic_rate=52.0,
posting_date="2020-04-10",
posting_time="14:00",
)
make_stock_entry(
item_code="_Test Internal Transfer Item",
target="Stores - TCP1",
qty=60000000,
basic_rate=52.349777,
posting_date="2020-04-10",
posting_time="14:00",
)
# Make an internal transfer Sales Invoice Stock in non stock uom to check
# for rounding errors while converting to stock uom
si = create_sales_invoice(
company="_Test Company with perpetual inventory",
customer="_Test Internal Customer 2",
item_code="_Test Internal Transfer Item",
qty=5000000,
uom="Box",
debit_to="Debtors - TCP1",
warehouse="Stores - TCP1",
income_account="Sales - TCP1",
expense_account="Cost of Goods Sold - TCP1",
cost_center="Main - TCP1",
currency="INR",
do_not_save=1,
)
# Check GL Entries with precision
si.update_stock = 1
si.items[0].target_warehouse = "Work In Progress - TCP1"
si.items[0].conversion_factor = 10
si.save()
si.submit()
# Check if adjustment entry is created
self.assertTrue(
frappe.db.exists(
"GL Entry",
{
"voucher_type": "Sales Invoice",
"voucher_no": si.name,
"remarks": "Rounding gain/loss Entry for Stock Transfer",
},
)
)
def test_item_tax_net_range(self):
item = create_item("T Shirt")
@@ -3312,7 +3278,7 @@ class TestSalesInvoice(unittest.TestCase):
[deferred_account, 2022.47, 0.0, "2019-03-15"],
]
gl_entries = frappe.db.sql(
gl_entries = gl_entries = frappe.db.sql(
"""select account, debit, credit, posting_date
from `tabGL Entry`
where voucher_type='Journal Entry' and voucher_detail_no=%s and posting_date <= %s
@@ -3717,7 +3683,6 @@ def create_sales_invoice(**args):
"description": args.description or "_Test Item",
"gst_hsn_code": "999800",
"warehouse": args.warehouse or "_Test Warehouse - _TC",
"target_warehouse": args.target_warehouse,
"qty": args.qty or 1,
"uom": args.uom or "Nos",
"stock_uom": args.uom or "Nos",
@@ -3730,7 +3695,7 @@ def create_sales_invoice(**args):
"discount_amount": args.discount_amount or 0,
"cost_center": args.cost_center or "_Test Cost Center - _TC",
"serial_no": args.serial_no,
"conversion_factor": args.get("conversion_factor", 1),
"conversion_factor": 1,
"incoming_rate": args.incoming_rate or 0,
"batch_no": args.batch_no or None,
},
@@ -3844,34 +3809,6 @@ def get_taxes_and_charges():
]
def create_internal_parties():
from erpnext.selling.doctype.customer.test_customer import create_internal_customer
create_internal_customer(
customer_name="_Test Internal Customer",
represents_company="_Test Company 1",
allowed_to_interact_with="Wind Power LLC",
)
create_internal_customer(
customer_name="_Test Internal Customer 2",
represents_company="_Test Company with perpetual inventory",
allowed_to_interact_with="_Test Company with perpetual inventory",
)
create_internal_supplier(
supplier_name="_Test Internal Supplier",
represents_company="Wind Power LLC",
allowed_to_interact_with="_Test Company 1",
)
create_internal_supplier(
supplier_name="_Test Internal Supplier 2",
represents_company="_Test Company with perpetual inventory",
allowed_to_interact_with="_Test Company with perpetual inventory",
)
def create_internal_supplier(supplier_name, represents_company, allowed_to_interact_with):
if not frappe.db.exists("Supplier", supplier_name):
supplier = frappe.get_doc(
@@ -3894,19 +3831,6 @@ def create_internal_supplier(supplier_name, represents_company, allowed_to_inter
return supplier_name
def setup_accounts():
## Create internal transfer account
account = create_account(
account_name="Unrealized Profit",
parent_account="Current Liabilities - TCP1",
company="_Test Company with perpetual inventory",
)
frappe.db.set_value(
"Company", "_Test Company with perpetual inventory", "unrealized_profit_loss_account", account
)
def add_taxes(doc):
doc.append(
"taxes",

View File

@@ -812,8 +812,6 @@
"fieldtype": "Currency",
"label": "Incoming Rate (Costing)",
"no_copy": 1,
"options": "Company:company:default_currency",
"precision": "6",
"print_hide": 1
},
{
@@ -843,7 +841,7 @@
"idx": 1,
"istable": 1,
"links": [],
"modified": "2022-10-10 20:57:38.340026",
"modified": "2022-08-26 12:06:31.205417",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Item",

View File

@@ -50,10 +50,6 @@
<div class="col-xs-4"><label>Document No</label></div>
<div class="col-xs-8 value">{{ einvoice.DocDtls.No }}</div>
</div>
<div class="row data-field">
<div class="col-xs-4"><label>Document Date</label></div>
<div class="col-xs-8 value">{{ einvoice.DocDtls.Dt }}</div>
</div>
</div>
<div class="col-xs-4 column-break">
<img src="{{ doc.qrcode_image }}" width="175px" style="float: right;">

View File

@@ -835,7 +835,10 @@ def remove_return_pos_invoices(party_type, party, invoice_list):
else:
return invoice_list
invoice_list = [x for x in invoice_list if x.voucher_no not in return_pos]
# remove pos return invoices from invoice_list
for idx, inv in enumerate(invoice_list, 0):
if inv.voucher_no in return_pos:
del invoice_list[idx]
return invoice_list

View File

@@ -384,11 +384,7 @@ frappe.ui.form.on('Asset', {
set_values_from_purchase_doc: function(frm, doctype, purchase_doc) {
frm.set_value('company', purchase_doc.company);
if (purchase_doc.bill_date) {
frm.set_value('purchase_date', purchase_doc.bill_date);
} else {
frm.set_value('purchase_date', purchase_doc.posting_date);
}
frm.set_value('purchase_date', purchase_doc.posting_date);
const item = purchase_doc.items.find(item => item.item_code === frm.doc.item_code);
if (!item) {
doctype_field = frappe.scrub(doctype)

View File

@@ -43,11 +43,6 @@ frappe.ui.form.on("Purchase Order", {
erpnext.queries.setup_queries(frm, "Warehouse", function() {
return erpnext.queries.warehouse(frm.doc);
});
// On cancel and amending a purchase order with advance payment, reset advance paid amount
if (frm.is_new()) {
frm.set_value("advance_paid", 0)
}
},
apply_tds: function(frm) {

View File

@@ -18,7 +18,7 @@ from erpnext.accounts.doctype.sales_invoice.sales_invoice import (
from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import (
get_party_tax_withholding_details,
)
from erpnext.accounts.party import get_party_account, get_party_account_currency
from erpnext.accounts.party import get_party_account_currency
from erpnext.buying.utils import check_on_hold_or_closed_status, validate_for_items
from erpnext.controllers.buying_controller import BuyingController
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
@@ -533,7 +533,6 @@ def get_mapped_purchase_invoice(source_name, target_doc=None, ignore_permissions
target.set_advances()
target.set_payment_schedule()
target.credit_to = get_party_account("Supplier", source.supplier, source.company)
def update_item(obj, target, source_parent):
target.amount = flt(obj.amount) - flt(obj.billed_amt)

View File

@@ -152,7 +152,6 @@ class AccountsController(TransactionBase):
self.validate_inter_company_reference()
self.disable_pricing_rule_on_internal_transfer()
self.disable_tax_included_prices_for_internal_transfer()
self.set_incoming_rate()
if self.meta.get_field("currency"):
@@ -396,20 +395,6 @@ class AccountsController(TransactionBase):
alert=1,
)
def disable_tax_included_prices_for_internal_transfer(self):
if self.is_internal_transfer():
tax_updated = False
for tax in self.get("taxes"):
if tax.get("included_in_print_rate"):
tax.included_in_print_rate = 0
tax_updated = True
if tax_updated:
frappe.msgprint(
_("Disabled tax included prices since this {} is an internal transfer").format(self.doctype),
alert=1,
)
def validate_due_date(self):
if self.get("is_pos"):
return

View File

@@ -439,17 +439,11 @@ class SellingController(StockController):
# For internal transfers use incoming rate as the valuation rate
if self.is_internal_transfer():
if d.doctype == "Packed Item":
incoming_rate = flt(
flt(d.incoming_rate, d.precision("incoming_rate")) * d.conversion_factor,
d.precision("incoming_rate"),
)
incoming_rate = flt(d.incoming_rate * d.conversion_factor, d.precision("incoming_rate"))
if d.incoming_rate != incoming_rate:
d.incoming_rate = incoming_rate
else:
rate = flt(
flt(d.incoming_rate, d.precision("incoming_rate")) * d.conversion_factor,
d.precision("rate"),
)
rate = flt(d.incoming_rate * d.conversion_factor, d.precision("rate"))
if d.rate != rate:
d.rate = rate
frappe.msgprint(

View File

@@ -139,15 +139,13 @@ class StockController(AccountsController):
warehouse_with_no_account = []
precision = self.get_debit_field_precision()
for item_row in voucher_details:
sle_list = sle_map.get(item_row.name)
sle_rounding_diff = 0.0
if sle_list:
for sle in sle_list:
if warehouse_account.get(sle.warehouse):
# from warehouse account
sle_rounding_diff += flt(sle.stock_value_difference)
self.check_expense_account(item_row)
# expense account/ target_warehouse / source_warehouse
@@ -190,46 +188,6 @@ class StockController(AccountsController):
elif sle.warehouse not in warehouse_with_no_account:
warehouse_with_no_account.append(sle.warehouse)
if abs(sle_rounding_diff) > (1.0 / (10**precision)) and self.is_internal_transfer():
warehouse_asset_account = ""
if self.get("is_internal_customer"):
warehouse_asset_account = warehouse_account[item_row.get("target_warehouse")]["account"]
elif self.get("is_internal_supplier"):
warehouse_asset_account = warehouse_account[item_row.get("warehouse")]["account"]
expense_account = frappe.db.get_value("Company", self.company, "default_expense_account")
gl_list.append(
self.get_gl_dict(
{
"account": expense_account,
"against": warehouse_asset_account,
"cost_center": item_row.cost_center,
"project": item_row.project or self.get("project"),
"remarks": _("Rounding gain/loss Entry for Stock Transfer"),
"debit": sle_rounding_diff,
"is_opening": item_row.get("is_opening") or self.get("is_opening") or "No",
},
warehouse_account[sle.warehouse]["account_currency"],
item=item_row,
)
)
gl_list.append(
self.get_gl_dict(
{
"account": warehouse_asset_account,
"against": expense_account,
"cost_center": item_row.cost_center,
"remarks": _("Rounding gain/loss Entry for Stock Transfer"),
"credit": sle_rounding_diff,
"project": item_row.get("project") or self.get("project"),
"is_opening": item_row.get("is_opening") or self.get("is_opening") or "No",
},
item=item_row,
)
)
if warehouse_with_no_account:
for wh in warehouse_with_no_account:
if frappe.db.get_value("Warehouse", wh, "company"):

View File

@@ -890,33 +890,24 @@ class calculate_taxes_and_totals(object):
self.doc.other_charges_calculation = get_itemised_tax_breakup_html(self.doc)
def set_total_amount_to_default_mop(self, total_amount_to_pay):
total_paid_amount = 0
for payment in self.doc.get("payments"):
total_paid_amount += (
payment.amount if self.doc.party_account_currency == self.doc.currency else payment.base_amount
default_mode_of_payment = frappe.db.get_value(
"POS Payment Method",
{"parent": self.doc.pos_profile, "default": 1},
["mode_of_payment"],
as_dict=1,
)
if default_mode_of_payment:
self.doc.payments = []
self.doc.append(
"payments",
{
"mode_of_payment": default_mode_of_payment.mode_of_payment,
"amount": total_amount_to_pay,
"default": 1,
},
)
pending_amount = total_amount_to_pay - total_paid_amount
if pending_amount > 0:
default_mode_of_payment = frappe.db.get_value(
"POS Payment Method",
{"parent": self.doc.pos_profile, "default": 1},
["mode_of_payment"],
as_dict=1,
)
if default_mode_of_payment:
self.doc.payments = []
self.doc.append(
"payments",
{
"mode_of_payment": default_mode_of_payment.mode_of_payment,
"amount": pending_amount,
"default": 1,
},
)
def get_itemised_tax_breakup_html(doc):
if not doc.taxes:

View File

@@ -334,6 +334,8 @@ has_website_permission = {
"Patient": "erpnext.healthcare.web_form.personal_details.personal_details.has_website_permission",
}
dump_report_map = "erpnext.startup.report_data_map.data_map"
before_tests = "erpnext.setup.utils.before_tests"
standard_queries = {

View File

@@ -61,10 +61,6 @@ frappe.ui.form.on('Loan', {
},
refresh: function (frm) {
if (frm.doc.repayment_schedule_type == "Pro-rated calendar months") {
frm.set_df_property("repayment_start_date", "label", "Interest Calculation Start Date");
}
if (frm.doc.docstatus == 1) {
if (["Disbursed", "Partially Disbursed"].includes(frm.doc.status) && (!frm.doc.repay_from_salary)) {
frm.add_custom_button(__('Request Loan Closure'), function() {
@@ -107,14 +103,6 @@ frappe.ui.form.on('Loan', {
frm.trigger("toggle_fields");
},
repayment_schedule_type: function(frm) {
if (frm.doc.repayment_schedule_type == "Pro-rated calendar months") {
frm.set_df_property("repayment_start_date", "label", "Interest Calculation Start Date");
} else {
frm.set_df_property("repayment_start_date", "label", "Repayment Start Date");
}
},
loan_type: function(frm) {
frm.toggle_reqd("repayment_method", frm.doc.is_term_loan);
frm.toggle_display("repayment_method", frm.doc.is_term_loan);

View File

@@ -20,7 +20,6 @@
"manually_update_paid_amount_in_salary_slip",
"section_break_8",
"loan_type",
"repayment_schedule_type",
"loan_amount",
"rate_of_interest",
"is_secured_loan",
@@ -168,8 +167,7 @@
"depends_on": "is_term_loan",
"fieldname": "repayment_start_date",
"fieldtype": "Date",
"label": "Repayment Start Date",
"mandatory_depends_on": "is_term_loan"
"label": "Repayment Start Date"
},
{
"fieldname": "column_break_11",
@@ -421,20 +419,12 @@
"fieldname": "manually_update_paid_amount_in_salary_slip",
"fieldtype": "Check",
"label": "Manually Update Paid Amount in Salary Slip"
},
{
"depends_on": "is_term_loan",
"fetch_from": "loan_type.repayment_schedule_type",
"fieldname": "repayment_schedule_type",
"fieldtype": "Data",
"label": "Repayment Schedule Type",
"read_only": 1
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2022-11-01 10:36:47.902903",
"modified": "2022-09-13 02:05:25.017190",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Loan",

View File

@@ -7,16 +7,7 @@ import math
import frappe
from frappe import _
from frappe.utils import (
add_days,
add_months,
date_diff,
flt,
get_last_day,
getdate,
now_datetime,
nowdate,
)
from frappe.utils import add_months, flt, get_last_day, getdate, now_datetime, nowdate
from six import string_types
import erpnext
@@ -124,81 +115,30 @@ class Loan(AccountsController):
if not self.repayment_start_date:
frappe.throw(_("Repayment Start Date is mandatory for term loans"))
schedule_type_details = frappe.db.get_value(
"Loan Type", self.loan_type, ["repayment_schedule_type", "repayment_date_on"], as_dict=1
)
self.repayment_schedule = []
payment_date = self.repayment_start_date
balance_amount = self.loan_amount
while balance_amount > 0:
interest_amount, principal_amount, balance_amount, total_payment = self.get_amounts(
payment_date,
balance_amount,
schedule_type_details.repayment_schedule_type,
schedule_type_details.repayment_date_on,
interest_amount = flt(balance_amount * flt(self.rate_of_interest) / (12 * 100))
principal_amount = self.monthly_repayment_amount - interest_amount
balance_amount = flt(balance_amount + interest_amount - self.monthly_repayment_amount)
if balance_amount < 0:
principal_amount += balance_amount
balance_amount = 0.0
total_payment = principal_amount + interest_amount
self.append(
"repayment_schedule",
{
"payment_date": payment_date,
"principal_amount": principal_amount,
"interest_amount": interest_amount,
"total_payment": total_payment,
"balance_loan_amount": balance_amount,
},
)
if schedule_type_details.repayment_schedule_type == "Pro-rated calendar months":
next_payment_date = get_last_day(payment_date)
if schedule_type_details.repayment_date_on == "Start of the next month":
next_payment_date = add_days(next_payment_date, 1)
payment_date = next_payment_date
self.add_repayment_schedule_row(
payment_date, principal_amount, interest_amount, total_payment, balance_amount
)
if (
schedule_type_details.repayment_schedule_type == "Monthly as per repayment start date"
or schedule_type_details.repayment_date_on == "End of the current month"
):
next_payment_date = add_single_month(payment_date)
payment_date = next_payment_date
def get_amounts(self, payment_date, balance_amount, schedule_type, repayment_date_on):
if schedule_type == "Monthly as per repayment start date":
days = 1
months = 12
else:
expected_payment_date = get_last_day(payment_date)
if repayment_date_on == "Start of the next month":
expected_payment_date = add_days(expected_payment_date, 1)
if expected_payment_date == payment_date:
# using 30 days for calculating interest for all full months
days = 30
months = 365
else:
days = date_diff(get_last_day(payment_date), payment_date)
months = 365
interest_amount = flt(balance_amount * flt(self.rate_of_interest) * days / (months * 100))
principal_amount = self.monthly_repayment_amount - interest_amount
balance_amount = flt(balance_amount + interest_amount - self.monthly_repayment_amount)
if balance_amount < 0:
principal_amount += balance_amount
balance_amount = 0.0
total_payment = principal_amount + interest_amount
return interest_amount, principal_amount, balance_amount, total_payment
def add_repayment_schedule_row(
self, payment_date, principal_amount, interest_amount, total_payment, balance_loan_amount
):
self.append(
"repayment_schedule",
{
"payment_date": payment_date,
"principal_amount": principal_amount,
"interest_amount": interest_amount,
"total_payment": total_payment,
"balance_loan_amount": balance_loan_amount,
},
)
next_payment_date = add_single_month(payment_date)
payment_date = next_payment_date
def set_repayment_period(self):
if self.repayment_method == "Repay Fixed Amount per Period":

View File

@@ -4,16 +4,7 @@
import unittest
import frappe
from frappe.utils import (
add_days,
add_months,
add_to_date,
date_diff,
flt,
format_date,
get_datetime,
nowdate,
)
from frappe.utils import add_days, add_months, add_to_date, date_diff, flt, get_datetime, nowdate
from erpnext.loan_management.doctype.loan.loan import (
make_loan_write_off,
@@ -59,51 +50,6 @@ class TestLoan(unittest.TestCase):
loan_account="Loan Account - _TC",
interest_income_account="Interest Income Account - _TC",
penalty_income_account="Penalty Income Account - _TC",
repayment_schedule_type="Monthly as per repayment start date",
)
create_loan_type(
"Term Loan Type 1",
12000,
7.5,
is_term_loan=1,
mode_of_payment="Cash",
disbursement_account="Disbursement Account - _TC",
payment_account="Payment Account - _TC",
loan_account="Loan Account - _TC",
interest_income_account="Interest Income Account - _TC",
penalty_income_account="Penalty Income Account - _TC",
repayment_schedule_type="Monthly as per repayment start date",
)
create_loan_type(
"Term Loan Type 2",
12000,
7.5,
is_term_loan=1,
mode_of_payment="Cash",
disbursement_account="Disbursement Account - _TC",
payment_account="Payment Account - _TC",
loan_account="Loan Account - _TC",
interest_income_account="Interest Income Account - _TC",
penalty_income_account="Penalty Income Account - _TC",
repayment_schedule_type="Pro-rated calendar months",
repayment_date_on="Start of the next month",
)
create_loan_type(
"Term Loan Type 3",
12000,
7.5,
is_term_loan=1,
mode_of_payment="Cash",
disbursement_account="Disbursement Account - _TC",
payment_account="Payment Account - _TC",
loan_account="Loan Account - _TC",
interest_income_account="Interest Income Account - _TC",
penalty_income_account="Penalty Income Account - _TC",
repayment_schedule_type="Pro-rated calendar months",
repayment_date_on="End of the current month",
)
create_loan_type(
@@ -119,7 +65,6 @@ class TestLoan(unittest.TestCase):
"Loan Account - _TC",
"Interest Income Account - _TC",
"Penalty Income Account - _TC",
repayment_schedule_type="Monthly as per repayment start date",
)
create_loan_type(
@@ -967,69 +912,6 @@ class TestLoan(unittest.TestCase):
amounts = calculate_amounts(loan.name, add_days(last_date, 5))
self.assertEqual(flt(amounts["pending_principal_amount"], 0), 0)
def test_term_loan_schedule_types(self):
loan = create_loan(
self.applicant1,
"Term Loan Type 1",
12000,
"Repay Over Number of Periods",
12,
repayment_start_date="2022-10-17",
)
# Check for first, second and last installment date
self.assertEqual(
format_date(loan.get("repayment_schedule")[0].payment_date, "dd-MM-yyyy"), "17-10-2022"
)
self.assertEqual(
format_date(loan.get("repayment_schedule")[1].payment_date, "dd-MM-yyyy"), "17-11-2022"
)
self.assertEqual(
format_date(loan.get("repayment_schedule")[-1].payment_date, "dd-MM-yyyy"), "17-09-2023"
)
loan.loan_type = "Term Loan Type 2"
loan.save()
# Check for first, second and last installment date
self.assertEqual(
format_date(loan.get("repayment_schedule")[0].payment_date, "dd-MM-yyyy"), "01-11-2022"
)
self.assertEqual(
format_date(loan.get("repayment_schedule")[1].payment_date, "dd-MM-yyyy"), "01-12-2022"
)
self.assertEqual(
format_date(loan.get("repayment_schedule")[-1].payment_date, "dd-MM-yyyy"), "01-10-2023"
)
loan.loan_type = "Term Loan Type 3"
loan.save()
# Check for first, second and last installment date
self.assertEqual(
format_date(loan.get("repayment_schedule")[0].payment_date, "dd-MM-yyyy"), "31-10-2022"
)
self.assertEqual(
format_date(loan.get("repayment_schedule")[1].payment_date, "dd-MM-yyyy"), "30-11-2022"
)
self.assertEqual(
format_date(loan.get("repayment_schedule")[-1].payment_date, "dd-MM-yyyy"), "30-09-2023"
)
loan.repayment_method = "Repay Fixed Amount per Period"
loan.monthly_repayment_amount = 1042
loan.save()
self.assertEqual(
format_date(loan.get("repayment_schedule")[0].payment_date, "dd-MM-yyyy"), "31-10-2022"
)
self.assertEqual(
format_date(loan.get("repayment_schedule")[1].payment_date, "dd-MM-yyyy"), "30-11-2022"
)
self.assertEqual(
format_date(loan.get("repayment_schedule")[-1].payment_date, "dd-MM-yyyy"), "30-09-2023"
)
def create_loan_scenario_for_penalty(doc):
pledge = [{"loan_security": "Test Security 1", "qty": 4000.00}]
@@ -1161,8 +1043,6 @@ def create_loan_type(
penalty_income_account=None,
repayment_method=None,
repayment_periods=None,
repayment_schedule_type=None,
repayment_date_on=None,
):
if not frappe.db.exists("Loan Type", loan_name):
@@ -1172,7 +1052,6 @@ def create_loan_type(
"company": "_Test Company",
"loan_name": loan_name,
"is_term_loan": is_term_loan,
"repayment_schedule_type": "Monthly as per repayment start date",
"maximum_loan_amount": maximum_loan_amount,
"rate_of_interest": rate_of_interest,
"penalty_interest_rate": penalty_interest_rate,
@@ -1187,14 +1066,8 @@ def create_loan_type(
"repayment_periods": repayment_periods,
"write_off_amount": 100,
}
)
).insert()
if loan_type.is_term_loan:
loan_type.repayment_schedule_type = repayment_schedule_type
if loan_type.repayment_schedule_type != "Monthly as per repayment start date":
loan_type.repayment_date_on = repayment_date_on
loan_type.insert()
loan_type.submit()

View File

@@ -16,8 +16,6 @@
"company",
"is_term_loan",
"disabled",
"repayment_schedule_type",
"repayment_date_on",
"description",
"account_details_section",
"mode_of_payment",
@@ -159,30 +157,12 @@
"label": "Disbursement Account",
"options": "Account",
"reqd": 1
},
{
"depends_on": "is_term_loan",
"description": "The schedule type that will be used for generating the term loan schedules (will affect the payment date and monthly repayment amount)",
"fieldname": "repayment_schedule_type",
"fieldtype": "Select",
"label": "Repayment Schedule Type",
"mandatory_depends_on": "is_term_loan",
"options": "\nMonthly as per repayment start date\nPro-rated calendar months"
},
{
"depends_on": "eval:doc.repayment_schedule_type == \"Pro-rated calendar months\"",
"description": "Select whether the repayment date should be the end of the current month or start of the upcoming month",
"fieldname": "repayment_date_on",
"fieldtype": "Select",
"label": "Repayment Date On",
"mandatory_depends_on": "eval:doc.repayment_schedule_type == \"Pro-rated calendar months\"",
"options": "\nStart of the next month\nEnd of the current month"
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2022-11-01 17:43:03.954201",
"modified": "2022-01-25 16:23:57.009349",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Loan Type",

View File

@@ -384,7 +384,6 @@ class BOM(WebsiteGenerator):
if self.docstatus == 2:
return
self.flags.cost_updated = False
existing_bom_cost = self.total_cost
if self.docstatus == 1:
@@ -407,11 +406,7 @@ class BOM(WebsiteGenerator):
frappe.get_doc("BOM", bom).update_cost(from_child_bom=True)
if not from_child_bom:
msg = "Cost Updated"
if not self.flags.cost_updated:
msg = "No changes in cost found"
frappe.msgprint(_(msg), alert=True)
frappe.msgprint(_("Cost Updated"), alert=True)
def update_parent_cost(self):
if self.total_cost:
@@ -597,16 +592,11 @@ class BOM(WebsiteGenerator):
# not via doc event, table is not regenerated and needs updation
self.calculate_exploded_cost()
old_cost = self.total_cost
self.total_cost = self.operating_cost + self.raw_material_cost - self.scrap_material_cost
self.base_total_cost = (
self.base_operating_cost + self.base_raw_material_cost - self.base_scrap_material_cost
)
if self.total_cost != old_cost:
self.flags.cost_updated = True
def calculate_op_cost(self, update_hour_rate=False):
"""Update workstation rate and calculates totals"""
self.operating_cost = 0

View File

@@ -583,28 +583,6 @@ class TestBOM(FrappeTestCase):
bom.submit()
self.assertEqual(bom.exploded_items[0].rate, bom.items[0].base_rate)
def test_bom_cost_update_flag(self):
rm_item = make_item(
properties={"is_stock_item": 1, "valuation_rate": 99, "last_purchase_rate": 89}
).name
fg_item = make_item(properties={"is_stock_item": 1}).name
from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
bom = make_bom(item=fg_item, raw_materials=[rm_item])
create_stock_reconciliation(
item_code=rm_item, warehouse="_Test Warehouse - _TC", qty=100, rate=600
)
bom.load_from_db()
bom.update_cost()
self.assertTrue(bom.flags.cost_updated)
bom.load_from_db()
bom.update_cost()
self.assertFalse(bom.flags.cost_updated)
def get_default_bom(item_code="_Test FG Item 2"):
return frappe.db.get_value("BOM", {"item": item_code, "is_active": 1, "is_default": 1})

View File

@@ -133,7 +133,7 @@ class JobCard(Document):
(%(from_time)s <= jctl.from_time and %(to_time)s >= jctl.to_time) {0}
)
and jctl.name != %(name)s and jc.name != %(parent)s and jc.docstatus < 2 {1}
order by jctl.to_time desc""".format(
order by jctl.to_time desc limit 1""".format(
extra_cond, validate_overlap_for
),
{

View File

@@ -133,45 +133,6 @@ class TestJobCard(FrappeTestCase):
)
self.assertRaises(OverlapError, jc2.save)
def test_job_card_overlap_with_capacity(self):
wo2 = make_wo_order_test_record(item="_Test FG Item 2", qty=2)
workstation = make_workstation(workstation_name=random_string(5)).name
frappe.db.set_value("Workstation", workstation, "production_capacity", 1)
jc1 = frappe.get_last_doc("Job Card", {"work_order": self.work_order.name})
jc2 = frappe.get_last_doc("Job Card", {"work_order": wo2.name})
jc1.workstation = workstation
jc1.append(
"time_logs",
{"from_time": "2021-01-01 00:00:00", "to_time": "2021-01-01 08:00:00", "completed_qty": 1},
)
jc1.save()
jc2.workstation = workstation
# add a new entry in same time slice
jc2.append(
"time_logs",
{"from_time": "2021-01-01 00:01:00", "to_time": "2021-01-01 06:00:00", "completed_qty": 1},
)
self.assertRaises(OverlapError, jc2.save)
frappe.db.set_value("Workstation", workstation, "production_capacity", 2)
jc2.load_from_db()
jc2.workstation = workstation
# add a new entry in same time slice
jc2.append(
"time_logs",
{"from_time": "2021-01-01 00:01:00", "to_time": "2021-01-01 06:00:00", "completed_qty": 1},
)
jc2.save()
self.assertTrue(jc2.name)
def test_job_card_multiple_materials_transfer(self):
"Test transferring RMs separately against Job Card with multiple RMs."
self.transfer_material_against = "Job Card"

View File

@@ -27,7 +27,6 @@ from six import iteritems
from erpnext.manufacturing.doctype.bom.bom import get_children, 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
from erpnext.stock.get_item_details import get_conversion_factor
from erpnext.utilities.transaction_base import validate_uom_is_integer
@@ -652,23 +651,13 @@ class ProductionPlan(Document):
else:
material_request = material_request_map[key]
conversion_factor = 1.0
if (
material_request_type == "Purchase"
and item_doc.purchase_uom
and item_doc.purchase_uom != item_doc.stock_uom
):
conversion_factor = (
get_conversion_factor(item_doc.name, item_doc.purchase_uom).get("conversion_factor") or 1.0
)
# add item
material_request.append(
"items",
{
"item_code": item.item_code,
"from_warehouse": item.from_warehouse,
"qty": item.quantity / conversion_factor,
"qty": item.quantity,
"schedule_date": schedule_date,
"warehouse": item.warehouse,
"sales_order": item.sales_order,

View File

@@ -732,35 +732,6 @@ class TestProductionPlan(FrappeTestCase):
self.assertEqual(pln.status, "Completed")
self.assertEqual(pln.po_items[0].produced_qty, 5)
def test_material_request_item_for_purchase_uom(self):
from erpnext.stock.doctype.item.test_item import make_item
fg_item = make_item(properties={"is_stock_item": 1, "stock_uom": "_Test UOM 1"}).name
bom_item = make_item(
properties={"is_stock_item": 1, "stock_uom": "_Test UOM 1", "purchase_uom": "Nos"}
).name
if not frappe.db.exists("UOM Conversion Detail", {"parent": bom_item, "uom": "Nos"}):
doc = frappe.get_doc("Item", bom_item)
doc.append("uoms", {"uom": "Nos", "conversion_factor": 10})
doc.save()
make_bom(item=fg_item, raw_materials=[bom_item], source_warehouse="_Test Warehouse - _TC")
pln = create_production_plan(
item_code=fg_item, planned_qty=10, ignore_existing_ordered_qty=1, stock_uom="_Test UOM 1"
)
pln.make_material_request()
for row in frappe.get_all(
"Material Request Item",
filters={"production_plan": pln.name},
fields=["item_code", "uom", "qty"],
):
self.assertEqual(row.item_code, bom_item)
self.assertEqual(row.uom, "Nos")
self.assertEqual(row.qty, 1)
def create_production_plan(**args):
"""

View File

@@ -555,69 +555,66 @@ erpnext.work_order = {
}
}
if (frm.doc.status != 'Stopped') {
if(!frm.doc.skip_transfer){
// If "Material Consumption is check in Manufacturing Settings, allow Material Consumption
if (frm.doc.__onload && frm.doc.__onload.material_consumption == 1) {
if (flt(doc.material_transferred_for_manufacturing) > 0 || frm.doc.skip_transfer) {
// Only show "Material Consumption" when required_qty > consumed_qty
var counter = 0;
var tbl = frm.doc.required_items || [];
var tbl_lenght = tbl.length;
for (var i = 0, len = tbl_lenght; i < len; i++) {
let wo_item_qty = frm.doc.required_items[i].transferred_qty || frm.doc.required_items[i].required_qty;
if (flt(wo_item_qty) > flt(frm.doc.required_items[i].consumed_qty)) {
counter += 1;
}
}
if (counter > 0) {
var consumption_btn = frm.add_custom_button(__('Material Consumption'), function() {
const backflush_raw_materials_based_on = frm.doc.__onload.backflush_raw_materials_based_on;
erpnext.work_order.make_consumption_se(frm, backflush_raw_materials_based_on);
});
consumption_btn.addClass('btn-primary');
}
}
}
if (flt(doc.material_transferred_for_manufacturing) > 0 && frm.doc.status != 'Stopped') {
if ((flt(doc.produced_qty) < flt(doc.material_transferred_for_manufacturing))) {
frm.has_finish_btn = true;
if(!frm.doc.skip_transfer){
if (flt(doc.material_transferred_for_manufacturing) > 0) {
if ((flt(doc.produced_qty) < flt(doc.material_transferred_for_manufacturing))) {
frm.has_finish_btn = true;
var finish_btn = frm.add_custom_button(__('Finish'), function() {
erpnext.work_order.make_se(frm, 'Manufacture');
});
if(doc.material_transferred_for_manufacturing>=doc.qty) {
// all materials transferred for manufacturing, make this primary
finish_btn.addClass('btn-primary');
}
} else {
frappe.db.get_doc("Manufacturing Settings").then((doc) => {
let allowance_percentage = doc.overproduction_percentage_for_work_order;
if (allowance_percentage > 0) {
let allowed_qty = frm.doc.qty + ((allowance_percentage / 100) * frm.doc.qty);
if ((flt(doc.produced_qty) < allowed_qty)) {
frm.add_custom_button(__('Finish'), function() {
erpnext.work_order.make_se(frm, 'Manufacture');
});
}
if (frm.doc.__onload && frm.doc.__onload.material_consumption == 1) {
// Only show "Material Consumption" when required_qty > consumed_qty
var counter = 0;
var tbl = frm.doc.required_items || [];
var tbl_lenght = tbl.length;
for (var i = 0, len = tbl_lenght; i < len; i++) {
let wo_item_qty = frm.doc.required_items[i].transferred_qty || frm.doc.required_items[i].required_qty;
if (flt(wo_item_qty) > flt(frm.doc.required_items[i].consumed_qty)) {
counter += 1;
}
});
}
if (counter > 0) {
var consumption_btn = frm.add_custom_button(__('Material Consumption'), function() {
const backflush_raw_materials_based_on = frm.doc.__onload.backflush_raw_materials_based_on;
erpnext.work_order.make_consumption_se(frm, backflush_raw_materials_based_on);
});
consumption_btn.addClass('btn-primary');
}
}
}
} else {
if ((flt(doc.produced_qty) < flt(doc.qty))) {
var finish_btn = frm.add_custom_button(__('Finish'), function() {
erpnext.work_order.make_se(frm, 'Manufacture');
});
finish_btn.addClass('btn-primary');
if(doc.material_transferred_for_manufacturing>=doc.qty) {
// all materials transferred for manufacturing, make this primary
finish_btn.addClass('btn-primary');
}
} else {
frappe.db.get_doc("Manufacturing Settings").then((doc) => {
let allowance_percentage = doc.overproduction_percentage_for_work_order;
if (allowance_percentage > 0) {
let allowed_qty = frm.doc.qty + ((allowance_percentage / 100) * frm.doc.qty);
if ((flt(doc.produced_qty) < allowed_qty)) {
frm.add_custom_button(__('Finish'), function() {
erpnext.work_order.make_se(frm, 'Manufacture');
});
}
}
});
}
}
} else {
if ((flt(doc.produced_qty) < flt(doc.qty)) && frm.doc.status != 'Stopped') {
var finish_btn = frm.add_custom_button(__('Finish'), function() {
erpnext.work_order.make_se(frm, 'Manufacture');
});
finish_btn.addClass('btn-primary');
}
}
}
},
calculate_cost: function(doc) {
if (doc.operations){

View File

@@ -374,4 +374,3 @@ erpnext.patches.v13_0.reset_corrupt_defaults
erpnext.patches.v13_0.show_hr_payroll_deprecation_warning
erpnext.patches.v13_0.create_accounting_dimensions_for_asset_repair
execute:frappe.db.set_value("Naming Series", "Naming Series", {"select_doc_for_series": "", "set_options": "", "prefix": "", "current_value": 0, "user_must_always_select": 0})
erpnext.patches.v13_0.update_schedule_type_in_loans

View File

@@ -1,17 +0,0 @@
import frappe
def execute():
frappe.reload_doc("loan_management", "doctype", "loan")
frappe.reload_doc("loan_management", "doctype", "loan_type")
loan = frappe.qb.DocType("Loan")
loan_type = frappe.qb.DocType("Loan Type")
frappe.qb.update(loan_type).set(
loan_type.repayment_schedule_type, "Monthly as per repayment start date"
).where(loan_type.is_term_loan == 1).run()
frappe.qb.update(loan).set(
loan.repayment_schedule_type, "Monthly as per repayment start date"
).where(loan.is_term_loan == 1).run()

View File

@@ -295,7 +295,6 @@ class TestPayrollEntry(FrappeTestCase):
loan_account="Loan Account - _TC",
interest_income_account="Interest Income Account - _TC",
penalty_income_account="Penalty Income Account - _TC",
repayment_schedule_type="Monthly as per repayment start date",
)
loan = create_loan(

View File

@@ -545,7 +545,6 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
if(!this.validate_company_and_party()) {
this.frm.fields_dict["items"].grid.grid_rows[item.idx - 1].remove();
} else {
item.pricing_rules = ''
return this.frm.call({
method: "erpnext.stock.get_item_details.get_item_details",
child: item,
@@ -1161,7 +1160,6 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
uom: function(doc, cdt, cdn) {
var me = this;
var item = frappe.get_doc(cdt, cdn);
item.pricing_rules = ''
if(item.item_code && item.uom) {
return this.frm.call({
method: "erpnext.stock.get_item_details.get_conversion_factor",
@@ -1238,7 +1236,6 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
qty: function(doc, cdt, cdn) {
let item = frappe.get_doc(cdt, cdn);
item.pricing_rules = ''
this.conversion_factor(doc, cdt, cdn, true);
this.calculate_stock_uom_rate(doc, cdt, cdn);
this.apply_pricing_rule(item, true);

View File

@@ -242,29 +242,20 @@ erpnext.utils.set_taxes = function(frm, triggered_from_field) {
});
};
erpnext.utils.get_contact_details = function (frm) {
erpnext.utils.get_contact_details = function(frm) {
if (frm.updating_party_details) return;
if (frm.doc["contact_person"]) {
frappe.call({
method: "frappe.contacts.doctype.contact.contact.get_contact_details",
args: { contact: frm.doc.contact_person },
callback: function (r) {
if (r.message) frm.set_value(r.message);
},
});
} else {
frm.set_value({
contact_person: "",
contact_display: "",
contact_email: "",
contact_mobile: "",
contact_phone: "",
contact_designation: "",
contact_department: "",
});
args: {contact: frm.doc.contact_person },
callback: function(r) {
if (r.message)
frm.set_value(r.message);
}
})
}
};
}
erpnext.utils.validate_mandatory = function(frm, label, value, trigger_on) {
if (!value) {

View File

@@ -47,12 +47,6 @@ erpnext.setup_auto_gst_taxation = (doctype) => {
}
}
});
},
reverse_charge: function(frm) {
if (frm.doc.reverse_charge == "Y") {
frm.set_value('eligibility_for_itc', 'ITC on Reverse Charge');
}
}
});
}

View File

@@ -983,6 +983,8 @@ def validate_reverse_charge_transaction(doc, method):
frappe.throw(msg)
doc.eligibility_for_itc = "ITC on Reverse Charge"
def update_itc_availed_fields(doc, method):
country = frappe.get_cached_value("Company", doc.company, "country")

View File

@@ -83,12 +83,11 @@ erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({
}
}
if (doc.docstatus == 1 && !["Lost", "Ordered"].includes(doc.status)) {
this.frm.add_custom_button(
__("Sales Order"),
this.frm.cscript["Make Sales Order"],
__("Create")
);
if(doc.docstatus == 1 && !(['Lost', 'Ordered']).includes(doc.status)) {
if(!doc.valid_till || frappe.datetime.get_diff(doc.valid_till, frappe.datetime.get_today()) >= 0) {
cur_frm.add_custom_button(__('Sales Order'),
cur_frm.cscript['Make Sales Order'], __('Create'));
}
if(doc.status!=="Ordered") {
this.frm.add_custom_button(__('Set as Lost'), () => {

View File

@@ -95,11 +95,6 @@ frappe.ui.form.on("Sales Order", {
return query;
});
// On cancel and amending a sales order with advance payment, reset advance paid amount
if (frm.is_new()) {
frm.set_value("advance_paid", 0)
}
frm.ignore_doctypes_on_cancel_all = ['Purchase Order'];
},

View File

@@ -19,7 +19,6 @@ from erpnext.accounts.doctype.sales_invoice.sales_invoice import (
update_linked_doc,
validate_inter_company_party,
)
from erpnext.accounts.party import get_party_account
from erpnext.controllers.selling_controller import SellingController
from erpnext.manufacturing.doctype.production_plan.production_plan import (
get_items_for_material_requests,
@@ -798,8 +797,6 @@ def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False):
if source.loyalty_points and source.order_type == "Shopping Cart":
target.redeem_loyalty_points = 1
target.debit_to = get_party_account("Customer", source.customer, source.company)
def update_item(source, target, source_parent):
target.amount = flt(source.amount) - flt(source.billed_amt)
target.base_amount = target.amount * flt(source_parent.conversion_rate)

View File

@@ -67,7 +67,7 @@ erpnext.PointOfSale.Controller = class {
{
fieldtype: 'Link', label: __('POS Profile'),
options: 'POS Profile', fieldname: 'pos_profile', reqd: 1,
get_query: () => pos_profile_query(),
get_query: () => pos_profile_query,
onchange: () => fetch_pos_payment_methods()
},
{
@@ -101,11 +101,9 @@ erpnext.PointOfSale.Controller = class {
primary_action_label: __('Submit')
});
dialog.show();
const pos_profile_query = () => {
return {
query: 'erpnext.accounts.doctype.pos_profile.pos_profile.pos_profile_query',
filters: { company: dialog.fields_dict.company.get_value() }
}
const pos_profile_query = {
query: 'erpnext.accounts.doctype.pos_profile.pos_profile.pos_profile_query',
filters: { company: dialog.fields_dict.company.get_value() }
};
}

View File

@@ -1,71 +1,13 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
frappe.ui.form.on('Brand', {
setup: (frm) => {
frm.fields_dict["brand_defaults"].grid.get_field("default_warehouse").get_query = function(doc, cdt, cdn) {
const row = locals[cdt][cdn];
return {
filters: { company: row.company }
}
}
frm.fields_dict["brand_defaults"].grid.get_field("default_discount_account").get_query = function(doc, cdt, cdn) {
const row = locals[cdt][cdn];
return {
filters: {
'report_type': 'Profit and Loss',
'company': row.company,
"is_group": 0
}
};
}
frm.fields_dict["brand_defaults"].grid.get_field("buying_cost_center").get_query = function(doc, cdt, cdn) {
const row = locals[cdt][cdn];
return {
filters: {
"is_group": 0,
"company": row.company
}
}
}
//--------- ONLOAD -------------
cur_frm.cscript.onload = function(doc, cdt, cdn) {
frm.fields_dict["brand_defaults"].grid.get_field("expense_account").get_query = function(doc, cdt, cdn) {
const row = locals[cdt][cdn];
return {
query: "erpnext.controllers.queries.get_expense_account",
filters: { company: row.company }
}
}
}
frm.fields_dict["brand_defaults"].grid.get_field("default_provisional_account").get_query = function(doc, cdt, cdn) {
const row = locals[cdt][cdn];
return {
filters: {
"company": row.company,
"root_type": ["in", ["Liability", "Asset"]],
"is_group": 0
}
};
}
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
frm.fields_dict["brand_defaults"].grid.get_field("selling_cost_center").get_query = function(doc, cdt, cdn) {
const row = locals[cdt][cdn];
return {
filters: {
"is_group": 0,
"company": row.company
}
}
}
frm.fields_dict["brand_defaults"].grid.get_field("income_account").get_query = function(doc, cdt, cdn) {
const row = locals[cdt][cdn];
return {
query: "erpnext.controllers.queries.get_income_account",
filters: { company: row.company }
}
}
}
});
}

View File

@@ -0,0 +1,327 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
# mappings for table dumps
# "remember to add indexes!"
data_map = {
"Company": {"columns": ["name"], "conditions": ["docstatus < 2"]},
"Fiscal Year": {
"columns": ["name", "year_start_date", "year_end_date"],
"conditions": ["docstatus < 2"],
},
# Accounts
"Account": {
"columns": ["name", "parent_account", "lft", "rgt", "report_type", "company", "is_group"],
"conditions": ["docstatus < 2"],
"order_by": "lft",
"links": {
"company": ["Company", "name"],
},
},
"Cost Center": {
"columns": ["name", "lft", "rgt"],
"conditions": ["docstatus < 2"],
"order_by": "lft",
},
"GL Entry": {
"columns": [
"name",
"account",
"posting_date",
"cost_center",
"debit",
"credit",
"is_opening",
"company",
"voucher_type",
"voucher_no",
"remarks",
],
"order_by": "posting_date, account",
"links": {
"account": ["Account", "name"],
"company": ["Company", "name"],
"cost_center": ["Cost Center", "name"],
},
},
# Stock
"Item": {
"columns": [
"name",
"if(item_name=name, '', item_name) as item_name",
"description",
"item_group as parent_item_group",
"stock_uom",
"brand",
"valuation_method",
],
# "conditions": ["docstatus < 2"],
"order_by": "name",
"links": {"parent_item_group": ["Item Group", "name"], "brand": ["Brand", "name"]},
},
"Item Group": {
"columns": ["name", "parent_item_group"],
# "conditions": ["docstatus < 2"],
"order_by": "lft",
},
"Brand": {"columns": ["name"], "conditions": ["docstatus < 2"], "order_by": "name"},
"Project": {"columns": ["name"], "conditions": ["docstatus < 2"], "order_by": "name"},
"Warehouse": {"columns": ["name"], "conditions": ["docstatus < 2"], "order_by": "name"},
"Stock Ledger Entry": {
"columns": [
"name",
"posting_date",
"posting_time",
"item_code",
"warehouse",
"actual_qty as qty",
"voucher_type",
"voucher_no",
"project",
"incoming_rate as incoming_rate",
"stock_uom",
"serial_no",
"qty_after_transaction",
"valuation_rate",
],
"order_by": "posting_date, posting_time, creation",
"links": {
"item_code": ["Item", "name"],
"warehouse": ["Warehouse", "name"],
"project": ["Project", "name"],
},
"force_index": "posting_sort_index",
},
"Serial No": {
"columns": ["name", "purchase_rate as incoming_rate"],
"conditions": ["docstatus < 2"],
"order_by": "name",
},
"Stock Entry": {
"columns": ["name", "purpose"],
"conditions": ["docstatus=1"],
"order_by": "posting_date, posting_time, name",
},
"Material Request Item": {
"columns": ["item.name as name", "item_code", "warehouse", "(qty - ordered_qty) as qty"],
"from": "`tabMaterial Request Item` item, `tabMaterial Request` main",
"conditions": [
"item.parent = main.name",
"main.docstatus=1",
"main.status != 'Stopped'",
"ifnull(warehouse, '')!=''",
"qty > ordered_qty",
],
"links": {"item_code": ["Item", "name"], "warehouse": ["Warehouse", "name"]},
},
"Purchase Order Item": {
"columns": [
"item.name as name",
"item_code",
"warehouse",
"(qty - received_qty)*conversion_factor as qty",
],
"from": "`tabPurchase Order Item` item, `tabPurchase Order` main",
"conditions": [
"item.parent = main.name",
"main.docstatus=1",
"main.status != 'Stopped'",
"ifnull(warehouse, '')!=''",
"qty > received_qty",
],
"links": {"item_code": ["Item", "name"], "warehouse": ["Warehouse", "name"]},
},
"Sales Order Item": {
"columns": [
"item.name as name",
"item_code",
"(qty - delivered_qty)*conversion_factor as qty",
"warehouse",
],
"from": "`tabSales Order Item` item, `tabSales Order` main",
"conditions": [
"item.parent = main.name",
"main.docstatus=1",
"main.status != 'Stopped'",
"ifnull(warehouse, '')!=''",
"qty > delivered_qty",
],
"links": {"item_code": ["Item", "name"], "warehouse": ["Warehouse", "name"]},
},
# Sales
"Customer": {
"columns": [
"name",
"if(customer_name=name, '', customer_name) as customer_name",
"customer_group as parent_customer_group",
"territory as parent_territory",
],
"conditions": ["docstatus < 2"],
"order_by": "name",
"links": {
"parent_customer_group": ["Customer Group", "name"],
"parent_territory": ["Territory", "name"],
},
},
"Customer Group": {
"columns": ["name", "parent_customer_group"],
"conditions": ["docstatus < 2"],
"order_by": "lft",
},
"Territory": {
"columns": ["name", "parent_territory"],
"conditions": ["docstatus < 2"],
"order_by": "lft",
},
"Sales Invoice": {
"columns": ["name", "customer", "posting_date", "company"],
"conditions": ["docstatus=1"],
"order_by": "posting_date",
"links": {"customer": ["Customer", "name"], "company": ["Company", "name"]},
},
"Sales Invoice Item": {
"columns": ["name", "parent", "item_code", "stock_qty as qty", "base_net_amount"],
"conditions": ["docstatus=1", "ifnull(parent, '')!=''"],
"order_by": "parent",
"links": {"parent": ["Sales Invoice", "name"], "item_code": ["Item", "name"]},
},
"Sales Order": {
"columns": ["name", "customer", "transaction_date as posting_date", "company"],
"conditions": ["docstatus=1"],
"order_by": "transaction_date",
"links": {"customer": ["Customer", "name"], "company": ["Company", "name"]},
},
"Sales Order Item[Sales Analytics]": {
"columns": ["name", "parent", "item_code", "stock_qty as qty", "base_net_amount"],
"conditions": ["docstatus=1", "ifnull(parent, '')!=''"],
"order_by": "parent",
"links": {"parent": ["Sales Order", "name"], "item_code": ["Item", "name"]},
},
"Delivery Note": {
"columns": ["name", "customer", "posting_date", "company"],
"conditions": ["docstatus=1"],
"order_by": "posting_date",
"links": {"customer": ["Customer", "name"], "company": ["Company", "name"]},
},
"Delivery Note Item[Sales Analytics]": {
"columns": ["name", "parent", "item_code", "stock_qty as qty", "base_net_amount"],
"conditions": ["docstatus=1", "ifnull(parent, '')!=''"],
"order_by": "parent",
"links": {"parent": ["Delivery Note", "name"], "item_code": ["Item", "name"]},
},
"Supplier": {
"columns": [
"name",
"if(supplier_name=name, '', supplier_name) as supplier_name",
"supplier_group as parent_supplier_group",
],
"conditions": ["docstatus < 2"],
"order_by": "name",
"links": {
"parent_supplier_group": ["Supplier Group", "name"],
},
},
"Supplier Group": {
"columns": ["name", "parent_supplier_group"],
"conditions": ["docstatus < 2"],
"order_by": "name",
},
"Purchase Invoice": {
"columns": ["name", "supplier", "posting_date", "company"],
"conditions": ["docstatus=1"],
"order_by": "posting_date",
"links": {"supplier": ["Supplier", "name"], "company": ["Company", "name"]},
},
"Purchase Invoice Item": {
"columns": ["name", "parent", "item_code", "stock_qty as qty", "base_net_amount"],
"conditions": ["docstatus=1", "ifnull(parent, '')!=''"],
"order_by": "parent",
"links": {"parent": ["Purchase Invoice", "name"], "item_code": ["Item", "name"]},
},
"Purchase Order": {
"columns": ["name", "supplier", "transaction_date as posting_date", "company"],
"conditions": ["docstatus=1"],
"order_by": "posting_date",
"links": {"supplier": ["Supplier", "name"], "company": ["Company", "name"]},
},
"Purchase Order Item[Purchase Analytics]": {
"columns": ["name", "parent", "item_code", "stock_qty as qty", "base_net_amount"],
"conditions": ["docstatus=1", "ifnull(parent, '')!=''"],
"order_by": "parent",
"links": {"parent": ["Purchase Order", "name"], "item_code": ["Item", "name"]},
},
"Purchase Receipt": {
"columns": ["name", "supplier", "posting_date", "company"],
"conditions": ["docstatus=1"],
"order_by": "posting_date",
"links": {"supplier": ["Supplier", "name"], "company": ["Company", "name"]},
},
"Purchase Receipt Item[Purchase Analytics]": {
"columns": ["name", "parent", "item_code", "stock_qty as qty", "base_net_amount"],
"conditions": ["docstatus=1", "ifnull(parent, '')!=''"],
"order_by": "parent",
"links": {"parent": ["Purchase Receipt", "name"], "item_code": ["Item", "name"]},
},
# Support
"Issue": {
"columns": ["name", "status", "creation", "resolution_date", "first_responded_on"],
"conditions": ["docstatus < 2"],
"order_by": "creation",
},
# Manufacturing
"Work Order": {
"columns": [
"name",
"status",
"creation",
"planned_start_date",
"planned_end_date",
"status",
"actual_start_date",
"actual_end_date",
"modified",
],
"conditions": ["docstatus = 1"],
"order_by": "creation",
},
# Medical
"Patient": {
"columns": [
"name",
"creation",
"owner",
"if(patient_name=name, '', patient_name) as patient_name",
],
"conditions": ["docstatus < 2"],
"order_by": "name",
"links": {"owner": ["User", "name"]},
},
"Patient Appointment": {
"columns": [
"name",
"appointment_type",
"patient",
"practitioner",
"appointment_date",
"department",
"status",
"company",
],
"order_by": "name",
"links": {
"practitioner": ["Healthcare Practitioner", "name"],
"appointment_type": ["Appointment Type", "name"],
},
},
"Healthcare Practitioner": {
"columns": ["name", "department"],
"order_by": "name",
"links": {
"department": ["Department", "name"],
},
},
"Appointment Type": {"columns": ["name"], "order_by": "name"},
"Medical Department": {"columns": ["name"], "order_by": "name"},
}

View File

@@ -285,7 +285,7 @@ def get_batch_no(item_code, warehouse, qty=1, throw=False, serial_no=None):
batches = get_batches(item_code, warehouse, qty, throw, serial_no)
for batch in batches:
if flt(qty) <= flt(batch.qty):
if cint(qty) <= cint(batch.qty):
batch_no = batch.batch_id
break

View File

@@ -832,9 +832,6 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None):
update_address(
target_doc, "shipping_address", "shipping_address_display", source_doc.customer_address
)
update_address(
target_doc, "billing_address", "billing_address_display", source_doc.customer_address
)
update_taxes(
target_doc,

View File

@@ -1050,22 +1050,9 @@ class TestDeliveryNote(FrappeTestCase):
do_not_submit=True,
)
dn.append(
"taxes",
{
"charge_type": "On Net Total",
"account_head": "_Test Account Service Tax - _TC",
"description": "Tax 1",
"rate": 14,
"cost_center": "_Test Cost Center - _TC",
"included_in_print_rate": 1,
},
)
self.assertEqual(dn.items[0].rate, 500) # haven't saved yet
dn.save()
self.assertEqual(dn.ignore_pricing_rule, 1)
self.assertEqual(dn.taxes[0].included_in_print_rate, 0)
# rate should reset to incoming rate
self.assertEqual(dn.items[0].rate, rate)
@@ -1076,7 +1063,6 @@ class TestDeliveryNote(FrappeTestCase):
dn.save()
self.assertEqual(dn.items[0].rate, rate)
self.assertEqual(dn.items[0].net_rate, rate)
def test_internal_transfer_precision_gle(self):
from erpnext.selling.doctype.customer.test_customer import create_internal_customer

View File

@@ -746,7 +746,6 @@
"fieldtype": "Currency",
"label": "Incoming Rate",
"no_copy": 1,
"precision": "6",
"print_hide": 1,
"read_only": 1
},
@@ -781,7 +780,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2022-10-12 03:36:05.344847",
"modified": "2022-05-02 12:09:39.610075",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note Item",

View File

@@ -30,7 +30,7 @@ test_ignore = ["BOM"]
test_dependencies = ["Warehouse", "Item Group", "Item Tax Template", "Brand", "Item Attribute"]
def make_item(item_code=None, properties=None, uoms=None):
def make_item(item_code=None, properties=None):
if not item_code:
item_code = frappe.generate_hash(length=16)
@@ -54,11 +54,6 @@ def make_item(item_code=None, properties=None, uoms=None):
for item_default in [doc for doc in item.get("item_defaults") if not doc.default_warehouse]:
item_default.default_warehouse = "_Test Warehouse - _TC"
item_default.company = "_Test Company"
if uoms:
for uom in uoms:
item.append("uoms", uom)
item.insert()
return item

View File

@@ -4,13 +4,10 @@ from frappe import _
def get_data():
return {
"fieldname": "material_request",
"internal_links": {
"Sales Order": ["items", "sales_order"],
},
"transactions": [
{
"label": _("Reference"),
"items": ["Sales Order", "Request for Quotation", "Supplier Quotation", "Purchase Order"],
"items": ["Request for Quotation", "Supplier Quotation", "Purchase Order"],
},
{"label": _("Stock"), "items": ["Stock Entry", "Purchase Receipt", "Pick List"]},
{"label": _("Manufacturing"), "items": ["Work Order"]},

View File

@@ -12,17 +12,13 @@ def get_data():
"Purchase Receipt": "return_against",
},
"internal_links": {
"Material Request": ["items", "material_request"],
"Purchase Order": ["items", "purchase_order"],
"Project": ["items", "project"],
"Quality Inspection": ["items", "quality_inspection"],
},
"transactions": [
{"label": _("Related"), "items": ["Purchase Invoice", "Landed Cost Voucher", "Asset"]},
{
"label": _("Reference"),
"items": ["Material Request", "Purchase Order", "Quality Inspection", "Project"],
},
{"label": _("Reference"), "items": ["Purchase Order", "Quality Inspection", "Project"]},
{"label": _("Returns"), "items": ["Purchase Receipt"]},
{"label": _("Subscription"), "items": ["Auto Repeat"]},
],

View File

@@ -1404,8 +1404,6 @@ class TestPurchaseReceipt(FrappeTestCase):
self.assertEqual(pr1.items[0].rate, 100)
pr1.submit()
self.assertEqual(pr1.is_internal_supplier, 1)
# Backdated purchase receipt entry, the valuation rate should be updated for DN1 and PR1
make_purchase_receipt(
item_code=item_doc.name,
@@ -1448,234 +1446,6 @@ class TestPurchaseReceipt(FrappeTestCase):
self.assertEqual(query[0].value, 0)
def test_backdated_transaction_for_internal_transfer_in_trasit_warehouse_for_purchase_receipt(
self,
):
from erpnext.stock.doctype.delivery_note.delivery_note import make_inter_company_purchase_receipt
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
prepare_data_for_internal_transfer()
customer = "_Test Internal Customer 2"
company = "_Test Company with perpetual inventory"
from_warehouse = create_warehouse("_Test Internal From Warehouse New", company=company)
to_warehouse = create_warehouse("_Test Internal To Warehouse New", company=company)
item_doc = create_item("Test Internal Transfer Item")
target_warehouse = create_warehouse("_Test Internal GIT Warehouse New", company=company)
make_purchase_receipt(
item_code=item_doc.name,
company=company,
posting_date=add_days(today(), -1),
warehouse=from_warehouse,
qty=1,
rate=100,
)
# Keep stock in advance and make sure that systen won't pick this stock while reposting backdated transaction
for i in range(1, 4):
make_purchase_receipt(
item_code=item_doc.name,
company=company,
posting_date=add_days(today(), -1 * i),
warehouse=target_warehouse,
qty=1,
rate=320 * i,
)
dn1 = create_delivery_note(
item_code=item_doc.name,
company=company,
customer=customer,
cost_center="Main - TCP1",
expense_account="Cost of Goods Sold - TCP1",
qty=1,
rate=500,
warehouse=from_warehouse,
target_warehouse=target_warehouse,
)
self.assertEqual(dn1.items[0].rate, 100)
pr1 = make_inter_company_purchase_receipt(dn1.name)
pr1.items[0].warehouse = to_warehouse
self.assertEqual(pr1.items[0].rate, 100)
pr1.submit()
stk_ledger = frappe.db.get_value(
"Stock Ledger Entry",
{"voucher_type": "Purchase Receipt", "voucher_no": pr1.name, "warehouse": target_warehouse},
["stock_value_difference", "outgoing_rate"],
as_dict=True,
)
self.assertEqual(abs(stk_ledger.stock_value_difference), 100)
self.assertEqual(stk_ledger.outgoing_rate, 100)
# Backdated purchase receipt entry, the valuation rate should be updated for DN1 and PR1
make_purchase_receipt(
item_code=item_doc.name,
company=company,
posting_date=add_days(today(), -2),
warehouse=from_warehouse,
qty=1,
rate=200,
)
dn_value = frappe.db.get_value(
"Stock Ledger Entry",
{"voucher_type": "Delivery Note", "voucher_no": dn1.name, "warehouse": target_warehouse},
"stock_value_difference",
)
self.assertEqual(abs(dn_value), 200.00)
pr_value = frappe.db.get_value(
"Stock Ledger Entry",
{"voucher_type": "Purchase Receipt", "voucher_no": pr1.name, "warehouse": to_warehouse},
"stock_value_difference",
)
self.assertEqual(abs(pr_value), 200.00)
pr1.load_from_db()
self.assertEqual(pr1.items[0].valuation_rate, 200)
self.assertEqual(pr1.items[0].rate, 100)
Gl = frappe.qb.DocType("GL Entry")
query = (
frappe.qb.from_(Gl)
.select(
(fn.Sum(Gl.debit) - fn.Sum(Gl.credit)).as_("value"),
)
.where((Gl.voucher_type == pr1.doctype) & (Gl.voucher_no == pr1.name))
).run(as_dict=True)
self.assertEqual(query[0].value, 0)
def test_backdated_transaction_for_internal_transfer_in_trasit_warehouse_for_purchase_invoice(
self,
):
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import (
make_purchase_invoice as make_purchase_invoice_for_si,
)
from erpnext.accounts.doctype.sales_invoice.sales_invoice import (
make_inter_company_purchase_invoice,
)
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
prepare_data_for_internal_transfer()
customer = "_Test Internal Customer 2"
company = "_Test Company with perpetual inventory"
from_warehouse = create_warehouse("_Test Internal From Warehouse New", company=company)
to_warehouse = create_warehouse("_Test Internal To Warehouse New", company=company)
item_doc = create_item("Test Internal Transfer Item")
target_warehouse = create_warehouse("_Test Internal GIT Warehouse New", company=company)
make_purchase_invoice_for_si(
item_code=item_doc.name,
company=company,
posting_date=add_days(today(), -1),
warehouse=from_warehouse,
qty=1,
update_stock=1,
expense_account="Cost of Goods Sold - TCP1",
cost_center="Main - TCP1",
rate=100,
)
# Keep stock in advance and make sure that systen won't pick this stock while reposting backdated transaction
for i in range(1, 4):
make_purchase_invoice_for_si(
item_code=item_doc.name,
company=company,
posting_date=add_days(today(), -1 * i),
warehouse=target_warehouse,
update_stock=1,
qty=1,
expense_account="Cost of Goods Sold - TCP1",
cost_center="Main - TCP1",
rate=320 * i,
)
si1 = create_sales_invoice(
item_code=item_doc.name,
company=company,
customer=customer,
cost_center="Main - TCP1",
income_account="Sales - TCP1",
qty=1,
rate=500,
update_stock=1,
warehouse=from_warehouse,
target_warehouse=target_warehouse,
)
self.assertEqual(si1.items[0].rate, 100)
pi1 = make_inter_company_purchase_invoice(si1.name)
pi1.items[0].warehouse = to_warehouse
self.assertEqual(pi1.items[0].rate, 100)
pi1.update_stock = 1
pi1.save()
pi1.submit()
stk_ledger = frappe.db.get_value(
"Stock Ledger Entry",
{"voucher_type": pi1.doctype, "voucher_no": pi1.name, "warehouse": target_warehouse},
["stock_value_difference", "outgoing_rate"],
as_dict=True,
)
self.assertEqual(abs(stk_ledger.stock_value_difference), 100)
self.assertEqual(stk_ledger.outgoing_rate, 100)
# Backdated purchase receipt entry, the valuation rate should be updated for si1 and pi1
make_purchase_receipt(
item_code=item_doc.name,
company=company,
posting_date=add_days(today(), -2),
warehouse=from_warehouse,
qty=1,
rate=200,
)
si_value = frappe.db.get_value(
"Stock Ledger Entry",
{"voucher_type": si1.doctype, "voucher_no": si1.name, "warehouse": target_warehouse},
"stock_value_difference",
)
self.assertEqual(abs(si_value), 200.00)
pi_value = frappe.db.get_value(
"Stock Ledger Entry",
{"voucher_type": pi1.doctype, "voucher_no": pi1.name, "warehouse": to_warehouse},
"stock_value_difference",
)
self.assertEqual(abs(pi_value), 200.00)
pi1.load_from_db()
self.assertEqual(pi1.items[0].valuation_rate, 200)
self.assertEqual(pi1.items[0].rate, 100)
Gl = frappe.qb.DocType("GL Entry")
query = (
frappe.qb.from_(Gl)
.select(
(fn.Sum(Gl.debit) - fn.Sum(Gl.credit)).as_("value"),
)
.where((Gl.voucher_type == pi1.doctype) & (Gl.voucher_no == pi1.name))
).run(as_dict=True)
self.assertEqual(query[0].value, 0)
def test_batch_expiry_for_purchase_receipt(self):
from erpnext.controllers.sales_and_purchase_return import make_return_doc

View File

@@ -738,7 +738,6 @@
"oldfieldname": "valuation_rate",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"precision": "6",
"print_hide": 1,
"print_width": "80px",
"read_only": 1,
@@ -993,7 +992,7 @@
"idx": 1,
"istable": 1,
"links": [],
"modified": "2022-10-12 03:37:59.516609",
"modified": "2022-07-28 19:27:54.880781",
"modified_by": "Administrator",
"module": "Stock",
"name": "Purchase Receipt Item",

View File

@@ -864,15 +864,16 @@ def get_pos_reserved_serial_nos(filters):
pos_transacted_sr_nos = query.run(as_dict=True)
reserved_sr_nos = set()
returned_sr_nos = set()
reserved_sr_nos = []
returned_sr_nos = []
for d in pos_transacted_sr_nos:
if d.is_return == 0:
[reserved_sr_nos.add(x) for x in get_serial_nos(d.serial_no)]
reserved_sr_nos += get_serial_nos(d.serial_no)
elif d.is_return == 1:
[returned_sr_nos.add(x) for x in get_serial_nos(d.serial_no)]
returned_sr_nos += get_serial_nos(d.serial_no)
reserved_sr_nos = list(reserved_sr_nos - returned_sr_nos)
for sr_no in returned_sr_nos:
reserved_sr_nos.remove(sr_no)
return reserved_sr_nos

View File

@@ -902,15 +902,13 @@ def create_product_bundle_item(new_item_code, packed_items):
item.save()
def create_items(items=None, uoms=None):
if not items:
items = [
"_Test Item for Reposting",
"_Test Finished Item for Reposting",
"_Test Subcontracted Item for Reposting",
"_Test Bundled Item for Reposting",
]
def create_items():
items = [
"_Test Item for Reposting",
"_Test Finished Item for Reposting",
"_Test Subcontracted Item for Reposting",
"_Test Bundled Item for Reposting",
]
for d in items:
properties = {"valuation_method": "FIFO"}
if d == "_Test Bundled Item for Reposting":
@@ -918,7 +916,7 @@ def create_items(items=None, uoms=None):
elif d == "_Test Subcontracted Item for Reposting":
properties.update({"is_sub_contracted_item": 1})
make_item(d, properties=properties, uoms=uoms)
make_item(d, properties=properties)
return items

View File

@@ -131,9 +131,7 @@ class StockReconciliation(StockController):
key.append(row.get(field))
if key in item_warehouse_combinations:
self.validation_messages.append(
_get_msg(row_num, _("Same item and warehouse combination already entered."))
)
self.validation_messages.append(_get_msg(row_num, _("Duplicate entry")))
else:
item_warehouse_combinations.append(key)

View File

@@ -74,21 +74,10 @@ def get_conditions(filters):
else:
frappe.throw(_("'To Date' is required"))
for field in ["item_code", "batch_no", "company"]:
for field in ["item_code", "warehouse", "batch_no", "company"]:
if filters.get(field):
conditions += " and {0} = {1}".format(field, frappe.db.escape(filters.get(field)))
if filters.get("warehouse"):
warehouse_details = frappe.db.get_value(
"Warehouse", filters.get("warehouse"), ["lft", "rgt"], as_dict=1
)
if warehouse_details:
conditions += (
" and exists (select name from `tabWarehouse` wh \
where wh.lft >= %s and wh.rgt <= %s and sle.warehouse = wh.name)"
% (warehouse_details.lft, warehouse_details.rgt)
)
return conditions
@@ -98,7 +87,7 @@ def get_stock_ledger_entries(filters):
return frappe.db.sql(
"""
select item_code, batch_no, warehouse, posting_date, sum(actual_qty) as actual_qty
from `tabStock Ledger Entry` as sle
from `tabStock Ledger Entry`
where is_cancelled = 0 and docstatus < 2 and ifnull(batch_no, '') != '' %s
group by voucher_no, batch_no, item_code, warehouse
order by item_code, warehouse"""

View File

@@ -532,14 +532,6 @@ class update_entries_after(object):
if not self.args.get("sle_id"):
self.get_dynamic_incoming_outgoing_rate(sle)
if (
sle.voucher_type in ["Purchase Receipt", "Purchase Invoice"]
and sle.voucher_detail_no
and sle.actual_qty < 0
and frappe.get_cached_value(sle.voucher_type, sle.voucher_no, "is_internal_supplier")
):
sle.outgoing_rate = get_incoming_rate_for_inter_company_transfer(sle)
if get_serial_nos(sle.serial_no):
self.get_serialized_values(sle)
self.wh_data.qty_after_transaction += flt(sle.actual_qty)
@@ -587,7 +579,6 @@ class update_entries_after(object):
sle.stock_queue = json.dumps(self.wh_data.stock_queue)
sle.stock_value_difference = stock_value_difference
sle.doctype = "Stock Ledger Entry"
frappe.get_doc(sle).db_update()
if not self.args.get("sle_id"):
@@ -650,7 +641,22 @@ class update_entries_after(object):
and sle.voucher_detail_no
and frappe.get_cached_value(sle.voucher_type, sle.voucher_no, "is_internal_supplier")
):
rate = get_incoming_rate_for_inter_company_transfer(sle)
field = (
"delivery_note_item" if sle.voucher_type == "Purchase Receipt" else "sales_invoice_item"
)
doctype = (
"Delivery Note Item" if sle.voucher_type == "Purchase Receipt" else "Sales Invoice Item"
)
refernce_name = frappe.get_cached_value(
sle.voucher_type + " Item", sle.voucher_detail_no, field
)
if refernce_name:
rate = frappe.get_cached_value(
doctype,
refernce_name,
"incoming_rate",
)
else:
if sle.voucher_type in ("Purchase Receipt", "Purchase Invoice"):
rate_field = "valuation_rate"
@@ -725,12 +731,14 @@ class update_entries_after(object):
def update_rate_on_purchase_receipt(self, sle, outgoing_rate):
if frappe.db.exists(sle.voucher_type + " Item", sle.voucher_detail_no):
if sle.voucher_type in ["Purchase Receipt", "Purchase Invoice"] and frappe.get_cached_value(
sle.voucher_type, sle.voucher_no, "is_internal_supplier"
):
frappe.db.set_value(
f"{sle.voucher_type} Item", sle.voucher_detail_no, "valuation_rate", sle.outgoing_rate
)
frappe.db.set_value(
sle.voucher_type + " Item",
sle.voucher_detail_no,
{
"base_net_rate": outgoing_rate,
"valuation_rate": outgoing_rate,
},
)
else:
frappe.db.set_value(
"Purchase Receipt Item Supplied", sle.voucher_detail_no, "rate", outgoing_rate
@@ -1474,25 +1482,3 @@ def _round_off_if_near_zero(number: float, precision: int = 6) -> float:
return 0.0
return flt(number)
def get_incoming_rate_for_inter_company_transfer(sle) -> float:
"""
For inter company transfer, incoming rate is the average of the outgoing rate
"""
rate = 0.0
field = "delivery_note_item" if sle.voucher_type == "Purchase Receipt" else "sales_invoice_item"
doctype = "Delivery Note Item" if sle.voucher_type == "Purchase Receipt" else "Sales Invoice Item"
reference_name = frappe.get_cached_value(sle.voucher_type + " Item", sle.voucher_detail_no, field)
if reference_name:
rate = frappe.get_cached_value(
doctype,
reference_name,
"incoming_rate",
)
return rate

View File

@@ -9865,35 +9865,3 @@ Leave Type Allocation,Zuordnung Abwesenheitsarten,
From Lead,Aus Lead,
From Opportunity,Aus Chance,
Publish in Website,Auf Webseite veröffentlichen,
Total Allocated Leave(s),Gesamte zugewiesene Urlaubstage,
Expired Leave(s),Verfallene Urlaubstage,
Used Leave(s),Verbrauchte Urlaubstage,
Leave(s) Pending Approval,Urlaubstage zur Genehmigung ausstehend,
Available Leave(s),Verfügbare Urlaubstage,
Party Specific Item,Parteispezifischer Artikel,
Active Customers,Aktive Kunden,
Annual Sales,Jährlicher Umsatz,
Total Outgoing Bills,Ausgangsrechnungen insgesamt,
Total Incoming Bills,Eingangsrechnungen insgesamt,
Total Incoming Payment,Zahlungseingang insgesamt,
Total Outgoing Payment,Zahlungsausgang insgesamt,
Incoming Bills (Purchase Invoice),Eingehende Rechnungen (Eingangsrechnung),
Outgoing Bills (Sales Invoice),Ausgehende Rechnungen (Ausgangsrechnung),
Accounts Receivable Ageing,Fälligkeit Forderungen,
Accounts Payable Ageing,Fälligkeit Verbindlichkeiten,
Budget Variance,Budgetabweichung,
Based On Value,Basierend auf Wert,
Restrict Items Based On,Artikel einschränken auf Basis von,
Earnings & Deductions,Erträge & Abzüge,
Is Process Loss,Ist Prozessverlust,
Is Finished Item,Ist fertiger Artikel,
Is Scrap Item,Ist Schrott,
Issue a debit note with 0 qty against an existing Sales Invoice,Lastschrift mit Menge 0 gegen eine bestehende Ausgangsrechnung ausstellen,
Show Remarks,Bemerkungen anzeigen,
Website Item,Webseiten-Artikel,
Update Property,Eigenschaft aktualisieren,
Recurring Sales Invoice,Wiederkehrende Ausgangsrechnung,
Total Asset,Aktiva,
Total Liability,Verbindlichkeiten,
Total Equity,Eigenkapital,
Warehouse wise Stock Value,Warenwert nach Lager,
Can't render this file because it is too large.

View File

@@ -60,7 +60,7 @@ def update_youtube_data():
"Video Settings", "Video Settings", ["enable_youtube_tracking", "frequency"]
)
if not frappe.utils.cint(enable_youtube_tracking):
if not enable_youtube_tracking:
return
frequency = get_frequency(frequency)