fix: Add validations and other fixes

This commit is contained in:
Deepesh Garg
2020-12-26 19:11:04 +05:30
parent a9f4508cd1
commit afef92a88b
12 changed files with 115 additions and 29 deletions

View File

@@ -761,6 +761,7 @@
"read_only": 1 "read_only": 1
}, },
{ {
"depends_on": "eval:parent.is_internal_supplier && parent.update_stock",
"fieldname": "from_warehouse", "fieldname": "from_warehouse",
"fieldtype": "Link", "fieldtype": "Link",
"ignore_user_permissions": 1, "ignore_user_permissions": 1,
@@ -794,7 +795,7 @@
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2020-12-25 23:43:57.272553", "modified": "2020-12-26 17:20:36.415791",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Purchase Invoice Item", "name": "Purchase Invoice Item",

View File

@@ -22,6 +22,7 @@ from erpnext.regional.india.utils import get_ewb_data
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice
from erpnext.stock.utils import get_incoming_rate
class TestSalesInvoice(unittest.TestCase): class TestSalesInvoice(unittest.TestCase):
def make(self): def make(self):
@@ -1801,6 +1802,24 @@ class TestSalesInvoice(unittest.TestCase):
si.items[0].target_warehouse = 'Work In Progress - TCP1' si.items[0].target_warehouse = 'Work In Progress - TCP1'
add_taxes(si) add_taxes(si)
si.save() si.save()
rate = 0.0
for d in si.get('items'):
rate = get_incoming_rate({
"item_code": d.item_code,
"warehouse": d.warehouse,
"posting_date": si.posting_date,
"posting_time": si.posting_time,
"qty": -1 * flt(d.get('stock_qty')),
"serial_no": d.serial_no,
"company": si.company,
"voucher_type": 'Sales Invoice',
"voucher_no": si.name,
"allow_zero_valuation": d.get("allow_zero_valuation")
}, raise_error_if_no_rate=False)
rate = flt(rate, 2)
si.submit() si.submit()
target_doc = make_inter_company_transaction("Sales Invoice", si.name) target_doc = make_inter_company_transaction("Sales Invoice", si.name)
@@ -1810,18 +1829,23 @@ class TestSalesInvoice(unittest.TestCase):
target_doc.save() target_doc.save()
target_doc.submit() target_doc.submit()
tax_amount = flt(rate * (12/100), 2)
si_gl_entries = [ si_gl_entries = [
["_Test Account Excise Duty - TCP1", 0.0, 12.0, nowdate()], ["_Test Account Excise Duty - TCP1", 0.0, tax_amount, nowdate()],
["Unrealized Profit - TCP1", 12.0, 0.0, nowdate()] ["Unrealized Profit - TCP1", tax_amount, 0.0, nowdate()]
] ]
check_gl_entries(self, si.name, si_gl_entries, add_days(nowdate(), -1)) check_gl_entries(self, si.name, si_gl_entries, add_days(nowdate(), -1))
pi_gl_entries = [ pi_gl_entries = [
["_Test Account Excise Duty - TCP1", 12.0 , 0.0, nowdate()], ["_Test Account Excise Duty - TCP1", tax_amount , 0.0, nowdate()],
["Unrealized Profit - TCP1", 0.0, 12.0, nowdate()] ["Unrealized Profit - TCP1", 0.0, tax_amount, nowdate()]
] ]
# Sale and Purchase both should be at valuation rate
self.assertEqual(si.items[0].rate, rate)
self.assertEqual(target_doc.items[0].rate, rate)
check_gl_entries(self, target_doc.name, pi_gl_entries, add_days(nowdate(), -1)) check_gl_entries(self, target_doc.name, pi_gl_entries, add_days(nowdate(), -1))
def test_eway_bill_json(self): def test_eway_bill_json(self):

View File

@@ -565,6 +565,7 @@
"print_hide": 1 "print_hide": 1
}, },
{ {
"depends_on": "eval: parent.is_internal_customer && parent.update_stock",
"fieldname": "target_warehouse", "fieldname": "target_warehouse",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 1, "hidden": 1,
@@ -815,7 +816,7 @@
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2020-12-25 22:46:26.778091", "modified": "2020-12-26 17:25:04.090630",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Sales Invoice Item", "name": "Sales Invoice Item",

View File

@@ -963,9 +963,9 @@ class AccountsController(TransactionBase):
It will an internal transfer if its an internal customer and representation It will an internal transfer if its an internal customer and representation
company is same as billing company company is same as billing company
""" """
if self.doctype == 'Sales Invoice': if self.doctype in ('Sales Invoice', 'Delivery Note'):
internal_party_field = 'is_internal_customer' internal_party_field = 'is_internal_customer'
else: elif self.doctype in ('Purchase Invoice', 'Purchase Invoice Item'):
internal_party_field = 'is_internal_supplier' internal_party_field = 'is_internal_supplier'
if self.get(internal_party_field) and (self.represents_company == self.company): if self.get(internal_party_field) and (self.represents_company == self.company):

View File

@@ -235,7 +235,7 @@ class BuyingController(StockController):
"warehouse": d.from_warehouse, "warehouse": d.from_warehouse,
"posting_date": self.posting_date, "posting_date": self.posting_date,
"posting_time": self.posting_time, "posting_time": self.posting_time,
"qty": -1 * flt(d.stock_qty), "qty": -1 * flt(d.get('stock_qty')),
"serial_no": d.serial_no, "serial_no": d.serial_no,
"company": self.company, "company": self.company,
"voucher_type": self.doctype, "voucher_type": self.doctype,

View File

@@ -323,7 +323,7 @@ class SellingController(StockController):
"warehouse": d.warehouse, "warehouse": d.warehouse,
"posting_date": self.posting_date, "posting_date": self.posting_date,
"posting_time": self.posting_time, "posting_time": self.posting_time,
"qty": -1*flt(d.stock_qty), "qty": -1 * flt(d.get('stock_qty') or d.get('actual_qty')),
"serial_no": d.serial_no, "serial_no": d.serial_no,
"company": self.company, "company": self.company,
"voucher_type": self.doctype, "voucher_type": self.doctype,

View File

@@ -23,6 +23,7 @@ class StockController(AccountsController):
self.validate_inspection() self.validate_inspection()
self.validate_serialized_batch() self.validate_serialized_batch()
self.validate_customer_provided_item() self.validate_customer_provided_item()
self.validate_internal_transfer()
def make_gl_entries(self, gl_entries=None, from_repost=False): def make_gl_entries(self, gl_entries=None, from_repost=False):
if self.docstatus == 2: if self.docstatus == 2:
@@ -72,7 +73,13 @@ class StockController(AccountsController):
warehouse_with_no_account = [] warehouse_with_no_account = []
precision = frappe.get_precision("GL Entry", "debit_in_account_currency") precision = frappe.get_precision("GL Entry", "debit_in_account_currency")
for item_row in voucher_details: for item_row in voucher_details:
sle_list = sle_map.get((item_row.name, item_row.warehouse))
if self.doctype == 'Stock Entry':
warehouse_field = 's_warehouse'
else:
warehouse_field = 'warehouse'
sle_list = sle_map.get((item_row.name, item_row.get(warehouse_field)))
if sle_list: if sle_list:
for sle in sle_list: for sle in sle_list:
if warehouse_account.get(sle.warehouse): if warehouse_account.get(sle.warehouse):
@@ -391,6 +398,40 @@ class StockController(AccountsController):
if frappe.db.get_value('Item', d.item_code, 'is_customer_provided_item'): if frappe.db.get_value('Item', d.item_code, 'is_customer_provided_item'):
d.allow_zero_valuation_rate = 1 d.allow_zero_valuation_rate = 1
def validate_internal_transfer(self):
if self.doctype in ('Sales Invoice', 'Delivery Note', 'Purchase Invoice', 'Purchase Receipt') \
and self.is_internal_transfer():
self.validate_in_transit_warehouses()
self.validate_multi_currency()
self.validate_packed_items()
self.validate_inter_company_reference()
def validate_in_transit_warehouses(self):
if self.doctype in ('Sales Invoice', 'Delivery Note'):
for item in self.get('items'):
if not item.target_warehouse:
frappe.throw(_("Row {0}: Target Warehouse is mandatory for internal transfers"))
if self.doctype in ('Purchase Invoice', 'Purchase Receipt'):
for item in self.get('items'):
if not item.from_warehouse:
frappe.throw(_("Row {0}: From Warehouse is mandatory for internal transfers"))
def validate_multi_currency(self):
if self.currency != self.company_currency:
frappe.throw(_("Internal transfers can only be done in company's default currency"))
def validate_packed_items(self):
if self.doctype in ('Sales Invoice', 'Delivery Note Item') and self.get('packed_items'):
frappe.throw(_("Packed Items cannot be transferred internally"))
def validate_inter_company_reference(self):
if self.doctype in ('Purchase Invoice', 'Purchase Receipt'):
if not (self.get('inter_company_reference') or self.get('inter_company_invoice_reference')):
msg = _("Internal Sale or Delivery Reference needed for internal purchase")
msg += _("Please create purchase from the internal sale or delivery document itself")
frappe.throw(msg)
def repost_future_sle_and_gle(self): def repost_future_sle_and_gle(self):
args = frappe._dict({ args = frappe._dict({
"posting_date": self.posting_date, "posting_date": self.posting_date,

View File

@@ -117,6 +117,7 @@
"source", "source",
"column_break5", "column_break5",
"is_internal_customer", "is_internal_customer",
"represents_company",
"inter_company_reference", "inter_company_reference",
"per_billed", "per_billed",
"customer_group", "customer_group",
@@ -1261,13 +1262,22 @@
"oldfieldtype": "Link", "oldfieldtype": "Link",
"options": "Warehouse", "options": "Warehouse",
"print_hide": 1 "print_hide": 1
},
{
"description": "Company which internal customer represents.",
"fetch_from": "customer.represents_company",
"fieldname": "represents_company",
"fieldtype": "Link",
"label": "Represents Company",
"options": "Company",
"read_only": 1
} }
], ],
"icon": "fa fa-truck", "icon": "fa fa-truck",
"idx": 146, "idx": 146,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2020-12-25 23:11:46.584226", "modified": "2020-12-26 17:07:59.194403",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Delivery Note", "name": "Delivery Note",

View File

@@ -458,7 +458,7 @@
"fieldname": "warehouse", "fieldname": "warehouse",
"fieldtype": "Link", "fieldtype": "Link",
"in_list_view": 1, "in_list_view": 1,
"label": "From Warehouse", "label": "Warehouse",
"oldfieldname": "warehouse", "oldfieldname": "warehouse",
"oldfieldtype": "Link", "oldfieldtype": "Link",
"options": "Warehouse", "options": "Warehouse",
@@ -467,11 +467,12 @@
"width": "100px" "width": "100px"
}, },
{ {
"depends_on": "eval:parent.is_internal_customer",
"fieldname": "target_warehouse", "fieldname": "target_warehouse",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 1, "hidden": 1,
"ignore_user_permissions": 1, "ignore_user_permissions": 1,
"label": "Customer Warehouse (Optional)", "label": "Target Warehouse",
"no_copy": 1, "no_copy": 1,
"options": "Warehouse", "options": "Warehouse",
"print_hide": 1 "print_hide": 1
@@ -748,7 +749,7 @@
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2020-12-07 19:59:27.119856", "modified": "2020-12-26 17:31:27.029803",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Delivery Note Item", "name": "Delivery Note Item",

View File

@@ -115,6 +115,7 @@
"per_returned", "per_returned",
"is_internal_supplier", "is_internal_supplier",
"inter_company_reference", "inter_company_reference",
"represents_company",
"subscription_detail", "subscription_detail",
"auto_repeat", "auto_repeat",
"printing_settings", "printing_settings",
@@ -1123,13 +1124,21 @@
"fieldtype": "Link", "fieldtype": "Link",
"label": "Set From Warehouse", "label": "Set From Warehouse",
"options": "Warehouse" "options": "Warehouse"
},
{
"fetch_from": "supplier.represents_company",
"fieldname": "represents_company",
"fieldtype": "Link",
"label": "Represents Company",
"options": "Company",
"read_only": 1
} }
], ],
"icon": "fa fa-truck", "icon": "fa fa-truck",
"idx": 261, "idx": 261,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2020-12-25 23:15:01.451518", "modified": "2020-12-26 17:10:00.798835",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Purchase Receipt", "name": "Purchase Receipt",

View File

@@ -819,11 +819,12 @@
"read_only": 1 "read_only": 1
}, },
{ {
"depends_on": "eval:parent.is_internal_supplier",
"fieldname": "from_warehouse", "fieldname": "from_warehouse",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 1, "hidden": 1,
"ignore_user_permissions": 1, "ignore_user_permissions": 1,
"label": "Supplier Warehouse", "label": "From Warehouse",
"options": "Warehouse" "options": "Warehouse"
}, },
{ {
@@ -875,7 +876,7 @@
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2020-12-25 22:33:12.057271", "modified": "2020-12-26 16:50:56.479347",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Purchase Receipt Item", "name": "Purchase Receipt Item",

View File

@@ -377,14 +377,14 @@ class update_entries_after(object):
def update_rate_on_delivery_and_sales_return(self, sle, outgoing_rate): def update_rate_on_delivery_and_sales_return(self, sle, outgoing_rate):
if frappe.db.get_value(sle.voucher_type, sle.voucher_no, 'is_internal_customer'): if frappe.db.get_value(sle.voucher_type, sle.voucher_no, 'is_internal_customer'):
frappe.db.set_value(doctype + " Item", voucher_detail_no, "rate", rate) frappe.db.set_value(sle.voucher_type + " Item", sle.voucher_detail_no, "rate", outgoing_rate)
update_taxes_and_totals(sle.voucher_type, sle.voucher_no, outgoing_rate) update_taxes_and_totals(sle.voucher_type, sle.voucher_no, outgoing_rate)
purchase_doctype = 'Purchase Invoice' if sle.voucher_type == 'Sales Invoice' else 'Purchase Receipt' purchase_doctype = 'Purchase Invoice' if sle.voucher_type == 'Sales Invoice' else 'Purchase Receipt'
ref_field = frappe.scrub(sle.voucher_type + ' Item') ref_field = frappe.scrub(sle.voucher_type + ' Item')
purchase_document_list = frappe.db.get_all(purchase_doctype, {'inter_company_invoice_reference': purchase_document_list = frappe.db.get_all(purchase_doctype, {'inter_company_invoice_reference':
sle.voucher_no}, ['name'], as_dict=1) sle.voucher_no}, ['name'])
for d in purchase_document_list: for d in purchase_document_list:
frappe.db.set_value(purchase_doctype + ' Item', {ref_field: sle.voucher_detail_no}, 'rate', outgoing_rate) frappe.db.set_value(purchase_doctype + ' Item', {ref_field: sle.voucher_detail_no}, 'rate', outgoing_rate)
@@ -400,13 +400,6 @@ class update_entries_after(object):
{"parent_detail_docname": sle.voucher_detail_no, "item_code": sle.item_code}, {"parent_detail_docname": sle.voucher_detail_no, "item_code": sle.item_code},
"incoming_rate", outgoing_rate) "incoming_rate", outgoing_rate)
def update_taxes_and_totals(doctype, docname, rate):
ref_doc = frappe.get_doc(doctype, docname)
ref_doc.calculate_taxes_and_totals()
ref_doc.db_update()
for d in ref_doc.items:
d.db_update()
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(sle.voucher_type + " Item", sle.voucher_detail_no, "base_net_rate", outgoing_rate) frappe.db.set_value(sle.voucher_type + " Item", sle.voucher_detail_no, "base_net_rate", outgoing_rate)
@@ -508,8 +501,6 @@ class update_entries_after(object):
self.wh_data.valuation_rate = new_stock_value / new_stock_qty self.wh_data.valuation_rate = new_stock_value / new_stock_qty
else: else:
self.wh_data.valuation_rate = sle.outgoing_rate self.wh_data.valuation_rate = sle.outgoing_rate
print(self.wh_data.valuation_rate, "$#$#$#$#")
else: else:
if flt(self.wh_data.qty_after_transaction) >= 0 and sle.outgoing_rate: if flt(self.wh_data.qty_after_transaction) >= 0 and sle.outgoing_rate:
self.wh_data.valuation_rate = sle.outgoing_rate self.wh_data.valuation_rate = sle.outgoing_rate
@@ -667,6 +658,13 @@ class update_entries_after(object):
bin_doc.flags.via_stock_ledger_entry = True bin_doc.flags.via_stock_ledger_entry = True
bin_doc.save(ignore_permissions=True) bin_doc.save(ignore_permissions=True)
def update_taxes_and_totals(doctype, docname, rate):
ref_doc = frappe.get_doc(doctype, docname)
ref_doc.calculate_taxes_and_totals()
ref_doc.db_update()
for d in ref_doc.items:
d.db_update()
def get_previous_sle(args, for_update=False): def get_previous_sle(args, for_update=False):
""" """
get the last sle on or before the current time-bucket, get the last sle on or before the current time-bucket,