mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-06 15:00:27 +00:00
Merge branch 'version-12-hotfix' of https://github.com/frappe/erpnext into purchase-register-filters-v12
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
frappe.provide("frappe.treeview_settings")
|
frappe.provide("frappe.treeview_settings")
|
||||||
|
|
||||||
frappe.treeview_settings["Account"] = {
|
frappe.treeview_settings["Account"] = {
|
||||||
breadcrumbs: "Accounts",
|
breadcrumb: "Accounts",
|
||||||
title: __("Chart Of Accounts"),
|
title: __("Chart Of Accounts"),
|
||||||
get_tree_root: false,
|
get_tree_root: false,
|
||||||
filters: [
|
filters: [
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ def get_dimension_with_children(doctype, dimension):
|
|||||||
|
|
||||||
all_dimensions = []
|
all_dimensions = []
|
||||||
lft, rgt = frappe.db.get_value(doctype, dimension, ["lft", "rgt"])
|
lft, rgt = frappe.db.get_value(doctype, dimension, ["lft", "rgt"])
|
||||||
children = frappe.get_all(doctype, filters={"lft": [">=", lft], "rgt": ["<=", rgt]})
|
children = frappe.get_all(doctype, filters={"lft": [">=", lft], "rgt": ["<=", rgt]}, order_by="lft")
|
||||||
all_dimensions += [c.name for c in children]
|
all_dimensions += [c.name for c in children]
|
||||||
|
|
||||||
return all_dimensions
|
return all_dimensions
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ def build_forest(data):
|
|||||||
error_messages = []
|
error_messages = []
|
||||||
|
|
||||||
for i in data:
|
for i in data:
|
||||||
account_name, _, account_number, is_group, account_type, root_type = i
|
account_name, __, account_number, is_group, account_type, root_type = i
|
||||||
|
|
||||||
if not account_name:
|
if not account_name:
|
||||||
error_messages.append("Row {0}: Please enter Account Name".format(line_no))
|
error_messages.append("Row {0}: Please enter Account Name".format(line_no))
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
frappe.treeview_settings["Cost Center"] = {
|
frappe.treeview_settings["Cost Center"] = {
|
||||||
breadcrumbs: "Accounts",
|
breadcrumb: "Accounts",
|
||||||
get_tree_root: false,
|
get_tree_root: false,
|
||||||
filters: [{
|
filters: [{
|
||||||
fieldname: "company",
|
fieldname: "company",
|
||||||
|
|||||||
@@ -81,7 +81,12 @@ class PaymentEntry(AccountsController):
|
|||||||
self.update_advance_paid()
|
self.update_advance_paid()
|
||||||
self.update_expense_claim()
|
self.update_expense_claim()
|
||||||
self.delink_advance_entry_references()
|
self.delink_advance_entry_references()
|
||||||
|
self.set_payment_req_status()
|
||||||
self.set_status()
|
self.set_status()
|
||||||
|
|
||||||
|
def set_payment_req_status(self):
|
||||||
|
from erpnext.accounts.doctype.payment_request.payment_request import update_payment_req_status
|
||||||
|
update_payment_req_status(self, None)
|
||||||
|
|
||||||
def update_outstanding_amounts(self):
|
def update_outstanding_amounts(self):
|
||||||
self.set_missing_ref_details(force=True)
|
self.set_missing_ref_details(force=True)
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ frappe.ui.form.on('Payment Order', {
|
|||||||
if (frm.doc.docstatus == 0) {
|
if (frm.doc.docstatus == 0) {
|
||||||
frm.add_custom_button(__('Payment Request'), function() {
|
frm.add_custom_button(__('Payment Request'), function() {
|
||||||
frm.trigger("get_from_payment_request");
|
frm.trigger("get_from_payment_request");
|
||||||
}, __("Get from"));
|
}, __("Get Payments from"));
|
||||||
|
|
||||||
frm.add_custom_button(__('Payment Entry'), function() {
|
frm.add_custom_button(__('Payment Entry'), function() {
|
||||||
frm.trigger("get_from_payment_entry");
|
frm.trigger("get_from_payment_entry");
|
||||||
}, __("Get from"));
|
}, __("Get Payments from"));
|
||||||
|
|
||||||
frm.trigger('remove_button');
|
frm.trigger('remove_button');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,6 @@
|
|||||||
"fieldtype": "Section Break"
|
"fieldtype": "Section Break"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 1,
|
|
||||||
"fieldname": "references",
|
"fieldname": "references",
|
||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"label": "Payment Order Reference",
|
"label": "Payment Order Reference",
|
||||||
@@ -108,7 +107,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"modified": "2019-05-14 17:12:24.912666",
|
"modified": "2020-04-06 18:00:56.022642",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Payment Order",
|
"name": "Payment Order",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -66,6 +66,8 @@ class PaymentRequest(Document):
|
|||||||
if self.payment_request_type == 'Outward':
|
if self.payment_request_type == 'Outward':
|
||||||
self.db_set('status', 'Initiated')
|
self.db_set('status', 'Initiated')
|
||||||
return
|
return
|
||||||
|
elif self.payment_request_type == 'Inward':
|
||||||
|
self.db_set('status', 'Requested')
|
||||||
|
|
||||||
send_mail = self.payment_gateway_validation()
|
send_mail = self.payment_gateway_validation()
|
||||||
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
|
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
|
||||||
@@ -88,6 +90,7 @@ class PaymentRequest(Document):
|
|||||||
if (hasattr(ref_doc, "order_type") and getattr(ref_doc, "order_type") == "Shopping Cart"):
|
if (hasattr(ref_doc, "order_type") and getattr(ref_doc, "order_type") == "Shopping Cart"):
|
||||||
from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice
|
from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice
|
||||||
si = make_sales_invoice(self.reference_name, ignore_permissions=True)
|
si = make_sales_invoice(self.reference_name, ignore_permissions=True)
|
||||||
|
si.allocate_advances_automatically = True
|
||||||
si = si.insert(ignore_permissions=True)
|
si = si.insert(ignore_permissions=True)
|
||||||
si.submit()
|
si.submit()
|
||||||
|
|
||||||
@@ -415,17 +418,31 @@ def make_payment_entry(docname):
|
|||||||
doc = frappe.get_doc("Payment Request", docname)
|
doc = frappe.get_doc("Payment Request", docname)
|
||||||
return doc.create_payment_entry(submit=False).as_dict()
|
return doc.create_payment_entry(submit=False).as_dict()
|
||||||
|
|
||||||
def make_status_as_paid(doc, method):
|
def update_payment_req_status(doc, method):
|
||||||
|
from erpnext.accounts.doctype.payment_entry.payment_entry import get_reference_details
|
||||||
|
|
||||||
for ref in doc.references:
|
for ref in doc.references:
|
||||||
payment_request_name = frappe.db.get_value("Payment Request",
|
payment_request_name = frappe.db.get_value("Payment Request",
|
||||||
{"reference_doctype": ref.reference_doctype, "reference_name": ref.reference_name,
|
{"reference_doctype": ref.reference_doctype, "reference_name": ref.reference_name,
|
||||||
"docstatus": 1})
|
"docstatus": 1})
|
||||||
|
|
||||||
if payment_request_name:
|
if payment_request_name:
|
||||||
doc = frappe.get_doc("Payment Request", payment_request_name)
|
ref_details = get_reference_details(ref.reference_doctype, ref.reference_name, doc.party_account_currency)
|
||||||
if doc.status != "Paid":
|
pay_req_doc = frappe.get_doc('Payment Request', payment_request_name)
|
||||||
doc.db_set('status', 'Paid')
|
status = pay_req_doc.status
|
||||||
frappe.db.commit()
|
|
||||||
|
if status != "Paid" and not ref_details.outstanding_amount:
|
||||||
|
status = 'Paid'
|
||||||
|
elif status != "Partially Paid" and ref_details.outstanding_amount != ref_details.total_amount:
|
||||||
|
status = 'Partially Paid'
|
||||||
|
elif ref_details.outstanding_amount == ref_details.total_amount:
|
||||||
|
if pay_req_doc.payment_request_type == 'Outward':
|
||||||
|
status = 'Initiated'
|
||||||
|
elif pay_req_doc.payment_request_type == 'Inward':
|
||||||
|
status = 'Requested'
|
||||||
|
|
||||||
|
pay_req_doc.db_set('status', status)
|
||||||
|
frappe.db.commit()
|
||||||
|
|
||||||
def get_dummy_message(doc):
|
def get_dummy_message(doc):
|
||||||
return frappe.render_template("""{% if doc.contact_person -%}
|
return frappe.render_template("""{% if doc.contact_person -%}
|
||||||
|
|||||||
@@ -4,14 +4,20 @@ frappe.listview_settings['Payment Request'] = {
|
|||||||
if(doc.status == "Draft") {
|
if(doc.status == "Draft") {
|
||||||
return [__("Draft"), "darkgrey", "status,=,Draft"];
|
return [__("Draft"), "darkgrey", "status,=,Draft"];
|
||||||
}
|
}
|
||||||
|
if(doc.status == "Requested") {
|
||||||
|
return [__("Requested"), "green", "status,=,Requested"];
|
||||||
|
}
|
||||||
else if(doc.status == "Initiated") {
|
else if(doc.status == "Initiated") {
|
||||||
return [__("Initiated"), "green", "status,=,Initiated"];
|
return [__("Initiated"), "green", "status,=,Initiated"];
|
||||||
}
|
}
|
||||||
|
else if(doc.status == "Partially Paid") {
|
||||||
|
return [__("Partially Paid"), "orange", "status,=,Partially Paid"];
|
||||||
|
}
|
||||||
else if(doc.status == "Paid") {
|
else if(doc.status == "Paid") {
|
||||||
return [__("Paid"), "blue", "status,=,Paid"];
|
return [__("Paid"), "blue", "status,=,Paid"];
|
||||||
}
|
}
|
||||||
else if(doc.status == "Cancelled") {
|
else if(doc.status == "Cancelled") {
|
||||||
return [__("Cancelled"), "orange", "status,=,Cancelled"];
|
return [__("Cancelled"), "red", "status,=,Cancelled"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,6 +101,23 @@ class TestPaymentRequest(unittest.TestCase):
|
|||||||
self.assertEqual(expected_gle[gle.account][2], gle.credit)
|
self.assertEqual(expected_gle[gle.account][2], gle.credit)
|
||||||
self.assertEqual(expected_gle[gle.account][3], gle.against_voucher)
|
self.assertEqual(expected_gle[gle.account][3], gle.against_voucher)
|
||||||
|
|
||||||
|
def test_status(self):
|
||||||
|
si_usd = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC",
|
||||||
|
currency="USD", conversion_rate=50)
|
||||||
|
|
||||||
|
pr = make_payment_request(dt="Sales Invoice", dn=si_usd.name, recipient_id="saurabh@erpnext.com",
|
||||||
|
mute_email=1, payment_gateway="_Test Gateway - USD", submit_doc=1, return_doc=1)
|
||||||
|
|
||||||
|
pe = pr.create_payment_entry()
|
||||||
|
pr.load_from_db()
|
||||||
|
|
||||||
|
self.assertEqual(pr.status, 'Paid')
|
||||||
|
|
||||||
|
pe.cancel()
|
||||||
|
pr.load_from_db()
|
||||||
|
|
||||||
|
self.assertEqual(pr.status, 'Requested')
|
||||||
|
|
||||||
def test_multiple_payment_entries_against_sales_order(self):
|
def test_multiple_payment_entries_against_sales_order(self):
|
||||||
# Make Sales Order, grand_total = 1000
|
# Make Sales Order, grand_total = 1000
|
||||||
so = make_sales_order()
|
so = make_sales_order()
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe, erpnext
|
import frappe, erpnext
|
||||||
from frappe.utils import cint, cstr, formatdate, flt, getdate, nowdate
|
from frappe.utils import cint, cstr, formatdate, flt, getdate, nowdate, get_link_to_form
|
||||||
from frappe import _, throw
|
from frappe import _, throw
|
||||||
import frappe.defaults
|
import frappe.defaults
|
||||||
|
|
||||||
@@ -146,10 +146,14 @@ class PurchaseInvoice(BuyingController):
|
|||||||
["account_type", "report_type", "account_currency"], as_dict=True)
|
["account_type", "report_type", "account_currency"], as_dict=True)
|
||||||
|
|
||||||
if account.report_type != "Balance Sheet":
|
if account.report_type != "Balance Sheet":
|
||||||
frappe.throw(_("Credit To account must be a Balance Sheet account"))
|
frappe.throw(_("Please ensure {} account is a Balance Sheet account. \
|
||||||
|
You can change the parent account to a Balance Sheet account or select a different account.")
|
||||||
|
.format(frappe.bold("Credit To")), title=_("Invalid Account"))
|
||||||
|
|
||||||
if self.supplier and account.account_type != "Payable":
|
if self.supplier and account.account_type != "Payable":
|
||||||
frappe.throw(_("Credit To account must be a Payable account"))
|
frappe.throw(_("Please ensure {} account is a Payable account. \
|
||||||
|
Change the account type to Payable or select a different account.")
|
||||||
|
.format(frappe.bold("Credit To")), title=_("Invalid Account"))
|
||||||
|
|
||||||
self.party_account_currency = account.account_currency
|
self.party_account_currency = account.account_currency
|
||||||
|
|
||||||
@@ -255,16 +259,30 @@ class PurchaseInvoice(BuyingController):
|
|||||||
|
|
||||||
def po_required(self):
|
def po_required(self):
|
||||||
if frappe.db.get_value("Buying Settings", None, "po_required") == 'Yes':
|
if frappe.db.get_value("Buying Settings", None, "po_required") == 'Yes':
|
||||||
|
|
||||||
|
if frappe.get_value('Supplier', self.supplier, 'allow_purchase_invoice_creation_without_purchase_order'):
|
||||||
|
return
|
||||||
|
|
||||||
for d in self.get('items'):
|
for d in self.get('items'):
|
||||||
if not d.purchase_order:
|
if not d.purchase_order:
|
||||||
throw(_("As per the Buying Settings if Purchase Order Required == 'YES', then for creating Purchase Invoice, user need to create Purchase Order first for item {0}").format(d.item_code))
|
throw(_("""Purchase Order Required for item {0}
|
||||||
|
To submit the invoice without purchase order please set
|
||||||
|
{1} as {2} in {3}""").format(frappe.bold(d.item_code), frappe.bold(_('Purchase Order Required')),
|
||||||
|
frappe.bold('No'), get_link_to_form('Buying Settings', 'Buying Settings', 'Buying Settings')))
|
||||||
|
|
||||||
def pr_required(self):
|
def pr_required(self):
|
||||||
stock_items = self.get_stock_items()
|
stock_items = self.get_stock_items()
|
||||||
if frappe.db.get_value("Buying Settings", None, "pr_required") == 'Yes':
|
if frappe.db.get_value("Buying Settings", None, "pr_required") == 'Yes':
|
||||||
|
|
||||||
|
if frappe.get_value('Supplier', self.supplier, 'allow_purchase_invoice_creation_without_purchase_receipt'):
|
||||||
|
return
|
||||||
|
|
||||||
for d in self.get('items'):
|
for d in self.get('items'):
|
||||||
if not d.purchase_receipt and d.item_code in stock_items:
|
if not d.purchase_receipt and d.item_code in stock_items:
|
||||||
throw(_("As per the Buying Settings if Purchase Reciept Required == 'YES', then for creating Purchase Invoice, user need to create Purchase Receipt first for item {0}").format(d.item_code))
|
throw(_("""Purchase Receipt Required for item {0}
|
||||||
|
To submit the invoice without purchase receipt please set
|
||||||
|
{1} as {2} in {3}""").format(frappe.bold(d.item_code), frappe.bold(_('Purchase Receipt Required')),
|
||||||
|
frappe.bold('No'), get_link_to_form('Buying Settings', 'Buying Settings', 'Buying Settings')))
|
||||||
|
|
||||||
def validate_write_off_account(self):
|
def validate_write_off_account(self):
|
||||||
if self.write_off_amount and not self.write_off_account:
|
if self.write_off_amount and not self.write_off_account:
|
||||||
|
|||||||
@@ -760,7 +760,7 @@
|
|||||||
"depends_on": "is_fixed_asset",
|
"depends_on": "is_fixed_asset",
|
||||||
"fetch_from": "item_code.asset_category",
|
"fetch_from": "item_code.asset_category",
|
||||||
"fieldname": "asset_category",
|
"fieldname": "asset_category",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Link",
|
||||||
"in_preview": 1,
|
"in_preview": 1,
|
||||||
"label": "Asset Category",
|
"label": "Asset Category",
|
||||||
"options": "Asset Category",
|
"options": "Asset Category",
|
||||||
@@ -770,7 +770,7 @@
|
|||||||
"idx": 1,
|
"idx": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-03-05 14:20:17.297284",
|
"modified": "2020-04-01 14:20:17.297284",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Purchase Invoice Item",
|
"name": "Purchase Invoice Item",
|
||||||
|
|||||||
@@ -412,7 +412,7 @@ class SalesInvoice(SellingController):
|
|||||||
|
|
||||||
if pos:
|
if pos:
|
||||||
self.allow_print_before_pay = pos.allow_print_before_pay
|
self.allow_print_before_pay = pos.allow_print_before_pay
|
||||||
|
|
||||||
if not for_validate:
|
if not for_validate:
|
||||||
self.tax_category = pos.get("tax_category")
|
self.tax_category = pos.get("tax_category")
|
||||||
|
|
||||||
@@ -429,13 +429,17 @@ class SalesInvoice(SellingController):
|
|||||||
if (not for_validate) or (for_validate and not self.get(fieldname)):
|
if (not for_validate) or (for_validate and not self.get(fieldname)):
|
||||||
self.set(fieldname, pos.get(fieldname))
|
self.set(fieldname, pos.get(fieldname))
|
||||||
|
|
||||||
customer_price_list = frappe.get_value("Customer", self.customer, 'default_price_list')
|
|
||||||
|
|
||||||
if pos.get("company_address"):
|
if pos.get("company_address"):
|
||||||
self.company_address = pos.get("company_address")
|
self.company_address = pos.get("company_address")
|
||||||
|
|
||||||
if not customer_price_list:
|
customer_price_list, customer_group = frappe.get_value("Customer", self.customer, ['default_price_list', 'customer_group'])
|
||||||
self.set('selling_price_list', pos.get('selling_price_list'))
|
|
||||||
|
customer_group_price_list = frappe.get_value("Customer Group", customer_group, 'default_price_list')
|
||||||
|
|
||||||
|
selling_price_list = customer_price_list or customer_group_price_list or pos.get('selling_price_list')
|
||||||
|
|
||||||
|
if selling_price_list:
|
||||||
|
self.set('selling_price_list', selling_price_list)
|
||||||
|
|
||||||
if not for_validate:
|
if not for_validate:
|
||||||
self.update_stock = cint(pos.get("update_stock"))
|
self.update_stock = cint(pos.get("update_stock"))
|
||||||
@@ -466,13 +470,17 @@ class SalesInvoice(SellingController):
|
|||||||
["account_type", "report_type", "account_currency"], as_dict=True)
|
["account_type", "report_type", "account_currency"], as_dict=True)
|
||||||
|
|
||||||
if not account:
|
if not account:
|
||||||
frappe.throw(_("Debit To is required"))
|
frappe.throw(_("Debit To is required"), title=_("Account Missing"))
|
||||||
|
|
||||||
if account.report_type != "Balance Sheet":
|
if account.report_type != "Balance Sheet":
|
||||||
frappe.throw(_("Debit To account must be a Balance Sheet account"))
|
frappe.throw(_("Please ensure {} account is a Balance Sheet account. \
|
||||||
|
You can change the parent account to a Balance Sheet account or select a different account.")
|
||||||
|
.format(frappe.bold("Debit To")), title=_("Invalid Account"))
|
||||||
|
|
||||||
if self.customer and account.account_type != "Receivable":
|
if self.customer and account.account_type != "Receivable":
|
||||||
frappe.throw(_("Debit To account must be a Receivable account"))
|
frappe.throw(_("Please ensure {} account is a Receivable account. \
|
||||||
|
Change the account type to Receivable or select a different account.")
|
||||||
|
.format(frappe.bold("Debit To")), title=_("Invalid Account"))
|
||||||
|
|
||||||
self.party_account_currency = account.account_currency
|
self.party_account_currency = account.account_currency
|
||||||
|
|
||||||
@@ -534,14 +542,18 @@ class SalesInvoice(SellingController):
|
|||||||
"""check in manage account if sales order / delivery note required or not."""
|
"""check in manage account if sales order / delivery note required or not."""
|
||||||
if self.is_return:
|
if self.is_return:
|
||||||
return
|
return
|
||||||
dic = {'Sales Order':['so_required', 'is_pos'],'Delivery Note':['dn_required', 'update_stock']}
|
|
||||||
for i in dic:
|
prev_doc_field_map = {'Sales Order': ['so_required', 'is_pos'],'Delivery Note': ['dn_required', 'update_stock']}
|
||||||
if frappe.db.get_single_value('Selling Settings', dic[i][0]) == 'Yes':
|
for key, value in iteritems(prev_doc_field_map):
|
||||||
|
if frappe.db.get_single_value('Selling Settings', value[0]) == 'Yes':
|
||||||
|
|
||||||
|
if frappe.get_value('Customer', self.customer, value[0]):
|
||||||
|
continue
|
||||||
|
|
||||||
for d in self.get('items'):
|
for d in self.get('items'):
|
||||||
is_stock_item = frappe.get_cached_value('Item', d.item_code, 'is_stock_item')
|
is_stock_item = frappe.get_cached_value('Item', d.item_code, 'is_stock_item')
|
||||||
if (d.item_code and is_stock_item == 1\
|
if (d.item_code and is_stock_item ==1 and not d.get(key.lower().replace(' ', '_')) and not self.get(value[1])):
|
||||||
and not d.get(i.lower().replace(' ','_')) and not self.get(dic[i][1])):
|
msgprint(_("{0} is mandatory for Item {1}").format(key, d.item_code), raise_exception=1)
|
||||||
msgprint(_("{0} is mandatory for Item {1}").format(i,d.item_code), raise_exception=1)
|
|
||||||
|
|
||||||
|
|
||||||
def validate_proj_cust(self):
|
def validate_proj_cust(self):
|
||||||
|
|||||||
@@ -1868,6 +1868,16 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
item.taxes = []
|
item.taxes = []
|
||||||
item.save()
|
item.save()
|
||||||
|
|
||||||
|
def test_customer_provided_parts_si(self):
|
||||||
|
create_item('CUST-0987', is_customer_provided_item = 1, customer = '_Test Customer', is_purchase_item = 0)
|
||||||
|
si = create_sales_invoice(item_code='CUST-0987', rate=0)
|
||||||
|
self.assertEqual(si.get("items")[0].allow_zero_valuation_rate, 1)
|
||||||
|
self.assertEqual(si.get("items")[0].amount, 0)
|
||||||
|
|
||||||
|
# test if Sales Invoice with rate is allowed
|
||||||
|
si2 = create_sales_invoice(item_code='CUST-0987', do_not_save=True)
|
||||||
|
self.assertRaises(frappe.ValidationError, si2.save)
|
||||||
|
|
||||||
def create_sales_invoice(**args):
|
def create_sales_invoice(**args):
|
||||||
si = frappe.new_doc("Sales Invoice")
|
si = frappe.new_doc("Sales Invoice")
|
||||||
args = frappe._dict(args)
|
args = frappe._dict(args)
|
||||||
@@ -1890,7 +1900,7 @@ def create_sales_invoice(**args):
|
|||||||
"gst_hsn_code": "999800",
|
"gst_hsn_code": "999800",
|
||||||
"warehouse": args.warehouse or "_Test Warehouse - _TC",
|
"warehouse": args.warehouse or "_Test Warehouse - _TC",
|
||||||
"qty": args.qty or 1,
|
"qty": args.qty or 1,
|
||||||
"rate": args.rate or 100,
|
"rate": args.rate if args.get("rate") is not None else 100,
|
||||||
"income_account": args.income_account or "Sales - _TC",
|
"income_account": args.income_account or "Sales - _TC",
|
||||||
"expense_account": args.expense_account or "Cost of Goods Sold - _TC",
|
"expense_account": args.expense_account or "Cost of Goods Sold - _TC",
|
||||||
"cost_center": args.cost_center or "_Test Cost Center - _TC",
|
"cost_center": args.cost_center or "_Test Cost Center - _TC",
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ class ShippingRule(Document):
|
|||||||
if not shipping_country:
|
if not shipping_country:
|
||||||
frappe.throw(_('Shipping Address does not have country, which is required for this Shipping Rule'))
|
frappe.throw(_('Shipping Address does not have country, which is required for this Shipping Rule'))
|
||||||
if shipping_country not in [d.country for d in self.countries]:
|
if shipping_country not in [d.country for d in self.countries]:
|
||||||
frappe.throw(_('Shipping rule not applicable for country {0}'.format(shipping_country)))
|
frappe.throw(_('Shipping rule not applicable for country {0} in Shipping Address').format(shipping_country))
|
||||||
|
|
||||||
def add_shipping_rule_to_tax_table(self, doc, shipping_amount):
|
def add_shipping_rule_to_tax_table(self, doc, shipping_amount):
|
||||||
shipping_charge = {
|
shipping_charge = {
|
||||||
|
|||||||
@@ -419,7 +419,9 @@ def get_additional_conditions(from_date, ignore_closing_entries, filters):
|
|||||||
if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
|
if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
|
||||||
filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
|
filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
|
||||||
filters.get(dimension.fieldname))
|
filters.get(dimension.fieldname))
|
||||||
additional_conditions.append("{0} in %({0})s".format(dimension.fieldname))
|
additional_conditions.append("{0} in %({0})s".format(dimension.fieldname))
|
||||||
|
else:
|
||||||
|
additional_conditions.append("{0} in (%({0})s)".format(dimension.fieldname))
|
||||||
|
|
||||||
return " and {}".format(" and ".join(additional_conditions)) if additional_conditions else ""
|
return " and {}".format(" and ".join(additional_conditions)) if additional_conditions else ""
|
||||||
|
|
||||||
|
|||||||
@@ -202,7 +202,9 @@ def get_conditions(filters):
|
|||||||
if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
|
if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
|
||||||
filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
|
filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
|
||||||
filters.get(dimension.fieldname))
|
filters.get(dimension.fieldname))
|
||||||
conditions.append("{0} in %({0})s".format(dimension.fieldname))
|
conditions.append("{0} in %({0})s".format(dimension.fieldname))
|
||||||
|
else:
|
||||||
|
conditions.append("{0} in (%({0})s)".format(dimension.fieldname))
|
||||||
|
|
||||||
return "and {}".format(" and ".join(conditions)) if conditions else ""
|
return "and {}".format(" and ".join(conditions)) if conditions else ""
|
||||||
|
|
||||||
|
|||||||
@@ -344,16 +344,19 @@ def get_conditions(filters):
|
|||||||
accounting_dimensions = get_accounting_dimensions(as_list=False)
|
accounting_dimensions = get_accounting_dimensions(as_list=False)
|
||||||
|
|
||||||
if accounting_dimensions:
|
if accounting_dimensions:
|
||||||
|
common_condition = """
|
||||||
|
and exists(select name from `tabSales Invoice Item`
|
||||||
|
where parent=`tabSales Invoice`.name
|
||||||
|
"""
|
||||||
for dimension in accounting_dimensions:
|
for dimension in accounting_dimensions:
|
||||||
if filters.get(dimension.fieldname):
|
if filters.get(dimension.fieldname):
|
||||||
if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
|
if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
|
||||||
filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
|
filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
|
||||||
filters.get(dimension.fieldname))
|
filters.get(dimension.fieldname))
|
||||||
|
|
||||||
conditions += """ and exists(select name from `tabSales Invoice Item`
|
conditions += common_condition + "and ifnull(`tabSales Invoice Item`.{0}, '') in %({0})s)".format(dimension.fieldname)
|
||||||
where parent=`tabSales Invoice`.name
|
else:
|
||||||
and ifnull(`tabSales Invoice Item`.{0}, '') in %({0})s)""".format(dimension.fieldname)
|
conditions += common_condition + "and ifnull(`tabSales Invoice Item`.{0}, '') in (%({0})s))".format(dimension.fieldname)
|
||||||
|
|
||||||
|
|
||||||
return conditions
|
return conditions
|
||||||
|
|
||||||
|
|||||||
@@ -126,7 +126,9 @@ def get_rootwise_opening_balances(filters, report_type):
|
|||||||
if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
|
if frappe.get_cached_value('DocType', dimension.document_type, 'is_tree'):
|
||||||
filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
|
filters[dimension.fieldname] = get_dimension_with_children(dimension.document_type,
|
||||||
filters.get(dimension.fieldname))
|
filters.get(dimension.fieldname))
|
||||||
additional_conditions += "and {0} in %({0})s".format(dimension.fieldname)
|
additional_conditions += "and {0} in %({0})s".format(dimension.fieldname)
|
||||||
|
else:
|
||||||
|
additional_conditions += "and {0} in (%({0})s)".format(dimension.fieldname)
|
||||||
|
|
||||||
query_filters.update({
|
query_filters.update({
|
||||||
dimension.fieldname: filters.get(dimension.fieldname)
|
dimension.fieldname: filters.get(dimension.fieldname)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,7 @@ from erpnext.accounts.doctype.pricing_rule.utils import (apply_pricing_rule_on_t
|
|||||||
from erpnext.exceptions import InvalidCurrency
|
from erpnext.exceptions import InvalidCurrency
|
||||||
from six import text_type
|
from six import text_type
|
||||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
|
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
|
||||||
|
from erpnext.stock.get_item_details import get_item_warehouse
|
||||||
|
|
||||||
force_item_fields = ("item_group", "brand", "stock_uom", "is_fixed_asset", "item_tax_rate", "pricing_rules")
|
force_item_fields = ("item_group", "brand", "stock_uom", "is_fixed_asset", "item_tax_rate", "pricing_rules")
|
||||||
|
|
||||||
@@ -1126,16 +1127,16 @@ def set_sales_order_defaults(parent_doctype, parent_doctype_name, child_docname,
|
|||||||
"""
|
"""
|
||||||
Returns a Sales Order Item child item containing the default values
|
Returns a Sales Order Item child item containing the default values
|
||||||
"""
|
"""
|
||||||
p_doctype = frappe.get_doc(parent_doctype, parent_doctype_name)
|
p_doc = frappe.get_doc(parent_doctype, parent_doctype_name)
|
||||||
child_item = frappe.new_doc('Sales Order Item', p_doctype, child_docname)
|
child_item = frappe.new_doc('Sales Order Item', p_doc, child_docname)
|
||||||
item = frappe.get_doc("Item", item_code)
|
item = frappe.get_doc("Item", item_code)
|
||||||
child_item.item_code = item.item_code
|
child_item.item_code = item.item_code
|
||||||
child_item.item_name = item.item_name
|
child_item.item_name = item.item_name
|
||||||
child_item.description = item.description
|
child_item.description = item.description
|
||||||
child_item.reqd_by_date = p_doctype.delivery_date
|
child_item.reqd_by_date = p_doc.delivery_date
|
||||||
child_item.uom = item.stock_uom
|
child_item.uom = item.stock_uom
|
||||||
child_item.conversion_factor = get_conversion_factor(item_code, item.stock_uom).get("conversion_factor") or 1.0
|
child_item.conversion_factor = get_conversion_factor(item_code, item.stock_uom).get("conversion_factor") or 1.0
|
||||||
child_item.warehouse = p_doctype.set_warehouse or p_doctype.items[0].warehouse
|
child_item.warehouse = get_item_warehouse(item, p_doc, overwrite_warehouse=True)
|
||||||
return child_item
|
return child_item
|
||||||
|
|
||||||
|
|
||||||
@@ -1143,13 +1144,13 @@ def set_purchase_order_defaults(parent_doctype, parent_doctype_name, child_docna
|
|||||||
"""
|
"""
|
||||||
Returns a Purchase Order Item child item containing the default values
|
Returns a Purchase Order Item child item containing the default values
|
||||||
"""
|
"""
|
||||||
p_doctype = frappe.get_doc(parent_doctype, parent_doctype_name)
|
p_doc = frappe.get_doc(parent_doctype, parent_doctype_name)
|
||||||
child_item = frappe.new_doc('Purchase Order Item', p_doctype, child_docname)
|
child_item = frappe.new_doc('Purchase Order Item', p_doc, child_docname)
|
||||||
item = frappe.get_doc("Item", item_code)
|
item = frappe.get_doc("Item", item_code)
|
||||||
child_item.item_code = item.item_code
|
child_item.item_code = item.item_code
|
||||||
child_item.item_name = item.item_name
|
child_item.item_name = item.item_name
|
||||||
child_item.description = item.description
|
child_item.description = item.description
|
||||||
child_item.schedule_date = p_doctype.schedule_date
|
child_item.schedule_date = p_doc.schedule_date
|
||||||
child_item.uom = item.stock_uom
|
child_item.uom = item.stock_uom
|
||||||
child_item.conversion_factor = get_conversion_factor(item_code, item.stock_uom).get("conversion_factor") or 1.0
|
child_item.conversion_factor = get_conversion_factor(item_code, item.stock_uom).get("conversion_factor") or 1.0
|
||||||
child_item.base_rate = 1 # Initiallize value will update in parent validation
|
child_item.base_rate = 1 # Initiallize value will update in parent validation
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ class StockController(AccountsController):
|
|||||||
super(StockController, self).validate()
|
super(StockController, self).validate()
|
||||||
self.validate_inspection()
|
self.validate_inspection()
|
||||||
self.validate_serialized_batch()
|
self.validate_serialized_batch()
|
||||||
|
self.validate_customer_provided_item()
|
||||||
|
|
||||||
def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False):
|
def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False):
|
||||||
if self.docstatus == 2:
|
if self.docstatus == 2:
|
||||||
@@ -368,6 +369,15 @@ class StockController(AccountsController):
|
|||||||
for blanket_order in blanket_orders:
|
for blanket_order in blanket_orders:
|
||||||
frappe.get_doc("Blanket Order", blanket_order).update_ordered_qty()
|
frappe.get_doc("Blanket Order", blanket_order).update_ordered_qty()
|
||||||
|
|
||||||
|
def validate_customer_provided_item(self):
|
||||||
|
for d in self.get('items'):
|
||||||
|
# Customer Provided parts will have zero valuation rate
|
||||||
|
if frappe.db.get_value('Item', d.item_code, 'is_customer_provided_item'):
|
||||||
|
d.allow_zero_valuation_rate = 1
|
||||||
|
if d.parenttype in ["Delivery Note", "Sales Invoice"] and d.rate:
|
||||||
|
frappe.throw(_("Row #{0}: {1} cannot have {2} as it is a Customer Provided Item")
|
||||||
|
.format(d.idx, frappe.bold(d.item_code), frappe.bold("Rate")))
|
||||||
|
|
||||||
def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None,
|
def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None,
|
||||||
warehouse_account=None, company=None):
|
warehouse_account=None, company=None):
|
||||||
def _delete_gl_entries(voucher_type, voucher_no):
|
def _delete_gl_entries(voucher_type, voucher_no):
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ def call_mws_method(mws_method, *args, **kwargs):
|
|||||||
time.sleep(delay)
|
time.sleep(delay)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
mws_settings.enable_synch = 0
|
mws_settings.enable_sync = 0
|
||||||
mws_settings.save()
|
mws_settings.save()
|
||||||
|
|
||||||
frappe.throw(_("Sync has been temporarily disabled because maximum retries have been exceeded"))
|
frappe.throw(_("Sync has been temporarily disabled because maximum retries have been exceeded"))
|
||||||
|
|||||||
@@ -39,16 +39,19 @@ __all__ = [
|
|||||||
# for a list of the end points and marketplace IDs
|
# for a list of the end points and marketplace IDs
|
||||||
|
|
||||||
MARKETPLACES = {
|
MARKETPLACES = {
|
||||||
"CA" : "https://mws.amazonservices.ca", #A2EUQ1WTGCTBG2
|
"CA": "https://mws.amazonservices.ca", #A2EUQ1WTGCTBG2
|
||||||
"US" : "https://mws.amazonservices.com", #ATVPDKIKX0DER",
|
"US": "https://mws.amazonservices.com", #ATVPDKIKX0DER",
|
||||||
"DE" : "https://mws-eu.amazonservices.com", #A1PA6795UKMFR9
|
"DE": "https://mws-eu.amazonservices.com", #A1PA6795UKMFR9
|
||||||
"ES" : "https://mws-eu.amazonservices.com", #A1RKKUPIHCS9HS
|
"ES": "https://mws-eu.amazonservices.com", #A1RKKUPIHCS9HS
|
||||||
"FR" : "https://mws-eu.amazonservices.com", #A13V1IB3VIYZZH
|
"FR": "https://mws-eu.amazonservices.com", #A13V1IB3VIYZZH
|
||||||
"IN" : "https://mws.amazonservices.in", #A21TJRUUN4KGV
|
"IN": "https://mws.amazonservices.in", #A21TJRUUN4KGV
|
||||||
"IT" : "https://mws-eu.amazonservices.com", #APJ6JRA9NG5V4
|
"IT": "https://mws-eu.amazonservices.com", #APJ6JRA9NG5V4
|
||||||
"UK" : "https://mws-eu.amazonservices.com", #A1F83G8C2ARO7P
|
"UK": "https://mws-eu.amazonservices.com", #A1F83G8C2ARO7P
|
||||||
"JP" : "https://mws.amazonservices.jp", #A1VC38T7YXB528
|
"JP": "https://mws.amazonservices.jp", #A1VC38T7YXB528
|
||||||
"CN" : "https://mws.amazonservices.com.cn", #AAHKV2X7AFYLW
|
"CN": "https://mws.amazonservices.com.cn", #AAHKV2X7AFYLW
|
||||||
|
"AE": " https://mws.amazonservices.ae", #A2VIGQ35RCS4UG
|
||||||
|
"MX": "https://mws.amazonservices.com.mx", #A1AM78C64UM0Y8
|
||||||
|
"BR": "https://mws.amazonservices.com", #A2Q3Y263D00KWC
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -7,14 +7,15 @@ import frappe
|
|||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
import dateutil
|
import dateutil
|
||||||
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
|
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
|
||||||
|
from erpnext.erpnext_integrations.doctype.amazon_mws_settings.amazon_methods import get_orders
|
||||||
|
|
||||||
class AmazonMWSSettings(Document):
|
class AmazonMWSSettings(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
if self.enable_amazon == 1:
|
if self.enable_amazon == 1:
|
||||||
self.enable_synch = 1
|
self.enable_sync = 1
|
||||||
setup_custom_fields()
|
setup_custom_fields()
|
||||||
else:
|
else:
|
||||||
self.enable_synch = 0
|
self.enable_sync = 0
|
||||||
|
|
||||||
def get_products_details(self):
|
def get_products_details(self):
|
||||||
if self.enable_amazon == 1:
|
if self.enable_amazon == 1:
|
||||||
@@ -27,7 +28,7 @@ class AmazonMWSSettings(Document):
|
|||||||
|
|
||||||
def schedule_get_order_details():
|
def schedule_get_order_details():
|
||||||
mws_settings = frappe.get_doc("Amazon MWS Settings")
|
mws_settings = frappe.get_doc("Amazon MWS Settings")
|
||||||
if mws_settings.enable_synch and mws_settings.enable_amazon:
|
if mws_settings.enable_sync and mws_settings.enable_amazon:
|
||||||
after_date = dateutil.parser.parse(mws_settings.after_date).strftime("%Y-%m-%d")
|
after_date = dateutil.parser.parse(mws_settings.after_date).strftime("%Y-%m-%d")
|
||||||
get_orders(after_date = after_date)
|
get_orders(after_date = after_date)
|
||||||
|
|
||||||
|
|||||||
@@ -245,7 +245,7 @@ doc_events = {
|
|||||||
"on_trash": "erpnext.regional.check_deletion_permission"
|
"on_trash": "erpnext.regional.check_deletion_permission"
|
||||||
},
|
},
|
||||||
"Payment Entry": {
|
"Payment Entry": {
|
||||||
"on_submit": ["erpnext.regional.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.update_payment_req_status"],
|
||||||
"on_trash": "erpnext.regional.check_deletion_permission"
|
"on_trash": "erpnext.regional.check_deletion_permission"
|
||||||
},
|
},
|
||||||
'Address': {
|
'Address': {
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ class LeaveApplication(Document):
|
|||||||
if self.status == "Approved":
|
if self.status == "Approved":
|
||||||
for dt in daterange(getdate(self.from_date), getdate(self.to_date)):
|
for dt in daterange(getdate(self.from_date), getdate(self.to_date)):
|
||||||
date = dt.strftime("%Y-%m-%d")
|
date = dt.strftime("%Y-%m-%d")
|
||||||
status = "Half Day" if date == self.half_day_date else "On Leave"
|
status = "Half Day" if getdate(date) == getdate(self.half_day_date) else "On Leave"
|
||||||
|
|
||||||
attendance_name = frappe.db.exists('Attendance', dict(employee = self.employee,
|
attendance_name = frappe.db.exists('Attendance', dict(employee = self.employee,
|
||||||
attendance_date = date, docstatus = ('!=', 2)))
|
attendance_date = date, docstatus = ('!=', 2)))
|
||||||
|
|||||||
@@ -355,13 +355,13 @@ class SalarySlip(TransactionBase):
|
|||||||
|
|
||||||
def eval_condition_and_formula(self, d, data):
|
def eval_condition_and_formula(self, d, data):
|
||||||
try:
|
try:
|
||||||
condition = d.condition.strip() if d.condition else None
|
condition = d.condition.strip().replace("\n", " ") if d.condition else None
|
||||||
if condition:
|
if condition:
|
||||||
if not frappe.safe_eval(condition, self.whitelisted_globals, data):
|
if not frappe.safe_eval(condition, self.whitelisted_globals, data):
|
||||||
return None
|
return None
|
||||||
amount = d.amount
|
amount = d.amount
|
||||||
if d.amount_based_on_formula:
|
if d.amount_based_on_formula:
|
||||||
formula = d.formula.strip() if d.formula else None
|
formula = d.formula.strip().replace("\n", " ") if d.formula else None
|
||||||
if formula:
|
if formula:
|
||||||
amount = flt(frappe.safe_eval(formula, self.whitelisted_globals, data), d.precision("amount"))
|
amount = flt(frappe.safe_eval(formula, self.whitelisted_globals, data), d.precision("amount"))
|
||||||
if amount:
|
if amount:
|
||||||
|
|||||||
@@ -582,7 +582,7 @@ erpnext.patches.v11_0.rename_bom_wo_fields
|
|||||||
erpnext.patches.v12_0.set_default_homepage_type
|
erpnext.patches.v12_0.set_default_homepage_type
|
||||||
erpnext.patches.v11_0.rename_additional_salary_component_additional_salary
|
erpnext.patches.v11_0.rename_additional_salary_component_additional_salary
|
||||||
erpnext.patches.v11_0.renamed_from_to_fields_in_project
|
erpnext.patches.v11_0.renamed_from_to_fields_in_project
|
||||||
erpnext.patches.v11_0.add_permissions_in_gst_settings
|
erpnext.patches.v11_0.add_permissions_in_gst_settings #2020-04-04
|
||||||
erpnext.patches.v11_1.setup_guardian_role
|
erpnext.patches.v11_1.setup_guardian_role
|
||||||
execute:frappe.delete_doc('DocType', 'Notification Control')
|
execute:frappe.delete_doc('DocType', 'Notification Control')
|
||||||
erpnext.patches.v12_0.set_gst_category
|
erpnext.patches.v12_0.set_gst_category
|
||||||
@@ -627,10 +627,11 @@ erpnext.patches.v12_0.update_ewaybill_field_position
|
|||||||
erpnext.patches.v12_0.create_accounting_dimensions_in_missing_doctypes
|
erpnext.patches.v12_0.create_accounting_dimensions_in_missing_doctypes
|
||||||
erpnext.patches.v11_1.set_status_for_material_request_type_manufacture
|
erpnext.patches.v11_1.set_status_for_material_request_type_manufacture
|
||||||
erpnext.patches.v12_0.move_plaid_settings_to_doctype
|
erpnext.patches.v12_0.move_plaid_settings_to_doctype
|
||||||
execute:frappe.reload_doc('desk', 'doctype','dashboard_chart_link')
|
execute:frappe.reload_doc('desk', 'doctype', 'dashboard_chart_link')
|
||||||
execute:frappe.reload_doc('desk', 'doctype','dashboard')
|
execute:frappe.reload_doc('desk', 'doctype', 'dashboard')
|
||||||
execute:frappe.reload_doc('desk', 'doctype','dashboard_chart_source')
|
execute:frappe.reload_doc('desk', 'doctype', 'dashboard_chart_source')
|
||||||
execute:frappe.reload_doc('desk', 'doctype','dashboard_chart')
|
execute:frappe.reload_doc('desk', 'doctype', 'dashboard_chart')
|
||||||
|
execute:frappe.reload_doc('desk', 'doctype', 'dashboard_chart_field')
|
||||||
erpnext.patches.v12_0.add_default_dashboards
|
erpnext.patches.v12_0.add_default_dashboards
|
||||||
erpnext.patches.v12_0.remove_bank_remittance_custom_fields
|
erpnext.patches.v12_0.remove_bank_remittance_custom_fields
|
||||||
erpnext.patches.v12_0.generate_leave_ledger_entries
|
erpnext.patches.v12_0.generate_leave_ledger_entries
|
||||||
@@ -651,3 +652,6 @@ erpnext.patches.v12_0.add_export_type_field_in_party_master
|
|||||||
erpnext.patches.v12_0.rename_bank_reconciliation_fields # 2020-01-22
|
erpnext.patches.v12_0.rename_bank_reconciliation_fields # 2020-01-22
|
||||||
erpnext.patches.v12_0.create_irs_1099_field_united_states
|
erpnext.patches.v12_0.create_irs_1099_field_united_states
|
||||||
erpnext.patches.v12_0.set_permission_einvoicing
|
erpnext.patches.v12_0.set_permission_einvoicing
|
||||||
|
erpnext.patches.v12_0.set_received_qty_in_material_request_as_per_stock_uom
|
||||||
|
erpnext.patches.v12_0.recalculate_requested_qty_in_bin
|
||||||
|
erpnext.patches.v12_0.rename_mws_settings_fields
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe.permissions import add_permission, update_permission_property
|
from erpnext.regional.india.setup import add_permissions
|
||||||
|
|
||||||
def execute():
|
def execute():
|
||||||
company = frappe.get_all('Company', filters = {'country': 'India'})
|
company = frappe.get_all('Company', filters = {'country': 'India'})
|
||||||
if not company:
|
if not company:
|
||||||
return
|
return
|
||||||
|
|
||||||
for doctype in ('GST HSN Code', 'GST Settings'):
|
add_permissions()
|
||||||
add_permission(doctype, 'Accounts Manager', 0)
|
|
||||||
update_permission_property(doctype, 'Accounts Manager', 0, 'write', 1)
|
|
||||||
update_permission_property(doctype, 'Accounts Manager', 0, 'create', 1)
|
|
||||||
13
erpnext/patches/v12_0/recalculate_requested_qty_in_bin.py
Normal file
13
erpnext/patches/v12_0/recalculate_requested_qty_in_bin.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
from erpnext.stock.stock_balance import update_bin_qty, get_indented_qty
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
bin_details = frappe.db.sql("""
|
||||||
|
SELECT item_code, warehouse
|
||||||
|
FROM `tabBin`""",as_dict=1)
|
||||||
|
|
||||||
|
for entry in bin_details:
|
||||||
|
update_bin_qty(entry.get("item_code"), entry.get("warehouse"), {
|
||||||
|
"indented_qty": get_indented_qty(entry.get("item_code"), entry.get("warehouse"))
|
||||||
|
})
|
||||||
11
erpnext/patches/v12_0/rename_mws_settings_fields.py
Normal file
11
erpnext/patches/v12_0/rename_mws_settings_fields.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# Copyright (c) 2020, Frappe and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
count = frappe.db.sql("SELECT COUNT(*) FROM `tabSingles` WHERE doctype='Amazon MWS Settings' AND field='enable_sync';")[0][0]
|
||||||
|
if count == 0:
|
||||||
|
frappe.db.sql("UPDATE `tabSingles` SET field='enable_sync' WHERE doctype='Amazon MWS Settings' AND field='enable_synch';")
|
||||||
|
|
||||||
|
frappe.reload_doc("ERPNext Integrations", "doctype", "Amazon MWS Settings")
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
purchase_receipts = frappe.db.sql("""
|
||||||
|
SELECT
|
||||||
|
parent from `tabPurchase Receipt Item`
|
||||||
|
WHERE
|
||||||
|
material_request is not null
|
||||||
|
AND docstatus=1
|
||||||
|
""",as_dict=1)
|
||||||
|
|
||||||
|
purchase_receipts = set([d.parent for d in purchase_receipts])
|
||||||
|
|
||||||
|
for pr in purchase_receipts:
|
||||||
|
doc = frappe.get_doc("Purchase Receipt", pr)
|
||||||
|
doc.status_updater = [
|
||||||
|
{
|
||||||
|
'source_dt': 'Purchase Receipt Item',
|
||||||
|
'target_dt': 'Material Request Item',
|
||||||
|
'join_field': 'material_request_item',
|
||||||
|
'target_field': 'received_qty',
|
||||||
|
'target_parent_dt': 'Material Request',
|
||||||
|
'target_parent_field': 'per_received',
|
||||||
|
'target_ref_field': 'stock_qty',
|
||||||
|
'source_field': 'stock_qty',
|
||||||
|
'percent_join_field': 'material_request'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
doc.update_qty()
|
||||||
@@ -56,7 +56,6 @@ $.extend(frappe.breadcrumbs.preferred, {
|
|||||||
$.extend(frappe.breadcrumbs.module_map, {
|
$.extend(frappe.breadcrumbs.module_map, {
|
||||||
'ERPNext Integrations': 'Integrations',
|
'ERPNext Integrations': 'Integrations',
|
||||||
'Geo': 'Settings',
|
'Geo': 'Settings',
|
||||||
'Accounts': 'Accounting',
|
|
||||||
'Portal': 'Website',
|
'Portal': 'Website',
|
||||||
'Utilities': 'Settings',
|
'Utilities': 'Settings',
|
||||||
'Shopping Cart': 'Website',
|
'Shopping Cart': 'Website',
|
||||||
|
|||||||
@@ -85,12 +85,6 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
|||||||
filters:{ 'is_sub_contracted_item': 1 }
|
filters:{ 'is_sub_contracted_item': 1 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (me.frm.doc.material_request_type == "Customer Provided") {
|
|
||||||
return{
|
|
||||||
query: "erpnext.controllers.queries.item_query",
|
|
||||||
filters:{ 'customer': me.frm.doc.customer }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
return{
|
return{
|
||||||
query: "erpnext.controllers.queries.item_query",
|
query: "erpnext.controllers.queries.item_query",
|
||||||
|
|||||||
@@ -473,6 +473,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
item_code: item.item_code,
|
item_code: item.item_code,
|
||||||
barcode: item.barcode,
|
barcode: item.barcode,
|
||||||
serial_no: item.serial_no,
|
serial_no: item.serial_no,
|
||||||
|
batch_no: item.batch_no,
|
||||||
set_warehouse: me.frm.doc.set_warehouse,
|
set_warehouse: me.frm.doc.set_warehouse,
|
||||||
warehouse: item.warehouse,
|
warehouse: item.warehouse,
|
||||||
customer: me.frm.doc.customer || me.frm.doc.party_name,
|
customer: me.frm.doc.customer || me.frm.doc.party_name,
|
||||||
@@ -599,6 +600,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
|
|
||||||
// Add the new list to the serial no. field in grid with each in new line
|
// Add the new list to the serial no. field in grid with each in new line
|
||||||
item.serial_no = valid_serial_nos.join('\n');
|
item.serial_no = valid_serial_nos.join('\n');
|
||||||
|
item.conversion_factor = item.conversion_factor || 1;
|
||||||
|
|
||||||
refresh_field("serial_no", item.name, item.parentfield);
|
refresh_field("serial_no", item.name, item.parentfield);
|
||||||
if(!doc.is_return && cint(user_defaults.set_qty_in_transactions_based_on_serial_no_input)) {
|
if(!doc.is_return && cint(user_defaults.set_qty_in_transactions_based_on_serial_no_input)) {
|
||||||
@@ -854,7 +856,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
|
|
||||||
shipping_rule: function() {
|
shipping_rule: function() {
|
||||||
var me = this;
|
var me = this;
|
||||||
if(this.frm.doc.shipping_rule) {
|
if(this.frm.doc.shipping_rule && this.frm.doc.shipping_address) {
|
||||||
return this.frm.call({
|
return this.frm.call({
|
||||||
doc: this.frm.doc,
|
doc: this.frm.doc,
|
||||||
method: "apply_shipping_rule",
|
method: "apply_shipping_rule",
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class Quiz {
|
|||||||
this.questions.push(question)
|
this.questions.push(question)
|
||||||
this.wrapper.appendChild(question_wrapper);
|
this.wrapper.appendChild(question_wrapper);
|
||||||
})
|
})
|
||||||
if (data.activity.is_complete) {
|
if (data.activity && data.activity.is_complete) {
|
||||||
this.disable()
|
this.disable()
|
||||||
let indicator = 'red'
|
let indicator = 'red'
|
||||||
let message = 'Your are not allowed to attempt the quiz again.'
|
let message = 'Your are not allowed to attempt the quiz again.'
|
||||||
|
|||||||
@@ -453,7 +453,8 @@ erpnext.utils.update_child_items = function(opts) {
|
|||||||
fields: [{
|
fields: [{
|
||||||
fieldtype:'Data',
|
fieldtype:'Data',
|
||||||
fieldname:"docname",
|
fieldname:"docname",
|
||||||
hidden: 0,
|
read_only: 1,
|
||||||
|
hidden: 1,
|
||||||
}, {
|
}, {
|
||||||
fieldtype:'Link',
|
fieldtype:'Link',
|
||||||
fieldname:"item_code",
|
fieldname:"item_code",
|
||||||
|
|||||||
@@ -8,12 +8,19 @@ frappe.ui.form.ItemQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
|
|||||||
render_dialog: function() {
|
render_dialog: function() {
|
||||||
this.mandatory = this.get_variant_fields().concat(this.mandatory);
|
this.mandatory = this.get_variant_fields().concat(this.mandatory);
|
||||||
this.mandatory = this.mandatory.concat(this.get_attributes_fields());
|
this.mandatory = this.mandatory.concat(this.get_attributes_fields());
|
||||||
|
this.check_naming_series_based_on();
|
||||||
this._super();
|
this._super();
|
||||||
this.init_post_render_dialog_operations();
|
this.init_post_render_dialog_operations();
|
||||||
this.preset_fields_for_template();
|
this.preset_fields_for_template();
|
||||||
this.dialog.$wrapper.find('.edit-full').text(__('Edit in full page for more options like assets, serial nos, batches etc.'))
|
this.dialog.$wrapper.find('.edit-full').text(__('Edit in full page for more options like assets, serial nos, batches etc.'))
|
||||||
},
|
},
|
||||||
|
|
||||||
|
check_naming_series_based_on: function() {
|
||||||
|
if (frappe.defaults.get_default("item_naming_by") === "Naming Series") {
|
||||||
|
this.mandatory = this.mandatory.filter(d => d.fieldname !== "item_code");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
init_post_render_dialog_operations: function() {
|
init_post_render_dialog_operations: function() {
|
||||||
this.dialog.fields_dict.attribute_html.$wrapper.append(frappe.render_template("item_quick_entry"));
|
this.dialog.fields_dict.attribute_html.$wrapper.append(frappe.render_template("item_quick_entry"));
|
||||||
this.init_for_create_variant_trigger();
|
this.init_for_create_variant_trigger();
|
||||||
|
|||||||
@@ -78,3 +78,7 @@
|
|||||||
z-index: 0;
|
z-index: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.place-order-container {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>(a) {{__("Outward taxable supplies(other than zero rated, nil rated and exempted")}}</td>
|
<td>(a) {{__("Outward taxable supplies(other than zero rated, nil rated and exempted)")}}</td>
|
||||||
<td class="right">{{ flt(data.sup_details.osup_det.txval, 2) }}</td>
|
<td class="right">{{ flt(data.sup_details.osup_det.txval, 2) }}</td>
|
||||||
<td class="right">{{ flt(data.sup_details.osup_det.iamt, 2) }}</td>
|
<td class="right">{{ flt(data.sup_details.osup_det.iamt, 2) }}</td>
|
||||||
<td class="right">{{ flt(data.sup_details.osup_det.camt, 2) }}</td>
|
<td class="right">{{ flt(data.sup_details.osup_det.camt, 2) }}</td>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"autoname": "format:GSTR3B-{month}-{year}-{company_address}",
|
"autoname": "format:GSTR3B-{month}-{year}-{company_address}",
|
||||||
"creation": "2019-02-04 11:35:55.964639",
|
"creation": "2019-02-04 11:35:55.964639",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
@@ -48,25 +49,13 @@
|
|||||||
"read_only": 1
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"modified": "2019-08-10 22:30:26.727038",
|
"links": [],
|
||||||
|
"modified": "2020-04-04 19:32:30.772908",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Regional",
|
"module": "Regional",
|
||||||
"name": "GSTR 3B Report",
|
"name": "GSTR 3B Report",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [
|
"permissions": [],
|
||||||
{
|
|
||||||
"create": 1,
|
|
||||||
"delete": 1,
|
|
||||||
"email": 1,
|
|
||||||
"export": 1,
|
|
||||||
"print": 1,
|
|
||||||
"read": 1,
|
|
||||||
"report": 1,
|
|
||||||
"role": "System Manager",
|
|
||||||
"share": 1,
|
|
||||||
"write": 1
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"track_changes": 1
|
"track_changes": 1
|
||||||
|
|||||||
@@ -77,13 +77,19 @@ def add_custom_roles_for_reports():
|
|||||||
)).insert()
|
)).insert()
|
||||||
|
|
||||||
def add_permissions():
|
def add_permissions():
|
||||||
for doctype in ('GST HSN Code', 'GST Settings'):
|
for doctype in ('GST HSN Code', 'GST Settings', 'GSTR 3B Report'):
|
||||||
add_permission(doctype, 'All', 0)
|
add_permission(doctype, 'All', 0)
|
||||||
for role in ('Accounts Manager', 'System Manager', 'Item Manager', 'Stock Manager'):
|
for role in ('Accounts Manager', 'Accounts User', 'System Manager'):
|
||||||
add_permission(doctype, role, 0)
|
add_permission(doctype, role, 0)
|
||||||
update_permission_property(doctype, role, 0, 'write', 1)
|
update_permission_property(doctype, role, 0, 'write', 1)
|
||||||
update_permission_property(doctype, role, 0, 'create', 1)
|
update_permission_property(doctype, role, 0, 'create', 1)
|
||||||
|
|
||||||
|
if doctype == 'GST HSN Code':
|
||||||
|
for role in ('Item Manager', 'Stock Manager'):
|
||||||
|
add_permission(doctype, role, 0)
|
||||||
|
update_permission_property(doctype, role, 0, 'write', 1)
|
||||||
|
update_permission_property(doctype, role, 0, 'create', 1)
|
||||||
|
|
||||||
def add_print_formats():
|
def add_print_formats():
|
||||||
frappe.reload_doc("regional", "print_format", "gst_tax_invoice")
|
frappe.reload_doc("regional", "print_format", "gst_tax_invoice")
|
||||||
frappe.reload_doc("accounts", "print_format", "gst_pos_invoice")
|
frappe.reload_doc("accounts", "print_format", "gst_pos_invoice")
|
||||||
|
|||||||
@@ -25,6 +25,8 @@
|
|||||||
"territory",
|
"territory",
|
||||||
"tax_id",
|
"tax_id",
|
||||||
"tax_category",
|
"tax_category",
|
||||||
|
"so_required",
|
||||||
|
"dn_required",
|
||||||
"disabled",
|
"disabled",
|
||||||
"is_internal_customer",
|
"is_internal_customer",
|
||||||
"represents_company",
|
"represents_company",
|
||||||
@@ -466,13 +468,25 @@
|
|||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"label": "Credit Limit",
|
"label": "Credit Limit",
|
||||||
"options": "Customer Credit Limit"
|
"options": "Customer Credit Limit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fieldname": "so_required",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Allow Sales Invoice Creation Without Sales Order"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fieldname": "dn_required",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Allow Sales Invoice Creation Without Delivery Note"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-user",
|
"icon": "fa fa-user",
|
||||||
"idx": 363,
|
"idx": 363,
|
||||||
"image_field": "image",
|
"image_field": "image",
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-01-29 20:36:37.879581",
|
"modified": "2020-03-17 11:03:42.706907",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Selling",
|
"module": "Selling",
|
||||||
"name": "Customer",
|
"name": "Customer",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import getdate, cint
|
from frappe.utils import getdate, cint, cstr
|
||||||
import calendar
|
import calendar
|
||||||
|
|
||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
@@ -48,7 +48,7 @@ def execute(filters=None):
|
|||||||
new = new_customers_in.get(key, [0,0.0])
|
new = new_customers_in.get(key, [0,0.0])
|
||||||
repeat = repeat_customers_in.get(key, [0,0.0])
|
repeat = repeat_customers_in.get(key, [0,0.0])
|
||||||
|
|
||||||
out.append([year, calendar.month_name[month],
|
out.append([cstr(year), calendar.month_name[month],
|
||||||
new[0], repeat[0], new[0] + repeat[0],
|
new[0], repeat[0], new[0] + repeat[0],
|
||||||
new[1], repeat[1], new[1] + repeat[1]])
|
new[1], repeat[1], new[1] + repeat[1]])
|
||||||
|
|
||||||
|
|||||||
@@ -38,14 +38,14 @@ def get_cart_quotation(doc=None):
|
|||||||
addresses = get_address_docs(party=party)
|
addresses = get_address_docs(party=party)
|
||||||
|
|
||||||
if not doc.customer_address and addresses:
|
if not doc.customer_address and addresses:
|
||||||
update_cart_address("customer_address", addresses[0].name)
|
update_cart_address("billing", addresses[0].name)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"doc": decorate_quotation_doc(doc),
|
"doc": decorate_quotation_doc(doc),
|
||||||
"shipping_addresses": [{"name": address.name, "display": address.display}
|
"shipping_addresses": [{"name": address.name, "display": address.display}
|
||||||
for address in addresses],
|
for address in addresses if address.address_type == "Shipping"],
|
||||||
"billing_addresses": [{"name": address.name, "display": address.display}
|
"billing_addresses": [{"name": address.name, "display": address.display}
|
||||||
for address in addresses],
|
for address in addresses if address.address_type == "Billing"],
|
||||||
"shipping_rules": get_applicable_shipping_rules(party),
|
"shipping_rules": get_applicable_shipping_rules(party),
|
||||||
"cart_settings": frappe.get_cached_doc("Shopping Cart Settings")
|
"cart_settings": frappe.get_cached_doc("Shopping Cart Settings")
|
||||||
}
|
}
|
||||||
@@ -64,6 +64,9 @@ def place_order():
|
|||||||
# company used to create customer accounts
|
# company used to create customer accounts
|
||||||
frappe.defaults.set_user_default("company", quotation.company)
|
frappe.defaults.set_user_default("company", quotation.company)
|
||||||
|
|
||||||
|
if not (quotation.shipping_address_name or quotation.customer_address):
|
||||||
|
frappe.throw(_("Set Shipping Address or Billing Address"))
|
||||||
|
|
||||||
from erpnext.selling.doctype.quotation.quotation import _make_sales_order
|
from erpnext.selling.doctype.quotation.quotation import _make_sales_order
|
||||||
sales_order = frappe.get_doc(_make_sales_order(quotation.name, ignore_permissions=True))
|
sales_order = frappe.get_doc(_make_sales_order(quotation.name, ignore_permissions=True))
|
||||||
sales_order.payment_schedule = []
|
sales_order.payment_schedule = []
|
||||||
@@ -194,21 +197,18 @@ def get_terms_and_conditions(terms_name):
|
|||||||
return frappe.db.get_value('Terms and Conditions', terms_name, 'terms')
|
return frappe.db.get_value('Terms and Conditions', terms_name, 'terms')
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def update_cart_address(address_fieldname, address_name):
|
def update_cart_address(address_type, address_name):
|
||||||
quotation = _get_cart_quotation()
|
quotation = _get_cart_quotation()
|
||||||
address_display = get_address_display(frappe.get_doc("Address", address_name).as_dict())
|
address_display = get_address_display(frappe.get_doc("Address", address_name).as_dict())
|
||||||
|
|
||||||
if address_fieldname == "shipping_address_name":
|
if address_type.lower() == "billing":
|
||||||
quotation.shipping_address_name = address_name
|
|
||||||
quotation.shipping_address = address_display
|
|
||||||
|
|
||||||
if not quotation.customer_address:
|
|
||||||
address_fieldname == "customer_address"
|
|
||||||
|
|
||||||
if address_fieldname == "customer_address":
|
|
||||||
quotation.customer_address = address_name
|
quotation.customer_address = address_name
|
||||||
quotation.address_display = address_display
|
quotation.address_display = address_display
|
||||||
|
quotation.shipping_address_name == quotation.shipping_address_name or address_name
|
||||||
|
elif address_type.lower() == "shipping":
|
||||||
|
quotation.shipping_address_name = address_name
|
||||||
|
quotation.shipping_address = address_display
|
||||||
|
quotation.customer_address == quotation.customer_address or address_name
|
||||||
|
|
||||||
apply_cart_settings(quotation=quotation)
|
apply_cart_settings(quotation=quotation)
|
||||||
|
|
||||||
|
|||||||
@@ -111,7 +111,6 @@ class DeliveryNote(SellingController):
|
|||||||
self.so_required()
|
self.so_required()
|
||||||
self.validate_proj_cust()
|
self.validate_proj_cust()
|
||||||
self.check_sales_order_on_hold_or_close("against_sales_order")
|
self.check_sales_order_on_hold_or_close("against_sales_order")
|
||||||
self.validate_for_items()
|
|
||||||
self.validate_warehouse()
|
self.validate_warehouse()
|
||||||
self.validate_uom_is_integer("stock_uom", "stock_qty")
|
self.validate_uom_is_integer("stock_uom", "stock_qty")
|
||||||
self.validate_uom_is_integer("uom", "qty")
|
self.validate_uom_is_integer("uom", "qty")
|
||||||
@@ -165,12 +164,6 @@ class DeliveryNote(SellingController):
|
|||||||
if not res:
|
if not res:
|
||||||
frappe.throw(_("Customer {0} does not belong to project {1}").format(self.customer, self.project))
|
frappe.throw(_("Customer {0} does not belong to project {1}").format(self.customer, self.project))
|
||||||
|
|
||||||
def validate_for_items(self):
|
|
||||||
for d in self.get('items'):
|
|
||||||
#Customer Provided parts will have zero valuation rate
|
|
||||||
if frappe.db.get_value('Item', d.item_code, 'is_customer_provided_item'):
|
|
||||||
d.allow_zero_valuation_rate = 1
|
|
||||||
|
|
||||||
def validate_warehouse(self):
|
def validate_warehouse(self):
|
||||||
super(DeliveryNote, self).validate_warehouse()
|
super(DeliveryNote, self).validate_warehouse()
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation \
|
|||||||
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order, create_dn_against_so
|
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order, create_dn_against_so
|
||||||
from erpnext.accounts.doctype.account.test_account import get_inventory_account, create_account
|
from erpnext.accounts.doctype.account.test_account import get_inventory_account, create_account
|
||||||
from erpnext.stock.doctype.warehouse.test_warehouse import get_warehouse
|
from erpnext.stock.doctype.warehouse.test_warehouse import get_warehouse
|
||||||
|
from erpnext.stock.doctype.item.test_item import create_item
|
||||||
|
|
||||||
class TestDeliveryNote(unittest.TestCase):
|
class TestDeliveryNote(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@@ -433,6 +434,15 @@ class TestDeliveryNote(unittest.TestCase):
|
|||||||
update_delivery_note_status(dn.name, "Closed")
|
update_delivery_note_status(dn.name, "Closed")
|
||||||
self.assertEqual(frappe.db.get_value("Delivery Note", dn.name, "Status"), "Closed")
|
self.assertEqual(frappe.db.get_value("Delivery Note", dn.name, "Status"), "Closed")
|
||||||
|
|
||||||
|
def test_customer_provided_parts_dn(self):
|
||||||
|
create_item('CUST-0987', is_customer_provided_item = 1, customer = '_Test Customer', is_purchase_item = 0)
|
||||||
|
dn = create_delivery_note(item_code='CUST-0987', rate=0)
|
||||||
|
self.assertEqual(dn.get("items")[0].allow_zero_valuation_rate, 1)
|
||||||
|
|
||||||
|
# test if Delivery Note with rate is allowed against Customer Provided Item
|
||||||
|
dn2 = create_delivery_note(item_code='CUST-0987', do_not_save=True)
|
||||||
|
self.assertRaises(frappe.ValidationError, dn2.save)
|
||||||
|
|
||||||
def test_dn_billing_status_case1(self):
|
def test_dn_billing_status_case1(self):
|
||||||
# SO -> DN -> SI
|
# SO -> DN -> SI
|
||||||
so = make_sales_order()
|
so = make_sales_order()
|
||||||
@@ -671,7 +681,7 @@ def create_delivery_note(**args):
|
|||||||
"item_code": args.item or args.item_code or "_Test Item",
|
"item_code": args.item or args.item_code or "_Test Item",
|
||||||
"warehouse": args.warehouse or "_Test Warehouse - _TC",
|
"warehouse": args.warehouse or "_Test Warehouse - _TC",
|
||||||
"qty": args.qty or 1,
|
"qty": args.qty or 1,
|
||||||
"rate": args.rate or 100,
|
"rate": args.rate if args.get("rate") is not None else 100,
|
||||||
"conversion_factor": 1.0,
|
"conversion_factor": 1.0,
|
||||||
"allow_zero_valuation_rate": args.allow_zero_valuation_rate or 1,
|
"allow_zero_valuation_rate": args.allow_zero_valuation_rate or 1,
|
||||||
"expense_account": args.expense_account or "Cost of Goods Sold - _TC",
|
"expense_account": args.expense_account or "Cost of Goods Sold - _TC",
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ class Item(WebsiteGenerator):
|
|||||||
self.add_default_uom_in_conversion_factor_table()
|
self.add_default_uom_in_conversion_factor_table()
|
||||||
self.validate_conversion_factor()
|
self.validate_conversion_factor()
|
||||||
self.validate_item_type()
|
self.validate_item_type()
|
||||||
|
self.validate_naming_series()
|
||||||
self.check_for_active_boms()
|
self.check_for_active_boms()
|
||||||
self.fill_customer_code()
|
self.fill_customer_code()
|
||||||
self.check_item_tax()
|
self.check_item_tax()
|
||||||
@@ -186,7 +187,7 @@ class Item(WebsiteGenerator):
|
|||||||
or frappe.db.get_single_value('Stock Settings', 'default_warehouse'))
|
or frappe.db.get_single_value('Stock Settings', 'default_warehouse'))
|
||||||
if default_warehouse:
|
if default_warehouse:
|
||||||
warehouse_company = frappe.db.get_value("Warehouse", default_warehouse, "company")
|
warehouse_company = frappe.db.get_value("Warehouse", default_warehouse, "company")
|
||||||
|
|
||||||
if not default_warehouse or warehouse_company != default.company:
|
if not default_warehouse or warehouse_company != default.company:
|
||||||
default_warehouse = frappe.db.get_value('Warehouse',
|
default_warehouse = frappe.db.get_value('Warehouse',
|
||||||
{'warehouse_name': _('Stores'), 'company': default.company})
|
{'warehouse_name': _('Stores'), 'company': default.company})
|
||||||
@@ -522,6 +523,13 @@ class Item(WebsiteGenerator):
|
|||||||
if self.has_serial_no == 0 and self.serial_no_series:
|
if self.has_serial_no == 0 and self.serial_no_series:
|
||||||
self.serial_no_series = None
|
self.serial_no_series = None
|
||||||
|
|
||||||
|
def validate_naming_series(self):
|
||||||
|
for field in ["serial_no_series", "batch_number_series"]:
|
||||||
|
series = self.get(field)
|
||||||
|
if series and "#" in series and "." not in series:
|
||||||
|
frappe.throw(_("Invalid naming series (. missing) for {0}")
|
||||||
|
.format(frappe.bold(self.meta.get_field(field).label)))
|
||||||
|
|
||||||
def check_for_active_boms(self):
|
def check_for_active_boms(self):
|
||||||
if self.default_bom:
|
if self.default_bom:
|
||||||
bom_item = frappe.db.get_value("BOM", self.default_bom, "item")
|
bom_item = frappe.db.get_value("BOM", self.default_bom, "item")
|
||||||
|
|||||||
@@ -19,11 +19,6 @@ frappe.ui.form.on('Material Request', {
|
|||||||
frm.set_indicator_formatter('item_code',
|
frm.set_indicator_formatter('item_code',
|
||||||
function(doc) { return (doc.qty<=doc.ordered_qty) ? "green" : "orange"; });
|
function(doc) { return (doc.qty<=doc.ordered_qty) ? "green" : "orange"; });
|
||||||
|
|
||||||
frm.set_query("item_code", "items", function() {
|
|
||||||
return {
|
|
||||||
query: "erpnext.controllers.queries.item_query"
|
|
||||||
};
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onload: function(frm) {
|
onload: function(frm) {
|
||||||
@@ -145,6 +140,8 @@ frappe.ui.form.on('Material Request', {
|
|||||||
},
|
},
|
||||||
|
|
||||||
get_item_data: function(frm, item) {
|
get_item_data: function(frm, item) {
|
||||||
|
if (item && !item.item_code) { return; }
|
||||||
|
|
||||||
frm.call({
|
frm.call({
|
||||||
method: "erpnext.stock.get_item_details.get_item_details",
|
method: "erpnext.stock.get_item_details.get_item_details",
|
||||||
child: item,
|
child: item,
|
||||||
@@ -359,6 +356,22 @@ erpnext.buying.MaterialRequestController = erpnext.buying.BuyingController.exten
|
|||||||
set_schedule_date(this.frm);
|
set_schedule_date(this.frm);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onload: function(doc, cdt, cdn) {
|
||||||
|
this.frm.set_query("item_code", "items", function() {
|
||||||
|
if (doc.material_request_type == "Customer Provided") {
|
||||||
|
return{
|
||||||
|
query: "erpnext.controllers.queries.item_query",
|
||||||
|
filters:{ 'customer': me.frm.doc.customer }
|
||||||
|
}
|
||||||
|
} else if (doc.material_request_type != "Manufacture") {
|
||||||
|
return{
|
||||||
|
query: "erpnext.controllers.queries.item_query",
|
||||||
|
filters: {'is_purchase_item': 1}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
items_add: function(doc, cdt, cdn) {
|
items_add: function(doc, cdt, cdn) {
|
||||||
var row = frappe.get_doc(cdt, cdn);
|
var row = frappe.get_doc(cdt, cdn);
|
||||||
if(doc.schedule_date) {
|
if(doc.schedule_date) {
|
||||||
|
|||||||
@@ -437,6 +437,9 @@ def make_stock_entry(source_name, target_doc=None):
|
|||||||
else:
|
else:
|
||||||
target.s_warehouse = obj.warehouse
|
target.s_warehouse = obj.warehouse
|
||||||
|
|
||||||
|
if source_parent.material_request_type == "Customer Provided":
|
||||||
|
target.allow_zero_valuation_rate = 1
|
||||||
|
|
||||||
def set_missing_values(source, target):
|
def set_missing_values(source, target):
|
||||||
target.purpose = source.material_request_type
|
target.purpose = source.material_request_type
|
||||||
if source.job_card:
|
if source.job_card:
|
||||||
@@ -454,7 +457,7 @@ def make_stock_entry(source_name, target_doc=None):
|
|||||||
"doctype": "Stock Entry",
|
"doctype": "Stock Entry",
|
||||||
"validation": {
|
"validation": {
|
||||||
"docstatus": ["=", 1],
|
"docstatus": ["=", 1],
|
||||||
"material_request_type": ["in", ["Material Transfer", "Material Issue"]]
|
"material_request_type": ["in", ["Material Transfer", "Material Issue", "Customer Provided"]]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Material Request Item": {
|
"Material Request Item": {
|
||||||
|
|||||||
@@ -276,8 +276,8 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
||||||
current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
|
current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
|
||||||
|
|
||||||
self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 + 54.0)
|
self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 - 54.0)
|
||||||
self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 + 3.0)
|
self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 - 3.0)
|
||||||
|
|
||||||
from erpnext.stock.doctype.material_request.material_request import make_stock_entry
|
from erpnext.stock.doctype.material_request.material_request import make_stock_entry
|
||||||
|
|
||||||
@@ -331,8 +331,8 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
||||||
current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
|
current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
|
||||||
|
|
||||||
self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 + 27.0)
|
self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 - 27.0)
|
||||||
self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 + 1.5)
|
self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 - 1.5)
|
||||||
|
|
||||||
# check if per complete is as expected for Stock Entry cancelled
|
# check if per complete is as expected for Stock Entry cancelled
|
||||||
se.cancel()
|
se.cancel()
|
||||||
@@ -344,8 +344,8 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
||||||
current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
|
current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
|
||||||
|
|
||||||
self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 + 54.0)
|
self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 - 54.0)
|
||||||
self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 + 3.0)
|
self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 - 3.0)
|
||||||
|
|
||||||
def test_completed_qty_for_over_transfer(self):
|
def test_completed_qty_for_over_transfer(self):
|
||||||
existing_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
existing_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
||||||
@@ -425,8 +425,8 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
|
||||||
current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
|
current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
|
||||||
|
|
||||||
self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 + 54.0)
|
self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 - 54.0)
|
||||||
self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 + 3.0)
|
self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 - 3.0)
|
||||||
|
|
||||||
def test_incorrect_mapping_of_stock_entry(self):
|
def test_incorrect_mapping_of_stock_entry(self):
|
||||||
# submit material request of type Transfer
|
# submit material request of type Transfer
|
||||||
@@ -512,7 +512,7 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
mr.submit()
|
mr.submit()
|
||||||
|
|
||||||
#testing bin value after material request is submitted
|
#testing bin value after material request is submitted
|
||||||
self.assertEqual(_get_requested_qty(), existing_requested_qty + 54.0)
|
self.assertEqual(_get_requested_qty(), existing_requested_qty - 54.0)
|
||||||
|
|
||||||
# receive items to allow issue
|
# receive items to allow issue
|
||||||
self._insert_stock_entry(60, 6, "_Test Warehouse - _TC")
|
self._insert_stock_entry(60, 6, "_Test Warehouse - _TC")
|
||||||
@@ -609,6 +609,8 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
def test_customer_provided_parts_mr(self):
|
def test_customer_provided_parts_mr(self):
|
||||||
from erpnext.stock.doctype.material_request.material_request import make_stock_entry
|
from erpnext.stock.doctype.material_request.material_request import make_stock_entry
|
||||||
create_item('CUST-0987', is_customer_provided_item = 1, customer = '_Test Customer', is_purchase_item = 0)
|
create_item('CUST-0987', is_customer_provided_item = 1, customer = '_Test Customer', is_purchase_item = 0)
|
||||||
|
existing_requested_qty = self._get_requested_qty("_Test Customer", "_Test Warehouse - _TC")
|
||||||
|
|
||||||
mr = make_material_request(item_code='CUST-0987', material_request_type='Customer Provided')
|
mr = make_material_request(item_code='CUST-0987', material_request_type='Customer Provided')
|
||||||
se = make_stock_entry(mr.name)
|
se = make_stock_entry(mr.name)
|
||||||
se.insert()
|
se.insert()
|
||||||
@@ -617,7 +619,10 @@ class TestMaterialRequest(unittest.TestCase):
|
|||||||
self.assertEqual(se.get("items")[0].material_request, mr.name)
|
self.assertEqual(se.get("items")[0].material_request, mr.name)
|
||||||
mr = frappe.get_doc("Material Request", mr.name)
|
mr = frappe.get_doc("Material Request", mr.name)
|
||||||
mr.submit()
|
mr.submit()
|
||||||
|
current_requested_qty = self._get_requested_qty("_Test Customer", "_Test Warehouse - _TC")
|
||||||
|
|
||||||
self.assertEqual(mr.per_ordered, 100)
|
self.assertEqual(mr.per_ordered, 100)
|
||||||
|
self.assertEqual(existing_requested_qty, current_requested_qty)
|
||||||
|
|
||||||
def make_material_request(**args):
|
def make_material_request(**args):
|
||||||
args = frappe._dict(args)
|
args = frappe._dict(args)
|
||||||
|
|||||||
@@ -47,6 +47,7 @@
|
|||||||
"is_subcontracted",
|
"is_subcontracted",
|
||||||
"supplier_warehouse",
|
"supplier_warehouse",
|
||||||
"items_section",
|
"items_section",
|
||||||
|
"scan_barcode",
|
||||||
"items",
|
"items",
|
||||||
"pricing_rule_details",
|
"pricing_rule_details",
|
||||||
"pricing_rules",
|
"pricing_rules",
|
||||||
@@ -1053,13 +1054,18 @@
|
|||||||
"oldfieldtype": "Date",
|
"oldfieldtype": "Date",
|
||||||
"print_width": "100px",
|
"print_width": "100px",
|
||||||
"width": "100px"
|
"width": "100px"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "scan_barcode",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Scan Barcode"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-truck",
|
"icon": "fa fa-truck",
|
||||||
"idx": 261,
|
"idx": 261,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2019-12-30 19:12:49.709711",
|
"modified": "2020-04-06 16:31:37.444891",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Purchase Receipt",
|
"name": "Purchase Receipt",
|
||||||
|
|||||||
@@ -49,8 +49,8 @@ class PurchaseReceipt(BuyingController):
|
|||||||
'target_field': 'received_qty',
|
'target_field': 'received_qty',
|
||||||
'target_parent_dt': 'Material Request',
|
'target_parent_dt': 'Material Request',
|
||||||
'target_parent_field': 'per_received',
|
'target_parent_field': 'per_received',
|
||||||
'target_ref_field': 'qty',
|
'target_ref_field': 'stock_qty',
|
||||||
'source_field': 'qty',
|
'source_field': 'stock_qty',
|
||||||
'percent_join_field': 'material_request'
|
'percent_join_field': 'material_request'
|
||||||
}]
|
}]
|
||||||
if cint(self.is_return):
|
if cint(self.is_return):
|
||||||
@@ -349,7 +349,7 @@ class PurchaseReceipt(BuyingController):
|
|||||||
if warehouse_with_no_account:
|
if warehouse_with_no_account:
|
||||||
frappe.msgprint(_("No accounting entries for the following warehouses") + ": \n" +
|
frappe.msgprint(_("No accounting entries for the following warehouses") + ": \n" +
|
||||||
"\n".join(warehouse_with_no_account))
|
"\n".join(warehouse_with_no_account))
|
||||||
|
|
||||||
return process_gl_map(gl_entries)
|
return process_gl_map(gl_entries)
|
||||||
|
|
||||||
def get_asset_gl_entry(self, gl_entries):
|
def get_asset_gl_entry(self, gl_entries):
|
||||||
@@ -616,7 +616,7 @@ def get_item_account_wise_additional_cost(purchase_document):
|
|||||||
|
|
||||||
if not landed_cost_vouchers:
|
if not landed_cost_vouchers:
|
||||||
return
|
return
|
||||||
|
|
||||||
item_account_wise_cost = {}
|
item_account_wise_cost = {}
|
||||||
|
|
||||||
for lcv in landed_cost_vouchers:
|
for lcv in landed_cost_vouchers:
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ class StockEntry(StockController):
|
|||||||
self.validate_posting_time()
|
self.validate_posting_time()
|
||||||
self.validate_purpose()
|
self.validate_purpose()
|
||||||
self.validate_item()
|
self.validate_item()
|
||||||
|
self.validate_customer_provided_item()
|
||||||
self.validate_qty()
|
self.validate_qty()
|
||||||
self.set_transfer_qty()
|
self.set_transfer_qty()
|
||||||
self.validate_uom_is_integer("uom", "qty")
|
self.validate_uom_is_integer("uom", "qty")
|
||||||
@@ -203,10 +204,6 @@ class StockEntry(StockController):
|
|||||||
frappe.throw(_("Row #{0}: Please specify Serial No for Item {1}").format(item.idx, item.item_code),
|
frappe.throw(_("Row #{0}: Please specify Serial No for Item {1}").format(item.idx, item.item_code),
|
||||||
frappe.MandatoryError)
|
frappe.MandatoryError)
|
||||||
|
|
||||||
#Customer Provided parts will have zero valuation rate
|
|
||||||
if frappe.db.get_value('Item', item.item_code, 'is_customer_provided_item'):
|
|
||||||
item.allow_zero_valuation_rate = 1
|
|
||||||
|
|
||||||
def validate_qty(self):
|
def validate_qty(self):
|
||||||
manufacture_purpose = ["Manufacture", "Material Consumption for Manufacture"]
|
manufacture_purpose = ["Manufacture", "Material Consumption for Manufacture"]
|
||||||
|
|
||||||
|
|||||||
@@ -744,7 +744,7 @@ class TestStockEntry(unittest.TestCase):
|
|||||||
|
|
||||||
def test_customer_provided_parts_se(self):
|
def test_customer_provided_parts_se(self):
|
||||||
create_item('CUST-0987', is_customer_provided_item = 1, customer = '_Test Customer', is_purchase_item = 0)
|
create_item('CUST-0987', is_customer_provided_item = 1, customer = '_Test Customer', is_purchase_item = 0)
|
||||||
se = make_stock_entry(item_code='CUST-0987', purporse = 'Material Receipt', qty=4, to_warehouse = "_Test Warehouse - _TC")
|
se = make_stock_entry(item_code='CUST-0987', purpose = 'Material Receipt', qty=4, to_warehouse = "_Test Warehouse - _TC")
|
||||||
self.assertEqual(se.get("items")[0].allow_zero_valuation_rate, 1)
|
self.assertEqual(se.get("items")[0].allow_zero_valuation_rate, 1)
|
||||||
self.assertEqual(se.get("items")[0].amount, 0)
|
self.assertEqual(se.get("items")[0].amount, 0)
|
||||||
|
|
||||||
|
|||||||
@@ -488,12 +488,14 @@ def get_stock_balance_for(item_code, warehouse,
|
|||||||
["has_serial_no", "has_batch_no"], as_dict=1)
|
["has_serial_no", "has_batch_no"], as_dict=1)
|
||||||
|
|
||||||
serial_nos = ""
|
serial_nos = ""
|
||||||
if item_dict.get("has_serial_no"):
|
with_serial_no = True if item_dict.get("has_serial_no") else False
|
||||||
qty, rate, serial_nos = get_qty_rate_for_serial_nos(item_code,
|
data = get_stock_balance(item_code, warehouse, posting_date, posting_time,
|
||||||
warehouse, posting_date, posting_time, item_dict)
|
with_valuation_rate=with_valuation_rate, with_serial_no=with_serial_no)
|
||||||
|
|
||||||
|
if with_serial_no:
|
||||||
|
qty, rate, serial_nos = data
|
||||||
else:
|
else:
|
||||||
qty, rate = get_stock_balance(item_code, warehouse,
|
qty, rate = data
|
||||||
posting_date, posting_time, with_valuation_rate=with_valuation_rate)
|
|
||||||
|
|
||||||
if item_dict.get("has_batch_no"):
|
if item_dict.get("has_batch_no"):
|
||||||
qty = get_batch_qty(batch_no, warehouse) or 0
|
qty = get_batch_qty(batch_no, warehouse) or 0
|
||||||
@@ -504,28 +506,6 @@ def get_stock_balance_for(item_code, warehouse,
|
|||||||
'serial_nos': serial_nos
|
'serial_nos': serial_nos
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_qty_rate_for_serial_nos(item_code, warehouse, posting_date, posting_time, item_dict):
|
|
||||||
args = {
|
|
||||||
"item_code": item_code,
|
|
||||||
"warehouse": warehouse,
|
|
||||||
"posting_date": posting_date,
|
|
||||||
"posting_time": posting_time,
|
|
||||||
}
|
|
||||||
|
|
||||||
serial_nos_list = [serial_no.get("name")
|
|
||||||
for serial_no in get_available_serial_nos(args)]
|
|
||||||
|
|
||||||
qty = len(serial_nos_list)
|
|
||||||
serial_nos = '\n'.join(serial_nos_list)
|
|
||||||
args.update({
|
|
||||||
'qty': qty,
|
|
||||||
"serial_nos": serial_nos
|
|
||||||
})
|
|
||||||
|
|
||||||
rate = get_incoming_rate(args, raise_error_if_no_rate=False) or 0
|
|
||||||
|
|
||||||
return qty, rate, serial_nos
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_difference_account(purpose, company):
|
def get_difference_account(purpose, company):
|
||||||
if purpose == 'Stock Reconciliation':
|
if purpose == 'Stock Reconciliation':
|
||||||
|
|||||||
@@ -239,26 +239,13 @@ def get_basic_details(args, item, overwrite_warehouse=True):
|
|||||||
item_group_defaults = get_item_group_defaults(item.name, args.company)
|
item_group_defaults = get_item_group_defaults(item.name, args.company)
|
||||||
brand_defaults = get_brand_defaults(item.name, args.company)
|
brand_defaults = get_brand_defaults(item.name, args.company)
|
||||||
|
|
||||||
if overwrite_warehouse or not args.warehouse:
|
defaults = frappe._dict({
|
||||||
warehouse = (
|
'item_defaults': item_defaults,
|
||||||
args.get("set_warehouse") or
|
'item_group_defaults': item_group_defaults,
|
||||||
item_defaults.get("default_warehouse") or
|
'brand_defaults': brand_defaults
|
||||||
item_group_defaults.get("default_warehouse") or
|
})
|
||||||
brand_defaults.get("default_warehouse") or
|
|
||||||
args.warehouse
|
|
||||||
)
|
|
||||||
|
|
||||||
if not warehouse:
|
warehouse = get_item_warehouse(item, args, overwrite_warehouse, defaults)
|
||||||
defaults = frappe.defaults.get_defaults() or {}
|
|
||||||
warehouse_exists = frappe.db.exists("Warehouse", {
|
|
||||||
'name': defaults.default_warehouse,
|
|
||||||
'company': args.company
|
|
||||||
})
|
|
||||||
if defaults.get("default_warehouse") and warehouse_exists:
|
|
||||||
warehouse = defaults.default_warehouse
|
|
||||||
|
|
||||||
else:
|
|
||||||
warehouse = args.warehouse
|
|
||||||
|
|
||||||
if args.get('doctype') == "Material Request" and not args.get('material_request_type'):
|
if args.get('doctype') == "Material Request" and not args.get('material_request_type'):
|
||||||
args['material_request_type'] = frappe.db.get_value('Material Request',
|
args['material_request_type'] = frappe.db.get_value('Material Request',
|
||||||
@@ -271,7 +258,7 @@ def get_basic_details(args, item, overwrite_warehouse=True):
|
|||||||
expense_account = get_asset_category_account(fieldname = "fixed_asset_account", item = args.item_code, company= args.company)
|
expense_account = get_asset_category_account(fieldname = "fixed_asset_account", item = args.item_code, company= args.company)
|
||||||
|
|
||||||
#Set the UOM to the Default Sales UOM or Default Purchase UOM if configured in the Item Master
|
#Set the UOM to the Default Sales UOM or Default Purchase UOM if configured in the Item Master
|
||||||
if not args.uom:
|
if not args.get('uom'):
|
||||||
if args.get('doctype') in sales_doctypes:
|
if args.get('doctype') in sales_doctypes:
|
||||||
args.uom = item.sales_uom if item.sales_uom else item.stock_uom
|
args.uom = item.sales_uom if item.sales_uom else item.stock_uom
|
||||||
elif (args.get('doctype') in ['Purchase Order', 'Purchase Receipt', 'Purchase Invoice']) or \
|
elif (args.get('doctype') in ['Purchase Order', 'Purchase Receipt', 'Purchase Invoice']) or \
|
||||||
@@ -291,7 +278,7 @@ def get_basic_details(args, item, overwrite_warehouse=True):
|
|||||||
"cost_center": get_default_cost_center(args, item_defaults, item_group_defaults, brand_defaults),
|
"cost_center": get_default_cost_center(args, item_defaults, item_group_defaults, brand_defaults),
|
||||||
'has_serial_no': item.has_serial_no,
|
'has_serial_no': item.has_serial_no,
|
||||||
'has_batch_no': item.has_batch_no,
|
'has_batch_no': item.has_batch_no,
|
||||||
"batch_no": None,
|
"batch_no": args.get("batch_no"),
|
||||||
"uom": args.uom,
|
"uom": args.uom,
|
||||||
"min_order_qty": flt(item.min_order_qty) if args.doctype == "Material Request" else "",
|
"min_order_qty": flt(item.min_order_qty) if args.doctype == "Material Request" else "",
|
||||||
"qty": flt(args.qty) or 1.0,
|
"qty": flt(args.qty) or 1.0,
|
||||||
@@ -360,6 +347,37 @@ def get_basic_details(args, item, overwrite_warehouse=True):
|
|||||||
|
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
def get_item_warehouse(item, args, overwrite_warehouse, defaults={}):
|
||||||
|
if not defaults:
|
||||||
|
defaults = frappe._dict({
|
||||||
|
'item_defaults' : get_item_defaults(item.name, args.company),
|
||||||
|
'item_group_defaults' : get_item_group_defaults(item.name, args.company),
|
||||||
|
'brand_defaults' : get_brand_defaults(item.name, args.company)
|
||||||
|
})
|
||||||
|
|
||||||
|
if overwrite_warehouse or not args.warehouse:
|
||||||
|
warehouse = (
|
||||||
|
args.get("set_warehouse") or
|
||||||
|
defaults.item_defaults.get("default_warehouse") or
|
||||||
|
defaults.item_group_defaults.get("default_warehouse") or
|
||||||
|
defaults.brand_defaults.get("default_warehouse") or
|
||||||
|
args.get('warehouse')
|
||||||
|
)
|
||||||
|
|
||||||
|
if not warehouse:
|
||||||
|
defaults = frappe.defaults.get_defaults() or {}
|
||||||
|
warehouse_exists = frappe.db.exists("Warehouse", {
|
||||||
|
'name': defaults.default_warehouse,
|
||||||
|
'company': args.company
|
||||||
|
})
|
||||||
|
if defaults.get("default_warehouse") and warehouse_exists:
|
||||||
|
warehouse = defaults.default_warehouse
|
||||||
|
|
||||||
|
else:
|
||||||
|
warehouse = args.get('warehouse')
|
||||||
|
|
||||||
|
return warehouse
|
||||||
|
|
||||||
def update_barcode_value(out):
|
def update_barcode_value(out):
|
||||||
from erpnext.accounts.doctype.sales_invoice.pos import get_barcode_data
|
from erpnext.accounts.doctype.sales_invoice.pos import get_barcode_data
|
||||||
barcode_data = get_barcode_data([out])
|
barcode_data = get_barcode_data([out])
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ def get_data(report_filters):
|
|||||||
gl_data = voucher_wise_gl_data.get(key) or {}
|
gl_data = voucher_wise_gl_data.get(key) or {}
|
||||||
d.account_value = gl_data.get("account_value", 0)
|
d.account_value = gl_data.get("account_value", 0)
|
||||||
d.difference_value = (d.stock_value - d.account_value)
|
d.difference_value = (d.stock_value - d.account_value)
|
||||||
if abs(d.difference_value) > 1.0/10 ** currency_precision:
|
if abs(d.difference_value) > 0.1:
|
||||||
data.append(d)
|
data.append(d)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|||||||
@@ -113,13 +113,24 @@ def get_reserved_qty(item_code, warehouse):
|
|||||||
return flt(reserved_qty[0][0]) if reserved_qty else 0
|
return flt(reserved_qty[0][0]) if reserved_qty else 0
|
||||||
|
|
||||||
def get_indented_qty(item_code, warehouse):
|
def get_indented_qty(item_code, warehouse):
|
||||||
indented_qty = frappe.db.sql("""select sum((mr_item.qty - mr_item.ordered_qty) * mr_item.conversion_factor)
|
inward_qty = frappe.db.sql("""select sum((mr_item.qty - mr_item.ordered_qty) * mr_item.conversion_factor)
|
||||||
|
from `tabMaterial Request Item` mr_item, `tabMaterial Request` mr
|
||||||
|
where mr_item.item_code=%s and mr_item.warehouse=%s
|
||||||
|
and mr.material_request_type in ('Purchase', 'Manufacture')
|
||||||
|
and mr_item.qty > mr_item.ordered_qty and mr_item.parent=mr.name
|
||||||
|
and mr.status!='Stopped' and mr.docstatus=1""", (item_code, warehouse))
|
||||||
|
|
||||||
|
outward_qty = frappe.db.sql("""select sum((mr_item.qty - mr_item.ordered_qty) * mr_item.conversion_factor)
|
||||||
from `tabMaterial Request Item` mr_item, `tabMaterial Request` mr
|
from `tabMaterial Request Item` mr_item, `tabMaterial Request` mr
|
||||||
where mr_item.item_code=%s and mr_item.warehouse=%s
|
where mr_item.item_code=%s and mr_item.warehouse=%s
|
||||||
|
and mr.material_request_type in ('Material Issue', 'Material Transfer')
|
||||||
and mr_item.qty > mr_item.ordered_qty and mr_item.parent=mr.name
|
and mr_item.qty > mr_item.ordered_qty and mr_item.parent=mr.name
|
||||||
and mr.status!='Stopped' and mr.docstatus=1""", (item_code, warehouse))
|
and mr.status!='Stopped' and mr.docstatus=1""", (item_code, warehouse))
|
||||||
|
|
||||||
return flt(indented_qty[0][0]) if indented_qty else 0
|
inward_qty, outward_qty = flt(inward_qty[0][0]) if inward_qty else 0, flt(outward_qty[0][0]) if outward_qty else 0
|
||||||
|
indented_qty = inward_qty - outward_qty
|
||||||
|
|
||||||
|
return indented_qty
|
||||||
|
|
||||||
def get_ordered_qty(item_code, warehouse):
|
def get_ordered_qty(item_code, warehouse):
|
||||||
ordered_qty = frappe.db.sql("""
|
ordered_qty = frappe.db.sql("""
|
||||||
@@ -145,9 +156,9 @@ def update_bin_qty(item_code, warehouse, qty_dict=None):
|
|||||||
from erpnext.stock.utils import get_bin
|
from erpnext.stock.utils import get_bin
|
||||||
bin = get_bin(item_code, warehouse)
|
bin = get_bin(item_code, warehouse)
|
||||||
mismatch = False
|
mismatch = False
|
||||||
for fld, val in qty_dict.items():
|
for field, value in qty_dict.items():
|
||||||
if flt(bin.get(fld)) != flt(val):
|
if flt(bin.get(field)) != flt(value):
|
||||||
bin.set(fld, flt(val))
|
bin.set(field, flt(value))
|
||||||
mismatch = True
|
mismatch = True
|
||||||
|
|
||||||
if mismatch:
|
if mismatch:
|
||||||
|
|||||||
@@ -428,7 +428,7 @@ class update_entries_after(object):
|
|||||||
frappe.get_desk_link(self.exceptions[0]["voucher_type"], self.exceptions[0]["voucher_no"]))
|
frappe.get_desk_link(self.exceptions[0]["voucher_type"], self.exceptions[0]["voucher_no"]))
|
||||||
|
|
||||||
if self.verbose:
|
if self.verbose:
|
||||||
frappe.throw(msg, NegativeStockError, title='Insufficent Stock')
|
frappe.throw(msg, NegativeStockError, title='Insufficient Stock')
|
||||||
else:
|
else:
|
||||||
raise NegativeStockError(msg)
|
raise NegativeStockError(msg)
|
||||||
|
|
||||||
|
|||||||
@@ -74,7 +74,8 @@ def get_stock_value_on(warehouse=None, posting_date=None, item_code=None):
|
|||||||
return sum(sle_map.values())
|
return sum(sle_map.values())
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_stock_balance(item_code, warehouse, posting_date=None, posting_time=None, with_valuation_rate=False):
|
def get_stock_balance(item_code, warehouse, posting_date=None, posting_time=None,
|
||||||
|
with_valuation_rate=False, with_serial_no=False):
|
||||||
"""Returns stock balance quantity at given warehouse on given posting date or current date.
|
"""Returns stock balance quantity at given warehouse on given posting date or current date.
|
||||||
|
|
||||||
If `with_valuation_rate` is True, will return tuple (qty, rate)"""
|
If `with_valuation_rate` is True, will return tuple (qty, rate)"""
|
||||||
@@ -84,17 +85,51 @@ def get_stock_balance(item_code, warehouse, posting_date=None, posting_time=None
|
|||||||
if not posting_date: posting_date = nowdate()
|
if not posting_date: posting_date = nowdate()
|
||||||
if not posting_time: posting_time = nowtime()
|
if not posting_time: posting_time = nowtime()
|
||||||
|
|
||||||
last_entry = get_previous_sle({
|
args = {
|
||||||
"item_code": item_code,
|
"item_code": item_code,
|
||||||
"warehouse":warehouse,
|
"warehouse":warehouse,
|
||||||
"posting_date": posting_date,
|
"posting_date": posting_date,
|
||||||
"posting_time": posting_time })
|
"posting_time": posting_time
|
||||||
|
}
|
||||||
|
|
||||||
|
last_entry = get_previous_sle(args)
|
||||||
|
|
||||||
if with_valuation_rate:
|
if with_valuation_rate:
|
||||||
return (last_entry.qty_after_transaction, last_entry.valuation_rate) if last_entry else (0.0, 0.0)
|
if with_serial_no:
|
||||||
|
serial_nos = last_entry.get("serial_no")
|
||||||
|
|
||||||
|
if (serial_nos and
|
||||||
|
len(get_serial_nos_data(serial_nos)) < last_entry.qty_after_transaction):
|
||||||
|
serial_nos = get_serial_nos_data_after_transactions(args)
|
||||||
|
|
||||||
|
return ((last_entry.qty_after_transaction, last_entry.valuation_rate, serial_nos)
|
||||||
|
if last_entry else (0.0, 0.0, 0.0))
|
||||||
|
else:
|
||||||
|
return (last_entry.qty_after_transaction, last_entry.valuation_rate) if last_entry else (0.0, 0.0)
|
||||||
else:
|
else:
|
||||||
return last_entry.qty_after_transaction if last_entry else 0.0
|
return last_entry.qty_after_transaction if last_entry else 0.0
|
||||||
|
|
||||||
|
def get_serial_nos_data_after_transactions(args):
|
||||||
|
serial_nos = []
|
||||||
|
data = frappe.db.sql(""" SELECT serial_no, actual_qty
|
||||||
|
FROM `tabStock Ledger Entry`
|
||||||
|
WHERE
|
||||||
|
item_code = %(item_code)s and warehouse = %(warehouse)s
|
||||||
|
and timestamp(posting_date, posting_time) < timestamp(%(posting_date)s, %(posting_time)s)
|
||||||
|
order by posting_date, posting_time asc """, args, as_dict=1)
|
||||||
|
|
||||||
|
for d in data:
|
||||||
|
if d.actual_qty > 0:
|
||||||
|
serial_nos.extend(get_serial_nos_data(d.serial_no))
|
||||||
|
else:
|
||||||
|
serial_nos = list(set(serial_nos) - set(get_serial_nos_data(d.serial_no)))
|
||||||
|
|
||||||
|
return '\n'.join(serial_nos)
|
||||||
|
|
||||||
|
def get_serial_nos_data(serial_nos):
|
||||||
|
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||||
|
return get_serial_nos(serial_nos)
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_latest_stock_qty(item_code, warehouse=None):
|
def get_latest_stock_qty(item_code, warehouse=None):
|
||||||
values, condition = [item_code], ""
|
values, condition = [item_code], ""
|
||||||
|
|||||||
@@ -26,15 +26,14 @@ $.extend(shopping_cart, {
|
|||||||
bind_address_select: function() {
|
bind_address_select: function() {
|
||||||
$(".cart-addresses").on('click', '.address-card', function(e) {
|
$(".cart-addresses").on('click', '.address-card', function(e) {
|
||||||
const $card = $(e.currentTarget);
|
const $card = $(e.currentTarget);
|
||||||
const address_fieldname = $card.closest('[data-fieldname]').attr('data-fieldname');
|
const address_type = $card.closest('[data-address-type]').attr('data-address-type');
|
||||||
const address_name = $card.closest('[data-address-name]').attr('data-address-name');
|
const address_name = $card.closest('[data-address-name]').attr('data-address-name');
|
||||||
|
|
||||||
return frappe.call({
|
return frappe.call({
|
||||||
type: "POST",
|
type: "POST",
|
||||||
method: "erpnext.shopping_cart.cart.update_cart_address",
|
method: "erpnext.shopping_cart.cart.update_cart_address",
|
||||||
freeze: true,
|
freeze: true,
|
||||||
args: {
|
args: {
|
||||||
address_fieldname,
|
address_type,
|
||||||
address_name
|
address_name
|
||||||
},
|
},
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<h6 class="text-uppercase">{{ _("Shipping Address") }}</h6>
|
<h6 class="text-uppercase">{{ _("Shipping Address") }}</h6>
|
||||||
<div class="row no-gutters" data-fieldname="shipping_address_name">
|
<div class="row no-gutters" data-fieldname="shipping_address_name">
|
||||||
{% for address in shipping_addresses %}
|
{% for address in shipping_addresses %}
|
||||||
<div class="mr-3 mb-3 w-25" data-address-name="{{address.name}}" {% if doc.shipping_address_name == address.name %} data-active {% endif %}>
|
<div class="mr-3 mb-3 w-25" data-address-name="{{address.name}}" data-address-type="shipping" {% if doc.shipping_address_name == address.name %} data-active {% endif %}>
|
||||||
{% include "templates/includes/cart/address_card.html" %}
|
{% include "templates/includes/cart/address_card.html" %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
<h6 class="text-uppercase">{{ _("Billing Address") }}</h6>
|
<h6 class="text-uppercase">{{ _("Billing Address") }}</h6>
|
||||||
<div class="row no-gutters" data-fieldname="customer_address">
|
<div class="row no-gutters" data-fieldname="customer_address">
|
||||||
{% for address in billing_addresses %}
|
{% for address in billing_addresses %}
|
||||||
<div class="mr-3 mb-3 w-25" data-address-name="{{address.name}}" {% if doc.customer_address == address.name %} data-active {% endif %}>
|
<div class="mr-3 mb-3 w-25" data-address-name="{{address.name}}" data-address-type="billing" {% if doc.customer_address == address.name %} data-active {% endif %}>
|
||||||
{% include "templates/includes/cart/address_card.html" %}
|
{% include "templates/includes/cart/address_card.html" %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
@@ -123,9 +123,19 @@ frappe.ready(() => {
|
|||||||
primary_action: (values) => {
|
primary_action: (values) => {
|
||||||
frappe.call('erpnext.shopping_cart.cart.add_new_address', { doc: values })
|
frappe.call('erpnext.shopping_cart.cart.add_new_address', { doc: values })
|
||||||
.then(r => {
|
.then(r => {
|
||||||
d.hide();
|
frappe.call({
|
||||||
window.location.reload();
|
method: "erpnext.shopping_cart.cart.update_cart_address",
|
||||||
|
args: {
|
||||||
|
address_type: r.message.address_type,
|
||||||
|
address_name: r.message.name
|
||||||
|
},
|
||||||
|
callback: function (r) {
|
||||||
|
d.hide();
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -10,16 +10,16 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% for d in doc.taxes %}
|
{% for d in doc.taxes %}
|
||||||
{% if d.base_tax_amount > 0 %}
|
{% if d.base_tax_amount %}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-right" colspan="2">
|
<td class="text-right" colspan="2">
|
||||||
{{ d.description }}
|
{{ d.description }}
|
||||||
</td>
|
</td>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
{{ d.get_formatted("base_tax_amount") }}
|
{{ d.get_formatted("base_tax_amount") }}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
{% if doc.doctype == 'Quotation' %}
|
{% if doc.doctype == 'Quotation' %}
|
||||||
|
|||||||
@@ -12,16 +12,6 @@
|
|||||||
|
|
||||||
|
|
||||||
{% block header_actions %}
|
{% block header_actions %}
|
||||||
{% if doc.items and cart_settings.enable_checkout %}
|
|
||||||
<button class="btn btn-primary btn-place-order" type="button">
|
|
||||||
{{ _("Place Order") }}
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
|
||||||
{% if doc.items and not cart_settings.enable_checkout %}
|
|
||||||
<button class="btn btn-primary btn-request-for-quotation" type="button">
|
|
||||||
{{ _("Request for Quotation") }}
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block page_content %}
|
{% block page_content %}
|
||||||
@@ -55,6 +45,20 @@
|
|||||||
<p class="text-muted">{{ _('Your cart is Empty') }}</p>
|
<p class="text-muted">{{ _('Your cart is Empty') }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if doc.items %}
|
||||||
|
<div class="place-order-container">
|
||||||
|
{% if cart_settings.enable_checkout %}
|
||||||
|
<button class="btn btn-primary btn-place-order" type="button">
|
||||||
|
{{ _("Place Order") }}
|
||||||
|
</button>
|
||||||
|
{% else %}
|
||||||
|
<button class="btn btn-primary btn-request-for-quotation" type="button">
|
||||||
|
{{ _("Request for Quotation") }}
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if doc.items %}
|
{% if doc.items %}
|
||||||
{% if doc.tc_name %}
|
{% if doc.tc_name %}
|
||||||
<div class="terms-and-conditions-link">
|
<div class="terms-and-conditions-link">
|
||||||
|
|||||||
@@ -63,7 +63,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h1>{{ content.name }} <span class="small text-muted">({{ position + 1 }}/{{length}})</span></h1>
|
<h2>{{ content.name }} <span class="small text-muted">({{ position + 1 }}/{{length}})</span></h2>
|
||||||
</div>
|
</div>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user