Merge branch 'develop' into fix/v14/stock-entry/send-to-subcontractor
This commit is contained in:
commit
b49caf170c
@ -141,7 +141,7 @@ frappe.ui.form.on("Bank Statement Import", {
|
|||||||
},
|
},
|
||||||
|
|
||||||
show_import_status(frm) {
|
show_import_status(frm) {
|
||||||
let import_log = JSON.parse(frm.doc.import_log || "[]");
|
let import_log = JSON.parse(frm.doc.statement_import_log || "[]");
|
||||||
let successful_records = import_log.filter((log) => log.success);
|
let successful_records = import_log.filter((log) => log.success);
|
||||||
let failed_records = import_log.filter((log) => !log.success);
|
let failed_records = import_log.filter((log) => !log.success);
|
||||||
if (successful_records.length === 0) return;
|
if (successful_records.length === 0) return;
|
||||||
@ -309,7 +309,7 @@ frappe.ui.form.on("Bank Statement Import", {
|
|||||||
// method: 'frappe.core.doctype.data_import.data_import.get_preview_from_template',
|
// method: 'frappe.core.doctype.data_import.data_import.get_preview_from_template',
|
||||||
|
|
||||||
show_import_preview(frm, preview_data) {
|
show_import_preview(frm, preview_data) {
|
||||||
let import_log = JSON.parse(frm.doc.import_log || "[]");
|
let import_log = JSON.parse(frm.doc.statement_import_log || "[]");
|
||||||
|
|
||||||
if (
|
if (
|
||||||
frm.import_preview &&
|
frm.import_preview &&
|
||||||
@ -439,7 +439,7 @@ frappe.ui.form.on("Bank Statement Import", {
|
|||||||
},
|
},
|
||||||
|
|
||||||
show_import_log(frm) {
|
show_import_log(frm) {
|
||||||
let import_log = JSON.parse(frm.doc.import_log || "[]");
|
let import_log = JSON.parse(frm.doc.statement_import_log || "[]");
|
||||||
let logs = import_log;
|
let logs = import_log;
|
||||||
frm.toggle_display("import_log", false);
|
frm.toggle_display("import_log", false);
|
||||||
frm.toggle_display("import_log_section", logs.length > 0);
|
frm.toggle_display("import_log_section", logs.length > 0);
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
"section_import_preview",
|
"section_import_preview",
|
||||||
"import_preview",
|
"import_preview",
|
||||||
"import_log_section",
|
"import_log_section",
|
||||||
"import_log",
|
"statement_import_log",
|
||||||
"show_failed_logs",
|
"show_failed_logs",
|
||||||
"import_log_preview",
|
"import_log_preview",
|
||||||
"reference_doctype",
|
"reference_doctype",
|
||||||
@ -90,12 +90,6 @@
|
|||||||
"options": "JSON",
|
"options": "JSON",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "import_log",
|
|
||||||
"fieldtype": "Code",
|
|
||||||
"label": "Import Log",
|
|
||||||
"options": "JSON"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"fieldname": "import_log_section",
|
"fieldname": "import_log_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
@ -198,11 +192,17 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "column_break_4",
|
"fieldname": "column_break_4",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "statement_import_log",
|
||||||
|
"fieldtype": "Code",
|
||||||
|
"label": "Statement Import Log",
|
||||||
|
"options": "JSON"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"hide_toolbar": 1,
|
"hide_toolbar": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-05-12 14:17:37.777246",
|
"modified": "2022-09-07 11:11:40.293317",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Bank Statement Import",
|
"name": "Bank Statement Import",
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<table class="table table-bordered">
|
<table class="table table-bordered" style="font-size: 10px">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width: 12%">{{ _("Date") }}</th>
|
<th style="width: 12%">{{ _("Date") }}</th>
|
||||||
|
@ -700,6 +700,47 @@ class StockController(AccountsController):
|
|||||||
else:
|
else:
|
||||||
create_repost_item_valuation_entry(args)
|
create_repost_item_valuation_entry(args)
|
||||||
|
|
||||||
|
def add_gl_entry(
|
||||||
|
self,
|
||||||
|
gl_entries,
|
||||||
|
account,
|
||||||
|
cost_center,
|
||||||
|
debit,
|
||||||
|
credit,
|
||||||
|
remarks,
|
||||||
|
against_account,
|
||||||
|
debit_in_account_currency=None,
|
||||||
|
credit_in_account_currency=None,
|
||||||
|
account_currency=None,
|
||||||
|
project=None,
|
||||||
|
voucher_detail_no=None,
|
||||||
|
item=None,
|
||||||
|
posting_date=None,
|
||||||
|
):
|
||||||
|
|
||||||
|
gl_entry = {
|
||||||
|
"account": account,
|
||||||
|
"cost_center": cost_center,
|
||||||
|
"debit": debit,
|
||||||
|
"credit": credit,
|
||||||
|
"against": against_account,
|
||||||
|
"remarks": remarks,
|
||||||
|
}
|
||||||
|
|
||||||
|
if voucher_detail_no:
|
||||||
|
gl_entry.update({"voucher_detail_no": voucher_detail_no})
|
||||||
|
|
||||||
|
if debit_in_account_currency:
|
||||||
|
gl_entry.update({"debit_in_account_currency": debit_in_account_currency})
|
||||||
|
|
||||||
|
if credit_in_account_currency:
|
||||||
|
gl_entry.update({"credit_in_account_currency": credit_in_account_currency})
|
||||||
|
|
||||||
|
if posting_date:
|
||||||
|
gl_entry.update({"posting_date": posting_date})
|
||||||
|
|
||||||
|
gl_entries.append(self.get_gl_dict(gl_entry, item=item))
|
||||||
|
|
||||||
|
|
||||||
def repost_required_for_queue(doc: StockController) -> bool:
|
def repost_required_for_queue(doc: StockController) -> bool:
|
||||||
"""check if stock document contains repeated item-warehouse with queue based valuation.
|
"""check if stock document contains repeated item-warehouse with queue based valuation.
|
||||||
|
@ -877,6 +877,7 @@ def make_return_stock_entry_for_subcontract(
|
|||||||
{
|
{
|
||||||
order_doctype: {
|
order_doctype: {
|
||||||
"doctype": "Stock Entry",
|
"doctype": "Stock Entry",
|
||||||
|
"field_no_map": ["purchase_order", "subcontracting_order"],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ignore_child_tables=True,
|
ignore_child_tables=True,
|
||||||
|
@ -897,7 +897,7 @@ def make_stock_transfer_entry(**args):
|
|||||||
"item_name": row.item_code,
|
"item_name": row.item_code,
|
||||||
"rate": row.rate or 100,
|
"rate": row.rate or 100,
|
||||||
"stock_uom": row.stock_uom or "Nos",
|
"stock_uom": row.stock_uom or "Nos",
|
||||||
"warehouse": row.warehuose or "_Test Warehouse - _TC",
|
"warehouse": row.warehouse or "_Test Warehouse - _TC",
|
||||||
}
|
}
|
||||||
|
|
||||||
item_details = args.itemwise_details.get(row.item_code)
|
item_details = args.itemwise_details.get(row.item_code)
|
||||||
@ -1031,9 +1031,9 @@ def get_subcontracting_order(**args):
|
|||||||
if not args.service_items:
|
if not args.service_items:
|
||||||
service_items = [
|
service_items = [
|
||||||
{
|
{
|
||||||
"warehouse": "_Test Warehouse - _TC",
|
"warehouse": args.warehouse or "_Test Warehouse - _TC",
|
||||||
"item_code": "Subcontracted Service Item 7",
|
"item_code": "Subcontracted Service Item 7",
|
||||||
"qty": 5,
|
"qty": 10,
|
||||||
"rate": 100,
|
"rate": 100,
|
||||||
"fg_item": "Subcontracted Item SA7",
|
"fg_item": "Subcontracted Item SA7",
|
||||||
"fg_item_qty": 10,
|
"fg_item_qty": 10,
|
||||||
@ -1046,6 +1046,7 @@ def get_subcontracting_order(**args):
|
|||||||
rm_items=service_items,
|
rm_items=service_items,
|
||||||
is_subcontracted=1,
|
is_subcontracted=1,
|
||||||
supplier_warehouse=args.supplier_warehouse or "_Test Warehouse 1 - _TC",
|
supplier_warehouse=args.supplier_warehouse or "_Test Warehouse 1 - _TC",
|
||||||
|
company=args.company,
|
||||||
)
|
)
|
||||||
|
|
||||||
return create_subcontracting_order(po_name=po.name, **args)
|
return create_subcontracting_order(po_name=po.name, **args)
|
||||||
|
@ -312,4 +312,5 @@ erpnext.patches.v13_0.fix_number_and_frequency_for_monthly_depreciation
|
|||||||
erpnext.patches.v14_0.remove_hr_and_payroll_modules # 20-07-2022
|
erpnext.patches.v14_0.remove_hr_and_payroll_modules # 20-07-2022
|
||||||
erpnext.patches.v14_0.fix_crm_no_of_employees
|
erpnext.patches.v14_0.fix_crm_no_of_employees
|
||||||
erpnext.patches.v14_0.create_accounting_dimensions_in_subcontracting_doctypes
|
erpnext.patches.v14_0.create_accounting_dimensions_in_subcontracting_doctypes
|
||||||
|
erpnext.patches.v14_0.fix_subcontracting_receipt_gl_entries
|
||||||
erpnext.patches.v14_0.migrate_remarks_from_gl_to_payment_ledger
|
erpnext.patches.v14_0.migrate_remarks_from_gl_to_payment_ledger
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
from erpnext.stock.report.stock_and_account_value_comparison.stock_and_account_value_comparison import (
|
||||||
|
get_data,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
data = []
|
||||||
|
|
||||||
|
for company in frappe.db.get_list("Company", pluck="name"):
|
||||||
|
data += get_data(
|
||||||
|
frappe._dict(
|
||||||
|
{
|
||||||
|
"company": company,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if data:
|
||||||
|
for d in data:
|
||||||
|
if d and d.get("voucher_type") == "Subcontracting Receipt":
|
||||||
|
doc = frappe.new_doc("Repost Item Valuation")
|
||||||
|
doc.voucher_type = d.get("voucher_type")
|
||||||
|
doc.voucher_no = d.get("voucher_no")
|
||||||
|
doc.save()
|
||||||
|
doc.submit()
|
@ -226,7 +226,7 @@ $.extend(erpnext.utils, {
|
|||||||
if (!found) {
|
if (!found) {
|
||||||
filters.splice(index, 0, {
|
filters.splice(index, 0, {
|
||||||
"fieldname": dimension["fieldname"],
|
"fieldname": dimension["fieldname"],
|
||||||
"label": __(dimension["label"]),
|
"label": __(dimension["doctype"]),
|
||||||
"fieldtype": "MultiSelectList",
|
"fieldtype": "MultiSelectList",
|
||||||
get_data: function(txt) {
|
get_data: function(txt) {
|
||||||
return frappe.db.get_link_options(dimension["doctype"], txt);
|
return frappe.db.get_link_options(dimension["doctype"], txt);
|
||||||
|
@ -362,6 +362,12 @@ class PurchaseReceipt(BuyingController):
|
|||||||
if credit_currency == self.company_currency
|
if credit_currency == self.company_currency
|
||||||
else flt(d.net_amount, d.precision("net_amount"))
|
else flt(d.net_amount, d.precision("net_amount"))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
outgoing_amount = d.base_net_amount
|
||||||
|
if self.is_internal_supplier and d.valuation_rate:
|
||||||
|
outgoing_amount = d.valuation_rate * d.stock_qty
|
||||||
|
credit_amount = outgoing_amount
|
||||||
|
|
||||||
if credit_amount:
|
if credit_amount:
|
||||||
account = warehouse_account[d.from_warehouse]["account"] if d.from_warehouse else stock_rbnb
|
account = warehouse_account[d.from_warehouse]["account"] if d.from_warehouse else stock_rbnb
|
||||||
|
|
||||||
@ -369,7 +375,7 @@ class PurchaseReceipt(BuyingController):
|
|||||||
gl_entries=gl_entries,
|
gl_entries=gl_entries,
|
||||||
account=account,
|
account=account,
|
||||||
cost_center=d.cost_center,
|
cost_center=d.cost_center,
|
||||||
debit=-1 * flt(d.base_net_amount, d.precision("base_net_amount")),
|
debit=-1 * flt(outgoing_amount, d.precision("base_net_amount")),
|
||||||
credit=0.0,
|
credit=0.0,
|
||||||
remarks=remarks,
|
remarks=remarks,
|
||||||
against_account=warehouse_account_name,
|
against_account=warehouse_account_name,
|
||||||
@ -456,7 +462,7 @@ class PurchaseReceipt(BuyingController):
|
|||||||
|
|
||||||
# divisional loss adjustment
|
# divisional loss adjustment
|
||||||
valuation_amount_as_per_doc = (
|
valuation_amount_as_per_doc = (
|
||||||
flt(d.base_net_amount, d.precision("base_net_amount"))
|
flt(outgoing_amount, d.precision("base_net_amount"))
|
||||||
+ flt(d.landed_cost_voucher_amount)
|
+ flt(d.landed_cost_voucher_amount)
|
||||||
+ flt(d.rm_supp_cost)
|
+ flt(d.rm_supp_cost)
|
||||||
+ flt(d.item_tax_amount)
|
+ flt(d.item_tax_amount)
|
||||||
@ -631,47 +637,6 @@ class PurchaseReceipt(BuyingController):
|
|||||||
|
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
def add_gl_entry(
|
|
||||||
self,
|
|
||||||
gl_entries,
|
|
||||||
account,
|
|
||||||
cost_center,
|
|
||||||
debit,
|
|
||||||
credit,
|
|
||||||
remarks,
|
|
||||||
against_account,
|
|
||||||
debit_in_account_currency=None,
|
|
||||||
credit_in_account_currency=None,
|
|
||||||
account_currency=None,
|
|
||||||
project=None,
|
|
||||||
voucher_detail_no=None,
|
|
||||||
item=None,
|
|
||||||
posting_date=None,
|
|
||||||
):
|
|
||||||
|
|
||||||
gl_entry = {
|
|
||||||
"account": account,
|
|
||||||
"cost_center": cost_center,
|
|
||||||
"debit": debit,
|
|
||||||
"credit": credit,
|
|
||||||
"against": against_account,
|
|
||||||
"remarks": remarks,
|
|
||||||
}
|
|
||||||
|
|
||||||
if voucher_detail_no:
|
|
||||||
gl_entry.update({"voucher_detail_no": voucher_detail_no})
|
|
||||||
|
|
||||||
if debit_in_account_currency:
|
|
||||||
gl_entry.update({"debit_in_account_currency": debit_in_account_currency})
|
|
||||||
|
|
||||||
if credit_in_account_currency:
|
|
||||||
gl_entry.update({"credit_in_account_currency": credit_in_account_currency})
|
|
||||||
|
|
||||||
if posting_date:
|
|
||||||
gl_entry.update({"posting_date": posting_date})
|
|
||||||
|
|
||||||
gl_entries.append(self.get_gl_dict(gl_entry, item=item))
|
|
||||||
|
|
||||||
def get_asset_gl_entry(self, gl_entries):
|
def get_asset_gl_entry(self, gl_entries):
|
||||||
for item in self.get("items"):
|
for item in self.get("items"):
|
||||||
if item.is_fixed_asset:
|
if item.is_fixed_asset:
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe.tests.utils import FrappeTestCase, change_settings
|
from frappe.tests.utils import FrappeTestCase, change_settings
|
||||||
from frappe.utils import add_days, cint, cstr, flt, today
|
from frappe.utils import add_days, cint, cstr, flt, today
|
||||||
|
from pypika import functions as fn
|
||||||
|
|
||||||
import erpnext
|
import erpnext
|
||||||
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
||||||
@ -1156,6 +1157,125 @@ class TestPurchaseReceipt(FrappeTestCase):
|
|||||||
if gle.account == account:
|
if gle.account == account:
|
||||||
self.assertEqual(gle.credit, 50)
|
self.assertEqual(gle.credit, 50)
|
||||||
|
|
||||||
|
def test_backdated_transaction_for_internal_transfer(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,
|
||||||
|
)
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
# 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 prepare_data_for_internal_transfer():
|
||||||
|
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier
|
||||||
|
from erpnext.selling.doctype.customer.test_customer import create_internal_customer
|
||||||
|
|
||||||
|
company = "_Test Company with perpetual inventory"
|
||||||
|
|
||||||
|
create_internal_customer(
|
||||||
|
"_Test Internal Customer 2",
|
||||||
|
company,
|
||||||
|
company,
|
||||||
|
)
|
||||||
|
|
||||||
|
create_internal_supplier(
|
||||||
|
"_Test Internal Supplier 2",
|
||||||
|
company,
|
||||||
|
company,
|
||||||
|
)
|
||||||
|
|
||||||
|
if not frappe.db.get_value("Company", company, "unrealized_profit_loss_account"):
|
||||||
|
account = "Unrealized Profit and Loss - TCP1"
|
||||||
|
if not frappe.db.exists("Account", account):
|
||||||
|
frappe.get_doc(
|
||||||
|
{
|
||||||
|
"doctype": "Account",
|
||||||
|
"account_name": "Unrealized Profit and Loss",
|
||||||
|
"parent_account": "Direct Income - TCP1",
|
||||||
|
"company": company,
|
||||||
|
"is_group": 0,
|
||||||
|
"account_type": "Income Account",
|
||||||
|
}
|
||||||
|
).insert()
|
||||||
|
|
||||||
|
frappe.db.set_value("Company", company, "unrealized_profit_loss_account", account)
|
||||||
|
|
||||||
|
|
||||||
def get_sl_entries(voucher_type, voucher_no):
|
def get_sl_entries(voucher_type, voucher_no):
|
||||||
return frappe.db.sql(
|
return frappe.db.sql(
|
||||||
|
@ -58,6 +58,21 @@ frappe.ui.form.on('Repost Item Valuation', {
|
|||||||
}
|
}
|
||||||
|
|
||||||
frm.trigger('show_reposting_progress');
|
frm.trigger('show_reposting_progress');
|
||||||
|
|
||||||
|
if (frm.doc.status === 'Queued' && frm.doc.docstatus === 1) {
|
||||||
|
frm.trigger('execute_reposting');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
execute_reposting(frm) {
|
||||||
|
frm.add_custom_button(__("Start Reposting"), () => {
|
||||||
|
frappe.call({
|
||||||
|
method: 'erpnext.stock.doctype.repost_item_valuation.repost_item_valuation.execute_repost_item_valuation',
|
||||||
|
callback: function() {
|
||||||
|
frappe.msgprint(__('Reposting has been started in the background.'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
show_reposting_progress: function(frm) {
|
show_reposting_progress: function(frm) {
|
||||||
|
@ -307,3 +307,9 @@ def in_configured_timeslot(repost_settings=None, current_time=None):
|
|||||||
return end_time >= now_time >= start_time
|
return end_time >= now_time >= start_time
|
||||||
else:
|
else:
|
||||||
return now_time >= start_time or now_time <= end_time
|
return now_time >= start_time or now_time <= end_time
|
||||||
|
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def execute_repost_item_valuation():
|
||||||
|
"""Execute repost item valuation via scheduler."""
|
||||||
|
frappe.get_doc("Scheduled Job Type", "repost_item_valuation.repost_entries").enqueue(force=True)
|
||||||
|
@ -649,21 +649,25 @@ class update_entries_after(object):
|
|||||||
|
|
||||||
elif (
|
elif (
|
||||||
sle.voucher_type in ["Purchase Receipt", "Purchase Invoice"]
|
sle.voucher_type in ["Purchase Receipt", "Purchase Invoice"]
|
||||||
and sle.actual_qty > 0
|
and sle.voucher_detail_no
|
||||||
and frappe.get_cached_value(sle.voucher_type, sle.voucher_no, "is_internal_supplier")
|
and frappe.get_cached_value(sle.voucher_type, sle.voucher_no, "is_internal_supplier")
|
||||||
):
|
):
|
||||||
sle_details = frappe.db.get_value(
|
field = (
|
||||||
"Stock Ledger Entry",
|
"delivery_note_item" if sle.voucher_type == "Purchase Receipt" else "sales_invoice_item"
|
||||||
{
|
)
|
||||||
"voucher_type": sle.voucher_type,
|
doctype = (
|
||||||
"voucher_no": sle.voucher_no,
|
"Delivery Note Item" if sle.voucher_type == "Purchase Receipt" else "Sales Invoice Item"
|
||||||
"dependant_sle_voucher_detail_no": sle.voucher_detail_no,
|
)
|
||||||
},
|
refernce_name = frappe.get_cached_value(
|
||||||
["stock_value_difference", "actual_qty"],
|
sle.voucher_type + " Item", sle.voucher_detail_no, field
|
||||||
as_dict=1,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
rate = abs(sle_details.stock_value_difference / sle.actual_qty)
|
if refernce_name:
|
||||||
|
rate = frappe.get_cached_value(
|
||||||
|
doctype,
|
||||||
|
refernce_name,
|
||||||
|
"incoming_rate",
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
if sle.voucher_type in ("Purchase Receipt", "Purchase Invoice"):
|
if sle.voucher_type in ("Purchase Receipt", "Purchase Invoice"):
|
||||||
rate_field = "valuation_rate"
|
rate_field = "valuation_rate"
|
||||||
@ -745,7 +749,12 @@ class update_entries_after(object):
|
|||||||
def update_rate_on_purchase_receipt(self, sle, outgoing_rate):
|
def update_rate_on_purchase_receipt(self, sle, outgoing_rate):
|
||||||
if frappe.db.exists(sle.voucher_type + " Item", sle.voucher_detail_no):
|
if frappe.db.exists(sle.voucher_type + " Item", sle.voucher_detail_no):
|
||||||
frappe.db.set_value(
|
frappe.db.set_value(
|
||||||
sle.voucher_type + " Item", sle.voucher_detail_no, "base_net_rate", outgoing_rate
|
sle.voucher_type + " Item",
|
||||||
|
sle.voucher_detail_no,
|
||||||
|
{
|
||||||
|
"base_net_rate": outgoing_rate,
|
||||||
|
"valuation_rate": outgoing_rate,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
frappe.db.set_value(
|
frappe.db.set_value(
|
||||||
|
@ -107,7 +107,7 @@ frappe.ui.form.on('Subcontracting Order', {
|
|||||||
get_materials_from_supplier: function (frm) {
|
get_materials_from_supplier: function (frm) {
|
||||||
let sco_rm_details = [];
|
let sco_rm_details = [];
|
||||||
|
|
||||||
if (frm.doc.supplied_items && frm.doc.per_received > 0) {
|
if (frm.doc.status != "Closed" && frm.doc.supplied_items && frm.doc.per_received > 0) {
|
||||||
frm.doc.supplied_items.forEach(d => {
|
frm.doc.supplied_items.forEach(d => {
|
||||||
if (d.total_supplied_qty > 0 && d.total_supplied_qty != d.consumed_qty) {
|
if (d.total_supplied_qty > 0 && d.total_supplied_qty != d.consumed_qty) {
|
||||||
sco_rm_details.push(d.name);
|
sco_rm_details.push(d.name);
|
||||||
|
@ -502,6 +502,35 @@ class TestSubcontractingOrder(FrappeTestCase):
|
|||||||
|
|
||||||
set_backflush_based_on("BOM")
|
set_backflush_based_on("BOM")
|
||||||
|
|
||||||
|
def test_get_materials_from_supplier(self):
|
||||||
|
# Create SCO
|
||||||
|
sco = get_subcontracting_order()
|
||||||
|
|
||||||
|
# Transfer RM
|
||||||
|
rm_items = get_rm_items(sco.supplied_items)
|
||||||
|
itemwise_details = make_stock_in_entry(rm_items=rm_items)
|
||||||
|
make_stock_transfer_entry(
|
||||||
|
sco_no=sco.name,
|
||||||
|
rm_items=rm_items,
|
||||||
|
itemwise_details=copy.deepcopy(itemwise_details),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create SCR (Partial)
|
||||||
|
scr = make_subcontracting_receipt(sco.name)
|
||||||
|
scr.items[0].qty -= 5
|
||||||
|
scr.save()
|
||||||
|
scr.submit()
|
||||||
|
|
||||||
|
# Get RM from Supplier
|
||||||
|
ste = get_materials_from_supplier(sco.name, [d.name for d in sco.supplied_items])
|
||||||
|
ste.save()
|
||||||
|
ste.submit()
|
||||||
|
|
||||||
|
sco.load_from_db()
|
||||||
|
|
||||||
|
self.assertEqual(sco.status, "Closed")
|
||||||
|
self.assertEqual(sco.supplied_items[0].returned_qty, 5)
|
||||||
|
|
||||||
|
|
||||||
def create_subcontracting_order(**args):
|
def create_subcontracting_order(**args):
|
||||||
args = frappe._dict(args)
|
args = frappe._dict(args)
|
||||||
@ -510,7 +539,7 @@ def create_subcontracting_order(**args):
|
|||||||
for item in sco.items:
|
for item in sco.items:
|
||||||
item.include_exploded_items = args.get("include_exploded_items", 1)
|
item.include_exploded_items = args.get("include_exploded_items", 1)
|
||||||
|
|
||||||
if args.get("warehouse"):
|
if args.warehouse:
|
||||||
for item in sco.items:
|
for item in sco.items:
|
||||||
item.warehouse = args.warehouse
|
item.warehouse = args.warehouse
|
||||||
else:
|
else:
|
||||||
|
@ -5,6 +5,8 @@ import frappe
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import cint, flt, getdate, nowdate
|
from frappe.utils import cint, flt, getdate, nowdate
|
||||||
|
|
||||||
|
import erpnext
|
||||||
|
from erpnext.accounts.utils import get_account_currency
|
||||||
from erpnext.controllers.subcontracting_controller import SubcontractingController
|
from erpnext.controllers.subcontracting_controller import SubcontractingController
|
||||||
|
|
||||||
|
|
||||||
@ -225,6 +227,137 @@ class SubcontractingReceipt(SubcontractingController):
|
|||||||
if status:
|
if status:
|
||||||
frappe.db.set_value("Subcontracting Receipt", self.name, "status", status, update_modified)
|
frappe.db.set_value("Subcontracting Receipt", self.name, "status", status, update_modified)
|
||||||
|
|
||||||
|
def get_gl_entries(self, warehouse_account=None):
|
||||||
|
from erpnext.accounts.general_ledger import process_gl_map
|
||||||
|
|
||||||
|
gl_entries = []
|
||||||
|
self.make_item_gl_entries(gl_entries, warehouse_account)
|
||||||
|
|
||||||
|
return process_gl_map(gl_entries)
|
||||||
|
|
||||||
|
def make_item_gl_entries(self, gl_entries, warehouse_account=None):
|
||||||
|
if erpnext.is_perpetual_inventory_enabled(self.company):
|
||||||
|
stock_rbnb = self.get_company_default("stock_received_but_not_billed")
|
||||||
|
expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
|
||||||
|
|
||||||
|
warehouse_with_no_account = []
|
||||||
|
|
||||||
|
for item in self.items:
|
||||||
|
if flt(item.rate) and flt(item.qty):
|
||||||
|
if warehouse_account.get(item.warehouse):
|
||||||
|
stock_value_diff = frappe.db.get_value(
|
||||||
|
"Stock Ledger Entry",
|
||||||
|
{
|
||||||
|
"voucher_type": "Subcontracting Receipt",
|
||||||
|
"voucher_no": self.name,
|
||||||
|
"voucher_detail_no": item.name,
|
||||||
|
"warehouse": item.warehouse,
|
||||||
|
"is_cancelled": 0,
|
||||||
|
},
|
||||||
|
"stock_value_difference",
|
||||||
|
)
|
||||||
|
|
||||||
|
warehouse_account_name = warehouse_account[item.warehouse]["account"]
|
||||||
|
warehouse_account_currency = warehouse_account[item.warehouse]["account_currency"]
|
||||||
|
supplier_warehouse_account = warehouse_account.get(self.supplier_warehouse, {}).get("account")
|
||||||
|
supplier_warehouse_account_currency = warehouse_account.get(self.supplier_warehouse, {}).get(
|
||||||
|
"account_currency"
|
||||||
|
)
|
||||||
|
remarks = self.get("remarks") or _("Accounting Entry for Stock")
|
||||||
|
|
||||||
|
# FG Warehouse Account (Debit)
|
||||||
|
self.add_gl_entry(
|
||||||
|
gl_entries=gl_entries,
|
||||||
|
account=warehouse_account_name,
|
||||||
|
cost_center=item.cost_center,
|
||||||
|
debit=stock_value_diff,
|
||||||
|
credit=0.0,
|
||||||
|
remarks=remarks,
|
||||||
|
against_account=stock_rbnb,
|
||||||
|
account_currency=warehouse_account_currency,
|
||||||
|
item=item,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Supplier Warehouse Account (Credit)
|
||||||
|
if flt(item.rm_supp_cost) and warehouse_account.get(self.supplier_warehouse):
|
||||||
|
self.add_gl_entry(
|
||||||
|
gl_entries=gl_entries,
|
||||||
|
account=supplier_warehouse_account,
|
||||||
|
cost_center=item.cost_center,
|
||||||
|
debit=0.0,
|
||||||
|
credit=flt(item.rm_supp_cost),
|
||||||
|
remarks=remarks,
|
||||||
|
against_account=warehouse_account_name,
|
||||||
|
account_currency=supplier_warehouse_account_currency,
|
||||||
|
item=item,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Expense Account (Credit)
|
||||||
|
if flt(item.service_cost_per_qty):
|
||||||
|
self.add_gl_entry(
|
||||||
|
gl_entries=gl_entries,
|
||||||
|
account=item.expense_account,
|
||||||
|
cost_center=item.cost_center,
|
||||||
|
debit=0.0,
|
||||||
|
credit=flt(item.service_cost_per_qty) * flt(item.qty),
|
||||||
|
remarks=remarks,
|
||||||
|
against_account=warehouse_account_name,
|
||||||
|
account_currency=get_account_currency(item.expense_account),
|
||||||
|
item=item,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Loss Account (Credit)
|
||||||
|
divisional_loss = flt(item.amount - stock_value_diff, item.precision("amount"))
|
||||||
|
|
||||||
|
if divisional_loss:
|
||||||
|
if self.is_return:
|
||||||
|
loss_account = expenses_included_in_valuation
|
||||||
|
else:
|
||||||
|
loss_account = item.expense_account
|
||||||
|
|
||||||
|
self.add_gl_entry(
|
||||||
|
gl_entries=gl_entries,
|
||||||
|
account=loss_account,
|
||||||
|
cost_center=item.cost_center,
|
||||||
|
debit=divisional_loss,
|
||||||
|
credit=0.0,
|
||||||
|
remarks=remarks,
|
||||||
|
against_account=warehouse_account_name,
|
||||||
|
account_currency=get_account_currency(loss_account),
|
||||||
|
project=item.project,
|
||||||
|
item=item,
|
||||||
|
)
|
||||||
|
elif (
|
||||||
|
item.warehouse not in warehouse_with_no_account
|
||||||
|
or item.rejected_warehouse not in warehouse_with_no_account
|
||||||
|
):
|
||||||
|
warehouse_with_no_account.append(item.warehouse)
|
||||||
|
|
||||||
|
# Additional Costs Expense Accounts (Credit)
|
||||||
|
for row in self.additional_costs:
|
||||||
|
credit_amount = (
|
||||||
|
flt(row.base_amount)
|
||||||
|
if (row.base_amount or row.account_currency != self.company_currency)
|
||||||
|
else flt(row.amount)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.add_gl_entry(
|
||||||
|
gl_entries=gl_entries,
|
||||||
|
account=row.expense_account,
|
||||||
|
cost_center=self.cost_center or self.get_company_default("cost_center"),
|
||||||
|
debit=0.0,
|
||||||
|
credit=credit_amount,
|
||||||
|
remarks=remarks,
|
||||||
|
against_account=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
if warehouse_with_no_account:
|
||||||
|
frappe.msgprint(
|
||||||
|
_("No accounting entries for the following warehouses")
|
||||||
|
+ ": \n"
|
||||||
|
+ "\n".join(warehouse_with_no_account)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def make_subcontract_return(source_name, target_doc=None):
|
def make_subcontract_return(source_name, target_doc=None):
|
||||||
|
@ -6,8 +6,10 @@ import copy
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.tests.utils import FrappeTestCase
|
from frappe.tests.utils import FrappeTestCase
|
||||||
from frappe.utils import flt
|
from frappe.utils import cint, flt
|
||||||
|
|
||||||
|
import erpnext
|
||||||
|
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
||||||
from erpnext.controllers.sales_and_purchase_return import make_return_doc
|
from erpnext.controllers.sales_and_purchase_return import make_return_doc
|
||||||
from erpnext.controllers.tests.test_subcontracting_controller import (
|
from erpnext.controllers.tests.test_subcontracting_controller import (
|
||||||
get_rm_items,
|
get_rm_items,
|
||||||
@ -22,6 +24,7 @@ from erpnext.controllers.tests.test_subcontracting_controller import (
|
|||||||
set_backflush_based_on,
|
set_backflush_based_on,
|
||||||
)
|
)
|
||||||
from erpnext.stock.doctype.item.test_item import make_item
|
from erpnext.stock.doctype.item.test_item import make_item
|
||||||
|
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import get_gl_entries
|
||||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
||||||
from erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order import (
|
from erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order import (
|
||||||
make_subcontracting_receipt,
|
make_subcontracting_receipt,
|
||||||
@ -366,6 +369,103 @@ class TestSubcontractingReceipt(FrappeTestCase):
|
|||||||
args = frappe._dict(scr_name=scr1.name, qty=-15)
|
args = frappe._dict(scr_name=scr1.name, qty=-15)
|
||||||
self.assertRaises(OverAllowanceError, make_return_subcontracting_receipt, **args)
|
self.assertRaises(OverAllowanceError, make_return_subcontracting_receipt, **args)
|
||||||
|
|
||||||
|
def test_subcontracting_receipt_no_gl_entry(self):
|
||||||
|
sco = get_subcontracting_order()
|
||||||
|
rm_items = get_rm_items(sco.supplied_items)
|
||||||
|
itemwise_details = make_stock_in_entry(rm_items=rm_items)
|
||||||
|
make_stock_transfer_entry(
|
||||||
|
sco_no=sco.name,
|
||||||
|
rm_items=rm_items,
|
||||||
|
itemwise_details=copy.deepcopy(itemwise_details),
|
||||||
|
)
|
||||||
|
|
||||||
|
scr = make_subcontracting_receipt(sco.name)
|
||||||
|
scr.append(
|
||||||
|
"additional_costs",
|
||||||
|
{
|
||||||
|
"expense_account": "Expenses Included In Valuation - _TC",
|
||||||
|
"description": "Test Additional Costs",
|
||||||
|
"amount": 100,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
scr.save()
|
||||||
|
scr.submit()
|
||||||
|
|
||||||
|
stock_value_difference = frappe.db.get_value(
|
||||||
|
"Stock Ledger Entry",
|
||||||
|
{
|
||||||
|
"voucher_type": "Subcontracting Receipt",
|
||||||
|
"voucher_no": scr.name,
|
||||||
|
"item_code": "Subcontracted Item SA7",
|
||||||
|
"warehouse": "_Test Warehouse - _TC",
|
||||||
|
},
|
||||||
|
"stock_value_difference",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Service Cost(100 * 10) + Raw Materials Cost(50 * 10) + Additional Costs(100) = 1600
|
||||||
|
self.assertEqual(stock_value_difference, 1600)
|
||||||
|
self.assertFalse(get_gl_entries("Subcontracting Receipt", scr.name))
|
||||||
|
|
||||||
|
def test_subcontracting_receipt_gl_entry(self):
|
||||||
|
sco = get_subcontracting_order(
|
||||||
|
company="_Test Company with perpetual inventory",
|
||||||
|
warehouse="Stores - TCP1",
|
||||||
|
supplier_warehouse="Work In Progress - TCP1",
|
||||||
|
)
|
||||||
|
rm_items = get_rm_items(sco.supplied_items)
|
||||||
|
itemwise_details = make_stock_in_entry(rm_items=rm_items)
|
||||||
|
make_stock_transfer_entry(
|
||||||
|
sco_no=sco.name,
|
||||||
|
rm_items=rm_items,
|
||||||
|
itemwise_details=copy.deepcopy(itemwise_details),
|
||||||
|
)
|
||||||
|
|
||||||
|
scr = make_subcontracting_receipt(sco.name)
|
||||||
|
additional_costs_expense_account = "Expenses Included In Valuation - TCP1"
|
||||||
|
scr.append(
|
||||||
|
"additional_costs",
|
||||||
|
{
|
||||||
|
"expense_account": additional_costs_expense_account,
|
||||||
|
"description": "Test Additional Costs",
|
||||||
|
"amount": 100,
|
||||||
|
"base_amount": 100,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
scr.save()
|
||||||
|
scr.submit()
|
||||||
|
|
||||||
|
self.assertEqual(cint(erpnext.is_perpetual_inventory_enabled(scr.company)), 1)
|
||||||
|
|
||||||
|
gl_entries = get_gl_entries("Subcontracting Receipt", scr.name)
|
||||||
|
|
||||||
|
self.assertTrue(gl_entries)
|
||||||
|
|
||||||
|
fg_warehouse_ac = get_inventory_account(scr.company, scr.items[0].warehouse)
|
||||||
|
supplier_warehouse_ac = get_inventory_account(scr.company, scr.supplier_warehouse)
|
||||||
|
expense_account = scr.items[0].expense_account
|
||||||
|
|
||||||
|
if fg_warehouse_ac == supplier_warehouse_ac:
|
||||||
|
expected_values = {
|
||||||
|
fg_warehouse_ac: [2100.0, 1000.0], # FG Amount (D), RM Cost (C)
|
||||||
|
expense_account: [0.0, 1000.0], # Service Cost (C)
|
||||||
|
additional_costs_expense_account: [0.0, 100.0], # Additional Cost (C)
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
expected_values = {
|
||||||
|
fg_warehouse_ac: [2100.0, 0.0], # FG Amount (D)
|
||||||
|
supplier_warehouse_ac: [0.0, 1000.0], # RM Cost (C)
|
||||||
|
expense_account: [0.0, 1000.0], # Service Cost (C)
|
||||||
|
additional_costs_expense_account: [0.0, 100.0], # Additional Cost (C)
|
||||||
|
}
|
||||||
|
|
||||||
|
for gle in gl_entries:
|
||||||
|
self.assertEqual(expected_values[gle.account][0], gle.debit)
|
||||||
|
self.assertEqual(expected_values[gle.account][1], gle.credit)
|
||||||
|
|
||||||
|
scr.reload()
|
||||||
|
scr.cancel()
|
||||||
|
self.assertTrue(get_gl_entries("Subcontracting Receipt", scr.name))
|
||||||
|
|
||||||
|
|
||||||
def make_return_subcontracting_receipt(**args):
|
def make_return_subcontracting_receipt(**args):
|
||||||
args = frappe._dict(args)
|
args = frappe._dict(args)
|
||||||
|
Loading…
Reference in New Issue
Block a user