fixed strings for translation

This commit is contained in:
Rushabh Mehta
2014-04-15 14:36:12 +05:30
parent 5d4ffa6cf8
commit 2c45899a02
20 changed files with 516 additions and 562 deletions

View File

@@ -114,7 +114,7 @@ class JournalVoucher(AccountsController):
if self.cheque_no: if self.cheque_no:
if self.cheque_date: if self.cheque_date:
r.append(_('Reference #{0} dated {1}').format(self.cheque_no, formatdate(self.cheque_date))) r.append(_('Reference #{0} dated {1}').format(self.cheque_no, formatdate(self.cheque_date)))
else : else:
msgprint(_("Please enter Reference date"), raise_exception=1) msgprint(_("Please enter Reference date"), raise_exception=1)
for d in self.get('entries'): for d in self.get('entries'):

View File

@@ -86,9 +86,7 @@ class Customer(TransactionBase):
def validate_name_with_customer_group(self): def validate_name_with_customer_group(self):
if frappe.db.exists("Customer Group", self.name): if frappe.db.exists("Customer Group", self.name):
frappe.msgprint("An Customer Group exists with same name (%s), \ frappe.throw("A Customer Group exists with same name please change the Customer name or rename the Customer Group")
please change the Customer name or rename the Customer Group" %
self.name, raise_exception=1)
def delete_customer_address(self): def delete_customer_address(self):
addresses = frappe.db.sql("""select name, lead from `tabAddress` addresses = frappe.db.sql("""select name, lead from `tabAddress`
@@ -140,7 +138,7 @@ class Customer(TransactionBase):
@frappe.whitelist() @frappe.whitelist()
def get_dashboard_info(customer): def get_dashboard_info(customer):
if not frappe.has_permission("Customer", "read", customer): if not frappe.has_permission("Customer", "read", customer):
frappe.msgprint("No Permission", raise_exception=True) frappe.msgprint(_("Not permitted"), raise_exception=True)
out = {} out = {}
for doctype in ["Opportunity", "Quotation", "Sales Order", "Delivery Note", "Sales Invoice"]: for doctype in ["Opportunity", "Quotation", "Sales Order", "Delivery Note", "Sales Invoice"]:

View File

@@ -4,38 +4,33 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe.utils import add_days, cstr, flt, nowdate, cint, now from frappe.utils import flt, now
from frappe import session, msgprint
from erpnext.stock.utils import get_valid_serial_nos
from frappe.model.document import Document from frappe.model.document import Document
class StockLedger(Document): class StockLedger(Document):
def update_stock(self, values, is_amended = 'No'): def update_stock(self, values, is_amended = 'No'):
for v in values: for v in values:
sle_id = '' sle_id = ''
# reverse quantities for cancel # reverse quantities for cancel
if v.get('is_cancelled') == 'Yes': if v.get('is_cancelled') == 'Yes':
v['actual_qty'] = -flt(v['actual_qty']) v['actual_qty'] = -flt(v['actual_qty'])
# cancel matching entry # cancel matching entry
frappe.db.sql("""update `tabStock Ledger Entry` set is_cancelled='Yes', frappe.db.sql("""update `tabStock Ledger Entry` set is_cancelled='Yes',
modified=%s, modified_by=%s modified=%s, modified_by=%s
where voucher_no=%s and voucher_type=%s""", where voucher_no=%s and voucher_type=%s""",
(now(), frappe.session.user, v['voucher_no'], v['voucher_type'])) (now(), frappe.session.user, v['voucher_no'], v['voucher_type']))
if v.get("actual_qty"): if v.get("actual_qty"):
sle_id = self.make_entry(v) sle_id = self.make_entry(v)
args = v.copy() args = v.copy()
args.update({ args.update({
"sle_id": sle_id, "sle_id": sle_id,
"is_amended": is_amended "is_amended": is_amended
}) })
frappe.get_doc('Warehouse', v["warehouse"]).update_bin(args) frappe.get_doc('Warehouse', v["warehouse"]).update_bin(args)
@@ -45,7 +40,7 @@ class StockLedger(Document):
sle.ignore_permissions = 1 sle.ignore_permissions = 1
sle.insert() sle.insert()
return sle.name return sle.name
def repost(self): def repost(self):
""" """
Repost everything! Repost everything!

View File

@@ -4,15 +4,14 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe import msgprint from frappe import _
from frappe.utils import flt, getdate, add_days from frappe.utils import flt, getdate, add_days, formatdate
from frappe.model.controller import DocListController from frappe.model.controller import DocListController
from datetime import date from datetime import date
class StockFreezeError(frappe.ValidationError): pass class StockFreezeError(frappe.ValidationError): pass
class StockLedgerEntry(DocListController): class StockLedgerEntry(DocListController):
def validate(self): def validate(self):
from erpnext.stock.utils import validate_warehouse_company from erpnext.stock.utils import validate_warehouse_company
self.validate_mandatory() self.validate_mandatory()
@@ -55,11 +54,7 @@ class StockLedgerEntry(DocListController):
mandatory = ['warehouse','posting_date','voucher_type','voucher_no','actual_qty','company'] mandatory = ['warehouse','posting_date','voucher_type','voucher_no','actual_qty','company']
for k in mandatory: for k in mandatory:
if not self.get(k): if not self.get(k):
msgprint("Stock Ledger Entry: '%s' is mandatory" % k, raise_exception = 1) frappe.throw(_("{0} is required").format(k))
elif k == 'warehouse':
if not frappe.db.exists("Warehouse", self.get(k)):
msgprint("Warehouse: '%s' does not exist in the system. Please check." %
self.get(k), raise_exception = 1)
def validate_item(self): def validate_item(self):
item_det = frappe.db.sql("""select name, has_batch_no, docstatus, item_det = frappe.db.sql("""select name, has_batch_no, docstatus,
@@ -89,15 +84,14 @@ class StockLedgerEntry(DocListController):
if stock_frozen_upto: if stock_frozen_upto:
stock_auth_role = frappe.db.get_value('Stock Settings', None,'stock_auth_role') stock_auth_role = frappe.db.get_value('Stock Settings', None,'stock_auth_role')
if getdate(self.posting_date) <= getdate(stock_frozen_upto) and not stock_auth_role in frappe.user.get_roles(): if getdate(self.posting_date) <= getdate(stock_frozen_upto) and not stock_auth_role in frappe.user.get_roles():
msgprint("You are not authorized to do / modify back dated stock entries before %s" % getdate(stock_frozen_upto).strftime('%d-%m-%Y'), raise_exception=StockFreezeError) frappe.throw(_("Entries before {0} are frozen").format(formatdate(stock_frozen_upto)), StockFreezeError)
stock_frozen_upto_days = int(frappe.db.get_value('Stock Settings', None, 'stock_frozen_upto_days') or 0) stock_frozen_upto_days = int(frappe.db.get_value('Stock Settings', None, 'stock_frozen_upto_days') or 0)
if stock_frozen_upto_days: if stock_frozen_upto_days:
stock_auth_role = frappe.db.get_value('Stock Settings', None,'stock_auth_role') stock_auth_role = frappe.db.get_value('Stock Settings', None,'stock_auth_role')
older_than_x_days_ago = (add_days(getdate(self.posting_date), stock_frozen_upto_days) <= date.today()) older_than_x_days_ago = (add_days(getdate(self.posting_date), stock_frozen_upto_days) <= date.today())
if older_than_x_days_ago and not stock_auth_role in frappe.user.get_roles(): if older_than_x_days_ago and not stock_auth_role in frappe.user.get_roles():
msgprint("You are not authorized to do / modify back dated stock entries older than %d days ago" %stock_frozen_upto_days, raise_exception=StockFreezeError) frappe.throw(_("Not allowed to update entries older than {0}").format(stock_frozen_upto_days), StockFreezeError)
def scrub_posting_time(self): def scrub_posting_time(self):
if not self.posting_time or self.posting_time == '00:0': if not self.posting_time or self.posting_time == '00:0':

View File

@@ -4,7 +4,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe.utils import cstr, flt, cint from frappe.utils import cstr, flt, cint
from frappe import msgprint, _ from frappe import _
from frappe.model.document import Document from frappe.model.document import Document
@@ -12,71 +12,66 @@ from frappe.model.document import Document
class StockUOMReplaceUtility(Document): class StockUOMReplaceUtility(Document):
def validate_mandatory(self): def validate_mandatory(self):
if not cstr(self.item_code): if not cstr(self.item_code):
msgprint("Please Enter an Item.") frappe.throw(_("Item is required"))
raise Exception
if not cstr(self.new_stock_uom): if not cstr(self.new_stock_uom):
msgprint("Please Enter New Stock UOM.") frappe.throw(_("New Stock UOM is required"))
raise Exception
if cstr(self.current_stock_uom) == cstr(self.new_stock_uom): if cstr(self.current_stock_uom) == cstr(self.new_stock_uom):
msgprint("Current Stock UOM and Stock UOM are same.") frappe.throw(_("New Stock UOM must be different from current stock UOM"))
raise Exception
# check conversion factor # check conversion factor
if not flt(self.conversion_factor): if not flt(self.conversion_factor):
msgprint("Please Enter Conversion Factor.") frappe.throw(_("Conversion Factor is required"))
raise Exception
stock_uom = frappe.db.get_value("Item", self.item_code, "stock_uom") stock_uom = frappe.db.get_value("Item", self.item_code, "stock_uom")
if cstr(self.new_stock_uom) == cstr(stock_uom): if cstr(self.new_stock_uom) == cstr(stock_uom):
msgprint("Item Master is already updated with New Stock UOM " + cstr(self.new_stock_uom)) frappe.throw(_("Item is updated"))
raise Exception
def update_item_master(self): def update_item_master(self):
item_doc = frappe.get_doc("Item", self.item_code) item_doc = frappe.get_doc("Item", self.item_code)
item_doc.stock_uom = self.new_stock_uom item_doc.stock_uom = self.new_stock_uom
item_doc.save() item_doc.save()
msgprint(_("Default UOM updated in item ") + self.item_code) frappe.msgprint(_("Stock UOM updatd for Item {0}").format(self.item_code))
def update_bin(self): def update_bin(self):
# update bin # update bin
if flt(self.conversion_factor) != flt(1): if flt(self.conversion_factor) != flt(1):
frappe.db.sql("""update `tabBin` frappe.db.sql("""update `tabBin`
set stock_uom = %s, set stock_uom = %s,
indented_qty = ifnull(indented_qty,0) * %s, indented_qty = ifnull(indented_qty,0) * %s,
ordered_qty = ifnull(ordered_qty,0) * %s, ordered_qty = ifnull(ordered_qty,0) * %s,
reserved_qty = ifnull(reserved_qty,0) * %s, reserved_qty = ifnull(reserved_qty,0) * %s,
planned_qty = ifnull(planned_qty,0) * %s, planned_qty = ifnull(planned_qty,0) * %s,
projected_qty = actual_qty + ordered_qty + indented_qty + projected_qty = actual_qty + ordered_qty + indented_qty +
planned_qty - reserved_qty planned_qty - reserved_qty
where item_code = %s""", (self.new_stock_uom, self.conversion_factor, where item_code = %s""", (self.new_stock_uom, self.conversion_factor,
self.conversion_factor, self.conversion_factor, self.conversion_factor, self.conversion_factor,
self.conversion_factor, self.item_code)) self.conversion_factor, self.item_code))
else: else:
frappe.db.sql("update `tabBin` set stock_uom = %s where item_code = %s", frappe.db.sql("update `tabBin` set stock_uom = %s where item_code = %s",
(self.new_stock_uom, self.item_code) ) (self.new_stock_uom, self.item_code) )
# acknowledge user # acknowledge user
msgprint(" All Bins Updated Successfully.") frappe.msgprint(_("Stock balances updated"))
def update_stock_ledger_entry(self): def update_stock_ledger_entry(self):
# update stock ledger entry # update stock ledger entry
from erpnext.stock.stock_ledger import update_entries_after from erpnext.stock.stock_ledger import update_entries_after
if flt(self.conversion_factor) != flt(1): if flt(self.conversion_factor) != flt(1):
frappe.db.sql("""update `tabStock Ledger Entry` frappe.db.sql("""update `tabStock Ledger Entry`
set stock_uom = %s, actual_qty = ifnull(actual_qty,0) * %s set stock_uom = %s, actual_qty = ifnull(actual_qty,0) * %s
where item_code = %s""", where item_code = %s""",
(self.new_stock_uom, self.conversion_factor, self.item_code)) (self.new_stock_uom, self.conversion_factor, self.item_code))
else: else:
frappe.db.sql("""update `tabStock Ledger Entry` set stock_uom=%s frappe.db.sql("""update `tabStock Ledger Entry` set stock_uom=%s
where item_code=%s""", (self.new_stock_uom, self.item_code)) where item_code=%s""", (self.new_stock_uom, self.item_code))
# acknowledge user # acknowledge user
msgprint("Stock Ledger Entries Updated Successfully.") frappe.msgprint(_("Stock Ledger entries balances updated"))
# update item valuation # update item valuation
if flt(self.conversion_factor) != flt(1): if flt(self.conversion_factor) != flt(1):
wh = frappe.db.sql("select name from `tabWarehouse`") wh = frappe.db.sql("select name from `tabWarehouse`")
@@ -84,34 +79,31 @@ class StockUOMReplaceUtility(Document):
update_entries_after({"item_code": self.item_code, "warehouse": w[0]}) update_entries_after({"item_code": self.item_code, "warehouse": w[0]})
# acknowledge user # acknowledge user
msgprint("Item Valuation Updated Successfully.") frappe.msgprint(_("Item valuation updated"))
# Update Stock UOM # Update Stock UOM
def update_stock_uom(self): def update_stock_uom(self):
self.validate_mandatory() self.validate_mandatory()
self.validate_uom_integer_type() self.validate_uom_integer_type()
self.update_stock_ledger_entry() self.update_stock_ledger_entry()
self.update_bin() self.update_bin()
self.update_item_master() self.update_item_master()
def validate_uom_integer_type(self): def validate_uom_integer_type(self):
current_is_integer = frappe.db.get_value("UOM", self.current_stock_uom, "must_be_whole_number") current_is_integer = frappe.db.get_value("UOM", self.current_stock_uom, "must_be_whole_number")
new_is_integer = frappe.db.get_value("UOM", self.new_stock_uom, "must_be_whole_number") new_is_integer = frappe.db.get_value("UOM", self.new_stock_uom, "must_be_whole_number")
if current_is_integer and not new_is_integer:
frappe.msgprint("New UOM must be of type Whole Number", raise_exception=True)
if not current_is_integer and new_is_integer: if not current_is_integer and new_is_integer:
frappe.msgprint("New UOM must NOT be of type Whole Number", raise_exception=True) frappe.throw(_("New UOM must NOT be of type Whole Number"))
if current_is_integer and new_is_integer and cint(self.conversion_factor)!=self.conversion_factor: if current_is_integer and new_is_integer and cint(self.conversion_factor)!=self.conversion_factor:
frappe.msgprint("Conversion Factor cannot be fraction", raise_exception=True) frappe.throw(_("Conversion factor cannot be in fractions"))
@frappe.whitelist() @frappe.whitelist()
def get_stock_uom(item_code): def get_stock_uom(item_code):
return { 'current_stock_uom': cstr(frappe.db.get_value('Item', item_code, 'stock_uom')) } return { 'current_stock_uom': cstr(frappe.db.get_value('Item', item_code, 'stock_uom')) }

View File

@@ -9,7 +9,7 @@ from frappe import throw, msgprint, _
from frappe.model.document import Document from frappe.model.document import Document
class Warehouse(Document): class Warehouse(Document):
def autoname(self): def autoname(self):
suffix = " - " + frappe.db.get_value("Company", self.company, "abbr") suffix = " - " + frappe.db.get_value("Company", self.company, "abbr")
if not self.warehouse_name.endswith(suffix): if not self.warehouse_name.endswith(suffix):
@@ -18,78 +18,78 @@ class Warehouse(Document):
def validate(self): def validate(self):
if self.email_id and not validate_email_add(self.email_id): if self.email_id and not validate_email_add(self.email_id):
throw(_("Please enter valid Email Id")) throw(_("Please enter valid Email Id"))
self.update_parent_account() self.update_parent_account()
def update_parent_account(self): def update_parent_account(self):
if not getattr(self, "__islocal", None) and (self.create_account_under != if not getattr(self, "__islocal", None) and (self.create_account_under !=
frappe.db.get_value("Warehouse", self.name, "create_account_under")): frappe.db.get_value("Warehouse", self.name, "create_account_under")):
warehouse_account = frappe.db.get_value("Account", warehouse_account = frappe.db.get_value("Account",
{"account_type": "Warehouse", "company": self.company, {"account_type": "Warehouse", "company": self.company,
"master_name": self.name}, ["name", "parent_account"]) "master_name": self.name}, ["name", "parent_account"])
if warehouse_account and warehouse_account[1] != self.create_account_under: if warehouse_account and warehouse_account[1] != self.create_account_under:
acc_doc = frappe.get_doc("Account", warehouse_account[0]) acc_doc = frappe.get_doc("Account", warehouse_account[0])
acc_doc.parent_account = self.create_account_under acc_doc.parent_account = self.create_account_under
acc_doc.save() acc_doc.save()
def on_update(self): def on_update(self):
self.create_account_head() self.create_account_head()
def create_account_head(self): def create_account_head(self):
if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")): if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")):
if not frappe.db.get_value("Account", {"account_type": "Warehouse", if not frappe.db.get_value("Account", {"account_type": "Warehouse",
"master_name": self.name}) and not frappe.db.get_value("Account", "master_name": self.name}) and not frappe.db.get_value("Account",
{"account_name": self.warehouse_name}): {"account_name": self.warehouse_name}):
if self.get("__islocal") or not frappe.db.get_value( if self.get("__islocal") or not frappe.db.get_value(
"Stock Ledger Entry", {"warehouse": self.name}): "Stock Ledger Entry", {"warehouse": self.name}):
self.validate_parent_account() self.validate_parent_account()
ac_doc = frappe.get_doc({ ac_doc = frappe.get_doc({
"doctype": "Account", "doctype": "Account",
'account_name': self.warehouse_name, 'account_name': self.warehouse_name,
'parent_account': self.create_account_under, 'parent_account': self.create_account_under,
'group_or_ledger':'Ledger', 'group_or_ledger':'Ledger',
'company':self.company, 'company':self.company,
"account_type": "Warehouse", "account_type": "Warehouse",
"master_name": self.name, "master_name": self.name,
"freeze_account": "No" "freeze_account": "No"
}) })
ac_doc.ignore_permissions = True ac_doc.ignore_permissions = True
ac_doc.insert() ac_doc.insert()
msgprint(_("Account Head") + ": " + ac_doc.name + _(" created")) msgprint(_("Account head {0} created"))
def validate_parent_account(self): def validate_parent_account(self):
if not self.create_account_under: if not self.create_account_under:
parent_account = frappe.db.get_value("Account", parent_account = frappe.db.get_value("Account",
{"account_name": "Stock Assets", "company": self.company}) {"account_name": "Stock Assets", "company": self.company})
if parent_account: if parent_account:
self.create_account_under = parent_account self.create_account_under = parent_account
else: else:
frappe.throw(_("Please enter account group under which account \ frappe.throw(_("Please enter account group under which account \
for warehouse ") + self.name +_(" will be created")) for warehouse ") + self.name +_(" will be created"))
def on_trash(self): def on_trash(self):
# delete bin # delete bin
bins = frappe.db.sql("select * from `tabBin` where warehouse = %s", bins = frappe.db.sql("select * from `tabBin` where warehouse = %s",
self.name, as_dict=1) self.name, as_dict=1)
for d in bins: for d in bins:
if d['actual_qty'] or d['reserved_qty'] or d['ordered_qty'] or \ if d['actual_qty'] or d['reserved_qty'] or d['ordered_qty'] or \
d['indented_qty'] or d['projected_qty'] or d['planned_qty']: d['indented_qty'] or d['projected_qty'] or d['planned_qty']:
throw("""Warehouse: %s can not be deleted as qty exists for item: %s""" throw("""Warehouse: %s can not be deleted as qty exists for item: %s"""
% (self.name, d['item_code'])) % (self.name, d['item_code']))
else: else:
frappe.db.sql("delete from `tabBin` where name = %s", d['name']) frappe.db.sql("delete from `tabBin` where name = %s", d['name'])
warehouse_account = frappe.db.get_value("Account", warehouse_account = frappe.db.get_value("Account",
{"account_type": "Warehouse", "master_name": self.name}) {"account_type": "Warehouse", "master_name": self.name})
if warehouse_account: if warehouse_account:
frappe.delete_doc("Account", warehouse_account) frappe.delete_doc("Account", warehouse_account)
if frappe.db.sql("""select name from `tabStock Ledger Entry` if frappe.db.sql("""select name from `tabStock Ledger Entry`
where warehouse = %s""", self.name): where warehouse = %s""", self.name):
throw(_("""Warehouse can not be deleted as stock ledger entry throw(_("""Warehouse can not be deleted as stock ledger entry
exists for this warehouse.""")) exists for this warehouse."""))
def before_rename(self, olddn, newdn, merge=False): def before_rename(self, olddn, newdn, merge=False):
# Add company abbr if not provided # Add company abbr if not provided
from erpnext.setup.doctype.company.company import get_name_with_abbr from erpnext.setup.doctype.company.company import get_name_with_abbr
@@ -98,12 +98,12 @@ class Warehouse(Document):
if merge: if merge:
if not frappe.db.exists("Warehouse", new_warehouse): if not frappe.db.exists("Warehouse", new_warehouse):
frappe.throw(_("Warehouse ") + new_warehouse +_(" does not exists")) frappe.throw(_("Warehouse ") + new_warehouse +_(" does not exists"))
if self.company != frappe.db.get_value("Warehouse", new_warehouse, "company"): if self.company != frappe.db.get_value("Warehouse", new_warehouse, "company"):
frappe.throw(_("Both Warehouse must belong to same Company")) frappe.throw(_("Both Warehouse must belong to same Company"))
frappe.db.sql("delete from `tabBin` where warehouse=%s", olddn) frappe.db.sql("delete from `tabBin` where warehouse=%s", olddn)
from erpnext.accounts.utils import rename_account_for from erpnext.accounts.utils import rename_account_for
rename_account_for("Warehouse", olddn, newdn, merge, self.company) rename_account_for("Warehouse", olddn, newdn, merge, self.company)
@@ -112,18 +112,18 @@ class Warehouse(Document):
def after_rename(self, olddn, newdn, merge=False): def after_rename(self, olddn, newdn, merge=False):
if merge: if merge:
self.recalculate_bin_qty(newdn) self.recalculate_bin_qty(newdn)
def recalculate_bin_qty(self, newdn): def recalculate_bin_qty(self, newdn):
from erpnext.utilities.repost_stock import repost_stock from erpnext.utilities.repost_stock import repost_stock
frappe.db.auto_commit_on_many_writes = 1 frappe.db.auto_commit_on_many_writes = 1
frappe.db.set_default("allow_negative_stock", 1) frappe.db.set_default("allow_negative_stock", 1)
for item in frappe.db.sql("""select distinct item_code from ( for item in frappe.db.sql("""select distinct item_code from (
select name as item_code from `tabItem` where ifnull(is_stock_item, 'Yes')='Yes' select name as item_code from `tabItem` where ifnull(is_stock_item, 'Yes')='Yes'
union union
select distinct item_code from tabBin) a"""): select distinct item_code from tabBin) a"""):
repost_stock(item[0], newdn) repost_stock(item[0], newdn)
frappe.db.set_default("allow_negative_stock", frappe.db.set_default("allow_negative_stock",
frappe.db.get_value("Stock Settings", None, "allow_negative_stock")) frappe.db.get_value("Stock Settings", None, "allow_negative_stock"))
frappe.db.auto_commit_on_many_writes = 0 frappe.db.auto_commit_on_many_writes = 0

View File

@@ -3,31 +3,32 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe import _
from frappe.utils import flt from frappe.utils import flt
def execute(filters=None): def execute(filters=None):
if not filters: filters = {} if not filters: filters = {}
columns = get_columns(filters) columns = get_columns(filters)
item_map = get_item_details(filters) item_map = get_item_details(filters)
iwb_map = get_item_warehouse_batch_map(filters) iwb_map = get_item_warehouse_batch_map(filters)
data = [] data = []
for item in sorted(iwb_map): for item in sorted(iwb_map):
for wh in sorted(iwb_map[item]): for wh in sorted(iwb_map[item]):
for batch in sorted(iwb_map[item][wh]): for batch in sorted(iwb_map[item][wh]):
qty_dict = iwb_map[item][wh][batch] qty_dict = iwb_map[item][wh][batch]
data.append([item, item_map[item]["item_name"], data.append([item, item_map[item]["item_name"],
item_map[item]["description"], wh, batch, item_map[item]["description"], wh, batch,
qty_dict.opening_qty, qty_dict.in_qty, qty_dict.opening_qty, qty_dict.in_qty,
qty_dict.out_qty, qty_dict.bal_qty qty_dict.out_qty, qty_dict.bal_qty
]) ])
return columns, data return columns, data
def get_columns(filters): def get_columns(filters):
"""return columns based on filters""" """return columns based on filters"""
columns = ["Item:Link/Item:100"] + ["Item Name::150"] + ["Description::150"] + \ columns = ["Item:Link/Item:100"] + ["Item Name::150"] + ["Description::150"] + \
["Warehouse:Link/Warehouse:100"] + ["Batch:Link/Batch:100"] + ["Opening Qty::90"] + \ ["Warehouse:Link/Warehouse:100"] + ["Batch:Link/Batch:100"] + ["Opening Qty::90"] + \
["In Qty::80"] + ["Out Qty::80"] + ["Balance Qty::90"] ["In Qty::80"] + ["Out Qty::80"] + ["Balance Qty::90"]
@@ -37,21 +38,21 @@ def get_columns(filters):
def get_conditions(filters): def get_conditions(filters):
conditions = "" conditions = ""
if not filters.get("from_date"): if not filters.get("from_date"):
frappe.msgprint("Please enter From Date", raise_exception=1) frappe.throw(_("'From Date' is required"))
if filters.get("to_date"): if filters.get("to_date"):
conditions += " and posting_date <= '%s'" % filters["to_date"] conditions += " and posting_date <= '%s'" % filters["to_date"]
else: else:
frappe.msgprint("Please enter To Date", raise_exception=1) frappe.throw(_("'To Date' is required"))
return conditions return conditions
#get all details #get all details
def get_stock_ledger_entries(filters): def get_stock_ledger_entries(filters):
conditions = get_conditions(filters) conditions = get_conditions(filters)
return frappe.db.sql("""select item_code, batch_no, warehouse, return frappe.db.sql("""select item_code, batch_no, warehouse,
posting_date, actual_qty posting_date, actual_qty
from `tabStock Ledger Entry` from `tabStock Ledger Entry`
where docstatus < 2 %s order by item_code, warehouse""" % where docstatus < 2 %s order by item_code, warehouse""" %
conditions, as_dict=1) conditions, as_dict=1)
@@ -82,4 +83,4 @@ def get_item_details(filters):
for d in frappe.db.sql("select name, item_name, description from tabItem", as_dict=1): for d in frappe.db.sql("select name, item_name, description from tabItem", as_dict=1):
item_map.setdefault(d.name, d) item_map.setdefault(d.name, d)
return item_map return item_map

View File

@@ -2,6 +2,7 @@
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
import frappe import frappe
from frappe import _
from frappe.utils import getdate, flt from frappe.utils import getdate, flt
def execute(filters=None): def execute(filters=None):
@@ -13,7 +14,7 @@ def execute(filters=None):
avg_daily_outgoing = 0 avg_daily_outgoing = 0
diff = ((getdate(filters.get("to_date")) - getdate(filters.get("from_date"))).days)+1 diff = ((getdate(filters.get("to_date")) - getdate(filters.get("from_date"))).days)+1
if diff <= 0: if diff <= 0:
frappe.msgprint("To Date should not be less than eual to From Date",raise_exception=1) frappe.throw(_("'From Date' must be after 'To Date'"))
columns = get_columns() columns = get_columns()
items = get_item_info() items = get_item_info()
@@ -27,8 +28,8 @@ def execute(filters=None):
avg_daily_outgoing = flt(total_outgoing/diff, float_preceision) avg_daily_outgoing = flt(total_outgoing/diff, float_preceision)
reorder_level = (avg_daily_outgoing * flt(item.lead_time_days)) + flt(item.min_order_qty) reorder_level = (avg_daily_outgoing * flt(item.lead_time_days)) + flt(item.min_order_qty)
data.append([item.name, item.item_name, item.description, item.min_order_qty, item.lead_time_days, data.append([item.name, item.item_name, item.description, item.min_order_qty, item.lead_time_days,
consumed_item_map.get(item.name, 0), delivered_item_map.get(item.name,0), total_outgoing, consumed_item_map.get(item.name, 0), delivered_item_map.get(item.name,0), total_outgoing,
avg_daily_outgoing, reorder_level]) avg_daily_outgoing, reorder_level])
return columns , data return columns , data
@@ -36,7 +37,7 @@ def execute(filters=None):
def get_columns(): def get_columns():
return[ return[
"Item:Link/Item:120", "Item name:Data:120", "Description::160", "Item:Link/Item:120", "Item name:Data:120", "Description::160",
"Minimum Inventory Level:Float:160", "Lead Time Days:Float:120", "Consumed:Float:120", "Minimum Inventory Level:Float:160", "Lead Time Days:Float:120", "Consumed:Float:120",
"Delivered:Float:120", "Total Outgoing:Float:120", "Avg Daily Outgoing:Float:160", "Delivered:Float:120", "Total Outgoing:Float:120", "Avg Daily Outgoing:Float:160",
"Reorder Level:Float:120" "Reorder Level:Float:120"
] ]
@@ -47,10 +48,10 @@ def get_item_info():
def get_consumed_items(condition): def get_consumed_items(condition):
cn_items = frappe.db.sql("""select se_item.item_code, cn_items = frappe.db.sql("""select se_item.item_code,
sum(se_item.actual_qty) as 'consume_qty' sum(se_item.actual_qty) as 'consume_qty'
from `tabStock Entry` se, `tabStock Entry Detail` se_item from `tabStock Entry` se, `tabStock Entry Detail` se_item
where se.name = se_item.parent and se.docstatus = 1 where se.name = se_item.parent and se.docstatus = 1
and ifnull(se_item.t_warehouse, '') = '' %s and ifnull(se_item.t_warehouse, '') = '' %s
group by se_item.item_code""" % (condition), as_dict=1) group by se_item.item_code""" % (condition), as_dict=1)
@@ -64,13 +65,13 @@ def get_delivered_items(condition):
dn_items = frappe.db.sql("""select dn_item.item_code, sum(dn_item.qty) as dn_qty dn_items = frappe.db.sql("""select dn_item.item_code, sum(dn_item.qty) as dn_qty
from `tabDelivery Note` dn, `tabDelivery Note Item` dn_item from `tabDelivery Note` dn, `tabDelivery Note Item` dn_item
where dn.name = dn_item.parent and dn.docstatus = 1 %s where dn.name = dn_item.parent and dn.docstatus = 1 %s
group by dn_item.item_code""" % (condition), as_dict=1) group by dn_item.item_code""" % (condition), as_dict=1)
si_items = frappe.db.sql("""select si_item.item_name, sum(si_item.qty) as si_qty si_items = frappe.db.sql("""select si_item.item_name, sum(si_item.qty) as si_qty
from `tabSales Invoice` si, `tabSales Invoice Item` si_item from `tabSales Invoice` si, `tabSales Invoice Item` si_item
where si.name = si_item.parent and si.docstatus = 1 and where si.name = si_item.parent and si.docstatus = 1 and
ifnull(si.update_stock, 0) = 1 and ifnull(si.is_pos, 0) = 1 %s ifnull(si.update_stock, 0) = 1 and ifnull(si.is_pos, 0) = 1 %s
group by si_item.item_name""" % (condition), as_dict=1) group by si_item.item_name""" % (condition), as_dict=1)
dn_item_map = {} dn_item_map = {}
@@ -87,5 +88,5 @@ def get_condition(filters):
if filters.get("from_date") and filters.get("to_date"): if filters.get("from_date") and filters.get("to_date"):
conditions += " and posting_date between '%s' and '%s'" % (filters["from_date"],filters["to_date"]) conditions += " and posting_date between '%s' and '%s'" % (filters["from_date"],filters["to_date"])
else: else:
frappe.msgprint("Please set date in from date field",raise_exception=1) frappe.throw(_("From and To dates required"))
return conditions return conditions

View File

@@ -3,31 +3,32 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe import _
from frappe.utils import flt from frappe.utils import flt
def execute(filters=None): def execute(filters=None):
if not filters: filters = {} if not filters: filters = {}
columns = get_columns(filters) columns = get_columns(filters)
item_map = get_item_details(filters) item_map = get_item_details(filters)
iwb_map = get_item_warehouse_map(filters) iwb_map = get_item_warehouse_map(filters)
data = [] data = []
for company in sorted(iwb_map): for company in sorted(iwb_map):
for item in sorted(iwb_map[company]): for item in sorted(iwb_map[company]):
for wh in sorted(iwb_map[company][item]): for wh in sorted(iwb_map[company][item]):
qty_dict = iwb_map[company][item][wh] qty_dict = iwb_map[company][item][wh]
data.append([item, item_map[item]["item_name"], data.append([item, item_map[item]["item_name"],
item_map[item]["description"], wh, item_map[item]["description"], wh,
qty_dict.opening_qty, qty_dict.in_qty, qty_dict.opening_qty, qty_dict.in_qty,
qty_dict.out_qty, qty_dict.bal_qty, company qty_dict.out_qty, qty_dict.bal_qty, company
]) ])
return columns, data return columns, data
def get_columns(filters): def get_columns(filters):
"""return columns based on filters""" """return columns based on filters"""
columns = ["Item:Link/Item:100", "Item Name::150", "Description::150", \ columns = ["Item:Link/Item:100", "Item Name::150", "Description::150", \
"Warehouse:Link/Warehouse:100", "Opening Qty:Float:90", \ "Warehouse:Link/Warehouse:100", "Opening Qty:Float:90", \
"In Qty:Float:80", "Out Qty:Float:80", "Balance Qty:Float:90", "Company:Link/Company:100"] "In Qty:Float:80", "Out Qty:Float:80", "Balance Qty:Float:90", "Company:Link/Company:100"]
@@ -37,21 +38,21 @@ def get_columns(filters):
def get_conditions(filters): def get_conditions(filters):
conditions = "" conditions = ""
if not filters.get("from_date"): if not filters.get("from_date"):
frappe.msgprint("Please enter From Date", raise_exception=1) frappe.throw(_("'From Date' is required"))
if filters.get("to_date"): if filters.get("to_date"):
conditions += " and posting_date <= '%s'" % filters["to_date"] conditions += " and posting_date <= '%s'" % filters["to_date"]
else: else:
frappe.msgprint("Please enter To Date", raise_exception=1) frappe.throw(_("'To Date' is required"))
return conditions return conditions
#get all details #get all details
def get_stock_ledger_entries(filters): def get_stock_ledger_entries(filters):
conditions = get_conditions(filters) conditions = get_conditions(filters)
return frappe.db.sql("""select item_code, warehouse, return frappe.db.sql("""select item_code, warehouse,
posting_date, actual_qty, company posting_date, actual_qty, company
from `tabStock Ledger Entry` from `tabStock Ledger Entry`
where docstatus < 2 %s order by item_code, warehouse""" % where docstatus < 2 %s order by item_code, warehouse""" %
conditions, as_dict=1) conditions, as_dict=1)
@@ -82,4 +83,4 @@ def get_item_details(filters):
for d in frappe.db.sql("select name, item_name, description from tabItem", as_dict=1): for d in frappe.db.sql("select name, item_name, description from tabItem", as_dict=1):
item_map.setdefault(d.name, d) item_map.setdefault(d.name, d)
return item_map return item_map

View File

@@ -4,34 +4,32 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe import session, msgprint from frappe import session, _
from frappe.utils import today from frappe.utils import today
from erpnext.utilities.transaction_base import TransactionBase from erpnext.utilities.transaction_base import TransactionBase
class CustomerIssue(TransactionBase): class CustomerIssue(TransactionBase):
def validate(self): def validate(self):
if session['user'] != 'Guest' and not self.customer: if session['user'] != 'Guest' and not self.customer:
msgprint("Please select Customer from whom issue is raised", frappe.throw(_("Customer is required"))
raise_exception=True)
if self.status=="Closed" and \ if self.status=="Closed" and \
frappe.db.get_value("Customer Issue", self.name, "status")!="Closed": frappe.db.get_value("Customer Issue", self.name, "status")!="Closed":
self.resolution_date = today() self.resolution_date = today()
self.resolved_by = frappe.session.user self.resolved_by = frappe.session.user
def on_cancel(self): def on_cancel(self):
lst = frappe.db.sql("""select t1.name lst = frappe.db.sql("""select t1.name
from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2
where t2.parent = t1.name and t2.prevdoc_docname = %s and t1.docstatus!=2""", where t2.parent = t1.name and t2.prevdoc_docname = %s and t1.docstatus!=2""",
(self.name)) (self.name))
if lst: if lst:
lst1 = ','.join([x[0] for x in lst]) lst1 = ','.join([x[0] for x in lst])
msgprint("Maintenance Visit No. "+lst1+" already created against this customer issue. So can not be Cancelled") frappe.throw(_("Cancel Material Visit {0} before cancelling this Customer Issue").format(lst1))
raise Exception
else: else:
frappe.db.set(self, 'status', 'Cancelled') frappe.db.set(self, 'status', 'Cancelled')
@@ -41,22 +39,22 @@ class CustomerIssue(TransactionBase):
@frappe.whitelist() @frappe.whitelist()
def make_maintenance_visit(source_name, target_doc=None): def make_maintenance_visit(source_name, target_doc=None):
from frappe.model.mapper import get_mapped_doc from frappe.model.mapper import get_mapped_doc
visit = frappe.db.sql("""select t1.name visit = frappe.db.sql("""select t1.name
from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2
where t2.parent=t1.name and t2.prevdoc_docname=%s where t2.parent=t1.name and t2.prevdoc_docname=%s
and t1.docstatus=1 and t1.completion_status='Fully Completed'""", source_name) and t1.docstatus=1 and t1.completion_status='Fully Completed'""", source_name)
if not visit: if not visit:
doclist = get_mapped_doc("Customer Issue", source_name, { doclist = get_mapped_doc("Customer Issue", source_name, {
"Customer Issue": { "Customer Issue": {
"doctype": "Maintenance Visit", "doctype": "Maintenance Visit",
"field_map": { "field_map": {
"complaint": "description", "complaint": "description",
"doctype": "prevdoc_doctype", "doctype": "prevdoc_doctype",
"name": "prevdoc_docname" "name": "prevdoc_docname"
} }
} }
}, target_doc) }, target_doc)
return doclist return doclist

View File

@@ -1,302 +1,303 @@
{ {
"autoname": "MV.#####", "autoname": "MV.#####",
"creation": "2013-01-10 16:34:31.000000", "creation": "2013-01-10 16:34:31.000000",
"docstatus": 0, "docstatus": 0,
"doctype": "DocType", "doctype": "DocType",
"fields": [ "fields": [
{ {
"fieldname": "customer_details", "fieldname": "customer_details",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Customer Details", "label": "Customer Details",
"oldfieldtype": "Section Break", "oldfieldtype": "Section Break",
"options": "icon-user", "options": "icon-user",
"permlevel": 0 "permlevel": 0
}, },
{ {
"fieldname": "column_break0", "fieldname": "column_break0",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"oldfieldtype": "Column Break", "oldfieldtype": "Column Break",
"permlevel": 0 "permlevel": 0
}, },
{ {
"fieldname": "customer", "fieldname": "customer",
"fieldtype": "Link", "fieldtype": "Link",
"in_filter": 1, "in_filter": 1,
"label": "Customer", "label": "Customer",
"oldfieldname": "customer", "oldfieldname": "customer",
"oldfieldtype": "Link", "oldfieldtype": "Link",
"options": "Customer", "options": "Customer",
"permlevel": 0, "permlevel": 0,
"print_hide": 1, "print_hide": 1,
"reqd": 1, "reqd": 1,
"search_index": 0 "search_index": 0
}, },
{ {
"fieldname": "customer_name", "fieldname": "customer_name",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 1, "hidden": 1,
"in_list_view": 1, "in_list_view": 1,
"label": "Customer Name", "label": "Customer Name",
"permlevel": 0, "permlevel": 0,
"read_only": 1 "read_only": 1
}, },
{ {
"fieldname": "address_display", "fieldname": "address_display",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"hidden": 1, "hidden": 1,
"label": "Address", "label": "Address",
"permlevel": 0, "permlevel": 0,
"read_only": 1 "read_only": 1
}, },
{ {
"fieldname": "contact_display", "fieldname": "contact_display",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"hidden": 1, "hidden": 1,
"label": "Contact", "label": "Contact",
"permlevel": 0, "permlevel": 0,
"read_only": 1 "read_only": 1
}, },
{ {
"fieldname": "contact_mobile", "fieldname": "contact_mobile",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 1, "hidden": 1,
"label": "Mobile No", "label": "Mobile No",
"permlevel": 0, "permlevel": 0,
"read_only": 1 "read_only": 1
}, },
{ {
"fieldname": "contact_email", "fieldname": "contact_email",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 1, "hidden": 1,
"label": "Contact Email", "label": "Contact Email",
"permlevel": 0, "permlevel": 0,
"read_only": 1 "read_only": 1
}, },
{ {
"fieldname": "column_break1", "fieldname": "column_break1",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"oldfieldtype": "Column Break", "oldfieldtype": "Column Break",
"permlevel": 0, "permlevel": 0,
"width": "50%" "width": "50%"
}, },
{ {
"default": "Today", "default": "Today",
"fieldname": "mntc_date", "fieldname": "mntc_date",
"fieldtype": "Date", "fieldtype": "Date",
"label": "Maintenance Date", "label": "Maintenance Date",
"no_copy": 1, "no_copy": 1,
"oldfieldname": "mntc_date", "oldfieldname": "mntc_date",
"oldfieldtype": "Date", "oldfieldtype": "Date",
"permlevel": 0, "permlevel": 0,
"reqd": 1 "reqd": 1
}, },
{ {
"fieldname": "mntc_time", "fieldname": "mntc_time",
"fieldtype": "Time", "fieldtype": "Time",
"label": "Maintenance Time", "label": "Maintenance Time",
"no_copy": 1, "no_copy": 1,
"oldfieldname": "mntc_time", "oldfieldname": "mntc_time",
"oldfieldtype": "Time", "oldfieldtype": "Time",
"permlevel": 0 "permlevel": 0
}, },
{ {
"fieldname": "maintenance_details", "fieldname": "maintenance_details",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Maintenance Details", "label": "Maintenance Details",
"oldfieldtype": "Section Break", "oldfieldtype": "Section Break",
"options": "icon-wrench", "options": "icon-wrench",
"permlevel": 0 "permlevel": 0
}, },
{ {
"fieldname": "completion_status", "fieldname": "completion_status",
"fieldtype": "Select", "fieldtype": "Select",
"in_list_view": 1, "in_list_view": 1,
"label": "Completion Status", "label": "Completion Status",
"oldfieldname": "completion_status", "oldfieldname": "completion_status",
"oldfieldtype": "Select", "oldfieldtype": "Select",
"options": "\nPartially Completed\nFully Completed", "options": "\nPartially Completed\nFully Completed",
"permlevel": 0, "permlevel": 0,
"reqd": 1 "reqd": 1
}, },
{ {
"fieldname": "column_break_14", "fieldname": "column_break_14",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"permlevel": 0 "permlevel": 0
}, },
{ {
"default": "Unscheduled", "default": "Unscheduled",
"fieldname": "maintenance_type", "fieldname": "maintenance_type",
"fieldtype": "Select", "fieldtype": "Select",
"in_filter": 1, "in_filter": 1,
"in_list_view": 1, "in_list_view": 1,
"label": "Maintenance Type", "label": "Maintenance Type",
"oldfieldname": "maintenance_type", "oldfieldname": "maintenance_type",
"oldfieldtype": "Select", "oldfieldtype": "Select",
"options": "\nScheduled\nUnscheduled\nBreakdown", "options": "\nScheduled\nUnscheduled\nBreakdown",
"permlevel": 0, "permlevel": 0,
"reqd": 1, "reqd": 1,
"search_index": 0 "search_index": 0
}, },
{ {
"fieldname": "section_break0", "fieldname": "section_break0",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"oldfieldtype": "Section Break", "oldfieldtype": "Section Break",
"options": "icon-wrench", "options": "icon-wrench",
"permlevel": 0 "permlevel": 0
}, },
{ {
"fieldname": "maintenance_visit_details", "fieldname": "maintenance_visit_details",
"fieldtype": "Table", "fieldtype": "Table",
"label": "Maintenance Visit Purpose", "label": "Maintenance Visit Purpose",
"oldfieldname": "maintenance_visit_details", "oldfieldname": "maintenance_visit_details",
"oldfieldtype": "Table", "oldfieldtype": "Table",
"options": "Maintenance Visit Purpose", "options": "Maintenance Visit Purpose",
"permlevel": 0 "permlevel": 0,
},
{
"fieldname": "more_info",
"fieldtype": "Section Break",
"label": "More Info",
"oldfieldtype": "Section Break",
"options": "icon-file-text",
"permlevel": 0
},
{
"fieldname": "customer_feedback",
"fieldtype": "Small Text",
"label": "Customer Feedback",
"oldfieldname": "customer_feedback",
"oldfieldtype": "Small Text",
"permlevel": 0
},
{
"fieldname": "col_break3",
"fieldtype": "Column Break",
"permlevel": 0
},
{
"default": "Draft",
"fieldname": "status",
"fieldtype": "Data",
"label": "Status",
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Data",
"options": "\nDraft\nCancelled\nSubmitted",
"permlevel": 0,
"read_only": 1,
"reqd": 1 "reqd": 1
}, },
{ {
"fieldname": "amended_from", "fieldname": "more_info",
"fieldtype": "Data", "fieldtype": "Section Break",
"ignore_restrictions": 1, "label": "More Info",
"label": "Amended From", "oldfieldtype": "Section Break",
"no_copy": 1, "options": "icon-file-text",
"oldfieldname": "amended_from", "permlevel": 0
"oldfieldtype": "Data", },
"permlevel": 0, {
"print_hide": 1, "fieldname": "customer_feedback",
"read_only": 1, "fieldtype": "Small Text",
"label": "Customer Feedback",
"oldfieldname": "customer_feedback",
"oldfieldtype": "Small Text",
"permlevel": 0
},
{
"fieldname": "col_break3",
"fieldtype": "Column Break",
"permlevel": 0
},
{
"default": "Draft",
"fieldname": "status",
"fieldtype": "Data",
"label": "Status",
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Data",
"options": "\nDraft\nCancelled\nSubmitted",
"permlevel": 0,
"read_only": 1,
"reqd": 1
},
{
"fieldname": "amended_from",
"fieldtype": "Data",
"ignore_restrictions": 1,
"label": "Amended From",
"no_copy": 1,
"oldfieldname": "amended_from",
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 1,
"read_only": 1,
"width": "150px" "width": "150px"
}, },
{ {
"fieldname": "company", "fieldname": "company",
"fieldtype": "Select", "fieldtype": "Select",
"in_filter": 1, "in_filter": 1,
"label": "Company", "label": "Company",
"oldfieldname": "company", "oldfieldname": "company",
"oldfieldtype": "Select", "oldfieldtype": "Select",
"options": "link:Company", "options": "link:Company",
"permlevel": 0, "permlevel": 0,
"print_hide": 1, "print_hide": 1,
"reqd": 1, "reqd": 1,
"search_index": 0 "search_index": 0
}, },
{ {
"fieldname": "fiscal_year", "fieldname": "fiscal_year",
"fieldtype": "Select", "fieldtype": "Select",
"in_filter": 1, "in_filter": 1,
"label": "Fiscal Year", "label": "Fiscal Year",
"oldfieldname": "fiscal_year", "oldfieldname": "fiscal_year",
"oldfieldtype": "Select", "oldfieldtype": "Select",
"options": "link:Fiscal Year", "options": "link:Fiscal Year",
"permlevel": 0, "permlevel": 0,
"print_hide": 1, "print_hide": 1,
"reqd": 1, "reqd": 1,
"search_index": 0 "search_index": 0
}, },
{ {
"depends_on": "customer", "depends_on": "customer",
"fieldname": "contact_info_section", "fieldname": "contact_info_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Contact Info", "label": "Contact Info",
"options": "icon-bullhorn", "options": "icon-bullhorn",
"permlevel": 0 "permlevel": 0
}, },
{ {
"fieldname": "customer_address", "fieldname": "customer_address",
"fieldtype": "Link", "fieldtype": "Link",
"label": "Customer Address", "label": "Customer Address",
"options": "Address", "options": "Address",
"permlevel": 0, "permlevel": 0,
"print_hide": 1 "print_hide": 1
}, },
{ {
"fieldname": "contact_person", "fieldname": "contact_person",
"fieldtype": "Link", "fieldtype": "Link",
"label": "Contact Person", "label": "Contact Person",
"options": "Contact", "options": "Contact",
"permlevel": 0, "permlevel": 0,
"print_hide": 1 "print_hide": 1
}, },
{ {
"fieldname": "col_break4", "fieldname": "col_break4",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"permlevel": 0 "permlevel": 0
}, },
{ {
"description": "<a href=\"#Sales Browser/Territory\">Add / Edit</a>", "description": "<a href=\"#Sales Browser/Territory\">Add / Edit</a>",
"fieldname": "territory", "fieldname": "territory",
"fieldtype": "Link", "fieldtype": "Link",
"label": "Territory", "label": "Territory",
"options": "Territory", "options": "Territory",
"permlevel": 0, "permlevel": 0,
"print_hide": 1 "print_hide": 1
}, },
{ {
"description": "<a href=\"#Sales Browser/Customer Group\">Add / Edit</a>", "description": "<a href=\"#Sales Browser/Customer Group\">Add / Edit</a>",
"fieldname": "customer_group", "fieldname": "customer_group",
"fieldtype": "Link", "fieldtype": "Link",
"label": "Customer Group", "label": "Customer Group",
"options": "Customer Group", "options": "Customer Group",
"permlevel": 0, "permlevel": 0,
"print_hide": 1 "print_hide": 1
} }
], ],
"icon": "icon-file-text", "icon": "icon-file-text",
"idx": 1, "idx": 1,
"is_submittable": 1, "is_submittable": 1,
"modified": "2014-01-20 17:48:57.000000", "modified": "2014-01-20 17:48:57.000001",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Support", "module": "Support",
"name": "Maintenance Visit", "name": "Maintenance Visit",
"owner": "ashwini@webnotestech.com", "owner": "ashwini@webnotestech.com",
"permissions": [ "permissions": [
{ {
"amend": 1, "amend": 1,
"cancel": 1, "cancel": 1,
"create": 1, "create": 1,
"delete": 1, "delete": 1,
"email": 1, "email": 1,
"permlevel": 0, "permlevel": 0,
"print": 1, "print": 1,
"read": 1, "read": 1,
"report": 1, "report": 1,
"role": "Maintenance User", "role": "Maintenance User",
"submit": 1, "submit": 1,
"write": 1 "write": 1
} }
], ],
"search_fields": "status,maintenance_type,customer,customer_name, address,mntc_date,company,fiscal_year" "search_fields": "status,maintenance_type,customer,customer_name, address,mntc_date,company,fiscal_year"
} }

View File

@@ -3,33 +3,24 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe import _
from frappe.utils import cstr
from frappe import msgprint
from erpnext.utilities.transaction_base import TransactionBase from erpnext.utilities.transaction_base import TransactionBase
class MaintenanceVisit(TransactionBase): class MaintenanceVisit(TransactionBase):
def get_item_details(self, item_code): def get_item_details(self, item_code):
return frappe.db.get_value("Item", item_code, ["item_name", "description"], as_dict=1) return frappe.db.get_value("Item", item_code, ["item_name", "description"], as_dict=1)
def validate_serial_no(self): def validate_serial_no(self):
for d in self.get('maintenance_visit_details'): for d in self.get('maintenance_visit_details'):
if d.serial_no and not frappe.db.exists("Serial No", d.serial_no): if d.serial_no and not frappe.db.exists("Serial No", d.serial_no):
frappe.throw("Serial No: "+ d.serial_no + " not exists in the system") frappe.throw("Serial No: "+ d.serial_no + " not exists in the system")
def validate(self):
if not self.get('maintenance_visit_details'):
msgprint("Please enter maintenance details")
raise Exception
def validate(self):
self.validate_serial_no() self.validate_serial_no()
def update_customer_issue(self, flag): def update_customer_issue(self, flag):
for d in self.get('maintenance_visit_details'): for d in self.get('maintenance_visit_details'):
if d.prevdoc_docname and d.prevdoc_doctype == 'Customer Issue' : if d.prevdoc_docname and d.prevdoc_doctype == 'Customer Issue' :
@@ -43,7 +34,7 @@ class MaintenanceVisit(TransactionBase):
status = 'Work In Progress' status = 'Work In Progress'
else: else:
nm = frappe.db.sql("select t1.name, t1.mntc_date, t2.service_person, t2.work_done from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent = t1.name and t1.completion_status = 'Partially Completed' and t2.prevdoc_docname = %s and t1.name!=%s and t1.docstatus = 1 order by t1.name desc limit 1", (d.prevdoc_docname, self.name)) nm = frappe.db.sql("select t1.name, t1.mntc_date, t2.service_person, t2.work_done from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent = t1.name and t1.completion_status = 'Partially Completed' and t2.prevdoc_docname = %s and t1.name!=%s and t1.docstatus = 1 order by t1.name desc limit 1", (d.prevdoc_docname, self.name))
if nm: if nm:
status = 'Work In Progress' status = 'Work In Progress'
mntc_date = nm and nm[0][1] or '' mntc_date = nm and nm[0][1] or ''
@@ -54,9 +45,9 @@ class MaintenanceVisit(TransactionBase):
mntc_date = '' mntc_date = ''
service_person = '' service_person = ''
work_done = '' work_done = ''
frappe.db.sql("update `tabCustomer Issue` set resolution_date=%s, resolved_by=%s, resolution_details=%s, status=%s where name =%s",(mntc_date,service_person,work_done,status,d.prevdoc_docname)) frappe.db.sql("update `tabCustomer Issue` set resolution_date=%s, resolved_by=%s, resolution_details=%s, status=%s where name =%s",(mntc_date,service_person,work_done,status,d.prevdoc_docname))
def check_if_last_visit(self): def check_if_last_visit(self):
"""check if last maintenance visit against same sales order/ customer issue""" """check if last maintenance visit against same sales order/ customer issue"""
@@ -65,25 +56,25 @@ class MaintenanceVisit(TransactionBase):
if d.prevdoc_docname: if d.prevdoc_docname:
check_for_docname = d.prevdoc_docname check_for_docname = d.prevdoc_docname
check_for_doctype = d.prevdoc_doctype check_for_doctype = d.prevdoc_doctype
if check_for_docname: if check_for_docname:
check = frappe.db.sql("select t1.name from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent = t1.name and t1.name!=%s and t2.prevdoc_docname=%s and t1.docstatus = 1 and (t1.mntc_date > %s or (t1.mntc_date = %s and t1.mntc_time > %s))", (self.name, check_for_docname, self.mntc_date, self.mntc_date, self.mntc_time)) check = frappe.db.sql("select t1.name from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent = t1.name and t1.name!=%s and t2.prevdoc_docname=%s and t1.docstatus = 1 and (t1.mntc_date > %s or (t1.mntc_date = %s and t1.mntc_time > %s))", (self.name, check_for_docname, self.mntc_date, self.mntc_date, self.mntc_time))
if check: if check:
check_lst = [x[0] for x in check] check_lst = [x[0] for x in check]
check_lst =','.join(check_lst) check_lst =','.join(check_lst)
msgprint("To cancel this, you need to cancel Maintenance Visit(s) "+cstr(check_lst)+" created after this maintenance visit against same "+check_for_doctype) frappe.throw(_("Cancel Material Visits {0} before cancelling this Maintenance Visit").format(check_lst))
raise Exception raise Exception
else: else:
self.update_customer_issue(0) self.update_customer_issue(0)
def on_submit(self): def on_submit(self):
self.update_customer_issue(1) self.update_customer_issue(1)
frappe.db.set(self, 'status', 'Submitted') frappe.db.set(self, 'status', 'Submitted')
def on_cancel(self): def on_cancel(self):
self.check_if_last_visit() self.check_if_last_visit()
frappe.db.set(self, 'status', 'Cancelled') frappe.db.set(self, 'status', 'Cancelled')
def on_update(self): def on_update(self):
pass pass

View File

@@ -6,7 +6,7 @@ from __future__ import unicode_literals
import frappe import frappe
import frappe.utils import frappe.utils
from frappe.utils import cstr from frappe.utils import cstr
from frappe import msgprint, throw, _ from frappe import throw, _
from frappe.model.document import Document from frappe.model.document import Document
class Newsletter(Document): class Newsletter(Document):
@@ -20,10 +20,7 @@ class Newsletter(Document):
self.recipients = self.test_email_id.split(",") self.recipients = self.test_email_id.split(",")
self.send_to_doctype = "Lead" self.send_to_doctype = "Lead"
self.send_bulk() self.send_bulk()
msgprint("{send} {email}".format**{ frappe.msgprint(_("Scheduled to send to {0}").format(self.test_email_id))
"send": _("Scheduled to send to"),
"email": self.test_email_id
})
def send_emails(self): def send_emails(self):
"""send emails to leads and customers""" """send emails to leads and customers"""
@@ -32,27 +29,23 @@ class Newsletter(Document):
self.recipients = self.get_recipients() self.recipients = self.get_recipients()
self.send_bulk() self.send_bulk()
msgprint("{send} {recipients} {doctype}(s)".format(**{ frappe.msgprint(_("Scheduled to send to {0} recipients").format(len(self.recipients)))
"send": _("Scheduled to send to"),
"recipients": len(self.recipients),
"doctype": self.send_to_doctype
}))
frappe.db.set(self, "email_sent", 1) frappe.db.set(self, "email_sent", 1)
def get_recipients(self): def get_recipients(self):
self.email_field = None self.email_field = None
if self.send_to_type=="Contact": if self.send_to_type=="Contact":
self.send_to_doctype = "Contact" self.send_to_doctype = "Contact"
if self.contact_type == "Customer": if self.contact_type == "Customer":
return frappe.db.sql_list("""select email_id from tabContact return frappe.db.sql_list("""select email_id from tabContact
where ifnull(email_id, '') != '' and ifnull(customer, '') != ''""") where ifnull(email_id, '') != '' and ifnull(customer, '') != ''""")
elif self.contact_type == "Supplier": elif self.contact_type == "Supplier":
return frappe.db.sql_list("""select email_id from tabContact return frappe.db.sql_list("""select email_id from tabContact
where ifnull(email_id, '') != '' and ifnull(supplier, '') != ''""") where ifnull(email_id, '') != '' and ifnull(supplier, '') != ''""")
elif self.send_to_type=="Lead": elif self.send_to_type=="Lead":
self.send_to_doctype = "Lead" self.send_to_doctype = "Lead"
conditions = [] conditions = []
@@ -63,37 +56,37 @@ class Newsletter(Document):
if conditions: if conditions:
conditions = "".join(conditions) conditions = "".join(conditions)
return frappe.db.sql_list("""select email_id from tabLead return frappe.db.sql_list("""select email_id from tabLead
where ifnull(email_id, '') != '' %s""" % (conditions or "")) where ifnull(email_id, '') != '' %s""" % (conditions or ""))
elif self.send_to_type=="Employee": elif self.send_to_type=="Employee":
self.send_to_doctype = "Employee" self.send_to_doctype = "Employee"
self.email_field = "company_email" self.email_field = "company_email"
return frappe.db.sql_list("""select return frappe.db.sql_list("""select
if(ifnull(company_email, '')!='', company_email, personal_email) as email_id if(ifnull(company_email, '')!='', company_email, personal_email) as email_id
from `tabEmployee` where status='Active'""") from `tabEmployee` where status='Active'""")
elif self.email_list: elif self.email_list:
email_list = [cstr(email).strip() for email in self.email_list.split(",")] email_list = [cstr(email).strip() for email in self.email_list.split(",")]
for email in email_list: for email in email_list:
create_lead(email) create_lead(email)
self.send_to_doctype = "Lead" self.send_to_doctype = "Lead"
return email_list return email_list
def send_bulk(self): def send_bulk(self):
self.validate_send() self.validate_send()
sender = self.send_from or frappe.utils.get_formatted_email(self.owner) sender = self.send_from or frappe.utils.get_formatted_email(self.owner)
from frappe.utils.email_lib.bulk import send from frappe.utils.email_lib.bulk import send
if not frappe.flags.in_test: if not frappe.flags.in_test:
frappe.db.auto_commit_on_many_writes = True frappe.db.auto_commit_on_many_writes = True
send(recipients = self.recipients, sender = sender, send(recipients = self.recipients, sender = sender,
subject = self.subject, message = self.message, subject = self.subject, message = self.message,
doctype = self.send_to_doctype, email_field = self.email_field or "email_id", doctype = self.send_to_doctype, email_field = self.email_field or "email_id",
ref_doctype = self.doctype, ref_docname = self.name) ref_doctype = self.doctype, ref_docname = self.name)
@@ -103,19 +96,18 @@ class Newsletter(Document):
def validate_send(self): def validate_send(self):
if self.get("__islocal"): if self.get("__islocal"):
throw(_("Please save the Newsletter before sending.")) throw(_("Please save the Newsletter before sending"))
from frappe import conf from frappe import conf
if (conf.get("status") or None) == "Trial": if (conf.get("status") or None) == "Trial":
throw(_("Sending newsletters is not allowed for Trial users, \ throw(_("Newsletters is not allowed for Trial users"))
to prevent abuse of this feature."))
@frappe.whitelist() @frappe.whitelist()
def get_lead_options(): def get_lead_options():
return { return {
"sources": ["All"] + filter(None, "sources": ["All"] + filter(None,
frappe.db.sql_list("""select distinct source from tabLead""")), frappe.db.sql_list("""select distinct source from tabLead""")),
"statuses": ["All"] + filter(None, "statuses": ["All"] + filter(None,
frappe.db.sql_list("""select distinct status from tabLead""")) frappe.db.sql_list("""select distinct status from tabLead"""))
} }
@@ -125,10 +117,10 @@ def create_lead(email_id):
from email.utils import parseaddr from email.utils import parseaddr
from frappe.model.naming import get_default_naming_series from frappe.model.naming import get_default_naming_series
real_name, email_id = parseaddr(email_id) real_name, email_id = parseaddr(email_id)
if frappe.db.get_value("Lead", {"email_id": email_id}): if frappe.db.get_value("Lead", {"email_id": email_id}):
return return
lead = frappe.get_doc({ lead = frappe.get_doc({
"doctype": "Lead", "doctype": "Lead",
"email_id": email_id, "email_id": email_id,
@@ -138,4 +130,4 @@ def create_lead(email_id):
"company": frappe.db.get_default("company"), "company": frappe.db.get_default("company"),
"source": "Email" "source": "Email"
}) })
lead.insert() lead.insert()

View File

@@ -5,24 +5,24 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe import _
from frappe.model.document import Document from frappe.model.document import Document
from frappe.utils.email_lib.receive import POP3Mailbox from frappe.utils.email_lib.receive import POP3Mailbox
import _socket, poplib import _socket, poplib
class SupportEmailSettings(Document): class SupportEmailSettings(Document):
def validate(self): def validate(self):
""" """
Checks support ticket email settings Checks support ticket email settings
""" """
if self.sync_support_mails and self.mail_server: if self.sync_support_mails and self.mail_server:
inc_email = frappe.get_doc('Incoming Email Settings') inc_email = frappe.get_doc('Incoming Email Settings')
# inc_email.encode() # inc_email.encode()
inc_email.host = self.mail_server inc_email.host = self.mail_server
inc_email.use_ssl = self.use_ssl inc_email.use_ssl = self.use_ssl
try: try:
err_msg = 'User Name or Support Password missing. Please enter and try again.' err_msg = _('User Name or Support Password missing. Please enter and try again.')
if not (self.mail_login and self.mail_password): if not (self.mail_login and self.mail_password):
raise AttributeError, err_msg raise AttributeError, err_msg
inc_email.username = self.mail_login inc_email.username = self.mail_login
@@ -32,14 +32,13 @@ class SupportEmailSettings(Document):
raise raise
pop_mb = POP3Mailbox(inc_email) pop_mb = POP3Mailbox(inc_email)
try: try:
pop_mb.connect() pop_mb.connect()
except _socket.error, e: except _socket.error, e:
# Invalid mail server -- due to refusing connection # Invalid mail server -- due to refusing connection
frappe.msgprint('Invalid POP3 Mail Server. Please rectify and try again.') frappe.msgprint(_('Invalid Mail Server. Please rectify and try again.'))
raise raise
except poplib.error_proto, e: except poplib.error_proto, e:
frappe.msgprint('Invalid User Name or Support Password. Please rectify and try again.') frappe.msgprint(_('Invalid User Name or Support Password. Please rectify and try again.'))
raise raise

View File

@@ -1,27 +1,27 @@
# ERPNext - web based ERP (http://erpnext.com) # ERPNext - web based ERP (http://erpnext.com)
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd # Copyright (C) 2012 Web Notes Technologies Pvt Ltd
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or # the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe import _, msgprint from frappe import _
from frappe.utils import cint, comma_or from frappe.utils import cint, comma_or
def validate_status(status, options): def validate_status(status, options):
if status not in options: if status not in options:
msgprint(_("Status must be one of ") + comma_or(options), raise_exception=True) frappe.throw(_("Status must be one of {0}").format(comma_or(options)))
def build_filter_conditions(filters): def build_filter_conditions(filters):
conditions, filter_values = [], [] conditions, filter_values = [], []
@@ -30,4 +30,4 @@ def build_filter_conditions(filters):
filter_values.append(filters[key]) filter_values.append(filters[key])
conditions = conditions and " and " + " and ".join(conditions) or "" conditions = conditions and " and " + " and ".join(conditions) or ""
return conditions, filter_values return conditions, filter_values

View File

@@ -4,8 +4,8 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe import msgprint, throw, _ from frappe import throw, _
from frappe.utils import cstr, cint from frappe.utils import cstr
from frappe.model.document import Document from frappe.model.document import Document
@@ -20,30 +20,30 @@ class Address(Document):
self.name = cstr(self.address_title).strip() + "-" + cstr(self.address_type).strip() self.name = cstr(self.address_title).strip() + "-" + cstr(self.address_type).strip()
else: else:
throw(_("Address Title is mandatory.")) throw(_("Address Title is mandatory."))
def validate(self): def validate(self):
self.validate_primary_address() self.validate_primary_address()
self.validate_shipping_address() self.validate_shipping_address()
def validate_primary_address(self): def validate_primary_address(self):
"""Validate that there can only be one primary address for particular customer, supplier""" """Validate that there can only be one primary address for particular customer, supplier"""
if self.is_primary_address == 1: if self.is_primary_address == 1:
self._unset_other("is_primary_address") self._unset_other("is_primary_address")
elif self.is_shipping_address != 1: elif self.is_shipping_address != 1:
for fieldname in ["customer", "supplier", "sales_partner", "lead"]: for fieldname in ["customer", "supplier", "sales_partner", "lead"]:
if self.get(fieldname): if self.get(fieldname):
if not frappe.db.sql("""select name from `tabAddress` where is_primary_address=1 if not frappe.db.sql("""select name from `tabAddress` where is_primary_address=1
and `%s`=%s and name!=%s""" % (fieldname, "%s", "%s"), and `%s`=%s and name!=%s""" % (fieldname, "%s", "%s"),
(self.get(fieldname), self.name)): (self.get(fieldname), self.name)):
self.is_primary_address = 1 self.is_primary_address = 1
break break
def validate_shipping_address(self): def validate_shipping_address(self):
"""Validate that there can only be one shipping address for particular customer, supplier""" """Validate that there can only be one shipping address for particular customer, supplier"""
if self.is_shipping_address == 1: if self.is_shipping_address == 1:
self._unset_other("is_shipping_address") self._unset_other("is_shipping_address")
def _unset_other(self, is_address_type): def _unset_other(self, is_address_type):
for fieldname in ["customer", "supplier", "sales_partner", "lead"]: for fieldname in ["customer", "supplier", "sales_partner", "lead"]:
if self.get(fieldname): if self.get(fieldname):
@@ -55,21 +55,21 @@ class Address(Document):
def get_address_display(address_dict): def get_address_display(address_dict):
if not isinstance(address_dict, dict): if not isinstance(address_dict, dict):
address_dict = frappe.db.get_value("Address", address_dict, "*", as_dict=True) or {} address_dict = frappe.db.get_value("Address", address_dict, "*", as_dict=True) or {}
meta = frappe.get_meta("Address") meta = frappe.get_meta("Address")
sequence = (("", "address_line1"), sequence = (("", "address_line1"),
("\n", "address_line2"), ("\n", "address_line2"),
("\n", "city"), ("\n", "city"),
("\n", "state"), ("\n", "state"),
("\n" + meta.get_label("pincode") + ": ", "pincode"), ("\n" + meta.get_label("pincode") + ": ", "pincode"),
("\n", "country"), ("\n", "country"),
("\n" + meta.get_label("phone") + ": ", "phone"), ("\n" + meta.get_label("phone") + ": ", "phone"),
("\n" + meta.get_label("fax") + ": ", "fax")) ("\n" + meta.get_label("fax") + ": ", "fax"))
display = "" display = ""
for separator, fieldname in sequence: for separator, fieldname in sequence:
if address_dict.get(fieldname): if address_dict.get(fieldname):
display += separator + address_dict.get(fieldname) display += separator + address_dict.get(fieldname)
return display.strip() return display.strip()

View File

@@ -5,24 +5,24 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe import _
from frappe.model.document import Document from frappe.model.document import Document
class Note(Document): class Note(Document):
def autoname(self): def autoname(self):
# replace forbidden characters # replace forbidden characters
import re import re
self.name = re.sub("[%'\"#*?`]", "", self.title.strip()) self.name = re.sub("[%'\"#*?`]", "", self.title.strip())
def onload(self): def onload(self):
if not self.public and frappe.session.user != self.owner: if not self.public and frappe.session.user != self.owner:
if frappe.session.user not in [d.user for d in self.get("share_with")]: if frappe.session.user not in [d.user for d in self.get("share_with")]:
frappe.msgprint("You are not authorized to read this record.", raise_exception=True) frappe.throw(_("Not permitted"), frappe.PermissionError)
def validate(self): def validate(self):
if not self.get("__islocal"): if not self.get("__islocal"):
if frappe.session.user != self.owner: if frappe.session.user != self.owner:
if frappe.session.user not in frappe.db.sql_list("""select user from `tabNote User` if frappe.session.user not in frappe.db.sql_list("""select user from `tabNote User`
where parent=%s and permission='Edit'""", self.name): where parent=%s and permission='Edit'""", self.name):
frappe.msgprint("You are not authorized to edit this record.", raise_exception=True) frappe.throw(_("Not permitted"), frappe.PermissionError)

View File

@@ -11,34 +11,32 @@ from frappe.model.document import Document
class RenameTool(Document): class RenameTool(Document):
pass pass
@frappe.whitelist() @frappe.whitelist()
def get_doctypes(): def get_doctypes():
return frappe.db.sql_list("""select name from tabDocType return frappe.db.sql_list("""select name from tabDocType
where ifnull(allow_rename,0)=1 and module!='Core' order by name""") where ifnull(allow_rename,0)=1 and module!='Core' order by name""")
@frappe.whitelist() @frappe.whitelist()
def upload(select_doctype=None, rows=None): def upload(select_doctype=None, rows=None):
from frappe.utils.datautils import read_csv_content_from_uploaded_file from frappe.utils.datautils import read_csv_content_from_uploaded_file
from frappe.modules import scrub
from frappe.model.rename_doc import rename_doc from frappe.model.rename_doc import rename_doc
if not select_doctype: if not select_doctype:
select_doctype = frappe.form_dict.select_doctype select_doctype = frappe.form_dict.select_doctype
if not frappe.has_permission(select_doctype, "write"): if not frappe.has_permission(select_doctype, "write"):
raise frappe.PermissionError raise frappe.PermissionError
if not rows: if not rows:
rows = read_csv_content_from_uploaded_file() rows = read_csv_content_from_uploaded_file()
if not rows: if not rows:
frappe.msgprint(_("Please select a valid csv file with data.")) frappe.throw(_("Please select a valid csv file with data"))
raise Exception
max_rows = 500
if len(rows) > 500: if len(rows) > max_rows:
frappe.msgprint(_("Max 500 rows only.")) frappe.throw(_("Maximum {0} rows allowed").format(max_rows))
raise Exception
rename_log = [] rename_log = []
for row in rows: for row in rows:
# if row has some content # if row has some content
@@ -53,5 +51,5 @@ def upload(select_doctype=None, rows=None):
rename_log.append("<span style='color: RED'>" + \ rename_log.append("<span style='color: RED'>" + \
_("Failed: ") + row[0] + " -> " + row[1] + "</span>") _("Failed: ") + row[0] + " -> " + row[1] + "</span>")
rename_log.append("<span style='margin-left: 20px;'>" + repr(e) + "</span>") rename_log.append("<span style='margin-left: 20px;'>" + repr(e) + "</span>")
return rename_log return rename_log

View File

@@ -19,7 +19,7 @@ class SMSControl(Document):
invalid_char_list = [' ', '+', '-', '(', ')'] invalid_char_list = [' ', '+', '-', '(', ')']
for x in invalid_char_list: for x in invalid_char_list:
d = d.replace(x, '') d = d.replace(x, '')
validated_receiver_list.append(d) validated_receiver_list.append(d)
if not validated_receiver_list: if not validated_receiver_list:
@@ -34,21 +34,18 @@ class SMSControl(Document):
'ERPNXT' 'ERPNXT'
if len(sender_name) > 6 and \ if len(sender_name) > 6 and \
frappe.db.get_default("country") == "India": frappe.db.get_default("country") == "India":
throw(_(""" throw("""As per TRAI rule, sender name must be exactly 6 characters.
As per TRAI rule, sender name must be exactly 6 characters.
Kindly change sender name in Setup --> Global Defaults. Kindly change sender name in Setup --> Global Defaults.
Note: Hyphen, space, numeric digit, special characters are not allowed.""")
Note: Hyphen, space, numeric digit, special characters are not allowed.
"""))
return sender_name return sender_name
def get_contact_number(self, arg): def get_contact_number(self, arg):
"returns mobile number of the contact" "returns mobile number of the contact"
args = json.loads(arg) args = json.loads(arg)
number = frappe.db.sql("""select mobile_no, phone from tabContact where name=%s and %s=%s""" % number = frappe.db.sql("""select mobile_no, phone from tabContact where name=%s and %s=%s""" %
('%s', args['key'], '%s'), (args['contact_name'], args['value'])) ('%s', args['key'], '%s'), (args['contact_name'], args['value']))
return number and (number[0][0] or number[0][1]) or '' return number and (number[0][0] or number[0][1]) or ''
def send_form_sms(self, arg): def send_form_sms(self, arg):
"called from client side" "called from client side"
args = json.loads(arg) args = json.loads(arg)
@@ -72,7 +69,7 @@ class SMSControl(Document):
args = {ss.message_parameter : arg.get('message')} args = {ss.message_parameter : arg.get('message')}
for d in ss.get("static_parameter_details"): for d in ss.get("static_parameter_details"):
args[d.parameter] = d.value args[d.parameter] = d.value
resp = [] resp = []
for d in arg.get('receiver_list'): for d in arg.get('receiver_list'):
args[ss.receiver_parameter] = d args[ss.receiver_parameter] = d

View File

@@ -15,26 +15,26 @@ class TransactionBase(StatusUpdater):
if int(frappe.db.get_value("Notification Control", None, dt) or 0): if int(frappe.db.get_value("Notification Control", None, dt) or 0):
self.set("__notification_message", self.set("__notification_message",
frappe.db.get_value("Notification Control", None, dt + "_message")) frappe.db.get_value("Notification Control", None, dt + "_message"))
def validate_posting_time(self): def validate_posting_time(self):
if not self.posting_time: if not self.posting_time:
self.posting_time = now_datetime().strftime('%H:%M:%S') self.posting_time = now_datetime().strftime('%H:%M:%S')
def add_calendar_event(self, opts, force=False): def add_calendar_event(self, opts, force=False):
if self.contact_by != cstr(self._prev.contact_by) or \ if self.contact_by != cstr(self._prev.contact_by) or \
self.contact_date != cstr(self._prev.contact_date) or force: self.contact_date != cstr(self._prev.contact_date) or force:
self.delete_events() self.delete_events()
self._add_calendar_event(opts) self._add_calendar_event(opts)
def delete_events(self): def delete_events(self):
frappe.delete_doc("Event", frappe.db.sql_list("""select name from `tabEvent` frappe.delete_doc("Event", frappe.db.sql_list("""select name from `tabEvent`
where ref_type=%s and ref_name=%s""", (self.doctype, self.name)), where ref_type=%s and ref_name=%s""", (self.doctype, self.name)),
ignore_permissions=True) ignore_permissions=True)
def _add_calendar_event(self, opts): def _add_calendar_event(self, opts):
opts = frappe._dict(opts) opts = frappe._dict(opts)
if self.contact_date: if self.contact_date:
event_doclist = frappe.get_doc({ event_doclist = frappe.get_doc({
"doctype": "Event", "doctype": "Event",
@@ -46,18 +46,18 @@ class TransactionBase(StatusUpdater):
"ref_type": self.doctype, "ref_type": self.doctype,
"ref_name": self.name "ref_name": self.name
}) })
if frappe.db.exists("User", self.contact_by): if frappe.db.exists("User", self.contact_by):
event_doclist.append("event_individuals", { event_doclist.append("event_individuals", {
"doctype": "Event User", "doctype": "Event User",
"person": self.contact_by "person": self.contact_by
}) })
event_doclist.insert() event_doclist.insert()
def validate_uom_is_integer(self, uom_field, qty_fields): def validate_uom_is_integer(self, uom_field, qty_fields):
validate_uom_is_integer(self, uom_field, qty_fields) validate_uom_is_integer(self, uom_field, qty_fields)
def validate_with_previous_doc(self, source_dt, ref): def validate_with_previous_doc(self, source_dt, ref):
for key, val in ref.items(): for key, val in ref.items():
is_child = val.get("is_child_table") is_child = val.get("is_child_table")
@@ -71,27 +71,26 @@ class TransactionBase(StatusUpdater):
if ref_dn not in item_ref_dn: if ref_dn not in item_ref_dn:
item_ref_dn.append(ref_dn) item_ref_dn.append(ref_dn)
elif not val.get("allow_duplicate_prev_row_id"): elif not val.get("allow_duplicate_prev_row_id"):
frappe.msgprint(_("Row ") + cstr(d.idx + 1) + frappe.throw(_("Duplicate row {0} with same {1}").format(d.idx, key))
_(": Duplicate row from same ") + key, raise_exception=1)
elif ref_dn: elif ref_dn:
ref_doc.setdefault(key, []) ref_doc.setdefault(key, [])
if ref_dn not in ref_doc[key]: if ref_dn not in ref_doc[key]:
ref_doc[key].append(ref_dn) ref_doc[key].append(ref_dn)
if ref_doc: if ref_doc:
self.compare_values(ref_doc, val["compare_fields"]) self.compare_values(ref_doc, val["compare_fields"])
def compare_values(self, ref_doc, fields, doc=None): def compare_values(self, ref_doc, fields, doc=None):
for ref_doctype, ref_dn_list in ref_doc.items(): for ref_doctype, ref_dn_list in ref_doc.items():
for ref_docname in ref_dn_list: for ref_docname in ref_dn_list:
prevdoc_values = frappe.db.get_value(ref_doctype, ref_docname, prevdoc_values = frappe.db.get_value(ref_doctype, ref_docname,
[d[0] for d in fields], as_dict=1) [d[0] for d in fields], as_dict=1)
for field, condition in fields: for field, condition in fields:
if prevdoc_values[field] is not None: if prevdoc_values[field] is not None:
self.validate_value(field, condition, prevdoc_values[field], doc) self.validate_value(field, condition, prevdoc_values[field], doc)
def delete_events(ref_type, ref_name): def delete_events(ref_type, ref_name):
frappe.delete_doc("Event", frappe.db.sql_list("""select name from `tabEvent` frappe.delete_doc("Event", frappe.db.sql_list("""select name from `tabEvent`
where ref_type=%s and ref_name=%s""", (ref_type, ref_name)), for_reload=True) where ref_type=%s and ref_name=%s""", (ref_type, ref_name)), for_reload=True)
class UOMMustBeIntegerError(frappe.ValidationError): pass class UOMMustBeIntegerError(frappe.ValidationError): pass
@@ -99,11 +98,11 @@ class UOMMustBeIntegerError(frappe.ValidationError): pass
def validate_uom_is_integer(doc, uom_field, qty_fields): def validate_uom_is_integer(doc, uom_field, qty_fields):
if isinstance(qty_fields, basestring): if isinstance(qty_fields, basestring):
qty_fields = [qty_fields] qty_fields = [qty_fields]
distinct_uoms = list(set([d.get(uom_field) for d in doc.get_all_children()])) distinct_uoms = list(set([d.get(uom_field) for d in doc.get_all_children()]))
integer_uoms = filter(lambda uom: frappe.db.get_value("UOM", uom, integer_uoms = filter(lambda uom: frappe.db.get_value("UOM", uom,
"must_be_whole_number") or None, distinct_uoms) "must_be_whole_number") or None, distinct_uoms)
if not integer_uoms: if not integer_uoms:
return return
@@ -112,7 +111,4 @@ def validate_uom_is_integer(doc, uom_field, qty_fields):
for f in qty_fields: for f in qty_fields:
if d.get(f): if d.get(f):
if cint(d.get(f))!=d.get(f): if cint(d.get(f))!=d.get(f):
frappe.msgprint(_("For UOM") + " '" + d.get(uom_field) \ frappe.throw(_("Quantity cannot be a fraction in row {0}").format(d.idx), UOMMustBeIntegerError)
+ "': " + _("Quantity cannot be a fraction.") \
+ " " + _("In Row") + ": " + str(d.idx),
raise_exception=UOMMustBeIntegerError)