{% } %}
{% } %}
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 3445df7206..a36e7f8581 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
@@ -8,6 +8,7 @@ from frappe.utils import flt
from erpnext.accounts.report.item_wise_sales_register.item_wise_sales_register import (get_tax_accounts,
get_grand_total, add_total_row, get_display_value, get_group_by_and_display_fields, add_sub_total_row,
get_group_by_conditions)
+from erpnext.selling.report.item_wise_sales_history.item_wise_sales_history import get_item_details
def execute(filters=None):
return _execute(filters)
@@ -22,7 +23,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
aii_account_map = get_aii_accounts()
if item_list:
itemised_tax, tax_columns = get_tax_accounts(item_list, columns, company_currency,
- doctype="Purchase Invoice", tax_doctype="Purchase Taxes and Charges")
+ doctype='Purchase Invoice', tax_doctype='Purchase Taxes and Charges')
po_pr_map = get_purchase_receipts_against_purchase_order(item_list)
@@ -34,10 +35,14 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
if filters.get('group_by'):
grand_total = get_grand_total(filters, 'Purchase Invoice')
+ item_details = get_item_details()
+
for d in item_list:
if not d.stock_qty:
continue
+ item_record = item_details.get(d.item_code)
+
purchase_receipt = None
if d.purchase_receipt:
purchase_receipt = d.purchase_receipt
@@ -48,8 +53,8 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
row = {
'item_code': d.item_code,
- 'item_name': d.item_name,
- 'item_group': d.item_group,
+ 'item_name': item_record.item_name,
+ 'item_group': item_record.item_group,
'description': d.description,
'invoice': d.parent,
'posting_date': d.posting_date,
@@ -81,10 +86,10 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
for tax in tax_columns:
item_tax = itemised_tax.get(d.name, {}).get(tax, {})
row.update({
- frappe.scrub(tax + ' Rate'): item_tax.get("tax_rate", 0),
- frappe.scrub(tax + ' Amount'): item_tax.get("tax_amount", 0),
+ frappe.scrub(tax + ' Rate'): item_tax.get('tax_rate', 0),
+ frappe.scrub(tax + ' Amount'): item_tax.get('tax_amount', 0),
})
- total_tax += flt(item_tax.get("tax_amount"))
+ total_tax += flt(item_tax.get('tax_amount'))
row.update({
'total_tax': total_tax,
@@ -309,8 +314,8 @@ def get_items(filters, additional_query_columns):
select
`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 Item`.`item_code`,
- `tabPurchase Invoice Item`.`item_name`, `tabPurchase Invoice Item`.`item_group`, `tabPurchase Invoice Item`.description,
+ `tabPurchase Invoice`.supplier, `tabPurchase Invoice`.remarks, `tabPurchase Invoice`.base_net_total,
+ `tabPurchase Invoice Item`.`item_code`, `tabPurchase Invoice Item`.description,
`tabPurchase Invoice Item`.`project`, `tabPurchase Invoice Item`.`purchase_order`,
`tabPurchase Invoice Item`.`purchase_receipt`, `tabPurchase Invoice Item`.`po_detail`,
`tabPurchase Invoice Item`.`expense_account`, `tabPurchase Invoice Item`.`stock_qty`,
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 a05dcd75ce..f54ceb0d2f 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
@@ -8,6 +8,7 @@ from frappe.utils import flt, cstr
from frappe.model.meta import get_field_precision
from frappe.utils.xlsxutils import handle_html
from erpnext.accounts.report.sales_register.sales_register import get_mode_of_payments
+from erpnext.selling.report.item_wise_sales_history.item_wise_sales_history import get_item_details, get_customer_details
def execute(filters=None):
return _execute(filters)
@@ -16,7 +17,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
if not filters: filters = {}
columns = get_columns(additional_table_columns, filters)
- company_currency = frappe.get_cached_value('Company', filters.get("company"), "default_currency")
+ company_currency = frappe.get_cached_value('Company', filters.get('company'), 'default_currency')
item_list = get_items(filters, additional_query_columns)
if item_list:
@@ -33,7 +34,13 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
if filters.get('group_by'):
grand_total = get_grand_total(filters, 'Sales Invoice')
+ customer_details = get_customer_details()
+ item_details = get_item_details()
+
for d in item_list:
+ customer_record = customer_details.get(d.customer)
+ item_record = item_details.get(d.item_code)
+
delivery_note = None
if d.delivery_note:
delivery_note = d.delivery_note
@@ -45,14 +52,14 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
row = {
'item_code': d.item_code,
- 'item_name': d.item_name,
- 'item_group': d.item_group,
+ 'item_name': item_record.item_name,
+ 'item_group': item_record.item_group,
'description': d.description,
'invoice': d.parent,
'posting_date': d.posting_date,
'customer': d.customer,
- 'customer_name': d.customer_name,
- 'customer_group': d.customer_group,
+ 'customer_name': customer_record.customer_name,
+ 'customer_group': customer_record.customer_group,
}
if additional_query_columns:
@@ -90,10 +97,10 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
for tax in tax_columns:
item_tax = itemised_tax.get(d.name, {}).get(tax, {})
row.update({
- frappe.scrub(tax + ' Rate'): item_tax.get("tax_rate", 0),
- frappe.scrub(tax + ' Amount'): item_tax.get("tax_amount", 0),
+ frappe.scrub(tax + ' Rate'): item_tax.get('tax_rate', 0),
+ frappe.scrub(tax + ' Amount'): item_tax.get('tax_amount', 0),
})
- total_tax += flt(item_tax.get("tax_amount"))
+ total_tax += flt(item_tax.get('tax_amount'))
row.update({
'total_tax': total_tax,
@@ -226,7 +233,7 @@ def get_columns(additional_table_columns, filters):
if filters.get('group_by') != 'Territory':
columns.extend([
{
- 'label': _("Territory"),
+ 'label': _('Territory'),
'fieldname': 'territory',
'fieldtype': 'Link',
'options': 'Territory',
@@ -374,13 +381,12 @@ def get_items(filters, additional_query_columns):
`tabSales Invoice`.posting_date, `tabSales Invoice`.debit_to,
`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`.item_name,
- `tabSales Invoice Item`.item_group, `tabSales Invoice Item`.description, `tabSales Invoice Item`.sales_order,
- `tabSales Invoice Item`.delivery_note, `tabSales Invoice Item`.income_account,
- `tabSales Invoice Item`.cost_center, `tabSales Invoice Item`.stock_qty,
- `tabSales Invoice Item`.stock_uom, `tabSales Invoice Item`.base_net_rate,
- `tabSales Invoice Item`.base_net_amount, `tabSales Invoice`.customer_name,
- `tabSales Invoice`.customer_group, `tabSales Invoice Item`.so_detail,
+ `tabSales Invoice Item`.item_code, `tabSales Invoice Item`.description,
+ `tabSales Invoice Item`.sales_order, `tabSales Invoice Item`.delivery_note,
+ `tabSales Invoice Item`.income_account, `tabSales Invoice Item`.cost_center,
+ `tabSales Invoice Item`.stock_qty, `tabSales Invoice Item`.stock_uom,
+ `tabSales Invoice Item`.base_net_rate, `tabSales Invoice Item`.base_net_amount,
+ `tabSales Invoice`.customer_name, `tabSales Invoice`.customer_group, `tabSales Invoice Item`.so_detail,
`tabSales Invoice`.update_stock, `tabSales Invoice Item`.uom, `tabSales Invoice Item`.qty {0}
from `tabSales Invoice`, `tabSales Invoice Item`
where `tabSales Invoice`.name = `tabSales Invoice Item`.parent
@@ -417,14 +423,14 @@ def get_deducted_taxes():
return frappe.db.sql_list("select name from `tabPurchase Taxes and Charges` where add_deduct_tax = 'Deduct'")
def get_tax_accounts(item_list, columns, company_currency,
- doctype="Sales Invoice", tax_doctype="Sales Taxes and Charges"):
+ doctype='Sales Invoice', tax_doctype='Sales Taxes and Charges'):
import json
item_row_map = {}
tax_columns = []
invoice_item_row = {}
itemised_tax = {}
- tax_amount_precision = get_field_precision(frappe.get_meta(tax_doctype).get_field("tax_amount"),
+ tax_amount_precision = get_field_precision(frappe.get_meta(tax_doctype).get_field('tax_amount'),
currency=company_currency) or 2
for d in item_list:
@@ -469,8 +475,8 @@ def get_tax_accounts(item_list, columns, company_currency,
tax_rate = tax_data
tax_amount = 0
- if charge_type == "Actual" and not tax_rate:
- tax_rate = "NA"
+ if charge_type == 'Actual' and not tax_rate:
+ tax_rate = 'NA'
item_net_amount = sum([flt(d.base_net_amount)
for d in item_row_map.get(parent, {}).get(item_code, [])])
@@ -484,17 +490,17 @@ def get_tax_accounts(item_list, columns, company_currency,
if (doctype == 'Purchase Invoice' and name in deducted_tax) else tax_value)
itemised_tax.setdefault(d.name, {})[description] = frappe._dict({
- "tax_rate": tax_rate,
- "tax_amount": tax_value
+ 'tax_rate': tax_rate,
+ 'tax_amount': tax_value
})
except ValueError:
continue
- elif charge_type == "Actual" and tax_amount:
+ elif charge_type == 'Actual' and tax_amount:
for d in invoice_item_row.get(parent, []):
itemised_tax.setdefault(d.name, {})[description] = frappe._dict({
- "tax_rate": "NA",
- "tax_amount": flt((tax_amount * d.base_net_amount) / d.base_net_total,
+ 'tax_rate': 'NA',
+ 'tax_amount': flt((tax_amount * d.base_net_amount) / d.base_net_total,
tax_amount_precision)
})
@@ -563,7 +569,7 @@ def add_total_row(data, filters, prev_group_by_value, item, total_row_map,
})
total_row_map.setdefault('total_row', {
- subtotal_display_field: "Total",
+ subtotal_display_field: 'Total',
'stock_qty': 0.0,
'amount': 0.0,
'bold': 1,
diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py
index fd702c74c7..74ca62ffda 100644
--- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py
+++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py
@@ -13,8 +13,8 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import g
class AssetValueAdjustment(Document):
def validate(self):
self.validate_date()
- self.set_difference_amount()
self.set_current_asset_value()
+ self.set_difference_amount()
def on_submit(self):
self.make_depreciation_entry()
@@ -25,7 +25,7 @@ class AssetValueAdjustment(Document):
frappe.throw(_("Cancel the journal entry {0} first").format(self.journal_entry))
self.reschedule_depreciations(self.current_asset_value)
-
+
def validate_date(self):
asset_purchase_date = frappe.db.get_value('Asset', self.asset, 'purchase_date')
if getdate(self.date) < getdate(asset_purchase_date):
@@ -53,6 +53,7 @@ class AssetValueAdjustment(Document):
je.posting_date = self.date
je.company = self.company
je.remark = "Depreciation Entry against {0} worth {1}".format(self.asset, self.difference_amount)
+ je.finance_book = self.finance_book
credit_entry = {
"account": accumulated_depreciation_account,
@@ -78,7 +79,7 @@ class AssetValueAdjustment(Document):
debit_entry.update({
dimension['fieldname']: self.get(dimension['fieldname']) or dimension.get('default_dimension')
})
-
+
je.append("accounts", credit_entry)
je.append("accounts", debit_entry)
diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
index af08a2a601..d1457b9b85 100644
--- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
+++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
@@ -75,24 +75,23 @@ def get_data(filters):
for asset in assets_record:
asset_value = asset.gross_purchase_amount - flt(asset.opening_accumulated_depreciation) \
- flt(depreciation_amount_map.get(asset.name))
- if asset_value:
- row = {
- "asset_id": asset.asset_id,
- "asset_name": asset.asset_name,
- "status": asset.status,
- "department": asset.department,
- "cost_center": asset.cost_center,
- "vendor_name": pr_supplier_map.get(asset.purchase_receipt) or pi_supplier_map.get(asset.purchase_invoice),
- "gross_purchase_amount": asset.gross_purchase_amount,
- "opening_accumulated_depreciation": asset.opening_accumulated_depreciation,
- "depreciated_amount": depreciation_amount_map.get(asset.asset_id) or 0.0,
- "available_for_use_date": asset.available_for_use_date,
- "location": asset.location,
- "asset_category": asset.asset_category,
- "purchase_date": asset.purchase_date,
- "asset_value": asset_value
- }
- data.append(row)
+ row = {
+ "asset_id": asset.asset_id,
+ "asset_name": asset.asset_name,
+ "status": asset.status,
+ "department": asset.department,
+ "cost_center": asset.cost_center,
+ "vendor_name": pr_supplier_map.get(asset.purchase_receipt) or pi_supplier_map.get(asset.purchase_invoice),
+ "gross_purchase_amount": asset.gross_purchase_amount,
+ "opening_accumulated_depreciation": asset.opening_accumulated_depreciation,
+ "depreciated_amount": depreciation_amount_map.get(asset.asset_id) or 0.0,
+ "available_for_use_date": asset.available_for_use_date,
+ "location": asset.location,
+ "asset_category": asset.asset_category,
+ "purchase_date": asset.purchase_date,
+ "asset_value": asset_value
+ }
+ data.append(row)
return data
diff --git a/erpnext/buying/doctype/supplier/supplier.py b/erpnext/buying/doctype/supplier/supplier.py
index df143eefa0..0ee9d180d9 100644
--- a/erpnext/buying/doctype/supplier/supplier.py
+++ b/erpnext/buying/doctype/supplier/supplier.py
@@ -49,6 +49,12 @@ class Supplier(TransactionBase):
msgprint(_("Series is mandatory"), raise_exception=1)
validate_party_accounts(self)
+ 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"):
+ frappe.throw(_("Internal Supplier for company {0} already exists").format(
+ frappe.bold(self.represents_company)))
def on_trash(self):
delete_contact_and_address('Supplier', self.name)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 93a79ec934..32c5d3a3b1 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -107,6 +107,8 @@ class AccountsController(TransactionBase):
else:
self.validate_deferred_start_and_end_date()
+ self.set_inter_company_account()
+
validate_regional(self)
if self.doctype != 'Material Request':
apply_pricing_rule_on_transaction(self)
@@ -932,6 +934,38 @@ class AccountsController(TransactionBase):
else:
return frappe.db.get_single_value("Global Defaults", "disable_rounded_total")
+ def set_inter_company_account(self):
+ """
+ Set intercompany account for inter warehouse transactions
+ This account will be used in case billing company and internal customer's
+ representation company is same
+ """
+
+ if self.is_internal_transfer() and not self.unrealized_profit_loss_account:
+ unrealized_profit_loss_account = frappe.db.get_value('Company', self.company, 'unrealized_profit_loss_account')
+
+ if not unrealized_profit_loss_account:
+ msg = _("Please select Unrealized Profit / Loss account or add default Unrealized Profit / Loss account account for company {0}").format(
+ frappe.bold(self.company))
+ frappe.throw(msg)
+
+ self.unrealized_profit_loss_account = unrealized_profit_loss_account
+
+ def is_internal_transfer(self):
+ """
+ It will an internal transfer if its an internal customer and representation
+ company is same as billing company
+ """
+ if self.doctype == 'Sales Invoice':
+ internal_party_field = 'is_internal_customer'
+ else:
+ internal_party_field = 'is_internal_supplier'
+
+ if self.get(internal_party_field) and (self.represents_company == self.company):
+ return True
+
+ return False
+
@frappe.whitelist()
def get_tax_rate(account_head):
return frappe.db.get_value("Account", account_head, ["tax_rate", "account_name"], as_dict=True)
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index 5fabf7017b..286c4f4451 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -42,6 +42,7 @@ class BuyingController(StockController):
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()
@@ -94,13 +95,23 @@ class BuyingController(StockController):
def validate_stock_or_nonstock_items(self):
if self.meta.get_field("taxes") and not self.get_stock_items() and not self.get_asset_items():
- tax_for_valuation = [d for d in self.get("taxes")
+ 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"]]
- if tax_for_valuation:
- for d in tax_for_valuation:
- d.category = 'Total'
- msgprint(_('Tax Category has been changed to "Total" because all the Items are non-stock items'))
+ if tax_for_valuation:
+ for d in tax_for_valuation:
+ d.category = 'Total'
+
+ msgprint(msg)
def validate_asset_return(self):
if self.doctype not in ['Purchase Receipt', 'Purchase Invoice'] or not self.is_return:
diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py
index 2555edf06b..8c05134ae4 100644
--- a/erpnext/controllers/status_updater.py
+++ b/erpnext/controllers/status_updater.py
@@ -254,22 +254,26 @@ class StatusUpdater(Document):
if not args.get("second_source_extra_cond"):
args["second_source_extra_cond"] = ""
- args['second_source_condition'] = """ + ifnull((select sum(%(second_source_field)s)
+ args['second_source_condition'] = frappe.db.sql(""" select ifnull((select sum(%(second_source_field)s)
from `tab%(second_source_dt)s`
where `%(second_join_field)s`="%(detail_id)s"
- and (`tab%(second_source_dt)s`.docstatus=1) %(second_source_extra_cond)s FOR UPDATE), 0)""" % args
+ and (`tab%(second_source_dt)s`.docstatus=1)
+ %(second_source_extra_cond)s), 0) """ % args)[0][0]
if args['detail_id']:
if not args.get("extra_cond"): args["extra_cond"] = ""
- frappe.db.sql("""update `tab%(target_dt)s`
- set %(target_field)s = (
+ args["source_dt_value"] = frappe.db.sql("""
(select ifnull(sum(%(source_field)s), 0)
from `tab%(source_dt)s` where `%(join_field)s`="%(detail_id)s"
and (docstatus=1 %(cond)s) %(extra_cond)s)
- %(second_source_condition)s
- )
- %(update_modified)s
+ """ % args)[0][0] or 0.0
+
+ if args['second_source_condition']:
+ args["source_dt_value"] += flt(args['second_source_condition'])
+
+ frappe.db.sql("""update `tab%(target_dt)s`
+ set %(target_field)s = %(source_dt_value)s %(update_modified)s
where name='%(detail_id)s'""" % args)
def _update_percent_field_in_targets(self, args, update_modified=True):
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 2f7b361b39..683d7f77b5 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -77,7 +77,7 @@ class StockController(AccountsController):
if sle_list:
for sle in sle_list:
if warehouse_account.get(sle.warehouse):
- # from warehouse account/ target warehouse account
+ # from warehouse account
self.check_expense_account(item_row)
@@ -92,9 +92,16 @@ class StockController(AccountsController):
sle = self.update_stock_ledger_entries(sle)
+ # expense account/ target_warehouse / source_warehouse
+ if item_row.get('target_warehouse'):
+ warehouse = item_row.get('target_warehouse')
+ expense_account = warehouse_account[warehouse]["account"]
+ else:
+ expense_account = item_row.expense_account
+
gl_list.append(self.get_gl_dict({
"account": warehouse_account[sle.warehouse]["account"],
- "against": item_row.expense_account,
+ "against": expense_account,
"cost_center": item_row.cost_center,
"project": item_row.project or self.get('project'),
"remarks": self.get("remarks") or "Accounting Entry for Stock",
@@ -102,9 +109,8 @@ class StockController(AccountsController):
"is_opening": item_row.get("is_opening") or self.get("is_opening") or "No",
}, warehouse_account[sle.warehouse]["account_currency"], item=item_row))
- # expense account
gl_list.append(self.get_gl_dict({
- "account": item_row.expense_account,
+ "account": expense_account,
"against": warehouse_account[sle.warehouse]["account"],
"cost_center": item_row.cost_center,
"project": item_row.project or self.get('project'),
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index ad58f137ee..8dd2e5bacb 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -519,6 +519,17 @@ class calculate_taxes_and_totals(object):
if self.doc.docstatus == 0:
self.calculate_outstanding_amount()
+ def is_internal_invoice(self):
+ """
+ Checks if its an internal transfer invoice
+ and decides if to calculate any out standing amount or not
+ """
+
+ if self.doc.doctype in ('Sales Invoice', 'Purchase Invoice') and self.doc.is_internal_transfer():
+ return True
+
+ return False
+
def calculate_outstanding_amount(self):
# NOTE:
# write_off_amount is only for POS Invoice
@@ -526,7 +537,8 @@ class calculate_taxes_and_totals(object):
if self.doc.doctype == "Sales Invoice":
self.calculate_paid_amount()
- if self.doc.is_return and self.doc.return_against and not self.doc.get('is_pos'): return
+ if self.doc.is_return and self.doc.return_against and not self.doc.get('is_pos') or \
+ self.is_internal_invoice(): return
self.doc.round_floats_in(self.doc, ["grand_total", "total_advance", "write_off_amount"])
self._set_in_company_currency(self.doc, ['write_off_amount'])
diff --git a/erpnext/crm/doctype/contract/contract.js b/erpnext/crm/doctype/contract/contract.js
index ee9e895130..9968855163 100644
--- a/erpnext/crm/doctype/contract/contract.js
+++ b/erpnext/crm/doctype/contract/contract.js
@@ -1,23 +1,31 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
-cur_frm.add_fetch("contract_template", "contract_terms", "contract_terms");
-cur_frm.add_fetch("contract_template", "requires_fulfilment", "requires_fulfilment");
-
-// Add fulfilment terms from contract template into contract
frappe.ui.form.on("Contract", {
contract_template: function (frm) {
- // Populate the fulfilment terms table from a contract template, if any
if (frm.doc.contract_template) {
- frappe.model.with_doc("Contract Template", frm.doc.contract_template, function () {
- var tabletransfer = frappe.model.get_doc("Contract Template", frm.doc.contract_template);
-
- frm.doc.fulfilment_terms = [];
- $.each(tabletransfer.fulfilment_terms, function (index, row) {
- var d = frm.add_child("fulfilment_terms");
- d.requirement = row.requirement;
- frm.refresh_field("fulfilment_terms");
- });
+ frappe.call({
+ method: 'erpnext.crm.doctype.contract_template.contract_template.get_contract_template',
+ args: {
+ template_name: frm.doc.contract_template,
+ doc: frm.doc
+ },
+ callback: function(r) {
+ if (r && r.message) {
+ let contract_template = r.message.contract_template;
+ frm.set_value("contract_terms", r.message.contract_terms);
+ frm.set_value("requires_fulfilment", contract_template.requires_fulfilment);
+
+ if (frm.doc.requires_fulfilment) {
+ // Populate the fulfilment terms table from a contract template, if any
+ r.message.contract_template.fulfilment_terms.forEach(element => {
+ let d = frm.add_child("fulfilment_terms");
+ d.requirement = element.requirement;
+ });
+ frm.refresh_field("fulfilment_terms");
+ }
+ }
+ }
});
}
}
diff --git a/erpnext/crm/doctype/contract/contract.json b/erpnext/crm/doctype/contract/contract.json
index 0026e4a02e..de3230f0e6 100755
--- a/erpnext/crm/doctype/contract/contract.json
+++ b/erpnext/crm/doctype/contract/contract.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"allow_import": 1,
"allow_rename": 1,
"creation": "2018-04-12 06:32:04.582486",
@@ -247,7 +248,7 @@
],
"is_submittable": 1,
"links": [],
- "modified": "2020-03-30 06:56:07.257932",
+ "modified": "2020-12-07 11:15:58.385521",
"modified_by": "Administrator",
"module": "CRM",
"name": "Contract",
diff --git a/erpnext/crm/doctype/contract_template/contract_template.json b/erpnext/crm/doctype/contract_template/contract_template.json
index 5e4582f8d3..7cc5ec13cf 100644
--- a/erpnext/crm/doctype/contract_template/contract_template.json
+++ b/erpnext/crm/doctype/contract_template/contract_template.json
@@ -11,7 +11,9 @@
"contract_terms",
"sb_fulfilment",
"requires_fulfilment",
- "fulfilment_terms"
+ "fulfilment_terms",
+ "section_break_6",
+ "contract_template_help"
],
"fields": [
{
@@ -41,10 +43,20 @@
"fieldtype": "Table",
"label": "Fulfilment Terms and Conditions",
"options": "Contract Template Fulfilment Terms"
+ },
+ {
+ "fieldname": "section_break_6",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "contract_template_help",
+ "fieldtype": "HTML",
+ "label": "Contract Template Help",
+ "options": "
Contract Template Example
\n\n
Contract for Customer {{ party_name }}\n\n-Valid From : {{ start_date }} \n-Valid To : {{ end_date }}\n
\n\n
How to get fieldnames
\n\n
The field names you can use in your Contract Template are the fields in the Contract for which you are creating the template. You can find out the fields of any documents via Setup > Customize Form View and selecting the document type (e.g. Contract)
\n\n
Templating
\n\n
Templates are compiled using the Jinja Templating Language. To learn more about Jinja, read this documentation.
"
}
],
"links": [],
- "modified": "2020-11-11 17:49:44.879363",
+ "modified": "2020-12-07 10:44:22.587047",
"modified_by": "Administrator",
"module": "CRM",
"name": "Contract Template",
diff --git a/erpnext/crm/doctype/contract_template/contract_template.py b/erpnext/crm/doctype/contract_template/contract_template.py
index 601ee9a28b..69fd86f7fb 100644
--- a/erpnext/crm/doctype/contract_template/contract_template.py
+++ b/erpnext/crm/doctype/contract_template/contract_template.py
@@ -5,6 +5,27 @@
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
+from frappe.utils.jinja import validate_template
+from six import string_types
+import json
class ContractTemplate(Document):
- pass
+ def validate(self):
+ if self.contract_terms:
+ validate_template(self.contract_terms)
+
+@frappe.whitelist()
+def get_contract_template(template_name, doc):
+ if isinstance(doc, string_types):
+ doc = json.loads(doc)
+
+ contract_template = frappe.get_doc("Contract Template", template_name)
+ contract_terms = None
+
+ if contract_template.contract_terms:
+ contract_terms = frappe.render_template(contract_template.contract_terms, doc)
+
+ return {
+ 'contract_template': contract_template,
+ 'contract_terms': contract_terms
+ }
\ No newline at end of file
diff --git a/erpnext/erpnext_integrations/connectors/shopify_connection.py b/erpnext/erpnext_integrations/connectors/shopify_connection.py
index efbaa71924..f0a05ed192 100644
--- a/erpnext/erpnext_integrations/connectors/shopify_connection.py
+++ b/erpnext/erpnext_integrations/connectors/shopify_connection.py
@@ -260,6 +260,15 @@ def update_taxes_with_shipping_lines(taxes, shipping_lines, shopify_settings):
"""Shipping lines represents the shipping details,
each such shipping detail consists of a list of tax_lines"""
for shipping_charge in shipping_lines:
+ if shipping_charge.get("price"):
+ taxes.append({
+ "charge_type": _("Actual"),
+ "account_head": get_tax_account_head(shipping_charge),
+ "description": shipping_charge["title"],
+ "tax_amount": shipping_charge["price"],
+ "cost_center": shopify_settings.cost_center
+ })
+
for tax in shipping_charge.get("tax_lines"):
taxes.append({
"charge_type": _("Actual"),
diff --git a/erpnext/healthcare/desk_page/healthcare/healthcare.json b/erpnext/healthcare/desk_page/healthcare/healthcare.json
index 81d60481ce..af601f3eb2 100644
--- a/erpnext/healthcare/desk_page/healthcare/healthcare.json
+++ b/erpnext/healthcare/desk_page/healthcare/healthcare.json
@@ -30,6 +30,11 @@
"label": "Laboratory",
"links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Lab Test\",\n\t\t\"label\": \"Lab Test\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Sample Collection\",\n\t\t\"label\": \"Sample Collection\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Dosage Form\",\n\t\t\"label\": \"Dosage Form\"\n\t}\n]"
},
+ {
+ "hidden": 0,
+ "label": "Inpatient",
+ "links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Inpatient Record\",\n\t\t\"label\": \"Inpatient Record\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Inpatient Medication Order\",\n\t\t\"label\": \"Inpatient Medication Order\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Inpatient Medication Entry\",\n\t\t\"label\": \"Inpatient Medication Entry\"\n\t}\n]"
+ },
{
"hidden": 0,
"label": "Rehabilitation and Physiotherapy",
@@ -38,7 +43,7 @@
{
"hidden": 0,
"label": "Records and History",
- "links": "[\n\t{\n\t\t\"type\": \"page\",\n\t\t\"name\": \"patient_history\",\n\t\t\"label\": \"Patient History\"\n\t},\n\t{\n\t\t\"type\": \"page\",\n\t\t\"name\": \"patient-progress\",\n\t\t\"label\": \"Patient Progress\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient Medical Record\",\n\t\t\"label\": \"Patient Medical Record\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Inpatient Record\",\n\t\t\"label\": \"Inpatient Record\"\n\t}\n]"
+ "links": "[\n\t{\n\t\t\"type\": \"page\",\n\t\t\"name\": \"patient_history\",\n\t\t\"label\": \"Patient History\"\n\t},\n\t{\n\t\t\"type\": \"page\",\n\t\t\"name\": \"patient-progress\",\n\t\t\"label\": \"Patient Progress\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient Medical Record\",\n\t\t\"label\": \"Patient Medical Record\"\n\t}\n]"
},
{
"hidden": 0,
@@ -64,7 +69,7 @@
"idx": 0,
"is_standard": 1,
"label": "Healthcare",
- "modified": "2020-11-23 23:00:48.764377",
+ "modified": "2020-11-26 22:09:09.164584",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Healthcare",
diff --git a/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.js b/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.js
index f523cf21bd..ca97489b8d 100644
--- a/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.js
+++ b/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.js
@@ -29,6 +29,29 @@ frappe.ui.form.on('Inpatient Medication Entry', {
}
};
});
+
+ if (frm.doc.__islocal || frm.doc.docstatus !== 0 || !frm.doc.update_stock)
+ return;
+
+ frm.add_custom_button(__('Make Stock Entry'), function() {
+ frappe.call({
+ method: 'erpnext.healthcare.doctype.inpatient_medication_entry.inpatient_medication_entry.make_difference_stock_entry',
+ args: { docname: frm.doc.name },
+ freeze: true,
+ callback: function(r) {
+ if (r.message) {
+ var doclist = frappe.model.sync(r.message);
+ frappe.set_route('Form', doclist[0].doctype, doclist[0].name);
+ } else {
+ frappe.msgprint({
+ title: __('No Drug Shortage'),
+ message: __('All the drugs are available with sufficient qty to process this Inpatient Medication Entry.'),
+ indicator: 'green'
+ });
+ }
+ }
+ });
+ });
},
patient: function(frm) {
diff --git a/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.py b/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.py
index 5dac23abd9..70ae713866 100644
--- a/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.py
+++ b/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.py
@@ -142,25 +142,32 @@ class InpatientMedicationEntry(Document):
return orders, order_entry_map
def check_stock_qty(self):
- from erpnext.stock.stock_ledger import NegativeStockError
+ drug_shortage = get_drug_shortage_map(self.medication_orders, self.warehouse)
- drug_availability = dict()
- for d in self.medication_orders:
- if not drug_availability.get(d.drug_code):
- drug_availability[d.drug_code] = 0
- drug_availability[d.drug_code] += flt(d.dosage)
+ if drug_shortage:
+ message = _('Quantity not available for the following items in warehouse {0}. ').format(frappe.bold(self.warehouse))
+ message += _('Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.')
- for drug, dosage in drug_availability.items():
- available_qty = get_latest_stock_qty(drug, self.warehouse)
+ formatted_item_rows = ''
- # validate qty
- if flt(available_qty) < flt(dosage):
- frappe.throw(_('Quantity not available for {0} in warehouse {1}').format(
- frappe.bold(drug), frappe.bold(self.warehouse))
- + '
' + _('Available quantity is {0}, you need {1}').format(
- frappe.bold(available_qty), frappe.bold(dosage))
- + '
' + _('Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.'),
- NegativeStockError, title=_('Insufficient Stock'))
+ for drug, shortage_qty in drug_shortage.items():
+ item_link = get_link_to_form('Item', drug)
+ formatted_item_rows += """
+