mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-15 11:09:17 +00:00
[website] [minor] moving to framework
This commit is contained in:
207
selling/utils/__init__.py
Normal file
207
selling/utils/__init__.py
Normal file
@@ -0,0 +1,207 @@
|
||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
from webnotes import msgprint, _
|
||||
from webnotes.utils import flt, cint, comma_and
|
||||
import json
|
||||
|
||||
def get_customer_list(doctype, txt, searchfield, start, page_len, filters):
|
||||
if webnotes.conn.get_default("cust_master_name") == "Customer Name":
|
||||
fields = ["name", "customer_group", "territory"]
|
||||
else:
|
||||
fields = ["name", "customer_name", "customer_group", "territory"]
|
||||
|
||||
return webnotes.conn.sql("""select %s from `tabCustomer` where docstatus < 2
|
||||
and (%s like %s or customer_name like %s) order by
|
||||
case when name like %s then 0 else 1 end,
|
||||
case when customer_name like %s then 0 else 1 end,
|
||||
name, customer_name limit %s, %s""" %
|
||||
(", ".join(fields), searchfield, "%s", "%s", "%s", "%s", "%s", "%s"),
|
||||
("%%%s%%" % txt, "%%%s%%" % txt, "%%%s%%" % txt, "%%%s%%" % txt, start, page_len))
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_item_details(args):
|
||||
"""
|
||||
args = {
|
||||
"item_code": "",
|
||||
"warehouse": None,
|
||||
"customer": "",
|
||||
"conversion_rate": 1.0,
|
||||
"selling_price_list": None,
|
||||
"price_list_currency": None,
|
||||
"plc_conversion_rate": 1.0
|
||||
}
|
||||
"""
|
||||
if isinstance(args, basestring):
|
||||
args = json.loads(args)
|
||||
args = webnotes._dict(args)
|
||||
|
||||
if args.barcode:
|
||||
args.item_code = _get_item_code(args.barcode)
|
||||
|
||||
item_bean = webnotes.bean("Item", args.item_code)
|
||||
|
||||
_validate_item_details(args, item_bean.doc)
|
||||
|
||||
meta = webnotes.get_doctype(args.doctype)
|
||||
|
||||
# hack! for Sales Order Item
|
||||
warehouse_fieldname = "warehouse"
|
||||
if meta.get_field("reserved_warehouse", parentfield=args.parentfield):
|
||||
warehouse_fieldname = "reserved_warehouse"
|
||||
|
||||
out = _get_basic_details(args, item_bean, warehouse_fieldname)
|
||||
|
||||
if meta.get_field("currency"):
|
||||
out.base_ref_rate = out.basic_rate = out.ref_rate = out.export_rate = 0.0
|
||||
|
||||
if args.selling_price_list and args.price_list_currency:
|
||||
out.update(_get_price_list_rate(args, item_bean, meta))
|
||||
|
||||
out.update(_get_item_discount(out.item_group, args.customer))
|
||||
|
||||
if out.get(warehouse_fieldname):
|
||||
out.update(get_available_qty(args.item_code, out.get(warehouse_fieldname)))
|
||||
|
||||
out.customer_item_code = _get_customer_item_code(args, item_bean)
|
||||
|
||||
if cint(args.is_pos):
|
||||
pos_settings = get_pos_settings(args.company)
|
||||
if pos_settings:
|
||||
out.update(apply_pos_settings(pos_settings, out))
|
||||
|
||||
if args.doctype in ("Sales Invoice", "Delivery Note"):
|
||||
if item_bean.doc.has_serial_no and not args.serial_no:
|
||||
out.serial_no = _get_serial_nos_by_fifo(args, item_bean)
|
||||
|
||||
return out
|
||||
|
||||
def _get_serial_nos_by_fifo(args, item_bean):
|
||||
return "\n".join(webnotes.conn.sql_list("""select name from `tabSerial No`
|
||||
where item_code=%(item_code)s and warehouse=%(warehouse)s and status='Available'
|
||||
order by timestamp(purchase_date, purchase_time) asc limit %(qty)s""", {
|
||||
"item_code": args.item_code,
|
||||
"warehouse": args.warehouse,
|
||||
"qty": cint(args.qty)
|
||||
}))
|
||||
|
||||
def _get_item_code(barcode):
|
||||
item_code = webnotes.conn.sql_list("""select name from `tabItem` where barcode=%s""", barcode)
|
||||
|
||||
if not item_code:
|
||||
msgprint(_("No Item found with Barcode") + ": %s" % barcode, raise_exception=True)
|
||||
|
||||
elif len(item_code) > 1:
|
||||
msgprint(_("Items") + " %s " % comma_and(item_code) +
|
||||
_("have the same Barcode") + " %s" % barcode, raise_exception=True)
|
||||
|
||||
return item_code[0]
|
||||
|
||||
def _validate_item_details(args, item):
|
||||
from utilities.transaction_base import validate_item_fetch
|
||||
validate_item_fetch(args, item)
|
||||
|
||||
# validate if sales item or service item
|
||||
if args.order_type == "Maintenance":
|
||||
if item.is_service_item != "Yes":
|
||||
msgprint(_("Item") + (" %s: " % item.name) +
|
||||
_("not a service item.") +
|
||||
_("Please select a service item or change the order type to Sales."),
|
||||
raise_exception=True)
|
||||
|
||||
elif item.is_sales_item != "Yes":
|
||||
msgprint(_("Item") + (" %s: " % item.name) + _("not a sales item"),
|
||||
raise_exception=True)
|
||||
|
||||
def _get_basic_details(args, item_bean, warehouse_fieldname):
|
||||
item = item_bean.doc
|
||||
|
||||
out = webnotes._dict({
|
||||
"item_code": item.name,
|
||||
"description": item.description_html or item.description,
|
||||
warehouse_fieldname: item.default_warehouse or args.get(warehouse_fieldname),
|
||||
"income_account": item.default_income_account or args.income_account \
|
||||
or webnotes.conn.get_value("Company", args.company, "default_income_account"),
|
||||
"expense_account": item.purchase_account or args.expense_account \
|
||||
or webnotes.conn.get_value("Company", args.company, "default_expense_account"),
|
||||
"cost_center": item.default_sales_cost_center or args.cost_center,
|
||||
"qty": 1.0,
|
||||
"export_amount": 0.0,
|
||||
"amount": 0.0,
|
||||
"batch_no": None,
|
||||
"item_tax_rate": json.dumps(dict(([d.tax_type, d.tax_rate] for d in
|
||||
item_bean.doclist.get({"parentfield": "item_tax"})))),
|
||||
})
|
||||
|
||||
for fieldname in ("item_name", "item_group", "barcode", "brand", "stock_uom"):
|
||||
out[fieldname] = item.fields.get(fieldname)
|
||||
|
||||
return out
|
||||
|
||||
def _get_price_list_rate(args, item_bean, meta):
|
||||
base_ref_rate = item_bean.doclist.get({
|
||||
"parentfield": "ref_rate_details",
|
||||
"price_list": args.selling_price_list,
|
||||
"ref_currency": args.price_list_currency,
|
||||
"buying_or_selling": "Selling"})
|
||||
|
||||
if not base_ref_rate:
|
||||
return {}
|
||||
|
||||
# found price list rate - now we can validate
|
||||
from utilities.transaction_base import validate_currency
|
||||
validate_currency(args, item_bean.doc, meta)
|
||||
|
||||
return {"ref_rate": flt(base_ref_rate[0].ref_rate) * flt(args.plc_conversion_rate) / flt(args.conversion_rate)}
|
||||
|
||||
def _get_item_discount(item_group, customer):
|
||||
parent_item_groups = [x[0] for x in webnotes.conn.sql("""SELECT parent.name
|
||||
FROM `tabItem Group` AS node, `tabItem Group` AS parent
|
||||
WHERE parent.lft <= node.lft and parent.rgt >= node.rgt and node.name = %s
|
||||
GROUP BY parent.name
|
||||
ORDER BY parent.lft desc""", (item_group,))]
|
||||
|
||||
discount = 0
|
||||
for d in parent_item_groups:
|
||||
res = webnotes.conn.sql("""select discount, name from `tabCustomer Discount`
|
||||
where parent = %s and item_group = %s""", (customer, d))
|
||||
if res:
|
||||
discount = flt(res[0][0])
|
||||
break
|
||||
|
||||
return {"adj_rate": discount}
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_available_qty(item_code, warehouse):
|
||||
return webnotes.conn.get_value("Bin", {"item_code": item_code, "warehouse": warehouse},
|
||||
["projected_qty", "actual_qty"], as_dict=True) or {}
|
||||
|
||||
def _get_customer_item_code(args, item_bean):
|
||||
customer_item_code = item_bean.doclist.get({"parentfield": "item_customer_details",
|
||||
"customer_name": args.customer})
|
||||
|
||||
return customer_item_code and customer_item_code[0].ref_code or None
|
||||
|
||||
def get_pos_settings(company):
|
||||
pos_settings = webnotes.conn.sql("""select * from `tabPOS Setting` where user = %s
|
||||
and company = %s""", (webnotes.session['user'], company), as_dict=1)
|
||||
|
||||
if not pos_settings:
|
||||
pos_settings = webnotes.conn.sql("""select * from `tabPOS Setting`
|
||||
where ifnull(user,'') = '' and company = %s""", company, as_dict=1)
|
||||
|
||||
return pos_settings and pos_settings[0] or None
|
||||
|
||||
def apply_pos_settings(pos_settings, opts):
|
||||
out = {}
|
||||
|
||||
for fieldname in ("income_account", "cost_center", "warehouse", "expense_account"):
|
||||
if not opts.get(fieldname):
|
||||
out[fieldname] = pos_settings.get(fieldname)
|
||||
|
||||
if out.get("warehouse"):
|
||||
out["actual_qty"] = get_available_qty(opts.item_code, out.get("warehouse")).get("actual_qty")
|
||||
|
||||
return out
|
||||
462
selling/utils/cart.py
Normal file
462
selling/utils/cart.py
Normal file
@@ -0,0 +1,462 @@
|
||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
from webnotes import msgprint, _
|
||||
import webnotes.defaults
|
||||
from webnotes.utils import flt, get_fullname, fmt_money, cstr
|
||||
|
||||
class WebsitePriceListMissingError(webnotes.ValidationError): pass
|
||||
|
||||
def set_cart_count(quotation=None):
|
||||
if not quotation:
|
||||
quotation = _get_cart_quotation()
|
||||
webnotes.add_cookies["cart_count"] = cstr(len(quotation.doclist.get(
|
||||
{"parentfield": "quotation_details"})) or "")
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_cart_quotation(doclist=None):
|
||||
party = get_lead_or_customer()
|
||||
|
||||
if not doclist:
|
||||
quotation = _get_cart_quotation(party)
|
||||
doclist = quotation.doclist
|
||||
set_cart_count(quotation)
|
||||
|
||||
return {
|
||||
"doclist": decorate_quotation_doclist(doclist),
|
||||
"addresses": [{"name": address.name, "display": address.display}
|
||||
for address in get_address_docs(party)],
|
||||
"shipping_rules": get_applicable_shipping_rules(party)
|
||||
}
|
||||
|
||||
@webnotes.whitelist()
|
||||
def place_order():
|
||||
quotation = _get_cart_quotation()
|
||||
controller = quotation.make_controller()
|
||||
for fieldname in ["customer_address", "shipping_address_name"]:
|
||||
if not quotation.doc.fields.get(fieldname):
|
||||
msgprint(_("Please select a") + " " + _(controller.meta.get_label(fieldname)), raise_exception=True)
|
||||
|
||||
quotation.ignore_permissions = True
|
||||
quotation.submit()
|
||||
|
||||
from selling.doctype.quotation.quotation import _make_sales_order
|
||||
sales_order = webnotes.bean(_make_sales_order(quotation.doc.name, ignore_permissions=True))
|
||||
sales_order.ignore_permissions = True
|
||||
sales_order.insert()
|
||||
sales_order.submit()
|
||||
webnotes.add_cookies["cart_count"] = ""
|
||||
|
||||
return sales_order.doc.name
|
||||
|
||||
@webnotes.whitelist()
|
||||
def update_cart(item_code, qty, with_doclist=0):
|
||||
quotation = _get_cart_quotation()
|
||||
|
||||
qty = flt(qty)
|
||||
if qty == 0:
|
||||
quotation.set_doclist(quotation.doclist.get({"item_code": ["!=", item_code]}))
|
||||
if not quotation.doclist.get({"parentfield": "quotation_details"}) and \
|
||||
not quotation.doc.fields.get("__islocal"):
|
||||
quotation.__delete = True
|
||||
|
||||
else:
|
||||
quotation_items = quotation.doclist.get({"item_code": item_code})
|
||||
if not quotation_items:
|
||||
quotation.doclist.append({
|
||||
"doctype": "Quotation Item",
|
||||
"parentfield": "quotation_details",
|
||||
"item_code": item_code,
|
||||
"qty": qty
|
||||
})
|
||||
else:
|
||||
quotation_items[0].qty = qty
|
||||
|
||||
apply_cart_settings(quotation=quotation)
|
||||
|
||||
if hasattr(quotation, "__delete"):
|
||||
webnotes.delete_doc("Quotation", quotation.doc.name, ignore_permissions=True)
|
||||
quotation = _get_cart_quotation()
|
||||
else:
|
||||
quotation.ignore_permissions = True
|
||||
quotation.save()
|
||||
|
||||
set_cart_count(quotation)
|
||||
|
||||
if with_doclist:
|
||||
return get_cart_quotation(quotation.doclist)
|
||||
else:
|
||||
return quotation.doc.name
|
||||
|
||||
@webnotes.whitelist()
|
||||
def update_cart_address(address_fieldname, address_name):
|
||||
from utilities.transaction_base import get_address_display
|
||||
|
||||
quotation = _get_cart_quotation()
|
||||
address_display = get_address_display(webnotes.doc("Address", address_name).fields)
|
||||
|
||||
if address_fieldname == "shipping_address_name":
|
||||
quotation.doc.shipping_address_name = address_name
|
||||
quotation.doc.shipping_address = address_display
|
||||
|
||||
if not quotation.doc.customer_address:
|
||||
address_fieldname == "customer_address"
|
||||
|
||||
if address_fieldname == "customer_address":
|
||||
quotation.doc.customer_address = address_name
|
||||
quotation.doc.address_display = address_display
|
||||
|
||||
|
||||
apply_cart_settings(quotation=quotation)
|
||||
|
||||
quotation.ignore_permissions = True
|
||||
quotation.save()
|
||||
|
||||
return get_cart_quotation(quotation.doclist)
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_addresses():
|
||||
return [d.fields for d in get_address_docs()]
|
||||
|
||||
@webnotes.whitelist()
|
||||
def save_address(fields, address_fieldname=None):
|
||||
party = get_lead_or_customer()
|
||||
fields = webnotes.load_json(fields)
|
||||
|
||||
if fields.get("name"):
|
||||
bean = webnotes.bean("Address", fields.get("name"))
|
||||
else:
|
||||
bean = webnotes.bean({"doctype": "Address", "__islocal": 1})
|
||||
|
||||
bean.doc.fields.update(fields)
|
||||
|
||||
party_fieldname = party.doctype.lower()
|
||||
bean.doc.fields.update({
|
||||
party_fieldname: party.name,
|
||||
(party_fieldname + "_name"): party.fields[party_fieldname + "_name"]
|
||||
})
|
||||
bean.ignore_permissions = True
|
||||
bean.save()
|
||||
|
||||
if address_fieldname:
|
||||
update_cart_address(address_fieldname, bean.doc.name)
|
||||
|
||||
return bean.doc.name
|
||||
|
||||
def get_address_docs(party=None):
|
||||
from webnotes.model.doclist import objectify
|
||||
from utilities.transaction_base import get_address_display
|
||||
|
||||
if not party:
|
||||
party = get_lead_or_customer()
|
||||
|
||||
address_docs = objectify(webnotes.conn.sql("""select * from `tabAddress`
|
||||
where `%s`=%s order by name""" % (party.doctype.lower(), "%s"), party.name,
|
||||
as_dict=True, update={"doctype": "Address"}))
|
||||
|
||||
for address in address_docs:
|
||||
address.display = get_address_display(address.fields)
|
||||
address.display = (address.display).replace("\n", "<br>\n")
|
||||
|
||||
return address_docs
|
||||
|
||||
def get_lead_or_customer():
|
||||
customer = webnotes.conn.get_value("Contact", {"email_id": webnotes.session.user}, "customer")
|
||||
if customer:
|
||||
return webnotes.doc("Customer", customer)
|
||||
|
||||
lead = webnotes.conn.get_value("Lead", {"email_id": webnotes.session.user})
|
||||
if lead:
|
||||
return webnotes.doc("Lead", lead)
|
||||
else:
|
||||
lead_bean = webnotes.bean({
|
||||
"doctype": "Lead",
|
||||
"email_id": webnotes.session.user,
|
||||
"lead_name": get_fullname(webnotes.session.user),
|
||||
"territory": guess_territory(),
|
||||
"status": "Open" # TODO: set something better???
|
||||
})
|
||||
|
||||
if webnotes.session.user != "Guest":
|
||||
lead_bean.ignore_permissions = True
|
||||
lead_bean.insert()
|
||||
|
||||
return lead_bean.doc
|
||||
|
||||
def guess_territory():
|
||||
territory = None
|
||||
geoip_country = webnotes.session.get("session_country")
|
||||
if geoip_country:
|
||||
territory = webnotes.conn.get_value("Territory", geoip_country)
|
||||
|
||||
return territory or \
|
||||
webnotes.conn.get_value("Shopping Cart Settings", None, "territory") or \
|
||||
"All Territories"
|
||||
|
||||
def decorate_quotation_doclist(doclist):
|
||||
for d in doclist:
|
||||
if d.item_code:
|
||||
d.fields.update(webnotes.conn.get_value("Item", d.item_code,
|
||||
["website_image", "description", "page_name"], as_dict=True))
|
||||
d.formatted_rate = fmt_money(d.export_rate, currency=doclist[0].currency)
|
||||
d.formatted_amount = fmt_money(d.export_amount, currency=doclist[0].currency)
|
||||
elif d.charge_type:
|
||||
d.formatted_tax_amount = fmt_money(d.tax_amount / doclist[0].conversion_rate,
|
||||
currency=doclist[0].currency)
|
||||
|
||||
doclist[0].formatted_grand_total_export = fmt_money(doclist[0].grand_total_export,
|
||||
currency=doclist[0].currency)
|
||||
|
||||
return [d.fields for d in doclist]
|
||||
|
||||
def _get_cart_quotation(party=None):
|
||||
if not party:
|
||||
party = get_lead_or_customer()
|
||||
|
||||
quotation = webnotes.conn.get_value("Quotation",
|
||||
{party.doctype.lower(): party.name, "order_type": "Shopping Cart", "docstatus": 0})
|
||||
|
||||
if quotation:
|
||||
qbean = webnotes.bean("Quotation", quotation)
|
||||
else:
|
||||
qbean = webnotes.bean({
|
||||
"doctype": "Quotation",
|
||||
"naming_series": webnotes.defaults.get_user_default("shopping_cart_quotation_series") or "QTN-CART-",
|
||||
"quotation_to": party.doctype,
|
||||
"company": webnotes.defaults.get_user_default("company"),
|
||||
"order_type": "Shopping Cart",
|
||||
"status": "Draft",
|
||||
"docstatus": 0,
|
||||
"__islocal": 1,
|
||||
(party.doctype.lower()): party.name
|
||||
})
|
||||
|
||||
if party.doctype == "Customer":
|
||||
qbean.doc.contact_person = webnotes.conn.get_value("Contact", {"email_id": webnotes.session.user,
|
||||
"customer": party.name})
|
||||
qbean.run_method("set_contact_fields")
|
||||
|
||||
qbean.run_method("onload_post_render")
|
||||
apply_cart_settings(party, qbean)
|
||||
|
||||
return qbean
|
||||
|
||||
def update_party(fullname, company_name=None, mobile_no=None, phone=None):
|
||||
party = get_lead_or_customer()
|
||||
|
||||
if party.doctype == "Lead":
|
||||
party.company_name = company_name
|
||||
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 = webnotes.conn.get_value("Contact", {"email_id": webnotes.session.user,
|
||||
"customer": party.name})
|
||||
contact = webnotes.bean("Contact", contact_name)
|
||||
contact.doc.first_name = fullname
|
||||
contact.doc.last_name = None
|
||||
contact.doc.customer_name = party.customer_name
|
||||
contact.doc.mobile_no = mobile_no
|
||||
contact.doc.phone = phone
|
||||
contact.ignore_permissions = True
|
||||
contact.save()
|
||||
|
||||
party_bean = webnotes.bean(party.fields)
|
||||
party_bean.ignore_permissions = True
|
||||
party_bean.save()
|
||||
|
||||
qbean = _get_cart_quotation(party)
|
||||
if not qbean.doc.fields.get("__islocal"):
|
||||
qbean.doc.customer_name = company_name or fullname
|
||||
qbean.run_method("set_contact_fields")
|
||||
qbean.ignore_permissions = True
|
||||
qbean.save()
|
||||
|
||||
def apply_cart_settings(party=None, quotation=None):
|
||||
if not party:
|
||||
party = get_lead_or_customer()
|
||||
if not quotation:
|
||||
quotation = _get_cart_quotation(party)
|
||||
|
||||
cart_settings = webnotes.get_obj("Shopping Cart Settings")
|
||||
|
||||
billing_territory = get_address_territory(quotation.doc.customer_address) or \
|
||||
party.territory
|
||||
|
||||
set_price_list_and_rate(quotation, cart_settings, billing_territory)
|
||||
|
||||
quotation.run_method("calculate_taxes_and_totals")
|
||||
|
||||
set_taxes(quotation, cart_settings, billing_territory)
|
||||
|
||||
_apply_shipping_rule(party, quotation, cart_settings)
|
||||
|
||||
def set_price_list_and_rate(quotation, cart_settings, billing_territory):
|
||||
"""set price list based on billing territory"""
|
||||
quotation.doc.selling_price_list = cart_settings.get_price_list(billing_territory)
|
||||
|
||||
# reset values
|
||||
quotation.doc.price_list_currency = quotation.doc.currency = \
|
||||
quotation.doc.plc_conversion_rate = quotation.doc.conversion_rate = None
|
||||
for item in quotation.doclist.get({"parentfield": "quotation_details"}):
|
||||
item.ref_rate = item.adj_rate = item.export_rate = item.export_amount = None
|
||||
|
||||
# refetch values
|
||||
quotation.run_method("set_price_list_and_item_details")
|
||||
|
||||
# set it in cookies for using in product page
|
||||
webnotes.cookies[b"selling_price_list"] = quotation.doc.selling_price_list
|
||||
|
||||
def set_taxes(quotation, cart_settings, billing_territory):
|
||||
"""set taxes based on billing territory"""
|
||||
quotation.doc.charge = cart_settings.get_tax_master(billing_territory)
|
||||
|
||||
# clear table
|
||||
quotation.set_doclist(quotation.doclist.get({"parentfield": ["!=", "other_charges"]}))
|
||||
|
||||
# append taxes
|
||||
controller = quotation.make_controller()
|
||||
controller.append_taxes_from_master("other_charges", "charge")
|
||||
quotation.set_doclist(controller.doclist)
|
||||
|
||||
@webnotes.whitelist()
|
||||
def apply_shipping_rule(shipping_rule):
|
||||
quotation = _get_cart_quotation()
|
||||
|
||||
quotation.doc.shipping_rule = shipping_rule
|
||||
|
||||
apply_cart_settings(quotation=quotation)
|
||||
|
||||
quotation.ignore_permissions = True
|
||||
quotation.save()
|
||||
|
||||
return get_cart_quotation(quotation.doclist)
|
||||
|
||||
def _apply_shipping_rule(party=None, quotation=None, cart_settings=None):
|
||||
shipping_rules = get_shipping_rules(party, quotation, cart_settings)
|
||||
|
||||
if not shipping_rules:
|
||||
return
|
||||
|
||||
elif quotation.doc.shipping_rule not in shipping_rules:
|
||||
quotation.doc.shipping_rule = shipping_rules[0]
|
||||
|
||||
quotation.run_method("apply_shipping_rule")
|
||||
quotation.run_method("calculate_taxes_and_totals")
|
||||
|
||||
def get_applicable_shipping_rules(party=None, quotation=None):
|
||||
shipping_rules = get_shipping_rules(party, quotation)
|
||||
|
||||
if shipping_rules:
|
||||
rule_label_map = webnotes.conn.get_values("Shipping Rule", shipping_rules, "label")
|
||||
# we need this in sorted order as per the position of the rule in the settings page
|
||||
return [[rule, rule_label_map.get(rule)] for rule in shipping_rules]
|
||||
|
||||
def get_shipping_rules(party=None, quotation=None, cart_settings=None):
|
||||
if not party:
|
||||
party = get_lead_or_customer()
|
||||
if not quotation:
|
||||
quotation = _get_cart_quotation()
|
||||
if not cart_settings:
|
||||
cart_settings = webnotes.get_obj("Shopping Cart Settings")
|
||||
|
||||
# set shipping rule based on shipping territory
|
||||
shipping_territory = get_address_territory(quotation.doc.shipping_address_name) or \
|
||||
party.territory
|
||||
|
||||
shipping_rules = cart_settings.get_shipping_rules(shipping_territory)
|
||||
|
||||
return shipping_rules
|
||||
|
||||
def get_address_territory(address_name):
|
||||
"""Tries to match city, state and country of address to existing territory"""
|
||||
territory = None
|
||||
|
||||
if address_name:
|
||||
address_fields = webnotes.conn.get_value("Address", address_name,
|
||||
["city", "state", "country"])
|
||||
for value in address_fields:
|
||||
territory = webnotes.conn.get_value("Territory", value)
|
||||
if territory:
|
||||
break
|
||||
|
||||
return territory
|
||||
|
||||
import unittest
|
||||
test_dependencies = ["Item", "Price List", "Contact", "Shopping Cart Settings"]
|
||||
|
||||
class TestCart(unittest.TestCase):
|
||||
def tearDown(self):
|
||||
return
|
||||
|
||||
cart_settings = webnotes.bean("Shopping Cart Settings")
|
||||
cart_settings.ignore_permissions = True
|
||||
cart_settings.doc.enabled = 0
|
||||
cart_settings.save()
|
||||
|
||||
def enable_shopping_cart(self):
|
||||
return
|
||||
if not webnotes.conn.get_value("Shopping Cart Settings", None, "enabled"):
|
||||
cart_settings = webnotes.bean("Shopping Cart Settings")
|
||||
cart_settings.ignore_permissions = True
|
||||
cart_settings.doc.enabled = 1
|
||||
cart_settings.save()
|
||||
|
||||
def test_get_lead_or_customer(self):
|
||||
webnotes.session.user = "test@example.com"
|
||||
party1 = get_lead_or_customer()
|
||||
party2 = get_lead_or_customer()
|
||||
self.assertEquals(party1.name, party2.name)
|
||||
self.assertEquals(party1.doctype, "Lead")
|
||||
|
||||
webnotes.session.user = "test_contact_customer@example.com"
|
||||
party = get_lead_or_customer()
|
||||
self.assertEquals(party.name, "_Test Customer")
|
||||
|
||||
def test_add_to_cart(self):
|
||||
self.enable_shopping_cart()
|
||||
webnotes.session.user = "test@example.com"
|
||||
|
||||
update_cart("_Test Item", 1)
|
||||
|
||||
quotation = _get_cart_quotation()
|
||||
quotation_items = quotation.doclist.get({"parentfield": "quotation_details", "item_code": "_Test Item"})
|
||||
self.assertTrue(quotation_items)
|
||||
self.assertEquals(quotation_items[0].qty, 1)
|
||||
|
||||
return quotation
|
||||
|
||||
def test_update_cart(self):
|
||||
self.test_add_to_cart()
|
||||
|
||||
update_cart("_Test Item", 5)
|
||||
|
||||
quotation = _get_cart_quotation()
|
||||
quotation_items = quotation.doclist.get({"parentfield": "quotation_details", "item_code": "_Test Item"})
|
||||
self.assertTrue(quotation_items)
|
||||
self.assertEquals(quotation_items[0].qty, 5)
|
||||
|
||||
return quotation
|
||||
|
||||
def test_remove_from_cart(self):
|
||||
quotation0 = self.test_add_to_cart()
|
||||
|
||||
update_cart("_Test Item", 0)
|
||||
|
||||
quotation = _get_cart_quotation()
|
||||
self.assertEquals(quotation0.doc.name, quotation.doc.name)
|
||||
|
||||
quotation_items = quotation.doclist.get({"parentfield": "quotation_details", "item_code": "_Test Item"})
|
||||
self.assertEquals(quotation_items, [])
|
||||
|
||||
def test_place_order(self):
|
||||
quotation = self.test_update_cart()
|
||||
sales_order_name = place_order()
|
||||
sales_order = webnotes.bean("Sales Order", sales_order_name)
|
||||
self.assertEquals(sales_order.doclist.getone({"item_code": "_Test Item"}).prevdoc_docname, quotation.doc.name)
|
||||
|
||||
32
selling/utils/contact.py
Normal file
32
selling/utils/contact.py
Normal file
@@ -0,0 +1,32 @@
|
||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import webnotes
|
||||
from webnotes.utils import now
|
||||
|
||||
max_communications_per_hour = 300
|
||||
|
||||
@webnotes.whitelist(allow_guest=True)
|
||||
def send_message(subject="Website Query", message="", sender="", status="Open"):
|
||||
if not message:
|
||||
webnotes.response["message"] = 'Please write something'
|
||||
return
|
||||
|
||||
if not sender:
|
||||
webnotes.response["message"] = 'Email Id Required'
|
||||
return
|
||||
|
||||
# make lead / communication
|
||||
from selling.doctype.lead.get_leads import add_sales_communication
|
||||
message = add_sales_communication(subject or "Website Query", message, sender, sender,
|
||||
mail=None, status=status)
|
||||
|
||||
# guest method, cap max writes per hour
|
||||
if webnotes.conn.sql("""select count(*) from `tabCommunication`
|
||||
where TIMEDIFF(%s, modified) < '01:00:00'""", now())[0][0] > max_communications_per_hour:
|
||||
webnotes.response["message"] = "Sorry: we believe we have received an unreasonably high number of requests of this kind. Please try later"
|
||||
return
|
||||
|
||||
webnotes.response.status = "okay"
|
||||
130
selling/utils/product.py
Normal file
130
selling/utils/product.py
Normal file
@@ -0,0 +1,130 @@
|
||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import webnotes
|
||||
from webnotes.utils import cstr, cint, fmt_money
|
||||
from webnotes.webutils import build_html, delete_page_cache
|
||||
from selling.utils.cart import _get_cart_quotation
|
||||
|
||||
@webnotes.whitelist(allow_guest=True)
|
||||
def get_product_info(item_code):
|
||||
"""get product price / stock info"""
|
||||
if not cint(webnotes.conn.get_default("shopping_cart_enabled")):
|
||||
return {}
|
||||
|
||||
cart_quotation = _get_cart_quotation()
|
||||
|
||||
price_list = webnotes.cookies.get("selling_price_list").value
|
||||
|
||||
warehouse = webnotes.conn.get_value("Item", item_code, "website_warehouse")
|
||||
if warehouse:
|
||||
in_stock = webnotes.conn.sql("""select actual_qty from tabBin where
|
||||
item_code=%s and warehouse=%s""", (item_code, warehouse))
|
||||
if in_stock:
|
||||
in_stock = in_stock[0][0] > 0 and 1 or 0
|
||||
else:
|
||||
in_stock = -1
|
||||
|
||||
price = price_list and webnotes.conn.sql("""select ref_rate, ref_currency from
|
||||
`tabItem Price` where parent=%s and price_list=%s""",
|
||||
(item_code, price_list), as_dict=1) or []
|
||||
|
||||
price = price and price[0] or None
|
||||
qty = 0
|
||||
|
||||
if price:
|
||||
price["formatted_price"] = fmt_money(price["ref_rate"], currency=price["ref_currency"])
|
||||
|
||||
price["ref_currency"] = not cint(webnotes.conn.get_default("hide_currency_symbol")) \
|
||||
and (webnotes.conn.get_value("Currency", price.ref_currency, "symbol") or price.ref_currency) \
|
||||
or ""
|
||||
|
||||
if webnotes.session.user != "Guest":
|
||||
item = cart_quotation.doclist.get({"item_code": item_code})
|
||||
if item:
|
||||
qty = item[0].qty
|
||||
|
||||
return {
|
||||
"price": price,
|
||||
"stock": in_stock,
|
||||
"uom": webnotes.conn.get_value("Item", item_code, "stock_uom"),
|
||||
"qty": qty
|
||||
}
|
||||
|
||||
@webnotes.whitelist(allow_guest=True)
|
||||
def get_product_list(search=None, start=0, limit=10):
|
||||
# base query
|
||||
query = """select name, item_name, page_name, website_image, item_group,
|
||||
web_long_description as website_description
|
||||
from `tabItem` where docstatus = 0 and show_in_website = 1 """
|
||||
|
||||
# search term condition
|
||||
if search:
|
||||
query += """and (web_long_description like %(search)s or
|
||||
item_name like %(search)s or name like %(search)s)"""
|
||||
search = "%" + cstr(search) + "%"
|
||||
|
||||
# order by
|
||||
query += """order by weightage desc, modified desc limit %s, %s""" % (start, limit)
|
||||
|
||||
data = webnotes.conn.sql(query, {
|
||||
"search": search,
|
||||
}, as_dict=1)
|
||||
|
||||
return [get_item_for_list_in_html(r) for r in data]
|
||||
|
||||
|
||||
def get_product_list_for_group(product_group=None, start=0, limit=10):
|
||||
child_groups = ", ".join(['"' + i[0] + '"' for i in get_child_groups(product_group)])
|
||||
|
||||
# base query
|
||||
query = """select name, item_name, page_name, website_image, item_group,
|
||||
web_long_description as website_description
|
||||
from `tabItem` where docstatus = 0 and show_in_website = 1
|
||||
and (item_group in (%s)
|
||||
or name in (select parent from `tabWebsite Item Group` where item_group in (%s))) """ % (child_groups, child_groups)
|
||||
|
||||
query += """order by weightage desc, modified desc limit %s, %s""" % (start, limit)
|
||||
|
||||
data = webnotes.conn.sql(query, {"product_group": product_group}, as_dict=1)
|
||||
|
||||
return [get_item_for_list_in_html(r) for r in data]
|
||||
|
||||
def get_child_groups(item_group_name):
|
||||
item_group = webnotes.doc("Item Group", item_group_name)
|
||||
return webnotes.conn.sql("""select name
|
||||
from `tabItem Group` where lft>=%(lft)s and rgt<=%(rgt)s
|
||||
and show_in_website = 1""", item_group.fields)
|
||||
|
||||
def get_group_item_count(item_group):
|
||||
child_groups = ", ".join(['"' + i[0] + '"' for i in get_child_groups(item_group)])
|
||||
return webnotes.conn.sql("""select count(*) from `tabItem`
|
||||
where docstatus = 0 and show_in_website = 1
|
||||
and (item_group in (%s)
|
||||
or name in (select parent from `tabWebsite Item Group`
|
||||
where item_group in (%s))) """ % (child_groups, child_groups))[0][0]
|
||||
|
||||
def get_item_for_list_in_html(r):
|
||||
scrub_item_for_list(r)
|
||||
r.template = "app/website/templates/html/product_in_grid.html"
|
||||
return build_html(r)
|
||||
|
||||
def scrub_item_for_list(r):
|
||||
if not r.website_description:
|
||||
r.website_description = "No description given"
|
||||
if len(r.website_description.split(" ")) > 24:
|
||||
r.website_description = " ".join(r.website_description.split(" ")[:24]) + "..."
|
||||
|
||||
def get_parent_item_groups(item_group_name):
|
||||
item_group = webnotes.doc("Item Group", item_group_name)
|
||||
return webnotes.conn.sql("""select name, page_name from `tabItem Group`
|
||||
where lft <= %s and rgt >= %s
|
||||
and ifnull(show_in_website,0)=1
|
||||
order by lft asc""", (item_group.lft, item_group.rgt), as_dict=True)
|
||||
|
||||
def invalidate_cache_for(item_group):
|
||||
for i in get_parent_item_groups(item_group):
|
||||
if i.page_name:
|
||||
delete_page_cache(i.page_name)
|
||||
Reference in New Issue
Block a user