Merge branch 'develop' into lcv_multicurrency
diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
index 41f9ce0..a3c29b6 100644
--- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
+++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
@@ -21,6 +21,7 @@
"book_asset_depreciation_entry_automatically",
"add_taxes_from_item_tax_template",
"automatically_fetch_payment_terms",
+ "delete_linked_ledger_entries",
"deferred_accounting_settings_section",
"automatically_process_deferred_accounting_entry",
"book_deferred_entries_based_on",
@@ -219,6 +220,12 @@
"fieldtype": "Select",
"label": "Book Deferred Entries Based On",
"options": "Days\nMonths"
+ },
+ {
+ "default": "0",
+ "fieldname": "delete_linked_ledger_entries",
+ "fieldtype": "Check",
+ "label": "Delete Accounting and Stock Ledger Entries on deletion of Transaction"
}
],
"icon": "icon-cog",
@@ -226,7 +233,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2020-10-13 11:32:52.268826",
+ "modified": "2021-01-05 13:04:00.118892",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",
@@ -254,4 +261,4 @@
"sort_field": "modified",
"sort_order": "ASC",
"track_changes": 1
-}
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index 4a952a3..06aa20b 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -275,8 +275,11 @@
supplier: function() {
var me = this;
- if(this.frm.updating_party_details)
+
+ // Do not update if inter company reference is there as the details will already be updated
+ if(this.frm.updating_party_details || this.frm.doc.inter_company_invoice_reference)
return;
+
erpnext.utils.get_party_details(this.frm, "erpnext.accounts.party.get_party_details",
{
posting_date: this.frm.doc.posting_date,
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index c64ffd8..451c936 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -57,8 +57,8 @@
"set_warehouse",
"rejected_warehouse",
"col_break_warehouse",
+ "set_from_warehouse",
"is_subcontracted",
- "supplier_warehouse",
"items_section",
"update_stock",
"scan_barcode",
@@ -515,6 +515,7 @@
},
{
"depends_on": "update_stock",
+ "description": "Sets 'Accepted Warehouse' in each row of the items table.",
"fieldname": "set_warehouse",
"fieldtype": "Link",
"label": "Set Accepted Warehouse",
@@ -544,17 +545,6 @@
"print_hide": 1
},
{
- "depends_on": "eval:doc.is_subcontracted==\"Yes\"",
- "fieldname": "supplier_warehouse",
- "fieldtype": "Link",
- "label": "Supplier Warehouse",
- "no_copy": 1,
- "options": "Warehouse",
- "print_hide": 1,
- "print_width": "50px",
- "width": "50px"
- },
- {
"fieldname": "items_section",
"fieldtype": "Section Break",
"oldfieldtype": "Section Break",
@@ -1232,7 +1222,9 @@
"fieldname": "inter_company_invoice_reference",
"fieldtype": "Link",
"label": "Inter Company Invoice Reference",
+ "no_copy": 1,
"options": "Sales Invoice",
+ "print_hide": 1,
"read_only": 1
},
{
@@ -1356,13 +1348,25 @@
"fieldtype": "Link",
"label": "Represents Company",
"options": "Company"
+ },
+ {
+ "depends_on": "eval:doc.update_stock && (doc.is_subcontracted==\"Yes\" || doc.is_internal_supplier)",
+ "description": "Sets 'From Warehouse' in each row of the items table.",
+ "fieldname": "set_from_warehouse",
+ "fieldtype": "Link",
+ "label": "Set From Warehouse",
+ "no_copy": 1,
+ "options": "Warehouse",
+ "print_hide": 1,
+ "print_width": "50px",
+ "width": "50px"
}
],
"icon": "fa fa-file-text",
"idx": 204,
"is_submittable": 1,
"links": [],
- "modified": "2020-12-11 12:46:12.796378",
+ "modified": "2020-12-26 20:49:03.305063",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 3c29561..dacd50a 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -480,7 +480,7 @@
grand_total = self.rounded_total if (self.rounding_adjustment and self.rounded_total) else self.grand_total
if grand_total and not self.is_internal_transfer():
- # Didnot use base_grand_total to book rounding loss gle
+ # Did not use base_grand_total to book rounding loss gle
grand_total_in_company_currency = flt(grand_total * self.conversion_rate,
self.precision("grand_total"))
gl_entries.append(
@@ -511,8 +511,8 @@
voucher_wise_stock_value = {}
if self.update_stock:
for d in frappe.get_all('Stock Ledger Entry',
- fields = ["voucher_detail_no", "stock_value_difference"], filters={'voucher_no': self.name}):
- voucher_wise_stock_value.setdefault(d.voucher_detail_no, d.stock_value_difference)
+ fields = ["voucher_detail_no", "stock_value_difference", "warehouse"], filters={'voucher_no': self.name}):
+ voucher_wise_stock_value.setdefault((d.voucher_detail_no, d.warehouse), d.stock_value_difference)
valuation_tax_accounts = [d.account_head for d in self.get("taxes")
if d.category in ('Valuation', 'Total and Valuation')
@@ -563,16 +563,17 @@
)
else:
- gl_entries.append(
- self.get_gl_dict({
- "account": item.expense_account,
- "against": self.supplier,
- "debit": warehouse_debit_amount,
- "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
- "cost_center": item.cost_center,
- "project": item.project or self.project
- }, account_currency, item=item)
- )
+ if not self.is_internal_transfer():
+ gl_entries.append(
+ self.get_gl_dict({
+ "account": item.expense_account,
+ "against": self.supplier,
+ "debit": warehouse_debit_amount,
+ "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
+ "cost_center": item.cost_center,
+ "project": item.project or self.project
+ }, account_currency, item=item)
+ )
# Amount added through landed-cost-voucher
if landed_cost_entries:
@@ -625,13 +626,14 @@
if expense_booked_in_pr:
expense_account = service_received_but_not_billed_account
- gl_entries.append(self.get_gl_dict({
- "account": expense_account,
- "against": self.supplier,
- "debit": amount,
- "cost_center": item.cost_center,
- "project": item.project or self.project
- }, account_currency, item=item))
+ if not self.is_internal_transfer():
+ gl_entries.append(self.get_gl_dict({
+ "account": expense_account,
+ "against": self.supplier,
+ "debit": amount,
+ "cost_center": item.cost_center,
+ "project": item.project or self.project
+ }, account_currency, item=item))
# If asset is bought through this document and not linked to PR
if self.update_stock and item.landed_cost_voucher_amount:
@@ -796,10 +798,10 @@
# Stock ledger value is not matching with the warehouse amount
if (self.update_stock and voucher_wise_stock_value.get(item.name) and
- warehouse_debit_amount != flt(voucher_wise_stock_value.get(item.name), net_amt_precision)):
+ warehouse_debit_amount != flt(voucher_wise_stock_value.get((item.name, item.warehouse)), net_amt_precision)):
cost_of_goods_sold_account = self.get_company_default("default_expense_account")
- stock_amount = flt(voucher_wise_stock_value.get(item.name), net_amt_precision)
+ stock_amount = flt(voucher_wise_stock_value.get((item.name, item.warehouse)), net_amt_precision)
stock_adjustment_amt = warehouse_debit_amount - stock_amount
gl_entries.append(
diff --git a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
index f6d76e5..1f7853d 100644
--- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
+++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"autoname": "hash",
"creation": "2013-05-22 12:43:10",
"doctype": "DocType",
@@ -87,6 +88,7 @@
"po_detail",
"purchase_receipt",
"pr_detail",
+ "sales_invoice_item",
"item_weight_details",
"weight_per_unit",
"total_weight",
@@ -553,8 +555,8 @@
"fieldtype": "Link",
"hidden": 1,
"label": "Brand",
- "print_hide": 1,
- "options": "Brand"
+ "options": "Brand",
+ "print_hide": 1
},
{
"fetch_from": "item_code.item_group",
@@ -562,9 +564,9 @@
"fieldname": "item_group",
"fieldtype": "Link",
"label": "Item Group",
+ "options": "Item Group",
"print_hide": 1,
- "read_only": 1,
- "options": "Item Group"
+ "read_only": 1
},
{
"description": "Tax detail table fetched from item master as a string and stored in this field.\nUsed for Taxes and Charges",
@@ -759,10 +761,11 @@
"read_only": 1
},
{
+ "depends_on": "eval:parent.is_internal_supplier && parent.update_stock",
"fieldname": "from_warehouse",
"fieldtype": "Link",
"ignore_user_permissions": 1,
- "label": "Supplier Warehouse",
+ "label": "From Warehouse",
"options": "Warehouse"
},
{
@@ -779,11 +782,20 @@
"no_copy": 1,
"print_hide": 1,
"read_only": 1
+ },
+ {
+ "fieldname": "sales_invoice_item",
+ "fieldtype": "Data",
+ "label": "Sales Invoice Item",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
}
],
"idx": 1,
"istable": 1,
- "modified": "2020-08-20 11:48:01.398356",
+ "links": [],
+ "modified": "2020-12-26 17:20:36.415791",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice Item",
@@ -791,4 +803,4 @@
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC"
-}
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 72199a9..f2a62cd 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -130,16 +130,15 @@
this.set_default_print_format();
if (doc.docstatus == 1 && !doc.inter_company_invoice_reference) {
- frappe.model.with_doc("Customer", me.frm.doc.customer, function() {
- var customer = frappe.model.get_doc("Customer", me.frm.doc.customer);
- var internal = customer.is_internal_customer;
- var disabled = customer.disabled;
- if (internal == 1 && disabled == 0) {
- me.frm.add_custom_button("Inter Company Invoice", function() {
- me.make_inter_company_invoice();
- }, __('Create'));
- }
- });
+ let internal = me.frm.doc.is_internal_customer;
+ if (internal) {
+ let button_label = (me.frm.doc.company === me.frm.doc.represents_company) ? "Internal Purchase Invoice" :
+ "Inter Company Purchase Invoice";
+
+ me.frm.add_custom_button(button_label, function() {
+ me.make_inter_company_invoice();
+ }, __('Create'));
+ }
}
},
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index 6799fb9..447cee4 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -60,6 +60,8 @@
"ignore_pricing_rule",
"sec_warehouse",
"set_warehouse",
+ "column_break_55",
+ "set_target_warehouse",
"items_section",
"update_stock",
"scan_barcode",
@@ -1969,13 +1971,24 @@
"label": "Represents Company",
"options": "Company",
"read_only": 1
+ },
+ {
+ "fieldname": "column_break_55",
+ "fieldtype": "Column Break"
+ },
+ {
+ "depends_on": "eval: doc.is_internal_customer && doc.update_stock",
+ "fieldname": "set_target_warehouse",
+ "fieldtype": "Link",
+ "label": "Set Target Warehouse",
+ "options": "Warehouse"
}
],
"icon": "fa fa-file-text",
"idx": 181,
"is_submittable": 1,
"links": [],
- "modified": "2020-12-11 12:48:31.769958",
+ "modified": "2020-12-25 22:57:32.555067",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 566734e..7116a6a 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -6,7 +6,7 @@
import frappe.defaults
from frappe.utils import cint, flt, getdate, add_days, cstr, nowdate, get_link_to_form, formatdate
from frappe import _, msgprint, throw
-from erpnext.accounts.party import get_party_account, get_due_date
+from erpnext.accounts.party import get_party_account, get_due_date, get_party_details
from frappe.model.mapper import get_mapped_doc
from erpnext.controllers.selling_controller import SellingController
from erpnext.accounts.utils import get_account_currency
@@ -21,6 +21,8 @@
from erpnext.accounts.doctype.loyalty_program.loyalty_program import \
get_loyalty_program_details_with_points, get_loyalty_details, validate_loyalty_points
from erpnext.accounts.deferred_revenue import validate_service_stop_date
+from frappe.model.utils import get_fetch_values
+from frappe.contacts.doctype.address.address import get_address_display
from erpnext.healthcare.utils import manage_invoice_submit_cancel
@@ -1534,7 +1536,7 @@
details = get_inter_company_details(doc, doctype)
price_list = doc.selling_price_list if doctype in ["Sales Invoice", "Sales Order", "Delivery Note"] else doc.buying_price_list
valid_price_list = frappe.db.get_value("Price List", {"name": price_list, "buying": 1, "selling": 1})
- if not valid_price_list:
+ if not valid_price_list and not doc.is_internal_transfer():
frappe.throw(_("Selected Price List should have buying and selling fields checked."))
party = details.get("party")
@@ -1557,6 +1559,7 @@
if doctype in ["Sales Invoice", "Sales Order"]:
source_doc = frappe.get_doc(doctype, source_name)
target_doctype = "Purchase Invoice" if doctype == "Sales Invoice" else "Purchase Order"
+ target_detail_field = "sales_invoice_item" if doctype == "Sales Invoice" else "sales_order_item"
source_document_warehouse_field = 'target_warehouse'
target_document_warehouse_field = 'from_warehouse'
else:
@@ -1570,6 +1573,7 @@
def set_missing_values(source, target):
target.run_method("set_missing_values")
+ set_purchase_references(target)
def update_details(source_doc, target_doc, source_parent):
target_doc.inter_company_invoice_reference = source_doc.name
@@ -1577,19 +1581,38 @@
currency = frappe.db.get_value('Supplier', details.get('party'), 'default_currency')
target_doc.company = details.get("company")
target_doc.supplier = details.get("party")
+ target_doc.is_internal_supplier = 1
+ target_doc.ignore_pricing_rule = 1
target_doc.buying_price_list = source_doc.selling_price_list
+ # Invert Addresses
+ update_address(target_doc, 'supplier_address', 'address_display', source_doc.company_address)
+ update_address(target_doc, 'shipping_address', 'shipping_address_display', source_doc.customer_address)
+
if currency:
target_doc.currency = currency
+
+ update_taxes(target_doc, party=target_doc.supplier, party_type='Supplier', company=target_doc.company,
+ doctype=target_doc.doctype, party_address=target_doc.supplier_address,
+ company_address=target_doc.shipping_address)
+
else:
currency = frappe.db.get_value('Customer', details.get('party'), 'default_currency')
target_doc.company = details.get("company")
target_doc.customer = details.get("party")
target_doc.selling_price_list = source_doc.buying_price_list
+ update_address(target_doc, 'company_address', 'company_address_display', source_doc.supplier_address)
+ update_address(target_doc, 'shipping_address_name', 'shipping_address', source_doc.shipping_address)
+ update_address(target_doc, 'customer_address', 'address_display', source_doc.shipping_address)
+
if currency:
target_doc.currency = currency
+ update_taxes(target_doc, party=target_doc.customer, party_type='Customer', company=target_doc.company,
+ doctype=target_doc.doctype, party_address=target_doc.customer_address,
+ company_address=target_doc.company_address, shipping_address_name=target_doc.shipping_address_name)
+
item_field_map = {
"doctype": target_doctype + " Item",
"field_no_map": [
@@ -1597,25 +1620,33 @@
"expense_account",
"cost_center",
"warehouse"
- ]
+ ],
+ "field_map": {
+ 'rate': 'rate',
+ }
}
- if source_doc.get('update_stock'):
- item_field_map.update({
- 'field_map': {
- source_document_warehouse_field: target_document_warehouse_field,
- 'batch_no': 'batch_no',
- 'serial_no': 'serial_no'
- }
+ if doctype in ["Sales Invoice", "Sales Order"]:
+ item_field_map["field_map"].update({
+ "name": target_detail_field,
})
+ if source_doc.get('update_stock'):
+ item_field_map["field_map"].update({
+ source_document_warehouse_field: target_document_warehouse_field,
+ 'batch_no': 'batch_no',
+ 'serial_no': 'serial_no'
+ })
doclist = get_mapped_doc(doctype, source_name, {
doctype: {
"doctype": target_doctype,
"postprocess": update_details,
+ "set_target_warehouse": "set_from_warehouse",
"field_no_map": [
- "taxes_and_charges"
+ "taxes_and_charges",
+ "set_warehouse",
+ "shipping_address"
]
},
doctype +" Item": item_field_map
@@ -1624,6 +1655,110 @@
return doclist
+def set_purchase_references(doc):
+ # add internal PO or PR links if any
+ if doc.is_internal_transfer():
+ if doc.doctype == 'Purchase Receipt':
+ so_item_map = get_delivery_note_details(doc.inter_company_invoice_reference)
+
+ if so_item_map:
+ pd_item_map, parent_child_map, warehouse_map = \
+ get_pd_details('Purchase Order Item', so_item_map, 'sales_order_item')
+
+ update_pr_items(doc, so_item_map, pd_item_map, parent_child_map, warehouse_map)
+
+ elif doc.doctype == 'Purchase Invoice':
+ dn_item_map, so_item_map = get_sales_invoice_details(doc.inter_company_invoice_reference)
+ # First check for Purchase receipt
+ if list(dn_item_map.values()):
+ pd_item_map, parent_child_map, warehouse_map = \
+ get_pd_details('Purchase Receipt Item', dn_item_map, 'delivery_note_item')
+
+ update_pi_items(doc, 'pr_detail', 'purchase_receipt',
+ dn_item_map, pd_item_map, parent_child_map, warehouse_map)
+
+ if list(so_item_map.values()):
+ pd_item_map, parent_child_map, warehouse_map = \
+ get_pd_details('Purchase Order Item', so_item_map, 'sales_order_item')
+
+ update_pi_items(doc, 'po_detail', 'purchase_order',
+ so_item_map, pd_item_map, parent_child_map, warehouse_map)
+
+def update_pi_items(doc, detail_field, parent_field, sales_item_map,
+ purchase_item_map, parent_child_map, warehouse_map):
+ for item in doc.get('items'):
+ item.set(detail_field, purchase_item_map.get(sales_item_map.get(item.sales_invoice_item)))
+ item.set(parent_field, parent_child_map.get(sales_item_map.get(item.sales_invoice_item)))
+ if doc.update_stock:
+ item.warehouse = warehouse_map.get(sales_item_map.get(item.sales_invoice_item))
+
+def update_pr_items(doc, sales_item_map, purchase_item_map, parent_child_map, warehouse_map):
+ for item in doc.get('items'):
+ item.purchase_order_item = purchase_item_map.get(sales_item_map.get(item.delivery_note_item))
+ item.warehouse = warehouse_map.get(sales_item_map.get(item.delivery_note_item))
+ item.purchase_order = parent_child_map.get(sales_item_map.get(item.delivery_note_item))
+
+def get_delivery_note_details(internal_reference):
+ so_item_map = {}
+
+ si_item_details = frappe.get_all('Delivery Note Item', fields=['name', 'so_detail'],
+ filters={'parent': internal_reference})
+
+ for d in si_item_details:
+ so_item_map.setdefault(d.name, d.so_detail)
+
+ return so_item_map
+
+def get_sales_invoice_details(internal_reference):
+ dn_item_map = {}
+ so_item_map = {}
+
+ si_item_details = frappe.get_all('Sales Invoice Item', fields=['name', 'so_detail',
+ 'dn_detail'], filters={'parent': internal_reference})
+
+ for d in si_item_details:
+ if d.dn_detail:
+ dn_item_map.setdefault(d.name, d.dn_detail)
+ if d.so_detail:
+ so_item_map.setdefault(d.name, d.so_detail)
+
+ return dn_item_map, so_item_map
+
+def get_pd_details(doctype, sd_detail_map, sd_detail_field):
+ pd_item_map = {}
+ accepted_warehouse_map = {}
+ parent_child_map = {}
+
+ pd_item_details = frappe.get_all(doctype,
+ fields=[sd_detail_field, 'name', 'warehouse', 'parent'], filters={sd_detail_field: ('in', list(sd_detail_map.values()))})
+
+ for d in pd_item_details:
+ pd_item_map.setdefault(d.get(sd_detail_field), d.name)
+ parent_child_map.setdefault(d.get(sd_detail_field), d.parent)
+ accepted_warehouse_map.setdefault(d.get(sd_detail_field), d.warehouse)
+
+ return pd_item_map, parent_child_map, accepted_warehouse_map
+
+def update_taxes(doc, party=None, party_type=None, company=None, doctype=None, party_address=None,
+ company_address=None, shipping_address_name=None, master_doctype=None):
+ # Update Party Details
+ party_details = get_party_details(party=party, party_type=party_type, company=company,
+ doctype=doctype, party_address=party_address, company_address=company_address,
+ shipping_address=shipping_address_name)
+
+ # Update taxes and charges if any
+ doc.taxes_and_charges = party_details.get('taxes_and_charges')
+ doc.set('taxes', party_details.get('taxes'))
+
+def update_address(doc, address_field, address_display_field, address_name):
+ doc.set(address_field, address_name)
+ fetch_values = get_fetch_values(doc.doctype, address_field, address_name)
+
+ for key, value in fetch_values.items():
+ doc.set(key, value)
+
+ doc.set(address_display_field, get_address_display(doc.get(address_field)))
+
@frappe.whitelist()
def get_loyalty_programs(customer):
''' sets applicable loyalty program to the customer or returns a list of applicable programs '''
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 3a6dbeb..e94e2cd 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -22,6 +22,7 @@
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.delivery_note.delivery_note import make_sales_invoice
+from erpnext.stock.utils import get_incoming_rate
class TestSalesInvoice(unittest.TestCase):
def make(self):
@@ -688,7 +689,7 @@
self.assertTrue(gle)
def test_pos_gl_entry_with_perpetual_inventory(self):
- make_pos_profile(company="_Test Company with perpetual inventory", income_account = "Sales - TCP1",
+ make_pos_profile(company="_Test Company with perpetual inventory", income_account = "Sales - TCP1",
expense_account = "Cost of Goods Sold - TCP1", warehouse="Stores - TCP1", cost_center = "Main - TCP1", write_off_account="_Test Write Off - TCP1")
pr = make_purchase_receipt(company= "_Test Company with perpetual inventory", item_code= "_Test FG Item",warehouse= "Stores - TCP1",cost_center= "Main - TCP1")
@@ -745,7 +746,7 @@
self.assertEqual(pos_return.get('payments')[0].amount, -1000)
def test_pos_change_amount(self):
- make_pos_profile(company="_Test Company with perpetual inventory", income_account = "Sales - TCP1",
+ make_pos_profile(company="_Test Company with perpetual inventory", income_account = "Sales - TCP1",
expense_account = "Cost of Goods Sold - TCP1", warehouse="Stores - TCP1", cost_center = "Main - TCP1", write_off_account="_Test Write Off - TCP1")
pr = make_purchase_receipt(company= "_Test Company with perpetual inventory",
@@ -1770,59 +1771,82 @@
self.assertEqual(target_doc.company, "_Test Company 1")
self.assertEqual(target_doc.supplier, "_Test Internal Supplier")
- # def test_internal_transfer_gl_entry(self):
- # ## Create internal transfer account
- # account = create_account(account_name="Unrealized Profit",
- # parent_account="Current Liabilities - TCP1", company="_Test Company with perpetual inventory")
+ def test_internal_transfer_gl_entry(self):
+ ## 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)
+ 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")
+ 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")
+ 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 = customer,
- # 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
- # )
+ si = create_sales_invoice(
+ company = "_Test Company with perpetual inventory",
+ customer = customer,
+ 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
+ )
- # si.selling_price_list = "_Test Price List Rest of the World"
- # si.update_stock = 1
- # si.items[0].target_warehouse = 'Work In Progress - TCP1'
- # add_taxes(si)
- # si.save()
- # si.submit()
+ si.selling_price_list = "_Test Price List Rest of the World"
+ si.update_stock = 1
+ si.items[0].target_warehouse = 'Work In Progress - TCP1'
+ add_taxes(si)
+ si.save()
- # target_doc = make_inter_company_transaction("Sales Invoice", si.name)
- # target_doc.company = '_Test Company with perpetual inventory'
- # target_doc.items[0].warehouse = 'Finished Goods - TCP1'
- # add_taxes(target_doc)
- # target_doc.save()
- # target_doc.submit()
+ 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)
- # si_gl_entries = [
- # ["_Test Account Excise Duty - TCP1", 0.0, 12.0, nowdate()],
- # ["Unrealized Profit - TCP1", 12.0, 0.0, nowdate()]
- # ]
+ rate = flt(rate, 2)
- # check_gl_entries(self, si.name, si_gl_entries, add_days(nowdate(), -1))
+ si.submit()
- # pi_gl_entries = [
- # ["_Test Account Excise Duty - TCP1", 12.0 , 0.0, nowdate()],
- # ["Unrealized Profit - TCP1", 0.0, 12.0, nowdate()]
- # ]
+ target_doc = make_inter_company_transaction("Sales Invoice", si.name)
+ target_doc.company = '_Test Company with perpetual inventory'
+ target_doc.items[0].warehouse = 'Finished Goods - TCP1'
+ add_taxes(target_doc)
+ target_doc.save()
+ target_doc.submit()
- # check_gl_entries(self, target_doc.name, pi_gl_entries, add_days(nowdate(), -1))
+ tax_amount = flt(rate * (12/100), 2)
+ si_gl_entries = [
+ ["_Test Account Excise Duty - TCP1", 0.0, tax_amount, nowdate()],
+ ["Unrealized Profit - TCP1", tax_amount, 0.0, nowdate()]
+ ]
+
+ check_gl_entries(self, si.name, si_gl_entries, add_days(nowdate(), -1))
+
+ pi_gl_entries = [
+ ["_Test Account Excise Duty - TCP1", tax_amount , 0.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))
def test_eway_bill_json(self):
si = make_sales_invoice_for_ewaybill()
diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
index 3695075..7a98aff 100644
--- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
+++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
@@ -565,11 +565,12 @@
"print_hide": 1
},
{
+ "depends_on": "eval: parent.is_internal_customer && parent.update_stock",
"fieldname": "target_warehouse",
"fieldtype": "Link",
"hidden": 1,
"ignore_user_permissions": 1,
- "label": "Customer Warehouse (Optional)",
+ "label": "Target Warehouse",
"no_copy": 1,
"options": "Warehouse",
"print_hide": 1
@@ -815,7 +816,7 @@
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2020-09-23 19:59:04.879322",
+ "modified": "2020-12-26 17:25:04.090630",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Item",
diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py
index b46de6c..429a9f3 100644
--- a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py
+++ b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py
@@ -34,6 +34,9 @@
validate_disabled(doc)
+ # Validate with existing taxes and charges template for unique tax category
+ validate_for_tax_category(doc)
+
for tax in doc.get("taxes"):
validate_taxes_and_charges(tax)
validate_inclusive_tax(tax, doc)
@@ -41,3 +44,7 @@
def validate_disabled(doc):
if doc.is_default and doc.disabled:
frappe.throw(_("Disabled template must not be default template"))
+
+def validate_for_tax_category(doc):
+ if frappe.db.exists(doc.doctype, {"company": doc.company, "tax_category": doc.tax_category, "disabled": 0}):
+ frappe.throw(_("A template with tax category {0} already exists. Only one template is allowed with each tax category").format(frappe.bold(doc.tax_category)))
diff --git a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py
index eeb5140..cb4d9b4 100644
--- a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py
+++ b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py
@@ -49,7 +49,8 @@
elif d.po_detail:
purchase_receipt = ", ".join(po_pr_map.get(d.po_detail, []))
- expense_account = d.expense_account or aii_account_map.get(d.company)
+ expense_account = d.unrealized_profit_loss_account or d.expense_account \
+ or aii_account_map.get(d.company)
row = {
'item_code': d.item_code,
@@ -315,6 +316,7 @@
`tabPurchase Invoice Item`.`name`, `tabPurchase Invoice Item`.`parent`,
`tabPurchase Invoice`.posting_date, `tabPurchase Invoice`.credit_to, `tabPurchase Invoice`.company,
`tabPurchase Invoice`.supplier, `tabPurchase Invoice`.remarks, `tabPurchase Invoice`.base_net_total,
+ `tabPurchase Invoice`.unrealized_profit_loss_account,
`tabPurchase Invoice Item`.`item_code`, `tabPurchase Invoice Item`.description,
`tabPurchase Invoice Item`.`item_name`, `tabPurchase Invoice Item`.`item_group`,
`tabPurchase Invoice Item`.`project`, `tabPurchase Invoice Item`.`purchase_order`,
diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py
index f54ceb0..998003a 100644
--- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py
+++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py
@@ -76,7 +76,7 @@
'company': d.company,
'sales_order': d.sales_order,
'delivery_note': d.delivery_note,
- 'income_account': d.income_account,
+ 'income_account': d.unrealized_profit_loss_account or d.income_account,
'cost_center': d.cost_center,
'stock_qty': d.stock_qty,
'stock_uom': d.stock_uom
@@ -379,6 +379,7 @@
select
`tabSales Invoice Item`.name, `tabSales Invoice Item`.parent,
`tabSales Invoice`.posting_date, `tabSales Invoice`.debit_to,
+ `tabSales Invoice`.unrealized_profit_loss_account,
`tabSales Invoice`.project, `tabSales Invoice`.customer, `tabSales Invoice`.remarks,
`tabSales Invoice`.territory, `tabSales Invoice`.company, `tabSales Invoice`.base_net_total,
`tabSales Invoice Item`.item_code, `tabSales Invoice Item`.description,
diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py
index 9399e70..8ac749d 100644
--- a/erpnext/accounts/report/purchase_register/purchase_register.py
+++ b/erpnext/accounts/report/purchase_register/purchase_register.py
@@ -14,13 +14,15 @@
if not filters: filters = {}
invoice_list = get_invoices(filters, additional_query_columns)
- columns, expense_accounts, tax_accounts = get_columns(invoice_list, additional_table_columns)
+ columns, expense_accounts, tax_accounts, unrealized_profit_loss_accounts \
+ = get_columns(invoice_list, additional_table_columns)
if not invoice_list:
msgprint(_("No record found"))
return columns, invoice_list
invoice_expense_map = get_invoice_expense_map(invoice_list)
+ internal_invoice_map = get_internal_invoice_map(invoice_list)
invoice_expense_map, invoice_tax_map = get_invoice_tax_map(invoice_list,
invoice_expense_map, expense_accounts)
invoice_po_pr_map = get_invoice_po_pr_map(invoice_list)
@@ -52,10 +54,17 @@
# map expense values
base_net_total = 0
for expense_acc in expense_accounts:
- expense_amount = flt(invoice_expense_map.get(inv.name, {}).get(expense_acc))
+ if inv.is_internal_supplier and inv.company == inv.represents_company:
+ expense_amount = 0
+ else:
+ expense_amount = flt(invoice_expense_map.get(inv.name, {}).get(expense_acc))
base_net_total += expense_amount
row.append(expense_amount)
+ # Add amount in unrealized account
+ for account in unrealized_profit_loss_accounts:
+ row.append(flt(internal_invoice_map.get((inv.name, account))))
+
# net total
row.append(base_net_total or inv.base_net_total)
@@ -96,7 +105,8 @@
"width": 80
}
]
- expense_accounts = tax_accounts = expense_columns = tax_columns = []
+ expense_accounts = tax_accounts = expense_columns = tax_columns = unrealized_profit_loss_accounts = \
+ unrealized_profit_loss_account_columns = []
if invoice_list:
expense_accounts = frappe.db.sql_list("""select distinct expense_account
@@ -112,17 +122,25 @@
and parent in (%s) order by account_head""" %
', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]))
+ unrealized_profit_loss_accounts = frappe.db.sql_list("""SELECT distinct unrealized_profit_loss_account
+ from `tabPurchase Invoice` where docstatus = 1 and name in (%s)
+ and ifnull(unrealized_profit_loss_account, '') != ''
+ order by unrealized_profit_loss_account""" %
+ ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]))
expense_columns = [(account + ":Currency/currency:120") for account in expense_accounts]
+ unrealized_profit_loss_account_columns = [(account + ":Currency/currency:120") for account in unrealized_profit_loss_accounts]
+
for account in tax_accounts:
if account not in expense_accounts:
tax_columns.append(account + ":Currency/currency:120")
- columns = columns + expense_columns + [_("Net Total") + ":Currency/currency:120"] + tax_columns + \
+ columns = columns + expense_columns + unrealized_profit_loss_account_columns + \
+ [_("Net Total") + ":Currency/currency:120"] + tax_columns + \
[_("Total Tax") + ":Currency/currency:120", _("Grand Total") + ":Currency/currency:120",
_("Rounded Total") + ":Currency/currency:120", _("Outstanding Amount") + ":Currency/currency:120"]
- return columns, expense_accounts, tax_accounts
+ return columns, expense_accounts, tax_accounts, unrealized_profit_loss_accounts
def get_conditions(filters):
conditions = ""
@@ -199,6 +217,19 @@
return invoice_expense_map
+def get_internal_invoice_map(invoice_list):
+ unrealized_amount_details = frappe.db.sql("""SELECT name, unrealized_profit_loss_account,
+ base_net_total as amount from `tabPurchase Invoice` where name in (%s)
+ and is_internal_supplier = 1 and company = represents_company""" %
+ ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1)
+
+ internal_invoice_map = {}
+ for d in unrealized_amount_details:
+ if d.unrealized_profit_loss_account:
+ internal_invoice_map.setdefault((d.name, d.unrealized_profit_loss_account), d.amount)
+
+ return internal_invoice_map
+
def get_invoice_tax_map(invoice_list, invoice_expense_map, expense_accounts):
tax_details = frappe.db.sql("""
select parent, account_head, case add_deduct_tax when "Add" then sum(base_tax_amount_after_discount_amount)
diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py
index b6e61b1..cb2c98b 100644
--- a/erpnext/accounts/report/sales_register/sales_register.py
+++ b/erpnext/accounts/report/sales_register/sales_register.py
@@ -15,13 +15,14 @@
if not filters: filters = frappe._dict({})
invoice_list = get_invoices(filters, additional_query_columns)
- columns, income_accounts, tax_accounts = get_columns(invoice_list, additional_table_columns)
+ columns, income_accounts, tax_accounts, unrealized_profit_loss_accounts = get_columns(invoice_list, additional_table_columns)
if not invoice_list:
msgprint(_("No record found"))
return columns, invoice_list
invoice_income_map = get_invoice_income_map(invoice_list)
+ internal_invoice_map = get_internal_invoice_map(invoice_list)
invoice_income_map, invoice_tax_map = get_invoice_tax_map(invoice_list,
invoice_income_map, income_accounts)
#Cost Center & Warehouse Map
@@ -70,12 +71,22 @@
# map income values
base_net_total = 0
for income_acc in income_accounts:
- income_amount = flt(invoice_income_map.get(inv.name, {}).get(income_acc))
+ if inv.is_internal_customer and inv.company == inv.represents_company:
+ income_amount = 0
+ else:
+ income_amount = flt(invoice_income_map.get(inv.name, {}).get(income_acc))
+
base_net_total += income_amount
row.update({
frappe.scrub(income_acc): income_amount
})
+ # Add amount in unrealized account
+ for account in unrealized_profit_loss_accounts:
+ row.update({
+ frappe.scrub(account): flt(internal_invoice_map.get((inv.name, account)))
+ })
+
# net total
row.update({'net_total': base_net_total or inv.base_net_total})
@@ -230,6 +241,8 @@
tax_accounts = []
income_columns = []
tax_columns = []
+ unrealized_profit_loss_accounts = []
+ unrealized_profit_loss_account_columns = []
if invoice_list:
income_accounts = frappe.db.sql_list("""select distinct income_account
@@ -243,12 +256,18 @@
and parent in (%s) order by account_head""" %
', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]))
+ unrealized_profit_loss_accounts = frappe.db.sql_list("""SELECT distinct unrealized_profit_loss_account
+ from `tabSales Invoice` where docstatus = 1 and name in (%s)
+ and ifnull(unrealized_profit_loss_account, '') != ''
+ order by unrealized_profit_loss_account""" %
+ ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]))
+
for account in income_accounts:
income_columns.append({
"label": account,
"fieldname": frappe.scrub(account),
"fieldtype": "Currency",
- "options": 'currency',
+ "options": "currency",
"width": 120
})
@@ -258,15 +277,24 @@
"label": account,
"fieldname": frappe.scrub(account),
"fieldtype": "Currency",
- "options": 'currency',
+ "options": "currency",
"width": 120
})
+ for account in unrealized_profit_loss_accounts:
+ unrealized_profit_loss_account_columns.append({
+ "label": account,
+ "fieldname": frappe.scrub(account),
+ "fieldtype": "Currency",
+ "options": "currency",
+ "width": 120
+ })
+
net_total_column = [{
"label": _("Net Total"),
"fieldname": "net_total",
"fieldtype": "Currency",
- "options": 'currency',
+ "options": "currency",
"width": 120
}]
@@ -301,9 +329,10 @@
}
]
- columns = columns + income_columns + net_total_column + tax_columns + total_columns
+ columns = columns + income_columns + unrealized_profit_loss_account_columns + \
+ net_total_column + tax_columns + total_columns
- return columns, income_accounts, tax_accounts
+ return columns, income_accounts, tax_accounts, unrealized_profit_loss_accounts
def get_conditions(filters):
conditions = ""
@@ -368,7 +397,8 @@
return frappe.db.sql("""
select name, posting_date, debit_to, project, customer,
customer_name, owner, remarks, territory, tax_id, customer_group,
- base_net_total, base_grand_total, base_rounded_total, outstanding_amount {0}
+ base_net_total, base_grand_total, base_rounded_total, outstanding_amount,
+ is_internal_customer, represents_company, company {0}
from `tabSales Invoice`
where docstatus = 1 %s order by posting_date desc, name desc""".format(additional_query_columns or '') %
conditions, filters, as_dict=1)
@@ -385,6 +415,19 @@
return invoice_income_map
+def get_internal_invoice_map(invoice_list):
+ unrealized_amount_details = frappe.db.sql("""SELECT name, unrealized_profit_loss_account,
+ base_net_total as amount from `tabSales Invoice` where name in (%s)
+ and is_internal_customer = 1 and company = represents_company""" %
+ ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1)
+
+ internal_invoice_map = {}
+ for d in unrealized_amount_details:
+ if d.unrealized_profit_loss_account:
+ internal_invoice_map.setdefault((d.name, d.unrealized_profit_loss_account), d.amount)
+
+ return internal_invoice_map
+
def get_invoice_tax_map(invoice_list, invoice_income_map, income_accounts):
tax_details = frappe.db.sql("""select parent, account_head,
sum(base_tax_amount_after_discount_amount) as tax_amount
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js
index 14534ef..dd0f065 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.js
@@ -164,16 +164,16 @@
if (doc.docstatus === 1 && !doc.inter_company_order_reference) {
let me = this;
- frappe.model.with_doc("Supplier", me.frm.doc.supplier, () => {
- let supplier = frappe.model.get_doc("Supplier", me.frm.doc.supplier);
- let internal = supplier.is_internal_supplier;
- let disabled = supplier.disabled;
- if (internal === 1 && disabled === 0) {
- me.frm.add_custom_button("Inter Company Order", function() {
- me.make_inter_company_order(me.frm);
- }, __('Create'));
- }
- });
+ let internal = me.frm.doc.is_internal_supplier;
+ if (internal) {
+ let button_label = (me.frm.doc.company === me.frm.doc.represents_company) ? "Internal Sales Order" :
+ "Inter Company Sales Order";
+
+ me.frm.add_custom_button(button_label, function() {
+ me.make_inter_company_order(me.frm);
+ }, __('Create'));
+ }
+
}
}
@@ -381,7 +381,7 @@
material_request_type: "Purchase",
docstatus: 1,
status: ["!=", "Stopped"],
- per_ordered: ["<", 99.99],
+ per_ordered: ["<", 100],
company: me.frm.doc.company
}
})
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json
index 75da71c..ee2beea 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.json
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.json
@@ -134,6 +134,8 @@
"ref_sq",
"column_break_74",
"party_account_currency",
+ "is_internal_supplier",
+ "represents_company",
"inter_company_order_reference"
],
"fields": [
@@ -1101,13 +1103,28 @@
{
"fieldname": "items_col_break",
"fieldtype": "Column Break"
+ },
+ {
+ "default": "0",
+ "fetch_from": "supplier.is_internal_supplier",
+ "fieldname": "is_internal_supplier",
+ "fieldtype": "Check",
+ "label": "Is Internal Supplier"
+ },
+ {
+ "fetch_from": "supplier.represents_company",
+ "fieldname": "represents_company",
+ "fieldtype": "Link",
+ "label": "Represents Company",
+ "options": "Company",
+ "read_only": 1
}
],
"icon": "fa fa-file-text",
"idx": 105,
"is_submittable": 1,
"links": [],
- "modified": "2020-12-03 16:46:44.229351",
+ "modified": "2021-01-20 22:07:23.487138",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order",
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
index e537771..b76c378 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
@@ -224,7 +224,7 @@
material_request_type: "Purchase",
docstatus: 1,
status: ["!=", "Stopped"],
- per_ordered: ["<", 99.99],
+ per_ordered: ["<", 100],
company: me.frm.doc.company
}
})
@@ -280,7 +280,7 @@
material_request_type: "Purchase",
docstatus: 1,
status: ["!=", "Stopped"],
- per_ordered: ["<", 99.99]
+ per_ordered: ["<", 100]
}
});
dialog.hide();
diff --git a/erpnext/buying/doctype/supplier/supplier.py b/erpnext/buying/doctype/supplier/supplier.py
index 0ee9d18..edeb135 100644
--- a/erpnext/buying/doctype/supplier/supplier.py
+++ b/erpnext/buying/doctype/supplier/supplier.py
@@ -52,7 +52,10 @@
self.validate_internal_supplier()
def validate_internal_supplier(self):
- if self.is_internal_supplier and frappe.db.get_value("Supplier", {"represents_company": self.represents_company}, "name"):
+ internal_supplier = frappe.db.get_value("Supplier",
+ {"is_internal_supplier": 1, "represents_company": self.represents_company, "name": ("!=", self.name)}, "name")
+
+ if internal_supplier:
frappe.throw(_("Internal Supplier for company {0} already exists").format(
frappe.bold(self.represents_company)))
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js
index a3b2085..a0187b0 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js
@@ -44,7 +44,7 @@
material_request_type: "Purchase",
docstatus: 1,
status: ["!=", "Stopped"],
- per_ordered: ["<", 99.99],
+ per_ordered: ["<", 100],
company: me.frm.doc.company
}
})
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 7ac4cfe..9d9d1b3 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -75,6 +75,9 @@
self.ensure_supplier_is_not_blocked()
self.validate_date_with_fiscal_year()
+ self.validate_inter_company_reference()
+
+ self.set_incoming_rate()
if self.meta.get_field("currency"):
self.calculate_taxes_and_totals()
@@ -118,6 +121,12 @@
def before_cancel(self):
validate_einvoice_fields(self)
+
+ def on_trash(self):
+ # delete sl and gl entries on deletion of transaction
+ if frappe.db.get_single_value('Accounts Settings', 'delete_linked_ledger_entries'):
+ frappe.db.sql("delete from `tabGL Entry` where voucher_type=%s and voucher_no=%s", (self.doctype, self.name))
+ frappe.db.sql("delete from `tabStock Ledger Entry` where voucher_type=%s and voucher_no=%s", (self.doctype, self.name))
def validate_deferred_start_and_end_date(self):
for d in self.items:
@@ -206,6 +215,17 @@
validate_fiscal_year(self.get(date_field), self.fiscal_year, self.company,
self.meta.get_label(date_field), self)
+ def validate_inter_company_reference(self):
+ if self.doctype not in ('Purchase Invoice', 'Purchase Receipt', 'Purchase Order'):
+ return
+
+ if self.is_internal_transfer():
+ if not (self.get('inter_company_reference') or self.get('inter_company_invoice_reference')
+ or self.get('inter_company_order_reference')):
+ msg = _("Internal Sale or Delivery Reference missing. ")
+ msg += _("Please create purchase from internal sale or delivery document itself")
+ frappe.throw(msg, title=_("Internal Sales Reference Missing"))
+
def validate_due_date(self):
if self.get('is_pos'): return
@@ -964,9 +984,9 @@
It will an internal transfer if its an internal customer and representation
company is same as billing company
"""
- if self.doctype == 'Sales Invoice':
+ if self.doctype in ('Sales Invoice', 'Delivery Note', 'Sales Order'):
internal_party_field = 'is_internal_customer'
- else:
+ elif self.doctype in ('Purchase Invoice', 'Purchase Receipt', 'Purchase Order'):
internal_party_field = 'is_internal_supplier'
if self.get(internal_party_field) and (self.represents_company == self.company):
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index 4dee375..ab1f027 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -44,7 +44,6 @@
self.validate_items()
self.set_qty_as_per_stock_uom()
self.validate_stock_or_nonstock_items()
- self.update_tax_category_for_internal_transfer()
self.validate_warehouse()
self.validate_from_warehouse()
self.set_supplier_address()
@@ -100,11 +99,6 @@
msg = _('Tax Category has been changed to "Total" because all the Items are non-stock items')
self.update_tax_category(msg)
- def update_tax_category_for_internal_transfer(self):
- if self.doctype == 'Purchase Invoice' and self.is_internal_transfer():
- msg = _('Tax Category has been changed to "Total" as its an internal purchase.')
- self.update_tax_category(msg)
-
def update_tax_category(self, msg):
tax_for_valuation = [d for d in self.get("taxes")
if d.category in ["Valuation", "Valuation and Total"]]
@@ -224,6 +218,48 @@
else:
item.valuation_rate = 0.0
+ def set_incoming_rate(self):
+ if self.doctype not in ("Purchase Receipt", "Purchase Invoice", "Purchase Order"):
+ return
+
+ ref_doctype_map = {
+ "Purchase Order": "Sales Order Item",
+ "Purchase Receipt": "Delivery Note Item",
+ "Purchase Invoice": "Sales Invoice Item",
+ }
+
+ ref_doctype = ref_doctype_map.get(self.doctype)
+ items = self.get("items")
+ for d in items:
+ if not cint(self.get("is_return")):
+ # Get outgoing rate based on original item cost based on valuation method
+
+ if not d.get(frappe.scrub(ref_doctype)):
+ outgoing_rate = get_incoming_rate({
+ "item_code": d.item_code,
+ "warehouse": d.get('from_warehouse'),
+ "posting_date": self.get('posting_date') or self.get('transation_date'),
+ "posting_time": self.get('posting_time'),
+ "qty": -1 * flt(d.get('stock_qty')),
+ "serial_no": d.get('serial_no'),
+ "company": self.company,
+ "voucher_type": self.doctype,
+ "voucher_no": self.name,
+ "allow_zero_valuation": d.get("allow_zero_valuation")
+ }, raise_error_if_no_rate=False)
+
+ rate = flt(outgoing_rate * d.conversion_factor, d.precision('rate'))
+ else:
+ rate = frappe.db.get_value(ref_doctype, d.get(frappe.scrub(ref_doctype)), 'rate')
+
+ if self.is_internal_transfer():
+ if rate != d.rate:
+ d.rate = rate
+ d.discount_percentage = 0
+ d.discount_amount = 0
+ frappe.msgprint(_("Row {0}: Item rate has been updated as per valuation rate since its an internal stock transfer")
+ .format(d.idx), alert=1)
+
def get_supplied_items_cost(self, item_row_id, reset_outgoing_rate=True):
supplied_items_cost = 0.0
for d in self.get("supplied_items"):
@@ -243,7 +279,7 @@
d.amount = flt(flt(d.consumed_qty) * flt(d.rate), d.precision("amount"))
supplied_items_cost += flt(d.amount)
-
+
return supplied_items_cost
def validate_for_subcontracting(self):
@@ -559,6 +595,8 @@
from_warehouse_sle = self.get_sl_entries(d, {
"actual_qty": -1 * pr_qty,
"warehouse": d.from_warehouse,
+ "outgoing_rate": d.rate,
+ "recalculate_rate": 1,
"dependant_sle_voucher_detail_no": d.name
})
diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py
index 812021f..e085048 100644
--- a/erpnext/controllers/selling_controller.py
+++ b/erpnext/controllers/selling_controller.py
@@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe
-from frappe.utils import cint, flt, cstr, comma_or, get_link_to_form
+from frappe.utils import cint, flt, cstr, get_link_to_form, nowtime
from frappe import _, throw
from erpnext.stock.get_item_details import get_bin_details
from erpnext.stock.utils import get_incoming_rate
@@ -49,7 +49,6 @@
self.set_customer_address()
self.validate_for_duplicate_items()
self.validate_target_warehouse()
- self.set_incoming_rate()
def set_missing_values(self, for_validate=False):
@@ -191,7 +190,7 @@
for it in self.get("items"):
if not it.item_code:
continue
-
+
last_purchase_rate, is_stock_item = frappe.get_cached_value("Item", it.item_code, ["last_purchase_rate", "is_stock_item"])
last_purchase_rate_in_sales_uom = last_purchase_rate * (it.conversion_factor or 1)
if flt(it.base_net_rate) < flt(last_purchase_rate_in_sales_uom):
@@ -312,7 +311,7 @@
sales_order.update_reserved_qty(so_item_rows)
def set_incoming_rate(self):
- if self.doctype not in ("Delivery Note", "Sales Invoice"):
+ if self.doctype not in ("Delivery Note", "Sales Invoice", "Sales Order"):
return
items = self.get("items") + (self.get("packed_items") or [])
@@ -322,15 +321,26 @@
d.incoming_rate = get_incoming_rate({
"item_code": d.item_code,
"warehouse": d.warehouse,
- "posting_date": self.posting_date,
- "posting_time": self.posting_time,
- "qty": -1*flt(d.qty),
- "serial_no": d.serial_no,
+ "posting_date": self.get('posting_date') or self.get('transaction_date'),
+ "posting_time": self.get('posting_time') or nowtime(),
+ "qty": -1 * flt(d.get('stock_qty') or d.get('actual_qty')),
+ "serial_no": d.get('serial_no'),
"company": self.company,
"voucher_type": self.doctype,
"voucher_no": self.name,
"allow_zero_valuation": d.get("allow_zero_valuation")
}, raise_error_if_no_rate=False)
+
+ # For internal transfers use incoming rate as the valuation rate
+ if self.is_internal_transfer():
+ rate = flt(d.incoming_rate * d.conversion_factor, d.precision('rate'))
+ if d.rate != rate:
+ d.rate = rate
+ d.discount_percentage = 0
+ d.discount_amount = 0
+ frappe.msgprint(_("Row {0}: Item rate has been updated as per valuation rate since its an internal stock transfer")
+ .format(d.idx), alert=1)
+
elif self.get("return_against"):
# Get incoming rate of return entry from reference document
# based on original item cost as per valuation method
@@ -391,7 +401,7 @@
})
if item_row.warehouse:
sle.dependant_sle_voucher_detail_no = item_row.name
-
+
return sle
def set_po_nos(self, for_validate=False):
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index e0fcf47..4b5e347 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -24,6 +24,7 @@
self.validate_inspection()
self.validate_serialized_batch()
self.validate_customer_provided_item()
+ self.validate_internal_transfer()
self.validate_putaway_capacity()
def make_gl_entries(self, gl_entries=None, from_repost=False):
@@ -74,6 +75,7 @@
warehouse_with_no_account = []
precision = frappe.get_precision("GL Entry", "debit_in_account_currency")
for item_row in voucher_details:
+
sle_list = sle_map.get(item_row.name)
if sle_list:
for sle in sle_list:
@@ -218,7 +220,7 @@
""", (self.doctype, self.name), as_dict=True)
for sle in stock_ledger_entries:
- stock_ledger.setdefault(sle.voucher_detail_no, []).append(sle)
+ stock_ledger.setdefault(sle.voucher_detail_no, []).append(sle)
return stock_ledger
def make_batches(self, warehouse_field):
@@ -393,6 +395,32 @@
if frappe.db.get_value('Item', d.item_code, 'is_customer_provided_item'):
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()
+
+ def validate_in_transit_warehouses(self):
+ if (self.doctype == 'Sales Invoice' and self.get('update_stock')) or self.doctype == 'Delivery Note':
+ for item in self.get('items'):
+ if not item.target_warehouse:
+ frappe.throw(_("Row {0}: Target Warehouse is mandatory for internal transfers").format(item.idx))
+
+ if (self.doctype == 'Purchase Invoice' and self.get('update_stock')) or self.doctype == 'Purchase Receipt':
+ for item in self.get('items'):
+ if not item.from_warehouse:
+ frappe.throw(_("Row {0}: From Warehouse is mandatory for internal transfers").format(item.idx))
+
+ 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_putaway_capacity(self):
# if over receipt is attempted while 'apply putaway rule' is disabled
# and if rule was applied on the transaction, validate it.
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 14377e1..1c20555 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -416,9 +416,6 @@
'Italy': {
'erpnext.controllers.taxes_and_totals.update_itemised_tax_data': 'erpnext.regional.italy.utils.update_itemised_tax_data',
'erpnext.controllers.accounts_controller.validate_regional': 'erpnext.regional.italy.utils.sales_invoice_validate',
- },
- 'Germany': {
- 'erpnext.controllers.accounts_controller.validate_regional': 'erpnext.regional.germany.accounts_controller.validate_regional',
}
}
user_privacy_documents = [
diff --git a/erpnext/hr/doctype/shift_assignment/shift_assignment.py b/erpnext/hr/doctype/shift_assignment/shift_assignment.py
index 2c385e8..ab65260 100644
--- a/erpnext/hr/doctype/shift_assignment/shift_assignment.py
+++ b/erpnext/hr/doctype/shift_assignment/shift_assignment.py
@@ -88,7 +88,7 @@
def add_assignments(events, start, end, conditions=None):
query = """select name, start_date, end_date, employee_name,
- employee, docstatus
+ employee, docstatus, shift_type
from `tabShift Assignment` where
start_date >= %(start_date)s
or end_date <= %(end_date)s
@@ -97,18 +97,40 @@
if conditions:
query += conditions
- for d in frappe.db.sql(query, {"start_date":start, "end_date":end}, as_dict=True):
- e = {
- "name": d.name,
- "doctype": "Shift Assignment",
- "start_date": d.start_date,
- "end_date": d.end_date if d.end_date else nowdate(),
- "title": cstr(d.employee_name) + ": "+ \
- cstr(d.shift_type),
- "docstatus": d.docstatus
- }
- if e not in events:
- events.append(e)
+ records = frappe.db.sql(query, {"start_date":start, "end_date":end}, as_dict=True)
+ shift_timing_map = get_shift_type_timing([d.shift_type for d in records])
+
+ for d in records:
+ daily_event_start = d.start_date
+ daily_event_end = d.end_date if d.end_date else getdate()
+ delta = timedelta(days=1)
+ while daily_event_start <= daily_event_end:
+ start_timing = frappe.utils.get_datetime(daily_event_start)+ shift_timing_map[d.shift_type]['start_time']
+ end_timing = frappe.utils.get_datetime(daily_event_start)+ shift_timing_map[d.shift_type]['end_time']
+ daily_event_start += delta
+ e = {
+ "name": d.name,
+ "doctype": "Shift Assignment",
+ "start_date": start_timing,
+ "end_date": end_timing,
+ "title": cstr(d.employee_name) + ": "+ \
+ cstr(d.shift_type),
+ "docstatus": d.docstatus,
+ "allDay": 0
+ }
+ if e not in events:
+ events.append(e)
+
+ return events
+
+def get_shift_type_timing(shift_types):
+ shift_timing_map = {}
+ data = frappe.get_all("Shift Type", filters = {"name": ("IN", shift_types)}, fields = ['name', 'start_time', 'end_time'])
+
+ for d in data:
+ shift_timing_map[d.name] = d
+
+ return shift_timing_map
def get_employee_shift(employee, for_date=nowdate(), consider_default_shift=False, next_shift_direction=None):
diff --git a/erpnext/hr/doctype/shift_assignment/shift_assignment_calendar.js b/erpnext/hr/doctype/shift_assignment/shift_assignment_calendar.js
index 17a986d..bb692e1 100644
--- a/erpnext/hr/doctype/shift_assignment/shift_assignment_calendar.js
+++ b/erpnext/hr/doctype/shift_assignment/shift_assignment_calendar.js
@@ -6,14 +6,8 @@
"start": "start_date",
"end": "end_date",
"id": "name",
- "docstatus": 1
- },
- options: {
- header: {
- left: 'prev,next today',
- center: 'title',
- right: 'month'
- }
+ "docstatus": 1,
+ "allDay": "allDay",
},
get_events_method: "erpnext.hr.doctype.shift_assignment.shift_assignment.get_events"
}
\ No newline at end of file
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 1d1f18b..9627600 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -105,10 +105,18 @@
frappe.ui.form.on(this.frm.doctype + " Item", {
items_add: function(frm, cdt, cdn) {
var item = frappe.get_doc(cdt, cdn);
- if(!item.warehouse && frm.doc.set_warehouse) {
+ if (!item.warehouse && frm.doc.set_warehouse) {
item.warehouse = frm.doc.set_warehouse;
}
+ if (!item.target_warehouse && frm.doc.set_target_warehouse) {
+ item.target_warehouse = frm.doc.set_target_warehouse;
+ }
+
+ if (!item.from_warehouse && frm.doc.set_from_warehouse) {
+ item.from_warehouse = frm.doc.set_from_warehouse;
+ }
+
erpnext.accounts.dimensions.copy_dimension_from_first_row(frm, cdt, cdn, 'items');
}
});
@@ -227,6 +235,8 @@
}
};
+ this.frm.trigger('set_default_internal_warehouse');
+
return frappe.run_serially([
() => set_value('currency', currency),
() => set_value('price_list_currency', currency),
@@ -658,7 +668,7 @@
args: item_args
},
callback: function(r) {
- frappe.model.set_value(item.doctype, item.name, 'rate', r.message);
+ frappe.model.set_value(item.doctype, item.name, 'rate', r.message * item.conversion_factor);
}
});
},
@@ -724,6 +734,31 @@
this.calculate_taxes_and_totals(false);
},
+ update_stock: function() {
+ this.frm.trigger('set_default_internal_warehouse');
+ },
+
+ set_default_internal_warehouse: function() {
+ let me = this;
+ if ((this.frm.doc.doctype === 'Sales Invoice' && me.frm.doc.update_stock)
+ || this.frm.doc.doctype == 'Delivery Note') {
+ if (this.frm.doc.is_internal_customer && this.frm.doc.company === this.frm.doc.represents_company) {
+ frappe.db.get_value('Company', this.frm.doc.company, 'default_in_transit_warehouse', function(value) {
+ me.frm.set_value('set_target_warehouse', value.default_in_transit_warehouse);
+ });
+ }
+ }
+
+ if ((this.frm.doc.doctype === 'Purchase Invoice' && me.frm.doc.update_stock)
+ || this.frm.doc.doctype == 'Purchase Receipt') {
+ if (this.frm.doc.is_internal_supplier && this.frm.doc.company === this.frm.doc.represents_company) {
+ frappe.db.get_value('Company', this.frm.doc.company, 'default_in_transit_warehouse', function(value) {
+ me.frm.set_value('set_from_warehouse', value.default_in_transit_warehouse);
+ });
+ }
+ }
+ },
+
company: function() {
var me = this;
var set_pricing = function() {
@@ -810,7 +845,7 @@
in_list(['Purchase Order', 'Purchase Receipt', 'Purchase Invoice'], this.frm.doctype)) {
erpnext.utils.get_shipping_address(this.frm, function(){
set_party_account(set_pricing);
- })
+ });
// Get default company billing address in Purchase Invoice, Order and Receipt
frappe.call({
@@ -1977,6 +2012,14 @@
this.autofill_warehouse(this.frm.doc.items, "warehouse", this.frm.doc.set_warehouse);
},
+ set_target_warehouse: function() {
+ this.autofill_warehouse(this.frm.doc.items, "target_warehouse", this.frm.doc.set_target_warehouse);
+ },
+
+ set_from_warehouse: function() {
+ this.autofill_warehouse(this.frm.doc.items, "from_warehouse", this.frm.doc.set_from_warehouse);
+ },
+
autofill_warehouse : function (child_table, warehouse_field, warehouse) {
if (warehouse && child_table && child_table.length) {
let doctype = child_table[0].doctype;
diff --git a/erpnext/public/js/utils/party.js b/erpnext/public/js/utils/party.js
index 770704e..808dd5a 100644
--- a/erpnext/public/js/utils/party.js
+++ b/erpnext/public/js/utils/party.js
@@ -276,6 +276,12 @@
erpnext.utils.get_shipping_address = function(frm, callback){
if (frm.doc.company) {
+ if (!(frm.doc.inter_com_order_reference || frm.doc.internal_invoice_reference ||
+ frm.doc.internal_order_reference)) {
+ if (callback) {
+ return callback();
+ }
+ }
frappe.call({
method: "erpnext.accounts.custom.address.get_shipping_address",
args: {
diff --git a/erpnext/regional/germany/accounts_controller.py b/erpnext/regional/germany/accounts_controller.py
deleted file mode 100644
index 7f76493..0000000
--- a/erpnext/regional/germany/accounts_controller.py
+++ /dev/null
@@ -1,53 +0,0 @@
-import frappe
-from frappe import _
-from frappe import msgprint
-
-
-REQUIRED_FIELDS = {
- "Sales Invoice": [
- {
- "field_name": "company_address",
- "regulation": "§ 14 Abs. 4 Nr. 1 UStG"
- },
- {
- "field_name": "company_tax_id",
- "regulation": "§ 14 Abs. 4 Nr. 2 UStG"
- },
- {
- "field_name": "taxes",
- "regulation": "§ 14 Abs. 4 Nr. 8 UStG"
- },
- {
- "field_name": "customer_address",
- "regulation": "§ 14 Abs. 4 Nr. 1 UStG",
- "condition": "base_grand_total > 250"
- }
- ]
-}
-
-
-def validate_regional(doc):
- """Check if required fields for this document are present."""
- required_fields = REQUIRED_FIELDS.get(doc.doctype)
- if not required_fields:
- return
-
- meta = frappe.get_meta(doc.doctype)
- field_map = {field.fieldname: field.label for field in meta.fields}
-
- for field in required_fields:
- condition = field.get("condition")
- if condition and not frappe.safe_eval(condition, doc.as_dict()):
- continue
-
- field_name = field.get("field_name")
- regulation = field.get("regulation")
- if field_name and not doc.get(field_name):
- missing(field_map.get(field_name), regulation)
-
-
-def missing(field_label, regulation):
- """Notify the user that a required field is missing."""
- translated_msg = _('Remember to set {field_label}. It is required by {regulation}.', context='Specific for Germany. Example: Remember to set Company Tax ID. It is required by § 14 Abs. 4 Nr. 2 UStG.') # noqa: E501
- formatted_msg = translated_msg.format(field_label=frappe.bold(_(field_label)), regulation=regulation)
- msgprint(formatted_msg)
diff --git a/erpnext/regional/germany/test_accounts_controller.py b/erpnext/regional/germany/test_accounts_controller.py
deleted file mode 100644
index 8bd378c..0000000
--- a/erpnext/regional/germany/test_accounts_controller.py
+++ /dev/null
@@ -1,12 +0,0 @@
-import frappe
-import unittest
-from erpnext.regional.germany.accounts_controller import validate_regional
-
-
-class TestAccountsController(unittest.TestCase):
-
- def setUp(self):
- self.sales_invoice = frappe.get_last_doc('Sales Invoice')
-
- def test_validate_regional(self):
- validate_regional(self.sales_invoice)
diff --git a/erpnext/regional/india/taxes.js b/erpnext/regional/india/taxes.js
index 87baece..f09d3d0 100644
--- a/erpnext/regional/india/taxes.js
+++ b/erpnext/regional/india/taxes.js
@@ -40,14 +40,12 @@
callback: function(r) {
if(r.message) {
frm.set_value('taxes_and_charges', r.message.taxes_and_charges);
+ frm.set_value('taxes', r.message.taxes);
frm.set_value('place_of_supply', r.message.place_of_supply);
- } else if (frm.doc.is_internal_supplier || frm.doc.is_internal_customer) {
- frm.set_value('taxes_and_charges', '');
- frm.set_value('taxes', []);
}
}
});
}
});
-};
+}
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 0d82638..e89885f 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -171,7 +171,7 @@
if is_internal_transfer(party_details, doctype):
party_details.taxes_and_charges = ''
- party_details.taxes = ''
+ party_details.taxes = []
return party_details
if doctype in ("Sales Invoice", "Delivery Note", "Sales Order"):
diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py
index ad3de5f..96dc3f7 100644
--- a/erpnext/regional/report/gstr_1/gstr_1.py
+++ b/erpnext/regional/report/gstr_1/gstr_1.py
@@ -255,15 +255,16 @@
for item_code, tax_amounts in item_wise_tax_detail.items():
tax_rate = tax_amounts[0]
- if cgst_or_sgst:
- tax_rate *= 2
- if parent not in self.cgst_sgst_invoices:
- self.cgst_sgst_invoices.append(parent)
+ if tax_rate:
+ if cgst_or_sgst:
+ tax_rate *= 2
+ if parent not in self.cgst_sgst_invoices:
+ self.cgst_sgst_invoices.append(parent)
- rate_based_dict = self.items_based_on_tax_rate\
- .setdefault(parent, {}).setdefault(tax_rate, [])
- if item_code not in rate_based_dict:
- rate_based_dict.append(item_code)
+ rate_based_dict = self.items_based_on_tax_rate\
+ .setdefault(parent, {}).setdefault(tax_rate, [])
+ if item_code not in rate_based_dict:
+ rate_based_dict.append(item_code)
except ValueError:
continue
if unidentified_gst_accounts:
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 29214ee..bf8b7fc 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -84,7 +84,10 @@
frappe.throw(_("{0} is not a company bank account").format(frappe.bold(self.default_bank_account)))
def validate_internal_customer(self):
- if self.is_internal_customer and frappe.db.get_value('Customer', {"represents_company": self.represents_company}, "name"):
+ internal_customer = frappe.db.get_value("Customer",
+ {"is_internal_customer": 1, "represents_company": self.represents_company, "name": ("!=", self.name)}, "name")
+
+ if internal_customer:
frappe.throw(_("Internal Customer for company {0} already exists").format(
frappe.bold(self.represents_company)))
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index d4fb07c..78f9df9 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -171,8 +171,10 @@
this.frm.add_custom_button(__('Request for Raw Materials'), () => this.make_raw_material_request(), __('Create'));
}
- // make purchase order
+ // Make Purchase Order
+ if (!this.frm.doc.is_internal_customer) {
this.frm.add_custom_button(__('Purchase Order'), () => this.make_purchase_order(), __('Create'));
+ }
// maintenance
if(flt(doc.per_delivered, 2) < 100 && (order_is_maintenance || order_is_a_custom_sale)) {
@@ -193,16 +195,15 @@
if (doc.docstatus === 1 && !doc.inter_company_order_reference) {
let me = this;
- frappe.model.with_doc("Customer", me.frm.doc.customer, () => {
- let customer = frappe.model.get_doc("Customer", me.frm.doc.customer);
- let internal = customer.is_internal_customer;
- let disabled = customer.disabled;
- if (internal === 1 && disabled === 0) {
- me.frm.add_custom_button("Inter Company Order", function() {
- me.make_inter_company_order();
- }, __('Create'));
- }
- });
+ let internal = me.frm.doc.is_internal_customer;
+ if (internal) {
+ let button_label = (me.frm.doc.company === me.frm.doc.represents_company) ? "Internal Purchase Order" :
+ "Inter Company Purchase Order";
+
+ me.frm.add_custom_button(button_label, function() {
+ me.make_inter_company_order();
+ }, __('Create'));
+ }
}
}
// payment request
diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json
index 3d64ac3..0a5c665 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.json
+++ b/erpnext/selling/doctype/sales_order/sales_order.json
@@ -107,6 +107,8 @@
"tc_name",
"terms",
"more_info",
+ "is_internal_customer",
+ "represents_company",
"inter_company_order_reference",
"project",
"party_account_currency",
@@ -1103,7 +1105,8 @@
"hide_days": 1,
"hide_seconds": 1,
"label": "Inter Company Order Reference",
- "options": "Purchase Order"
+ "options": "Purchase Order",
+ "read_only": 1
},
{
"description": "Track this Sales Order against any Project",
@@ -1455,13 +1458,29 @@
"hide_seconds": 1,
"label": "Skip Delivery Note",
"print_hide": 1
+ },
+ {
+ "default": "0",
+ "fetch_from": "customer.is_internal_customer",
+ "fieldname": "is_internal_customer",
+ "fieldtype": "Check",
+ "label": "Is Internal Customer",
+ "read_only": 1
+ },
+ {
+ "fetch_from": "customer.represents_company",
+ "fieldname": "represents_company",
+ "fieldtype": "Link",
+ "label": "Represents Company",
+ "options": "Company",
+ "read_only": 1
}
],
"icon": "fa fa-file-text",
"idx": 105,
"is_submittable": 1,
"links": [],
- "modified": "2020-10-30 13:59:18.628077",
+ "modified": "2021-01-20 23:40:39.929296",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order",
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.js b/erpnext/stock/doctype/delivery_note/delivery_note.js
index ee18042..334bdea 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.js
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.js
@@ -95,13 +95,19 @@
frm.page.set_inner_btn_group_as_primary(__('Create'));
}
- if (frm.doc.docstatus === 1 && frm.doc.is_internal_customer && !frm.doc.inter_company_reference) {
- frm.add_custom_button(__('Purchase Receipt'), function() {
- frappe.model.open_mapped_doc({
- method: 'erpnext.stock.doctype.delivery_note.delivery_note.make_inter_company_purchase_receipt',
- frm: frm,
- })
- }, __('Create'));
+ if (frm.doc.docstatus == 1 && !frm.doc.inter_company_reference) {
+ let internal = me.frm.doc.is_internal_customer;
+ if (internal) {
+ let button_label = (me.frm.doc.company === me.frm.doc.represents_company) ? "Internal Purchase Receipt" :
+ "Inter Company Purchase Receipt";
+
+ me.frm.add_custom_button(button_label, function() {
+ frappe.model.open_mapped_doc({
+ method: 'erpnext.stock.doctype.delivery_note.delivery_note.make_inter_company_purchase_receipt',
+ frm: frm,
+ });
+ }, __('Create'));
+ }
}
}
});
@@ -297,15 +303,6 @@
}
})
},
-
- to_warehouse: function() {
- let packed_items_table = this.frm.doc["packed_items"];
- this.autofill_warehouse(this.frm.doc["items"], "target_warehouse", this.frm.doc.to_warehouse);
- if (packed_items_table && packed_items_table.length) {
- this.autofill_warehouse(packed_items_table, "target_warehouse", this.frm.doc.to_warehouse);
- }
- }
-
});
$.extend(cur_frm.cscript, new erpnext.stock.DeliveryNoteController({frm: cur_frm}));
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.json b/erpnext/stock/doctype/delivery_note/delivery_note.json
index c9f8d08..f595aad 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.json
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.json
@@ -53,7 +53,7 @@
"sec_warehouse",
"set_warehouse",
"col_break_warehouse",
- "to_warehouse",
+ "set_target_warehouse",
"items_section",
"scan_barcode",
"items",
@@ -117,6 +117,7 @@
"source",
"column_break5",
"is_internal_customer",
+ "represents_company",
"inter_company_reference",
"per_billed",
"customer_group",
@@ -503,18 +504,6 @@
"fieldtype": "Column Break"
},
{
- "description": "Required only for sample item.",
- "fieldname": "to_warehouse",
- "fieldtype": "Link",
- "in_standard_filter": 1,
- "label": "To Warehouse",
- "no_copy": 1,
- "oldfieldname": "to_warehouse",
- "oldfieldtype": "Link",
- "options": "Warehouse",
- "print_hide": 1
- },
- {
"fieldname": "items_section",
"fieldtype": "Section Break",
"oldfieldtype": "Section Break",
@@ -1261,13 +1250,34 @@
"no_copy": 1,
"print_hide": 1,
"read_only": 1
+ },
+ {
+ "depends_on": "eval: doc.is_internal_customer",
+ "fieldname": "set_target_warehouse",
+ "fieldtype": "Link",
+ "in_standard_filter": 1,
+ "label": "Set Target Warehouse",
+ "no_copy": 1,
+ "oldfieldname": "to_warehouse",
+ "oldfieldtype": "Link",
+ "options": "Warehouse",
+ "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",
"idx": 146,
"is_submittable": 1,
"links": [],
- "modified": "2020-11-30 12:54:45.407289",
+ "modified": "2020-12-26 17:07:59.194403",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note",
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index a30cadf..fa5a7fb 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -664,7 +664,8 @@
return make_inter_company_transaction("Delivery Note", source_name, target_doc)
def make_inter_company_transaction(doctype, source_name, target_doc=None):
- from erpnext.accounts.doctype.sales_invoice.sales_invoice import validate_inter_company_transaction, get_inter_company_details
+ from erpnext.accounts.doctype.sales_invoice.sales_invoice import (validate_inter_company_transaction,
+ get_inter_company_details, update_address, update_taxes, set_purchase_references)
if doctype == 'Delivery Note':
source_doc = frappe.get_doc(doctype, source_name)
@@ -682,6 +683,7 @@
def set_missing_values(source, target):
target.run_method("set_missing_values")
+ set_purchase_references(target)
if target.doctype == 'Purchase Receipt':
master_doctype = 'Purchase Taxes and Charges Template'
@@ -697,21 +699,35 @@
if target_doc.doctype == 'Purchase Receipt':
target_doc.company = details.get("company")
target_doc.supplier = details.get("party")
- target_doc.supplier_address = source_doc.company_address
- target_doc.shipping_address = source_doc.shipping_address_name or source_doc.customer_address
target_doc.buying_price_list = source_doc.selling_price_list
target_doc.is_internal_supplier = 1
target_doc.inter_company_reference = source_doc.name
+
+ # Invert the address on target doc creation
+ update_address(target_doc, 'supplier_address', 'address_display', source_doc.company_address)
+ update_address(target_doc, 'shipping_address', 'shipping_address_display', source_doc.customer_address)
+
+ update_taxes(target_doc, party=target_doc.supplier, party_type='Supplier', company=target_doc.company,
+ doctype=target_doc.doctype, party_address=target_doc.supplier_address,
+ company_address=target_doc.shipping_address)
else:
target_doc.company = details.get("company")
target_doc.customer = details.get("party")
target_doc.company_address = source_doc.supplier_address
- target_doc.shipping_address_name = source_doc.shipping_address
target_doc.selling_price_list = source_doc.buying_price_list
target_doc.is_internal_customer = 1
target_doc.inter_company_reference = source_doc.name
- doclist = get_mapped_doc(doctype, source_name, {
+ # Invert the address on target doc creation
+ update_address(target_doc, 'company_address', 'company_address_display', source_doc.supplier_address)
+ update_address(target_doc, 'shipping_address_name', 'shipping_address', source_doc.shipping_address)
+ update_address(target_doc, 'customer_address', 'address_display', source_doc.shipping_address)
+
+ update_taxes(target_doc, party=target_doc.customer, party_type='Customer', company=target_doc.company,
+ doctype=target_doc.doctype, party_address=target_doc.customer_address,
+ company_address=target_doc.company_address, shipping_address_name=target_doc.shipping_address_name)
+
+ doclist = get_mapped_doc(doctype, source_name, {
doctype: {
"doctype": target_doctype,
"postprocess": update_details,
@@ -722,7 +738,10 @@
doctype +" Item": {
"doctype": target_doctype + " Item",
"field_map": {
- source_document_warehouse_field: target_document_warehouse_field
+ source_document_warehouse_field: target_document_warehouse_field,
+ 'name': 'delivery_note_item',
+ 'batch_no': 'batch_no',
+ 'serial_no': 'serial_no'
},
"field_no_map": [
"warehouse"
diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
index 4bbf3de..9de088d 100644
--- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
+++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json
@@ -458,7 +458,7 @@
"fieldname": "warehouse",
"fieldtype": "Link",
"in_list_view": 1,
- "label": "From Warehouse",
+ "label": "Warehouse",
"oldfieldname": "warehouse",
"oldfieldtype": "Link",
"options": "Warehouse",
@@ -467,11 +467,12 @@
"width": "100px"
},
{
+ "depends_on": "eval:parent.is_internal_customer",
"fieldname": "target_warehouse",
"fieldtype": "Link",
"hidden": 1,
"ignore_user_permissions": 1,
- "label": "Customer Warehouse (Optional)",
+ "label": "Target Warehouse",
"no_copy": 1,
"options": "Warehouse",
"print_hide": 1
@@ -748,7 +749,7 @@
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2020-12-07 19:59:27.119856",
+ "modified": "2020-12-26 17:31:27.029803",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note Item",
diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json
index d07b3dc..fcf7c26 100644
--- a/erpnext/stock/doctype/item/item.json
+++ b/erpnext/stock/doctype/item/item.json
@@ -106,9 +106,9 @@
"item_tax_section_break",
"taxes",
"inspection_criteria",
+ "quality_inspection_template",
"inspection_required_before_purchase",
"inspection_required_before_delivery",
- "quality_inspection_template",
"manufacturing",
"default_bom",
"is_sub_contracted_item",
@@ -814,7 +814,6 @@
"label": "Inspection Required before Delivery"
},
{
- "depends_on": "eval:(doc.inspection_required_before_purchase || doc.inspection_required_before_delivery)",
"fieldname": "quality_inspection_template",
"fieldtype": "Link",
"label": "Quality Inspection Template",
@@ -1069,7 +1068,7 @@
"index_web_pages_for_search": 1,
"links": [],
"max_attachments": 1,
- "modified": "2020-08-07 14:24:58.384992",
+ "modified": "2021-01-25 20:49:50.222976",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item",
@@ -1131,4 +1130,4 @@
"sort_order": "DESC",
"title_field": "item_name",
"track_changes": 1
-}
+}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/material_request/material_request_list.js b/erpnext/stock/doctype/material_request/material_request_list.js
index 0d70958..de7a3d0 100644
--- a/erpnext/stock/doctype/material_request/material_request_list.js
+++ b/erpnext/stock/doctype/material_request/material_request_list.js
@@ -1,9 +1,10 @@
frappe.listview_settings['Material Request'] = {
add_fields: ["material_request_type", "status", "per_ordered", "per_received", "transfer_status"],
get_indicator: function(doc) {
- if(doc.status=="Stopped") {
+ var precision = frappe.defaults.get_default("float_precision");
+ if (doc.status=="Stopped") {
return [__("Stopped"), "red", "status,=,Stopped"];
- } else if(doc.transfer_status && doc.docstatus != 2) {
+ } else if (doc.transfer_status && doc.docstatus != 2) {
if (doc.transfer_status == "Not Started") {
return [__("Not Started"), "orange"];
} else if (doc.transfer_status == "In Transit") {
@@ -11,14 +12,14 @@
} else if (doc.transfer_status == "Completed") {
return [__("Completed"), "green"];
}
- } else if(doc.docstatus==1 && flt(doc.per_ordered, 2) == 0) {
+ } else if (doc.docstatus==1 && flt(doc.per_ordered, precision) == 0) {
return [__("Pending"), "orange", "per_ordered,=,0"];
- } else if(doc.docstatus==1 && flt(doc.per_ordered, 2) < 100) {
+ } else if (doc.docstatus==1 && flt(doc.per_ordered, precision) < 100) {
return [__("Partially ordered"), "yellow", "per_ordered,<,100"];
- } else if(doc.docstatus==1 && flt(doc.per_ordered, 2) == 100) {
- if (doc.material_request_type == "Purchase" && flt(doc.per_received, 2) < 100 && flt(doc.per_received, 2) > 0) {
+ } else if (doc.docstatus==1 && flt(doc.per_ordered, precision) == 100) {
+ if (doc.material_request_type == "Purchase" && flt(doc.per_received, precision) < 100 && flt(doc.per_received, precision) > 0) {
return [__("Partially Received"), "yellow", "per_received,<,100"];
- } else if (doc.material_request_type == "Purchase" && flt(doc.per_received, 2) == 100) {
+ } else if (doc.material_request_type == "Purchase" && flt(doc.per_received, precision) == 100) {
return [__("Received"), "green", "per_received,=,100"];
} else if (doc.material_request_type == "Purchase") {
return [__("Ordered"), "green", "per_ordered,=,100"];
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
index 55f0f0c..32d349f 100755
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
@@ -48,6 +48,7 @@
"set_warehouse",
"rejected_warehouse",
"col_break_warehouse",
+ "set_from_warehouse",
"is_subcontracted",
"supplier_warehouse",
"items_section",
@@ -115,6 +116,7 @@
"per_returned",
"is_internal_supplier",
"inter_company_reference",
+ "represents_company",
"subscription_detail",
"auto_repeat",
"printing_settings",
@@ -1087,7 +1089,9 @@
"fieldname": "inter_company_reference",
"fieldtype": "Link",
"label": "Inter Company Reference",
+ "no_copy": 1,
"options": "Delivery Note",
+ "print_hide": 1,
"read_only": 1
},
{
@@ -1121,13 +1125,29 @@
"no_copy": 1,
"print_hide": 1,
"read_only": 1
+ },
+ {
+ "depends_on": "eval: doc.is_internal_supplier",
+ "description": "Sets 'From Warehouse' in each row of the items table.",
+ "fieldname": "set_from_warehouse",
+ "fieldtype": "Link",
+ "label": "Set From 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",
"idx": 261,
"is_submittable": 1,
"links": [],
- "modified": "2020-12-08 18:31:32.234503",
+ "modified": "2020-12-26 20:49:39.106049",
"modified_by": "Administrator",
"module": "Stock",
"name": "Purchase Receipt",
diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
index 662e50c..e991192 100644
--- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
+++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
@@ -76,6 +76,7 @@
"purchase_order_item",
"material_request_item",
"purchase_receipt_item",
+ "delivery_note_item",
"putaway_rule",
"section_break_45",
"allow_zero_valuation_rate",
@@ -819,11 +820,12 @@
"read_only": 1
},
{
+ "depends_on": "eval:parent.is_internal_supplier",
"fieldname": "from_warehouse",
"fieldtype": "Link",
"hidden": 1,
"ignore_user_permissions": 1,
- "label": "Supplier Warehouse",
+ "label": "From Warehouse",
"options": "Warehouse"
},
{
@@ -871,12 +873,20 @@
"fieldtype": "Float",
"label": "Received Qty in Stock UOM",
"print_hide": 1
+ },
+ {
+ "fieldname": "delivery_note_item",
+ "fieldtype": "Data",
+ "label": "Delivery Note Item",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
}
],
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2020-12-09 10:00:38.204294",
+ "modified": "2020-12-26 16:50:56.479347",
"modified_by": "Administrator",
"module": "Stock",
"name": "Purchase Receipt Item",
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index 9aaa669..726118d 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -7,6 +7,14 @@
frappe.ui.form.on('Stock Entry', {
setup: function(frm) {
+ frm.set_indicator_formatter('item_code', function(doc) {
+ if (!doc.s_warehouse) {
+ return 'blue';
+ } else {
+ return (doc.qty<=doc.actual_qty) ? 'green' : 'orange';
+ }
+ });
+
frm.set_query('work_order', function() {
return {
filters: [
@@ -782,15 +790,6 @@
}
}
- this.frm.set_indicator_formatter('item_code',
- function(doc) {
- if (!doc.s_warehouse) {
- return 'blue';
- } else {
- return (doc.qty<=doc.actual_qty) ? "green" : "orange"
- }
- })
-
this.frm.add_fetch("purchase_order", "supplier", "supplier");
frappe.dynamic_link = { doc: this.frm.doc, fieldname: 'supplier', doctype: 'Supplier' }
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index 5b9ada0..2b2a7a2 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -41,7 +41,7 @@
if sle.get("actual_qty") or sle.get("voucher_type")=="Stock Reconciliation":
sle_doc = make_entry(sle, allow_negative_stock, via_landed_cost_voucher)
-
+
args = sle_doc.as_dict()
update_bin(args, allow_negative_stock, via_landed_cost_voucher)
@@ -65,7 +65,7 @@
def repost_future_sle(args=None, voucher_type=None, voucher_no=None, allow_negative_stock=False, via_landed_cost_voucher=False):
if not args and voucher_type and voucher_no:
args = get_args_for_voucher(voucher_type, voucher_no)
-
+
distinct_item_warehouses = [(d.item_code, d.warehouse) for d in args]
i = 0
@@ -80,7 +80,7 @@
for item_wh, new_sle in iteritems(obj.new_items):
if item_wh not in distinct_item_warehouses:
args.append(new_sle)
-
+
i += 1
def get_args_for_voucher(voucher_type, voucher_no):
@@ -127,7 +127,7 @@
self.initialize_previous_data(self.args)
self.build()
-
+
def get_precision(self):
company_base_currency = frappe.get_cached_value('Company', self.company, "default_currency")
self.precision = get_field_precision(frappe.get_meta("Stock Ledger Entry").get_field("stock_value"),
@@ -213,13 +213,13 @@
# includes current entry!
args = self.data[self.args.warehouse].previous_sle \
or frappe._dict({"item_code": self.item_code, "warehouse": self.args.warehouse})
-
+
return list(self.get_sle_after_datetime(args))
def get_dependent_entries_to_fix(self, entries_to_fix, sle):
dependant_sle = get_sle_by_voucher_detail_no(sle.dependant_sle_voucher_detail_no,
excluded_sle=sle.name)
-
+
if not dependant_sle:
return
elif dependant_sle.item_code == self.item_code and dependant_sle.warehouse == self.args.warehouse:
@@ -251,7 +251,7 @@
# Get dynamic incoming/outgoing rate
self.get_dynamic_incoming_outgoing_rate(sle)
-
+
if sle.serial_no:
self.get_serialized_values(sle)
self.wh_data.qty_after_transaction += flt(sle.actual_qty)
@@ -329,7 +329,7 @@
rate = get_rate_for_return(sle.voucher_type, sle.voucher_no, sle.item_code, voucher_detail_no=sle.voucher_detail_no)
else:
if sle.voucher_type in ("Purchase Receipt", "Purchase Invoice"):
- rate_field = "valuation_rate"
+ rate_field = "valuation_rate"
else:
rate_field = "incoming_rate"
@@ -344,7 +344,7 @@
ref_doctype = "Packed Item"
else:
ref_doctype = "Purchase Receipt Item Supplied"
-
+
rate = frappe.db.get_value(ref_doctype, {"parent_detail_docname": sle.voucher_detail_no,
"item_code": sle.item_code}, rate_field)
@@ -374,7 +374,7 @@
stock_entry.db_update()
for d in stock_entry.items:
d.db_update()
-
+
def update_rate_on_delivery_and_sales_return(self, sle, outgoing_rate):
# Update item's incoming rate on transaction
item_code = frappe.db.get_value(sle.voucher_type + " Item", sle.voucher_detail_no, "item_code")
@@ -487,7 +487,6 @@
self.wh_data.valuation_rate = new_stock_value / new_stock_qty
else:
self.wh_data.valuation_rate = sle.outgoing_rate
-
else:
if flt(self.wh_data.qty_after_transaction) >= 0 and sle.outgoing_rate:
self.wh_data.valuation_rate = sle.outgoing_rate
@@ -631,7 +630,7 @@
frappe.throw(message, NegativeStockError, title='Insufficient Stock')
else:
raise NegativeStockError(message)
-
+
def update_bin(self):
# update bin for each warehouse
for warehouse, data in iteritems(self.data):
@@ -766,7 +765,7 @@
frappe.db.sql("""
update `tabStock Ledger Entry`
set qty_after_transaction = qty_after_transaction + {qty}
- where
+ where
item_code = %(item_code)s
and warehouse = %(warehouse)s
and voucher_no != %(voucher_no)s
@@ -794,7 +793,7 @@
frappe.get_desk_link('Warehouse', args.warehouse),
sle[0]["posting_date"], sle[0]["posting_time"],
frappe.get_desk_link(sle[0]["voucher_type"], sle[0]["voucher_no"]))
-
+
frappe.throw(message, NegativeStockError, title='Insufficient Stock')
def get_future_sle_with_negative_qty(args):
@@ -803,7 +802,7 @@
qty_after_transaction, posting_date, posting_time,
voucher_type, voucher_no
from `tabStock Ledger Entry`
- where
+ where
item_code = %(item_code)s
and warehouse = %(warehouse)s
and voucher_no != %(voucher_no)s
diff --git a/erpnext/templates/includes/macros.html b/erpnext/templates/includes/macros.html
index ea6b00f..5d8ee5c 100644
--- a/erpnext/templates/includes/macros.html
+++ b/erpnext/templates/includes/macros.html
@@ -40,7 +40,7 @@
<div class="col-md-{{ section.column_value }} mb-4">
<div class="card h-100 justify-content-between">
{% if card.image %}
- <div class="website-image-lazy" data-class="card-img-top h-100" data-src="{{ card.image }}" data-alt="{{ card.title }}"></div>
+ <div class="website-image-lazy" data-class="card-img-top h-75" data-src="{{ card.image }}" data-alt="{{ card.title }}"></div>
{% endif %}
<div class="card-body">
<h5 class="card-title">{{ card.title }}</h5>