Merge pull request #19533 from rohitwaghchaure/fixed_precision_issue_while_updating_qty_and_rate
fix: precision issue
diff --git a/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py b/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py
index d098d84..716bef3 100644
--- a/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py
+++ b/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py
@@ -19,6 +19,11 @@
else:
chart = frappe._dict(frappe.parse_json(chart))
timespan = chart.timespan
+
+ if chart.timespan == 'Select Date Range':
+ from_date = chart.from_date
+ to_date = chart.to_date
+
timegrain = chart.time_interval
filters = frappe.parse_json(chart.filters_json)
diff --git a/erpnext/accounts/deferred_revenue.py b/erpnext/accounts/deferred_revenue.py
index 32485a3..62a8f05 100644
--- a/erpnext/accounts/deferred_revenue.py
+++ b/erpnext/accounts/deferred_revenue.py
@@ -174,6 +174,8 @@
# GL Entry for crediting the amount in the deferred expense
from erpnext.accounts.general_ledger import make_gl_entries
+ if amount == 0: return
+
gl_entries = []
gl_entries.append(
doc.get_gl_dict({
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
index af51fc5..522ed4f 100644
--- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
@@ -24,6 +24,11 @@
msg = _("Not allowed to create accounting dimension for {0}").format(self.document_type)
frappe.throw(msg)
+ exists = frappe.db.get_value("Accounting Dimension", {'document_type': self.document_type}, ['name'])
+
+ if exists and self.is_new():
+ frappe.throw("Document Type already used as a dimension")
+
def after_insert(self):
if frappe.flags.in_test:
make_dimension_in_accounting_doctypes(doc=self)
@@ -60,7 +65,8 @@
"label": doc.label,
"fieldtype": "Link",
"options": doc.document_type,
- "insert_after": insert_after_field
+ "insert_after": insert_after_field,
+ "owner": "Administrator"
}
if doctype == "Budget":
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js
index 11d847d..221e3a7 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.js
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js
@@ -570,7 +570,7 @@
},
{fieldtype: "Date", fieldname: "posting_date", label: __("Date"), reqd: 1,
default: frm.doc.posting_date},
- {fieldtype: "Small Text", fieldname: "user_remark", label: __("User Remark"), reqd: 1},
+ {fieldtype: "Small Text", fieldname: "user_remark", label: __("User Remark")},
{fieldtype: "Select", fieldname: "naming_series", label: __("Series"), reqd: 1,
options: naming_series_options, default: naming_series_default},
]
diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py
index ce8aba7..54464e7 100644
--- a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py
+++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py
@@ -32,8 +32,10 @@
})
invoices_summary.update({company: _summary})
- paid_amount.append(invoice.paid_amount)
- outstanding_amount.append(invoice.outstanding_amount)
+ if invoice.paid_amount:
+ paid_amount.append(invoice.paid_amount)
+ if invoice.outstanding_amount:
+ outstanding_amount.append(invoice.outstanding_amount)
if paid_amount or outstanding_amount:
max_count.update({
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.json b/erpnext/accounts/doctype/payment_entry/payment_entry.json
index a85eccd..acfc660 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.json
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.json
@@ -62,6 +62,7 @@
"dimension_col_break",
"cost_center",
"section_break_12",
+ "status",
"remarks",
"column_break_16",
"letter_head",
@@ -563,10 +564,18 @@
{
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
+ },
+ {
+ "default": "Draft",
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "label": "Status",
+ "options": "\nDraft\nSubmitted\nCancelled",
+ "read_only": 1
}
],
"is_submittable": 1,
- "modified": "2019-05-27 15:53:21.108857",
+ "modified": "2019-11-06 12:59:43.151721",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry",
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 89aaffb..bf7e833 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -61,6 +61,7 @@
self.validate_duplicate_entry()
self.validate_allocated_amount()
self.ensure_supplier_is_not_blocked()
+ self.set_status()
def on_submit(self):
self.setup_party_account_field()
@@ -70,6 +71,7 @@
self.update_outstanding_amounts()
self.update_advance_paid()
self.update_expense_claim()
+ self.set_status()
def on_cancel(self):
@@ -79,6 +81,7 @@
self.update_advance_paid()
self.update_expense_claim()
self.delink_advance_entry_references()
+ self.set_status()
def update_outstanding_amounts(self):
self.set_missing_ref_details(force=True)
@@ -275,6 +278,14 @@
frappe.throw(_("Against Journal Entry {0} does not have any unmatched {1} entry")
.format(d.reference_name, dr_or_cr))
+ def set_status(self):
+ if self.docstatus == 2:
+ self.status = 'Cancelled'
+ elif self.docstatus == 1:
+ self.status = 'Submitted'
+ else:
+ self.status = 'Draft'
+
def set_amounts(self):
self.set_amounts_in_company_currency()
self.set_total_allocated_amount()
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
index 4665d75..d85344e 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
@@ -90,7 +90,8 @@
FROM `tab{doc}`, `tabGL Entry`
WHERE
(`tab{doc}`.name = `tabGL Entry`.against_voucher or `tab{doc}`.name = `tabGL Entry`.voucher_no)
- and `tab{doc}`.is_return = 1 and `tabGL Entry`.against_voucher_type = %(voucher_type)s
+ and `tab{doc}`.is_return = 1 and `tab{doc}`.return_against IS NULL
+ and `tabGL Entry`.against_voucher_type = %(voucher_type)s
and `tab{doc}`.docstatus = 1 and `tabGL Entry`.party = %(party)s
and `tabGL Entry`.party_type = %(party_type)s and `tabGL Entry`.account = %(account)s
GROUP BY `tab{doc}`.name
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 4ea9b1c..9c1a9ec 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -25,6 +25,7 @@
unlink_inter_company_doc
from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import get_party_tax_withholding_details
from erpnext.accounts.deferred_revenue import validate_service_stop_date
+from erpnext.stock.doctype.purchase_receipt.purchase_receipt import get_item_account_wise_additional_cost
form_grid_templates = {
"items": "templates/form_grid/item_grid.html"
@@ -436,6 +437,8 @@
if self.update_stock and self.auto_accounting_for_stock:
warehouse_account = get_warehouse_account_map(self.company)
+ landed_cost_entries = get_item_account_wise_additional_cost(self.name)
+
voucher_wise_stock_value = {}
if self.update_stock:
for d in frappe.get_all('Stock Ledger Entry',
@@ -463,15 +466,16 @@
)
# Amount added through landed-cost-voucher
- if flt(item.landed_cost_voucher_amount):
- gl_entries.append(self.get_gl_dict({
- "account": expenses_included_in_valuation,
- "against": item.expense_account,
- "cost_center": item.cost_center,
- "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
- "credit": flt(item.landed_cost_voucher_amount),
- "project": item.project
- }, item=item))
+ if landed_cost_entries:
+ for account, amount in iteritems(landed_cost_entries[(item.item_code, item.name)]):
+ gl_entries.append(self.get_gl_dict({
+ "account": account,
+ "against": item.expense_account,
+ "cost_center": item.cost_center,
+ "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
+ "credit": flt(amount),
+ "project": item.project
+ }, item=item))
# sub-contracting warehouse
if flt(item.rm_supp_cost):
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js
index 4e76a8d..800ed92 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js
@@ -6,8 +6,8 @@
add_fields: ["supplier", "supplier_name", "base_grand_total", "outstanding_amount", "due_date", "company",
"currency", "is_return", "release_date", "on_hold"],
get_indicator: function(doc) {
- if(flt(doc.outstanding_amount) < 0 && doc.docstatus == 1) {
- return [__("Debit Note Issued"), "darkgrey", "outstanding_amount,<,0"]
+ if( (flt(doc.outstanding_amount) <= 0) && doc.docstatus == 1 && doc.status == 'Debit Note Issued') {
+ return [__("Debit Note Issued"), "darkgrey", "outstanding_amount,<=,0"];
} else if(flt(doc.outstanding_amount) > 0 && doc.docstatus==1) {
if(cint(doc.on_hold) && !doc.release_date) {
return [__("On Hold"), "darkgrey"];
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 5766c9a..0ebca8b 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -1230,7 +1230,8 @@
self.status = "Unpaid and Discounted"
elif flt(self.outstanding_amount) > 0 and getdate(self.due_date) >= getdate(nowdate()):
self.status = "Unpaid"
- elif flt(self.outstanding_amount) < 0 and self.is_return==0 and frappe.db.get_value('Sales Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1}):
+ #Check if outstanding amount is 0 due to credit note issued against invoice
+ elif flt(self.outstanding_amount) <= 0 and self.is_return == 0 and frappe.db.get_value('Sales Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1}):
self.status = "Credit Note Issued"
elif self.is_return == 1:
self.status = "Return"
diff --git a/erpnext/accounts/doctype/share_transfer/share_transfer.js b/erpnext/accounts/doctype/share_transfer/share_transfer.js
index 364ca6f..1cad4df 100644
--- a/erpnext/accounts/doctype/share_transfer/share_transfer.js
+++ b/erpnext/accounts/doctype/share_transfer/share_transfer.js
@@ -21,6 +21,8 @@
erpnext.share_transfer.make_jv(frm);
});
}
+
+ frm.toggle_reqd("asset_account", frm.doc.transfer_type != "Transfer");
},
no_of_shares: (frm) => {
if (frm.doc.rate != undefined || frm.doc.rate != null){
@@ -56,6 +58,10 @@
};
});
}
+ },
+
+ transfer_type: function(frm) {
+ frm.toggle_reqd("asset_account", frm.doc.transfer_type != "Transfer");
}
});
diff --git a/erpnext/accounts/doctype/share_transfer/share_transfer.json b/erpnext/accounts/doctype/share_transfer/share_transfer.json
index 24c4569..f17bf04 100644
--- a/erpnext/accounts/doctype/share_transfer/share_transfer.json
+++ b/erpnext/accounts/doctype/share_transfer/share_transfer.json
@@ -1,881 +1,239 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "ACC-SHT-.YYYY.-.#####",
- "beta": 0,
- "creation": "2017-12-25 17:18:03.143726",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "autoname": "ACC-SHT-.YYYY.-.#####",
+ "creation": "2017-12-25 17:18:03.143726",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "transfer_type",
+ "column_break_1",
+ "date",
+ "section_break_1",
+ "from_shareholder",
+ "from_folio_no",
+ "column_break_3",
+ "to_shareholder",
+ "to_folio_no",
+ "section_break_10",
+ "equity_or_liability_account",
+ "column_break_12",
+ "asset_account",
+ "section_break_4",
+ "share_type",
+ "from_no",
+ "rate",
+ "column_break_8",
+ "no_of_shares",
+ "to_no",
+ "amount",
+ "section_break_11",
+ "company",
+ "section_break_6",
+ "remarks",
+ "amended_from"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "transfer_type",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Transfer Type",
- "length": 0,
- "no_copy": 0,
- "options": "\nIssue\nPurchase\nTransfer",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "transfer_type",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Transfer Type",
+ "options": "\nIssue\nPurchase\nTransfer",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_1",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_1",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "date",
+ "fieldtype": "Date",
+ "label": "Date",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_1",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_1",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.transfer_type != 'Issue'",
- "fieldname": "from_shareholder",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "From Shareholder",
- "length": 0,
- "no_copy": 0,
- "options": "Shareholder",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.transfer_type != 'Issue'",
+ "fieldname": "from_shareholder",
+ "fieldtype": "Link",
+ "label": "From Shareholder",
+ "options": "Shareholder"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.transfer_type != 'Issue'",
- "fetch_from": "from_shareholder.folio_no",
- "fieldname": "from_folio_no",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "From Folio No",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.transfer_type != 'Issue'",
+ "fetch_from": "from_shareholder.folio_no",
+ "fieldname": "from_folio_no",
+ "fieldtype": "Data",
+ "label": "From Folio No"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.company",
- "fieldname": "equity_or_liability_account",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Equity/Liability Account",
- "length": 0,
- "no_copy": 0,
- "options": "Account",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.company",
+ "fieldname": "equity_or_liability_account",
+ "fieldtype": "Link",
+ "label": "Equity/Liability Account",
+ "options": "Account",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:(doc.transfer_type != 'Transfer') && (doc.company)",
- "fieldname": "asset_account",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Asset Account",
- "length": 0,
- "no_copy": 0,
- "options": "Account",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:(doc.transfer_type != 'Transfer') && (doc.company)",
+ "fieldname": "asset_account",
+ "fieldtype": "Link",
+ "label": "Asset Account",
+ "options": "Account"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_3",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.transfer_type != 'Purchase'",
- "fieldname": "to_shareholder",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "To Shareholder",
- "length": 0,
- "no_copy": 0,
- "options": "Shareholder",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.transfer_type != 'Purchase'",
+ "fieldname": "to_shareholder",
+ "fieldtype": "Link",
+ "label": "To Shareholder",
+ "options": "Shareholder"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.transfer_type != 'Purchase'",
- "fetch_from": "to_shareholder.folio_no",
- "fieldname": "to_folio_no",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "To Folio No",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.transfer_type != 'Purchase'",
+ "fetch_from": "to_shareholder.folio_no",
+ "fieldname": "to_folio_no",
+ "fieldtype": "Data",
+ "label": "To Folio No"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_4",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_4",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "share_type",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Share Type",
- "length": 0,
- "no_copy": 0,
- "options": "Share Type",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "share_type",
+ "fieldtype": "Link",
+ "label": "Share Type",
+ "options": "Share Type",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "(including)",
- "fieldname": "from_no",
- "fieldtype": "Int",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "From No",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "description": "(including)",
+ "fieldname": "from_no",
+ "fieldtype": "Int",
+ "label": "From No",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "rate",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Rate",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "rate",
+ "fieldtype": "Currency",
+ "label": "Rate",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_8",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_8",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "no_of_shares",
- "fieldtype": "Int",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "No of Shares",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "no_of_shares",
+ "fieldtype": "Int",
+ "label": "No of Shares",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "(including)",
- "fieldname": "to_no",
- "fieldtype": "Int",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "To No",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "description": "(including)",
+ "fieldname": "to_no",
+ "fieldtype": "Int",
+ "label": "To No",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amount",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "amount",
+ "fieldtype": "Currency",
+ "label": "Amount",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_11",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_11",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_6",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_6",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "remarks",
- "fieldtype": "Long Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Remarks",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "remarks",
+ "fieldtype": "Long Text",
+ "label": "Remarks"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amended From",
- "length": 0,
- "no_copy": 1,
- "options": "Share Transfer",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Share Transfer",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "section_break_10",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "column_break_12",
+ "fieldtype": "Column Break"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-09-18 14:14:46.233568",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Share Transfer",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "is_submittable": 1,
+ "modified": "2019-11-07 13:31:17.999744",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Share Transfer",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 1,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Accounts User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts User",
+ "share": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Accounts Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts Manager",
+ "share": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.js b/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.js
index 6eafa0d..854b973 100644
--- a/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.js
+++ b/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.js
@@ -139,15 +139,11 @@
}
make() {
- const me = this;
- frappe.upload.make({
- args: {
- method: 'erpnext.accounts.doctype.bank_transaction.bank_transaction_upload.upload_bank_statement',
- allow_multiple: 0
- },
- no_socketio: true,
- sample_url: "e.g. http://example.com/somefile.csv",
- callback: function(attachment, r) {
+ const me = this;
+ new frappe.ui.FileUploader({
+ method: 'erpnext.accounts.doctype.bank_transaction.bank_transaction_upload.upload_bank_statement',
+ allow_multiple: 0,
+ on_success: function(attachment, r) {
if (!r.exc && r.message) {
me.data = r.message;
me.setup_transactions_dom();
@@ -575,4 +571,4 @@
}
}
-}
\ No newline at end of file
+}
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
index 228be18..9b4dda2 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
@@ -79,13 +79,20 @@
"options": "Customer",
on_change: () => {
var customer = frappe.query_report.get_filter_value('customer');
+ var company = frappe.query_report.get_filter_value('company');
if (customer) {
- frappe.db.get_value('Customer', customer, ["tax_id", "customer_name", "credit_limit", "payment_terms"], function(value) {
+ frappe.db.get_value('Customer', customer, ["tax_id", "customer_name", "payment_terms"], function(value) {
frappe.query_report.set_filter_value('tax_id', value["tax_id"]);
frappe.query_report.set_filter_value('customer_name', value["customer_name"]);
- frappe.query_report.set_filter_value('credit_limit', value["credit_limit"]);
frappe.query_report.set_filter_value('payment_terms', value["payment_terms"]);
});
+
+ frappe.db.get_value('Customer Credit Limit', {'parent': customer, 'company': company},
+ ["credit_limit"], function(value) {
+ if (value) {
+ frappe.query_report.set_filter_value('credit_limit', value["credit_limit"]);
+ }
+ }, "Customer");
} else {
frappe.query_report.set_filter_value('tax_id', "");
frappe.query_report.set_filter_value('customer_name', "");
diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py
index 9d1389c..2b2c27b 100644
--- a/erpnext/controllers/status_updater.py
+++ b/erpnext/controllers/status_updater.py
@@ -49,7 +49,8 @@
["Submitted", "eval:self.docstatus==1"],
["Paid", "eval:self.outstanding_amount==0 and self.docstatus==1"],
["Return", "eval:self.is_return==1 and self.docstatus==1"],
- ["Debit Note Issued", "eval:self.outstanding_amount < 0 and self.docstatus==1"],
+ ["Debit Note Issued",
+ "eval:self.outstanding_amount <= 0 and self.docstatus==1 and self.is_return==0 and get_value('Purchase Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1})"],
["Unpaid", "eval:self.outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()) and self.docstatus==1"],
["Overdue", "eval:self.outstanding_amount > 0 and getdate(self.due_date) < getdate(nowdate()) and self.docstatus==1"],
["Cancelled", "eval:self.docstatus==2"],
@@ -118,7 +119,6 @@
if self.doctype in status_map:
_status = self.status
-
if status and update:
self.db_set("status", status)
diff --git a/erpnext/education/doctype/education_settings/education_settings.json b/erpnext/education/doctype/education_settings/education_settings.json
index 32b5fb8..967a030 100644
--- a/erpnext/education/doctype/education_settings/education_settings.json
+++ b/erpnext/education/doctype/education_settings/education_settings.json
@@ -11,6 +11,7 @@
"validate_batch",
"validate_course",
"academic_term_reqd",
+ "user_creation_skip",
"section_break_7",
"instructor_created_by",
"web_academy_settings_section",
@@ -91,6 +92,13 @@
"fieldname": "enable_lms",
"fieldtype": "Check",
"label": "Enable LMS"
+ },
+ {
+ "default": "0",
+ "description": "By default, a new User is created for every new Student. If enabled, no new User will be created when a new Student is created.",
+ "fieldname": "user_creation_skip",
+ "fieldtype": "Check",
+ "label": "Skip User creation for new Student"
}
],
"issingle": 1,
@@ -133,4 +141,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/education/doctype/student/student.py b/erpnext/education/doctype/student/student.py
index 705c6e4..9af5e22 100644
--- a/erpnext/education/doctype/student/student.py
+++ b/erpnext/education/doctype/student/student.py
@@ -40,7 +40,8 @@
frappe.throw(_("Student {0} exist against student applicant {1}").format(student[0][0], self.student_applicant))
def after_insert(self):
- self.create_student_user()
+ if not frappe.get_single('Education Settings').user_creation_skip:
+ self.create_student_user()
def create_student_user(self):
"""Create a website user for student creation if not already exists"""
diff --git a/erpnext/erpnext_integrations/connectors/woocommerce_connection.py b/erpnext/erpnext_integrations/connectors/woocommerce_connection.py
index 0b6ea8c..28c2ab9 100644
--- a/erpnext/erpnext_integrations/connectors/woocommerce_connection.py
+++ b/erpnext/erpnext_integrations/connectors/woocommerce_connection.py
@@ -1,10 +1,8 @@
from __future__ import unicode_literals
import frappe, base64, hashlib, hmac, json
-import datetime
from frappe import _
-
def verify_request():
woocommerce_settings = frappe.get_doc("Woocommerce Settings")
sig = base64.b64encode(
@@ -30,191 +28,149 @@
frappe.log_error(error_message, "WooCommerce Error")
raise
-
def _order(*args, **kwargs):
woocommerce_settings = frappe.get_doc("Woocommerce Settings")
if frappe.flags.woocomm_test_order_data:
- fd = frappe.flags.woocomm_test_order_data
+ order = frappe.flags.woocomm_test_order_data
event = "created"
elif frappe.request and frappe.request.data:
verify_request()
- fd = json.loads(frappe.request.data)
+ try:
+ order = json.loads(frappe.request.data)
+ except ValueError:
+ #woocommerce returns 'webhook_id=value' for the first request which is not JSON
+ order = frappe.request.data
event = frappe.get_request_header("X-Wc-Webhook-Event")
else:
return "success"
if event == "created":
- raw_billing_data = fd.get("billing")
- customer_woo_com_email = raw_billing_data.get("email")
-
- if frappe.get_value("Customer",{"woocommerce_email": customer_woo_com_email}):
- # Edit
- link_customer_and_address(raw_billing_data,1)
- else:
- # Create
- link_customer_and_address(raw_billing_data,0)
-
-
- items_list = fd.get("line_items")
- for item in items_list:
-
- item_woo_com_id = item.get("product_id")
-
- if frappe.get_value("Item",{"woocommerce_id": item_woo_com_id}):
- #Edit
- link_item(item,1)
- else:
- link_item(item,0)
-
-
+ raw_billing_data = order.get("billing")
customer_name = raw_billing_data.get("first_name") + " " + raw_billing_data.get("last_name")
+ link_customer_and_address(raw_billing_data, customer_name)
+ link_items(order.get("line_items"), woocommerce_settings)
+ create_sales_order(order, woocommerce_settings, customer_name)
- new_sales_order = frappe.new_doc("Sales Order")
- new_sales_order.customer = customer_name
-
- created_date = fd.get("date_created").split("T")
- new_sales_order.transaction_date = created_date[0]
-
- new_sales_order.po_no = fd.get("id")
- new_sales_order.woocommerce_id = fd.get("id")
- new_sales_order.naming_series = woocommerce_settings.sales_order_series or "SO-WOO-"
-
- placed_order_date = created_date[0]
- raw_date = datetime.datetime.strptime(placed_order_date, "%Y-%m-%d")
- raw_delivery_date = frappe.utils.add_to_date(raw_date,days = 7)
- order_delivery_date_str = raw_delivery_date.strftime('%Y-%m-%d')
- order_delivery_date = str(order_delivery_date_str)
-
- new_sales_order.delivery_date = order_delivery_date
- default_set_company = frappe.get_doc("Global Defaults")
- company = raw_billing_data.get("company") or default_set_company.default_company
- found_company = frappe.get_doc("Company",{"name":company})
- company_abbr = found_company.abbr
-
- new_sales_order.company = company
-
- for item in items_list:
- woocomm_item_id = item.get("product_id")
- found_item = frappe.get_doc("Item",{"woocommerce_id": woocomm_item_id})
-
- ordered_items_tax = item.get("total_tax")
-
- new_sales_order.append("items",{
- "item_code": found_item.item_code,
- "item_name": found_item.item_name,
- "description": found_item.item_name,
- "delivery_date":order_delivery_date,
- "uom": woocommerce_settings.uom or _("Nos"),
- "qty": item.get("quantity"),
- "rate": item.get("price"),
- "warehouse": woocommerce_settings.warehouse or "Stores" + " - " + company_abbr
- })
-
- add_tax_details(new_sales_order,ordered_items_tax,"Ordered Item tax",0)
-
- # shipping_details = fd.get("shipping_lines") # used for detailed order
- shipping_total = fd.get("shipping_total")
- shipping_tax = fd.get("shipping_tax")
-
- add_tax_details(new_sales_order,shipping_tax,"Shipping Tax",1)
- add_tax_details(new_sales_order,shipping_total,"Shipping Total",1)
-
- new_sales_order.submit()
-
- frappe.db.commit()
-
-def link_customer_and_address(raw_billing_data,customer_status):
-
- if customer_status == 0:
- # create
+def link_customer_and_address(raw_billing_data, customer_name):
+ customer_woo_com_email = raw_billing_data.get("email")
+ customer_exists = frappe.get_value("Customer", {"woocommerce_email": customer_woo_com_email})
+ if not customer_exists:
+ # Create Customer
customer = frappe.new_doc("Customer")
- address = frappe.new_doc("Address")
-
- if customer_status == 1:
- # Edit
- customer_woo_com_email = raw_billing_data.get("email")
- customer = frappe.get_doc("Customer",{"woocommerce_email": customer_woo_com_email})
+ else:
+ # Edit Customer
+ customer = frappe.get_doc("Customer", {"woocommerce_email": customer_woo_com_email})
old_name = customer.customer_name
- full_name = str(raw_billing_data.get("first_name"))+ " "+str(raw_billing_data.get("last_name"))
- customer.customer_name = full_name
- customer.woocommerce_email = str(raw_billing_data.get("email"))
- customer.save()
- frappe.db.commit()
+ customer.customer_name = customer_name
+ customer.woocommerce_email = customer_woo_com_email
+ customer.flags.ignore_mandatory = True
+ customer.save()
- if customer_status == 1:
- frappe.rename_doc("Customer", old_name, full_name)
- address = frappe.get_doc("Address",{"woocommerce_email":customer_woo_com_email})
- customer = frappe.get_doc("Customer",{"woocommerce_email": customer_woo_com_email})
+ if customer_exists:
+ frappe.rename_doc("Customer", old_name, customer_name)
+ address = frappe.get_doc("Address", {"woocommerce_email": customer_woo_com_email})
+ else:
+ address = frappe.new_doc("Address")
address.address_line1 = raw_billing_data.get("address_1", "Not Provided")
address.address_line2 = raw_billing_data.get("address_2", "Not Provided")
address.city = raw_billing_data.get("city", "Not Provided")
- address.woocommerce_email = str(raw_billing_data.get("email"))
- address.address_type = "Shipping"
- address.country = frappe.get_value("Country", filters={"code":raw_billing_data.get("country", "IN").lower()})
- address.state = raw_billing_data.get("state")
- address.pincode = str(raw_billing_data.get("postcode"))
- address.phone = str(raw_billing_data.get("phone"))
- address.email_id = str(raw_billing_data.get("email"))
-
+ address.woocommerce_email = customer_woo_com_email
+ address.address_type = "Billing"
+ address.country = frappe.get_value("Country", {"code": raw_billing_data.get("country", "IN").lower()})
+ address.state = raw_billing_data.get("state")
+ address.pincode = raw_billing_data.get("postcode")
+ address.phone = raw_billing_data.get("phone")
+ address.email_id = customer_woo_com_email
address.append("links", {
"link_doctype": "Customer",
"link_name": customer.customer_name
})
+ address.flags.ignore_mandatory = True
+ address = address.save()
- address.save()
- frappe.db.commit()
-
- if customer_status == 1:
-
- address = frappe.get_doc("Address",{"woocommerce_email":customer_woo_com_email})
+ if customer_exists:
old_address_title = address.name
- new_address_title = customer.customer_name+"-billing"
+ new_address_title = customer.customer_name + "-billing"
address.address_title = customer.customer_name
address.save()
- frappe.rename_doc("Address",old_address_title,new_address_title)
+ frappe.rename_doc("Address", old_address_title, new_address_title)
- frappe.db.commit()
-
-def link_item(item_data,item_status):
- woocommerce_settings = frappe.get_doc("Woocommerce Settings")
-
- if item_status == 0:
- #Create Item
- item = frappe.new_doc("Item")
-
- if item_status == 1:
- #Edit Item
+def link_items(items_list, woocommerce_settings):
+ for item_data in items_list:
item_woo_com_id = item_data.get("product_id")
- item = frappe.get_doc("Item",{"woocommerce_id": item_woo_com_id})
- item.item_name = str(item_data.get("name"))
- item.item_code = "woocommerce - " + str(item_data.get("product_id"))
- item.woocommerce_id = str(item_data.get("product_id"))
- item.item_group = _("WooCommerce Products")
- item.stock_uom = woocommerce_settings.uom or _("Nos")
- item.save()
+ if frappe.get_value("Item", {"woocommerce_id": item_woo_com_id}):
+ #Edit Item
+ item = frappe.get_doc("Item", {"woocommerce_id": item_woo_com_id})
+ else:
+ #Create Item
+ item = frappe.new_doc("Item")
+
+ item.item_name = item_data.get("name")
+ item.item_code = _("woocommerce - {0}").format(item_data.get("product_id"))
+ item.woocommerce_id = item_data.get("product_id")
+ item.item_group = _("WooCommerce Products")
+ item.stock_uom = woocommerce_settings.uom or _("Nos")
+ item.flags.ignore_mandatory = True
+ item.save()
+
+def create_sales_order(order, woocommerce_settings, customer_name):
+ new_sales_order = frappe.new_doc("Sales Order")
+ new_sales_order.customer = customer_name
+
+ new_sales_order.po_no = new_sales_order.woocommerce_id = order.get("id")
+ new_sales_order.naming_series = woocommerce_settings.sales_order_series or "SO-WOO-"
+
+ created_date = order.get("date_created").split("T")
+ new_sales_order.transaction_date = created_date[0]
+ delivery_after = woocommerce_settings.delivery_after_days or 7
+ new_sales_order.delivery_date = frappe.utils.add_days(created_date[0], delivery_after)
+
+ new_sales_order.company = woocommerce_settings.company
+
+ set_items_in_sales_order(new_sales_order, woocommerce_settings, order)
+ new_sales_order.flags.ignore_mandatory = True
+ new_sales_order.insert()
+ new_sales_order.submit()
+
frappe.db.commit()
-def add_tax_details(sales_order,price,desc,status):
+def set_items_in_sales_order(new_sales_order, woocommerce_settings, order):
+ company_abbr = frappe.db.get_value('Company', woocommerce_settings.company, 'abbr')
- woocommerce_settings = frappe.get_doc("Woocommerce Settings")
+ for item in order.get("line_items"):
+ woocomm_item_id = item.get("product_id")
+ found_item = frappe.get_doc("Item", {"woocommerce_id": woocomm_item_id})
- if status == 0:
- # Product taxes
- account_head_type = woocommerce_settings.tax_account
+ ordered_items_tax = item.get("total_tax")
- if status == 1:
- # Shipping taxes
- account_head_type = woocommerce_settings.f_n_f_account
+ new_sales_order.append("items",{
+ "item_code": found_item.item_code,
+ "item_name": found_item.item_name,
+ "description": found_item.item_name,
+ "delivery_date": new_sales_order.delivery_date,
+ "uom": woocommerce_settings.uom or _("Nos"),
+ "qty": item.get("quantity"),
+ "rate": item.get("price"),
+ "warehouse": woocommerce_settings.warehouse or _("Stores - {0}").format(company_abbr)
+ })
- sales_order.append("taxes",{
- "charge_type":"Actual",
- "account_head": account_head_type,
- "tax_amount": price,
- "description": desc
- })
+ add_tax_details(new_sales_order, ordered_items_tax, "Ordered Item tax", woocommerce_settings.tax_account)
+
+ # shipping_details = order.get("shipping_lines") # used for detailed order
+
+ add_tax_details(new_sales_order, order.get("shipping_tax"), "Shipping Tax", woocommerce_settings.f_n_f_account)
+ add_tax_details(new_sales_order, order.get("shipping_total"), "Shipping Total", woocommerce_settings.f_n_f_account)
+
+def add_tax_details(sales_order, price, desc, tax_account_head):
+ sales_order.append("taxes", {
+ "charge_type":"Actual",
+ "account_head": tax_account_head,
+ "tax_amount": price,
+ "description": desc
+ })
diff --git a/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.json b/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.json
index dd3c24d..956ae09 100644
--- a/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.json
+++ b/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.json
@@ -1,694 +1,175 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
"creation": "2018-02-12 15:10:05.495713",
- "custom": 0,
- "docstatus": 0,
"doctype": "DocType",
- "document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
+ "field_order": [
+ "enable_sync",
+ "sb_00",
+ "woocommerce_server_url",
+ "secret",
+ "cb_00",
+ "api_consumer_key",
+ "api_consumer_secret",
+ "sb_accounting_details",
+ "tax_account",
+ "column_break_10",
+ "f_n_f_account",
+ "defaults_section",
+ "creation_user",
+ "warehouse",
+ "sales_order_series",
+ "column_break_14",
+ "company",
+ "delivery_after_days",
+ "uom",
+ "endpoints",
+ "endpoint"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
+ "default": "0",
"fieldname": "enable_sync",
"fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Enable Sync",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "label": "Enable Sync"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "sb_00",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Section Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "woocommerce_server_url",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Woocommerce Server URL",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "label": "Woocommerce Server URL"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "secret",
"fieldtype": "Code",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Secret",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "cb_00",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "api_consumer_key",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
- "in_standard_filter": 0,
- "label": "API consumer key",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "label": "API consumer key"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "api_consumer_secret",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
- "in_standard_filter": 0,
- "label": "API consumer secret",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "label": "API consumer secret"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "sb_accounting_details",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Accounting Details",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "label": "Accounting Details"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "tax_account",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Tax Account",
- "length": 0,
- "no_copy": 0,
"options": "Account",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "column_break_10",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "f_n_f_account",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Freight and Forwarding Account",
- "length": 0,
- "no_copy": 0,
"options": "Account",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "defaults_section",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Defaults",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "label": "Defaults"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"description": "The user that will be used to create Customers, Items and Sales Orders. This user should have the relevant permissions.",
- "fetch_if_empty": 0,
"fieldname": "creation_user",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Creation User",
- "length": 0,
- "no_copy": 0,
"options": "User",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "This warehouse will be used to create Sale Orders. The fallback warehouse is \"Stores\".",
- "fetch_if_empty": 0,
+ "description": "This warehouse will be used to create Sales Orders. The fallback warehouse is \"Stores\".",
"fieldname": "warehouse",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Warehouse",
- "length": 0,
- "no_copy": 0,
- "options": "Warehouse",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "options": "Warehouse"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "column_break_14",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"description": "The fallback series is \"SO-WOO-\".",
- "fetch_if_empty": 0,
"fieldname": "sales_order_series",
"fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Sales Order Series",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "label": "Sales Order Series"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"description": "This is the default UOM used for items and Sales orders. The fallback UOM is \"Nos\".",
- "fetch_if_empty": 0,
"fieldname": "uom",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "UOM",
- "length": 0,
- "no_copy": 0,
- "options": "UOM",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "options": "UOM"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "endpoints",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Endpoints",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "label": "Endpoints"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "endpoint",
"fieldtype": "Code",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Endpoint",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
+ },
+ {
+ "description": "This company will be used to create Sales Orders.",
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
+ },
+ {
+ "description": "This is the default offset (days) for the Delivery Date in Sales Orders. The fallback offset is 7 days from the order placement date.",
+ "fieldname": "delivery_after_days",
+ "fieldtype": "Int",
+ "label": "Delivery After (Days)"
}
],
- "has_web_view": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "in_create": 0,
- "is_submittable": 0,
"issingle": 1,
- "istable": 0,
- "max_attachments": 0,
- "menu_index": 0,
- "modified": "2019-04-08 17:04:16.720696",
+ "modified": "2019-11-04 00:45:21.232096",
"modified_by": "Administrator",
"module": "ERPNext Integrations",
"name": "Woocommerce Settings",
- "name_case": "",
"owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
"create": 1,
- "delete": 0,
"email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
- "report": 0,
"role": "System Manager",
- "set_user_permissions": 0,
"share": 1,
- "submit": 0,
"write": 1
}
],
"quick_entry": 1,
- "read_only": 0,
- "show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py b/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py
index 055684d..bd072f4 100644
--- a/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py
+++ b/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py
@@ -8,6 +8,7 @@
from frappe.utils.nestedset import get_root_of
from frappe.model.document import Document
from six.moves.urllib.parse import urlparse
+from frappe.custom.doctype.custom_field.custom_field import create_custom_field
class WoocommerceSettings(Document):
def validate(self):
@@ -17,75 +18,21 @@
def create_delete_custom_fields(self):
if self.enable_sync:
+ custom_fields = {}
# create
- create_custom_field_id_and_check_status = False
- create_custom_field_email_check = False
- names = ["Customer-woocommerce_id","Sales Order-woocommerce_id","Item-woocommerce_id","Address-woocommerce_id"]
- names_check_box = ["Customer-woocommerce_check","Sales Order-woocommerce_check","Item-woocommerce_check","Address-woocommerce_check"]
- email_names = ["Customer-woocommerce_email","Address-woocommerce_email"]
+ for doctype in ["Customer", "Sales Order", "Item", "Address"]:
+ df = dict(fieldname='woocommerce_id', label='Woocommerce ID', fieldtype='Data', read_only=1, print_hide=1)
+ create_custom_field(doctype, df)
- for i in zip(names,names_check_box):
-
- if not frappe.get_value("Custom Field",{"name":i[0]}) or not frappe.get_value("Custom Field",{"name":i[1]}):
- create_custom_field_id_and_check_status = True
- break
-
-
- if create_custom_field_id_and_check_status:
- names = ["Customer","Sales Order","Item","Address"]
- for name in names:
- custom = frappe.new_doc("Custom Field")
- custom.dt = name
- custom.label = "woocommerce_id"
- custom.read_only = 1
- custom.save()
-
- custom = frappe.new_doc("Custom Field")
- custom.dt = name
- custom.label = "woocommerce_check"
- custom.fieldtype = "Check"
- custom.read_only = 1
- custom.save()
-
- for i in email_names:
-
- if not frappe.get_value("Custom Field",{"name":i}):
- create_custom_field_email_check = True
- break;
-
- if create_custom_field_email_check:
- names = ["Customer","Address"]
- for name in names:
- custom = frappe.new_doc("Custom Field")
- custom.dt = name
- custom.label = "woocommerce_email"
- custom.read_only = 1
- custom.save()
-
- if not frappe.get_value("Item Group",{"name": _("WooCommerce Products")}):
+ for doctype in ["Customer", "Address"]:
+ df = dict(fieldname='woocommerce_email', label='Woocommerce Email', fieldtype='Data', read_only=1, print_hide=1)
+ create_custom_field(doctype, df)
+
+ if not frappe.get_value("Item Group", {"name": _("WooCommerce Products")}):
item_group = frappe.new_doc("Item Group")
item_group.item_group_name = _("WooCommerce Products")
item_group.parent_item_group = get_root_of("Item Group")
- item_group.save()
-
-
- elif not self.enable_sync:
- # delete
- names = ["Customer-woocommerce_id","Sales Order-woocommerce_id","Item-woocommerce_id","Address-woocommerce_id"]
- names_check_box = ["Customer-woocommerce_check","Sales Order-woocommerce_check","Item-woocommerce_check","Address-woocommerce_check"]
- email_names = ["Customer-woocommerce_email","Address-woocommerce_email"]
- for name in names:
- frappe.delete_doc("Custom Field",name)
-
- for name in names_check_box:
- frappe.delete_doc("Custom Field",name)
-
- for name in email_names:
- frappe.delete_doc("Custom Field",name)
-
- frappe.delete_doc("Item Group", _("WooCommerce Products"))
-
- frappe.db.commit()
+ item_group.insert()
def validate_settings(self):
if self.enable_sync:
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index b1855ec..9e74bfd 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -235,17 +235,16 @@
("Sales Taxes and Charges Template", 'Price List'): {
"on_update": "erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings.validate_cart_settings"
},
-
"Website Settings": {
"validate": "erpnext.portal.doctype.products_settings.products_settings.home_page_is_products"
},
"Sales Invoice": {
- "on_submit": ["erpnext.regional.france.utils.create_transaction_log", "erpnext.regional.italy.utils.sales_invoice_on_submit"],
+ "on_submit": ["erpnext.regional.create_transaction_log", "erpnext.regional.italy.utils.sales_invoice_on_submit"],
"on_cancel": "erpnext.regional.italy.utils.sales_invoice_on_cancel",
"on_trash": "erpnext.regional.check_deletion_permission"
},
"Payment Entry": {
- "on_submit": ["erpnext.regional.france.utils.create_transaction_log", "erpnext.accounts.doctype.payment_request.payment_request.make_status_as_paid"],
+ "on_submit": ["erpnext.regional.create_transaction_log", "erpnext.accounts.doctype.payment_request.payment_request.make_status_as_paid"],
"on_trash": "erpnext.regional.check_deletion_permission"
},
'Address': {
diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.js b/erpnext/hr/doctype/salary_structure/salary_structure.js
index d56320a..dd34ef2 100755
--- a/erpnext/hr/doctype/salary_structure/salary_structure.js
+++ b/erpnext/hr/doctype/salary_structure/salary_structure.js
@@ -46,10 +46,12 @@
frm.trigger("toggle_fields");
frm.fields_dict['earnings'].grid.set_column_disp("default_amount", false);
frm.fields_dict['deductions'].grid.set_column_disp("default_amount", false);
-
- frm.add_custom_button(__("Preview Salary Slip"), function() {
- frm.trigger('preview_salary_slip');
- });
+
+ if(frm.doc.docstatus === 1) {
+ frm.add_custom_button(__("Preview Salary Slip"), function() {
+ frm.trigger('preview_salary_slip');
+ });
+ }
if(frm.doc.docstatus==1) {
frm.add_custom_button(__("Assign Salary Structure"), function() {
diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.py b/erpnext/hr/doctype/salary_structure/salary_structure.py
index f7d712d..0e1a74f 100644
--- a/erpnext/hr/doctype/salary_structure/salary_structure.py
+++ b/erpnext/hr/doctype/salary_structure/salary_structure.py
@@ -169,5 +169,10 @@
@frappe.whitelist()
def get_employees(salary_structure):
employees = frappe.get_list('Salary Structure Assignment',
- filters={'salary_structure': salary_structure}, fields=['employee'])
+ filters={'salary_structure': salary_structure, 'docstatus': 1}, fields=['employee'])
+
+ if not employees:
+ frappe.throw(_("There's no Employee with Salary Structure: {0}. \
+ Assign {1} to an Employee to preview Salary Slip").format(salary_structure, salary_structure))
+
return list(set([d.employee for d in employees]))
diff --git a/erpnext/hr/report/department_analytics/department_analytics.js b/erpnext/hr/report/department_analytics/department_analytics.js
index a0b6fc7..29fedcd 100644
--- a/erpnext/hr/report/department_analytics/department_analytics.js
+++ b/erpnext/hr/report/department_analytics/department_analytics.js
@@ -2,4 +2,14 @@
// For license information, please see license.txt
frappe.query_reports["Department Analytics"] = {
+ "filters": [
+ {
+ "fieldname":"company",
+ "label": __("Company"),
+ "fieldtype": "Link",
+ "options": "Company",
+ "default": frappe.defaults.get_user_default("Company"),
+ "reqd": 1
+ },
+ ]
};
\ No newline at end of file
diff --git a/erpnext/hr/report/department_analytics/department_analytics.py b/erpnext/hr/report/department_analytics/department_analytics.py
index c4a9030..b28eac4 100644
--- a/erpnext/hr/report/department_analytics/department_analytics.py
+++ b/erpnext/hr/report/department_analytics/department_analytics.py
@@ -7,6 +7,10 @@
def execute(filters=None):
if not filters: filters = {}
+
+ if not filters["company"]:
+ frappe.throw(_('{0} is mandatory').format(_('Company')))
+
columns = get_columns()
employees = get_employees(filters)
departments_result = get_department(filters)
@@ -28,6 +32,9 @@
conditions = ""
if filters.get("department"): conditions += " and department = '%s'" % \
filters["department"].replace("'", "\\'")
+
+ if filters.get("company"): conditions += " and company = '%s'" % \
+ filters["company"].replace("'", "\\'")
return conditions
def get_employees(filters):
@@ -37,7 +44,7 @@
gender, company from `tabEmployee` where status = 'Active' %s""" % conditions, as_list=1)
def get_department(filters):
- return frappe.db.sql("""select name from `tabDepartment`""" , as_list=1)
+ return frappe.db.sql("""select name from `tabDepartment` where company = %s""", (filters["company"]), as_list=1)
def get_chart_data(departments,employees):
if not departments:
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index c849f5b..db79d7f 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -420,8 +420,12 @@
def traverse_tree(self, bom_list=None):
def _get_children(bom_no):
- return frappe.db.sql_list("""select bom_no from `tabBOM Item`
- where parent = %s and ifnull(bom_no, '') != '' and parenttype='BOM'""", bom_no)
+ children = frappe.cache().hget('bom_children', bom_no)
+ if children is None:
+ children = frappe.db.sql_list("""SELECT `bom_no` FROM `tabBOM Item`
+ WHERE `parent`=%s AND `bom_no`!='' AND `parenttype`='BOM'""", bom_no)
+ frappe.cache().hset('bom_children', bom_no, children)
+ return children
count = 0
if not bom_list:
@@ -534,12 +538,24 @@
def get_child_exploded_items(self, bom_no, stock_qty):
""" Add all items from Flat BOM of child BOM"""
# Did not use qty_consumed_per_unit in the query, as it leads to rounding loss
- child_fb_items = frappe.db.sql("""select bom_item.item_code, bom_item.item_name,
- bom_item.description, bom_item.source_warehouse, bom_item.operation,
- bom_item.stock_uom, bom_item.stock_qty, bom_item.rate, bom_item.include_item_in_manufacturing,
- bom_item.stock_qty / ifnull(bom.quantity, 1) as qty_consumed_per_unit
- from `tabBOM Explosion Item` bom_item, tabBOM bom
- where bom_item.parent = bom.name and bom.name = %s and bom.docstatus = 1""", bom_no, as_dict = 1)
+ child_fb_items = frappe.db.sql("""
+ SELECT
+ bom_item.item_code,
+ bom_item.item_name,
+ bom_item.description,
+ bom_item.source_warehouse,
+ bom_item.operation,
+ bom_item.stock_uom,
+ bom_item.stock_qty,
+ bom_item.rate,
+ bom_item.include_item_in_manufacturing,
+ bom_item.stock_qty / ifnull(bom.quantity, 1) AS qty_consumed_per_unit
+ FROM `tabBOM Explosion Item` bom_item, tabBOM bom
+ WHERE
+ bom_item.parent = bom.name
+ AND bom.name = %s
+ AND bom.docstatus = 1
+ """, bom_no, as_dict = 1)
for d in child_fb_items:
self.add_to_cur_exploded_items(frappe._dict({
@@ -760,6 +776,8 @@
# Add non stock items cost in the additional cost
bom = frappe.get_doc('BOM', work_order.bom_no)
table = 'exploded_items' if work_order.get('use_multi_level_bom') else 'items'
+ expenses_included_in_valuation = frappe.get_cached_value("Company", work_order.company,
+ "expenses_included_in_valuation")
items = {}
for d in bom.get(table):
@@ -770,6 +788,7 @@
for name in non_stock_items:
stock_entry.append('additional_costs', {
+ 'expense_account': expenses_included_in_valuation,
'description': name[0],
'amount': items.get(name[0])
})
diff --git a/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py b/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py
index 87b8f67..2ca4d16 100644
--- a/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py
+++ b/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py
@@ -14,23 +14,23 @@
def replace_bom(self):
self.validate_bom()
self.update_new_bom()
+ frappe.cache().delete_key('bom_children')
bom_list = self.get_parent_boms(self.new_bom)
updated_bom = []
for bom in bom_list:
try:
- bom_obj = frappe.get_doc("BOM", bom)
- bom_obj.load_doc_before_save()
- updated_bom = bom_obj.update_cost_and_exploded_items(updated_bom)
+ bom_obj = frappe.get_cached_doc('BOM', bom)
+ # this is only used for versioning and we do not want
+ # to make separate db calls by using load_doc_before_save
+ # which proves to be expensive while doing bulk replace
+ bom_obj._doc_before_save = bom_obj.as_dict()
bom_obj.calculate_cost()
bom_obj.update_parent_cost()
bom_obj.db_update()
- if (getattr(bom_obj.meta, 'track_changes', False) and not bom_obj.flags.ignore_version):
+ if bom_obj.meta.get('track_changes') and not bom_obj.flags.ignore_version:
bom_obj.save_version()
-
- frappe.db.commit()
except Exception:
- frappe.db.rollback()
frappe.log_error(frappe.get_traceback())
def validate_bom(self):
@@ -42,22 +42,22 @@
frappe.throw(_("The selected BOMs are not for the same item"))
def update_new_bom(self):
- new_bom_unitcost = frappe.db.sql("""select total_cost/quantity
- from `tabBOM` where name = %s""", self.new_bom)
+ new_bom_unitcost = frappe.db.sql("""SELECT `total_cost`/`quantity`
+ FROM `tabBOM` WHERE name = %s""", self.new_bom)
new_bom_unitcost = flt(new_bom_unitcost[0][0]) if new_bom_unitcost else 0
frappe.db.sql("""update `tabBOM Item` set bom_no=%s,
rate=%s, amount=stock_qty*%s where bom_no = %s and docstatus < 2 and parenttype='BOM'""",
(self.new_bom, new_bom_unitcost, new_bom_unitcost, self.current_bom))
- def get_parent_boms(self, bom, bom_list=None):
- if not bom_list:
- bom_list = []
-
- data = frappe.db.sql(""" select distinct parent from `tabBOM Item`
- where bom_no = %s and docstatus < 2 and parenttype='BOM'""", bom)
+ def get_parent_boms(self, bom, bom_list=[]):
+ data = frappe.db.sql("""SELECT DISTINCT parent FROM `tabBOM Item`
+ WHERE bom_no = %s AND docstatus < 2 AND parenttype='BOM'""", bom)
for d in data:
+ if self.new_bom == d[0]:
+ frappe.throw(_("BOM recursion: {0} cannot be child of {1}").format(bom, self.new_bom))
+
bom_list.append(d[0])
self.get_parent_boms(d[0], bom_list)
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.js b/erpnext/manufacturing/doctype/production_plan/production_plan.js
index 4b654b4..96bb0ae 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.js
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.js
@@ -233,7 +233,7 @@
if (item_wise_qty) {
for (var key in item_wise_qty) {
- title += __('Item {0}: {1} qty produced, ', [key, item_wise_qty[key]]);
+ title += __('Item {0}: {1} qty produced. ', [key, item_wise_qty[key]]);
}
}
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index b57548e..ae4d9be 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -645,7 +645,8 @@
stock_entry.to_warehouse = work_order.fg_warehouse
stock_entry.project = work_order.project
if purpose=="Manufacture":
- additional_costs = get_additional_costs(work_order, fg_qty=stock_entry.fg_completed_qty)
+ additional_costs = get_additional_costs(work_order, fg_qty=stock_entry.fg_completed_qty,
+ company=work_order.company)
stock_entry.set("additional_costs", additional_costs)
stock_entry.set_stock_entry_type()
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index ee6bdff..047fc85 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -640,4 +640,7 @@
erpnext.patches.v12_0.set_produced_qty_field_in_sales_order_for_work_order
erpnext.patches.v12_0.generate_leave_ledger_entries
erpnext.patches.v12_0.set_default_shopify_app_type
+erpnext.patches.v12_0.set_expense_account_in_landed_cost_voucher_taxes
erpnext.patches.v12_0.replace_accounting_with_accounts_in_home_settings
+erpnext.patches.v12_0.set_payment_entry_status
+erpnext.patches.v12_0.update_owner_fields_in_acc_dimension_custom_fields
diff --git a/erpnext/patches/v11_0/update_delivery_trip_status.py b/erpnext/patches/v11_0/update_delivery_trip_status.py
index 64b3063..42f017e 100755
--- a/erpnext/patches/v11_0/update_delivery_trip_status.py
+++ b/erpnext/patches/v11_0/update_delivery_trip_status.py
@@ -1,27 +1,28 @@
-# Copyright (c) 2017, Frappe and Contributors
-# License: GNU General Public License v3. See license.txt
-
-from __future__ import unicode_literals
-import frappe
-
-def execute():
- frappe.reload_doc('stock', 'doctype', 'delivery_trip')
- frappe.reload_doc('stock', 'doctype', 'delivery_stop', force=True)
-
- for trip in frappe.get_all("Delivery Trip"):
- trip_doc = frappe.get_doc("Delivery Trip", trip.name)
-
- status = {
- 0: "Draft",
- 1: "Scheduled",
- 2: "Cancelled"
- }[trip_doc.docstatus]
-
- if trip_doc.docstatus == 1:
- visited_stops = [stop.visited for stop in trip_doc.delivery_stops]
- if all(visited_stops):
- status = "Completed"
- elif any(visited_stops):
- status = "In Transit"
-
- frappe.db.set_value("Delivery Trip", trip.name, "status", status, update_modified=False)
+# Copyright (c) 2017, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ frappe.reload_doc('setup', 'doctype', 'global_defaults', force=True)
+ frappe.reload_doc('stock', 'doctype', 'delivery_trip')
+ frappe.reload_doc('stock', 'doctype', 'delivery_stop', force=True)
+
+ for trip in frappe.get_all("Delivery Trip"):
+ trip_doc = frappe.get_doc("Delivery Trip", trip.name)
+
+ status = {
+ 0: "Draft",
+ 1: "Scheduled",
+ 2: "Cancelled"
+ }[trip_doc.docstatus]
+
+ if trip_doc.docstatus == 1:
+ visited_stops = [stop.visited for stop in trip_doc.delivery_stops]
+ if all(visited_stops):
+ status = "Completed"
+ elif any(visited_stops):
+ status = "In Transit"
+
+ frappe.db.set_value("Delivery Trip", trip.name, "status", status, update_modified=False)
diff --git a/erpnext/patches/v12_0/set_expense_account_in_landed_cost_voucher_taxes.py b/erpnext/patches/v12_0/set_expense_account_in_landed_cost_voucher_taxes.py
new file mode 100644
index 0000000..a996a69
--- /dev/null
+++ b/erpnext/patches/v12_0/set_expense_account_in_landed_cost_voucher_taxes.py
@@ -0,0 +1,33 @@
+from __future__ import unicode_literals
+import frappe
+from six import iteritems
+
+def execute():
+ frappe.reload_doctype('Landed Cost Taxes and Charges')
+
+ company_account_map = frappe._dict(frappe.db.sql("""
+ SELECT name, expenses_included_in_valuation from `tabCompany`
+ """))
+
+ for company, account in iteritems(company_account_map):
+ frappe.db.sql("""
+ UPDATE
+ `tabLanded Cost Taxes and Charges` t, `tabLanded Cost Voucher` l
+ SET
+ t.expense_account = %s
+ WHERE
+ l.docstatus = 1
+ AND l.company = %s
+ AND t.parent = l.name
+ """, (account, company))
+
+ frappe.db.sql("""
+ UPDATE
+ `tabLanded Cost Taxes and Charges` t, `tabStock Entry` s
+ SET
+ t.expense_account = %s
+ WHERE
+ s.docstatus = 1
+ AND s.company = %s
+ AND t.parent = s.name
+ """, (account, company))
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/set_payment_entry_status.py b/erpnext/patches/v12_0/set_payment_entry_status.py
new file mode 100644
index 0000000..fafbec6
--- /dev/null
+++ b/erpnext/patches/v12_0/set_payment_entry_status.py
@@ -0,0 +1,9 @@
+import frappe
+
+def execute():
+ frappe.reload_doctype("Payment Entry")
+ frappe.db.sql("""update `tabPayment Entry` set status = CASE
+ WHEN docstatus = 1 THEN 'Submitted'
+ WHEN docstatus = 2 THEN 'Cancelled'
+ ELSE 'Draft'
+ END;""")
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/update_owner_fields_in_acc_dimension_custom_fields.py b/erpnext/patches/v12_0/update_owner_fields_in_acc_dimension_custom_fields.py
new file mode 100644
index 0000000..e4dcecd
--- /dev/null
+++ b/erpnext/patches/v12_0/update_owner_fields_in_acc_dimension_custom_fields.py
@@ -0,0 +1,17 @@
+from __future__ import unicode_literals
+import frappe
+from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_doctypes_with_dimensions
+
+def execute():
+ accounting_dimensions = frappe.db.sql("""select fieldname from
+ `tabAccounting Dimension`""", as_dict=1)
+
+ doclist = get_doctypes_with_dimensions()
+
+ for dimension in accounting_dimensions:
+ frappe.db.sql("""
+ UPDATE `tabCustom Field`
+ SET owner = 'Administrator'
+ WHERE fieldname = %s
+ AND dt IN (%s)""" % #nosec
+ ('%s', ', '.join(['%s']* len(doclist))), tuple([dimension.fieldname] + doclist))
\ No newline at end of file
diff --git a/erpnext/projects/doctype/project/project.js b/erpnext/projects/doctype/project/project.js
index 192e1bc..4a03a58 100644
--- a/erpnext/projects/doctype/project/project.js
+++ b/erpnext/projects/doctype/project/project.js
@@ -19,7 +19,7 @@
frappe.ui.form.make_quick_entry(doctype, null, null, new_doc);
});
},
- }
+ };
},
onload: function (frm) {
var so = frappe.meta.get_docfield("Project", "sales_order");
@@ -28,15 +28,15 @@
return {
"customer": frm.doc.customer,
"project_name": frm.doc.name
- }
- }
+ };
+ };
frm.set_query('customer', 'erpnext.controllers.queries.customer_query');
frm.set_query("user", "users", function () {
return {
query: "erpnext.projects.doctype.project.project.get_users_for_project"
- }
+ };
});
// sales order
@@ -51,7 +51,7 @@
return {
filters: filters
- }
+ };
});
if (frappe.model.can_read("Task")) {
@@ -85,6 +85,10 @@
set_buttons: function(frm) {
if (!frm.is_new()) {
+ frm.add_custom_button(__('Duplicate Project with Tasks'), () => {
+ frm.events.create_duplicate(frm);
+ });
+
frm.add_custom_button(__('Completed'), () => {
frm.events.set_status(frm, 'Completed');
}, __('Set Status'));
@@ -95,6 +99,22 @@
}
},
+ create_duplicate: function(frm) {
+ return new Promise(resolve => {
+ frappe.prompt('Project Name', (data) => {
+ frappe.xcall('erpnext.projects.doctype.project.project.create_duplicate_project',
+ {
+ prev_doc: frm.doc,
+ project_name: data.value
+ }).then(() => {
+ frappe.set_route('Form', "Project", data.value);
+ frappe.show_alert(__("Duplicate project has been created"));
+ });
+ resolve();
+ });
+ });
+ },
+
set_status: function(frm, status) {
frappe.confirm(__('Set Project and all Tasks to status {0}?', [status.bold()]), () => {
frappe.xcall('erpnext.projects.doctype.project.project.set_project_status',
diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py
index 783bcf3..bf6e21a 100644
--- a/erpnext/projects/doctype/project/project.py
+++ b/erpnext/projects/doctype/project/project.py
@@ -323,6 +323,37 @@
if get_time(nowtime()) >= get_time(time):
return True
+
+@frappe.whitelist()
+def create_duplicate_project(prev_doc, project_name):
+ ''' Create duplicate project based on the old project '''
+ import json
+ prev_doc = json.loads(prev_doc)
+
+ if project_name == prev_doc.get('name'):
+ frappe.throw(_("Use a name that is different from previous project name"))
+
+ # change the copied doc name to new project name
+ project = frappe.copy_doc(prev_doc)
+ project.name = project_name
+ project.project_template = ''
+ project.project_name = project_name
+ project.insert()
+
+ # fetch all the task linked with the old project
+ task_list = frappe.get_all("Task", filters={
+ 'project': prev_doc.get('name')
+ }, fields=['name'])
+
+ # Create duplicate task for all the task
+ for task in task_list:
+ task = frappe.get_doc('Task', task)
+ new_task = frappe.copy_doc(task)
+ new_task.project = project.name
+ new_task.insert()
+
+ project.db_set('project_template', prev_doc.get('project_template'))
+
def get_projects_for_collect_progress(frequency, fields):
fields.extend(["name"])
diff --git a/erpnext/regional/__init__.py b/erpnext/regional/__init__.py
index 7388ea0..630d5fa 100644
--- a/erpnext/regional/__init__.py
+++ b/erpnext/regional/__init__.py
@@ -10,3 +10,21 @@
region = get_region(doc.company)
if region in ["Nepal", "France"] and doc.docstatus != 0:
frappe.throw(_("Deletion is not permitted for country {0}".format(region)))
+
+def create_transaction_log(doc, method):
+ """
+ Appends the transaction to a chain of hashed logs for legal resons.
+ Called on submit of Sales Invoice and Payment Entry.
+ """
+ region = get_region()
+ if region not in ["France", "Germany"]:
+ return
+
+ data = str(doc.as_dict())
+
+ frappe.get_doc({
+ "doctype": "Transaction Log",
+ "reference_doctype": doc.doctype,
+ "document_name": doc.name,
+ "data": data
+ }).insert(ignore_permissions=True)
diff --git a/erpnext/regional/france/utils.py b/erpnext/regional/france/utils.py
index e4b72f6..424615d 100644
--- a/erpnext/regional/france/utils.py
+++ b/erpnext/regional/france/utils.py
@@ -3,22 +3,6 @@
from __future__ import unicode_literals
import frappe
-from frappe import _
-from erpnext import get_region
-
-def create_transaction_log(doc, method):
- region = get_region()
- if region not in ["France"]:
- return
- else:
- data = str(doc.as_dict())
-
- frappe.get_doc({
- "doctype": "Transaction Log",
- "reference_doctype": doc.doctype,
- "document_name": doc.name,
- "data": data
- }).insert(ignore_permissions=True)
# don't remove this function it is used in tests
def test_method():
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 0bc277f..aae0779 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -72,8 +72,8 @@
total += digit
factor = 2 if factor == 1 else 1
if gstin[-1] != code_point_chars[((mod - (total % mod)) % mod)]:
- frappe.throw(_("Invalid {0}! The check digit validation has failed. " +
- "Please ensure you've typed the {0} correctly.".format(label)))
+ frappe.throw(_("""Invalid {0}! The check digit validation has failed.
+ Please ensure you've typed the {0} correctly.""".format(label)))
def get_itemised_tax_breakup_header(item_doctype, tax_accounts):
if frappe.get_meta(item_doctype).has_field('gst_hsn_code'):
diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py
index 922619c..090616b 100644
--- a/erpnext/regional/report/gstr_1/gstr_1.py
+++ b/erpnext/regional/report/gstr_1/gstr_1.py
@@ -116,7 +116,7 @@
taxable_value = 0
for item_code, net_amount in self.invoice_items.get(invoice).items():
if item_code in items:
- if self.item_tax_rate.get(invoice) and tax_rate in self.item_tax_rate.get(invoice, {}).get(item_code):
+ if self.item_tax_rate.get(invoice) and tax_rate in self.item_tax_rate.get(invoice, {}).get(item_code, []):
taxable_value += abs(net_amount)
elif not self.item_tax_rate.get(invoice):
taxable_value += abs(net_amount)
diff --git a/erpnext/shopping_cart/cart.py b/erpnext/shopping_cart/cart.py
index a4c10cf..1236ade 100644
--- a/erpnext/shopping_cart/cart.py
+++ b/erpnext/shopping_cart/cart.py
@@ -11,6 +11,7 @@
from frappe.utils.nestedset import get_root_of
from erpnext.accounts.utils import get_account_name
from erpnext.utilities.product import get_qty_in_stock
+from frappe.contacts.doctype.contact.contact import get_contact_name
class WebsitePriceListMissingError(frappe.ValidationError):
@@ -371,7 +372,7 @@
if not user:
user = frappe.session.user
- contact_name = frappe.db.get_value("Contact", {"email_id": user})
+ contact_name = get_contact_name(user)
party = None
if contact_name:
@@ -417,7 +418,7 @@
contact = frappe.new_doc("Contact")
contact.update({
"first_name": fullname,
- "email_id": user
+ "email_ids": [{"email_id": user, "is_primary": 1}]
})
contact.append('links', dict(link_doctype='Customer', link_name=customer.name))
contact.flags.ignore_mandatory = True
@@ -504,7 +505,7 @@
if shipping_rules:
rule_label_map = frappe.db.get_values("Shipping Rule", shipping_rules, "label")
# we need this in sorted order as per the position of the rule in the settings page
- return [[rule, rule_label_map.get(rule)] for rule in shipping_rules]
+ return [[rule, rule] for rule in shipping_rules]
def get_shipping_rules(quotation=None, cart_settings=None):
if not quotation:
@@ -562,4 +563,4 @@
frappe.throw(_("Please enter valid coupon code !!"))
else:
frappe.throw(_("Please enter coupon code !!"))
- return quotation
\ No newline at end of file
+ return quotation
diff --git a/erpnext/stock/doctype/landed_cost_taxes_and_charges/landed_cost_taxes_and_charges.json b/erpnext/stock/doctype/landed_cost_taxes_and_charges/landed_cost_taxes_and_charges.json
index 1aaf73f..0cc243d 100644
--- a/erpnext/stock/doctype/landed_cost_taxes_and_charges/landed_cost_taxes_and_charges.json
+++ b/erpnext/stock/doctype/landed_cost_taxes_and_charges/landed_cost_taxes_and_charges.json
@@ -1,129 +1,51 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2014-07-11 11:51:00.453717",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "creation": "2014-07-11 11:51:00.453717",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "expense_account",
+ "description",
+ "col_break3",
+ "amount"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "description",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Description",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "description",
+ "fieldtype": "Small Text",
+ "in_list_view": 1,
+ "label": "Description",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "col_break3",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0,
+ "fieldname": "col_break3",
+ "fieldtype": "Column Break",
"width": "50%"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Amount",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
+ "fieldname": "amount",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Amount",
+ "options": "Company:company:default_currency",
+ "reqd": 1
+ },
+ {
+ "fieldname": "expense_account",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Expense Account",
+ "options": "Account",
+ "reqd": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2017-11-15 19:27:59.542487",
- "modified_by": "Administrator",
- "module": "Stock",
- "name": "Landed Cost Taxes and Charges",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 0,
- "track_seen": 0
+ ],
+ "istable": 1,
+ "modified": "2019-09-30 18:28:32.070655",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Landed Cost Taxes and Charges",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC"
}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.js b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.js
index edc3444..c9a3fd9 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.js
+++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.js
@@ -30,6 +30,16 @@
this.frm.add_fetch("receipt_document", "posting_date", "posting_date");
this.frm.add_fetch("receipt_document", "base_grand_total", "grand_total");
+ this.frm.set_query("expense_account", "taxes", function() {
+ return {
+ query: "erpnext.controllers.queries.tax_account_query",
+ filters: {
+ "account_type": ["Tax", "Chargeable", "Income Account", "Expenses Included In Valuation", "Expenses Included In Asset Valuation"],
+ "company": me.frm.doc.company
+ }
+ };
+ });
+
},
refresh: function(frm) {
@@ -38,7 +48,7 @@
<table class="table table-bordered" style="background-color: #f9f9f9;">
<tr><td>
<h4>
- <i class="fa fa-hand-right"></i>
+ <i class="fa fa-hand-right"></i>
${__("Notes")}:
</h4>
<ul>
@@ -96,7 +106,7 @@
var me = this;
if(this.frm.doc.taxes.length) {
-
+
var total_item_cost = 0.0;
var based_on = this.frm.doc.distribute_charges_based_on.toLowerCase();
$.each(this.frm.doc.items || [], function(i, d) {
@@ -105,7 +115,7 @@
var total_charges = 0.0;
$.each(this.frm.doc.items || [], function(i, item) {
- item.applicable_charges = flt(item[based_on]) * flt(me.frm.doc.total_taxes_and_charges) / flt(total_item_cost)
+ item.applicable_charges = flt(item[based_on]) * flt(me.frm.doc.total_taxes_and_charges) / flt(total_item_cost)
item.applicable_charges = flt(item.applicable_charges, precision("applicable_charges", item))
total_charges += item.applicable_charges
});
diff --git a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
index 4dc0b7b..fe5d3ed 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
+++ b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
@@ -179,7 +179,7 @@
lcv.set("taxes", [{
"description": "Insurance Charges",
- "account": "_Test Account Insurance Charges - _TC",
+ "expense_account": "Expenses Included In Valuation - TCP1",
"amount": charges
}])
diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js
index 3f66743..2789711 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -173,8 +173,10 @@
});
function get_item_details(item_code, uom=null) {
- return frappe.xcall('erpnext.stock.doctype.pick_list.pick_list.get_item_details', {
- item_code,
- uom
- });
+ if (item_code) {
+ return frappe.xcall('erpnext.stock.doctype.pick_list.pick_list.get_item_details', {
+ item_code,
+ uom
+ });
+ }
}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index fae4de3..3362d4b 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -195,6 +195,7 @@
from erpnext.accounts.general_ledger import process_gl_map
stock_rbnb = self.get_company_default("stock_received_but_not_billed")
+ landed_cost_entries = get_item_account_wise_additional_cost(self.name)
expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
gl_entries = []
@@ -233,15 +234,16 @@
negative_expense_to_be_booked += flt(d.item_tax_amount)
# Amount added through landed-cost-voucher
- if flt(d.landed_cost_voucher_amount):
- gl_entries.append(self.get_gl_dict({
- "account": expenses_included_in_valuation,
- "against": warehouse_account[d.warehouse]["account"],
- "cost_center": d.cost_center,
- "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
- "credit": flt(d.landed_cost_voucher_amount),
- "project": d.project
- }, item=d))
+ if landed_cost_entries:
+ for account, amount in iteritems(landed_cost_entries[(d.item_code, d.name)]):
+ gl_entries.append(self.get_gl_dict({
+ "account": account,
+ "against": warehouse_account[d.warehouse]["account"],
+ "cost_center": d.cost_center,
+ "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
+ "credit": flt(amount),
+ "project": d.project
+ }, item=d))
# sub-contracting warehouse
if flt(d.rm_supp_cost) and warehouse_account.get(self.supplier_warehouse):
@@ -584,3 +586,30 @@
}, target_doc, set_missing_values)
return doclist
+
+def get_item_account_wise_additional_cost(purchase_document):
+ landed_cost_voucher = frappe.get_value("Landed Cost Purchase Receipt",
+ {"receipt_document": purchase_document}, "parent")
+
+ if not landed_cost_voucher:
+ return
+
+ total_item_cost = 0
+ item_account_wise_cost = {}
+ landed_cost_voucher_doc = frappe.get_doc("Landed Cost Voucher", landed_cost_voucher)
+ based_on_field = frappe.scrub(landed_cost_voucher_doc.distribute_charges_based_on)
+
+ for item in landed_cost_voucher_doc.items:
+ if item.receipt_document == purchase_document:
+ total_item_cost += item.get(based_on_field)
+
+ for item in landed_cost_voucher_doc.items:
+ if item.receipt_document == purchase_document:
+ for account in landed_cost_voucher_doc.taxes:
+ item_account_wise_cost.setdefault((item.item_code, item.purchase_receipt_item), {})
+ item_account_wise_cost[(item.item_code, item.purchase_receipt_item)].setdefault(account.expense_account, 0.0)
+ item_account_wise_cost[(item.item_code, item.purchase_receipt_item)][account.expense_account] += \
+ account.amount * item.get(based_on_field) / total_item_cost
+
+ return item_account_wise_cost
+
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index 0b02302..6e78b98 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -68,6 +68,16 @@
}
});
+ frm.set_query("expense_account", "additional_costs", function() {
+ return {
+ query: "erpnext.controllers.queries.tax_account_query",
+ filters: {
+ "account_type": ["Tax", "Chargeable", "Income Account", "Expenses Included In Valuation", "Expenses Included In Asset Valuation"],
+ "company": frm.doc.company
+ }
+ };
+ });
+
frm.add_fetch("bom_no", "inspection_required", "inspection_required");
},
@@ -727,7 +737,8 @@
return frappe.call({
method: "erpnext.stock.doctype.stock_entry.stock_entry.get_work_order_details",
args: {
- work_order: me.frm.doc.work_order
+ work_order: me.frm.doc.work_order,
+ company: me.frm.doc.company
},
callback: function(r) {
if (!r.exc) {
@@ -743,6 +754,8 @@
if (me.frm.doc.purpose == "Manufacture") {
if (!me.frm.doc.to_warehouse) me.frm.set_value("to_warehouse", r.message["fg_warehouse"]);
if (r.message["additional_costs"].length) {
+ me.frm.clear_table("additional_costs");
+
$.each(r.message["additional_costs"], function(i, row) {
me.frm.add_child("additional_costs", row);
})
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 55e02a4..26693d2 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -644,28 +644,37 @@
self.make_sl_entries(sl_entries, self.amended_from and 'Yes' or 'No')
def get_gl_entries(self, warehouse_account):
- expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
-
gl_entries = super(StockEntry, self).get_gl_entries(warehouse_account)
- for d in self.get("items"):
- additional_cost = flt(d.additional_cost, d.precision("additional_cost"))
- if additional_cost:
- gl_entries.append(self.get_gl_dict({
- "account": expenses_included_in_valuation,
- "against": d.expense_account,
- "cost_center": d.cost_center,
- "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
- "credit": additional_cost
- }, item=d))
+ total_basic_amount = sum([flt(t.basic_amount) for t in self.get("items") if t.t_warehouse])
+ item_account_wise_additional_cost = {}
- gl_entries.append(self.get_gl_dict({
- "account": d.expense_account,
- "against": expenses_included_in_valuation,
- "cost_center": d.cost_center,
- "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
- "credit": -1 * additional_cost # put it as negative credit instead of debit purposefully
- }, item=d))
+ for t in self.get("additional_costs"):
+ for d in self.get("items"):
+ if d.t_warehouse:
+ item_account_wise_additional_cost.setdefault((d.item_code, d.name), {})
+ item_account_wise_additional_cost[(d.item_code, d.name)].setdefault(t.expense_account, 0.0)
+ item_account_wise_additional_cost[(d.item_code, d.name)][t.expense_account] += \
+ (t.amount * d.basic_amount) / total_basic_amount
+
+ if item_account_wise_additional_cost:
+ for d in self.get("items"):
+ for account, amount in iteritems(item_account_wise_additional_cost.get((d.item_code, d.name), {})):
+ gl_entries.append(self.get_gl_dict({
+ "account": account,
+ "against": d.expense_account,
+ "cost_center": d.cost_center,
+ "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
+ "credit": amount
+ }, item=d))
+
+ gl_entries.append(self.get_gl_dict({
+ "account": d.expense_account,
+ "against": account,
+ "cost_center": d.cost_center,
+ "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
+ "credit": -1 * amount # put it as negative credit instead of debit purposefully
+ }, item=d))
return gl_entries
@@ -1349,7 +1358,7 @@
return doclist
@frappe.whitelist()
-def get_work_order_details(work_order):
+def get_work_order_details(work_order, company):
work_order = frappe.get_doc("Work Order", work_order)
pending_qty_to_produce = flt(work_order.qty) - flt(work_order.produced_qty)
@@ -1360,14 +1369,17 @@
"wip_warehouse": work_order.wip_warehouse,
"fg_warehouse": work_order.fg_warehouse,
"fg_completed_qty": pending_qty_to_produce,
- "additional_costs": get_additional_costs(work_order, fg_qty=pending_qty_to_produce)
+ "additional_costs": get_additional_costs(work_order, fg_qty=pending_qty_to_produce, company=company)
}
-def get_additional_costs(work_order=None, bom_no=None, fg_qty=None):
+def get_additional_costs(work_order=None, bom_no=None, fg_qty=None, company=None):
additional_costs = []
operating_cost_per_unit = get_operating_cost_per_unit(work_order, bom_no)
+ expenses_included_in_valuation = frappe.get_cached_value("Company", company, "expenses_included_in_valuation")
+
if operating_cost_per_unit:
additional_costs.append({
+ "expense_account": expenses_included_in_valuation,
"description": "Operating Cost as per Work Order / BOM",
"amount": operating_cost_per_unit * flt(fg_qty)
})
@@ -1377,6 +1389,7 @@
flt(work_order.additional_operating_cost) / flt(work_order.qty)
additional_costs.append({
+ "expense_account": expenses_included_in_valuation,
"description": "Additional Operating Cost",
"amount": additional_operating_cost_per_unit * flt(fg_qty)
})
diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
index 941472b..eddab5d 100644
--- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
@@ -259,6 +259,8 @@
repack.posting_date = nowdate()
repack.posting_time = nowtime()
+ expenses_included_in_valuation = frappe.get_value("Company", company, "expenses_included_in_valuation")
+
items = get_multiple_items()
repack.items = []
for item in items:
@@ -266,11 +268,13 @@
repack.set("additional_costs", [
{
- "description": "Actual Oerating Cost",
+ "expense_account": expenses_included_in_valuation,
+ "description": "Actual Operating Cost",
"amount": 1000
},
{
- "description": "additional operating costs",
+ "expense_account": expenses_included_in_valuation,
+ "description": "Additional Operating Cost",
"amount": 200
},
])
diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py
index 5bdbca2..db7f6ad 100644
--- a/erpnext/stock/report/stock_ledger/stock_ledger.py
+++ b/erpnext/stock/report/stock_ledger/stock_ledger.py
@@ -19,10 +19,26 @@
if opening_row:
data.append(opening_row)
+ actual_qty = stock_value = 0
+
for sle in sl_entries:
item_detail = item_details[sle.item_code]
sle.update(item_detail)
+
+ if filters.get("batch_no"):
+ actual_qty += sle.actual_qty
+ stock_value += sle.stock_value_difference
+
+ if sle.voucher_type == 'Stock Reconciliation':
+ actual_qty = sle.qty_after_transaction
+ stock_value = sle.stock_value
+
+ sle.update({
+ "qty_after_transaction": actual_qty,
+ "stock_value": stock_value
+ })
+
data.append(sle)
if include_uom:
@@ -67,7 +83,7 @@
return frappe.db.sql("""select concat_ws(" ", posting_date, posting_time) as date,
item_code, warehouse, actual_qty, qty_after_transaction, incoming_rate, valuation_rate,
- stock_value, voucher_type, voucher_no, batch_no, serial_no, company, project
+ stock_value, voucher_type, voucher_no, batch_no, serial_no, company, project, stock_value_difference
from `tabStock Ledger Entry` sle
where company = %(company)s and
posting_date between %(from_date)s and %(to_date)s
diff --git a/erpnext/support/doctype/issue_priority/issue_priority.py b/erpnext/support/doctype/issue_priority/issue_priority.py
index cecaaaa..7c8925e 100644
--- a/erpnext/support/doctype/issue_priority/issue_priority.py
+++ b/erpnext/support/doctype/issue_priority/issue_priority.py
@@ -8,7 +8,4 @@
from frappe.model.document import Document
class IssuePriority(Document):
-
- def validate(self):
- if frappe.db.exists("Issue Priority", {"name": self.name}):
- frappe.throw(_("Issue Priority Already Exists"))
+ pass
\ No newline at end of file
diff --git a/erpnext/tests/test_woocommerce.py b/erpnext/tests/test_woocommerce.py
index fc850d5..ce0f47d 100644
--- a/erpnext/tests/test_woocommerce.py
+++ b/erpnext/tests/test_woocommerce.py
@@ -18,6 +18,7 @@
woo_settings.api_consumer_key = "ck_fd43ff5756a6abafd95fadb6677100ce95a758a1"
woo_settings.api_consumer_secret = "cs_94360a1ad7bef7fa420a40cf284f7b3e0788454e"
woo_settings.enable_sync = 1
+ woo_settings.company = "Woocommerce"
woo_settings.tax_account = "Sales Expenses - W"
woo_settings.f_n_f_account = "Expenses - W"
woo_settings.creation_user = "Administrator"