mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-26 00:14:50 +00:00
@@ -35,6 +35,15 @@ class SalesInvoice(SellingController):
|
|||||||
'overflow_type': 'billing'
|
'overflow_type': 'billing'
|
||||||
}]
|
}]
|
||||||
|
|
||||||
|
def set_indicator(self):
|
||||||
|
"""Set indicator for portal"""
|
||||||
|
if self.outstanding_amount > 0:
|
||||||
|
self.indicator_color = "orange"
|
||||||
|
self.indicator_title = _("Unpaid")
|
||||||
|
else:
|
||||||
|
self.indicator_color = "green"
|
||||||
|
self.indicator_title = _("Paid")
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
super(SalesInvoice, self).validate()
|
super(SalesInvoice, self).validate()
|
||||||
self.validate_posting_time()
|
self.validate_posting_time()
|
||||||
@@ -90,7 +99,7 @@ class SalesInvoice(SellingController):
|
|||||||
|
|
||||||
# this sequence because outstanding may get -ve
|
# this sequence because outstanding may get -ve
|
||||||
self.make_gl_entries()
|
self.make_gl_entries()
|
||||||
|
|
||||||
if not self.is_return:
|
if not self.is_return:
|
||||||
self.update_billing_status_for_zero_amount_refdoc("Sales Order")
|
self.update_billing_status_for_zero_amount_refdoc("Sales Order")
|
||||||
self.check_credit_limit()
|
self.check_credit_limit()
|
||||||
@@ -161,10 +170,10 @@ class SalesInvoice(SellingController):
|
|||||||
'extra_cond': """ and exists (select name from `tabSales Invoice` where name=`tabSales Invoice Item`.parent and update_stock=1 and is_return=1)"""
|
'extra_cond': """ and exists (select name from `tabSales Invoice` where name=`tabSales Invoice Item`.parent and update_stock=1 and is_return=1)"""
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
def check_credit_limit(self):
|
def check_credit_limit(self):
|
||||||
from erpnext.selling.doctype.customer.customer import check_credit_limit
|
from erpnext.selling.doctype.customer.customer import check_credit_limit
|
||||||
|
|
||||||
validate_against_credit_limit = False
|
validate_against_credit_limit = False
|
||||||
for d in self.get("items"):
|
for d in self.get("items"):
|
||||||
if not (d.sales_order or d.delivery_note):
|
if not (d.sales_order or d.delivery_note):
|
||||||
@@ -282,7 +291,7 @@ class SalesInvoice(SellingController):
|
|||||||
reconcile_against_document(lst)
|
reconcile_against_document(lst)
|
||||||
|
|
||||||
def validate_debit_to_acc(self):
|
def validate_debit_to_acc(self):
|
||||||
account = frappe.db.get_value("Account", self.debit_to,
|
account = frappe.db.get_value("Account", self.debit_to,
|
||||||
["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":
|
||||||
@@ -290,7 +299,7 @@ class SalesInvoice(SellingController):
|
|||||||
|
|
||||||
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(_("Debit To account must be a Receivable account"))
|
||||||
|
|
||||||
self.party_account_currency = account.account_currency
|
self.party_account_currency = account.account_currency
|
||||||
|
|
||||||
def validate_fixed_asset_account(self):
|
def validate_fixed_asset_account(self):
|
||||||
@@ -437,18 +446,18 @@ class SalesInvoice(SellingController):
|
|||||||
if cint(self.is_pos) == 1:
|
if cint(self.is_pos) == 1:
|
||||||
if flt(self.paid_amount) == 0:
|
if flt(self.paid_amount) == 0:
|
||||||
if self.cash_bank_account:
|
if self.cash_bank_account:
|
||||||
frappe.db.set(self, 'paid_amount',
|
frappe.db.set(self, 'paid_amount',
|
||||||
flt(flt(self.grand_total) - flt(self.write_off_amount), self.precision("paid_amount")))
|
flt(flt(self.grand_total) - flt(self.write_off_amount), self.precision("paid_amount")))
|
||||||
else:
|
else:
|
||||||
# show message that the amount is not paid
|
# show message that the amount is not paid
|
||||||
frappe.db.set(self,'paid_amount',0)
|
frappe.db.set(self,'paid_amount',0)
|
||||||
frappe.msgprint(_("Note: Payment Entry will not be created since 'Cash or Bank Account' was not specified"))
|
frappe.msgprint(_("Note: Payment Entry will not be created since 'Cash or Bank Account' was not specified"))
|
||||||
else:
|
else:
|
||||||
frappe.db.set(self,'paid_amount',0)
|
frappe.db.set(self,'paid_amount',0)
|
||||||
|
|
||||||
frappe.db.set(self, 'base_paid_amount',
|
frappe.db.set(self, 'base_paid_amount',
|
||||||
flt(self.paid_amount*self.conversion_rate, self.precision("base_paid_amount")))
|
flt(self.paid_amount*self.conversion_rate, self.precision("base_paid_amount")))
|
||||||
|
|
||||||
def check_prev_docstatus(self):
|
def check_prev_docstatus(self):
|
||||||
for d in self.get('items'):
|
for d in self.get('items'):
|
||||||
if d.sales_order and frappe.db.get_value("Sales Order", d.sales_order, "docstatus") != 1:
|
if d.sales_order and frappe.db.get_value("Sales Order", d.sales_order, "docstatus") != 1:
|
||||||
@@ -487,7 +496,7 @@ class SalesInvoice(SellingController):
|
|||||||
from erpnext.accounts.general_ledger import merge_similar_entries
|
from erpnext.accounts.general_ledger import merge_similar_entries
|
||||||
|
|
||||||
gl_entries = []
|
gl_entries = []
|
||||||
|
|
||||||
self.make_customer_gl_entry(gl_entries)
|
self.make_customer_gl_entry(gl_entries)
|
||||||
|
|
||||||
self.make_tax_gl_entries(gl_entries)
|
self.make_tax_gl_entries(gl_entries)
|
||||||
@@ -586,7 +595,7 @@ class SalesInvoice(SellingController):
|
|||||||
# write off entries, applicable if only pos
|
# write off entries, applicable if only pos
|
||||||
if self.write_off_account and self.write_off_amount:
|
if self.write_off_account and self.write_off_amount:
|
||||||
write_off_account_currency = frappe.db.get_value("Account", self.write_off_account, "account_currency")
|
write_off_account_currency = frappe.db.get_value("Account", self.write_off_account, "account_currency")
|
||||||
|
|
||||||
gl_entries.append(
|
gl_entries.append(
|
||||||
self.get_gl_dict({
|
self.get_gl_dict({
|
||||||
"account": self.debit_to,
|
"account": self.debit_to,
|
||||||
|
|||||||
@@ -5,6 +5,3 @@ cur_frm.cscript.tax_table = "Sales Taxes and Charges";
|
|||||||
|
|
||||||
{% include "public/js/controllers/accounts.js" %}
|
{% include "public/js/controllers/accounts.js" %}
|
||||||
|
|
||||||
frappe.ui.form.on("Sales Taxes and Charges Template", "onload", function(frm) {
|
|
||||||
erpnext.add_applicable_territory();
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -164,29 +164,6 @@
|
|||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"description": "Specify a list of Territories, for which, this Taxes Master is valid",
|
|
||||||
"fieldname": "territories",
|
|
||||||
"fieldtype": "Table",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"label": "Valid for Territories",
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Applicable Territory",
|
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"hide_heading": 0,
|
"hide_heading": 0,
|
||||||
@@ -198,7 +175,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-11 12:19:46.488710",
|
"modified": "2015-09-17 07:09:28.797959",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Sales Taxes and Charges Template",
|
"name": "Sales Taxes and Charges Template",
|
||||||
@@ -206,7 +183,7 @@
|
|||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
"amend": 0,
|
"amend": 0,
|
||||||
"apply_user_permissions": 0,
|
"apply_user_permissions": 1,
|
||||||
"cancel": 0,
|
"cancel": 0,
|
||||||
"create": 0,
|
"create": 0,
|
||||||
"delete": 0,
|
"delete": 0,
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from erpnext.controllers.accounts_controller import validate_taxes_and_charges, validate_inclusive_tax
|
from erpnext.controllers.accounts_controller import validate_taxes_and_charges, validate_inclusive_tax
|
||||||
from frappe.utils.nestedset import get_root_of
|
|
||||||
|
|
||||||
class SalesTaxesandChargesTemplate(Document):
|
class SalesTaxesandChargesTemplate(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
@@ -20,10 +19,6 @@ def valdiate_taxes_and_charges_template(doc):
|
|||||||
where ifnull(is_default,0) = 1 and name != %s and company = %s""".format(doc.doctype),
|
where ifnull(is_default,0) = 1 and name != %s and company = %s""".format(doc.doctype),
|
||||||
(doc.name, doc.company))
|
(doc.name, doc.company))
|
||||||
|
|
||||||
if doc.meta.get_field("territories"):
|
|
||||||
if not doc.territories:
|
|
||||||
doc.append("territories", {"territory": get_root_of("Territory") })
|
|
||||||
|
|
||||||
for tax in doc.get("taxes"):
|
for tax in doc.get("taxes"):
|
||||||
validate_taxes_and_charges(tax)
|
validate_taxes_and_charges(tax)
|
||||||
validate_inclusive_tax(tax, doc)
|
validate_inclusive_tax(tax, doc)
|
||||||
|
|||||||
@@ -20,19 +20,7 @@
|
|||||||
"rate": 6.36
|
"rate": 6.36
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "_Test Sales Taxes and Charges Template",
|
"title": "_Test Sales Taxes and Charges Template"
|
||||||
"territories": [
|
|
||||||
{
|
|
||||||
"doctype": "Applicable Territory",
|
|
||||||
"parentfield": "territories",
|
|
||||||
"territory": "All Territories"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"doctype": "Applicable Territory",
|
|
||||||
"parentfield": "territories",
|
|
||||||
"territory": "_Test Territory Rest Of The World"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"company": "_Test Company",
|
"company": "_Test Company",
|
||||||
@@ -115,14 +103,7 @@
|
|||||||
"row_id": 7
|
"row_id": 7
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "_Test India Tax Master",
|
"title": "_Test India Tax Master"
|
||||||
"territories": [
|
|
||||||
{
|
|
||||||
"doctype": "Applicable Territory",
|
|
||||||
"parentfield": "territories",
|
|
||||||
"territory": "_Test Territory India"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"company": "_Test Company",
|
"company": "_Test Company",
|
||||||
@@ -145,14 +126,7 @@
|
|||||||
"rate": 4
|
"rate": 4
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "_Test Sales Taxes and Charges Template - Rest of the World",
|
"title": "_Test Sales Taxes and Charges Template - Rest of the World"
|
||||||
"territories": [
|
|
||||||
{
|
|
||||||
"doctype": "Applicable Territory",
|
|
||||||
"parentfield": "territories",
|
|
||||||
"territory": "_Test Territory Rest Of The World"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"company": "_Test Company",
|
"company": "_Test Company",
|
||||||
@@ -175,14 +149,7 @@
|
|||||||
"rate": 4
|
"rate": 4
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "_Test Sales Taxes and Charges Template 1",
|
"title": "_Test Sales Taxes and Charges Template 1"
|
||||||
"territories": [
|
|
||||||
{
|
|
||||||
"doctype": "Applicable Territory",
|
|
||||||
"parentfield": "territories",
|
|
||||||
"territory": "_Test Territory Rest Of The World"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"company": "_Test Company",
|
"company": "_Test Company",
|
||||||
@@ -205,14 +172,7 @@
|
|||||||
"rate": 4
|
"rate": 4
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "_Test Sales Taxes and Charges Template 2",
|
"title": "_Test Sales Taxes and Charges Template 2"
|
||||||
"territories": [
|
|
||||||
{
|
|
||||||
"doctype": "Applicable Territory",
|
|
||||||
"parentfield": "territories",
|
|
||||||
"territory": "_Test Territory Rest Of The World"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"doctype" : "Sales Taxes and Charges Template",
|
"doctype" : "Sales Taxes and Charges Template",
|
||||||
@@ -224,9 +184,6 @@
|
|||||||
"cost_center": "Main - _TC",
|
"cost_center": "Main - _TC",
|
||||||
"description": "Test Shopping cart taxes with Tax Rule",
|
"description": "Test Shopping cart taxes with Tax Rule",
|
||||||
"tax_amount": 1000
|
"tax_amount": 1000
|
||||||
}],
|
|
||||||
"territories":[{
|
|
||||||
"territory" : "All Territories"
|
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -239,9 +196,6 @@
|
|||||||
"cost_center": "Main - _TC",
|
"cost_center": "Main - _TC",
|
||||||
"description": "Test Shopping cart taxes with Tax Rule",
|
"description": "Test Shopping cart taxes with Tax Rule",
|
||||||
"tax_amount": 200
|
"tax_amount": 200
|
||||||
}],
|
|
||||||
"territories":[{
|
|
||||||
"territory" : "All Territories"
|
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,8 +1,3 @@
|
|||||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
// License: GNU General Public License v3. See license.txt
|
// License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
$.extend(cur_frm.cscript, {
|
|
||||||
onload: function() {
|
|
||||||
erpnext.add_applicable_territory();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@@ -1,388 +1,397 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"allow_copy": 0,
|
||||||
"allow_import": 0,
|
"allow_import": 0,
|
||||||
"allow_rename": 0,
|
"allow_rename": 0,
|
||||||
"autoname": "field:label",
|
"autoname": "field:label",
|
||||||
"creation": "2013-06-25 11:48:03",
|
"creation": "2013-06-25 11:48:03",
|
||||||
"custom": 0,
|
"custom": 0,
|
||||||
"description": "Specify conditions to calculate shipping amount",
|
"description": "Specify conditions to calculate shipping amount",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"description": "example: Next Day Shipping",
|
"description": "example: Next Day Shipping",
|
||||||
"fieldname": "label",
|
"fieldname": "label",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Shipping Rule Label",
|
"label": "Shipping Rule Label",
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"fieldname": "column_break_2",
|
"fieldname": "disabled",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"no_copy": 0,
|
"label": "Disabled",
|
||||||
"permlevel": 0,
|
"no_copy": 0,
|
||||||
"print_hide": 0,
|
"permlevel": 0,
|
||||||
"read_only": 0,
|
"precision": "",
|
||||||
"report_hide": 0,
|
"print_hide": 0,
|
||||||
"reqd": 0,
|
"read_only": 0,
|
||||||
"search_index": 0,
|
"report_hide": 0,
|
||||||
"set_only_once": 0,
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"default": "Net Total",
|
"default": "Net Total",
|
||||||
"fieldname": "calculate_based_on",
|
"fieldname": "calculate_based_on",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Calculate Based On",
|
"label": "Calculate Based On",
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"options": "Net Total\nNet Weight",
|
"options": "Net Total\nNet Weight",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"read_only": 1,
|
"read_only": 1,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 0,
|
"reqd": 0,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"fieldname": "rule_conditions_section",
|
"depends_on": "eval:!doc.disabled",
|
||||||
"fieldtype": "Section Break",
|
"fieldname": "rule_conditions_section",
|
||||||
"hidden": 0,
|
"fieldtype": "Section Break",
|
||||||
"ignore_user_permissions": 0,
|
"hidden": 0,
|
||||||
"in_filter": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_list_view": 0,
|
"in_filter": 0,
|
||||||
"label": "Shipping Rule Conditions",
|
"in_list_view": 0,
|
||||||
"no_copy": 0,
|
"label": "Shipping Rule Conditions",
|
||||||
"permlevel": 0,
|
"no_copy": 0,
|
||||||
"print_hide": 0,
|
"permlevel": 0,
|
||||||
"read_only": 0,
|
"print_hide": 0,
|
||||||
"report_hide": 0,
|
"read_only": 0,
|
||||||
"reqd": 0,
|
"report_hide": 0,
|
||||||
"search_index": 0,
|
"reqd": 0,
|
||||||
"set_only_once": 0,
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"fieldname": "conditions",
|
"fieldname": "conditions",
|
||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"label": "Shipping Rule Conditions",
|
"label": "Shipping Rule Conditions",
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"options": "Shipping Rule Condition",
|
"options": "Shipping Rule Condition",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"fieldname": "section_break_6",
|
"depends_on": "eval:!doc.disabled",
|
||||||
"fieldtype": "Section Break",
|
"fieldname": "section_break_6",
|
||||||
"hidden": 0,
|
"fieldtype": "Section Break",
|
||||||
"ignore_user_permissions": 0,
|
"hidden": 0,
|
||||||
"in_filter": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_list_view": 0,
|
"in_filter": 0,
|
||||||
"no_copy": 0,
|
"in_list_view": 0,
|
||||||
"permlevel": 0,
|
"label": "Valid for Countries",
|
||||||
"print_hide": 0,
|
"no_copy": 0,
|
||||||
"read_only": 0,
|
"permlevel": 0,
|
||||||
"report_hide": 0,
|
"print_hide": 0,
|
||||||
"reqd": 0,
|
"read_only": 0,
|
||||||
"search_index": 0,
|
"report_hide": 0,
|
||||||
"set_only_once": 0,
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"description": "Specify a list of Territories, for which, this Shipping Rule is valid",
|
"fieldname": "worldwide_shipping",
|
||||||
"fieldname": "territories",
|
"fieldtype": "Check",
|
||||||
"fieldtype": "Table",
|
"hidden": 0,
|
||||||
"hidden": 0,
|
"ignore_user_permissions": 0,
|
||||||
"ignore_user_permissions": 0,
|
"in_filter": 0,
|
||||||
"in_filter": 0,
|
"in_list_view": 0,
|
||||||
"in_list_view": 0,
|
"label": "Worldwide Shipping",
|
||||||
"label": "Valid For Territories",
|
"no_copy": 0,
|
||||||
"no_copy": 0,
|
"permlevel": 0,
|
||||||
"options": "Applicable Territory",
|
"precision": "",
|
||||||
"permlevel": 0,
|
"print_hide": 0,
|
||||||
"print_hide": 0,
|
"read_only": 0,
|
||||||
"read_only": 0,
|
"report_hide": 0,
|
||||||
"report_hide": 0,
|
"reqd": 0,
|
||||||
"reqd": 1,
|
"search_index": 0,
|
||||||
"search_index": 0,
|
"set_only_once": 0,
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"fieldname": "column_break_8",
|
"depends_on": "eval:!doc.worldwide_shipping",
|
||||||
"fieldtype": "Column Break",
|
"fieldname": "countries",
|
||||||
"hidden": 0,
|
"fieldtype": "Table",
|
||||||
"ignore_user_permissions": 0,
|
"hidden": 0,
|
||||||
"in_filter": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_list_view": 0,
|
"in_filter": 0,
|
||||||
"no_copy": 0,
|
"in_list_view": 0,
|
||||||
"permlevel": 0,
|
"label": "Valid for Countries",
|
||||||
"print_hide": 0,
|
"no_copy": 0,
|
||||||
"read_only": 0,
|
"options": "Shipping Rule Country",
|
||||||
"report_hide": 0,
|
"permlevel": 0,
|
||||||
"reqd": 0,
|
"precision": "",
|
||||||
"search_index": 0,
|
"print_hide": 0,
|
||||||
"set_only_once": 0,
|
"read_only": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"fieldname": "company",
|
"depends_on": "eval:!doc.disabled",
|
||||||
"fieldtype": "Link",
|
"fieldname": "section_break_10",
|
||||||
"hidden": 0,
|
"fieldtype": "Section Break",
|
||||||
"ignore_user_permissions": 0,
|
"hidden": 0,
|
||||||
"in_filter": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_list_view": 0,
|
"in_filter": 0,
|
||||||
"label": "Company",
|
"in_list_view": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"options": "Company",
|
"permlevel": 0,
|
||||||
"permlevel": 0,
|
"print_hide": 0,
|
||||||
"print_hide": 0,
|
"read_only": 0,
|
||||||
"read_only": 0,
|
"report_hide": 0,
|
||||||
"report_hide": 0,
|
"reqd": 0,
|
||||||
"reqd": 1,
|
"search_index": 0,
|
||||||
"search_index": 0,
|
"set_only_once": 0,
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"fieldname": "section_break_10",
|
"fieldname": "company",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"no_copy": 0,
|
"label": "Company",
|
||||||
"permlevel": 0,
|
"no_copy": 0,
|
||||||
"print_hide": 0,
|
"options": "Company",
|
||||||
"read_only": 0,
|
"permlevel": 0,
|
||||||
"report_hide": 0,
|
"print_hide": 0,
|
||||||
"reqd": 0,
|
"read_only": 0,
|
||||||
"search_index": 0,
|
"report_hide": 0,
|
||||||
"set_only_once": 0,
|
"reqd": 1,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"fieldname": "account",
|
"fieldname": "column_break_12",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Column Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"label": "Shipping Account",
|
"no_copy": 0,
|
||||||
"no_copy": 0,
|
"permlevel": 0,
|
||||||
"options": "Account",
|
"print_hide": 0,
|
||||||
"permlevel": 0,
|
"read_only": 0,
|
||||||
"print_hide": 0,
|
"report_hide": 0,
|
||||||
"read_only": 0,
|
"reqd": 0,
|
||||||
"report_hide": 0,
|
"search_index": 0,
|
||||||
"reqd": 1,
|
"set_only_once": 0,
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"fieldname": "column_break_12",
|
"fieldname": "account",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"no_copy": 0,
|
"label": "Shipping Account",
|
||||||
"permlevel": 0,
|
"no_copy": 0,
|
||||||
"print_hide": 0,
|
"options": "Account",
|
||||||
"read_only": 0,
|
"permlevel": 0,
|
||||||
"report_hide": 0,
|
"print_hide": 0,
|
||||||
"reqd": 0,
|
"read_only": 0,
|
||||||
"search_index": 0,
|
"report_hide": 0,
|
||||||
"set_only_once": 0,
|
"reqd": 1,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"fieldname": "cost_center",
|
"fieldname": "cost_center",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"label": "Cost Center",
|
"label": "Cost Center",
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"options": "Cost Center",
|
"options": "Cost Center",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"hide_heading": 0,
|
"hide_heading": 0,
|
||||||
"hide_toolbar": 0,
|
"hide_toolbar": 0,
|
||||||
"icon": "icon-truck",
|
"icon": "icon-truck",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"in_create": 0,
|
"in_create": 0,
|
||||||
"in_dialog": 0,
|
"in_dialog": 0,
|
||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-07 15:51:26",
|
"modified": "2015-09-22 08:30:57.226342",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Shipping Rule",
|
"name": "Shipping Rule",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
"amend": 0,
|
"amend": 0,
|
||||||
"apply_user_permissions": 0,
|
"apply_user_permissions": 1,
|
||||||
"cancel": 0,
|
"cancel": 0,
|
||||||
"create": 0,
|
"create": 0,
|
||||||
"delete": 0,
|
"delete": 0,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 0,
|
"export": 0,
|
||||||
"if_owner": 0,
|
"if_owner": 0,
|
||||||
"import": 0,
|
"import": 0,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "Accounts User",
|
"role": "Accounts User",
|
||||||
"set_user_permissions": 0,
|
"set_user_permissions": 0,
|
||||||
"share": 0,
|
"share": 0,
|
||||||
"submit": 0,
|
"submit": 0,
|
||||||
"write": 0
|
"write": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
"amend": 0,
|
||||||
"apply_user_permissions": 0,
|
"apply_user_permissions": 1,
|
||||||
"cancel": 0,
|
"cancel": 0,
|
||||||
"create": 0,
|
"create": 0,
|
||||||
"delete": 0,
|
"delete": 0,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 0,
|
"export": 0,
|
||||||
"if_owner": 0,
|
"if_owner": 0,
|
||||||
"import": 0,
|
"import": 0,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "Sales User",
|
"role": "Sales User",
|
||||||
"set_user_permissions": 0,
|
"set_user_permissions": 0,
|
||||||
"share": 0,
|
"share": 0,
|
||||||
"submit": 0,
|
"submit": 0,
|
||||||
"write": 0
|
"write": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
"amend": 0,
|
||||||
"apply_user_permissions": 0,
|
"apply_user_permissions": 0,
|
||||||
"cancel": 0,
|
"cancel": 0,
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 0,
|
"export": 0,
|
||||||
"if_owner": 0,
|
"if_owner": 0,
|
||||||
"import": 0,
|
"import": 0,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "Accounts Manager",
|
"role": "Accounts Manager",
|
||||||
"set_user_permissions": 0,
|
"set_user_permissions": 0,
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 0,
|
"submit": 0,
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
"amend": 0,
|
||||||
"apply_user_permissions": 0,
|
"apply_user_permissions": 0,
|
||||||
"cancel": 0,
|
"cancel": 0,
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 0,
|
"export": 0,
|
||||||
"if_owner": 0,
|
"if_owner": 0,
|
||||||
"import": 0,
|
"import": 0,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "Sales Master Manager",
|
"role": "Sales Master Manager",
|
||||||
"set_user_permissions": 0,
|
"set_user_permissions": 0,
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 0,
|
"submit": 0,
|
||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"read_only_onload": 0
|
"read_only_onload": 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,12 @@ class ShippingRule(Document):
|
|||||||
self.sort_shipping_rule_conditions()
|
self.sort_shipping_rule_conditions()
|
||||||
self.validate_overlapping_shipping_rule_conditions()
|
self.validate_overlapping_shipping_rule_conditions()
|
||||||
|
|
||||||
|
if self.worldwide_shipping:
|
||||||
|
self.countries = []
|
||||||
|
|
||||||
|
elif not len([d.country for d in self.countries if d.country]):
|
||||||
|
frappe.throw(_("Please specify a country for this Shipping Rule or check Worldwide Shipping"))
|
||||||
|
|
||||||
def validate_from_to_values(self):
|
def validate_from_to_values(self):
|
||||||
zero_to_values = []
|
zero_to_values = []
|
||||||
|
|
||||||
|
|||||||
@@ -1,116 +1,100 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"account": "_Test Account Shipping Charges - _TC",
|
"account": "_Test Account Shipping Charges - _TC",
|
||||||
"calculate_based_on": "Net Total",
|
"calculate_based_on": "Net Total",
|
||||||
"company": "_Test Company",
|
"company": "_Test Company",
|
||||||
"cost_center": "_Test Cost Center - _TC",
|
"cost_center": "_Test Cost Center - _TC",
|
||||||
"doctype": "Shipping Rule",
|
"doctype": "Shipping Rule",
|
||||||
"label": "_Test Shipping Rule",
|
"label": "_Test Shipping Rule",
|
||||||
"name": "_Test Shipping Rule",
|
"name": "_Test Shipping Rule",
|
||||||
"conditions": [
|
"conditions": [
|
||||||
{
|
{
|
||||||
"doctype": "Shipping Rule Condition",
|
"doctype": "Shipping Rule Condition",
|
||||||
"from_value": 0,
|
"from_value": 0,
|
||||||
"parentfield": "conditions",
|
"parentfield": "conditions",
|
||||||
"shipping_amount": 50.0,
|
"shipping_amount": 50.0,
|
||||||
"to_value": 100
|
"to_value": 100
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"doctype": "Shipping Rule Condition",
|
"doctype": "Shipping Rule Condition",
|
||||||
"from_value": 101,
|
"from_value": 101,
|
||||||
"parentfield": "conditions",
|
"parentfield": "conditions",
|
||||||
"shipping_amount": 100.0,
|
"shipping_amount": 100.0,
|
||||||
"to_value": 200
|
"to_value": 200
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"doctype": "Shipping Rule Condition",
|
"doctype": "Shipping Rule Condition",
|
||||||
"from_value": 201,
|
"from_value": 201,
|
||||||
"parentfield": "conditions",
|
"parentfield": "conditions",
|
||||||
"shipping_amount": 0.0
|
"shipping_amount": 0.0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"territories": [
|
"worldwide_shipping": 1
|
||||||
{
|
},
|
||||||
"doctype": "Applicable Territory",
|
|
||||||
"parentfield": "territories",
|
|
||||||
"territory": "_Test Territory"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"account": "_Test Account Shipping Charges - _TC",
|
"account": "_Test Account Shipping Charges - _TC",
|
||||||
"calculate_based_on": "Net Total",
|
"calculate_based_on": "Net Total",
|
||||||
"company": "_Test Company",
|
"company": "_Test Company",
|
||||||
"cost_center": "_Test Cost Center - _TC",
|
"cost_center": "_Test Cost Center - _TC",
|
||||||
"doctype": "Shipping Rule",
|
"doctype": "Shipping Rule",
|
||||||
"label": "_Test Shipping Rule - India",
|
"label": "_Test Shipping Rule - India",
|
||||||
"name": "_Test Shipping Rule - India",
|
"name": "_Test Shipping Rule - India",
|
||||||
"conditions": [
|
"conditions": [
|
||||||
{
|
{
|
||||||
"doctype": "Shipping Rule Condition",
|
"doctype": "Shipping Rule Condition",
|
||||||
"from_value": 0,
|
"from_value": 0,
|
||||||
"parentfield": "conditions",
|
"parentfield": "conditions",
|
||||||
"shipping_amount": 50.0,
|
"shipping_amount": 50.0,
|
||||||
"to_value": 100
|
"to_value": 100
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"doctype": "Shipping Rule Condition",
|
"doctype": "Shipping Rule Condition",
|
||||||
"from_value": 101,
|
"from_value": 101,
|
||||||
"parentfield": "conditions",
|
"parentfield": "conditions",
|
||||||
"shipping_amount": 100.0,
|
"shipping_amount": 100.0,
|
||||||
"to_value": 200
|
"to_value": 200
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"doctype": "Shipping Rule Condition",
|
"doctype": "Shipping Rule Condition",
|
||||||
"from_value": 201,
|
"from_value": 201,
|
||||||
"parentfield": "conditions",
|
"parentfield": "conditions",
|
||||||
"shipping_amount": 0.0
|
"shipping_amount": 0.0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"territories": [
|
"countries": [
|
||||||
{
|
{"country": "India"}
|
||||||
"doctype": "Applicable Territory",
|
|
||||||
"parentfield": "territories",
|
|
||||||
"territory": "_Test Territory India"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"account": "_Test Account Shipping Charges - _TC",
|
"account": "_Test Account Shipping Charges - _TC",
|
||||||
"calculate_based_on": "Net Total",
|
"calculate_based_on": "Net Total",
|
||||||
"company": "_Test Company",
|
"company": "_Test Company",
|
||||||
"cost_center": "_Test Cost Center - _TC",
|
"cost_center": "_Test Cost Center - _TC",
|
||||||
"doctype": "Shipping Rule",
|
"doctype": "Shipping Rule",
|
||||||
"label": "_Test Shipping Rule - Rest of the World",
|
"label": "_Test Shipping Rule - Rest of the World",
|
||||||
"name": "_Test Shipping Rule - Rest of the World",
|
"name": "_Test Shipping Rule - Rest of the World",
|
||||||
"conditions": [
|
"conditions": [
|
||||||
{
|
{
|
||||||
"doctype": "Shipping Rule Condition",
|
"doctype": "Shipping Rule Condition",
|
||||||
"from_value": 0,
|
"from_value": 0,
|
||||||
"parentfield": "conditions",
|
"parentfield": "conditions",
|
||||||
"shipping_amount": 500.0,
|
"shipping_amount": 500.0,
|
||||||
"to_value": 1000
|
"to_value": 1000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"doctype": "Shipping Rule Condition",
|
"doctype": "Shipping Rule Condition",
|
||||||
"from_value": 1001,
|
"from_value": 1001,
|
||||||
"parentfield": "conditions",
|
"parentfield": "conditions",
|
||||||
"shipping_amount": 1000.0,
|
"shipping_amount": 1000.0,
|
||||||
"to_value": 2000
|
"to_value": 2000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"doctype": "Shipping Rule Condition",
|
"doctype": "Shipping Rule Condition",
|
||||||
"from_value": 2001,
|
"from_value": 2001,
|
||||||
"parentfield": "conditions",
|
"parentfield": "conditions",
|
||||||
"shipping_amount": 1500.0
|
"shipping_amount": 1500.0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"territories": [
|
"worldwide_shipping": 1
|
||||||
{
|
|
||||||
"doctype": "Applicable Territory",
|
|
||||||
"parentfield": "territories",
|
|
||||||
"territory": "_Test Territory Rest Of The World"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -2,25 +2,27 @@
|
|||||||
"allow_copy": 0,
|
"allow_copy": 0,
|
||||||
"allow_import": 0,
|
"allow_import": 0,
|
||||||
"allow_rename": 0,
|
"allow_rename": 0,
|
||||||
"creation": "2013-06-20 16:00:18",
|
"creation": "2015-09-17 06:43:22.767534",
|
||||||
"custom": 0,
|
"custom": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
|
"document_type": "Other",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"fieldname": "selling_price_list",
|
"fieldname": "country",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Price List",
|
"label": "Country",
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"options": "Price List",
|
"options": "Country",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
@@ -32,18 +34,20 @@
|
|||||||
],
|
],
|
||||||
"hide_heading": 0,
|
"hide_heading": 0,
|
||||||
"hide_toolbar": 0,
|
"hide_toolbar": 0,
|
||||||
"idx": 1,
|
|
||||||
"in_create": 0,
|
"in_create": 0,
|
||||||
"in_dialog": 0,
|
"in_dialog": 0,
|
||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2013-12-20 19:30:47",
|
"modified": "2015-09-17 06:43:22.767534",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Shopping Cart",
|
"module": "Accounts",
|
||||||
"name": "Shopping Cart Price List",
|
"name": "Shipping Rule Country",
|
||||||
|
"name_case": "",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [],
|
"permissions": [],
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"read_only_onload": 0
|
"read_only_onload": 0,
|
||||||
|
"sort_field": "modified",
|
||||||
|
"sort_order": "DESC"
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,10 @@
|
|||||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
# -*- coding: utf-8 -*-
|
||||||
# MIT License. See license.txt
|
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
|
||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
|
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
|
||||||
class ApplicableTerritory(Document):
|
class ShippingRuleCountry(Document):
|
||||||
pass
|
pass
|
||||||
@@ -13,6 +13,9 @@ class IncorrectSupplierType(frappe.ValidationError): pass
|
|||||||
class ConflictingTaxRule(frappe.ValidationError): pass
|
class ConflictingTaxRule(frappe.ValidationError): pass
|
||||||
|
|
||||||
class TaxRule(Document):
|
class TaxRule(Document):
|
||||||
|
def __setup__(self):
|
||||||
|
self.flags.ignore_these_exceptions_in_test = [ConflictingTaxRule]
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.validate_tax_template()
|
self.validate_tax_template()
|
||||||
self.validate_customer_group()
|
self.validate_customer_group()
|
||||||
@@ -25,7 +28,7 @@ class TaxRule(Document):
|
|||||||
self.purchase_tax_template = self.supplier = self.supplier_type= None
|
self.purchase_tax_template = self.supplier = self.supplier_type= None
|
||||||
else:
|
else:
|
||||||
self.sales_tax_template= self.customer = self.customer_group= None
|
self.sales_tax_template= self.customer = self.customer_group= None
|
||||||
|
|
||||||
if not (self.sales_tax_template or self.purchase_tax_template):
|
if not (self.sales_tax_template or self.purchase_tax_template):
|
||||||
frappe.throw(_("Tax Template is mandatory."))
|
frappe.throw(_("Tax Template is mandatory."))
|
||||||
|
|
||||||
@@ -34,7 +37,7 @@ class TaxRule(Document):
|
|||||||
if not frappe.db.get_value("Customer", self.customer, "customer_group") == self.customer_group:
|
if not frappe.db.get_value("Customer", self.customer, "customer_group") == self.customer_group:
|
||||||
frappe.throw(_("Customer {0} does not belong to customer group {1}"). \
|
frappe.throw(_("Customer {0} does not belong to customer group {1}"). \
|
||||||
format(self.customer, self.customer_group), IncorrectCustomerGroup)
|
format(self.customer, self.customer_group), IncorrectCustomerGroup)
|
||||||
|
|
||||||
def validate_supplier_type(self):
|
def validate_supplier_type(self):
|
||||||
if self.supplier and self.supplier_type:
|
if self.supplier and self.supplier_type:
|
||||||
if not frappe.db.get_value("Supplier", self.supplier, "supplier_type") == self.supplier_type:
|
if not frappe.db.get_value("Supplier", self.supplier, "supplier_type") == self.supplier_type:
|
||||||
@@ -60,28 +63,28 @@ class TaxRule(Document):
|
|||||||
"shipping_country": self.shipping_country,
|
"shipping_country": self.shipping_country,
|
||||||
"company": self.company
|
"company": self.company
|
||||||
}
|
}
|
||||||
|
|
||||||
conds=""
|
conds=""
|
||||||
for d in filters:
|
for d in filters:
|
||||||
if conds:
|
if conds:
|
||||||
conds += " and "
|
conds += " and "
|
||||||
conds += """ifnull({0}, '') = '{1}'""".format(d, frappe.db.escape(cstr(filters[d])))
|
conds += """ifnull({0}, '') = '{1}'""".format(d, frappe.db.escape(cstr(filters[d])))
|
||||||
|
|
||||||
if self.from_date and self.to_date:
|
if self.from_date and self.to_date:
|
||||||
conds += """ and ((from_date > '{from_date}' and from_date < '{to_date}') or
|
conds += """ and ((from_date > '{from_date}' and from_date < '{to_date}') or
|
||||||
(to_date > '{from_date}' and to_date < '{to_date}') or
|
(to_date > '{from_date}' and to_date < '{to_date}') or
|
||||||
('{from_date}' > from_date and '{from_date}' < to_date) or
|
('{from_date}' > from_date and '{from_date}' < to_date) or
|
||||||
('{from_date}' = from_date and '{to_date}' = to_date))""".format(from_date=self.from_date, to_date=self.to_date)
|
('{from_date}' = from_date and '{to_date}' = to_date))""".format(from_date=self.from_date, to_date=self.to_date)
|
||||||
|
|
||||||
elif self.from_date and not self.to_date:
|
elif self.from_date and not self.to_date:
|
||||||
conds += """ and to_date > '{from_date}'""".format(from_date = self.from_date)
|
conds += """ and to_date > '{from_date}'""".format(from_date = self.from_date)
|
||||||
|
|
||||||
elif self.to_date and not self.from_date:
|
elif self.to_date and not self.from_date:
|
||||||
conds += """ and from_date < '{to_date}'""".format(to_date = self.to_date)
|
conds += """ and from_date < '{to_date}'""".format(to_date = self.to_date)
|
||||||
|
|
||||||
tax_rule = frappe.db.sql("select name, priority \
|
tax_rule = frappe.db.sql("select name, priority \
|
||||||
from `tabTax Rule` where {0} and name != '{1}'".format(conds, self.name), as_dict=1)
|
from `tabTax Rule` where {0} and name != '{1}'".format(conds, self.name), as_dict=1)
|
||||||
|
|
||||||
if tax_rule:
|
if tax_rule:
|
||||||
if tax_rule[0].priority == self.priority:
|
if tax_rule[0].priority == self.priority:
|
||||||
frappe.throw(_("Tax Rule Conflicts with {0}".format(tax_rule[0].name)), ConflictingTaxRule)
|
frappe.throw(_("Tax Rule Conflicts with {0}".format(tax_rule[0].name)), ConflictingTaxRule)
|
||||||
@@ -95,10 +98,10 @@ def get_party_details(party, party_type, args=None):
|
|||||||
else:
|
else:
|
||||||
billing_filters= {party_type: party, "is_primary_address": 1}
|
billing_filters= {party_type: party, "is_primary_address": 1}
|
||||||
shipping_filters= {party_type:party, "is_shipping_address": 1}
|
shipping_filters= {party_type:party, "is_shipping_address": 1}
|
||||||
|
|
||||||
billing_address= frappe.get_all("Address", fields=["city", "state", "country"], filters= billing_filters)
|
billing_address= frappe.get_all("Address", fields=["city", "state", "country"], filters= billing_filters)
|
||||||
shipping_address= frappe.get_all("Address", fields=["city", "state", "country"], filters= shipping_filters)
|
shipping_address= frappe.get_all("Address", fields=["city", "state", "country"], filters= shipping_filters)
|
||||||
|
|
||||||
if billing_address:
|
if billing_address:
|
||||||
out["billing_city"]= billing_address[0].city
|
out["billing_city"]= billing_address[0].city
|
||||||
out["billing_state"]= billing_address[0].state
|
out["billing_state"]= billing_address[0].state
|
||||||
@@ -108,7 +111,7 @@ def get_party_details(party, party_type, args=None):
|
|||||||
out["shipping_city"]= shipping_address[0].city
|
out["shipping_city"]= shipping_address[0].city
|
||||||
out["shipping_state"]= shipping_address[0].state
|
out["shipping_state"]= shipping_address[0].state
|
||||||
out["shipping_country"]= shipping_address[0].country
|
out["shipping_country"]= shipping_address[0].country
|
||||||
|
|
||||||
return out
|
return out
|
||||||
|
|
||||||
def get_tax_template(posting_date, args):
|
def get_tax_template(posting_date, args):
|
||||||
@@ -117,18 +120,21 @@ def get_tax_template(posting_date, args):
|
|||||||
conditions = []
|
conditions = []
|
||||||
|
|
||||||
for key, value in args.iteritems():
|
for key, value in args.iteritems():
|
||||||
conditions.append("ifnull({0}, '') in ('', '{1}')".format(key, frappe.db.escape(cstr(value))))
|
if key in "use_for_shopping_cart":
|
||||||
|
conditions.append("use_for_shopping_cart = {0}".format(1 if value else 0))
|
||||||
|
else:
|
||||||
|
conditions.append("ifnull({0}, '') in ('', '{1}')".format(key, frappe.db.escape(cstr(value))))
|
||||||
|
|
||||||
matching = frappe.db.sql("""select * from `tabTax Rule`
|
matching = frappe.db.sql("""select * from `tabTax Rule`
|
||||||
where {0}""".format(" and ".join(conditions)), as_dict = True)
|
where {0}""".format(" and ".join(conditions)), as_dict = True)
|
||||||
|
|
||||||
if not matching:
|
if not matching:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
for rule in matching:
|
for rule in matching:
|
||||||
rule.no_of_keys_matched = 0
|
rule.no_of_keys_matched = 0
|
||||||
for key in args:
|
for key in args:
|
||||||
if rule.get(key): rule.no_of_keys_matched += 1
|
if rule.get(key): rule.no_of_keys_matched += 1
|
||||||
|
|
||||||
rule = sorted(matching, lambda b, a: cmp(a.no_of_keys_matched, b.no_of_keys_matched) or cmp(a.priority, b.priority))[0]
|
rule = sorted(matching, lambda b, a: cmp(a.no_of_keys_matched, b.no_of_keys_matched) or cmp(a.priority, b.priority))[0]
|
||||||
return rule.sales_tax_template or rule.purchase_tax_template
|
return rule.sales_tax_template or rule.purchase_tax_template
|
||||||
|
|||||||
@@ -103,6 +103,19 @@ def set_other_values(out, party, party_type):
|
|||||||
if party.get("default_" + f):
|
if party.get("default_" + f):
|
||||||
out[f] = party.get("default_" + f)
|
out[f] = party.get("default_" + f)
|
||||||
|
|
||||||
|
def get_default_price_list(party):
|
||||||
|
"""Return default price list for party (Document object)"""
|
||||||
|
if party.default_price_list:
|
||||||
|
return party.default_price_list
|
||||||
|
|
||||||
|
if party.doctype == "Customer":
|
||||||
|
price_list = frappe.db.get_value("Customer Group",
|
||||||
|
party.customer_group, "default_price_list")
|
||||||
|
if price_list:
|
||||||
|
return price_list
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
def set_price_list(out, party, party_type, given_price_list):
|
def set_price_list(out, party, party_type, given_price_list):
|
||||||
# price list
|
# price list
|
||||||
price_list = filter(None, get_user_permissions().get("Price List", []))
|
price_list = filter(None, get_user_permissions().get("Price List", []))
|
||||||
@@ -110,11 +123,7 @@ def set_price_list(out, party, party_type, given_price_list):
|
|||||||
price_list = price_list[0] if len(price_list)==1 else None
|
price_list = price_list[0] if len(price_list)==1 else None
|
||||||
|
|
||||||
if not price_list:
|
if not price_list:
|
||||||
price_list = party.default_price_list
|
price_list = get_default_price_list(party)
|
||||||
|
|
||||||
if not price_list and party_type=="Customer":
|
|
||||||
price_list = frappe.db.get_value("Customer Group",
|
|
||||||
party.customer_group, "default_price_list")
|
|
||||||
|
|
||||||
if not price_list:
|
if not price_list:
|
||||||
price_list = given_price_list
|
price_list = given_price_list
|
||||||
@@ -271,7 +280,7 @@ def set_taxes(party, party_type, posting_date, company, customer_group=None, sup
|
|||||||
billing_address=None, shipping_address=None, use_for_shopping_cart=None):
|
billing_address=None, shipping_address=None, use_for_shopping_cart=None):
|
||||||
from erpnext.accounts.doctype.tax_rule.tax_rule import get_tax_template, get_party_details
|
from erpnext.accounts.doctype.tax_rule.tax_rule import get_tax_template, get_party_details
|
||||||
args = {
|
args = {
|
||||||
party_type: party,
|
party_type.lower(): party,
|
||||||
"customer_group": customer_group,
|
"customer_group": customer_group,
|
||||||
"supplier_type": supplier_type,
|
"supplier_type": supplier_type,
|
||||||
"company": company
|
"company": company
|
||||||
|
|||||||
@@ -21,37 +21,57 @@ def get_list_context(context=None):
|
|||||||
def get_transaction_list(doctype, txt=None, filters=None, limit_start=0, limit_page_length=20):
|
def get_transaction_list(doctype, txt=None, filters=None, limit_start=0, limit_page_length=20):
|
||||||
from frappe.templates.pages.list import get_list
|
from frappe.templates.pages.list import get_list
|
||||||
user = frappe.session.user
|
user = frappe.session.user
|
||||||
|
key = None
|
||||||
|
|
||||||
|
if not filters: filters = []
|
||||||
|
|
||||||
|
filters.append((doctype, "docstatus", "=", 1))
|
||||||
|
|
||||||
if user != "Guest" and is_website_user():
|
if user != "Guest" and is_website_user():
|
||||||
# find party for this contact
|
# find party for this contact
|
||||||
customers, suppliers = get_customers_suppliers(doctype, user)
|
customers, suppliers = get_customers_suppliers(doctype, user)
|
||||||
|
|
||||||
if customers:
|
if customers:
|
||||||
return post_process(get_list(doctype, txt, filters=[(doctype, "customer", "in", customers)],
|
key, parties = "customer", customers
|
||||||
limit_start=limit_start, limit_page_length=limit_page_length, ignore_permissions=True))
|
|
||||||
|
|
||||||
elif suppliers:
|
elif suppliers:
|
||||||
return post_process(get_list(doctype, txt, filters=[(doctype, "supplier", "in", suppliers)],
|
key, parties = "supplier", suppliers
|
||||||
limit_start=limit_start, limit_page_length=limit_page_length, ignore_permissions=True))
|
|
||||||
|
|
||||||
|
filters.append((doctype, key, "in", parties))
|
||||||
|
|
||||||
|
if key:
|
||||||
|
return post_process(doctype, get_list(doctype, txt,
|
||||||
|
filters=filters, fields = "name",
|
||||||
|
limit_start=limit_start, limit_page_length=limit_page_length,
|
||||||
|
ignore_permissions=True,
|
||||||
|
order_by = "modified desc"))
|
||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
return post_process(get_list(doctype, txt, filters, limit_start, limit_page_length))
|
return post_process(doctype, get_list(doctype, txt, filters, limit_start, limit_page_length,
|
||||||
|
fields="name", order_by = "modified desc"))
|
||||||
|
|
||||||
def post_process(result):
|
def post_process(doctype, data):
|
||||||
for r in result:
|
result = []
|
||||||
r.status_percent = 0
|
for d in data:
|
||||||
r.status_display = []
|
doc = frappe.get_doc(doctype, d.name)
|
||||||
|
|
||||||
if r.get("per_billed"):
|
doc.status_percent = 0
|
||||||
r.status_percent += flt(r.per_billed)
|
doc.status_display = []
|
||||||
r.status_display.append(_("Billed") if r.per_billed==100 else _("{0}% Billed").format(r.per_billed))
|
|
||||||
|
|
||||||
if r.get("per_delivered"):
|
if doc.get("per_billed"):
|
||||||
r.status_percent += flt(r.per_delivered)
|
doc.status_percent += flt(doc.per_billed)
|
||||||
r.status_display.append(_("Delivered") if r.per_delivered==100 else _("{0}% Delivered").format(r.per_delivered))
|
doc.status_display.append(_("Billed") if doc.per_billed==100 else _("{0}% Billed").format(doc.per_billed))
|
||||||
|
|
||||||
r.status_display = ", ".join(r.status_display)
|
if doc.get("per_delivered"):
|
||||||
|
doc.status_percent += flt(doc.per_delivered)
|
||||||
|
doc.status_display.append(_("Delivered") if doc.per_delivered==100 else _("{0}% Delivered").format(doc.per_delivered))
|
||||||
|
|
||||||
|
if hasattr(doc, "set_indicator"):
|
||||||
|
doc.set_indicator()
|
||||||
|
|
||||||
|
doc.status_display = ", ".join(doc.status_display)
|
||||||
|
doc.items_preview = ", ".join([d.item_name for d in doc.items])
|
||||||
|
result.append(doc)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
from frappe import _
|
||||||
|
|
||||||
app_name = "erpnext"
|
app_name = "erpnext"
|
||||||
app_title = "ERPNext"
|
app_title = "ERPNext"
|
||||||
app_publisher = "Frappe Technologies Pvt. Ltd."
|
app_publisher = "Frappe Technologies Pvt. Ltd."
|
||||||
@@ -62,11 +64,26 @@ website_context = {
|
|||||||
|
|
||||||
website_route_rules = [
|
website_route_rules = [
|
||||||
{"from_route": "/orders", "to_route": "Sales Order"},
|
{"from_route": "/orders", "to_route": "Sales Order"},
|
||||||
{"from_route": "/orders/<path:name>", "to_route": "print", "defaults": {"doctype": "Sales Order"}},
|
{"from_route": "/orders/<path:name>", "to_route": "order",
|
||||||
|
"defaults": {
|
||||||
|
"doctype": "Sales Order",
|
||||||
|
"parents": [{"title": _("Orders"), "name": "orders"}]
|
||||||
|
}
|
||||||
|
},
|
||||||
{"from_route": "/invoices", "to_route": "Sales Invoice"},
|
{"from_route": "/invoices", "to_route": "Sales Invoice"},
|
||||||
{"from_route": "/invoices/<path:name>", "to_route": "print", "defaults": {"doctype": "Sales Invoice"}},
|
{"from_route": "/invoices/<path:name>", "to_route": "order",
|
||||||
|
"defaults": {
|
||||||
|
"doctype": "Sales Invoice",
|
||||||
|
"parents": [{"title": _("Invoices"), "name": "invoices"}]
|
||||||
|
}
|
||||||
|
},
|
||||||
{"from_route": "/shipments", "to_route": "Delivery Note"},
|
{"from_route": "/shipments", "to_route": "Delivery Note"},
|
||||||
{"from_route": "/shipments/<path:name>", "to_route": "print", "defaults": {"doctype": "Delivery Note"}}
|
{"from_route": "/shipments/<path:name>", "to_route": "order",
|
||||||
|
"defaults": {
|
||||||
|
"doctype": "Delivery Notes",
|
||||||
|
"parents": [{"title": _("Shipments"), "name": "shipments"}]
|
||||||
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
has_website_permission = {
|
has_website_permission = {
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ cur_frm.fields_dict['project_name'].get_query = function(doc, dt, dn) {
|
|||||||
cur_frm.fields_dict['items'].grid.get_field('item_code').get_query = function(doc) {
|
cur_frm.fields_dict['items'].grid.get_field('item_code').get_query = function(doc) {
|
||||||
return{
|
return{
|
||||||
query: "erpnext.controllers.queries.item_query",
|
query: "erpnext.controllers.queries.item_query",
|
||||||
filters: [["Item", "name", "!=", doc.item]]
|
filters: [["Item", "name", "!=", cur_frm.doc.item]]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -209,3 +209,5 @@ erpnext.patches.v6_0.fix_planned_qty
|
|||||||
erpnext.patches.v6_0.multi_currency
|
erpnext.patches.v6_0.multi_currency
|
||||||
erpnext.patches.v6_2.remove_newsletter_duplicates
|
erpnext.patches.v6_2.remove_newsletter_duplicates
|
||||||
erpnext.patches.v6_2.fix_missing_default_taxes_and_lead
|
erpnext.patches.v6_2.fix_missing_default_taxes_and_lead
|
||||||
|
erpnext.patches.v5_8.tax_rule
|
||||||
|
erpnext.patches.v6_3.convert_applicable_territory
|
||||||
|
|||||||
17
erpnext/patches/v6_3/convert_applicable_territory.py
Normal file
17
erpnext/patches/v6_3/convert_applicable_territory.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import frappe
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
# for price list
|
||||||
|
countries = frappe.db.sql_list("select name from tabCountry")
|
||||||
|
|
||||||
|
for doctype in ("Price List", "Shipping Rule"):
|
||||||
|
for at in frappe.db.sql("""select name, parent, territory from `tabApplicable Territory` where
|
||||||
|
parenttype = %s """, doctype, as_dict=True):
|
||||||
|
if at.territory in countries:
|
||||||
|
parent = frappe.get_doc(doctype, at.parent)
|
||||||
|
if not parent.countries:
|
||||||
|
parent.append("countries", {"country": at.territory})
|
||||||
|
parent.save()
|
||||||
|
|
||||||
|
|
||||||
|
frappe.delete_doc("DocType", "Applicable Territory")
|
||||||
@@ -29,6 +29,7 @@
|
|||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: center top;
|
background-position: center top;
|
||||||
border-radius: 0.5em;
|
border-radius: 0.5em;
|
||||||
|
border: 1px solid #ebeff2;
|
||||||
}
|
}
|
||||||
.product-image.missing-image {
|
.product-image.missing-image {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -38,6 +39,7 @@
|
|||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: center top;
|
background-position: center top;
|
||||||
border-radius: 0.5em;
|
border-radius: 0.5em;
|
||||||
|
border: 1px solid #ebeff2;
|
||||||
border: 1px dashed #d1d8dd;
|
border: 1px dashed #d1d8dd;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ $.extend(shopping_cart, {
|
|||||||
args: {
|
args: {
|
||||||
item_code: opts.item_code,
|
item_code: opts.item_code,
|
||||||
qty: opts.qty,
|
qty: opts.qty,
|
||||||
with_doc: opts.with_doc || 0
|
with_items: opts.with_items || 0
|
||||||
},
|
},
|
||||||
btn: opts.btn,
|
btn: opts.btn,
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
|
|||||||
@@ -49,18 +49,6 @@ $.extend(erpnext, {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
add_applicable_territory: function() {
|
|
||||||
if(cur_frm.doc.__islocal && (cur_frm.doc.territories || []).length===0) {
|
|
||||||
var default_territory = frappe.defaults.get_user_default("territory");
|
|
||||||
if(default_territory) {
|
|
||||||
var territory = frappe.model.add_child(cur_frm.doc, "Applicable Territory",
|
|
||||||
"territories");
|
|
||||||
territory.territory = default_territory;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
setup_serial_no: function() {
|
setup_serial_no: function() {
|
||||||
var grid_row = cur_frm.open_grid_row();
|
var grid_row = cur_frm.open_grid_row();
|
||||||
if(!grid_row.fields_dict.serial_no ||
|
if(!grid_row.fields_dict.serial_no ||
|
||||||
@@ -131,8 +119,8 @@ $.extend(erpnext.utils, {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
copy_value_in_all_row: function(doc, dt, dn, table_fieldname, fieldname) {
|
copy_value_in_all_row: function(doc, dt, dn, table_fieldname, fieldname) {
|
||||||
var d = locals[dt][dn];
|
var d = locals[dt][dn];
|
||||||
if(d[fieldname]){
|
if(d[fieldname]){
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
@border-color: #d1d8dd;
|
@border-color: #d1d8dd;
|
||||||
|
@light-border-color: #EBEFF2;
|
||||||
|
|
||||||
.web-long-description {
|
.web-long-description {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
@@ -35,6 +36,7 @@
|
|||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: center top;
|
background-position: center top;
|
||||||
border-radius: 0.5em;
|
border-radius: 0.5em;
|
||||||
|
border: 1px solid @light-border-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.product-image.missing-image {
|
.product-image.missing-image {
|
||||||
|
|||||||
@@ -174,10 +174,7 @@ def create_price_lists(args):
|
|||||||
"enabled": 1,
|
"enabled": 1,
|
||||||
"buying": 1 if pl_type == "Buying" else 0,
|
"buying": 1 if pl_type == "Buying" else 0,
|
||||||
"selling": 1 if pl_type == "Selling" else 0,
|
"selling": 1 if pl_type == "Selling" else 0,
|
||||||
"currency": args["currency"],
|
"currency": args["currency"]
|
||||||
"territories": [{
|
|
||||||
"territory": get_root_of("Territory")
|
|
||||||
}]
|
|
||||||
}).insert()
|
}).insert()
|
||||||
|
|
||||||
def set_defaults(args):
|
def set_defaults(args):
|
||||||
@@ -304,7 +301,7 @@ def get_fy_details(fy_start_date, fy_end_date):
|
|||||||
return fy
|
return fy
|
||||||
|
|
||||||
def create_taxes(args):
|
def create_taxes(args):
|
||||||
|
|
||||||
for i in xrange(1,6):
|
for i in xrange(1,6):
|
||||||
if args.get("tax_" + str(i)):
|
if args.get("tax_" + str(i)):
|
||||||
# replace % in case someone also enters the % symbol
|
# replace % in case someone also enters the % symbol
|
||||||
@@ -324,7 +321,7 @@ def create_taxes(args):
|
|||||||
raise
|
raise
|
||||||
except RootNotEditable, e:
|
except RootNotEditable, e:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def make_tax_head(args, i, tax_group, tax_rate):
|
def make_tax_head(args, i, tax_group, tax_rate):
|
||||||
return frappe.get_doc({
|
return frappe.get_doc({
|
||||||
"doctype":"Account",
|
"doctype":"Account",
|
||||||
|
|||||||
@@ -1,103 +1,2 @@
|
|||||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
# License: GNU General Public License v3. See license.txt
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
from frappe import _
|
|
||||||
from frappe.utils import get_fullname, flt
|
|
||||||
from erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings import check_shopping_cart_enabled, get_default_territory
|
|
||||||
|
|
||||||
# TODO
|
|
||||||
# validate stock of each item in Website Warehouse or have a list of possible warehouses in Shopping Cart Settings
|
|
||||||
# Below functions are used for test cases
|
|
||||||
|
|
||||||
def get_quotation(user=None):
|
|
||||||
if not user:
|
|
||||||
user = frappe.session.user
|
|
||||||
if user == "Guest":
|
|
||||||
raise frappe.PermissionError
|
|
||||||
|
|
||||||
check_shopping_cart_enabled()
|
|
||||||
party = get_party(user)
|
|
||||||
values = {
|
|
||||||
"order_type": "Shopping Cart",
|
|
||||||
party.doctype.lower(): party.name,
|
|
||||||
"docstatus": 0,
|
|
||||||
"contact_email": user,
|
|
||||||
"selling_price_list": "_Test Price List Rest of the World",
|
|
||||||
"currency": "USD"
|
|
||||||
}
|
|
||||||
|
|
||||||
try:
|
|
||||||
quotation = frappe.get_doc("Quotation", values)
|
|
||||||
|
|
||||||
except frappe.DoesNotExistError:
|
|
||||||
quotation = frappe.new_doc("Quotation")
|
|
||||||
quotation.update(values)
|
|
||||||
if party.doctype == "Customer":
|
|
||||||
quotation.contact_person = frappe.db.get_value("Contact", {"customer": party.name, "email_id": user})
|
|
||||||
quotation.insert(ignore_permissions=True)
|
|
||||||
|
|
||||||
return quotation
|
|
||||||
|
|
||||||
def set_item_in_cart(item_code, qty, user=None):
|
|
||||||
validate_item(item_code)
|
|
||||||
quotation = get_quotation(user=user)
|
|
||||||
qty = flt(qty)
|
|
||||||
quotation_item = quotation.get("items", {"item_code": item_code})
|
|
||||||
if qty==0:
|
|
||||||
if quotation_item:
|
|
||||||
# remove
|
|
||||||
quotation.get("items").remove(quotation_item[0])
|
|
||||||
else:
|
|
||||||
# add or update
|
|
||||||
if quotation_item:
|
|
||||||
quotation_item[0].qty = qty
|
|
||||||
else:
|
|
||||||
quotation.append("items", {
|
|
||||||
"doctype": "Quotation Item",
|
|
||||||
"item_code": item_code,
|
|
||||||
"qty": qty
|
|
||||||
})
|
|
||||||
quotation.save(ignore_permissions=True)
|
|
||||||
return quotation
|
|
||||||
|
|
||||||
def validate_item(item_code):
|
|
||||||
item = frappe.db.get_value("Item", item_code, ["item_name", "show_in_website"], as_dict=True)
|
|
||||||
if not item.show_in_website:
|
|
||||||
frappe.throw(_("{0} cannot be purchased using Shopping Cart").format(item.item_name))
|
|
||||||
|
|
||||||
def get_party(user):
|
|
||||||
def _get_party(user):
|
|
||||||
customer = frappe.db.get_value("Contact", {"email_id": user}, "customer")
|
|
||||||
if customer:
|
|
||||||
return frappe.get_doc("Customer", customer)
|
|
||||||
|
|
||||||
lead = frappe.db.get_value("Lead", {"email_id": user})
|
|
||||||
if lead:
|
|
||||||
return frappe.get_doc("Lead", lead)
|
|
||||||
|
|
||||||
# create a lead
|
|
||||||
lead = frappe.new_doc("Lead")
|
|
||||||
lead.update({
|
|
||||||
"email_id": user,
|
|
||||||
"lead_name": get_fullname(user),
|
|
||||||
"territory": guess_territory()
|
|
||||||
})
|
|
||||||
lead.insert(ignore_permissions=True)
|
|
||||||
|
|
||||||
return lead
|
|
||||||
|
|
||||||
if not getattr(frappe.local, "shopping_cart_party", None):
|
|
||||||
frappe.local.shopping_cart_party = {}
|
|
||||||
|
|
||||||
if not frappe.local.shopping_cart_party.get(user):
|
|
||||||
frappe.local.shopping_cart_party[user] = _get_party(user)
|
|
||||||
|
|
||||||
return frappe.local.shopping_cart_party[user]
|
|
||||||
|
|
||||||
def guess_territory():
|
|
||||||
territory = None
|
|
||||||
if frappe.session.get("session_country"):
|
|
||||||
territory = frappe.db.get_value("Territory", frappe.session.get("session_country"))
|
|
||||||
return territory or get_default_territory()
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import throw, _
|
from frappe import throw, _
|
||||||
import frappe.defaults
|
import frappe.defaults
|
||||||
from frappe.utils import cint, flt, get_fullname, fmt_money, cstr
|
from frappe.utils import cint, flt, get_fullname, cstr
|
||||||
from erpnext.utilities.doctype.address.address import get_address_display
|
from erpnext.utilities.doctype.address.address import get_address_display
|
||||||
from erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings import get_shopping_cart_settings
|
from erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings import get_shopping_cart_settings
|
||||||
from frappe.utils.nestedset import get_root_of
|
from frappe.utils.nestedset import get_root_of
|
||||||
@@ -17,11 +17,13 @@ def set_cart_count(quotation=None):
|
|||||||
if not quotation:
|
if not quotation:
|
||||||
quotation = _get_cart_quotation()
|
quotation = _get_cart_quotation()
|
||||||
cart_count = cstr(len(quotation.get("items")))
|
cart_count = cstr(len(quotation.get("items")))
|
||||||
frappe.local.cookie_manager.set_cookie("cart_count", cart_count)
|
|
||||||
|
if hasattr(frappe.local, "cookie_manager"):
|
||||||
|
frappe.local.cookie_manager.set_cookie("cart_count", cart_count)
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_cart_quotation(doc=None):
|
def get_cart_quotation(doc=None):
|
||||||
party = get_lead_or_customer()
|
party = get_customer()
|
||||||
|
|
||||||
if not doc:
|
if not doc:
|
||||||
quotation = _get_cart_quotation(party)
|
quotation = _get_cart_quotation(party)
|
||||||
@@ -58,21 +60,19 @@ def place_order():
|
|||||||
sales_order.flags.ignore_permissions = True
|
sales_order.flags.ignore_permissions = True
|
||||||
sales_order.insert()
|
sales_order.insert()
|
||||||
sales_order.submit()
|
sales_order.submit()
|
||||||
frappe.local.cookie_manager.delete_cookie("cart_count")
|
|
||||||
|
if hasattr(frappe.local, "cookie_manager"):
|
||||||
|
frappe.local.cookie_manager.delete_cookie("cart_count")
|
||||||
|
|
||||||
return sales_order.name
|
return sales_order.name
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def update_cart(item_code, qty, with_doc):
|
def update_cart(item_code, qty, with_items=False):
|
||||||
quotation = _get_cart_quotation()
|
quotation = _get_cart_quotation()
|
||||||
|
|
||||||
qty = flt(qty)
|
qty = flt(qty)
|
||||||
if qty == 0:
|
if qty == 0:
|
||||||
quotation.set("items", quotation.get("items", {"item_code": ["!=", item_code]}))
|
quotation.set("items", quotation.get("items", {"item_code": ["!=", item_code]}))
|
||||||
if not quotation.get("items") and \
|
|
||||||
not quotation.get("__islocal"):
|
|
||||||
quotation.__delete = True
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
quotation_items = quotation.get("items", {"item_code": item_code})
|
quotation_items = quotation.get("items", {"item_code": item_code})
|
||||||
if not quotation_items:
|
if not quotation_items:
|
||||||
@@ -86,17 +86,19 @@ def update_cart(item_code, qty, with_doc):
|
|||||||
|
|
||||||
apply_cart_settings(quotation=quotation)
|
apply_cart_settings(quotation=quotation)
|
||||||
|
|
||||||
if hasattr(quotation, "__delete"):
|
quotation.flags.ignore_permissions = True
|
||||||
frappe.delete_doc("Quotation", quotation.name, ignore_permissions=True)
|
quotation.save()
|
||||||
quotation = _get_cart_quotation()
|
|
||||||
else:
|
|
||||||
quotation.flags.ignore_permissions = True
|
|
||||||
quotation.save()
|
|
||||||
|
|
||||||
set_cart_count(quotation)
|
set_cart_count(quotation)
|
||||||
|
|
||||||
if with_doc:
|
if with_items:
|
||||||
return get_cart_quotation(quotation)
|
context = get_cart_quotation(quotation)
|
||||||
|
return {
|
||||||
|
"items": frappe.render_template("templates/includes/cart/cart_items.html",
|
||||||
|
context),
|
||||||
|
"taxes": frappe.render_template("templates/includes/order/order_taxes.html",
|
||||||
|
context),
|
||||||
|
}
|
||||||
else:
|
else:
|
||||||
return quotation.name
|
return quotation.name
|
||||||
|
|
||||||
@@ -122,7 +124,11 @@ def update_cart_address(address_fieldname, address_name):
|
|||||||
quotation.flags.ignore_permissions = True
|
quotation.flags.ignore_permissions = True
|
||||||
quotation.save()
|
quotation.save()
|
||||||
|
|
||||||
return get_cart_quotation(quotation)
|
context = get_cart_quotation(quotation)
|
||||||
|
return {
|
||||||
|
"taxes": frappe.render_template("templates/includes/order/order_taxes.html",
|
||||||
|
context),
|
||||||
|
}
|
||||||
|
|
||||||
def guess_territory():
|
def guess_territory():
|
||||||
territory = None
|
territory = None
|
||||||
@@ -134,32 +140,23 @@ def guess_territory():
|
|||||||
frappe.db.get_value("Shopping Cart Settings", None, "territory") or \
|
frappe.db.get_value("Shopping Cart Settings", None, "territory") or \
|
||||||
get_root_of("Territory")
|
get_root_of("Territory")
|
||||||
|
|
||||||
def decorate_quotation_doc(quotation_doc):
|
def decorate_quotation_doc(doc):
|
||||||
doc = frappe._dict(quotation_doc.as_dict())
|
|
||||||
for d in doc.get("items", []):
|
for d in doc.get("items", []):
|
||||||
d.update(frappe.db.get_value("Item", d["item_code"],
|
d.update(frappe.db.get_value("Item", d.item_code,
|
||||||
["website_image", "description", "page_name"], as_dict=True))
|
["website_image", "description", "page_name"], as_dict=True))
|
||||||
d["formatted_rate"] = fmt_money(d.get("rate"), currency=doc.currency)
|
|
||||||
d["formatted_amount"] = fmt_money(d.get("amount"), currency=doc.currency)
|
|
||||||
|
|
||||||
for d in doc.get("taxes", []):
|
|
||||||
d["formatted_tax_amount"] = fmt_money(flt(d.get("tax_amount_after_discount_amount")),
|
|
||||||
currency=doc.currency)
|
|
||||||
|
|
||||||
doc.formatted_grand_total_export = fmt_money(doc.grand_total,
|
|
||||||
currency=doc.currency)
|
|
||||||
|
|
||||||
return doc
|
return doc
|
||||||
|
|
||||||
def _get_cart_quotation(party=None):
|
def _get_cart_quotation(party=None):
|
||||||
if not party:
|
if not party:
|
||||||
party = get_lead_or_customer()
|
party = get_customer()
|
||||||
|
|
||||||
quotation = frappe.db.get_value("Quotation",
|
quotation = frappe.get_all("Quotation", fields=["name"], filters=
|
||||||
{party.doctype.lower(): party.name, "order_type": "Shopping Cart", "docstatus": 0})
|
{party.doctype.lower(): party.name, "order_type": "Shopping Cart", "docstatus": 0},
|
||||||
|
order_by="modified desc", limit_page_length=1)
|
||||||
|
|
||||||
if quotation:
|
if quotation:
|
||||||
qdoc = frappe.get_doc("Quotation", quotation)
|
qdoc = frappe.get_doc("Quotation", quotation[0].name)
|
||||||
else:
|
else:
|
||||||
qdoc = frappe.get_doc({
|
qdoc = frappe.get_doc({
|
||||||
"doctype": "Quotation",
|
"doctype": "Quotation",
|
||||||
@@ -173,9 +170,9 @@ def _get_cart_quotation(party=None):
|
|||||||
(party.doctype.lower()): party.name
|
(party.doctype.lower()): party.name
|
||||||
})
|
})
|
||||||
|
|
||||||
if party.doctype == "Customer":
|
qdoc.contact_person = frappe.db.get_value("Contact", {"email_id": frappe.session.user,
|
||||||
qdoc.contact_person = frappe.db.get_value("Contact", {"email_id": frappe.session.user,
|
"customer": party.name})
|
||||||
"customer": party.name})
|
qdoc.contact_email = frappe.session.user
|
||||||
|
|
||||||
qdoc.flags.ignore_permissions = True
|
qdoc.flags.ignore_permissions = True
|
||||||
qdoc.run_method("set_missing_values")
|
qdoc.run_method("set_missing_values")
|
||||||
@@ -184,27 +181,21 @@ def _get_cart_quotation(party=None):
|
|||||||
return qdoc
|
return qdoc
|
||||||
|
|
||||||
def update_party(fullname, company_name=None, mobile_no=None, phone=None):
|
def update_party(fullname, company_name=None, mobile_no=None, phone=None):
|
||||||
party = get_lead_or_customer()
|
party = get_customer()
|
||||||
|
|
||||||
if party.doctype == "Lead":
|
party.customer_name = company_name or fullname
|
||||||
party.company_name = company_name
|
party.customer_type == "Company" if company_name else "Individual"
|
||||||
party.lead_name = fullname
|
|
||||||
party.mobile_no = mobile_no
|
|
||||||
party.phone = phone
|
|
||||||
else:
|
|
||||||
party.customer_name = company_name or fullname
|
|
||||||
party.customer_type == "Company" if company_name else "Individual"
|
|
||||||
|
|
||||||
contact_name = frappe.db.get_value("Contact", {"email_id": frappe.session.user,
|
contact_name = frappe.db.get_value("Contact", {"email_id": frappe.session.user,
|
||||||
"customer": party.name})
|
"customer": party.name})
|
||||||
contact = frappe.get_doc("Contact", contact_name)
|
contact = frappe.get_doc("Contact", contact_name)
|
||||||
contact.first_name = fullname
|
contact.first_name = fullname
|
||||||
contact.last_name = None
|
contact.last_name = None
|
||||||
contact.customer_name = party.customer_name
|
contact.customer_name = party.customer_name
|
||||||
contact.mobile_no = mobile_no
|
contact.mobile_no = mobile_no
|
||||||
contact.phone = phone
|
contact.phone = phone
|
||||||
contact.flags.ignore_permissions = True
|
contact.flags.ignore_permissions = True
|
||||||
contact.save()
|
contact.save()
|
||||||
|
|
||||||
party_doc = frappe.get_doc(party.as_dict())
|
party_doc = frappe.get_doc(party.as_dict())
|
||||||
party_doc.flags.ignore_permissions = True
|
party_doc.flags.ignore_permissions = True
|
||||||
@@ -219,26 +210,24 @@ def update_party(fullname, company_name=None, mobile_no=None, phone=None):
|
|||||||
|
|
||||||
def apply_cart_settings(party=None, quotation=None):
|
def apply_cart_settings(party=None, quotation=None):
|
||||||
if not party:
|
if not party:
|
||||||
party = get_lead_or_customer()
|
party = get_customer()
|
||||||
if not quotation:
|
if not quotation:
|
||||||
quotation = _get_cart_quotation(party)
|
quotation = _get_cart_quotation(party)
|
||||||
|
|
||||||
cart_settings = frappe.get_doc("Shopping Cart Settings")
|
cart_settings = frappe.get_doc("Shopping Cart Settings")
|
||||||
billing_territory = get_address_territory(quotation.customer_address) or \
|
|
||||||
party.territory or get_root_of("Territory")
|
|
||||||
|
|
||||||
set_price_list_and_rate(quotation, cart_settings, billing_territory)
|
set_price_list_and_rate(quotation, cart_settings)
|
||||||
|
|
||||||
quotation.run_method("calculate_taxes_and_totals")
|
quotation.run_method("calculate_taxes_and_totals")
|
||||||
|
|
||||||
set_taxes(quotation, cart_settings, billing_territory)
|
set_taxes(quotation, cart_settings)
|
||||||
|
|
||||||
_apply_shipping_rule(party, quotation, cart_settings)
|
_apply_shipping_rule(party, quotation, cart_settings)
|
||||||
|
|
||||||
def set_price_list_and_rate(quotation, cart_settings, billing_territory):
|
def set_price_list_and_rate(quotation, cart_settings):
|
||||||
"""set price list based on billing territory"""
|
"""set price list based on billing territory"""
|
||||||
|
|
||||||
_set_price_list(quotation, cart_settings, billing_territory)
|
_set_price_list(quotation, cart_settings)
|
||||||
|
|
||||||
# reset values
|
# reset values
|
||||||
quotation.price_list_currency = quotation.currency = \
|
quotation.price_list_currency = quotation.currency = \
|
||||||
@@ -249,27 +238,33 @@ def set_price_list_and_rate(quotation, cart_settings, billing_territory):
|
|||||||
# refetch values
|
# refetch values
|
||||||
quotation.run_method("set_price_list_and_item_details")
|
quotation.run_method("set_price_list_and_item_details")
|
||||||
|
|
||||||
# set it in cookies for using in product page
|
if hasattr(frappe.local, "cookie_manager"):
|
||||||
frappe.local.cookie_manager.set_cookie("selling_price_list", quotation.selling_price_list)
|
# set it in cookies for using in product page
|
||||||
|
frappe.local.cookie_manager.set_cookie("selling_price_list", quotation.selling_price_list)
|
||||||
|
|
||||||
|
def _set_price_list(quotation, cart_settings):
|
||||||
|
"""Set price list based on customer or shopping cart default"""
|
||||||
|
if quotation.selling_price_list:
|
||||||
|
return
|
||||||
|
|
||||||
def _set_price_list(quotation, cart_settings, billing_territory):
|
|
||||||
# check if customer price list exists
|
# check if customer price list exists
|
||||||
selling_price_list = None
|
selling_price_list = None
|
||||||
if quotation.customer:
|
if quotation.customer:
|
||||||
selling_price_list = frappe.db.get_value("Customer", quotation.customer, "default_price_list")
|
from erpnext.accounts.party import get_default_price_list
|
||||||
|
selling_price_list = get_default_price_list(frappe.get_doc("Customer", quotation.customer))
|
||||||
|
|
||||||
# else check for territory based price list
|
# else check for territory based price list
|
||||||
if not selling_price_list:
|
if not selling_price_list:
|
||||||
selling_price_list = cart_settings.get_price_list(billing_territory)
|
selling_price_list = cart_settings.price_list
|
||||||
|
|
||||||
quotation.selling_price_list = selling_price_list
|
quotation.selling_price_list = selling_price_list
|
||||||
|
|
||||||
def set_taxes(quotation, cart_settings, billing_territory):
|
def set_taxes(quotation, cart_settings):
|
||||||
"""set taxes based on billing territory"""
|
"""set taxes based on billing territory"""
|
||||||
from erpnext.accounts.party import set_taxes
|
from erpnext.accounts.party import set_taxes
|
||||||
|
|
||||||
customer_group = frappe.db.get_value("Customer", quotation.customer, "customer_group")
|
customer_group = frappe.db.get_value("Customer", quotation.customer, "customer_group")
|
||||||
|
|
||||||
quotation.taxes_and_charges = set_taxes(quotation.customer, "Customer", \
|
quotation.taxes_and_charges = set_taxes(quotation.customer, "Customer", \
|
||||||
quotation.transaction_date, quotation.company, customer_group, None, \
|
quotation.transaction_date, quotation.company, customer_group, None, \
|
||||||
quotation.customer_address, quotation.shipping_address_name, 1)
|
quotation.customer_address, quotation.shipping_address_name, 1)
|
||||||
@@ -280,32 +275,38 @@ def set_taxes(quotation, cart_settings, billing_territory):
|
|||||||
# # append taxes
|
# # append taxes
|
||||||
quotation.append_taxes_from_master()
|
quotation.append_taxes_from_master()
|
||||||
|
|
||||||
def get_lead_or_customer():
|
def get_customer(user=None):
|
||||||
customer = frappe.db.get_value("Contact", {"email_id": frappe.session.user}, "customer")
|
if not user:
|
||||||
|
user = frappe.session.user
|
||||||
|
|
||||||
|
customer = frappe.db.get_value("Contact", {"email_id": user}, "customer")
|
||||||
if customer:
|
if customer:
|
||||||
return frappe.get_doc("Customer", customer)
|
return frappe.get_doc("Customer", customer)
|
||||||
|
|
||||||
lead = frappe.db.get_value("Lead", {"email_id": frappe.session.user})
|
|
||||||
if lead:
|
|
||||||
return frappe.get_doc("Lead", lead)
|
|
||||||
else:
|
else:
|
||||||
lead_doc = frappe.get_doc({
|
customer = frappe.new_doc("Customer")
|
||||||
"doctype": "Lead",
|
fullname = get_fullname(user)
|
||||||
"email_id": frappe.session.user,
|
customer.update({
|
||||||
"lead_name": get_fullname(frappe.session.user),
|
"customer_name": fullname,
|
||||||
"territory": guess_territory(),
|
"customer_type": "Individual",
|
||||||
"status": "Open" # TODO: set something better???
|
"customer_group": get_shopping_cart_settings().default_customer_group,
|
||||||
|
"territory": get_root_of("Territory")
|
||||||
})
|
})
|
||||||
|
customer.insert(ignore_permissions=True)
|
||||||
|
|
||||||
if frappe.session.user not in ("Guest", "Administrator"):
|
contact = frappe.new_doc("Contact")
|
||||||
lead_doc.flags.ignore_permissions = True
|
contact.update({
|
||||||
lead_doc.insert()
|
"customer": customer.name,
|
||||||
|
"first_name": fullname,
|
||||||
|
"email_id": user
|
||||||
|
})
|
||||||
|
contact.insert(ignore_permissions=True)
|
||||||
|
|
||||||
return lead_doc
|
return customer
|
||||||
|
|
||||||
def get_address_docs(doctype=None, txt=None, filters=None, limit_start=0, limit_page_length=20, party=None):
|
def get_address_docs(doctype=None, txt=None, filters=None, limit_start=0, limit_page_length=20, party=None):
|
||||||
if not party:
|
if not party:
|
||||||
party = get_lead_or_customer()
|
party = get_customer()
|
||||||
|
|
||||||
address_docs = frappe.db.sql("""select * from `tabAddress`
|
address_docs = frappe.db.sql("""select * from `tabAddress`
|
||||||
where `{0}`=%s order by name limit {1}, {2}""".format(party.doctype.lower(),
|
where `{0}`=%s order by name limit {1}, {2}""".format(party.doctype.lower(),
|
||||||
@@ -314,7 +315,6 @@ def get_address_docs(doctype=None, txt=None, filters=None, limit_start=0, limit_
|
|||||||
|
|
||||||
for address in address_docs:
|
for address in address_docs:
|
||||||
address.display = get_address_display(address)
|
address.display = get_address_display(address)
|
||||||
address.display = (address.display).replace("\n", "<br>\n")
|
|
||||||
|
|
||||||
return address_docs
|
return address_docs
|
||||||
|
|
||||||
@@ -332,38 +332,39 @@ def apply_shipping_rule(shipping_rule):
|
|||||||
return get_cart_quotation(quotation)
|
return get_cart_quotation(quotation)
|
||||||
|
|
||||||
def _apply_shipping_rule(party=None, quotation=None, cart_settings=None):
|
def _apply_shipping_rule(party=None, quotation=None, cart_settings=None):
|
||||||
shipping_rules = get_shipping_rules(party, quotation, cart_settings)
|
if not quotation.shipping_rule:
|
||||||
|
shipping_rules = get_shipping_rules(quotation, cart_settings)
|
||||||
|
|
||||||
if not shipping_rules:
|
if not shipping_rules:
|
||||||
return
|
return
|
||||||
|
|
||||||
elif quotation.shipping_rule not in shipping_rules:
|
elif quotation.shipping_rule not in shipping_rules:
|
||||||
quotation.shipping_rule = shipping_rules[0]
|
quotation.shipping_rule = shipping_rules[0]
|
||||||
|
|
||||||
quotation.run_method("apply_shipping_rule")
|
if quotation.shipping_rule:
|
||||||
quotation.run_method("calculate_taxes_and_totals")
|
quotation.run_method("apply_shipping_rule")
|
||||||
|
quotation.run_method("calculate_taxes_and_totals")
|
||||||
|
|
||||||
def get_applicable_shipping_rules(party=None, quotation=None):
|
def get_applicable_shipping_rules(party=None, quotation=None):
|
||||||
shipping_rules = get_shipping_rules(party, quotation)
|
shipping_rules = get_shipping_rules(quotation)
|
||||||
|
|
||||||
if shipping_rules:
|
if shipping_rules:
|
||||||
rule_label_map = frappe.db.get_values("Shipping Rule", shipping_rules, "label")
|
rule_label_map = frappe.db.get_values("Shipping Rule", shipping_rules, "label")
|
||||||
# we need this in sorted order as per the position of the rule in the settings page
|
# we need this in sorted order as per the position of the rule in the settings page
|
||||||
return [[rule, rule_label_map.get(rule)] for rule in shipping_rules]
|
return [[rule, rule_label_map.get(rule)] for rule in shipping_rules]
|
||||||
|
|
||||||
def get_shipping_rules(party=None, quotation=None, cart_settings=None):
|
def get_shipping_rules(quotation=None, cart_settings=None):
|
||||||
if not party:
|
|
||||||
party = get_lead_or_customer()
|
|
||||||
if not quotation:
|
if not quotation:
|
||||||
quotation = _get_cart_quotation()
|
quotation = _get_cart_quotation()
|
||||||
if not cart_settings:
|
|
||||||
cart_settings = frappe.get_doc("Shopping Cart Settings")
|
|
||||||
|
|
||||||
# set shipping rule based on shipping territory
|
shipping_rules = []
|
||||||
shipping_territory = get_address_territory(quotation.shipping_address_name) or \
|
if quotation.shipping_address_name:
|
||||||
party.territory
|
country = frappe.db.get_value("Address", quotation.shipping_address_name, "country")
|
||||||
|
if country:
|
||||||
shipping_rules = cart_settings.get_shipping_rules(shipping_territory)
|
shipping_rules = frappe.db.sql_list("""select distinct sr.name
|
||||||
|
from `tabShipping Rule Country` src, `tabShipping Rule` sr
|
||||||
|
where src.country = %s and
|
||||||
|
sr.disabled != 1 and sr.name = src.parent""", country)
|
||||||
|
|
||||||
return shipping_rules
|
return shipping_rules
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
|
||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
# For license information, please see license.txt
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
|
||||||
|
|
||||||
from frappe.model.document import Document
|
|
||||||
|
|
||||||
class ShoppingCartPriceList(Document):
|
|
||||||
pass
|
|
||||||
@@ -75,17 +75,17 @@
|
|||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"description": "<a href=\"#Sales Browser/Territory\">Add / Edit</a>",
|
"fieldname": "price_list",
|
||||||
"fieldname": "default_territory",
|
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 1,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 1,
|
"in_list_view": 0,
|
||||||
"label": "Default Territory",
|
"label": "Price List",
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"options": "Territory",
|
"options": "Price List",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
@@ -118,7 +118,7 @@
|
|||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"description": "<a href=\"#Sales Browser/Customer Group\">Add / Edit</a>",
|
"description": "",
|
||||||
"fieldname": "default_customer_group",
|
"fieldname": "default_customer_group",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@@ -157,91 +157,6 @@
|
|||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"fieldname": "section_break_6",
|
|
||||||
"fieldtype": "Section Break",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"fieldname": "price_lists",
|
|
||||||
"fieldtype": "Table",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"label": "Price Lists",
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Shopping Cart Price List",
|
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"fieldname": "column_break_10",
|
|
||||||
"fieldtype": "Column Break",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"fieldname": "shipping_rules",
|
|
||||||
"fieldtype": "Table",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"label": "Shipping Rules",
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Shopping Cart Shipping Rule",
|
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"hide_heading": 0,
|
"hide_heading": 0,
|
||||||
@@ -253,7 +168,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-09-11 19:03:54.750937",
|
"modified": "2015-09-17 07:56:09.176098",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Shopping Cart",
|
"module": "Shopping Cart",
|
||||||
"name": "Shopping Cart Settings",
|
"name": "Shopping Cart Settings",
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ import frappe
|
|||||||
from frappe import _, msgprint
|
from frappe import _, msgprint
|
||||||
from frappe.utils import comma_and
|
from frappe.utils import comma_and
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils.nestedset import get_ancestors_of, get_root_of
|
|
||||||
from erpnext.utilities.doctype.address.address import get_territory_from_address
|
|
||||||
|
|
||||||
class ShoppingCartSetupError(frappe.ValidationError): pass
|
class ShoppingCartSetupError(frappe.ValidationError): pass
|
||||||
|
|
||||||
@@ -19,57 +17,7 @@ class ShoppingCartSettings(Document):
|
|||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
if self.enabled:
|
if self.enabled:
|
||||||
self.validate_price_lists()
|
|
||||||
self.validate_exchange_rates_exist()
|
self.validate_exchange_rates_exist()
|
||||||
self.validate_tax_rule()
|
|
||||||
|
|
||||||
def validate_overlapping_territories(self, parentfield, fieldname):
|
|
||||||
# for displaying message
|
|
||||||
doctype = self.meta.get_field(parentfield).options
|
|
||||||
|
|
||||||
# specify atleast one entry in the table
|
|
||||||
self.validate_table_has_rows(parentfield, raise_exception=ShoppingCartSetupError)
|
|
||||||
|
|
||||||
territory_name_map = self.get_territory_name_map(parentfield, fieldname)
|
|
||||||
for territory, names in territory_name_map.items():
|
|
||||||
if len(names) > 1:
|
|
||||||
frappe.throw(_("{0} {1} has a common territory {2}").format(_(doctype), comma_and(names), territory), ShoppingCartSetupError)
|
|
||||||
|
|
||||||
return territory_name_map
|
|
||||||
|
|
||||||
def validate_price_lists(self):
|
|
||||||
self.validate_overlapping_territories("price_lists", "selling_price_list")
|
|
||||||
|
|
||||||
# validate that a Shopping Cart Price List exists for the default territory as a catch all!
|
|
||||||
price_list_for_default_territory = self.get_name_from_territory(self.default_territory, "price_lists",
|
|
||||||
"selling_price_list")
|
|
||||||
|
|
||||||
if not price_list_for_default_territory:
|
|
||||||
msgprint(_("Please specify a Price List which is valid for Territory") +
|
|
||||||
": " + self.default_territory, raise_exception=ShoppingCartSetupError)
|
|
||||||
|
|
||||||
def get_territory_name_map(self, parentfield, fieldname):
|
|
||||||
territory_name_map = {}
|
|
||||||
|
|
||||||
# entries in table
|
|
||||||
names = [doc.get(fieldname) for doc in self.get(parentfield)]
|
|
||||||
if names:
|
|
||||||
# for condition in territory check
|
|
||||||
parenttype = frappe.get_meta(self.meta.get_options(parentfield)).get_options(fieldname)
|
|
||||||
# to validate territory overlap
|
|
||||||
# make a map of territory: [list of names]
|
|
||||||
# if list against each territory has more than one element, raise exception
|
|
||||||
territory_name = frappe.db.sql("""select `territory`, `parent`
|
|
||||||
from `tabApplicable Territory`
|
|
||||||
where `parenttype`=%s and `parent` in (%s)""" %
|
|
||||||
("%s", ", ".join(["%s"]*len(names))), tuple([parenttype] + names))
|
|
||||||
|
|
||||||
for territory, name in territory_name:
|
|
||||||
territory_name_map.setdefault(territory, []).append(name)
|
|
||||||
|
|
||||||
if len(territory_name_map[territory]) > 1:
|
|
||||||
territory_name_map[territory].sort(key=lambda val: names.index(val))
|
|
||||||
return territory_name_map
|
|
||||||
|
|
||||||
def validate_exchange_rates_exist(self):
|
def validate_exchange_rates_exist(self):
|
||||||
"""check if exchange rates exist for all Price List currencies (to company's currency)"""
|
"""check if exchange rates exist for all Price List currencies (to company's currency)"""
|
||||||
@@ -79,7 +27,7 @@ class ShoppingCartSettings(Document):
|
|||||||
raise_exception=ShoppingCartSetupError)
|
raise_exception=ShoppingCartSetupError)
|
||||||
|
|
||||||
price_list_currency_map = frappe.db.get_values("Price List",
|
price_list_currency_map = frappe.db.get_values("Price List",
|
||||||
[d.selling_price_list for d in self.get("price_lists")],
|
[self.price_list],
|
||||||
"currency")
|
"currency")
|
||||||
|
|
||||||
# check if all price lists have a currency
|
# check if all price lists have a currency
|
||||||
@@ -102,32 +50,10 @@ class ShoppingCartSettings(Document):
|
|||||||
msgprint(_("Missing Currency Exchange Rates for {0}").format(comma_and(missing)),
|
msgprint(_("Missing Currency Exchange Rates for {0}").format(comma_and(missing)),
|
||||||
raise_exception=ShoppingCartSetupError)
|
raise_exception=ShoppingCartSetupError)
|
||||||
|
|
||||||
def get_name_from_territory(self, territory, parentfield, fieldname):
|
|
||||||
name = None
|
|
||||||
territory_name_map = self.get_territory_name_map(parentfield, fieldname)
|
|
||||||
if territory_name_map.get(territory):
|
|
||||||
name = territory_name_map.get(territory)
|
|
||||||
else:
|
|
||||||
territory_ancestry = self.get_territory_ancestry(territory)
|
|
||||||
for ancestor in territory_ancestry:
|
|
||||||
if territory_name_map.get(ancestor):
|
|
||||||
name = territory_name_map.get(ancestor)
|
|
||||||
break
|
|
||||||
|
|
||||||
return name
|
|
||||||
|
|
||||||
def get_price_list(self, billing_territory):
|
|
||||||
price_list = self.get_name_from_territory(billing_territory, "price_lists", "selling_price_list")
|
|
||||||
if not (price_list and price_list[0]):
|
|
||||||
price_list = self.get_name_from_territory(self.default_territory or get_root_of("Territory"),
|
|
||||||
"price_lists", "selling_price_list")
|
|
||||||
|
|
||||||
return price_list and price_list[0] or None
|
|
||||||
|
|
||||||
def validate_tax_rule(self):
|
def validate_tax_rule(self):
|
||||||
if not frappe.db.get_value("Tax Rule", {"use_for_shopping_cart" : 1}, "name"):
|
if not frappe.db.get_value("Tax Rule", {"use_for_shopping_cart" : 1}, "name"):
|
||||||
frappe.throw(frappe._("Set Tax Rule for shopping cart"), ShoppingCartSetupError)
|
frappe.throw(frappe._("Set Tax Rule for shopping cart"), ShoppingCartSetupError)
|
||||||
|
|
||||||
def get_tax_master(self, billing_territory):
|
def get_tax_master(self, billing_territory):
|
||||||
tax_master = self.get_name_from_territory(billing_territory, "sales_taxes_and_charges_masters",
|
tax_master = self.get_name_from_territory(billing_territory, "sales_taxes_and_charges_masters",
|
||||||
"sales_taxes_and_charges_master")
|
"sales_taxes_and_charges_master")
|
||||||
@@ -136,15 +62,6 @@ class ShoppingCartSettings(Document):
|
|||||||
def get_shipping_rules(self, shipping_territory):
|
def get_shipping_rules(self, shipping_territory):
|
||||||
return self.get_name_from_territory(shipping_territory, "shipping_rules", "shipping_rule")
|
return self.get_name_from_territory(shipping_territory, "shipping_rules", "shipping_rule")
|
||||||
|
|
||||||
def get_territory_ancestry(self, territory):
|
|
||||||
if not hasattr(self, "_territory_ancestry"):
|
|
||||||
self._territory_ancestry = {}
|
|
||||||
|
|
||||||
if not self._territory_ancestry.get(territory):
|
|
||||||
self._territory_ancestry[territory] = get_ancestors_of("Territory", territory)
|
|
||||||
|
|
||||||
return self._territory_ancestry[territory]
|
|
||||||
|
|
||||||
def validate_cart_settings(doc, method):
|
def validate_cart_settings(doc, method):
|
||||||
frappe.get_doc("Shopping Cart Settings", "Shopping Cart Settings").run_method("validate")
|
frappe.get_doc("Shopping Cart Settings", "Shopping Cart Settings").run_method("validate")
|
||||||
|
|
||||||
@@ -157,10 +74,7 @@ def get_shopping_cart_settings():
|
|||||||
def is_cart_enabled():
|
def is_cart_enabled():
|
||||||
return get_shopping_cart_settings().enabled
|
return get_shopping_cart_settings().enabled
|
||||||
|
|
||||||
def get_default_territory():
|
|
||||||
return get_shopping_cart_settings().default_territory or get_root_of("Territory")
|
|
||||||
|
|
||||||
def check_shopping_cart_enabled():
|
def check_shopping_cart_enabled():
|
||||||
if not get_shopping_cart_settings().enabled:
|
if not get_shopping_cart_settings().enabled:
|
||||||
frappe.throw(_("You need to enable Shopping Cart"), ShoppingCartSetupError)
|
frappe.throw(_("You need to enable Shopping Cart"), ShoppingCartSetupError)
|
||||||
|
|
||||||
|
|||||||
@@ -11,55 +11,29 @@ from erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings
|
|||||||
class TestShoppingCartSettings(unittest.TestCase):
|
class TestShoppingCartSettings(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
frappe.db.sql("""delete from `tabSingles` where doctype="Shipping Cart Settings" """)
|
frappe.db.sql("""delete from `tabSingles` where doctype="Shipping Cart Settings" """)
|
||||||
frappe.db.sql("""delete from `tabShopping Cart Price List`""")
|
|
||||||
frappe.db.sql("""delete from `tabShopping Cart Shipping Rule`""")
|
|
||||||
|
|
||||||
def get_cart_settings(self):
|
def get_cart_settings(self):
|
||||||
return frappe.get_doc({"doctype": "Shopping Cart Settings",
|
return frappe.get_doc({"doctype": "Shopping Cart Settings",
|
||||||
"company": "_Test Company"})
|
"company": "_Test Company"})
|
||||||
|
|
||||||
def test_price_list_territory_overlap(self):
|
|
||||||
cart_settings = self.get_cart_settings()
|
|
||||||
|
|
||||||
def _add_price_list(price_list):
|
|
||||||
cart_settings.append("price_lists", {
|
|
||||||
"doctype": "Shopping Cart Price List",
|
|
||||||
"selling_price_list": price_list
|
|
||||||
})
|
|
||||||
|
|
||||||
for price_list in ("_Test Price List Rest of the World", "_Test Price List India",
|
|
||||||
"_Test Price List"):
|
|
||||||
_add_price_list(price_list)
|
|
||||||
|
|
||||||
controller = cart_settings
|
|
||||||
controller.validate_overlapping_territories("price_lists", "selling_price_list")
|
|
||||||
|
|
||||||
_add_price_list("_Test Price List 2")
|
|
||||||
|
|
||||||
controller = cart_settings
|
|
||||||
self.assertRaises(ShoppingCartSetupError, controller.validate_overlapping_territories,
|
|
||||||
"price_lists", "selling_price_list")
|
|
||||||
|
|
||||||
return cart_settings
|
|
||||||
|
|
||||||
def test_exchange_rate_exists(self):
|
def test_exchange_rate_exists(self):
|
||||||
frappe.db.sql("""delete from `tabCurrency Exchange`""")
|
frappe.db.sql("""delete from `tabCurrency Exchange`""")
|
||||||
|
|
||||||
cart_settings = self.test_price_list_territory_overlap()
|
cart_settings = self.get_cart_settings()
|
||||||
controller = cart_settings
|
cart_settings.price_list = "_Test Price List Rest of the World"
|
||||||
self.assertRaises(ShoppingCartSetupError, controller.validate_exchange_rates_exist)
|
self.assertRaises(ShoppingCartSetupError, cart_settings.validate_exchange_rates_exist)
|
||||||
|
|
||||||
from erpnext.setup.doctype.currency_exchange.test_currency_exchange import test_records as \
|
from erpnext.setup.doctype.currency_exchange.test_currency_exchange import test_records as \
|
||||||
currency_exchange_records
|
currency_exchange_records
|
||||||
frappe.get_doc(currency_exchange_records[0]).insert()
|
frappe.get_doc(currency_exchange_records[0]).insert()
|
||||||
controller.validate_exchange_rates_exist()
|
cart_settings.validate_exchange_rates_exist()
|
||||||
|
|
||||||
def test_tax_rule_validation(self):
|
def test_tax_rule_validation(self):
|
||||||
frappe.db.sql("update `tabTax Rule` set use_for_shopping_cart = 0")
|
frappe.db.sql("update `tabTax Rule` set use_for_shopping_cart = 0")
|
||||||
frappe.db.commit()
|
frappe.db.commit()
|
||||||
|
|
||||||
cart_settings = self.get_cart_settings()
|
cart_settings = self.get_cart_settings()
|
||||||
cart_settings.enabled = 1
|
cart_settings.enabled = 1
|
||||||
if not frappe.db.get_value("Tax Rule", {"use_for_shopping_cart": 1}, "name"):
|
if not frappe.db.get_value("Tax Rule", {"use_for_shopping_cart": 1}, "name"):
|
||||||
self.assertRaises(ShoppingCartSetupError, cart_settings.validate_tax_rule)
|
self.assertRaises(ShoppingCartSetupError, cart_settings.validate_tax_rule)
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import unittest
|
import unittest
|
||||||
import frappe
|
import frappe
|
||||||
from erpnext.shopping_cart import get_quotation, set_item_in_cart, get_party
|
from erpnext.shopping_cart.cart import _get_cart_quotation, update_cart, get_customer
|
||||||
|
|
||||||
class TestShoppingCart(unittest.TestCase):
|
class TestShoppingCart(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
@@ -23,23 +23,11 @@ class TestShoppingCart(unittest.TestCase):
|
|||||||
self.login_as_new_user()
|
self.login_as_new_user()
|
||||||
|
|
||||||
# test if lead is created and quotation with new lead is fetched
|
# test if lead is created and quotation with new lead is fetched
|
||||||
quotation = get_quotation()
|
quotation = _get_cart_quotation()
|
||||||
self.assertEquals(quotation.quotation_to, "Lead")
|
self.assertEquals(quotation.quotation_to, "Customer")
|
||||||
self.assertEquals(frappe.db.get_value("Lead", quotation.lead, "email_id"),
|
self.assertEquals(frappe.db.get_value("Contact", {"customer": quotation.customer}, "email_id"),
|
||||||
"test_cart_user@example.com")
|
"test_cart_user@example.com")
|
||||||
self.assertEquals(quotation.customer, None)
|
self.assertEquals(quotation.lead, None)
|
||||||
self.assertEquals(quotation.contact_email, frappe.session.user)
|
|
||||||
|
|
||||||
return quotation
|
|
||||||
|
|
||||||
def test_get_cart_lead(self):
|
|
||||||
self.login_as_lead()
|
|
||||||
|
|
||||||
# test if quotation with lead is fetched
|
|
||||||
quotation = get_quotation()
|
|
||||||
self.assertEquals(quotation.quotation_to, "Lead")
|
|
||||||
self.assertEquals(quotation.lead, frappe.db.get_value("Lead", {"email_id": "test_cart_lead@example.com"}))
|
|
||||||
self.assertEquals(quotation.customer, None)
|
|
||||||
self.assertEquals(quotation.contact_email, frappe.session.user)
|
self.assertEquals(quotation.contact_email, frappe.session.user)
|
||||||
|
|
||||||
return quotation
|
return quotation
|
||||||
@@ -48,7 +36,7 @@ class TestShoppingCart(unittest.TestCase):
|
|||||||
self.login_as_customer()
|
self.login_as_customer()
|
||||||
|
|
||||||
# test if quotation with customer is fetched
|
# test if quotation with customer is fetched
|
||||||
quotation = get_quotation()
|
quotation = _get_cart_quotation()
|
||||||
self.assertEquals(quotation.quotation_to, "Customer")
|
self.assertEquals(quotation.quotation_to, "Customer")
|
||||||
self.assertEquals(quotation.customer, "_Test Customer")
|
self.assertEquals(quotation.customer, "_Test Customer")
|
||||||
self.assertEquals(quotation.lead, None)
|
self.assertEquals(quotation.lead, None)
|
||||||
@@ -57,21 +45,24 @@ class TestShoppingCart(unittest.TestCase):
|
|||||||
return quotation
|
return quotation
|
||||||
|
|
||||||
def test_add_to_cart(self):
|
def test_add_to_cart(self):
|
||||||
self.login_as_lead()
|
self.login_as_customer()
|
||||||
|
|
||||||
# remove from cart
|
# remove from cart
|
||||||
self.remove_all_items_from_cart()
|
self.remove_all_items_from_cart()
|
||||||
|
|
||||||
# add first item
|
# add first item
|
||||||
set_item_in_cart("_Test Item", 1)
|
update_cart("_Test Item", 1)
|
||||||
quotation = self.test_get_cart_lead()
|
|
||||||
|
quotation = self.test_get_cart_customer()
|
||||||
|
|
||||||
self.assertEquals(quotation.get("items")[0].item_code, "_Test Item")
|
self.assertEquals(quotation.get("items")[0].item_code, "_Test Item")
|
||||||
self.assertEquals(quotation.get("items")[0].qty, 1)
|
self.assertEquals(quotation.get("items")[0].qty, 1)
|
||||||
self.assertEquals(quotation.get("items")[0].amount, 10)
|
self.assertEquals(quotation.get("items")[0].amount, 10)
|
||||||
|
|
||||||
|
|
||||||
# add second item
|
# add second item
|
||||||
set_item_in_cart("_Test Item 2", 1)
|
update_cart("_Test Item 2", 1)
|
||||||
quotation = self.test_get_cart_lead()
|
quotation = self.test_get_cart_customer()
|
||||||
self.assertEquals(quotation.get("items")[1].item_code, "_Test Item 2")
|
self.assertEquals(quotation.get("items")[1].item_code, "_Test Item 2")
|
||||||
self.assertEquals(quotation.get("items")[1].qty, 1)
|
self.assertEquals(quotation.get("items")[1].qty, 1)
|
||||||
self.assertEquals(quotation.get("items")[1].amount, 20)
|
self.assertEquals(quotation.get("items")[1].amount, 20)
|
||||||
@@ -83,8 +74,8 @@ class TestShoppingCart(unittest.TestCase):
|
|||||||
self.test_add_to_cart()
|
self.test_add_to_cart()
|
||||||
|
|
||||||
# update first item
|
# update first item
|
||||||
set_item_in_cart("_Test Item", 5)
|
update_cart("_Test Item", 5)
|
||||||
quotation = self.test_get_cart_lead()
|
quotation = self.test_get_cart_customer()
|
||||||
self.assertEquals(quotation.get("items")[0].item_code, "_Test Item")
|
self.assertEquals(quotation.get("items")[0].item_code, "_Test Item")
|
||||||
self.assertEquals(quotation.get("items")[0].qty, 5)
|
self.assertEquals(quotation.get("items")[0].qty, 5)
|
||||||
self.assertEquals(quotation.get("items")[0].amount, 50)
|
self.assertEquals(quotation.get("items")[0].amount, 50)
|
||||||
@@ -96,8 +87,9 @@ class TestShoppingCart(unittest.TestCase):
|
|||||||
self.test_add_to_cart()
|
self.test_add_to_cart()
|
||||||
|
|
||||||
# remove first item
|
# remove first item
|
||||||
set_item_in_cart("_Test Item", 0)
|
update_cart("_Test Item", 0)
|
||||||
quotation = self.test_get_cart_lead()
|
quotation = self.test_get_cart_customer()
|
||||||
|
|
||||||
self.assertEquals(quotation.get("items")[0].item_code, "_Test Item 2")
|
self.assertEquals(quotation.get("items")[0].item_code, "_Test Item 2")
|
||||||
self.assertEquals(quotation.get("items")[0].qty, 1)
|
self.assertEquals(quotation.get("items")[0].qty, 1)
|
||||||
self.assertEquals(quotation.get("items")[0].amount, 20)
|
self.assertEquals(quotation.get("items")[0].amount, 20)
|
||||||
@@ -105,16 +97,16 @@ class TestShoppingCart(unittest.TestCase):
|
|||||||
self.assertEquals(len(quotation.get("items")), 1)
|
self.assertEquals(len(quotation.get("items")), 1)
|
||||||
|
|
||||||
# remove second item
|
# remove second item
|
||||||
set_item_in_cart("_Test Item 2", 0)
|
update_cart("_Test Item 2", 0)
|
||||||
quotation = self.test_get_cart_lead()
|
quotation = self.test_get_cart_customer()
|
||||||
self.assertEquals(quotation.net_total, 0)
|
|
||||||
self.assertEquals(len(quotation.get("items")), 0)
|
self.assertEquals(len(quotation.get("items")), 0)
|
||||||
|
self.assertEquals(quotation.net_total, 0)
|
||||||
|
|
||||||
def test_taxe_rule(self):
|
def test_tax_rule(self):
|
||||||
self.login_as_customer()
|
self.login_as_customer()
|
||||||
quotation = self.create_quotation()
|
quotation = self.create_quotation()
|
||||||
|
|
||||||
from erpnext.accounts.party import set_taxes
|
from erpnext.accounts.party import set_taxes
|
||||||
|
|
||||||
tax_rule_master = set_taxes(quotation.customer, "Customer", \
|
tax_rule_master = set_taxes(quotation.customer, "Customer", \
|
||||||
@@ -123,17 +115,17 @@ class TestShoppingCart(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertEquals(quotation.taxes_and_charges, tax_rule_master)
|
self.assertEquals(quotation.taxes_and_charges, tax_rule_master)
|
||||||
self.assertEquals(quotation.total_taxes_and_charges, 1000.0)
|
self.assertEquals(quotation.total_taxes_and_charges, 1000.0)
|
||||||
|
|
||||||
self.remove_test_quotation(quotation)
|
self.remove_test_quotation(quotation)
|
||||||
|
|
||||||
def create_quotation(self):
|
def create_quotation(self):
|
||||||
quotation = frappe.new_doc("Quotation")
|
quotation = frappe.new_doc("Quotation")
|
||||||
|
|
||||||
values = {
|
values = {
|
||||||
"doctype": "Quotation",
|
"doctype": "Quotation",
|
||||||
"quotation_to": "Customer",
|
"quotation_to": "Customer",
|
||||||
"order_type": "Shopping Cart",
|
"order_type": "Shopping Cart",
|
||||||
"customer": get_party(frappe.session.user).name,
|
"customer": get_customer(frappe.session.user).name,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"contact_email": frappe.session.user,
|
"contact_email": frappe.session.user,
|
||||||
"selling_price_list": "_Test Price List Rest of the World",
|
"selling_price_list": "_Test Price List Rest of the World",
|
||||||
@@ -146,13 +138,13 @@ class TestShoppingCart(unittest.TestCase):
|
|||||||
"taxes": frappe.get_doc("Sales Taxes and Charges Template", "_Test Tax 1").taxes,
|
"taxes": frappe.get_doc("Sales Taxes and Charges Template", "_Test Tax 1").taxes,
|
||||||
"company": "_Test Company"
|
"company": "_Test Company"
|
||||||
}
|
}
|
||||||
|
|
||||||
quotation.update(values)
|
quotation.update(values)
|
||||||
|
|
||||||
quotation.insert(ignore_permissions=True)
|
quotation.insert(ignore_permissions=True)
|
||||||
|
|
||||||
return quotation
|
return quotation
|
||||||
|
|
||||||
def remove_test_quotation(self, quotation):
|
def remove_test_quotation(self, quotation):
|
||||||
frappe.set_user("Administrator")
|
frappe.set_user("Administrator")
|
||||||
quotation.delete()
|
quotation.delete()
|
||||||
@@ -161,26 +153,29 @@ class TestShoppingCart(unittest.TestCase):
|
|||||||
def enable_shopping_cart(self):
|
def enable_shopping_cart(self):
|
||||||
settings = frappe.get_doc("Shopping Cart Settings", "Shopping Cart Settings")
|
settings = frappe.get_doc("Shopping Cart Settings", "Shopping Cart Settings")
|
||||||
|
|
||||||
if settings.get("price_lists"):
|
settings.update({
|
||||||
settings.enabled = 1
|
"enabled": 1,
|
||||||
else:
|
"company": "_Test Company",
|
||||||
settings.update({
|
"default_customer_group": "_Test Customer Group",
|
||||||
"enabled": 1,
|
"quotation_series": "_T-Quotation-",
|
||||||
"company": "_Test Company",
|
"price_list": "_Test Price List India"
|
||||||
"default_territory": "_Test Territory Rest Of The World",
|
})
|
||||||
"default_customer_group": "_Test Customer Group",
|
|
||||||
"quotation_series": "_T-Quotation-"
|
# insert item price
|
||||||
})
|
if not frappe.db.get_value("Item Price", {"price_list": "_Test Price List India",
|
||||||
settings.set("price_lists", [
|
"item_code": "_Test Item"}):
|
||||||
# price lists
|
frappe.get_doc({
|
||||||
{"doctype": "Shopping Cart Price List", "parentfield": "price_lists",
|
"doctype": "Item Price",
|
||||||
"selling_price_list": "_Test Price List India"},
|
"price_list": "_Test Price List India",
|
||||||
{"doctype": "Shopping Cart Price List", "parentfield": "price_lists",
|
"item_code": "_Test Item",
|
||||||
"selling_price_list": "_Test Price List Rest of the World"}
|
"price_list_rate": 10
|
||||||
])
|
}).insert()
|
||||||
settings.set("shipping_rules", {"doctype": "Shopping Cart Shipping Rule", "parentfield": "shipping_rules",
|
frappe.get_doc({
|
||||||
"shipping_rule": "_Test Shipping Rule - India"})
|
"doctype": "Item Price",
|
||||||
|
"price_list": "_Test Price List India",
|
||||||
|
"item_code": "_Test Item 2",
|
||||||
|
"price_list_rate": 20
|
||||||
|
}).insert()
|
||||||
|
|
||||||
settings.save()
|
settings.save()
|
||||||
frappe.local.shopping_cart_settings = None
|
frappe.local.shopping_cart_settings = None
|
||||||
@@ -194,56 +189,13 @@ class TestShoppingCart(unittest.TestCase):
|
|||||||
def login_as_new_user(self):
|
def login_as_new_user(self):
|
||||||
frappe.set_user("test_cart_user@example.com")
|
frappe.set_user("test_cart_user@example.com")
|
||||||
|
|
||||||
def login_as_lead(self):
|
|
||||||
self.create_lead()
|
|
||||||
frappe.set_user("test_cart_lead@example.com")
|
|
||||||
|
|
||||||
def login_as_customer(self):
|
def login_as_customer(self):
|
||||||
frappe.set_user("test_contact_customer@example.com")
|
frappe.set_user("test_contact_customer@example.com")
|
||||||
|
|
||||||
def create_lead(self):
|
|
||||||
if frappe.db.get_value("Lead", {"email_id": "test_cart_lead@example.com"}):
|
|
||||||
return
|
|
||||||
|
|
||||||
lead = frappe.get_doc({
|
|
||||||
"doctype": "Lead",
|
|
||||||
"email_id": "test_cart_lead@example.com",
|
|
||||||
"lead_name": "_Test Website Lead",
|
|
||||||
"status": "Open",
|
|
||||||
"territory": "_Test Territory Rest Of The World",
|
|
||||||
"company": "_Test Company"
|
|
||||||
})
|
|
||||||
lead.insert(ignore_permissions=True)
|
|
||||||
|
|
||||||
frappe.get_doc({
|
|
||||||
"doctype": "Address",
|
|
||||||
"address_line1": "_Test Address Line 1",
|
|
||||||
"address_title": "_Test Cart Lead Address",
|
|
||||||
"address_type": "Office",
|
|
||||||
"city": "_Test City",
|
|
||||||
"country": "United States",
|
|
||||||
"lead": lead.name,
|
|
||||||
"lead_name": "_Test Website Lead",
|
|
||||||
"is_primary_address": 1,
|
|
||||||
"phone": "+91 0000000000"
|
|
||||||
}).insert(ignore_permissions=True)
|
|
||||||
|
|
||||||
frappe.get_doc({
|
|
||||||
"doctype": "Address",
|
|
||||||
"address_line1": "_Test Address Line 1",
|
|
||||||
"address_title": "_Test Cart Lead Address",
|
|
||||||
"address_type": "Personal",
|
|
||||||
"city": "_Test City",
|
|
||||||
"country": "India",
|
|
||||||
"lead": lead.name,
|
|
||||||
"lead_name": "_Test Website Lead",
|
|
||||||
"phone": "+91 0000000000"
|
|
||||||
}).insert(ignore_permissions=True)
|
|
||||||
|
|
||||||
def remove_all_items_from_cart(self):
|
def remove_all_items_from_cart(self):
|
||||||
quotation = get_quotation()
|
quotation = _get_cart_quotation()
|
||||||
quotation.set("items", [])
|
quotation.set("items", [])
|
||||||
quotation.save(ignore_permissions=True)
|
quotation.save(ignore_permissions=True)
|
||||||
|
|
||||||
test_dependencies = ["Sales Taxes and Charges Template", "Price List", "Item Price", "Shipping Rule", "Currency Exchange",
|
test_dependencies = ["Sales Taxes and Charges Template", "Price List", "Item Price", "Shipping Rule", "Currency Exchange",
|
||||||
"Customer Group", "Lead", "Customer", "Contact", "Address", "Item", "Tax Rule"]
|
"Customer Group", "Lead", "Customer", "Contact", "Address", "Item", "Tax Rule"]
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ class Item(WebsiteGenerator):
|
|||||||
condition_field = "show_in_website",
|
condition_field = "show_in_website",
|
||||||
template = "templates/generators/item.html",
|
template = "templates/generators/item.html",
|
||||||
parent_website_route_field = "item_group",
|
parent_website_route_field = "item_group",
|
||||||
|
no_cache = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
def onload(self):
|
def onload(self):
|
||||||
|
|||||||
@@ -2,10 +2,6 @@
|
|||||||
// License: GNU General Public License v3. See license.txt
|
// License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
$.extend(cur_frm.cscript, {
|
$.extend(cur_frm.cscript, {
|
||||||
onload: function() {
|
|
||||||
erpnext.add_applicable_territory();
|
|
||||||
},
|
|
||||||
|
|
||||||
refresh: function() {
|
refresh: function() {
|
||||||
cur_frm.add_custom_button(__("Add / Edit Prices"), function() {
|
cur_frm.add_custom_button(__("Add / Edit Prices"), function() {
|
||||||
frappe.route_options = {
|
frappe.route_options = {
|
||||||
@@ -14,4 +10,4 @@ $.extend(cur_frm.cscript, {
|
|||||||
frappe.set_route("Report", "Item Price");
|
frappe.set_route("Report", "Item Price");
|
||||||
}, "icon-money");
|
}, "icon-money");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -163,21 +163,21 @@
|
|||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"description": "Specify a list of Territories, for which, this Price List is valid",
|
"fieldname": "countries",
|
||||||
"fieldname": "territories",
|
|
||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"label": "Valid for Territories",
|
"label": "Applicable for Countries",
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"options": "Applicable Territory",
|
"options": "Price List Country",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 1,
|
"reqd": 0,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
@@ -193,7 +193,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 1,
|
"max_attachments": 1,
|
||||||
"modified": "2015-09-14 02:55:58.919822",
|
"modified": "2015-09-17 06:50:31.465221",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Price List",
|
"name": "Price List",
|
||||||
@@ -201,7 +201,7 @@
|
|||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
"amend": 0,
|
"amend": 0,
|
||||||
"apply_user_permissions": 0,
|
"apply_user_permissions": 1,
|
||||||
"cancel": 0,
|
"cancel": 0,
|
||||||
"create": 0,
|
"create": 0,
|
||||||
"delete": 0,
|
"delete": 0,
|
||||||
@@ -241,7 +241,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
"amend": 0,
|
||||||
"apply_user_permissions": 0,
|
"apply_user_permissions": 1,
|
||||||
"cancel": 0,
|
"cancel": 0,
|
||||||
"create": 0,
|
"create": 0,
|
||||||
"delete": 0,
|
"delete": 0,
|
||||||
@@ -281,7 +281,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
"amend": 0,
|
||||||
"apply_user_permissions": 0,
|
"apply_user_permissions": 1,
|
||||||
"cancel": 0,
|
"cancel": 0,
|
||||||
"create": 0,
|
"create": 0,
|
||||||
"delete": 0,
|
"delete": 0,
|
||||||
|
|||||||
@@ -13,19 +13,6 @@ class PriceList(Document):
|
|||||||
if not cint(self.buying) and not cint(self.selling):
|
if not cint(self.buying) and not cint(self.selling):
|
||||||
throw(_("Price List must be applicable for Buying or Selling"))
|
throw(_("Price List must be applicable for Buying or Selling"))
|
||||||
|
|
||||||
try:
|
|
||||||
# at least one territory
|
|
||||||
self.validate_table_has_rows("territories")
|
|
||||||
except frappe.EmptyTableError:
|
|
||||||
# if no territory, set default territory
|
|
||||||
if frappe.defaults.get_user_default("territory"):
|
|
||||||
self.append("territories", {
|
|
||||||
"doctype": "Applicable Territory",
|
|
||||||
"territory": frappe.defaults.get_user_default("territory")
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
raise
|
|
||||||
|
|
||||||
def on_update(self):
|
def on_update(self):
|
||||||
self.set_default_if_missing()
|
self.set_default_if_missing()
|
||||||
self.update_item_price()
|
self.update_item_price()
|
||||||
|
|||||||
@@ -1,67 +1,34 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"buying": 1,
|
"buying": 1,
|
||||||
"currency": "INR",
|
"currency": "INR",
|
||||||
"doctype": "Price List",
|
"doctype": "Price List",
|
||||||
"enabled": 1,
|
"enabled": 1,
|
||||||
"price_list_name": "_Test Price List",
|
"price_list_name": "_Test Price List",
|
||||||
"selling": 1,
|
"selling": 1
|
||||||
"territories": [
|
},
|
||||||
{
|
|
||||||
"doctype": "Applicable Territory",
|
|
||||||
"parentfield": "territories",
|
|
||||||
"territory": "All Territories"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"buying": 1,
|
"buying": 1,
|
||||||
"currency": "INR",
|
"currency": "INR",
|
||||||
"doctype": "Price List",
|
"doctype": "Price List",
|
||||||
"enabled": 1,
|
"enabled": 1,
|
||||||
"price_list_name": "_Test Price List 2",
|
"price_list_name": "_Test Price List 2",
|
||||||
"selling": 1,
|
"selling": 1
|
||||||
"territories": [
|
},
|
||||||
{
|
|
||||||
"doctype": "Applicable Territory",
|
|
||||||
"parentfield": "territories",
|
|
||||||
"territory": "_Test Territory Rest Of The World"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"buying": 1,
|
"buying": 1,
|
||||||
"currency": "INR",
|
"currency": "INR",
|
||||||
"doctype": "Price List",
|
"doctype": "Price List",
|
||||||
"enabled": 1,
|
"enabled": 1,
|
||||||
"price_list_name": "_Test Price List India",
|
"price_list_name": "_Test Price List India",
|
||||||
"selling": 1,
|
"selling": 1
|
||||||
"territories": [
|
},
|
||||||
{
|
|
||||||
"doctype": "Applicable Territory",
|
|
||||||
"parentfield": "territories",
|
|
||||||
"territory": "_Test Territory India"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"buying": 1,
|
"buying": 1,
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
"doctype": "Price List",
|
"doctype": "Price List",
|
||||||
"enabled": 1,
|
"enabled": 1,
|
||||||
"price_list_name": "_Test Price List Rest of the World",
|
"price_list_name": "_Test Price List Rest of the World",
|
||||||
"selling": 1,
|
"selling": 1
|
||||||
"territories": [
|
|
||||||
{
|
|
||||||
"doctype": "Applicable Territory",
|
|
||||||
"parentfield": "territories",
|
|
||||||
"territory": "_Test Territory Rest Of The World"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"doctype": "Applicable Territory",
|
|
||||||
"parentfield": "territories",
|
|
||||||
"territory": "_Test Territory United States"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -2,26 +2,27 @@
|
|||||||
"allow_copy": 0,
|
"allow_copy": 0,
|
||||||
"allow_import": 0,
|
"allow_import": 0,
|
||||||
"allow_rename": 0,
|
"allow_rename": 0,
|
||||||
"creation": "2013-06-20 12:48:38",
|
"creation": "2015-09-17 06:49:51.810318",
|
||||||
"custom": 0,
|
"custom": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
|
"document_type": "",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"description": "",
|
"fieldname": "country",
|
||||||
"fieldname": "territory",
|
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Territory",
|
"label": "Country",
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"options": "Territory",
|
"options": "Country",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
@@ -33,18 +34,20 @@
|
|||||||
],
|
],
|
||||||
"hide_heading": 0,
|
"hide_heading": 0,
|
||||||
"hide_toolbar": 0,
|
"hide_toolbar": 0,
|
||||||
"idx": 1,
|
|
||||||
"in_create": 0,
|
"in_create": 0,
|
||||||
"in_dialog": 0,
|
"in_dialog": 0,
|
||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2015-01-01 14:29:58.724652",
|
"modified": "2015-09-17 06:49:51.810318",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Setup",
|
"module": "Stock",
|
||||||
"name": "Applicable Territory",
|
"name": "Price List Country",
|
||||||
|
"name_case": "",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [],
|
"permissions": [],
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"read_only_onload": 0
|
"read_only_onload": 0,
|
||||||
|
"sort_field": "modified",
|
||||||
|
"sort_order": "DESC"
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
class PriceListCountry(Document):
|
||||||
|
pass
|
||||||
@@ -49,7 +49,7 @@ class StockEntry(StockController):
|
|||||||
self.validate_finished_goods()
|
self.validate_finished_goods()
|
||||||
self.validate_with_material_request()
|
self.validate_with_material_request()
|
||||||
self.validate_batch()
|
self.validate_batch()
|
||||||
|
|
||||||
self.set_actual_qty()
|
self.set_actual_qty()
|
||||||
self.calculate_rate_and_amount()
|
self.calculate_rate_and_amount()
|
||||||
|
|
||||||
@@ -212,10 +212,10 @@ class StockEntry(StockController):
|
|||||||
if fg_qty_already_entered >= qty:
|
if fg_qty_already_entered >= qty:
|
||||||
frappe.throw(_("Stock Entries already created for Production Order ")
|
frappe.throw(_("Stock Entries already created for Production Order ")
|
||||||
+ self.production_order + ":" + ", ".join(other_ste), DuplicateEntryForProductionOrderError)
|
+ self.production_order + ":" + ", ".join(other_ste), DuplicateEntryForProductionOrderError)
|
||||||
|
|
||||||
def set_actual_qty(self):
|
def set_actual_qty(self):
|
||||||
allow_negative_stock = cint(frappe.db.get_value("Stock Settings", None, "allow_negative_stock"))
|
allow_negative_stock = cint(frappe.db.get_value("Stock Settings", None, "allow_negative_stock"))
|
||||||
|
|
||||||
for d in self.get('items'):
|
for d in self.get('items'):
|
||||||
previous_sle = get_previous_sle({
|
previous_sle = get_previous_sle({
|
||||||
"item_code": d.item_code,
|
"item_code": d.item_code,
|
||||||
@@ -232,7 +232,7 @@ class StockEntry(StockController):
|
|||||||
frappe.throw(_("""Row {0}: Qty not avalable in warehouse {1} on {2} {3}.
|
frappe.throw(_("""Row {0}: Qty not avalable in warehouse {1} on {2} {3}.
|
||||||
Available Qty: {4}, Transfer Qty: {5}""").format(d.idx, d.s_warehouse,
|
Available Qty: {4}, Transfer Qty: {5}""").format(d.idx, d.s_warehouse,
|
||||||
self.posting_date, self.posting_time, d.actual_qty, d.transfer_qty), NegativeStockError)
|
self.posting_date, self.posting_time, d.actual_qty, d.transfer_qty), NegativeStockError)
|
||||||
|
|
||||||
def get_stock_and_rate(self):
|
def get_stock_and_rate(self):
|
||||||
self.set_actual_qty()
|
self.set_actual_qty()
|
||||||
self.calculate_rate_and_amount()
|
self.calculate_rate_and_amount()
|
||||||
@@ -244,7 +244,7 @@ class StockEntry(StockController):
|
|||||||
self.validate_valuation_rate()
|
self.validate_valuation_rate()
|
||||||
self.set_total_incoming_outgoing_value()
|
self.set_total_incoming_outgoing_value()
|
||||||
self.set_total_amount()
|
self.set_total_amount()
|
||||||
|
|
||||||
def set_basic_rate(self, force=False):
|
def set_basic_rate(self, force=False):
|
||||||
"""get stock and incoming rate on posting date"""
|
"""get stock and incoming rate on posting date"""
|
||||||
raw_material_cost = 0.0
|
raw_material_cost = 0.0
|
||||||
@@ -269,9 +269,9 @@ class StockEntry(StockController):
|
|||||||
d.basic_amount = flt(flt(d.transfer_qty) * flt(d.basic_rate), d.precision("basic_amount"))
|
d.basic_amount = flt(flt(d.transfer_qty) * flt(d.basic_rate), d.precision("basic_amount"))
|
||||||
if not d.t_warehouse:
|
if not d.t_warehouse:
|
||||||
raw_material_cost += flt(d.basic_amount)
|
raw_material_cost += flt(d.basic_amount)
|
||||||
|
|
||||||
self.set_basic_rate_for_finished_goods(raw_material_cost)
|
self.set_basic_rate_for_finished_goods(raw_material_cost)
|
||||||
|
|
||||||
def set_basic_rate_for_finished_goods(self, raw_material_cost):
|
def set_basic_rate_for_finished_goods(self, raw_material_cost):
|
||||||
if self.purpose in ["Manufacture", "Repack"]:
|
if self.purpose in ["Manufacture", "Repack"]:
|
||||||
number_of_fg_items = len([t.t_warehouse for t in self.get("items") if t.t_warehouse])
|
number_of_fg_items = len([t.t_warehouse for t in self.get("items") if t.t_warehouse])
|
||||||
@@ -279,11 +279,11 @@ class StockEntry(StockController):
|
|||||||
if d.bom_no or (d.t_warehouse and number_of_fg_items == 1):
|
if d.bom_no or (d.t_warehouse and number_of_fg_items == 1):
|
||||||
d.basic_rate = flt(raw_material_cost / flt(d.transfer_qty), d.precision("basic_rate"))
|
d.basic_rate = flt(raw_material_cost / flt(d.transfer_qty), d.precision("basic_rate"))
|
||||||
d.basic_amount = flt(raw_material_cost, d.precision("basic_amount"))
|
d.basic_amount = flt(raw_material_cost, d.precision("basic_amount"))
|
||||||
|
|
||||||
def distribute_additional_costs(self):
|
def distribute_additional_costs(self):
|
||||||
if self.purpose == "Material Issue":
|
if self.purpose == "Material Issue":
|
||||||
self.additional_costs = []
|
self.additional_costs = []
|
||||||
|
|
||||||
self.total_additional_costs = sum([flt(t.amount) for t in self.get("additional_costs")])
|
self.total_additional_costs = sum([flt(t.amount) for t in self.get("additional_costs")])
|
||||||
total_basic_amount = sum([flt(t.basic_amount) for t in self.get("items") if t.t_warehouse])
|
total_basic_amount = sum([flt(t.basic_amount) for t in self.get("items") if t.t_warehouse])
|
||||||
|
|
||||||
@@ -292,11 +292,11 @@ class StockEntry(StockController):
|
|||||||
d.additional_cost = (flt(d.basic_amount) / total_basic_amount) * self.total_additional_costs
|
d.additional_cost = (flt(d.basic_amount) / total_basic_amount) * self.total_additional_costs
|
||||||
else:
|
else:
|
||||||
d.additional_cost = 0
|
d.additional_cost = 0
|
||||||
|
|
||||||
def update_valuation_rate(self):
|
def update_valuation_rate(self):
|
||||||
for d in self.get("items"):
|
for d in self.get("items"):
|
||||||
d.amount = flt(d.basic_amount + flt(d.additional_cost), d.precision("amount"))
|
d.amount = flt(d.basic_amount + flt(d.additional_cost), d.precision("amount"))
|
||||||
d.valuation_rate = flt(flt(d.basic_rate) + flt(d.additional_cost) / flt(d.transfer_qty),
|
d.valuation_rate = flt(flt(d.basic_rate) + flt(d.additional_cost) / flt(d.transfer_qty),
|
||||||
d.precision("valuation_rate"))
|
d.precision("valuation_rate"))
|
||||||
|
|
||||||
def validate_valuation_rate(self):
|
def validate_valuation_rate(self):
|
||||||
@@ -373,7 +373,7 @@ class StockEntry(StockController):
|
|||||||
|
|
||||||
def update_stock_ledger(self):
|
def update_stock_ledger(self):
|
||||||
sl_entries = []
|
sl_entries = []
|
||||||
for d in self.get('items'):
|
for d in self.get('items'):
|
||||||
if cstr(d.s_warehouse) and self.docstatus == 1:
|
if cstr(d.s_warehouse) and self.docstatus == 1:
|
||||||
sl_entries.append(self.get_sl_entries(d, {
|
sl_entries.append(self.get_sl_entries(d, {
|
||||||
"warehouse": cstr(d.s_warehouse),
|
"warehouse": cstr(d.s_warehouse),
|
||||||
@@ -399,15 +399,15 @@ class StockEntry(StockController):
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
self.make_sl_entries(sl_entries, self.amended_from and 'Yes' or 'No')
|
self.make_sl_entries(sl_entries, self.amended_from and 'Yes' or 'No')
|
||||||
|
|
||||||
def get_gl_entries(self, warehouse_account):
|
def get_gl_entries(self, warehouse_account):
|
||||||
expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
|
expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
|
||||||
|
|
||||||
gl_entries = super(StockEntry, self).get_gl_entries(warehouse_account)
|
gl_entries = super(StockEntry, self).get_gl_entries(warehouse_account)
|
||||||
|
|
||||||
for d in self.get("items"):
|
for d in self.get("items"):
|
||||||
additional_cost = flt(d.additional_cost, d.precision("additional_cost"))
|
additional_cost = flt(d.additional_cost, d.precision("additional_cost"))
|
||||||
if additional_cost:
|
if additional_cost:
|
||||||
gl_entries.append(self.get_gl_dict({
|
gl_entries.append(self.get_gl_dict({
|
||||||
"account": expenses_included_in_valuation,
|
"account": expenses_included_in_valuation,
|
||||||
"against": d.expense_account,
|
"against": d.expense_account,
|
||||||
@@ -415,7 +415,7 @@ class StockEntry(StockController):
|
|||||||
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
||||||
"credit": additional_cost
|
"credit": additional_cost
|
||||||
}))
|
}))
|
||||||
|
|
||||||
gl_entries.append(self.get_gl_dict({
|
gl_entries.append(self.get_gl_dict({
|
||||||
"account": d.expense_account,
|
"account": d.expense_account,
|
||||||
"against": expenses_included_in_valuation,
|
"against": expenses_included_in_valuation,
|
||||||
@@ -521,7 +521,7 @@ class StockEntry(StockController):
|
|||||||
def get_items(self):
|
def get_items(self):
|
||||||
self.set('items', [])
|
self.set('items', [])
|
||||||
self.validate_production_order()
|
self.validate_production_order()
|
||||||
|
|
||||||
if not self.posting_date or not self.posting_time:
|
if not self.posting_date or not self.posting_time:
|
||||||
frappe.throw(_("Posting date and posting time is mandatory"))
|
frappe.throw(_("Posting date and posting time is mandatory"))
|
||||||
|
|
||||||
@@ -548,7 +548,7 @@ class StockEntry(StockController):
|
|||||||
for item in item_dict.values():
|
for item in item_dict.values():
|
||||||
item["to_warehouse"] = self.pro_doc.wip_warehouse
|
item["to_warehouse"] = self.pro_doc.wip_warehouse
|
||||||
self.add_to_stock_entry_detail(item_dict)
|
self.add_to_stock_entry_detail(item_dict)
|
||||||
|
|
||||||
elif self.production_order and self.purpose == "Manufacture" and \
|
elif self.production_order and self.purpose == "Manufacture" and \
|
||||||
frappe.db.get_single_value("Manufacturing Settings", "backflush_raw_materials_based_on")== "Material Transferred for Manufacture":
|
frappe.db.get_single_value("Manufacturing Settings", "backflush_raw_materials_based_on")== "Material Transferred for Manufacture":
|
||||||
self.get_transfered_raw_materials()
|
self.get_transfered_raw_materials()
|
||||||
@@ -578,10 +578,14 @@ class StockEntry(StockController):
|
|||||||
to_warehouse = self.pro_doc.fg_warehouse
|
to_warehouse = self.pro_doc.fg_warehouse
|
||||||
else:
|
else:
|
||||||
item_code = frappe.db.get_value("BOM", self.bom_no, "item")
|
item_code = frappe.db.get_value("BOM", self.bom_no, "item")
|
||||||
to_warehouse = ""
|
to_warehouse = self.to_warehouse
|
||||||
|
|
||||||
item = frappe.db.get_value("Item", item_code, ["item_name",
|
item = frappe.db.get_value("Item", item_code, ["item_name",
|
||||||
"description", "stock_uom", "expense_account", "buying_cost_center", "name"], as_dict=1)
|
"description", "stock_uom", "expense_account", "buying_cost_center", "name", "default_warehouse"], as_dict=1)
|
||||||
|
|
||||||
|
if not self.production_order and not to_warehouse:
|
||||||
|
# in case of BOM
|
||||||
|
to_warehouse = item.default_warehouse
|
||||||
|
|
||||||
self.add_to_stock_entry_detail({
|
self.add_to_stock_entry_detail({
|
||||||
item.name: {
|
item.name: {
|
||||||
@@ -600,57 +604,57 @@ class StockEntry(StockController):
|
|||||||
from erpnext.manufacturing.doctype.bom.bom import get_bom_items_as_dict
|
from erpnext.manufacturing.doctype.bom.bom import get_bom_items_as_dict
|
||||||
|
|
||||||
# item dict = { item_code: {qty, description, stock_uom} }
|
# item dict = { item_code: {qty, description, stock_uom} }
|
||||||
item_dict = get_bom_items_as_dict(self.bom_no, self.company, qty=qty,
|
item_dict = get_bom_items_as_dict(self.bom_no, self.company, qty=qty,
|
||||||
fetch_exploded = self.use_multi_level_bom)
|
fetch_exploded = self.use_multi_level_bom)
|
||||||
|
|
||||||
for item in item_dict.values():
|
for item in item_dict.values():
|
||||||
item.from_warehouse = self.from_warehouse or item.default_warehouse
|
item.from_warehouse = self.from_warehouse or item.default_warehouse
|
||||||
return item_dict
|
return item_dict
|
||||||
|
|
||||||
def get_transfered_raw_materials(self):
|
def get_transfered_raw_materials(self):
|
||||||
transferred_materials = frappe.db.sql("""
|
transferred_materials = frappe.db.sql("""
|
||||||
select
|
select
|
||||||
item_name, item_code, sum(qty) as qty, sed.t_warehouse as warehouse,
|
item_name, item_code, sum(qty) as qty, sed.t_warehouse as warehouse,
|
||||||
description, stock_uom, expense_account, cost_center
|
description, stock_uom, expense_account, cost_center
|
||||||
from `tabStock Entry` se,`tabStock Entry Detail` sed
|
from `tabStock Entry` se,`tabStock Entry Detail` sed
|
||||||
where
|
where
|
||||||
se.name = sed.parent and se.docstatus=1 and se.purpose='Material Transfer for Manufacture'
|
se.name = sed.parent and se.docstatus=1 and se.purpose='Material Transfer for Manufacture'
|
||||||
and se.production_order= %s and ifnull(sed.t_warehouse, '') != ''
|
and se.production_order= %s and ifnull(sed.t_warehouse, '') != ''
|
||||||
group by sed.item_code, sed.t_warehouse
|
group by sed.item_code, sed.t_warehouse
|
||||||
""", self.production_order, as_dict=1)
|
""", self.production_order, as_dict=1)
|
||||||
|
|
||||||
materials_already_backflushed = frappe.db.sql("""
|
materials_already_backflushed = frappe.db.sql("""
|
||||||
select
|
select
|
||||||
item_code, sed.s_warehouse as warehouse, sum(qty) as qty
|
item_code, sed.s_warehouse as warehouse, sum(qty) as qty
|
||||||
from
|
from
|
||||||
`tabStock Entry` se, `tabStock Entry Detail` sed
|
`tabStock Entry` se, `tabStock Entry Detail` sed
|
||||||
where
|
where
|
||||||
se.name = sed.parent and se.docstatus=1 and se.purpose='Manufacture'
|
se.name = sed.parent and se.docstatus=1 and se.purpose='Manufacture'
|
||||||
and se.production_order= %s and ifnull(sed.s_warehouse, '') != ''
|
and se.production_order= %s and ifnull(sed.s_warehouse, '') != ''
|
||||||
group by sed.item_code, sed.s_warehouse
|
group by sed.item_code, sed.s_warehouse
|
||||||
""", self.production_order, as_dict=1)
|
""", self.production_order, as_dict=1)
|
||||||
|
|
||||||
backflushed_materials= {}
|
backflushed_materials= {}
|
||||||
for d in materials_already_backflushed:
|
for d in materials_already_backflushed:
|
||||||
backflushed_materials.setdefault(d.item_code,[]).append({d.warehouse: d.qty})
|
backflushed_materials.setdefault(d.item_code,[]).append({d.warehouse: d.qty})
|
||||||
|
|
||||||
po_qty = frappe.db.sql("""select qty, produced_qty, material_transferred_for_manufacturing from
|
po_qty = frappe.db.sql("""select qty, produced_qty, material_transferred_for_manufacturing from
|
||||||
`tabProduction Order` where name=%s""", self.production_order, as_dict=1)[0]
|
`tabProduction Order` where name=%s""", self.production_order, as_dict=1)[0]
|
||||||
manufacturing_qty = flt(po_qty.qty)
|
manufacturing_qty = flt(po_qty.qty)
|
||||||
produced_qty = flt(po_qty.produced_qty)
|
produced_qty = flt(po_qty.produced_qty)
|
||||||
trans_qty = flt(po_qty.material_transferred_for_manufacturing)
|
trans_qty = flt(po_qty.material_transferred_for_manufacturing)
|
||||||
|
|
||||||
for item in transferred_materials:
|
for item in transferred_materials:
|
||||||
qty= item.qty
|
qty= item.qty
|
||||||
|
|
||||||
if manufacturing_qty > (produced_qty + flt(self.fg_completed_qty)):
|
if manufacturing_qty > (produced_qty + flt(self.fg_completed_qty)):
|
||||||
qty = (qty/trans_qty) * flt(self.fg_completed_qty)
|
qty = (qty/trans_qty) * flt(self.fg_completed_qty)
|
||||||
|
|
||||||
elif backflushed_materials.get(item.item_code):
|
elif backflushed_materials.get(item.item_code):
|
||||||
for d in backflushed_materials.get(item.item_code):
|
for d in backflushed_materials.get(item.item_code):
|
||||||
if d.get(item.warehouse):
|
if d.get(item.warehouse):
|
||||||
qty-= d.get(item.warehouse)
|
qty-= d.get(item.warehouse)
|
||||||
|
|
||||||
if qty > 0:
|
if qty > 0:
|
||||||
self.add_to_stock_entry_detail({
|
self.add_to_stock_entry_detail({
|
||||||
item.item_code: {
|
item.item_code: {
|
||||||
@@ -729,7 +733,7 @@ class StockEntry(StockController):
|
|||||||
se_child.s_warehouse = self.from_warehouse
|
se_child.s_warehouse = self.from_warehouse
|
||||||
if se_child.t_warehouse==None:
|
if se_child.t_warehouse==None:
|
||||||
se_child.t_warehouse = self.to_warehouse
|
se_child.t_warehouse = self.to_warehouse
|
||||||
|
|
||||||
# in stock uom
|
# in stock uom
|
||||||
se_child.transfer_qty = flt(item_dict[d]["qty"])
|
se_child.transfer_qty = flt(item_dict[d]["qty"])
|
||||||
se_child.conversion_factor = 1.00
|
se_child.conversion_factor = 1.00
|
||||||
@@ -761,7 +765,7 @@ class StockEntry(StockController):
|
|||||||
def get_production_order_details(production_order):
|
def get_production_order_details(production_order):
|
||||||
production_order = frappe.get_doc("Production Order", production_order)
|
production_order = frappe.get_doc("Production Order", production_order)
|
||||||
pending_qty_to_produce = flt(production_order.qty) - flt(production_order.produced_qty)
|
pending_qty_to_produce = flt(production_order.qty) - flt(production_order.produced_qty)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"from_bom": 1,
|
"from_bom": 1,
|
||||||
"bom_no": production_order.bom_no,
|
"bom_no": production_order.bom_no,
|
||||||
@@ -771,7 +775,7 @@ def get_production_order_details(production_order):
|
|||||||
"fg_completed_qty": pending_qty_to_produce,
|
"fg_completed_qty": pending_qty_to_produce,
|
||||||
"additional_costs": get_additional_costs(production_order, fg_qty=pending_qty_to_produce)
|
"additional_costs": get_additional_costs(production_order, fg_qty=pending_qty_to_produce)
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_additional_costs(production_order=None, bom_no=None, fg_qty=None):
|
def get_additional_costs(production_order=None, bom_no=None, fg_qty=None):
|
||||||
additional_costs = []
|
additional_costs = []
|
||||||
operating_cost_per_unit = get_operating_cost_per_unit(production_order, bom_no)
|
operating_cost_per_unit = get_operating_cost_per_unit(production_order, bom_no)
|
||||||
@@ -780,33 +784,33 @@ def get_additional_costs(production_order=None, bom_no=None, fg_qty=None):
|
|||||||
"description": "Operating Cost as per Production Order / BOM",
|
"description": "Operating Cost as per Production Order / BOM",
|
||||||
"amount": operating_cost_per_unit * flt(fg_qty)
|
"amount": operating_cost_per_unit * flt(fg_qty)
|
||||||
})
|
})
|
||||||
|
|
||||||
if production_order and production_order.additional_operating_cost:
|
if production_order and production_order.additional_operating_cost:
|
||||||
additional_operating_cost_per_unit = \
|
additional_operating_cost_per_unit = \
|
||||||
flt(production_order.additional_operating_cost) / flt(production_order.qty)
|
flt(production_order.additional_operating_cost) / flt(production_order.qty)
|
||||||
|
|
||||||
additional_costs.append({
|
additional_costs.append({
|
||||||
"description": "Additional Operating Cost",
|
"description": "Additional Operating Cost",
|
||||||
"amount": additional_operating_cost_per_unit * flt(fg_qty)
|
"amount": additional_operating_cost_per_unit * flt(fg_qty)
|
||||||
})
|
})
|
||||||
|
|
||||||
return additional_costs
|
return additional_costs
|
||||||
|
|
||||||
def get_operating_cost_per_unit(production_order=None, bom_no=None):
|
def get_operating_cost_per_unit(production_order=None, bom_no=None):
|
||||||
operating_cost_per_unit = 0
|
operating_cost_per_unit = 0
|
||||||
if production_order:
|
if production_order:
|
||||||
if not bom_no:
|
if not bom_no:
|
||||||
bom_no = production_order.bom_no
|
bom_no = production_order.bom_no
|
||||||
|
|
||||||
for d in production_order.get("operations"):
|
for d in production_order.get("operations"):
|
||||||
if flt(d.completed_qty):
|
if flt(d.completed_qty):
|
||||||
operating_cost_per_unit += flt(d.actual_operating_cost) / flt(d.completed_qty)
|
operating_cost_per_unit += flt(d.actual_operating_cost) / flt(d.completed_qty)
|
||||||
else:
|
else:
|
||||||
operating_cost_per_unit += flt(d.planned_operating_cost) / flt(production_order.qty)
|
operating_cost_per_unit += flt(d.planned_operating_cost) / flt(production_order.qty)
|
||||||
|
|
||||||
# Get operating cost from BOM if not found in production_order.
|
# Get operating cost from BOM if not found in production_order.
|
||||||
if not operating_cost_per_unit and bom_no:
|
if not operating_cost_per_unit and bom_no:
|
||||||
bom = frappe.db.get_value("BOM", bom_no, ["operating_cost", "quantity"], as_dict=1)
|
bom = frappe.db.get_value("BOM", bom_no, ["operating_cost", "quantity"], as_dict=1)
|
||||||
operating_cost_per_unit = flt(bom.operating_cost) / flt(bom.quantity)
|
operating_cost_per_unit = flt(bom.operating_cost) / flt(bom.quantity)
|
||||||
|
|
||||||
return operating_cost_per_unit
|
return operating_cost_per_unit
|
||||||
|
|||||||
@@ -27,22 +27,31 @@
|
|||||||
{{ _("Item Code") }}: <span itemprop="productID">{{ name }}</span></p>
|
{{ _("Item Code") }}: <span itemprop="productID">{{ name }}</span></p>
|
||||||
<br>
|
<br>
|
||||||
<div style="min-height: 100px; margin: 10px 0;">
|
<div style="min-height: 100px; margin: 10px 0;">
|
||||||
<div class="item-price-info" style="display: none;">
|
<h4 class="item-price" itemprop="price"></h4>
|
||||||
<h4 class="item-price" itemprop="price"></h4>
|
<div class="item-stock" itemprop="availablity"></div>
|
||||||
<div class="item-stock" itemprop="availablity"></div>
|
<div class="item-cart hide">
|
||||||
<div id="item-add-to-cart">
|
<div id="item-add-to-cart">
|
||||||
<button class="btn btn-primary">
|
<button class="btn btn-primary btn-sm">
|
||||||
<i class="icon-shopping-cart"></i> + {{ _("Add to Cart") }}</button>
|
{{ _("Add to Cart") }}</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="item-update-cart" class="input-group col-md-4" style="display: none;
|
<div id="item-update-cart"
|
||||||
padding-left: 0px; padding-right: 0px;">
|
style="display: none;
|
||||||
<input class="form-control" type="text">
|
padding-left: 0px; padding-right: 0px;
|
||||||
<div class="input-group-btn">
|
padding-top: 10px;">
|
||||||
<button class="btn btn-primary">
|
<div>
|
||||||
<i class="icon-ok"></i></button>
|
<input class="form-control"
|
||||||
</div>
|
type="text" style="max-width: 140px;">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div style="margin-top: 10px;">
|
||||||
|
<button class="btn btn-default btn-sm">
|
||||||
|
{{ _("Update") }}</button>
|
||||||
|
</div>
|
||||||
|
<div style="margin-top: 5px;">
|
||||||
|
<a href="/cart" class="text-muted small">
|
||||||
|
{{ _("View Cart") }}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,19 +1,8 @@
|
|||||||
<div class="web-list-item">
|
<div class="web-list-item">
|
||||||
<a href="/addresses?name={{ doc.name }}" no-pjax>
|
<a href="/addresses?name={{ doc.name }}" no-pjax class="no-decoration">
|
||||||
<div class="row">
|
<h4 class="strong">{{ doc.address_title }}</h4>
|
||||||
<div class="col-sm-4">
|
<p class="text-muted small">
|
||||||
<span class="strong">{{ doc.address_title }}</span>
|
{{ frappe.get_doc(doc).get_display() }}
|
||||||
</div>
|
|
||||||
<div class="col-sm-2">
|
|
||||||
{{ doc.address_type }}
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-4">
|
|
||||||
{{ doc.address_line1 }}<br>
|
|
||||||
{% if doc.address_line2 %}{{ doc.address_line2 }}<br>{% endif %}
|
|
||||||
{{ doc.city }}<br>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-2">
|
|
||||||
{% if doc.state %}{{ doc.state }}, {% endif %}{{ doc.country }}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
25
erpnext/templates/includes/cart.css
Normal file
25
erpnext/templates/includes/cart.css
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
.cart-content {
|
||||||
|
min-height: 400px;
|
||||||
|
margin-top: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-header, .cart-footer {
|
||||||
|
margin-bottom: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-item-header {
|
||||||
|
padding-bottom: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
border-bottom: 1px solid #d1d8dd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tax-grand-total-row {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-top: 30px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-addresses {
|
||||||
|
margin-top: 80px;
|
||||||
|
margin-bottom: 60px;
|
||||||
|
}
|
||||||
@@ -13,126 +13,64 @@ $.extend(shopping_cart, {
|
|||||||
},
|
},
|
||||||
|
|
||||||
bind_events: function() {
|
bind_events: function() {
|
||||||
// bind update button
|
shopping_cart.bind_address_select();
|
||||||
$(document).on("click", ".item-update-cart button", function() {
|
shopping_cart.bind_place_order();
|
||||||
var item_code = $(this).attr("data-item-code");
|
shopping_cart.bind_change_qty();
|
||||||
shopping_cart.update_cart({
|
|
||||||
item_code: item_code,
|
},
|
||||||
qty: $('input[data-item-code="'+item_code+'"]').val(),
|
|
||||||
with_doc: 1,
|
bind_address_select: function() {
|
||||||
btn: this,
|
$(".cart-addresses").find('input[data-address-name]').on("click", function() {
|
||||||
callback: function(r) {
|
if($(this).prop("checked")) {
|
||||||
if(!r.exc) {
|
var me = this;
|
||||||
shopping_cart.render(r.message);
|
|
||||||
var $button = $('button[data-item-code="'+item_code+'"]').addClass("btn-success");
|
return frappe.call({
|
||||||
setTimeout(function() { $button.removeClass("btn-success"); }, 1000);
|
type: "POST",
|
||||||
|
method: "erpnext.shopping_cart.cart.update_cart_address",
|
||||||
|
args: {
|
||||||
|
address_fieldname: $(this).attr("data-fieldname"),
|
||||||
|
address_name: $(this).attr("data-address-name")
|
||||||
|
},
|
||||||
|
callback: function(r) {
|
||||||
|
if(!r.exc) {
|
||||||
|
$(".cart-tax-items").html(r.message.taxes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
});
|
||||||
});
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#cart-add-shipping-address").on("click", function() {
|
},
|
||||||
window.location.href = "addresses";
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#cart-add-billing-address").on("click", function() {
|
|
||||||
window.location.href = "address";
|
|
||||||
});
|
|
||||||
|
|
||||||
|
bind_place_order: function() {
|
||||||
$(".btn-place-order").on("click", function() {
|
$(".btn-place-order").on("click", function() {
|
||||||
shopping_cart.place_order(this);
|
shopping_cart.place_order(this);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function(out) {
|
bind_change_qty: function() {
|
||||||
var doc = out.doc;
|
// bind update button
|
||||||
var addresses = out.addresses;
|
$(".cart-items").on("change", ".cart-qty", function() {
|
||||||
|
var item_code = $(this).attr("data-item-code");
|
||||||
var $cart_items = $("#cart-items").empty();
|
frappe.freeze();
|
||||||
var $cart_taxes = $("#cart-taxes").empty();
|
shopping_cart.update_cart({
|
||||||
var $cart_totals = $("#cart-totals").empty();
|
item_code: item_code,
|
||||||
var $cart_billing_address = $("#cart-billing-address").empty();
|
qty: $(this).val(),
|
||||||
var $cart_shipping_address = $("#cart-shipping-address").empty();
|
with_items: 1,
|
||||||
|
btn: this,
|
||||||
var no_items = $.map(doc.items || [],
|
callback: function(r) {
|
||||||
function(d) { return d.item_code || null;}).length===0;
|
frappe.unfreeze();
|
||||||
if(no_items) {
|
if(!r.exc) {
|
||||||
shopping_cart.show_error("Cart Empty", frappe._("Go ahead and add something to your cart."));
|
$(".cart-items").html(r.message.items);
|
||||||
$("#cart-addresses").toggle(false);
|
$(".cart-tax-items").html(r.message.taxes);
|
||||||
return;
|
}
|
||||||
}
|
$(".tax-grand-total").temp_highlight();
|
||||||
|
},
|
||||||
var shipping_rule_added = false;
|
});
|
||||||
var taxes_exist = false;
|
|
||||||
var shipping_rule_labels = $.map(out.shipping_rules || [], function(rule) { return rule[1]; });
|
|
||||||
|
|
||||||
$.each(doc.items || [], function(i, d) {
|
|
||||||
shopping_cart.render_item_row($cart_items, d);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$.each(doc.taxes || [], function(i, d) {
|
|
||||||
if(out.shipping_rules && out.shipping_rules.length &&
|
|
||||||
shipping_rule_labels.indexOf(d.description)!==-1) {
|
|
||||||
shipping_rule_added = true;
|
|
||||||
shopping_cart.render_tax_row($cart_taxes, d, out.shipping_rules);
|
|
||||||
} else {
|
|
||||||
shopping_cart.render_tax_row($cart_taxes, d);
|
|
||||||
}
|
|
||||||
|
|
||||||
taxes_exist = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
if(out.shipping_rules && out.shipping_rules.length && !shipping_rule_added) {
|
|
||||||
shopping_cart.render_tax_row($cart_taxes, {description: "", formatted_tax_amount: ""},
|
|
||||||
out.shipping_rules);
|
|
||||||
taxes_exist = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(taxes_exist)
|
|
||||||
$('<hr>').appendTo($cart_taxes);
|
|
||||||
|
|
||||||
shopping_cart.render_tax_row($cart_totals, {
|
|
||||||
description: "<strong>Total</strong>",
|
|
||||||
formatted_tax_amount: "<strong>" + doc.formatted_grand_total_export + "</strong>"
|
|
||||||
});
|
|
||||||
|
|
||||||
if(!(addresses && addresses.length)) {
|
|
||||||
$cart_shipping_address.html('<div class="msg-box">'+frappe._("Hey! Go ahead and add an address")+'</div>');
|
|
||||||
} else {
|
|
||||||
shopping_cart.render_address($cart_shipping_address, addresses, doc.shipping_address_name);
|
|
||||||
shopping_cart.render_address($cart_billing_address, addresses, doc.customer_address);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
render_item_row: function($cart_items, doc) {
|
|
||||||
doc.image_html = doc.website_image ?
|
|
||||||
'<div style="height: 120px; overflow: hidden;"><img src="' + doc.website_image + '" /></div>': "";
|
|
||||||
|
|
||||||
if(doc.description === doc.item_name) doc.description = "";
|
|
||||||
|
|
||||||
$(repl('<div class="row">\
|
|
||||||
<div class="col-md-9 col-sm-9">\
|
|
||||||
<div class="row">\
|
|
||||||
<div class="col-md-3">%(image_html)s</div>\
|
|
||||||
<div class="col-md-9">\
|
|
||||||
<h4><a href="%(page_name)s">%(item_name)s</a></h4>\
|
|
||||||
<p>%(description)s</p>\
|
|
||||||
</div>\
|
|
||||||
</div>\
|
|
||||||
</div>\
|
|
||||||
<div class="col-md-3 col-sm-3 text-right">\
|
|
||||||
<div class="input-group item-update-cart">\
|
|
||||||
<input type="text" placeholder="Qty" value="%(qty)s" \
|
|
||||||
data-item-code="%(item_code)s" class="text-right form-control">\
|
|
||||||
<div class="input-group-btn">\
|
|
||||||
<button class="btn btn-primary" data-item-code="%(item_code)s">\
|
|
||||||
<i class="icon-ok"></i></button>\
|
|
||||||
</div>\
|
|
||||||
</div>\
|
|
||||||
<p style="margin-top: 10px;">at %(formatted_rate)s</p>\
|
|
||||||
<small class="text-muted" style="margin-top: 10px;">= %(formatted_amount)s</small>\
|
|
||||||
</div>\
|
|
||||||
</div><hr>', doc)).appendTo($cart_items);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
render_tax_row: function($cart_taxes, doc, shipping_rules) {
|
render_tax_row: function($cart_taxes, doc, shipping_rules) {
|
||||||
@@ -182,72 +120,6 @@ $.extend(shopping_cart, {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
render_address: function($address_wrapper, addresses, address_name) {
|
|
||||||
$.each(addresses, function(i, address) {
|
|
||||||
$(repl('<div class="panel panel-default"> \
|
|
||||||
<div class="panel-heading"> \
|
|
||||||
<div class="row"> \
|
|
||||||
<div class="col-md-10 address-title" \
|
|
||||||
data-address-name="%(name)s"><strong>%(name)s</strong></div> \
|
|
||||||
<div class="col-md-2"><input type="checkbox" \
|
|
||||||
data-address-name="%(name)s"></div> \
|
|
||||||
</div> \
|
|
||||||
</div> \
|
|
||||||
<div class="panel-collapse collapse" data-address-name="%(name)s"> \
|
|
||||||
<div class="panel-body">%(display)s</div> \
|
|
||||||
</div> \
|
|
||||||
</div>', address))
|
|
||||||
.css({"margin": "10px auto"})
|
|
||||||
.appendTo($address_wrapper);
|
|
||||||
});
|
|
||||||
|
|
||||||
$address_wrapper.find(".panel-heading")
|
|
||||||
.find(".address-title")
|
|
||||||
.css({"cursor": "pointer"})
|
|
||||||
.on("click", function() {
|
|
||||||
$address_wrapper.find('.panel-collapse[data-address-name="'
|
|
||||||
+$(this).attr("data-address-name")+'"]').collapse("toggle");
|
|
||||||
});
|
|
||||||
|
|
||||||
$address_wrapper.find('input[type="checkbox"]').on("click", function() {
|
|
||||||
if($(this).prop("checked")) {
|
|
||||||
var me = this;
|
|
||||||
$address_wrapper.find('input[type="checkbox"]').each(function(i, chk) {
|
|
||||||
if($(chk).attr("data-address-name")!=$(me).attr("data-address-name")) {
|
|
||||||
$(chk).prop("checked", false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return frappe.call({
|
|
||||||
type: "POST",
|
|
||||||
method: "erpnext.shopping_cart.cart.update_cart_address",
|
|
||||||
args: {
|
|
||||||
address_fieldname: $address_wrapper.attr("data-fieldname"),
|
|
||||||
address_name: $(this).attr("data-address-name")
|
|
||||||
},
|
|
||||||
callback: function(r) {
|
|
||||||
if(!r.exc) {
|
|
||||||
shopping_cart.render(r.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$address_wrapper.find('input[type="checkbox"][data-address-name="'+ address_name +'"]')
|
|
||||||
.prop("checked", true);
|
|
||||||
|
|
||||||
$address_wrapper.find(".panel-collapse").collapse({
|
|
||||||
parent: $address_wrapper,
|
|
||||||
toggle: false
|
|
||||||
});
|
|
||||||
|
|
||||||
$address_wrapper.find('.panel-collapse[data-address-name="'+ address_name +'"]')
|
|
||||||
.collapse("show");
|
|
||||||
},
|
|
||||||
|
|
||||||
place_order: function(btn) {
|
place_order: function(btn) {
|
||||||
return frappe.call({
|
return frappe.call({
|
||||||
type: "POST",
|
type: "POST",
|
||||||
@@ -274,24 +146,4 @@ $.extend(shopping_cart, {
|
|||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
shopping_cart.bind_events();
|
shopping_cart.bind_events();
|
||||||
return frappe.call({
|
|
||||||
type: "POST",
|
|
||||||
method: "erpnext.shopping_cart.cart.get_cart_quotation",
|
|
||||||
callback: function(r) {
|
|
||||||
$("#cart-container").removeClass("hide");
|
|
||||||
$(".progress").remove();
|
|
||||||
if(r.exc) {
|
|
||||||
if(r.exc.indexOf("WebsitePriceListMissingError")!==-1) {
|
|
||||||
shopping_cart.show_error("Configuration Error", frappe._("Price List not configured."));
|
|
||||||
} else if(r["403"]) {
|
|
||||||
shopping_cart.show_error("Not Allowed", frappe._("You need to be logged in to view your cart."));
|
|
||||||
} else {
|
|
||||||
shopping_cart.show_error("Error", frappe._("Something went wrong."));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
shopping_cart.set_cart_count();
|
|
||||||
shopping_cart.render(r.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
24
erpnext/templates/includes/cart/cart_address.html
Normal file
24
erpnext/templates/includes/cart/cart_address.html
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{% from "erpnext/templates/includes/cart/cart_macros.html"
|
||||||
|
import show_address %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<h4>{{ _("Shipping Address") }}</h4>
|
||||||
|
<div id="cart-shipping-address" class="panel-group"
|
||||||
|
data-fieldname="shipping_address_name">
|
||||||
|
{% for address in addresses %}
|
||||||
|
{{ show_address(address, doc, "shipping_address_name") }}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<a class="btn btn-default btn-sm" href="/addresses">
|
||||||
|
{{ _("Manage Addresses") }}</a>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<h4>Billing Address</h4>
|
||||||
|
<div id="cart-billing-address" class="panel-group"
|
||||||
|
data-fieldname="customer_address">
|
||||||
|
{% for address in addresses %}
|
||||||
|
{{ show_address(address, doc, "customer_address") }}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
23
erpnext/templates/includes/cart/cart_items.html
Normal file
23
erpnext/templates/includes/cart/cart_items.html
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{% from "erpnext/templates/includes/order/order_macros.html" import item_name_and_description %}
|
||||||
|
|
||||||
|
{% for d in doc.items %}
|
||||||
|
<div class="cart-item">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-8 col-xs-6" style="margin-bottom: 10px;">
|
||||||
|
{{ item_name_and_description(d) }}
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-2 col-xs-3 text-right">
|
||||||
|
<span style="max-width: 50px; display: inline-block">
|
||||||
|
<input class="form-control text-right cart-qty"
|
||||||
|
value = "{{ d.get_formatted('qty') }}"
|
||||||
|
data-item-code="{{ d.item_code }}"></span>
|
||||||
|
<p class="text-muted small" style="margin-top: 10px;">
|
||||||
|
{{ _("Rate") + ': ' + d.get_formatted("rate") }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-2 col-xs-3 text-right">
|
||||||
|
{{ d.get_formatted("amount") }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
21
erpnext/templates/includes/cart/cart_macros.html
Normal file
21
erpnext/templates/includes/cart/cart_macros.html
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{% macro show_address(address, doc, fieldname) %}
|
||||||
|
{% set selected=address.name==doc.get(fieldname) %}
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-10 address-title"
|
||||||
|
data-address-name="{{ address.name }}">
|
||||||
|
<strong>{{ address.name }}</strong></div>
|
||||||
|
<div class="col-sm-2 text-right">
|
||||||
|
<input type="checkbox"
|
||||||
|
data-fieldname="{{ fieldname }}"
|
||||||
|
data-address-name="{{ address.name}}"
|
||||||
|
{{ "checked" if selected else "" }}></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel-collapse"
|
||||||
|
data-address-name="{{ address.name }}">
|
||||||
|
<div class="panel-body text-muted small">{{ address.display }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endmacro %}
|
||||||
@@ -1,21 +1,15 @@
|
|||||||
<div class="web-list-item">
|
<div class="web-list-item">
|
||||||
|
<a class="no-decoration" href="/issues?name={{ doc.name }}" no-pjax>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-6">
|
<div class="col-xs-8">
|
||||||
<a class="no-decoration" href="/issues?name={{ doc.name }}" no-pjax>
|
<span class="indicator {{ "red" if doc.status=="Open" else "darkgrey" }}">
|
||||||
{{ doc.subject }}
|
{{ doc.name }}</span>
|
||||||
</a>
|
<span style="margin-left: 15px;">
|
||||||
|
{{ doc.subject }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-2">
|
<div class="col-xs-4 text-right small text-muted">
|
||||||
<span class="indicator {{ "red" if doc.status=="Open" else "blue" }}">
|
{{ frappe.format_date(doc.modified) }}
|
||||||
{{ doc.status }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-2">
|
|
||||||
<a class="text-muted text-right" href="/issues?name={{ doc.name }}" no-pjax>
|
|
||||||
{{ doc.name }}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-2 text-muted text-right small">
|
|
||||||
{{ frappe.format_date(doc.creation) }}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,11 +6,12 @@
|
|||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro product_image(website_image, css_class="") %}
|
{% macro product_image(website_image, css_class="") %}
|
||||||
<div class="product-image {% if not website_image -%} missing-image {%- endif %} {{ css_class }}">
|
<div class="product-image {% if not website_image -%} missing-image {%- endif %} {{ css_class }}">
|
||||||
{% if website_image -%}
|
{% if website_image -%}
|
||||||
<img src="{{ frappe.utils.quoted(website_image) | abs_url }}" class="img-responsive">
|
<img src="{{ frappe.utils.quoted(website_image) | abs_url }}" class="img-responsive">
|
||||||
{%- else -%}
|
{%- else -%}
|
||||||
<i class="centered octicon octicon-device-camera"></i>
|
<i class="centered octicon octicon-device-camera"></i>
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
|||||||
25
erpnext/templates/includes/order/order.css
Normal file
25
erpnext/templates/includes/order/order.css
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
.order-container {
|
||||||
|
margin: 50px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-items {
|
||||||
|
margin: 20px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-item-table {
|
||||||
|
margin: 0px -15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-item-header {
|
||||||
|
border-bottom: 1px solid #d1d8dd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-image-col {
|
||||||
|
padding-right: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-image {
|
||||||
|
max-width: 55px;
|
||||||
|
max-height: 55px;
|
||||||
|
margin-top: -5px;
|
||||||
|
}
|
||||||
15
erpnext/templates/includes/order/order_macros.html
Normal file
15
erpnext/templates/includes/order/order_macros.html
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{% from "erpnext/templates/includes/macros.html" import product_image_square %}
|
||||||
|
|
||||||
|
{% macro item_name_and_description(d) %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-4 col-sm-2 order-image-col">
|
||||||
|
<div class="order-image">
|
||||||
|
{{ product_image_square(d.image) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-8 col-sm-10">
|
||||||
|
{{ d.item_code }}
|
||||||
|
<p class="text-muted small">{{ d.description }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endmacro %}
|
||||||
22
erpnext/templates/includes/order/order_taxes.html
Normal file
22
erpnext/templates/includes/order/order_taxes.html
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{% if doc.taxes %}
|
||||||
|
<div class="row tax-net-total-row">
|
||||||
|
<div class="col-xs-6 text-right">{{ _("Net Total") }}</div>
|
||||||
|
<div class="col-xs-6 text-right">
|
||||||
|
{{ doc.get_formatted("net_total") }}</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% for d in doc.taxes %}
|
||||||
|
<div class="row tax-row">
|
||||||
|
<div class="col-xs-6 text-right">{{ d.description }}</div>
|
||||||
|
<div class="col-xs-6 text-right">
|
||||||
|
{{ d.get_formatted("base_tax_amount") }}</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
<div class="row tax-grand-total-row">
|
||||||
|
<div class="col-xs-6 text-right">{{ _("Grand Total") }}</div>
|
||||||
|
<div class="col-xs-6 text-right">
|
||||||
|
<span class="tax-grand-total">
|
||||||
|
{{ doc.get_formatted("grand_total") }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
// License: GNU General Public License v3. See license.txt
|
// License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
$(document).ready(function() {
|
frappe.ready(function() {
|
||||||
var item_code = $('[itemscope] [itemprop="productID"]').text().trim();
|
var item_code = $('[itemscope] [itemprop="productID"]').text().trim();
|
||||||
var qty = 0;
|
var qty = 0;
|
||||||
|
|
||||||
frappe.call({
|
frappe.call({
|
||||||
type: "POST",
|
type: "POST",
|
||||||
method: "erpnext.shopping_cart.product.get_product_info",
|
method: "erpnext.shopping_cart.product.get_product_info",
|
||||||
@@ -12,10 +12,12 @@ $(document).ready(function() {
|
|||||||
item_code: "{{ name }}"
|
item_code: "{{ name }}"
|
||||||
},
|
},
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
|
console.log(r.message);
|
||||||
|
$(".item-cart").toggleClass("hide", !!!r.message.price);
|
||||||
if(r.message && r.message.price) {
|
if(r.message && r.message.price) {
|
||||||
$(".item-price")
|
$(".item-price")
|
||||||
.html(r.message.price.formatted_price + " per " + r.message.uom);
|
.html(r.message.price.formatted_price + " per " + r.message.uom);
|
||||||
|
|
||||||
if(r.message.stock==0) {
|
if(r.message.stock==0) {
|
||||||
$(".item-stock").html("<div class='help'>Not in stock</div>");
|
$(".item-stock").html("<div class='help'>Not in stock</div>");
|
||||||
}
|
}
|
||||||
@@ -23,18 +25,17 @@ $(document).ready(function() {
|
|||||||
$(".item-stock").html("<div style='color: green'>\
|
$(".item-stock").html("<div style='color: green'>\
|
||||||
<i class='icon-check'></i> Available (in stock)</div>");
|
<i class='icon-check'></i> Available (in stock)</div>");
|
||||||
}
|
}
|
||||||
|
|
||||||
$(".item-price-info").toggle(true);
|
|
||||||
|
|
||||||
if(r.message.qty) {
|
if(r.message.qty) {
|
||||||
qty = r.message.qty;
|
qty = r.message.qty;
|
||||||
toggle_update_cart(qty);
|
toggle_update_cart(r.message.qty);
|
||||||
$("#item-update-cart input").val(qty);
|
} else {
|
||||||
|
toggle_update_cart(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
$("#item-add-to-cart button").on("click", function() {
|
$("#item-add-to-cart button").on("click", function() {
|
||||||
shopping_cart.update_cart({
|
shopping_cart.update_cart({
|
||||||
item_code: item_code,
|
item_code: item_code,
|
||||||
@@ -45,10 +46,10 @@ $(document).ready(function() {
|
|||||||
qty = 1;
|
qty = 1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
btn: this,
|
btn: this,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#item-update-cart button").on("click", function() {
|
$("#item-update-cart button").on("click", function() {
|
||||||
shopping_cart.update_cart({
|
shopping_cart.update_cart({
|
||||||
item_code: item_code,
|
item_code: item_code,
|
||||||
@@ -63,7 +64,7 @@ $(document).ready(function() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
if(localStorage && localStorage.getItem("pending_add_to_cart") && full_name) {
|
if(localStorage && localStorage.getItem("pending_add_to_cart") && full_name) {
|
||||||
localStorage.removeItem("pending_add_to_cart");
|
localStorage.removeItem("pending_add_to_cart");
|
||||||
$("#item-add-to-cart button").trigger("click");
|
$("#item-add-to-cart button").trigger("click");
|
||||||
@@ -75,4 +76,4 @@ var toggle_update_cart = function(qty) {
|
|||||||
$("#item-update-cart")
|
$("#item-update-cart")
|
||||||
.toggle(qty ? true : false)
|
.toggle(qty ? true : false)
|
||||||
.find("input").val(qty);
|
.find("input").val(qty);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +1,22 @@
|
|||||||
{% set doc = frappe.get_doc(doc) %}
|
|
||||||
<div class="web-list-item">
|
<div class="web-list-item">
|
||||||
<a href="/{{ pathname }}/{{ doc.name }}" no-pjax>
|
<a href="/{{ pathname }}/{{ doc.name }}" no-pjax>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-6 col-xs-7">
|
<div class="col-sm-8 col-xs-7">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-9">{{ doc.customer or doc.supplier }}</div>
|
<div class="col-sm-9">
|
||||||
|
<div>{{ doc.name }}</div>
|
||||||
|
<div class="small text-muted">{{ doc.items_preview }}</div>
|
||||||
|
</div>
|
||||||
<div class="col-sm-3">
|
<div class="col-sm-3">
|
||||||
{%- if doc.status_percent > 0 -%}
|
<span class="indicator {{ doc.indicator_color or "darkgrey" }}">
|
||||||
{%- if doc.status_percent % 100 == 0 -%}
|
{{ doc.indicator_title or doc.status or "Submitted" }}
|
||||||
<span class="indicator green">{{ doc.status_display }}</span>
|
</span>
|
||||||
{%- else -%}
|
|
||||||
<span class="indicator orange">{{ doc.status_display }}</span>
|
|
||||||
{%- endif -%}
|
|
||||||
{%- elif doc.status -%}
|
|
||||||
<span class="indicator blue">{{ doc.status }}</span>
|
|
||||||
{%- endif -%}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-2 col-xs-5 text-right">
|
<div class="col-sm-2 col-xs-5 text-right">
|
||||||
{{ doc.get_formatted("grand_total") }}
|
{{ doc.get_formatted("grand_total") }}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-2 text-muted text-right">
|
|
||||||
{{ doc.name }}
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-2 small text-muted text-right" title="{{ frappe.utils.format_datetime(doc.creation, "medium") }}">
|
<div class="col-sm-2 small text-muted text-right" title="{{ frappe.utils.format_datetime(doc.creation, "medium") }}">
|
||||||
{{ frappe.utils.pretty_date(doc.creation) }}</div>
|
{{ frappe.utils.pretty_date(doc.creation) }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,53 +3,63 @@
|
|||||||
{% block header %}<h2>{{ _("My Cart") }}</h2>{% endblock %}
|
{% block header %}<h2>{{ _("My Cart") }}</h2>{% endblock %}
|
||||||
|
|
||||||
{% block script %}{% include "templates/includes/cart.js" %}{% endblock %}
|
{% block script %}{% include "templates/includes/cart.js" %}{% endblock %}
|
||||||
|
{% block style %}{% include "templates/includes/cart.css" %}{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block header_actions %}
|
||||||
|
{% if doc.items %}
|
||||||
|
<button class="btn btn-primary btn-place-order btn-sm"
|
||||||
|
type="button">
|
||||||
|
{{ _("Place Order") }}</button>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
|
{% from "templates/includes/macros.html" import item_name_and_description %}
|
||||||
|
|
||||||
<div class="cart-content">
|
<div class="cart-content">
|
||||||
<div class="text-muted progress">{{ _("Loading") }}...</div>
|
<div id="cart-container">
|
||||||
<div id="cart-container" class="hide">
|
<div id="cart-error" class="alert alert-danger"
|
||||||
<p class="pull-right"><button class="btn btn-success btn-place-order" type="button">
|
style="display: none;"></div>
|
||||||
{{ _("Place Order") }}</button></p>
|
<div id="cart-items">
|
||||||
<div class="clearfix"></div>
|
<div class="row cart-item-header">
|
||||||
<div id="cart-error" class="alert alert-danger" style="display: none;"></div>
|
<div class="col-sm-8 col-xs-6">
|
||||||
<hr>
|
Items
|
||||||
<div class="row">
|
</div>
|
||||||
<div class="col-md-9 col-sm-9">
|
<div class="col-sm-2 col-xs-3 text-right">
|
||||||
<div class="row">
|
Qty
|
||||||
<div class="col-md-9 col-md-offset-3"><h4>{{ _("Item Details") }}</h4></div>
|
</div>
|
||||||
</div>
|
<div class="col-sm-2 col-xs-3 text-right">
|
||||||
</div>
|
Amount
|
||||||
<div class="col-md-3 col-sm-3 text-right"><h4>{{ _("Qty, Amount") }}</h4></div>
|
</div>
|
||||||
</div><hr>
|
</div>
|
||||||
<div id="cart-items">
|
{% if doc.items %}
|
||||||
</div>
|
<div class="cart-items">
|
||||||
<div id="cart-taxes">
|
{% include "templates/includes/cart/cart_items.html" %}
|
||||||
</div>
|
</div>
|
||||||
<div id="cart-totals">
|
{% else %}
|
||||||
</div>
|
<p>{{ _("Cart is Empty") }}</p>
|
||||||
<hr>
|
{% endif %}
|
||||||
<div id="cart-addresses">
|
</div>
|
||||||
<div class="row">
|
{% if doc.items %}
|
||||||
<div class="col-md-6">
|
<!-- taxes -->
|
||||||
<h4>{{ _("Shipping Address") }}</h4>
|
<div class="cart-taxes row small">
|
||||||
<div id="cart-shipping-address" class="panel-group"
|
<div class="col-sm-8"><!-- empty --></div>
|
||||||
data-fieldname="shipping_address_name"></div>
|
<div class="col-sm-4 cart-tax-items">
|
||||||
<button class="btn btn-default" type="button" id="cart-add-shipping-address">
|
{% include "templates/includes/order/order_taxes.html" %}
|
||||||
<span class="icon icon-list"></span> {{ _("Manage Addresses") }}</button>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div id="cart-totals">
|
||||||
<h4>Billing Address</h4>
|
</div>
|
||||||
<div id="cart-billing-address" class="panel-group"
|
<div class="cart-addresses">
|
||||||
data-fieldname="customer_address"></div>
|
{% include "templates/includes/cart/cart_address.html" %}
|
||||||
<button class="btn btn-default" type="button" id="cart-add-billing-address">
|
</div>
|
||||||
<span class="icon icon-list"></span> {{ _("Manage Addresses") }}</button>
|
<p class="cart-footer text-right">
|
||||||
</div>
|
<button class="btn btn-primary btn-place-order btn-sm" type="button">
|
||||||
</div>
|
{{ _("Place Order") }}</button></p>
|
||||||
<hr>
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<p class="pull-right"><button class="btn btn-success btn-place-order" type="button">
|
|
||||||
{{ _("Place Order") }}</button></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- no-sidebar -->
|
<!-- no-sidebar -->
|
||||||
|
|||||||
@@ -2,7 +2,11 @@
|
|||||||
# License: GNU General Public License v3. See license.txt
|
# License: GNU General Public License v3. See license.txt
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
no_cache = 1
|
no_cache = 1
|
||||||
no_sitemap = 1
|
no_sitemap = 1
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
from erpnext.shopping_cart.cart import get_cart_quotation
|
||||||
|
|
||||||
|
def get_context(context):
|
||||||
|
context.update(get_cart_quotation())
|
||||||
|
|||||||
72
erpnext/templates/pages/order.html
Normal file
72
erpnext/templates/pages/order.html
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
{% block header %}
|
||||||
|
<h1>{{ doc.name }}</h1>
|
||||||
|
<!-- <h6 class="text-muted">{{ doc._title or doc.doctype }}</h6> -->
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block style %}{% include "templates/includes/order/order.css" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
{% from "erpnext/templates/includes/order/order_macros.html" import item_name_and_description %}
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<span class="indicator {{ doc.indicator_color or "darkgrey" }}">
|
||||||
|
{{ doc.indicator_title or doc.status or "Submitted" }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6 text-muted text-right h6">
|
||||||
|
{{ doc.get_formatted("transaction_date") }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if doc._header %}
|
||||||
|
{{ doc._header }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="order-container">
|
||||||
|
|
||||||
|
<!-- items -->
|
||||||
|
<div class="order-item-table">
|
||||||
|
<div class="row order-items order-item-header">
|
||||||
|
<div class="col-sm-8 col-xs-6 h6">
|
||||||
|
{{ _("Item") }}
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-2 col-xs-3 text-right h6">
|
||||||
|
{{ _("Quantity") }}
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-2 col-xs-3 text-right h6">
|
||||||
|
{{ _("Amount") }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% for d in doc.items %}
|
||||||
|
<div class="row order-items">
|
||||||
|
<div class="col-sm-8 col-xs-6">
|
||||||
|
{{ item_name_and_description(d) }}
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-2 col-xs-3 text-right">
|
||||||
|
{{ d.qty }}
|
||||||
|
{% if d.delivered_qty != None %}
|
||||||
|
<p class="text-muted small">{{
|
||||||
|
_("Delivered: {0}").format(d.delivered_qty) }}</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-2 col-xs-3 text-right">
|
||||||
|
{{ d.get_formatted("amount") }}
|
||||||
|
<p class="text-muted small">{{
|
||||||
|
_("Rate: {0}").format(d.get_formatted("rate")) }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- taxes -->
|
||||||
|
<div class="order-taxes row small">
|
||||||
|
<div class="col-sm-8"><!-- empty --></div>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
{% include "erpnext/templates/includes/order/order_taxes.html" %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
18
erpnext/templates/pages/order.py
Normal file
18
erpnext/templates/pages/order.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
from frappe import _
|
||||||
|
|
||||||
|
def get_context(context):
|
||||||
|
context.no_cache = 1
|
||||||
|
context.doc = frappe.get_doc(frappe.form_dict.doctype, frappe.form_dict.name)
|
||||||
|
if hasattr(context.doc, "set_indicator"):
|
||||||
|
context.doc.set_indicator()
|
||||||
|
|
||||||
|
context.parents = frappe.form_dict.parents
|
||||||
|
|
||||||
|
if not context.doc.has_permission("read"):
|
||||||
|
frappe.throw(_("Not Permitted"), frappe.PermissionError)
|
||||||
@@ -5,36 +5,31 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import cstr
|
from frappe.utils import cstr
|
||||||
from erpnext.shopping_cart.cart import get_lead_or_customer
|
from erpnext.shopping_cart.cart import get_customer
|
||||||
|
|
||||||
no_cache = 1
|
no_cache = 1
|
||||||
no_sitemap = 1
|
no_sitemap = 1
|
||||||
|
|
||||||
def get_context(context):
|
def get_context(context):
|
||||||
party = get_lead_or_customer()
|
party = get_customer()
|
||||||
if party.doctype == "Lead":
|
mobile_no, phone = frappe.db.get_value("Contact", {"email_id": frappe.session.user,
|
||||||
mobile_no = party.mobile_no
|
"customer": party.name}, ["mobile_no", "phone"])
|
||||||
phone = party.phone
|
|
||||||
else:
|
|
||||||
mobile_no, phone = frappe.db.get_value("Contact", {"email_id": frappe.session.user,
|
|
||||||
"customer": party.name}, ["mobile_no", "phone"])
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"company_name": cstr(party.customer_name if party.doctype == "Customer" else party.company_name),
|
"company_name": cstr(party.customer_name if party.doctype == "Customer" else party.company_name),
|
||||||
"mobile_no": cstr(mobile_no),
|
"mobile_no": cstr(mobile_no),
|
||||||
"phone": cstr(phone)
|
"phone": cstr(phone)
|
||||||
}
|
}
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def update_user(fullname, password=None, company_name=None, mobile_no=None, phone=None):
|
def update_user(fullname, password=None, company_name=None, mobile_no=None, phone=None):
|
||||||
from erpnext.shopping_cart.cart import update_party
|
from erpnext.shopping_cart.cart import update_party
|
||||||
update_party(fullname, company_name, mobile_no, phone)
|
update_party(fullname, company_name, mobile_no, phone)
|
||||||
|
|
||||||
if not fullname:
|
if not fullname:
|
||||||
return _("Name is required")
|
return _("Name is required")
|
||||||
|
|
||||||
frappe.db.set_value("User", frappe.session.user, "first_name", fullname)
|
frappe.db.set_value("User", frappe.session.user, "first_name", fullname)
|
||||||
frappe.local.cookie_manager.set_cookie("full_name", fullname)
|
frappe.local.cookie_manager.set_cookie("full_name", fullname)
|
||||||
|
|
||||||
return _("Updated")
|
return _("Updated")
|
||||||
|
|
||||||
@@ -70,6 +70,9 @@ class Address(Document):
|
|||||||
(is_address_type, fieldname, "%s", "%s"), (self.get(fieldname), self.name))
|
(is_address_type, fieldname, "%s", "%s"), (self.get(fieldname), self.name))
|
||||||
break
|
break
|
||||||
|
|
||||||
|
def get_display(self):
|
||||||
|
return get_address_display(self.as_dict())
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_address_display(address_dict):
|
def get_address_display(address_dict):
|
||||||
if not address_dict:
|
if not address_dict:
|
||||||
|
|||||||
Reference in New Issue
Block a user