mirror of
https://github.com/frappe/erpnext.git
synced 2026-04-17 05:45:11 +00:00
Merge branch 'version-12-hotfix' of https://github.com/frappe/erpnext into gstr3b_cess_v12_hotfix
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
{
|
||||
"doctype": "Item Tax Template",
|
||||
"title": "_Test Account Excise Duty @ 10",
|
||||
"company": "_Test Company",
|
||||
"taxes": [
|
||||
{
|
||||
"doctype": "Item Tax Template Detail",
|
||||
@@ -14,6 +15,7 @@
|
||||
{
|
||||
"doctype": "Item Tax Template",
|
||||
"title": "_Test Account Excise Duty @ 12",
|
||||
"company": "_Test Company",
|
||||
"taxes": [
|
||||
{
|
||||
"doctype": "Item Tax Template Detail",
|
||||
@@ -26,6 +28,7 @@
|
||||
{
|
||||
"doctype": "Item Tax Template",
|
||||
"title": "_Test Account Excise Duty @ 15",
|
||||
"company": "_Test Company",
|
||||
"taxes": [
|
||||
{
|
||||
"doctype": "Item Tax Template Detail",
|
||||
@@ -38,6 +41,7 @@
|
||||
{
|
||||
"doctype": "Item Tax Template",
|
||||
"title": "_Test Account Excise Duty @ 20",
|
||||
"company": "_Test Company",
|
||||
"taxes": [
|
||||
{
|
||||
"doctype": "Item Tax Template Detail",
|
||||
@@ -50,6 +54,7 @@
|
||||
{
|
||||
"doctype": "Item Tax Template",
|
||||
"title": "_Test Item Tax Template 1",
|
||||
"company": "_Test Company",
|
||||
"taxes": [
|
||||
{
|
||||
"doctype": "Item Tax Template Detail",
|
||||
|
||||
@@ -11,6 +11,7 @@ import json
|
||||
from six import string_types
|
||||
|
||||
import frappe
|
||||
from erpnext.accounts.doctype.pricing_rule.pricing_rule import set_transaction_type
|
||||
from erpnext.setup.doctype.item_group.item_group import get_child_item_groups
|
||||
from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses
|
||||
from erpnext.stock.get_item_details import get_conversion_factor, get_default_income_account
|
||||
@@ -418,9 +419,28 @@ def apply_pricing_rule_on_transaction(doc):
|
||||
values = {}
|
||||
conditions = get_other_conditions(conditions, values, doc)
|
||||
|
||||
pricing_rules = frappe.db.sql(""" Select `tabPricing Rule`.* from `tabPricing Rule`
|
||||
where {conditions} and `tabPricing Rule`.disable = 0
|
||||
""".format(conditions = conditions), values, as_dict=1)
|
||||
args = frappe._dict({
|
||||
'doctype': doc.doctype,
|
||||
'transaction_type': None,
|
||||
})
|
||||
set_transaction_type(args)
|
||||
tran_type_condition = '{} = 1'.format(args.transaction_type)
|
||||
|
||||
sql = """
|
||||
SELECT
|
||||
`tabPricing Rule`.*
|
||||
FROM
|
||||
`tabPricing Rule`
|
||||
WHERE
|
||||
{conditions} and
|
||||
{tran_type_condition} and
|
||||
`tabPricing Rule`.disable = 0
|
||||
""".format(
|
||||
conditions=conditions,
|
||||
tran_type_condition=tran_type_condition,
|
||||
)
|
||||
|
||||
pricing_rules = frappe.db.sql(sql, values, as_dict=1)
|
||||
|
||||
if pricing_rules:
|
||||
pricing_rules = filter_pricing_rules_for_qty_amount(doc.total_qty,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "hash",
|
||||
"creation": "2013-05-22 12:43:10",
|
||||
"doctype": "DocType",
|
||||
@@ -86,6 +85,7 @@
|
||||
"item_tax_rate",
|
||||
"bom",
|
||||
"include_exploded_items",
|
||||
"purchase_invoice_item",
|
||||
"col_break6",
|
||||
"purchase_order",
|
||||
"po_detail",
|
||||
@@ -764,12 +764,21 @@
|
||||
"label": "Asset Category",
|
||||
"options": "Asset Category",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:parent.update_stock == 1",
|
||||
"fieldname": "purchase_invoice_item",
|
||||
"fieldtype": "Data",
|
||||
"ignore_user_permissions": 1,
|
||||
"label": "Purchase Invoice Item",
|
||||
"no_copy": 1,
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-04-07 18:34:35.104178",
|
||||
"modified": "2020-06-30 16:48:01.398356",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Invoice Item",
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "hash",
|
||||
"creation": "2013-06-04 11:02:19",
|
||||
"doctype": "DocType",
|
||||
@@ -87,6 +86,7 @@
|
||||
"edit_references",
|
||||
"sales_order",
|
||||
"so_detail",
|
||||
"sales_invoice_item",
|
||||
"column_break_74",
|
||||
"delivery_note",
|
||||
"dn_detail",
|
||||
@@ -783,12 +783,21 @@
|
||||
"fieldtype": "Link",
|
||||
"label": "Finance Book",
|
||||
"options": "Finance Book"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:parent.update_stock == 1",
|
||||
"fieldname": "sales_invoice_item",
|
||||
"fieldtype": "Data",
|
||||
"ignore_user_permissions": 1,
|
||||
"label": "Sales Invoice Item",
|
||||
"no_copy": 1,
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2019-12-04 12:22:38.517710",
|
||||
"modified": "2020-06-30 16:47:37.650996",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice Item",
|
||||
|
||||
@@ -182,7 +182,7 @@ class BuyingController(StockController):
|
||||
if item.item_code and item.qty and item.item_code in stock_and_asset_items:
|
||||
item_proportion = flt(item.base_net_amount) / stock_and_asset_items_amount if stock_and_asset_items_amount \
|
||||
else flt(item.qty) / stock_and_asset_items_qty
|
||||
|
||||
|
||||
if i == (last_item_idx - 1):
|
||||
item.item_tax_amount = flt(valuation_amount_adjustment,
|
||||
self.precision("item_tax_amount", item))
|
||||
@@ -540,9 +540,19 @@ class BuyingController(StockController):
|
||||
"serial_no": cstr(d.serial_no).strip()
|
||||
})
|
||||
if self.is_return:
|
||||
original_incoming_rate = frappe.db.get_value("Stock Ledger Entry",
|
||||
{"voucher_type": "Purchase Receipt", "voucher_no": self.return_against,
|
||||
"item_code": d.item_code}, "incoming_rate")
|
||||
filters = {
|
||||
"voucher_type": self.doctype,
|
||||
"voucher_no": self.return_against,
|
||||
"item_code": d.item_code
|
||||
}
|
||||
|
||||
if (self.doctype == "Purchase Invoice" and self.update_stock
|
||||
and d.get("purchase_invoice_item")):
|
||||
filters["voucher_detail_no"] = d.purchase_invoice_item
|
||||
elif self.doctype == "Purchase Receipt" and d.get("purchase_receipt_item"):
|
||||
filters["voucher_detail_no"] = d.purchase_receipt_item
|
||||
|
||||
original_incoming_rate = frappe.db.get_value("Stock Ledger Entry", filters, "incoming_rate")
|
||||
|
||||
sle.update({
|
||||
"outgoing_rate": original_incoming_rate
|
||||
@@ -728,7 +738,7 @@ class BuyingController(StockController):
|
||||
if delete_asset and is_auto_create_enabled:
|
||||
# need to delete movements to delete assets otherwise throws link exists error
|
||||
movements = frappe.db.sql(
|
||||
"""SELECT asm.name
|
||||
"""SELECT asm.name
|
||||
FROM `tabAsset Movement` asm, `tabAsset Movement Item` asm_item
|
||||
WHERE asm_item.parent=asm.name and asm_item.asset=%s""", asset.name, as_dict=1)
|
||||
for movement in movements:
|
||||
|
||||
@@ -278,6 +278,8 @@ def make_return_doc(doctype, source_name, target_doc=None):
|
||||
target_doc.rejected_warehouse = source_doc.rejected_warehouse
|
||||
target_doc.po_detail = source_doc.po_detail
|
||||
target_doc.pr_detail = source_doc.pr_detail
|
||||
target_doc.purchase_invoice_item = source_doc.name
|
||||
|
||||
elif doctype == "Delivery Note":
|
||||
target_doc.against_sales_order = source_doc.against_sales_order
|
||||
target_doc.against_sales_invoice = source_doc.against_sales_invoice
|
||||
@@ -287,12 +289,14 @@ def make_return_doc(doctype, source_name, target_doc=None):
|
||||
target_doc.dn_detail = source_doc.name
|
||||
if default_warehouse_for_sales_return:
|
||||
target_doc.warehouse = default_warehouse_for_sales_return
|
||||
|
||||
elif doctype == "Sales Invoice":
|
||||
target_doc.sales_order = source_doc.sales_order
|
||||
target_doc.delivery_note = source_doc.delivery_note
|
||||
target_doc.so_detail = source_doc.so_detail
|
||||
target_doc.dn_detail = source_doc.dn_detail
|
||||
target_doc.expense_account = source_doc.expense_account
|
||||
target_doc.sales_invoice_item = source_doc.name
|
||||
if default_warehouse_for_sales_return:
|
||||
target_doc.warehouse = default_warehouse_for_sales_return
|
||||
|
||||
|
||||
@@ -216,7 +216,9 @@ class SellingController(StockController):
|
||||
'target_warehouse': p.target_warehouse,
|
||||
'company': self.company,
|
||||
'voucher_type': self.doctype,
|
||||
'allow_zero_valuation': d.allow_zero_valuation_rate
|
||||
'allow_zero_valuation': d.allow_zero_valuation_rate,
|
||||
'sales_invoice_item': d.get("sales_invoice_item"),
|
||||
'delivery_note_item': d.get("dn_detail")
|
||||
}))
|
||||
else:
|
||||
il.append(frappe._dict({
|
||||
@@ -232,7 +234,9 @@ class SellingController(StockController):
|
||||
'target_warehouse': d.target_warehouse,
|
||||
'company': self.company,
|
||||
'voucher_type': self.doctype,
|
||||
'allow_zero_valuation': d.allow_zero_valuation_rate
|
||||
'allow_zero_valuation': d.allow_zero_valuation_rate,
|
||||
'sales_invoice_item': d.get("sales_invoice_item"),
|
||||
'delivery_note_item': d.get("dn_detail")
|
||||
}))
|
||||
return il
|
||||
|
||||
@@ -301,7 +305,11 @@ class SellingController(StockController):
|
||||
d.conversion_factor = get_conversion_factor(d.item_code, d.uom).get("conversion_factor") or 1.0
|
||||
return_rate = 0
|
||||
if cint(self.is_return) and self.return_against and self.docstatus==1:
|
||||
return_rate = self.get_incoming_rate_for_sales_return(d.item_code, self.return_against)
|
||||
against_document_no = (d.get("sales_invoice_item")
|
||||
if self.doctype == "Sales Invoice" else d.get("delivery_note_item"))
|
||||
|
||||
return_rate = self.get_incoming_rate_for_sales_return(d.item_code,
|
||||
self.return_against, against_document_no)
|
||||
|
||||
# On cancellation or if return entry submission, make stock ledger entry for
|
||||
# target warehouse first, to update serial no values properly
|
||||
|
||||
@@ -297,14 +297,19 @@ class StockController(AccountsController):
|
||||
|
||||
return serialized_items
|
||||
|
||||
def get_incoming_rate_for_sales_return(self, item_code, against_document):
|
||||
def get_incoming_rate_for_sales_return(self, item_code, against_document, against_document_no=None):
|
||||
incoming_rate = 0.0
|
||||
cond = ''
|
||||
if against_document and item_code:
|
||||
if against_document_no:
|
||||
cond = " and voucher_detail_no = %s" %(frappe.db.escape(against_document_no))
|
||||
|
||||
incoming_rate = frappe.db.sql("""select abs(stock_value_difference / actual_qty)
|
||||
from `tabStock Ledger Entry`
|
||||
where voucher_type = %s and voucher_no = %s
|
||||
and item_code = %s limit 1""",
|
||||
and item_code = %s {0} limit 1""".format(cond),
|
||||
(self.doctype, against_document, item_code))
|
||||
|
||||
incoming_rate = incoming_rate[0][0] if incoming_rate else 0.0
|
||||
|
||||
return incoming_rate
|
||||
|
||||
@@ -13,14 +13,12 @@ class TestMapper(unittest.TestCase):
|
||||
'''Test mapping of multiple source docs on a single target doc'''
|
||||
|
||||
make_test_records("Item")
|
||||
items = frappe.get_all("Item", fields = ["name", "item_code"], filters = {'is_sales_item': 1, 'has_variants': 0})
|
||||
customers = frappe.get_all("Customer")
|
||||
if items and customers:
|
||||
# Make source docs (quotations) and a target doc (sales order)
|
||||
customer = random.choice(customers).name
|
||||
qtn1, item_list_1 = self.make_quotation(items, customer)
|
||||
qtn2, item_list_2 = self.make_quotation(items, customer)
|
||||
so, item_list_3 = self.make_sales_order()
|
||||
items = ['_Test Item', '_Test Item 2', '_Test FG Item']
|
||||
|
||||
# Make source docs (quotations) and a target doc (sales order)
|
||||
qtn1, item_list_1 = self.make_quotation(items, '_Test Customer')
|
||||
qtn2, item_list_2 = self.make_quotation(items, '_Test Customer')
|
||||
so, item_list_3 = self.make_sales_order()
|
||||
|
||||
# Map source docs to target with corresponding mapper method
|
||||
method = "erpnext.selling.doctype.quotation.quotation.make_sales_order"
|
||||
@@ -28,18 +26,12 @@ class TestMapper(unittest.TestCase):
|
||||
|
||||
# Assert that all inserted items are present in updated sales order
|
||||
src_items = item_list_1 + item_list_2 + item_list_3
|
||||
self.assertEqual(set([d.item_code for d in src_items]),
|
||||
self.assertEqual(set([d for d in src_items]),
|
||||
set([d.item_code for d in updated_so.items]))
|
||||
|
||||
def get_random_items(self, items, limit):
|
||||
'''Get a number of random items from a list of given items'''
|
||||
random_items = []
|
||||
for i in range(0, limit):
|
||||
random_items.append(random.choice(items))
|
||||
return random_items
|
||||
|
||||
def make_quotation(self, items, customer):
|
||||
item_list = self.get_random_items(items, 3)
|
||||
def make_quotation(self, item_list, customer):
|
||||
|
||||
qtn = frappe.get_doc({
|
||||
"doctype": "Quotation",
|
||||
"quotation_to": "Customer",
|
||||
@@ -49,7 +41,7 @@ class TestMapper(unittest.TestCase):
|
||||
"valid_till" : add_months(nowdate(), 1)
|
||||
})
|
||||
for item in item_list:
|
||||
qtn.append("items", {"qty": "2", "item_code": item.item_code})
|
||||
qtn.append("items", {"qty": "2", "item_code": item})
|
||||
|
||||
qtn.submit()
|
||||
return qtn, item_list
|
||||
@@ -60,7 +52,7 @@ class TestMapper(unittest.TestCase):
|
||||
"base_rate": 100.0,
|
||||
"description": "CPU",
|
||||
"doctype": "Sales Order Item",
|
||||
"item_code": "_Test Item Home Desktop 100",
|
||||
"item_code": "_Test Item",
|
||||
"item_name": "CPU",
|
||||
"parentfield": "items",
|
||||
"qty": 10.0,
|
||||
@@ -72,4 +64,4 @@ class TestMapper(unittest.TestCase):
|
||||
})
|
||||
so = frappe.get_doc(frappe.get_test_records('Sales Order')[0])
|
||||
so.insert(ignore_permissions=True)
|
||||
return so, [item]
|
||||
return so, [item.item_code]
|
||||
|
||||
@@ -30,6 +30,7 @@ class TestTaxes(unittest.TestCase):
|
||||
self.item_tax_template = frappe.get_doc({
|
||||
'doctype': 'Item Tax Template',
|
||||
'title': uuid4(),
|
||||
'company': self.company.name,
|
||||
'taxes': [
|
||||
{
|
||||
'tax_type': self.account.name,
|
||||
|
||||
@@ -60,12 +60,18 @@ frappe.ui.form.on("Opportunity", {
|
||||
|
||||
opportunity_from: function(frm) {
|
||||
frm.toggle_reqd("party_name", frm.doc.opportunity_from);
|
||||
frm.trigger("setup_opportunity_from");
|
||||
frm.set_value("party_name","");
|
||||
},
|
||||
|
||||
setup_opportunity_from: function(frm) {
|
||||
frm.trigger('setup_queries');
|
||||
frm.trigger("set_dynamic_field_label");
|
||||
},
|
||||
|
||||
refresh: function(frm) {
|
||||
var doc = frm.doc;
|
||||
frm.events.opportunity_from(frm);
|
||||
frm.trigger("setup_opportunity_from");
|
||||
frm.trigger('toggle_mandatory');
|
||||
erpnext.toggle_naming_series();
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ def get_fee_components(fee_structure):
|
||||
:param fee_structure: Fee Structure.
|
||||
"""
|
||||
if fee_structure:
|
||||
fs = frappe.get_list("Fee Component", fields=["fees_category", "amount"] , filters={"parent": fee_structure}, order_by= "idx")
|
||||
fs = frappe.get_list("Fee Component", fields=["fees_category", "description", "amount"] , filters={"parent": fee_structure}, order_by= "idx")
|
||||
return fs
|
||||
|
||||
|
||||
@@ -363,9 +363,9 @@ def get_current_enrollment(student, academic_year=None):
|
||||
select
|
||||
name as program_enrollment, student_name, program, student_batch_name as student_batch,
|
||||
student_category, academic_term, academic_year
|
||||
from
|
||||
from
|
||||
`tabProgram Enrollment`
|
||||
where
|
||||
where
|
||||
student = %s and academic_year = %s
|
||||
order by creation''', (student, current_academic_year), as_dict=1)
|
||||
|
||||
|
||||
@@ -161,6 +161,7 @@ frappe.ui.form.on("Fees", {
|
||||
$.each(r.message, function(i, d) {
|
||||
var row = frappe.model.add_child(frm.doc, "Fee Component", "components");
|
||||
row.fees_category = d.fees_category;
|
||||
row.description = d.description;
|
||||
row.amount = d.amount;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -776,10 +776,10 @@ class SalarySlip(TransactionBase):
|
||||
|
||||
# other taxes and charges on income tax
|
||||
for d in tax_slab.other_taxes_and_charges:
|
||||
if flt(d.min_taxable_income) and flt(d.min_taxable_income) > tax_amount:
|
||||
if flt(d.min_taxable_income) and flt(d.min_taxable_income) > annual_taxable_earning:
|
||||
continue
|
||||
|
||||
if flt(d.max_taxable_income) and flt(d.max_taxable_income) < tax_amount:
|
||||
if flt(d.max_taxable_income) and flt(d.max_taxable_income) < annual_taxable_earning:
|
||||
continue
|
||||
|
||||
tax_amount += tax_amount * flt(d.percent) / 100
|
||||
|
||||
@@ -701,7 +701,7 @@
|
||||
"columns": 0,
|
||||
"default": "Draft",
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Data",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
@@ -1001,7 +1001,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-08-21 14:44:44.911402",
|
||||
"modified": "2020-07-15 14:44:44.911402",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Maintenance",
|
||||
"name": "Maintenance Visit",
|
||||
|
||||
@@ -3,7 +3,7 @@ frappe.provide("erpnext.financial_statements");
|
||||
erpnext.financial_statements = {
|
||||
"filters": get_filters(),
|
||||
"formatter": function(value, row, column, data, default_formatter) {
|
||||
if (column.fieldname=="account") {
|
||||
if (data && column.fieldname=="account") {
|
||||
value = data.account_name || value;
|
||||
|
||||
column.link_onclick =
|
||||
@@ -13,7 +13,7 @@ erpnext.financial_statements = {
|
||||
|
||||
value = default_formatter(value, row, column, data);
|
||||
|
||||
if (!data.parent_account) {
|
||||
if (data && !data.parent_account) {
|
||||
value = $(`<span>${value}</span>`);
|
||||
|
||||
var $value = $(value).css("font-weight", "bold");
|
||||
|
||||
@@ -333,8 +333,8 @@ erpnext.SerialNoBatchSelector = Class.extend({
|
||||
};
|
||||
},
|
||||
change: function () {
|
||||
let val = this.get_value();
|
||||
if (val.length === 0) {
|
||||
const batch_no = this.get_value();
|
||||
if (!batch_no) {
|
||||
this.grid_row.on_grid_fields_dict
|
||||
.available_qty.set_value(0);
|
||||
return;
|
||||
@@ -354,14 +354,11 @@ erpnext.SerialNoBatchSelector = Class.extend({
|
||||
return;
|
||||
}
|
||||
|
||||
let batch_number = me.item.batch_no ||
|
||||
this.grid_row.on_grid_fields_dict.batch_no.get_value();
|
||||
|
||||
if (me.warehouse_details.name) {
|
||||
frappe.call({
|
||||
method: 'erpnext.stock.doctype.batch.batch.get_batch_qty',
|
||||
args: {
|
||||
batch_no: batch_number,
|
||||
batch_no,
|
||||
warehouse: me.warehouse_details.name,
|
||||
item_code: me.item_code
|
||||
},
|
||||
|
||||
@@ -7,6 +7,8 @@ from frappe import _
|
||||
from frappe.utils import flt
|
||||
from frappe.model.meta import get_field_precision
|
||||
from frappe.utils.xlsxutils import handle_html
|
||||
from six import iteritems
|
||||
import json
|
||||
|
||||
def execute(filters=None):
|
||||
return _execute(filters)
|
||||
@@ -21,21 +23,24 @@ def _execute(filters=None):
|
||||
itemised_tax, tax_columns = get_tax_accounts(item_list, columns, company_currency)
|
||||
|
||||
data = []
|
||||
added_item = []
|
||||
for d in item_list:
|
||||
row = [d.gst_hsn_code, d.description, d.stock_uom, d.stock_qty]
|
||||
total_tax = 0
|
||||
for tax in tax_columns:
|
||||
item_tax = itemised_tax.get(d.name, {}).get(tax, {})
|
||||
total_tax += flt(item_tax.get("tax_amount"))
|
||||
if (d.parent, d.item_code) not in added_item:
|
||||
row = [d.gst_hsn_code, d.description, d.stock_uom, d.stock_qty]
|
||||
total_tax = 0
|
||||
for tax in tax_columns:
|
||||
item_tax = itemised_tax.get((d.parent, d.item_code), {}).get(tax, {})
|
||||
total_tax += flt(item_tax.get("tax_amount", 0))
|
||||
|
||||
row += [d.base_net_amount + total_tax]
|
||||
row += [d.base_net_amount]
|
||||
row += [d.base_net_amount + total_tax]
|
||||
row += [d.base_net_amount]
|
||||
|
||||
for tax in tax_columns:
|
||||
item_tax = itemised_tax.get(d.name, {}).get(tax, {})
|
||||
row += [item_tax.get("tax_amount", 0)]
|
||||
for tax in tax_columns:
|
||||
item_tax = itemised_tax.get((d.parent, d.item_code), {}).get(tax, {})
|
||||
row += [item_tax.get("tax_amount", 0)]
|
||||
|
||||
data.append(row)
|
||||
data.append(row)
|
||||
added_item.append((d.parent, d.item_code))
|
||||
if data:
|
||||
data = get_merged_data(columns, data) # merge same hsn code data
|
||||
return columns, data
|
||||
@@ -103,7 +108,7 @@ def get_items(filters):
|
||||
match_conditions = " and {0} ".format(match_conditions)
|
||||
|
||||
|
||||
return frappe.db.sql("""
|
||||
items = frappe.db.sql("""
|
||||
select
|
||||
`tabSales Invoice Item`.name, `tabSales Invoice Item`.base_price_list_rate,
|
||||
`tabSales Invoice Item`.gst_hsn_code, `tabSales Invoice Item`.stock_qty,
|
||||
@@ -118,10 +123,9 @@ def get_items(filters):
|
||||
|
||||
""" % (conditions, match_conditions), filters, as_dict=1)
|
||||
|
||||
return items
|
||||
|
||||
def get_tax_accounts(item_list, columns, company_currency,
|
||||
doctype="Sales Invoice", tax_doctype="Sales Taxes and Charges"):
|
||||
import json
|
||||
def get_tax_accounts(item_list, columns, company_currency, doctype="Sales Invoice", tax_doctype="Sales Taxes and Charges"):
|
||||
item_row_map = {}
|
||||
tax_columns = []
|
||||
invoice_item_row = {}
|
||||
@@ -171,7 +175,7 @@ def get_tax_accounts(item_list, columns, company_currency,
|
||||
for d in item_row_map.get(parent, {}).get(item_code, []):
|
||||
item_tax_amount = tax_amount
|
||||
if item_tax_amount:
|
||||
itemised_tax.setdefault(d.name, {})[description] = frappe._dict({
|
||||
itemised_tax.setdefault((parent, item_code), {})[description] = frappe._dict({
|
||||
"tax_amount": flt(item_tax_amount, tax_amount_precision)
|
||||
})
|
||||
except ValueError:
|
||||
@@ -179,42 +183,32 @@ def get_tax_accounts(item_list, columns, company_currency,
|
||||
|
||||
tax_columns.sort()
|
||||
for desc in tax_columns:
|
||||
columns.append(desc + " Amount:Currency/currency:160")
|
||||
columns.append({
|
||||
"label": desc,
|
||||
"fieldname": frappe.scrub(desc),
|
||||
"fieldtype": "Float",
|
||||
"width": 110
|
||||
})
|
||||
|
||||
# columns += ["Total Amount:Currency/currency:110"]
|
||||
return itemised_tax, tax_columns
|
||||
|
||||
def get_merged_data(columns, data):
|
||||
merged_hsn_dict = {} # to group same hsn under one key and perform row addition
|
||||
add_column_index = [] # store index of columns that needs to be added
|
||||
tax_col = len(get_columns())
|
||||
fields_to_merge = ["stock_qty", "total_amount", "taxable_amount"] # columns for which index needs to be found
|
||||
|
||||
for i,d in enumerate(columns):
|
||||
# check if fieldname in to_merge list and ignore tax-columns
|
||||
if i < tax_col and d["fieldname"] in fields_to_merge:
|
||||
add_column_index.append(i)
|
||||
result = []
|
||||
|
||||
for row in data:
|
||||
if row[0] in merged_hsn_dict:
|
||||
to_add_row = merged_hsn_dict.get(row[0])
|
||||
merged_hsn_dict.setdefault(row[0], {})
|
||||
for i, d in enumerate(columns):
|
||||
if d['fieldtype'] not in ('Int', 'Float', 'Currency'):
|
||||
merged_hsn_dict[row[0]][d['fieldname']] = row[i]
|
||||
else:
|
||||
if merged_hsn_dict.get(row[0], {}).get(d['fieldname'], ''):
|
||||
merged_hsn_dict[row[0]][d['fieldname']] += row[i]
|
||||
else:
|
||||
merged_hsn_dict[row[0]][d['fieldname']] = row[i]
|
||||
|
||||
# add columns from the add_column_index table
|
||||
for k in add_column_index:
|
||||
to_add_row[k] += row[k]
|
||||
for key, value in iteritems(merged_hsn_dict):
|
||||
result.append(value)
|
||||
|
||||
# add tax columns
|
||||
for k in range(len(columns)):
|
||||
if tax_col <= k < len(columns):
|
||||
to_add_row[k] += row[k]
|
||||
|
||||
# update hsn dict with the newly added data
|
||||
merged_hsn_dict[row[0]] = to_add_row
|
||||
else:
|
||||
merged_hsn_dict[row[0]] = row
|
||||
|
||||
# extract data rows to be displayed in report
|
||||
data = [merged_hsn_dict[d] for d in merged_hsn_dict]
|
||||
|
||||
return data
|
||||
return result
|
||||
|
||||
|
||||
@@ -1,39 +1,39 @@
|
||||
[
|
||||
{
|
||||
"advance_paid": 0.0,
|
||||
"company": "_Test Company",
|
||||
"conversion_rate": 1.0,
|
||||
"currency": "INR",
|
||||
"customer": "_Test Customer",
|
||||
"customer_group": "_Test Customer Group",
|
||||
"customer_name": "_Test Customer",
|
||||
"doctype": "Sales Order",
|
||||
"base_grand_total": 1000.0,
|
||||
"grand_total": 1000.0,
|
||||
"naming_series": "_T-Sales Order-",
|
||||
"order_type": "Sales",
|
||||
"plc_conversion_rate": 1.0,
|
||||
"price_list_currency": "INR",
|
||||
"company": "_Test Company",
|
||||
"conversion_rate": 1.0,
|
||||
"currency": "INR",
|
||||
"customer": "_Test Customer",
|
||||
"customer_group": "_Test Customer Group",
|
||||
"customer_name": "_Test Customer",
|
||||
"doctype": "Sales Order",
|
||||
"base_grand_total": 1000.0,
|
||||
"grand_total": 1000.0,
|
||||
"naming_series": "_T-Sales Order-",
|
||||
"order_type": "Sales",
|
||||
"plc_conversion_rate": 1.0,
|
||||
"price_list_currency": "INR",
|
||||
"items": [
|
||||
{
|
||||
"base_amount": 1000.0,
|
||||
"base_rate": 100.0,
|
||||
"description": "CPU",
|
||||
"doctype": "Sales Order Item",
|
||||
"item_code": "_Test Item Home Desktop 100",
|
||||
"item_name": "CPU",
|
||||
"delivery_date": "2013-02-23",
|
||||
"parentfield": "items",
|
||||
"qty": 10.0,
|
||||
"rate": 100.0,
|
||||
"base_amount": 1000.0,
|
||||
"base_rate": 100.0,
|
||||
"description": "CPU",
|
||||
"doctype": "Sales Order Item",
|
||||
"item_code": "_Test Item",
|
||||
"item_name": "_Test Item 1",
|
||||
"delivery_date": "2013-02-23",
|
||||
"parentfield": "items",
|
||||
"qty": 10.0,
|
||||
"rate": 100.0,
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
"stock_uom": "_Test UOM",
|
||||
"conversion_factor": 1.0,
|
||||
"uom": "_Test UOM"
|
||||
}
|
||||
],
|
||||
"selling_price_list": "_Test Price List",
|
||||
"territory": "_Test Territory",
|
||||
],
|
||||
"selling_price_list": "_Test Price List",
|
||||
"territory": "_Test Territory",
|
||||
"transaction_date": "2013-02-21"
|
||||
}
|
||||
]
|
||||
@@ -13,7 +13,7 @@ from erpnext.controllers.item_variant import (ItemVariantExistsError,
|
||||
from erpnext.setup.doctype.item_group.item_group import (get_parent_item_groups, invalidate_cache_for)
|
||||
from frappe import _, msgprint
|
||||
from frappe.utils import (cint, cstr, flt, formatdate, get_timestamp, getdate,
|
||||
now_datetime, random_string, strip)
|
||||
now_datetime, random_string, strip, get_link_to_form)
|
||||
from frappe.utils.html_utils import clean_html
|
||||
from frappe.website.doctype.website_slideshow.website_slideshow import \
|
||||
get_slideshow
|
||||
@@ -634,6 +634,9 @@ class Item(WebsiteGenerator):
|
||||
+ ": \n" + ", ".join([self.meta.get_label(fld) for fld in field_list]))
|
||||
|
||||
def after_rename(self, old_name, new_name, merge):
|
||||
if merge:
|
||||
self.validate_duplicate_item_in_stock_reconciliation(old_name, new_name)
|
||||
|
||||
if self.route:
|
||||
invalidate_cache_for_item(self)
|
||||
clear_cache(self.route)
|
||||
@@ -656,6 +659,27 @@ class Item(WebsiteGenerator):
|
||||
frappe.db.set_value(dt, d.name, "item_wise_tax_detail",
|
||||
json.dumps(item_wise_tax_detail), update_modified=False)
|
||||
|
||||
def validate_duplicate_item_in_stock_reconciliation(self, old_name, new_name):
|
||||
records = frappe.db.sql(""" SELECT parent, COUNT(*) as records
|
||||
FROM `tabStock Reconciliation Item`
|
||||
WHERE item_code = %s and docstatus = 1
|
||||
GROUP By item_code, warehouse, parent
|
||||
HAVING records > 1
|
||||
""", new_name, as_dict=1)
|
||||
|
||||
if not records: return
|
||||
document = _("Stock Reconciliation") if len(records) == 1 else _("Stock Reconciliations")
|
||||
|
||||
msg = _("The items {0} and {1} are present in the following {2} : <br>"
|
||||
.format(frappe.bold(old_name), frappe.bold(new_name), document))
|
||||
|
||||
msg += ', '.join([get_link_to_form("Stock Reconciliation", d.parent) for d in records]) + "<br><br>"
|
||||
|
||||
msg += _("Note: To merge the items, create a separate Stock Reconciliation for the old item {0}"
|
||||
.format(frappe.bold(old_name)))
|
||||
|
||||
frappe.throw(_(msg), title=_("Merge not allowed"))
|
||||
|
||||
def set_last_purchase_rate(self, new_name):
|
||||
last_purchase_rate = get_last_purchase_details(new_name).get("base_net_rate", 0)
|
||||
frappe.db.set_value("Item", new_name, "last_purchase_rate", last_purchase_rate)
|
||||
|
||||
@@ -92,8 +92,7 @@
|
||||
{
|
||||
"doctype": "Item Tax",
|
||||
"parentfield": "taxes",
|
||||
"item_tax_template": "_Test Account Excise Duty @ 10",
|
||||
"tax_category": ""
|
||||
"item_tax_template": "_Test Account Excise Duty @ 10"
|
||||
}
|
||||
],
|
||||
"stock_uom": "_Test UOM 1"
|
||||
@@ -371,8 +370,7 @@
|
||||
{
|
||||
"doctype": "Item Tax",
|
||||
"parentfield": "taxes",
|
||||
"item_tax_template": "_Test Account Excise Duty @ 10",
|
||||
"tax_category": ""
|
||||
"item_tax_template": "_Test Account Excise Duty @ 10"
|
||||
},
|
||||
{
|
||||
"doctype": "Item Tax",
|
||||
@@ -451,14 +449,13 @@
|
||||
{
|
||||
"doctype": "Item Tax",
|
||||
"parentfield": "taxes",
|
||||
"item_tax_template": "_Test Account Excise Duty @ 20",
|
||||
"tax_category": ""
|
||||
"item_tax_template": "_Test Account Excise Duty @ 20"
|
||||
},
|
||||
{
|
||||
"doctype": "Item Tax",
|
||||
"parentfield": "taxes",
|
||||
"item_tax_template": "_Test Item Tax Template 1",
|
||||
"tax_category": "_Test Tax Category 1"
|
||||
"tax_category": "_Test Tax Category 1",
|
||||
"item_tax_template": "_Test Item Tax Template 1"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -19,6 +19,12 @@ frappe.ui.form.on('Material Request', {
|
||||
frm.set_indicator_formatter('item_code',
|
||||
function(doc) { return (doc.stock_qty<=doc.ordered_qty) ? "green" : "orange"; });
|
||||
|
||||
frm.set_query("from_warehouse", "items", function(doc) {
|
||||
return {
|
||||
filters: {'company': doc.company}
|
||||
};
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
onload: function(frm) {
|
||||
@@ -27,11 +33,24 @@ frappe.ui.form.on('Material Request', {
|
||||
|
||||
// set schedule_date
|
||||
set_schedule_date(frm);
|
||||
frm.fields_dict["items"].grid.get_field("warehouse").get_query = function(doc) {
|
||||
|
||||
frm.set_query("warehouse", "items", function(doc) {
|
||||
return {
|
||||
filters: {'company': doc.company}
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
frm.set_query("set_warehouse", function(doc){
|
||||
return {
|
||||
filters: {'company': doc.company}
|
||||
};
|
||||
});
|
||||
|
||||
frm.set_query("set_from_warehouse", function(doc){
|
||||
return {
|
||||
filters: {'company': doc.company}
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
onload_post_render: function(frm) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:serial_no",
|
||||
"creation": "2013-05-16 10:59:15",
|
||||
"description": "Distinct unit of an Item",
|
||||
@@ -426,7 +427,7 @@
|
||||
"icon": "fa fa-barcode",
|
||||
"idx": 1,
|
||||
"links": [],
|
||||
"modified": "2020-06-25 15:53:50.900855",
|
||||
"modified": "2020-07-22 15:53:50.900855",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Serial No",
|
||||
|
||||
@@ -193,7 +193,7 @@ class SerialNo(StockController):
|
||||
def after_rename(self, old, new, merge=False):
|
||||
"""rename serial_no text fields"""
|
||||
for dt in frappe.db.sql("""select parent from tabDocField
|
||||
where fieldname='serial_no' and fieldtype in ('Text', 'Small Text')"""):
|
||||
where fieldname='serial_no' and fieldtype in ('Text', 'Small Text', 'Long Text')"""):
|
||||
|
||||
for item in frappe.db.sql("""select name, serial_no from `tab%s`
|
||||
where serial_no like %s""" % (dt[0], frappe.db.escape('%' + old + '%'))):
|
||||
|
||||
@@ -257,6 +257,7 @@ class StockReconciliation(StockController):
|
||||
|
||||
sl_entries.append(args)
|
||||
|
||||
qty_after_transaction = 0
|
||||
for serial_no in serial_nos:
|
||||
args = self.get_sle_for_items(row, [serial_no])
|
||||
|
||||
@@ -270,11 +271,19 @@ class StockReconciliation(StockController):
|
||||
if previous_sle and row.warehouse != previous_sle.get("warehouse"):
|
||||
# If serial no exists in different warehouse
|
||||
|
||||
warehouse = previous_sle.get("warehouse", '') or row.warehouse
|
||||
|
||||
if not qty_after_transaction:
|
||||
qty_after_transaction = get_stock_balance(row.item_code,
|
||||
warehouse, self.posting_date, self.posting_time)
|
||||
|
||||
qty_after_transaction -= 1
|
||||
|
||||
new_args = args.copy()
|
||||
new_args.update({
|
||||
'actual_qty': -1,
|
||||
'qty_after_transaction': cint(previous_sle.get('qty_after_transaction')) - 1,
|
||||
'warehouse': previous_sle.get("warehouse", '') or row.warehouse,
|
||||
'qty_after_transaction': qty_after_transaction,
|
||||
'warehouse': warehouse,
|
||||
'valuation_rate': previous_sle.get("valuation_rate")
|
||||
})
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"creation": "2013-03-07 18:50:32",
|
||||
@@ -10,12 +9,14 @@
|
||||
"field_order": [
|
||||
"warehouse_detail",
|
||||
"warehouse_name",
|
||||
"section_break_3",
|
||||
"warehouse_type",
|
||||
"parent_warehouse",
|
||||
"is_group",
|
||||
"company",
|
||||
"disabled",
|
||||
"column_break_4",
|
||||
"account",
|
||||
"warehouse_type",
|
||||
"company",
|
||||
"disabled",
|
||||
"address_and_contact",
|
||||
"address_html",
|
||||
"column_break_10",
|
||||
@@ -31,7 +32,6 @@
|
||||
"state",
|
||||
"pin",
|
||||
"tree_details",
|
||||
"parent_warehouse",
|
||||
"lft",
|
||||
"rgt",
|
||||
"old_parent"
|
||||
@@ -91,6 +91,7 @@
|
||||
"options": "Account"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"fieldname": "address_and_contact",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Address and Contact"
|
||||
@@ -224,13 +225,16 @@
|
||||
"fieldtype": "Link",
|
||||
"label": "Warehouse Type",
|
||||
"options": "Warehouse Type"
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_3",
|
||||
"fieldtype": "Section Break"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-building",
|
||||
"idx": 1,
|
||||
"is_tree": 1,
|
||||
"links": [],
|
||||
"modified": "2020-03-18 18:26:00.479541",
|
||||
"modified": "2020-07-22 14:46:37.650475",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Warehouse",
|
||||
|
||||
Reference in New Issue
Block a user