Merge branch 'develop'

This commit is contained in:
Nabin Hait 2016-01-21 16:52:22 +05:30
commit ccddc48ced
310 changed files with 14385 additions and 10366 deletions

View File

@ -1,2 +1,2 @@
from __future__ import unicode_literals from __future__ import unicode_literals
__version__ = '6.17.0' __version__ = '6.18.0'

View File

@ -48,13 +48,13 @@ cur_frm.cscript.account_type = function(doc, cdt, cdn) {
cur_frm.cscript.add_toolbar_buttons = function(doc) { cur_frm.cscript.add_toolbar_buttons = function(doc) {
cur_frm.add_custom_button(__('Chart of Accounts'), cur_frm.add_custom_button(__('Chart of Accounts'),
function() { frappe.set_route("Accounts Browser", "Account"); }, 'icon-sitemap') function() { frappe.set_route("Accounts Browser", "Account"); }, __("View"))
if (doc.is_group == 1) { if (doc.is_group == 1) {
cur_frm.add_custom_button(__('Convert to non-Group'), cur_frm.add_custom_button(__('Group to Non-Group'),
function() { cur_frm.cscript.convert_to_ledger(); }, 'icon-retweet', 'btn-default'); function() { cur_frm.cscript.convert_to_ledger(); }, 'icon-retweet', 'btn-default');
} else if (cint(doc.is_group) == 0) { } else if (cint(doc.is_group) == 0) {
cur_frm.add_custom_button(__('View Ledger'), function() { cur_frm.add_custom_button(__('Ledger'), function() {
frappe.route_options = { frappe.route_options = {
"account": doc.name, "account": doc.name,
"from_date": sys_defaults.year_start_date, "from_date": sys_defaults.year_start_date,
@ -62,9 +62,9 @@ cur_frm.cscript.add_toolbar_buttons = function(doc) {
"company": doc.company "company": doc.company
}; };
frappe.set_route("query-report", "General Ledger"); frappe.set_route("query-report", "General Ledger");
}, "icon-table"); }, __("View"));
cur_frm.add_custom_button(__('Convert to Group'), cur_frm.add_custom_button(__('Group to Group'),
function() { cur_frm.cscript.convert_to_group(); }, 'icon-retweet', 'btn-default') function() { cur_frm.cscript.convert_to_group(); }, 'icon-retweet', 'btn-default')
} }
} }

View File

@ -27,6 +27,7 @@ class Account(Document):
return return
self.validate_parent() self.validate_parent()
self.validate_root_details() self.validate_root_details()
self.validate_group_or_ledger()
self.set_root_and_report_type() self.set_root_and_report_type()
self.validate_mandatory() self.validate_mandatory()
self.validate_warehouse_account() self.validate_warehouse_account()
@ -81,6 +82,20 @@ class Account(Document):
if not self.parent_account and not self.is_group: if not self.parent_account and not self.is_group:
frappe.throw(_("Root Account must be a group")) frappe.throw(_("Root Account must be a group"))
def validate_group_or_ledger(self):
if self.get("__islocal"):
return
existing_is_group = frappe.db.get_value("Account", self.name, "is_group")
if self.is_group != existing_is_group:
if self.check_gle_exists():
throw(_("Account with existing transaction cannot be converted to ledger"))
elif self.is_group:
if self.account_type:
throw(_("Cannot covert to Group because Account Type is selected."))
elif self.check_if_child_exists():
throw(_("Account with child nodes cannot be set as ledger"))
def validate_frozen_accounts_modifier(self): def validate_frozen_accounts_modifier(self):
old_value = frappe.db.get_value("Account", self.name, "freeze_account") old_value = frappe.db.get_value("Account", self.name, "freeze_account")
if old_value and old_value != self.freeze_account: if old_value and old_value != self.freeze_account:

View File

@ -21,9 +21,11 @@
"in_filter": 0, "in_filter": 0,
"in_list_view": 1, "in_list_view": 1,
"label": "Make Accounting Entry For Every Stock Movement", "label": "Make Accounting Entry For Every Stock Movement",
"length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -43,9 +45,11 @@
"in_filter": 0, "in_filter": 0,
"in_list_view": 1, "in_list_view": 1,
"label": "Accounts Frozen Upto", "label": "Accounts Frozen Upto",
"length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -65,10 +69,12 @@
"in_filter": 0, "in_filter": 0,
"in_list_view": 1, "in_list_view": 1,
"label": "Role Allowed to Set Frozen Accounts & Edit Frozen Entries", "label": "Role Allowed to Set Frozen Accounts & Edit Frozen Entries",
"length": 0,
"no_copy": 0, "no_copy": 0,
"options": "Role", "options": "Role",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -88,10 +94,12 @@
"in_filter": 0, "in_filter": 0,
"in_list_view": 1, "in_list_view": 1,
"label": "Credit Controller", "label": "Credit Controller",
"length": 0,
"no_copy": 0, "no_copy": 0,
"options": "Role", "options": "Role",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -110,10 +118,12 @@
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 0,
"label": "Check Supplier Invoice Number Uniqueness", "label": "Check Supplier Invoice Number Uniqueness",
"length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -131,7 +141,8 @@
"is_submittable": 0, "is_submittable": 0,
"issingle": 1, "issingle": 1,
"istable": 0, "istable": 0,
"modified": "2015-07-14 00:51:48.095525", "max_attachments": 0,
"modified": "2015-12-24 21:42:01.274459",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Accounts Settings", "name": "Accounts Settings",

View File

@ -26,7 +26,7 @@ class BankReconciliation(Document):
t2.parent = t1.name and t2.account = %s t2.parent = t1.name and t2.account = %s
and t1.posting_date >= %s and t1.posting_date <= %s and t1.docstatus=1 and t1.posting_date >= %s and t1.posting_date <= %s and t1.docstatus=1
and ifnull(t1.is_opening, 'No') = 'No' %s and ifnull(t1.is_opening, 'No') = 'No' %s
order by t1.posting_date""" % order by t1.posting_date DESC, t1.name DESC""" %
('%s', '%s', '%s', condition), (self.bank_account, self.from_date, self.to_date), as_dict=1) ('%s', '%s', '%s', condition), (self.bank_account, self.from_date, self.to_date), as_dict=1)
self.set('journal_entries', []) self.set('journal_entries', [])
@ -51,6 +51,7 @@ class BankReconciliation(Document):
if d.cheque_date and getdate(d.clearance_date) < getdate(d.cheque_date): if d.cheque_date and getdate(d.clearance_date) < getdate(d.cheque_date):
frappe.throw(_("Clearance date cannot be before check date in row {0}").format(d.idx)) frappe.throw(_("Clearance date cannot be before check date in row {0}").format(d.idx))
if d.clearance_date or self.include_reconciled_entries:
frappe.db.set_value("Journal Entry", d.voucher_id, "clearance_date", d.clearance_date) frappe.db.set_value("Journal Entry", d.voucher_id, "clearance_date", d.clearance_date)
frappe.db.sql("""update `tabJournal Entry` set clearance_date = %s, modified = %s frappe.db.sql("""update `tabJournal Entry` set clearance_date = %s, modified = %s
where name=%s""", (d.clearance_date, nowdate(), d.voucher_id)) where name=%s""", (d.clearance_date, nowdate(), d.voucher_id))

View File

@ -16,7 +16,7 @@
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 1,
"label": "Voucher ID", "label": "Voucher ID",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
@ -31,7 +31,8 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0,
"width": "50"
}, },
{ {
"allow_on_submit": 0, "allow_on_submit": 0,
@ -56,7 +57,8 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0,
"width": "15"
}, },
{ {
"allow_on_submit": 0, "allow_on_submit": 0,
@ -67,7 +69,7 @@
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 1, "in_list_view": 0,
"label": "Debit", "label": "Debit",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
@ -93,7 +95,7 @@
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 1, "in_list_view": 0,
"label": "Credit", "label": "Credit",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
@ -143,7 +145,7 @@
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"in_filter": 0, "in_filter": 0,
"in_list_view": 0, "in_list_view": 1,
"label": "Posting Date", "label": "Posting Date",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
@ -268,7 +270,7 @@
"istable": 1, "istable": 1,
"max_attachments": 0, "max_attachments": 0,
"menu_index": 0, "menu_index": 0,
"modified": "2015-12-04 11:01:24.286320", "modified": "2016-01-19 12:06:17.568428",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Bank Reconciliation Detail", "name": "Bank Reconciliation Detail",

View File

@ -51,7 +51,7 @@ cur_frm.cscript.refresh = function(doc, cdt, cdn) {
cur_frm.set_intro(intro_txt); cur_frm.set_intro(intro_txt);
cur_frm.add_custom_button(__('Chart of Cost Centers'), cur_frm.add_custom_button(__('Chart of Cost Centers'),
function() { frappe.set_route("Accounts Browser", "Cost Center"); }, 'icon-sitemap') function() { frappe.set_route("Accounts Browser", "Cost Center"); }, __("View"))
} }
cur_frm.cscript.parent_cost_center = function(doc, cdt, cdn) { cur_frm.cscript.parent_cost_center = function(doc, cdt, cdn) {
@ -62,12 +62,12 @@ cur_frm.cscript.parent_cost_center = function(doc, cdt, cdn) {
cur_frm.cscript.hide_unhide_group_ledger = function(doc) { cur_frm.cscript.hide_unhide_group_ledger = function(doc) {
if (doc.is_group == 1) { if (doc.is_group == 1) {
cur_frm.add_custom_button(__('Convert to non-Group'), cur_frm.add_custom_button(__('Convert to Non-Group'),
function() { cur_frm.cscript.convert_to_ledger(); }, 'icon-retweet', function() { cur_frm.cscript.convert_to_ledger(); }, "icon-retweet",
"btn-default") "btn-default")
} else if (doc.is_group == 0) { } else if (doc.is_group == 0) {
cur_frm.add_custom_button(__('Convert to Group'), cur_frm.add_custom_button(__('Convert to Group'),
function() { cur_frm.cscript.convert_to_group(); }, 'icon-retweet', function() { cur_frm.cscript.convert_to_group(); }, "icon-retweet",
"btn-default") "btn-default")
} }
} }

View File

@ -14,7 +14,7 @@ $.extend(cur_frm.cscript, {
this.frm.toggle_enable('year_end_date', doc.__islocal) this.frm.toggle_enable('year_end_date', doc.__islocal)
if (!doc.__islocal && (doc.name != sys_defaults.fiscal_year)) { if (!doc.__islocal && (doc.name != sys_defaults.fiscal_year)) {
this.frm.add_custom_button(__("Set as Default"), this.frm.add_custom_button(__("Default"),
this.frm.cscript.set_as_default, "icon-star"); this.frm.cscript.set_as_default, "icon-star");
this.frm.set_intro(__("To set this Fiscal Year as Default, click on 'Set as Default'")); this.frm.set_intro(__("To set this Fiscal Year as Default, click on 'Set as Default'"));
} else { } else {

View File

@ -11,7 +11,7 @@ frappe.ui.form.on("Journal Entry", {
frm.cscript.voucher_type(frm.doc); frm.cscript.voucher_type(frm.doc);
if(frm.doc.docstatus==1) { if(frm.doc.docstatus==1) {
frm.add_custom_button(__('View Ledger'), function() { frm.add_custom_button(__('Ledger'), function() {
frappe.route_options = { frappe.route_options = {
"voucher_no": frm.doc.name, "voucher_no": frm.doc.name,
"from_date": frm.doc.posting_date, "from_date": frm.doc.posting_date,

View File

@ -351,6 +351,7 @@ class JournalEntry(AccountsController):
def set_print_format_fields(self): def set_print_format_fields(self):
total_amount = 0.0 total_amount = 0.0
bank_account_currency = None bank_account_currency = None
self.pay_to_recd_from = None
for d in self.get('accounts'): for d in self.get('accounts'):
if d.party_type and d.party: if d.party_type and d.party:
if not self.pay_to_recd_from: if not self.pay_to_recd_from:
@ -361,6 +362,9 @@ class JournalEntry(AccountsController):
total_amount += (d.debit_in_account_currency or d.credit_in_account_currency) total_amount += (d.debit_in_account_currency or d.credit_in_account_currency)
bank_account_currency = d.account_currency bank_account_currency = d.account_currency
if not self.pay_to_recd_from:
total_amount = 0
self.set_total_amount(total_amount, bank_account_currency) self.set_total_amount(total_amount, bank_account_currency)
def set_total_amount(self, amt, currency): def set_total_amount(self, amt, currency):
@ -508,7 +512,7 @@ class JournalEntry(AccountsController):
d.party_balance = party_balance[(d.party_type, d.party)] d.party_balance = party_balance[(d.party_type, d.party)]
@frappe.whitelist() @frappe.whitelist()
def get_default_bank_cash_account(company, voucher_type, mode_of_payment=None): def get_default_bank_cash_account(company, voucher_type, mode_of_payment=None, account=None):
from erpnext.accounts.doctype.sales_invoice.sales_invoice import get_bank_cash_account from erpnext.accounts.doctype.sales_invoice.sales_invoice import get_bank_cash_account
if mode_of_payment: if mode_of_payment:
account = get_bank_cash_account(mode_of_payment, company) account = get_bank_cash_account(mode_of_payment, company)
@ -516,11 +520,13 @@ def get_default_bank_cash_account(company, voucher_type, mode_of_payment=None):
account.update({"balance": get_balance_on(account.get("account"))}) account.update({"balance": get_balance_on(account.get("account"))})
return account return account
if not account:
if voucher_type=="Bank Entry": if voucher_type=="Bank Entry":
account = frappe.db.get_value("Company", company, "default_bank_account") account = frappe.db.get_value("Company", company, "default_bank_account")
if not account: if not account:
account = frappe.db.get_value("Account", account = frappe.db.get_value("Account",
{"company": company, "account_type": "Bank", "is_group": 0}) {"company": company, "account_type": "Bank", "is_group": 0})
elif voucher_type=="Cash Entry": elif voucher_type=="Cash Entry":
account = frappe.db.get_value("Company", company, "default_cash_account") account = frappe.db.get_value("Company", company, "default_cash_account")
if not account: if not account:
@ -538,7 +544,7 @@ def get_default_bank_cash_account(company, voucher_type, mode_of_payment=None):
} }
@frappe.whitelist() @frappe.whitelist()
def get_payment_entry_against_order(dt, dn): def get_payment_entry_against_order(dt, dn, amount=None, journal_entry=False, bank_account=None):
ref_doc = frappe.get_doc(dt, dn) ref_doc = frappe.get_doc(dt, dn)
if flt(ref_doc.per_billed, 2) > 0: if flt(ref_doc.per_billed, 2) > 0:
@ -556,6 +562,7 @@ def get_payment_entry_against_order(dt, dn):
party_account = get_party_account(party_type, ref_doc.get(party_type.lower()), ref_doc.company) party_account = get_party_account(party_type, ref_doc.get(party_type.lower()), ref_doc.company)
party_account_currency = get_account_currency(party_account) party_account_currency = get_account_currency(party_account)
if not amount:
if party_account_currency == ref_doc.company_currency: if party_account_currency == ref_doc.company_currency:
amount = flt(ref_doc.base_grand_total) - flt(ref_doc.advance_paid) amount = flt(ref_doc.base_grand_total) - flt(ref_doc.advance_paid)
else: else:
@ -569,11 +576,13 @@ def get_payment_entry_against_order(dt, dn):
"amount_field_bank": amount_field_bank, "amount_field_bank": amount_field_bank,
"amount": amount, "amount": amount,
"remarks": 'Advance Payment received against {0} {1}'.format(dt, dn), "remarks": 'Advance Payment received against {0} {1}'.format(dt, dn),
"is_advance": "Yes" "is_advance": "Yes",
"bank_account": bank_account,
"journal_entry": journal_entry
}) })
@frappe.whitelist() @frappe.whitelist()
def get_payment_entry_against_invoice(dt, dn): def get_payment_entry_against_invoice(dt, dn, amount=None, journal_entry=False, bank_account=None):
ref_doc = frappe.get_doc(dt, dn) ref_doc = frappe.get_doc(dt, dn)
if dt == "Sales Invoice": if dt == "Sales Invoice":
party_type = "Customer" party_type = "Customer"
@ -597,24 +606,28 @@ def get_payment_entry_against_invoice(dt, dn):
"party_account_currency": ref_doc.party_account_currency, "party_account_currency": ref_doc.party_account_currency,
"amount_field_party": amount_field_party, "amount_field_party": amount_field_party,
"amount_field_bank": amount_field_bank, "amount_field_bank": amount_field_bank,
"amount": abs(ref_doc.outstanding_amount), "amount": amount if amount else abs(ref_doc.outstanding_amount),
"remarks": 'Payment received against {0} {1}. {2}'.format(dt, dn, ref_doc.remarks), "remarks": 'Payment received against {0} {1}. {2}'.format(dt, dn, ref_doc.remarks),
"is_advance": "No" "is_advance": "No",
"bank_account": bank_account,
"journal_entry": journal_entry
}) })
def get_payment_entry(ref_doc, args): def get_payment_entry(ref_doc, args):
cost_center = frappe.db.get_value("Company", ref_doc.company, "cost_center") cost_center = frappe.db.get_value("Company", ref_doc.company, "cost_center")
exchange_rate = 1
if args.get("party_account"):
exchange_rate = get_exchange_rate(args.get("party_account"), args.get("party_account_currency"), exchange_rate = get_exchange_rate(args.get("party_account"), args.get("party_account_currency"),
ref_doc.company, ref_doc.doctype, ref_doc.name) ref_doc.company, ref_doc.doctype, ref_doc.name)
jv = frappe.new_doc("Journal Entry") je = frappe.new_doc("Journal Entry")
jv.update({ je.update({
"voucher_type": "Bank Entry", "voucher_type": "Bank Entry",
"company": ref_doc.company, "company": ref_doc.company,
"remark": args.get("remarks") "remark": args.get("remarks")
}) })
party_row = jv.append("accounts", { party_row = je.append("accounts", {
"account": args.get("party_account"), "account": args.get("party_account"),
"party_type": args.get("party_type"), "party_type": args.get("party_type"),
"party": ref_doc.get(args.get("party_type").lower()), "party": ref_doc.get(args.get("party_type").lower()),
@ -631,8 +644,10 @@ def get_payment_entry(ref_doc, args):
"reference_name": ref_doc.name "reference_name": ref_doc.name
}) })
bank_row = jv.append("accounts") bank_row = je.append("accounts")
bank_account = get_default_bank_cash_account(ref_doc.company, "Bank Entry")
#make it bank_details
bank_account = get_default_bank_cash_account(ref_doc.company, "Bank Entry", account=args.get("bank_account"))
if bank_account: if bank_account:
bank_row.update(bank_account) bank_row.update(bank_account)
bank_row.exchange_rate = get_exchange_rate(bank_account["account"], bank_row.exchange_rate = get_exchange_rate(bank_account["account"],
@ -648,12 +663,12 @@ def get_payment_entry(ref_doc, args):
# set multi currency check # set multi currency check
if party_row.account_currency != ref_doc.company_currency \ if party_row.account_currency != ref_doc.company_currency \
or (bank_row.account_currency and bank_row.account_currency != ref_doc.company_currency): or (bank_row.account_currency and bank_row.account_currency != ref_doc.company_currency):
jv.multi_currency = 1 je.multi_currency = 1
jv.set_amounts_in_company_currency() je.set_amounts_in_company_currency()
jv.set_total_debit_credit() je.set_total_debit_credit()
return jv.as_dict() return je if args.get("journal_entry") else je.as_dict()
@frappe.whitelist() @frappe.whitelist()
def get_opening_accounts(company): def get_opening_accounts(company):

View File

@ -0,0 +1,118 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "field:gateway",
"creation": "2015-12-15 22:26:45.221162",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "gateway",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Gateway",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"in_create": 1,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2016-01-18 03:58:22.588834",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Gateway",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Administrator",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 0,
"role": "System Manager",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 0,
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
}
],
"read_only": 1,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC"
}

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
class PaymentGateway(Document):
pass

View File

@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import frappe
import unittest
# test_records = frappe.get_test_records('Payment Gateway')
class TestPaymentGateway(unittest.TestCase):
pass

View File

@ -0,0 +1,6 @@
cur_frm.cscript.refresh = function(doc, dt, dn){
if(!doc.__islocal){
var df = frappe.meta.get_docfield(doc.doctype, "gateway", doc.name);
df.read_only = 1;
}
}

View File

@ -0,0 +1,293 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"creation": "2015-12-23 21:31:52.699821",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "gateway",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Payment Gateway",
"length": 0,
"no_copy": 0,
"options": "Payment Gateway",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "is_default",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Is Default",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "column_break_4",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "payment_account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Payment Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "currency",
"fieldtype": "Read Only",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Currency",
"length": 0,
"no_copy": 0,
"options": "payment_account.account_currency",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "payment_request_message",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"default": "Please click on the link below to make your payment",
"fieldname": "message",
"fieldtype": "Text Editor",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Default Payment Request Message",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"default": "Click here to make a payment",
"fieldname": "payment_url_message",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Payment URL Message",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "payment_success_url",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Payment Success URL",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2016-01-18 03:53:50.534673",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Gateway Account",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Administrator",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"read_only": 0,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC"
}

View File

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
class PaymentGatewayAccount(Document):
def autoname(self):
self.name = self.gateway + " - " + self.currency
def validate(self):
self.update_default_payment_gateway()
self.set_as_default_if_not_set()
def update_default_payment_gateway(self):
if self.is_default:
frappe.db.sql("""update `tabPayment Gateway Account` set is_default = 0
where is_default = 1 """)
def set_as_default_if_not_set(self):
if not frappe.db.get_value("Payment Gateway Account", {"is_default": 1, "name": ("!=", self.name)}, "name"):
self.is_default = 1

View File

@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import frappe
import unittest
# test_records = frappe.get_test_records('Payment Gateway Account')
class TestPaymentGatewayAccount(unittest.TestCase):
pass

View File

@ -0,0 +1,34 @@
cur_frm.add_fetch("payment_gateway", "payment_account", "payment_account")
cur_frm.add_fetch("payment_gateway", "gateway", "gateway")
cur_frm.add_fetch("payment_gateway", "message", "message")
cur_frm.add_fetch("payment_gateway", "payment_url_message", "payment_url_message")
cur_frm.add_fetch("payment_gateway", "payment_success_url", "payment_success_url")
frappe.ui.form.on("Payment Request", "onload", function(frm, dt, dn){
if (frm.doc.reference_doctype) {
frappe.call({
method:"erpnext.accounts.doctype.payment_request.payment_request.get_print_format_list",
args: {"ref_doctype": frm.doc.reference_doctype},
callback:function(r){
set_field_options("print_format", r.message["print_format"])
}
})
}
})
frappe.ui.form.on("Payment Request", "refresh", function(frm) {
frm.add_custom_button(__('Resend Payment Email'), function(){
frappe.call({
method: "erpnext.accounts.doctype.payment_request.payment_request.resend_payment_email",
args: {"docname": frm.doc.name},
freeze: true,
freeze_message: __("Sending"),
callback: function(r){
if(!r.exc) {
frappe.msgprint(__("Message Sent"));
}
}
});
});
});

View File

@ -0,0 +1,678 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "PR.######",
"creation": "2015-12-15 22:23:24.745065",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "payment_details",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Payment Details",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Amount",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "2",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "currency",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Currency",
"length": 0,
"no_copy": 0,
"options": "Currency",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"depends_on": "eval:doc.reference_doctype==\"Sales Order\"",
"fieldname": "make_sales_invoice",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Make Sales Invoice",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "column_break_5",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"default": "Draft",
"fieldname": "status",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Status",
"length": 0,
"no_copy": 0,
"options": "\nDraft\nInitiated\nPaid\nFailed\nCancelled",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "section_break_7",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "payment_gateway",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Payment Gateway",
"length": 0,
"no_copy": 0,
"options": "Payment Gateway Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "payment_success_url",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Payment Success URL",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "column_break_9",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "gateway",
"fieldtype": "Read Only",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Gateway",
"length": 0,
"no_copy": 0,
"options": "payment_gateway.gateway",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "payment_account",
"fieldtype": "Read Only",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Payment Account",
"length": 0,
"no_copy": 0,
"options": "payment_gateway.payment_account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "recipient_and_message",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Recipient and Message",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"default": "",
"fieldname": "print_format",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Print Format",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "mute_email",
"fieldtype": "Check",
"hidden": 1,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Mute Email",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "email_to",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Email To",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"fieldname": "subject",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Subject",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "message",
"fieldtype": "Text Editor",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Message",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "payment_url_message",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Payment URL Message",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "payment_url",
"fieldtype": "Data",
"hidden": 1,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "payment_url",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "reference_details",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Reference Details",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "reference_doctype",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Reference Doctype",
"length": 0,
"no_copy": 1,
"options": "DocType",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "reference_name",
"fieldtype": "Dynamic Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Reference Name",
"length": 0,
"no_copy": 1,
"options": "reference_doctype",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "amended_from",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Amended From",
"length": 0,
"no_copy": 1,
"options": "Payment Request",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 1,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2016-01-11 05:49:28.342786",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Request",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 1,
"apply_user_permissions": 0,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1
},
{
"amend": 1,
"apply_user_permissions": 0,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Administrator",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1
}
],
"read_only": 0,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC"
}

View File

@ -0,0 +1,234 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import flt, nowdate, get_url, cstr
from erpnext.accounts.party import get_party_account
from erpnext.accounts.utils import get_account_currency, get_balance_on
from erpnext.accounts.doctype.journal_entry.journal_entry import (get_payment_entry_against_invoice,
get_payment_entry_against_order)
from itertools import chain
class PaymentRequest(Document):
def validate(self):
self.validate_payment_gateway_account()
self.validate_payment_request()
self.validate_currency()
def validate_payment_request(self):
if frappe.db.get_value("Payment Request", {"reference_name": self.reference_name,
"name": ("!=", self.name), "status": ("not in", ["Initiated", "Paid"]), "docstatus": 1}, "name"):
frappe.throw(_("Payment Request already exists {0}".fomart(self.reference_name)))
def validate_currency(self):
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
if ref_doc.currency != frappe.db.get_value("Account", self.payment_account, "account_currency"):
frappe.throw(_("Transaction currency must be same as Payment Gateway currency"))
def validate_payment_gateway_account(self):
if not self.payment_gateway:
frappe.throw(_("Payment Gateway Account is not configured"))
def validate_payment_gateway(self):
if self.gateway == "PayPal":
if not frappe.db.get_value("PayPal Settings", None, "api_username"):
if not frappe.conf.paypal_username:
frappe.throw(_("PayPal Settings missing"))
def on_submit(self):
if not self.mute_email:
self.send_payment_request()
self.send_email()
self.make_communication_entry()
def on_cancel(self):
self.set_as_cancelled()
def on_update_after_submit(self):
pass
def set_status(self):
pass
def get_payment_url(self):
pass
def make_invoice(self):
if self.make_sales_invoice:
from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice
si = make_sales_invoice(self.reference_name, ignore_permissions=True)
si = si.insert(ignore_permissions=True)
si.submit()
def send_payment_request(self):
self.payment_url = get_url("/api/method/erpnext.accounts.doctype.payment_request.payment_request.generate_payment_request?name={0}".format(self.name))
if self.payment_url:
frappe.db.set_value(self.doctype, self.name, "status", "Initiated")
def set_as_paid(self):
if frappe.session.user == "Guest":
frappe.set_user("Administrator")
jv = self.create_journal_entry()
self.make_invoice()
return jv
def create_journal_entry(self):
"""create entry"""
payment_details = {
"amount": self.amount,
"journal_entry": True,
"bank_account": self.payment_account
}
frappe.flags.ignore_account_permission = True
if self.reference_doctype == "Sales Order":
jv = get_payment_entry_against_order(self.reference_doctype, self.reference_name,\
amount=self.amount, journal_entry=True, bank_account=self.payment_account)
if self.reference_doctype == "Sales Invoice":
jv = get_payment_entry_against_invoice(self.reference_doctype, self.reference_name,\
amount=self.amount, journal_entry=True, bank_account=self.payment_account)
jv.update({
"voucher_type": "Journal Entry",
"posting_date": nowdate()
})
jv.insert(ignore_permissions=True)
jv.submit()
#set status as paid for Payment Request
frappe.db.set_value(self.doctype, self.name, "status", "Paid")
return jv
def send_email(self):
"""send email with payment link"""
frappe.sendmail(recipients=self.email_to, sender=None, subject=self.subject,
message=self.get_message(), attachments=[frappe.attach_print(self.reference_doctype,
self.reference_name, file_name=self.reference_name, print_format=self.print_format)])
def get_message(self):
"""return message with payment gateway link"""
return cstr(self.message) + " <a href='{0}'>{1}</a>".format(self.payment_url, \
self.payment_url_message or _(" Click here to pay"))
def set_failed(self):
pass
def set_as_cancelled(self):
frappe.db.set_value(self.doctype, self.name, "status", "Cancelled")
def make_communication_entry(self):
"""Make communication entry"""
comm = frappe.get_doc({
"doctype":"Communication",
"subject": self.subject,
"content": self.get_message(),
"sent_or_received": "Sent",
"reference_doctype": self.reference_doctype,
"reference_name": self.reference_name
})
comm.insert(ignore_permissions=True)
def get_payment_success_url(self):
return self.payment_success_url
@frappe.whitelist(allow_guest=True)
def make_payment_request(**args):
"""Make payment request"""
args = frappe._dict(args)
ref_doc = frappe.get_doc(args.dt, args.dn)
gateway_account = get_gateway_details(args)
pr = frappe.new_doc("Payment Request")
pr.update({
"payment_gateway": gateway_account.name,
"gateway": gateway_account.gateway,
"payment_account": gateway_account.payment_account,
"currency": ref_doc.currency,
"make_sales_invoice": args.cart or 0,
"amount": get_amount(ref_doc, args.dt),
"mute_email": args.mute_email or 0,
"email_to": args.recipient_id or "",
"subject": "Payment Request for %s"%args.dn,
"message": gateway_account.message,
"payment_url_message": gateway_account.payment_url_message,
"payment_success_url": gateway_account.payment_success_url,
"reference_doctype": args.dt,
"reference_name": args.dn
})
if args.return_doc:
return pr
if args.submit_doc:
pr.insert(ignore_permissions=True)
pr.submit()
if args.cart:
generate_payment_request(pr.name)
frappe.db.commit()
if not args.cart:
return pr
return pr.as_dict()
def get_amount(ref_doc, dt):
"""get amount based on doctype"""
if dt == "Sales Order":
amount = flt(ref_doc.base_grand_total) - flt(ref_doc.advance_paid)
if dt == "Sales Invoice":
amount = abs(ref_doc.outstanding_amount)
if amount > 0:
return amount
else:
frappe.throw(_("Payment Entry is already created"))
def get_gateway_details(args):
"""return gateway and payment account of default payment gateway"""
if args.payemnt_gateway:
gateway_account = frappe.db.get_value("Payment Gateway Account", args.payemnt_gateway,
["name", "gateway", "payment_account", "message", "payment_url_message", "payment_success_url"],
as_dict=1)
gateway_account = frappe.db.get_value("Payment Gateway Account", {"is_default": 1},
["name", "gateway", "payment_account", "message", "payment_url_message", "payment_success_url"],
as_dict=1)
if not gateway_account:
frappe.throw(_("Payment Gateway Account is not configured"))
return gateway_account
@frappe.whitelist()
def get_print_format_list(ref_doctype):
print_format_list = ["Standard"]
print_format_list.extend([p.name for p in frappe.get_all("Print Format",
filters={"doc_type": ref_doctype})])
return {
"print_format": print_format_list
}
@frappe.whitelist(allow_guest=True)
def generate_payment_request(name):
frappe.get_doc("Payment Request", name).run_method("get_payment_url")
@frappe.whitelist(allow_guest=True)
def resend_payment_email(docname):
return frappe.get_doc("Payment Request", docname).send_email()

View File

@ -0,0 +1,17 @@
frappe.listview_settings['Payment Request'] = {
add_fields: ["status"],
get_indicator: function(doc) {
if(doc.status == "Draft") {
return [__("Draft"), "darkgrey", "status,=,Draft"];
}
else if(doc.status == "Initiated") {
return [__("Initiated"), "green", "status,=,Initiated"];
}
else if(doc.status == "Paid") {
return [__("Paid"), "blue", "status,=,Paid"];
}
else if(doc.status == "Cancelled") {
return [__("Cancelled"), "orange", "status,=,Cancelled"];
}
}
}

View File

@ -0,0 +1,79 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import frappe
import unittest
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
# test_records = frappe.get_test_records('Payment Request')
test_dependencies = ["Currency Exchange", "Journal Entry", "Contact", "Address"]
payment_gateway = {
"doctype": "Payment Gateway",
"gateway": "_Test Gateway"
}
payment_method = [
{
"doctype": "Payment Gateway Account",
"is_default": 1,
"gateway": "_Test Gateway",
"payment_account": "_Test Bank - _TC",
"currency": "INR"
},
{
"doctype": "Payment Gateway Account",
"gateway": "_Test Gateway",
"payment_account": "_Test Bank - _TC",
"currency": "USD"
}
]
class TestPaymentRequest(unittest.TestCase):
def setUp(self):
if not frappe.db.get_value("Payment Gateway", payment_gateway["gateway"], "name"):
frappe.get_doc(payment_gateway).insert(ignore_permissions=True)
for method in payment_method:
if not frappe.db.get_value("Payment Gateway Account", {"gateway": method["gateway"],
"currency": method["currency"]}, "name"):
frappe.get_doc(method).insert(ignore_permissions=True)
def test_payment_request_linkings(self):
SO_INR = make_sales_order(currency="INR")
pr = make_payment_request(dt="Sales Order", dn=SO_INR.name, recipient_id="saurabh@erpnext.com")
self.assertEquals(pr.reference_doctype, "Sales Order")
self.assertEquals(pr.reference_name, SO_INR.name)
self.assertEquals(pr.currency, "INR")
SI_USD = create_sales_invoice(currency="USD", conversion_rate=50)
pr = make_payment_request(dt="Sales Invoice", dn=SI_USD.name, recipient_id="saurabh@erpnext.com")
self.assertEquals(pr.reference_doctype, "Sales Invoice")
self.assertEquals(pr.reference_name, SI_USD.name)
self.assertEquals(pr.currency, "USD")
def test_payment_entry(self):
SO_INR = make_sales_order(currency="INR")
pr = make_payment_request(dt="Sales Order", dn=SO_INR.name, recipient_id="saurabh@erpnext.com",
mute_email=1, submit_doc=1)
jv = pr.set_as_paid()
SO_INR = frappe.get_doc("Sales Order", SO_INR.name)
self.assertEquals(SO_INR.advance_paid, jv.total_debit)
SI_USD = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC",
currency="USD", conversion_rate=50)
pr = make_payment_request(dt="Sales Invoice", dn=SI_USD.name, recipient_id="saurabh@erpnext.com",
mute_email=1, return_doc=1, payemnt_gateway="_Test Gateway - USD")
self.assertRaises(frappe.ValidationError, pr.save)

View File

@ -1,8 +1,8 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_import": 1, "allow_import": 1,
"allow_rename": 0, "allow_rename": 1,
"autoname": "PRULE.#####", "autoname": "field:title",
"creation": "2014-02-21 15:02:51", "creation": "2014-02-21 15:02:51",
"custom": 0, "custom": 0,
"docstatus": 0, "docstatus": 0,
@ -24,6 +24,7 @@
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -47,6 +48,7 @@
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 1, "reqd": 1,
@ -71,6 +73,7 @@
"options": "\nItem Code\nItem Group\nBrand", "options": "\nItem Code\nItem Group\nBrand",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 1, "reqd": 1,
@ -95,6 +98,7 @@
"options": "Item", "options": "Item",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -119,6 +123,7 @@
"options": "Brand", "options": "Brand",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -143,6 +148,7 @@
"options": "Item Group", "options": "Item Group",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -165,6 +171,7 @@
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -189,6 +196,7 @@
"options": "\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20", "options": "\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -211,6 +219,7 @@
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -233,6 +242,7 @@
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -255,6 +265,7 @@
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -277,6 +288,7 @@
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -299,6 +311,7 @@
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -323,6 +336,7 @@
"options": "\nCustomer\nCustomer Group\nTerritory\nSales Partner\nCampaign\nSupplier\nSupplier Type", "options": "\nCustomer\nCustomer Group\nTerritory\nSales Partner\nCampaign\nSupplier\nSupplier Type",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -347,6 +361,7 @@
"options": "Customer", "options": "Customer",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -371,6 +386,7 @@
"options": "Customer Group", "options": "Customer Group",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -395,6 +411,7 @@
"options": "Territory", "options": "Territory",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -419,6 +436,7 @@
"options": "Sales Partner", "options": "Sales Partner",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -443,6 +461,7 @@
"options": "Campaign", "options": "Campaign",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -467,6 +486,7 @@
"options": "Supplier", "options": "Supplier",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -491,6 +511,7 @@
"options": "Supplier Type", "options": "Supplier Type",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -513,6 +534,7 @@
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -535,6 +557,7 @@
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -557,6 +580,7 @@
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -579,6 +603,7 @@
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -601,6 +626,7 @@
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -624,6 +650,7 @@
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -646,6 +673,7 @@
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -667,6 +695,7 @@
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -690,6 +719,7 @@
"options": "Company", "options": "Company",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -712,6 +742,7 @@
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -736,6 +767,7 @@
"options": "\nPrice\nDiscount Percentage", "options": "\nPrice\nDiscount Percentage",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 1, "reqd": 1,
@ -757,6 +789,7 @@
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -780,6 +813,7 @@
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -803,6 +837,7 @@
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -827,6 +862,7 @@
"options": "Price List", "options": "Price List",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -850,6 +886,7 @@
"options": "Simple", "options": "Simple",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -872,6 +909,7 @@
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -890,7 +928,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2015-11-16 06:29:51.958974", "modified": "2016-01-15 04:05:11.633824",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Pricing Rule", "name": "Pricing Rule",
@ -1001,5 +1039,5 @@
"read_only_onload": 0, "read_only_onload": 0,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"title_field": "title" "title_field": ""
} }

View File

@ -76,7 +76,7 @@ class PricingRule(Document):
def apply_pricing_rule(args): def apply_pricing_rule(args):
""" """
args = { args = {
"item_list": [{"doctype": "", "name": "", "item_code": "", "brand": "", "item_group": ""}, ...], "items": [{"doctype": "", "name": "", "item_code": "", "brand": "", "item_group": ""}, ...],
"customer": "something", "customer": "something",
"customer_group": "something", "customer_group": "something",
"territory": "something", "territory": "something",
@ -98,17 +98,16 @@ def apply_pricing_rule(args):
args = frappe._dict(args) args = frappe._dict(args)
if not args.transaction_type:
set_transaction_type(args)
# list of dictionaries # list of dictionaries
out = [] out = []
if args.get("parenttype") == "Material Request": return out if args.get("doctype") == "Material Request": return out
if not args.transaction_type: item_list = args.get("items")
args.transaction_type = "buying" if frappe.get_meta(args.parenttype).get_field("supplier") \ args.pop("items")
else "selling"
item_list = args.get("item_list")
args.pop("item_list")
for item in item_list: for item in item_list:
args_copy = copy.deepcopy(args) args_copy = copy.deepcopy(args)
@ -138,13 +137,17 @@ def get_pricing_rule_for_item(args):
if not args.item_group: if not args.item_group:
frappe.throw(_("Item Group not mentioned in item master for item {0}").format(args.item_code)) frappe.throw(_("Item Group not mentioned in item master for item {0}").format(args.item_code))
if args.transaction_type=="selling":
if args.customer and not (args.customer_group and args.territory): if args.customer and not (args.customer_group and args.territory):
customer = frappe.db.get_value("Customer", args.customer, ["customer_group", "territory"]) customer = frappe.db.get_value("Customer", args.customer, ["customer_group", "territory"])
if customer: if customer:
args.customer_group, args.territory = customer args.customer_group, args.territory = customer
args.supplier = args.supplier_type = None
elif args.supplier and not args.supplier_type: elif args.supplier and not args.supplier_type:
args.supplier_type = frappe.db.get_value("Supplier", args.supplier, "supplier_type") args.supplier_type = frappe.db.get_value("Supplier", args.supplier, "supplier_type")
args.customer = args.customer_group = args.territory = None
pricing_rules = get_pricing_rules(args) pricing_rules = get_pricing_rules(args)
pricing_rule = filter_pricing_rules(args, pricing_rules) pricing_rule = filter_pricing_rules(args, pricing_rules)
@ -184,9 +187,12 @@ def get_pricing_rules(args):
conditions = "" conditions = ""
values = {"item_code": args.get("item_code"), "brand": args.get("brand")}
for field in ["company", "customer", "supplier", "supplier_type", "campaign", "sales_partner"]: for field in ["company", "customer", "supplier", "supplier_type", "campaign", "sales_partner"]:
if args.get(field): if args.get(field):
conditions += " and ifnull("+field+", '') in (%("+field+")s, '')" conditions += " and ifnull("+field+", '') in (%("+field+")s, '')"
values[field] = args.get(field)
else: else:
conditions += " and ifnull("+field+", '') = ''" conditions += " and ifnull("+field+", '') = ''"
@ -194,12 +200,15 @@ def get_pricing_rules(args):
group_condition = _get_tree_conditions(parenttype) group_condition = _get_tree_conditions(parenttype)
if group_condition: if group_condition:
conditions += " and " + group_condition conditions += " and " + group_condition
if not args.price_list: args.price_list = None if not args.price_list: args.price_list = None
conditions += " and ifnull(for_price_list, '') in (%(price_list)s, '')" conditions += " and ifnull(for_price_list, '') in (%(price_list)s, '')"
values["price_list"] = args.get("price_list")
if args.get("transaction_date"): if args.get("transaction_date"):
conditions += """ and %(transaction_date)s between ifnull(valid_from, '2000-01-01') conditions += """ and %(transaction_date)s between ifnull(valid_from, '2000-01-01')
and ifnull(valid_upto, '2500-12-31')""" and ifnull(valid_upto, '2500-12-31')"""
values['transaction_date'] = args.get('transaction_date')
item_group_condition = _get_tree_conditions("Item Group", False) item_group_condition = _get_tree_conditions("Item Group", False)
if item_group_condition: item_group_condition = " or " + item_group_condition if item_group_condition: item_group_condition = " or " + item_group_condition
@ -210,7 +219,8 @@ def get_pricing_rules(args):
and {transaction_type} = 1 {conditions} and {transaction_type} = 1 {conditions}
order by priority desc, name desc""".format( order by priority desc, name desc""".format(
item_group_condition=item_group_condition, item_group_condition=item_group_condition,
transaction_type=args.transaction_type, conditions=conditions), args, as_dict=1) transaction_type= args.transaction_type,
conditions=conditions), values, as_dict=1)
def filter_pricing_rules(args, pricing_rules): def filter_pricing_rules(args, pricing_rules):
# filter for qty # filter for qty
@ -267,3 +277,14 @@ def apply_internal_priority(pricing_rules, field_set, args):
if filtered_rules: break if filtered_rules: break
return filtered_rules or pricing_rules return filtered_rules or pricing_rules
def set_transaction_type(args):
if args.doctype in ("Opportunity", "Quotation", "Sales Order", "Delivery Note", "Sales Invoice"):
args.transaction_type = "selling"
elif args.doctype in ("Material Request", "Supplier Quotation", "Purchase Order",
"Purchase Receipt", "Purchase Invoice"):
args.transaction_type = "buying"
elif args.customer:
args.transaction_type = "selling"
else:
args.transaction_type = "buying"

View File

@ -31,14 +31,12 @@ class TestPricingRule(unittest.TestCase):
"company": "_Test Company", "company": "_Test Company",
"price_list": "_Test Price List", "price_list": "_Test Price List",
"currency": "_Test Currency", "currency": "_Test Currency",
"parenttype": "Sales Order", "doctype": "Sales Order",
"conversion_rate": 1, "conversion_rate": 1,
"price_list_currency": "_Test Currency", "price_list_currency": "_Test Currency",
"plc_conversion_rate": 1, "plc_conversion_rate": 1,
"order_type": "Sales", "order_type": "Sales",
"transaction_type": "selling",
"customer": "_Test Customer", "customer": "_Test Customer",
"doctype": "Sales Order Item",
"name": None "name": None
}) })
details = get_item_details(args) details = get_item_details(args)
@ -46,7 +44,9 @@ class TestPricingRule(unittest.TestCase):
prule = frappe.get_doc(test_record.copy()) prule = frappe.get_doc(test_record.copy())
prule.applicable_for = "Customer" prule.applicable_for = "Customer"
prule.title = "_Test Pricing Rule for Customer"
self.assertRaises(MandatoryError, prule.insert) self.assertRaises(MandatoryError, prule.insert)
prule.customer = "_Test Customer" prule.customer = "_Test Customer"
prule.discount_percentage = 20 prule.discount_percentage = 20
prule.insert() prule.insert()
@ -56,16 +56,18 @@ class TestPricingRule(unittest.TestCase):
prule = frappe.get_doc(test_record.copy()) prule = frappe.get_doc(test_record.copy())
prule.apply_on = "Item Group" prule.apply_on = "Item Group"
prule.item_group = "All Item Groups" prule.item_group = "All Item Groups"
prule.title = "_Test Pricing Rule for Item Group"
prule.discount_percentage = 15 prule.discount_percentage = 15
prule.insert() prule.insert()
args.customer = None args.customer = "_Test Customer 1"
details = get_item_details(args) details = get_item_details(args)
self.assertEquals(details.get("discount_percentage"), 10) self.assertEquals(details.get("discount_percentage"), 10)
prule = frappe.get_doc(test_record.copy()) prule = frappe.get_doc(test_record.copy())
prule.applicable_for = "Campaign" prule.applicable_for = "Campaign"
prule.campaign = "_Test Campaign" prule.campaign = "_Test Campaign"
prule.title = "_Test Pricing Rule for Campaign"
prule.discount_percentage = 5 prule.discount_percentage = 5
prule.priority = 8 prule.priority = 8
prule.insert() prule.insert()

View File

@ -25,13 +25,14 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
if(!doc.is_return) { if(!doc.is_return) {
if(doc.docstatus==1) { if(doc.docstatus==1) {
if(doc.outstanding_amount != 0) { if(doc.outstanding_amount != 0) {
this.frm.add_custom_button(__('Payment'), this.make_bank_entry).addClass("btn-primary"); this.frm.add_custom_button(__('Payment'), this.make_bank_entry, __("Make"));
cur_frm.page.set_inner_btn_group_as_primary(__("Make"));
} }
cur_frm.add_custom_button(__('Debit Note'), this.make_debit_note); cur_frm.add_custom_button(__('Debit Note'), this.make_debit_note, __("Make"));
} }
if(doc.docstatus===0) { if(doc.docstatus===0) {
cur_frm.add_custom_button(__('From Purchase Order'), function() { cur_frm.add_custom_button(__('Purchase Order'), function() {
frappe.model.map_current_doc({ frappe.model.map_current_doc({
method: "erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_invoice", method: "erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_invoice",
source_doctype: "Purchase Order", source_doctype: "Purchase Order",
@ -43,9 +44,9 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
company: cur_frm.doc.company company: cur_frm.doc.company
} }
}) })
}); }, __("Get items from"));
cur_frm.add_custom_button(__('From Purchase Receipt'), function() { cur_frm.add_custom_button(__('Purchase Receipt'), function() {
frappe.model.map_current_doc({ frappe.model.map_current_doc({
method: "erpnext.stock.doctype.purchase_receipt.purchase_receipt.make_purchase_invoice", method: "erpnext.stock.doctype.purchase_receipt.purchase_receipt.make_purchase_invoice",
source_doctype: "Purchase Receipt", source_doctype: "Purchase Receipt",
@ -56,7 +57,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
company: cur_frm.doc.company company: cur_frm.doc.company
} }
}) })
}); }, __("Get items from"));
} }
} }
}, },

View File

@ -261,15 +261,19 @@ class PurchaseInvoice(BuyingController):
gl_entries = [] gl_entries = []
# parent's gl entry # parent's gl entry
if self.base_grand_total: if self.grand_total:
# Didnot use base_grand_total to book rounding loss gle
grand_total_in_company_currency = flt(self.grand_total * self.conversion_rate,
self.precision("grand_total"))
gl_entries.append( gl_entries.append(
self.get_gl_dict({ self.get_gl_dict({
"account": self.credit_to, "account": self.credit_to,
"party_type": "Supplier", "party_type": "Supplier",
"party": self.supplier, "party": self.supplier,
"against": self.against_expense_account, "against": self.against_expense_account,
"credit": self.base_grand_total, "credit": grand_total_in_company_currency,
"credit_in_account_currency": self.base_grand_total \ "credit_in_account_currency": grand_total_in_company_currency \
if self.party_account_currency==self.company_currency else self.grand_total, if self.party_account_currency==self.company_currency else self.grand_total,
"against_voucher": self.return_against if cint(self.is_return) else self.name, "against_voucher": self.return_against if cint(self.is_return) else self.name,
"against_voucher_type": self.doctype, "against_voucher_type": self.doctype,

View File

@ -58,7 +58,8 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
}) })
cur_frm.add_custom_button(doc.update_stock ? __('Sales Return') : __('Credit Note'), cur_frm.add_custom_button(doc.update_stock ? __('Sales Return') : __('Credit Note'),
this.make_sales_return); this.make_sales_return, __("Make"));
cur_frm.page.set_inner_btn_group_as_primary(__("Make"));
if(cint(doc.update_stock)!=1) { if(cint(doc.update_stock)!=1) {
// show Make Delivery Note button only if Sales Invoice is not created from Delivery Note // show Make Delivery Note button only if Sales Invoice is not created from Delivery Note
@ -69,12 +70,13 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
}); });
if(!from_delivery_note && !is_delivered_by_supplier) { if(!from_delivery_note && !is_delivered_by_supplier) {
cur_frm.add_custom_button(__('Delivery'), cur_frm.cscript['Make Delivery Note']).addClass("btn-primary"); cur_frm.add_custom_button(__('Delivery'), cur_frm.cscript['Delivery Note'], __("Make"));
} }
} }
if(doc.outstanding_amount!=0 && !cint(doc.is_return)) { if(doc.outstanding_amount!=0 && !cint(doc.is_return)) {
cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_bank_entry).addClass("btn-primary"); cur_frm.add_custom_button(__('Payment Request'), this.make_payment_request, __("Make"));
cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_bank_entry, __("Make"));
} }
} }
@ -104,7 +106,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
}, },
sales_order_btn: function() { sales_order_btn: function() {
this.$sales_order_btn = cur_frm.add_custom_button(__('From Sales Order'), this.$sales_order_btn = cur_frm.add_custom_button(__('Sales Order'),
function() { function() {
frappe.model.map_current_doc({ frappe.model.map_current_doc({
method: "erpnext.selling.doctype.sales_order.sales_order.make_sales_invoice", method: "erpnext.selling.doctype.sales_order.sales_order.make_sales_invoice",
@ -117,11 +119,11 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
company: cur_frm.doc.company company: cur_frm.doc.company
} }
}) })
}); }, __("Get items from"));
}, },
delivery_note_btn: function() { delivery_note_btn: function() {
this.$delivery_note_btn = cur_frm.add_custom_button(__('From Delivery Note'), this.$delivery_note_btn = cur_frm.add_custom_button(__('Delivery Note'),
function() { function() {
frappe.model.map_current_doc({ frappe.model.map_current_doc({
method: "erpnext.stock.doctype.delivery_note.delivery_note.make_sales_invoice", method: "erpnext.stock.doctype.delivery_note.delivery_note.make_sales_invoice",
@ -137,7 +139,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
}; };
} }
}); });
}); }, __("Get items from"));
}, },
tc_name: function() { tc_name: function() {
@ -435,9 +437,11 @@ cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
}) })
if(cur_frm.doc.is_pos) { if(cur_frm.doc.is_pos) {
cur_frm.msgbox = frappe.msgprint('<a class="btn btn-primary" \ cur_frm.msgbox = frappe.msgprint(format('<a class="btn btn-primary" \
onclick="cur_frm.print_preview.printit(true)" style="margin-right: 5px;">Print</a>\ onclick="cur_frm.print_preview.printit(true)" style="margin-right: 5px;">{0}</a>\
<a class="btn btn-default" href="#Form/Sales Invoice/New Sales Invoice">New</a>'); <a class="btn btn-default" href="javascript:new_doc(cur_frm.doctype);">{1}</a>', [
__('Print'), __('New')
]));
} else if(cint(frappe.boot.notification_settings.sales_invoice)) { } else if(cint(frappe.boot.notification_settings.sales_invoice)) {
cur_frm.email_doc(frappe.boot.notification_settings.sales_invoice_message); cur_frm.email_doc(frappe.boot.notification_settings.sales_invoice_message);

View File

@ -531,14 +531,18 @@ class SalesInvoice(SellingController):
def make_customer_gl_entry(self, gl_entries): def make_customer_gl_entry(self, gl_entries):
if self.grand_total: if self.grand_total:
# Didnot use base_grand_total to book rounding loss gle
grand_total_in_company_currency = flt(self.grand_total * self.conversion_rate,
self.precision("grand_total"))
gl_entries.append( gl_entries.append(
self.get_gl_dict({ self.get_gl_dict({
"account": self.debit_to, "account": self.debit_to,
"party_type": "Customer", "party_type": "Customer",
"party": self.customer, "party": self.customer,
"against": self.against_income_account, "against": self.against_income_account,
"debit": self.base_grand_total, "debit": grand_total_in_company_currency,
"debit_in_account_currency": self.base_grand_total \ "debit_in_account_currency": grand_total_in_company_currency \
if self.party_account_currency==self.company_currency else self.grand_total, if self.party_account_currency==self.company_currency else self.grand_total,
"against_voucher": self.return_against if cint(self.is_return) else self.name, "against_voucher": self.return_against if cint(self.is_return) else self.name,
"against_voucher_type": self.doctype "against_voucher_type": self.doctype

View File

@ -141,6 +141,8 @@ def make_round_off_gle(gl_map, debit_credit_diff):
round_off_gle.update({ round_off_gle.update({
"account": round_off_account, "account": round_off_account,
"debit_in_account_currency": abs(debit_credit_diff) if debit_credit_diff < 0 else 0,
"credit_in_account_currency": debit_credit_diff if debit_credit_diff > 0 else 0,
"debit": abs(debit_credit_diff) if debit_credit_diff < 0 else 0, "debit": abs(debit_credit_diff) if debit_credit_diff < 0 else 0,
"credit": debit_credit_diff if debit_credit_diff > 0 else 0, "credit": debit_credit_diff if debit_credit_diff > 0 else 0,
"cost_center": round_off_cost_center, "cost_center": round_off_cost_center,

View File

@ -1,8 +1,8 @@
<div style="margin-bottom: 7px;" class="text-center"> <div style="margin-bottom: 7px;">
{%= frappe.boot.letter_heads[frappe.defaults.get_default("letter_head")] %} {%= frappe.boot.letter_heads[frappe.defaults.get_default("letter_head")] %}
</div> </div>
<h2 class="text-center">{%= __("Bank Reconciliation Statement") %}</h2> <h2 class="text-center">{%= __("Bank Reconciliation Statement") %}</h2>
<h4 class="text-center">{%= filters.account %}</h4> <h4 class="text-center">{%= filters.account && (filters.account + ", "+filters.report_date) || "" %} {%= filters.company %}</h4>
<hr> <hr>
<table class="table table-bordered"> <table class="table table-bordered">
<thead> <thead>

View File

@ -39,18 +39,18 @@ def execute(filters=None):
+ amounts_not_reflected_in_system + amounts_not_reflected_in_system
data += [ data += [
get_balance_row(_("System Balance"), balance_as_per_system, account_currency), get_balance_row(_("Bank Statement balance as per General Ledger"), balance_as_per_system, account_currency),
{}, {},
{ {
"journal_entry": '"' + _("Amounts not reflected in bank") + '"', "journal_entry": _("Outstanding Cheques and Deposits to clear"),
"debit": total_debit, "debit": total_debit,
"credit": total_credit, "credit": total_credit,
"account_currency": account_currency "account_currency": account_currency
}, },
get_balance_row(_("Amounts not reflected in system"), amounts_not_reflected_in_system, get_balance_row(_("Cheques and Deposits incorrectly cleared"), amounts_not_reflected_in_system,
account_currency), account_currency),
{}, {},
get_balance_row(_("Expected balance as per bank"), bank_bal, account_currency) get_balance_row(_("Calculated Bank Statement balance"), bank_bal, account_currency)
] ]
return columns, data return columns, data
@ -129,21 +129,21 @@ def get_entries(filters):
and jvd.account = %(account)s and jv.posting_date <= %(report_date)s and jvd.account = %(account)s and jv.posting_date <= %(report_date)s
and ifnull(jv.clearance_date, '4000-01-01') > %(report_date)s and ifnull(jv.clearance_date, '4000-01-01') > %(report_date)s
and ifnull(jv.is_opening, 'No') = 'No' and ifnull(jv.is_opening, 'No') = 'No'
order by jv.name DESC""", filters, as_dict=1) order by jv.posting_date DESC,jv.name DESC""", filters, as_dict=1)
return entries return entries
def get_balance_row(label, amount, account_currency): def get_balance_row(label, amount, account_currency):
if amount > 0: if amount > 0:
return { return {
"journal_entry": '"' + label + '"', "journal_entry": label,
"debit": amount, "debit": amount,
"credit": 0, "credit": 0,
"account_currency": account_currency "account_currency": account_currency
} }
else: else:
return { return {
"journal_entry": '"' + label + '"', "journal_entry": label,
"debit": 0, "debit": 0,
"credit": abs(amount), "credit": abs(amount),
"account_currency": account_currency "account_currency": account_currency

View File

@ -7,7 +7,9 @@ from frappe import _, scrub
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 = frappe._dict()
company_currency = frappe.db.get_value("Company", filters.company, "default_currency")
gross_profit_data = GrossProfitGenerator(filters) gross_profit_data = GrossProfitGenerator(filters)
data = [] data = []
@ -43,6 +45,8 @@ def execute(filters=None):
row = [] row = []
for col in group_wise_columns.get(scrub(filters.group_by)): for col in group_wise_columns.get(scrub(filters.group_by)):
row.append(src.get(col)) row.append(src.get(col))
row.append(company_currency)
data.append(row) data.append(row)
return columns, data return columns, data
@ -60,15 +64,15 @@ def get_columns(group_wise_columns, filters):
"description": _("Description"), "description": _("Description"),
"warehouse": _("Warehouse") + ":Link/Warehouse", "warehouse": _("Warehouse") + ":Link/Warehouse",
"qty": _("Qty") + ":Float", "qty": _("Qty") + ":Float",
"base_rate": _("Avg. Selling Rate") + ":Currency", "base_rate": _("Avg. Selling Rate") + ":Currency/currency",
"buying_rate": _("Avg. Buying Rate") + ":Currency", "buying_rate": _("Avg. Buying Rate") + ":Currency/currency",
"base_amount": _("Selling Amount") + ":Currency", "base_amount": _("Selling Amount") + ":Currency/currency",
"buying_amount": _("Buying Amount") + ":Currency", "buying_amount": _("Buying Amount") + ":Currency/currency",
"gross_profit": _("Gross Profit") + ":Currency", "gross_profit": _("Gross Profit") + ":Currency/currency",
"gross_profit_percent": _("Gross Profit %") + ":Percent", "gross_profit_percent": _("Gross Profit %") + ":Percent",
"project": _("Project") + ":Link/Project", "project": _("Project") + ":Link/Project",
"sales_person": _("Sales person"), "sales_person": _("Sales person"),
"allocated_amount": _("Allocated Amount") + ":Currency", "allocated_amount": _("Allocated Amount") + ":Currency/currency",
"customer": _("Customer") + ":Link/Customer", "customer": _("Customer") + ":Link/Customer",
"customer_group": _("Customer Group") + ":Link/Customer Group", "customer_group": _("Customer Group") + ":Link/Customer Group",
"territory": _("Territory") + ":Link/Territory" "territory": _("Territory") + ":Link/Territory"
@ -77,6 +81,13 @@ def get_columns(group_wise_columns, filters):
for col in group_wise_columns.get(scrub(filters.group_by)): for col in group_wise_columns.get(scrub(filters.group_by)):
columns.append(column_map.get(col)) columns.append(column_map.get(col))
columns.append({
"fieldname": "currency",
"label" : _("Currency"),
"fieldtype": "Link",
"options": "Currency"
})
return columns return columns
class GrossProfitGenerator(object): class GrossProfitGenerator(object):

View File

@ -247,7 +247,7 @@ def update_against_doc(d, jv_obj):
# will work as update after submit # will work as update after submit
jv_obj.flags.ignore_validate_update_after_submit = True jv_obj.flags.ignore_validate_update_after_submit = True
jv_obj.save() jv_obj.save(ignore_permissions=True)
def remove_against_link_from_jv(ref_type, ref_no): def remove_against_link_from_jv(ref_type, ref_no):
linked_jv = frappe.db.sql_list("""select parent from `tabJournal Entry Account` linked_jv = frappe.db.sql_list("""select parent from `tabJournal Entry Account`

View File

@ -167,9 +167,9 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
set_from_product_bundle: function() { set_from_product_bundle: function() {
var me = this; var me = this;
this.frm.add_custom_button(__("From Product Bundle"), function() { this.frm.add_custom_button(__("Product Bundle"), function() {
erpnext.buying.get_items_from_product_bundle(me.frm); erpnext.buying.get_items_from_product_bundle(me.frm);
}); }, __("Get items from"));
} }
}); });

View File

@ -41,48 +41,61 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
if(doc.docstatus == 1 && !in_list(["Stopped", "Closed", "Delivered"], doc.status)) { if(doc.docstatus == 1 && !in_list(["Stopped", "Closed", "Delivered"], doc.status)) {
if (this.frm.has_perm("submit")) { if (this.frm.has_perm("submit")) {
if(flt(doc.per_billed, 2) < 100 || doc.per_received < 100) { if(flt(doc.per_billed, 2) < 100 || doc.per_received < 100) {
cur_frm.add_custom_button(__('Stop'), this.stop_purchase_order); cur_frm.add_custom_button(__('Stop'), this.stop_purchase_order, __("Status"));
} }
cur_frm.add_custom_button(__('Close'), this.close_purchase_order); cur_frm.add_custom_button(__('Close'), this.close_purchase_order, __("Status"));
} }
if(flt(doc.per_billed)==0) {
cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_bank_entry);
}
if(is_drop_ship && doc.status!="Delivered"){ if(is_drop_ship && doc.status!="Delivered"){
cur_frm.add_custom_button(__('Mark as Delivered'), cur_frm.add_custom_button(__('Delivered'),
this.delivered_by_supplier).addClass("btn-primary"); this.delivered_by_supplier, __("Status"));
cur_frm.page.set_inner_btn_group_as_primary(__("Status"));
} }
} else if(doc.docstatus===0) { } else if(doc.docstatus===0) {
cur_frm.add_custom_button(__('Get Last Purchase Rate'), this.get_last_purchase_rate);
cur_frm.cscript.add_from_mappers(); cur_frm.cscript.add_from_mappers();
} }
if(doc.docstatus == 1 && in_list(["Stopped", "Closed", "Delivered"], doc.status)) {
if (this.frm.has_perm("submit")) {
cur_frm.add_custom_button(__('Re-open'), this.unstop_purchase_order, __("Status"));
}
}
if(doc.docstatus == 1 && !in_list(["Stopped", "Closed"], doc.status)) { if(doc.docstatus == 1 && !in_list(["Stopped", "Closed"], doc.status)) {
if(flt(doc.per_received, 2) < 100 && allow_receipt) { if(flt(doc.per_received, 2) < 100 && allow_receipt) {
cur_frm.add_custom_button(__('Receive'), this.make_purchase_receipt).addClass("btn-primary"); cur_frm.add_custom_button(__('Receive'), this.make_purchase_receipt, __("Make"));
if(doc.is_subcontracted==="Yes") { if(doc.is_subcontracted==="Yes") {
cur_frm.add_custom_button(__('Transfer Material to Supplier'), cur_frm.add_custom_button(__('Material to Supplier'),
function() { me.make_stock_entry(); }); function() { me.make_stock_entry(); }, __("Transfer"));
} }
} }
if(flt(doc.per_billed, 2) < 100) if(flt(doc.per_billed, 2) < 100)
cur_frm.add_custom_button(__('Invoice'), cur_frm.add_custom_button(__('Invoice'),
this.make_purchase_invoice).addClass("btn-primary"); this.make_purchase_invoice, __("Make"));
}
if(doc.docstatus == 1 && in_list(["Stopped", "Closed", "Delivered"], doc.status)) { if(flt(doc.per_billed)==0 && doc.status != "Delivered") {
if (this.frm.has_perm("submit")) { cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_bank_entry, __("Make"));
cur_frm.add_custom_button(__('Re-open'), this.unstop_purchase_order).addClass("btn-primary");
} }
cur_frm.page.set_inner_btn_group_as_primary(__("Make"));
} }
}, },
get_items_from_open_material_requests: function() {
frappe.model.map_current_doc({
method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order_based_on_supplier",
source_name: this.frm.doc.supplier,
get_query_filters: {
docstatus: ["!=", 2],
}
});
},
make_stock_entry: function() { make_stock_entry: function() {
var items = $.map(cur_frm.doc.items, function(d) { return d.bom ? d.item_code : false; }); var items = $.map(cur_frm.doc.items, function(d) { return d.bom ? d.item_code : false; });
var me = this; var me = this;
@ -126,7 +139,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
}, },
add_from_mappers: function() { add_from_mappers: function() {
cur_frm.add_custom_button(__('From Material Request'), cur_frm.add_custom_button(__('Material Request'),
function() { function() {
frappe.model.map_current_doc({ frappe.model.map_current_doc({
method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order", method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order",
@ -139,10 +152,9 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
company: cur_frm.doc.company company: cur_frm.doc.company
} }
}) })
} }, __("Add items from"));
);
cur_frm.add_custom_button(__('From Supplier Quotation'), cur_frm.add_custom_button(__('Supplier Quotation'),
function() { function() {
frappe.model.map_current_doc({ frappe.model.map_current_doc({
method: "erpnext.buying.doctype.supplier_quotation.supplier_quotation.make_purchase_order", method: "erpnext.buying.doctype.supplier_quotation.supplier_quotation.make_purchase_order",
@ -153,20 +165,8 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
company: cur_frm.doc.company company: cur_frm.doc.company
} }
}) })
} }, __("Add items from"));
);
cur_frm.add_custom_button(__('For Supplier'),
function() {
frappe.model.map_current_doc({
method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order_based_on_supplier",
source_doctype: "Supplier",
get_query_filters: {
docstatus: ["!=", 2],
}
})
}
);
}, },
tc_name: function() { tc_name: function() {
@ -213,6 +213,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
"method": "get_last_purchase_rate", "method": "get_last_purchase_rate",
"doc": cur_frm.doc, "doc": cur_frm.doc,
callback: function(r, rt) { callback: function(r, rt) {
cur_frm.dirty();
cur_frm.cscript.calculate_taxes_and_totals(); cur_frm.cscript.calculate_taxes_and_totals();
} }
}) })
@ -265,54 +266,12 @@ cur_frm.fields_dict['items'].grid.get_field('bom').get_query = function(doc, cdt
} }
} }
cur_frm.pformat.indent_no = function(doc, cdt, cdn){
//function to make row of table
var make_row = function(title,val1, val2, bold){
var bstart = '<b>'; var bend = '</b>';
return '<tr><td style="width:39%;">'+(bold?bstart:'')+title+(bold?bend:'')+'</td>'
+'<td style="width:61%;text-align:left;">'+val1+(val2?' ('+dateutil.str_to_user(val2)+')':'')+'</td>'
+'</tr>'
}
out ='';
var cl = doc.items || [];
// outer table
var out='<div><table class="noborder" style="width:100%"><tr><td style="width: 50%"></td><td>';
// main table
out +='<table class="noborder" style="width:100%">';
// add rows
if(cl.length){
prevdoc_list = new Array();
for(var i=0;i<cl.length;i++){
if(cl[i].prevdoc_doctype == 'Material Request' && cl[i].prevdoc_docname && prevdoc_list.indexOf(cl[i].prevdoc_docname) == -1) {
prevdoc_list.push(cl[i].prevdoc_docname);
if(prevdoc_list.length ==1)
out += make_row(cl[i].prevdoc_doctype, cl[i].prevdoc_docname, null,0);
else
out += make_row('', cl[i].prevdoc_docname,null,0);
}
}
}
out +='</table></td></tr></table></div>';
return out;
}
cur_frm.cscript.on_submit = function(doc, cdt, cdn) { cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
if(cint(frappe.boot.notification_settings.purchase_order)) { if(cint(frappe.boot.notification_settings.purchase_order)) {
cur_frm.email_doc(frappe.boot.notification_settings.purchase_order_message); cur_frm.email_doc(frappe.boot.notification_settings.purchase_order_message);
} }
} }
cur_frm.cscript.schedule_date = function(doc, cdt, cdn) { cur_frm.cscript.schedule_date = function(doc, cdt, cdn) {
erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "schedule_date"); erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "schedule_date");
} }

View File

@ -111,6 +111,31 @@
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
}, },
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"depends_on": "eval:doc.supplier && doc.docstatus===0 && !(doc.items && doc.items.length)",
"fieldname": "get_items_from_open_material_requests",
"fieldtype": "Button",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Get Items from Open Material Requests",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{ {
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
@ -847,6 +872,31 @@
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
}, },
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"depends_on": "eval:doc.docstatus===0 && (doc.items && doc.items.length)",
"fieldname": "get_last_purchase_rate",
"fieldtype": "Button",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Get last purchase rate",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{ {
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
@ -2458,7 +2508,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2015-12-17 16:18:39.096762", "modified": "2016-01-15 04:13:35.179163",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Purchase Order", "name": "Purchase Order",

View File

@ -1,24 +1,44 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt // License: GNU General Public License v3. See license.txt
cur_frm.cscript.refresh = function(doc, dt, dn) { frappe.ui.form.on("Supplier", {
cur_frm.cscript.make_dashboard(doc); refresh: function(frm) {
frm.cscript.make_dashboard(frm.doc);
if(frappe.defaults.get_default("supp_master_name")!="Naming Series") { if(frappe.defaults.get_default("supp_master_name")!="Naming Series") {
cur_frm.toggle_display("naming_series", false); frm.toggle_display("naming_series", false);
} else { } else {
erpnext.toggle_naming_series(); erpnext.toggle_naming_series();
} }
if(doc.__islocal){ if(frm.doc.__islocal){
hide_field(['address_html','contact_html']); hide_field(['address_html','contact_html']);
erpnext.utils.clear_address_and_contact(cur_frm); erpnext.utils.clear_address_and_contact(frm);
} }
else{ else {
unhide_field(['address_html','contact_html']); unhide_field(['address_html','contact_html']);
erpnext.utils.render_address_and_contact(cur_frm) erpnext.utils.render_address_and_contact(frm);
} }
}
frm.events.add_custom_buttons(frm);
},
add_custom_buttons: function(frm) {
["Supplier Quotation", "Purchase Order", "Purchase Receipt", "Purchase Invoice"].forEach(function(doctype, i) {
if(frappe.model.can_read(doctype)) {
frm.add_custom_button(__(doctype), function() {
frappe.route_options = {"supplier": frm.doc.name};
frappe.set_route("List", doctype);
}, __("View"));
}
if(frappe.model.can_create(doctype)) {
frm.add_custom_button(__(doctype), function() {
frappe.route_options = {"supplier": frm.doc.name};
new_doc(doctype);
}, __("Make"));
}
});
},
});
cur_frm.cscript.make_dashboard = function(doc) { cur_frm.cscript.make_dashboard = function(doc) {
cur_frm.dashboard.reset(); cur_frm.dashboard.reset();

View File

@ -9,11 +9,12 @@ erpnext.buying.SupplierQuotationController = erpnext.buying.BuyingController.ext
this._super(); this._super();
if (this.frm.doc.docstatus === 1) { if (this.frm.doc.docstatus === 1) {
cur_frm.add_custom_button(__("Make Purchase Order"), this.make_purchase_order, cur_frm.add_custom_button(__("Purchase Order"), this.make_purchase_order,
frappe.boot.doctype_icons["Journal Entry"]); __("Make"));
cur_frm.page.set_inner_btn_group_as_primary(__("Make"));
} }
else if (this.frm.doc.docstatus===0) { else if (this.frm.doc.docstatus===0) {
cur_frm.add_custom_button(__('From Material Request'), cur_frm.add_custom_button(__('Material Request'),
function() { function() {
frappe.model.map_current_doc({ frappe.model.map_current_doc({
method: "erpnext.stock.doctype.material_request.material_request.make_supplier_quotation", method: "erpnext.stock.doctype.material_request.material_request.make_supplier_quotation",
@ -26,7 +27,7 @@ erpnext.buying.SupplierQuotationController = erpnext.buying.BuyingController.ext
company: cur_frm.doc.company company: cur_frm.doc.company
} }
}) })
}, "icon-download", "btn-default"); }, __("Get items from"));
} }
}, },

View File

@ -0,0 +1,4 @@
- Added Additional Cost field in Time Log and cleaned up layout
- Grouped contextual buttons in sales & purchase cycle
- Rounded Total and Change in POS based on smallest circulating currency fraction value
- Now items can be returned in any warehouse

View File

@ -32,6 +32,11 @@ def get_data():
"name": "Supplier", "name": "Supplier",
"description": _("Supplier database.") "description": _("Supplier database.")
}, },
{
"type": "doctype",
"name": "Payment Request",
"description": _("Payment Request")
},
{ {
"type": "page", "type": "page",
"name": "Accounts Browser", "name": "Accounts Browser",
@ -83,6 +88,11 @@ def get_data():
"name": "Fiscal Year", "name": "Fiscal Year",
"description": _("Financial / accounting year.") "description": _("Financial / accounting year.")
}, },
{
"type": "doctype",
"name": "Payment Gateway Account",
"description": _("Setup Gateway accounts.")
},
{ {
"type": "page", "type": "page",
"name": "Accounts Browser", "name": "Accounts Browser",

View File

@ -2,32 +2,50 @@ from __future__ import unicode_literals
from frappe import _ from frappe import _
def get_data(): def get_data():
return { return [
"Accounts": { {
"module_name": "Accounts",
"color": "#3498db", "color": "#3498db",
"icon": "octicon octicon-repo", "icon": "octicon octicon-repo",
"type": "module" "type": "module"
}, },
"Buying": { {
"module_name": "CRM",
"color": "#EF4DB6",
"icon": "octicon octicon-broadcast",
"type": "module"
},
{
"module_name": "Selling",
"color": "#1abc9c",
"icon": "icon-tag",
"icon": "octicon octicon-tag",
"type": "module"
},
{
"module_name": "Buying",
"color": "#c0392b", "color": "#c0392b",
"icon": "icon-shopping-cart", "icon": "icon-shopping-cart",
"icon": "octicon octicon-briefcase", "icon": "octicon octicon-briefcase",
"type": "module" "type": "module"
}, },
"HR": { {
"module_name": "HR",
"color": "#2ecc71", "color": "#2ecc71",
"icon": "icon-group", "icon": "icon-group",
"icon": "octicon octicon-organization", "icon": "octicon octicon-organization",
"label": _("Human Resources"), "label": _("Human Resources"),
"type": "module" "type": "module"
}, },
"Manufacturing": { {
"module_name": "Manufacturing",
"color": "#7f8c8d", "color": "#7f8c8d",
"icon": "icon-cogs", "icon": "icon-cogs",
"icon": "octicon octicon-tools", "icon": "octicon octicon-tools",
"type": "module" "type": "module"
}, },
"POS": { {
"module_name": "POS",
"color": "#589494", "color": "#589494",
"icon": "icon-th", "icon": "icon-th",
"icon": "octicon octicon-credit-card", "icon": "octicon octicon-credit-card",
@ -35,41 +53,33 @@ def get_data():
"link": "pos", "link": "pos",
"label": _("POS") "label": _("POS")
}, },
"Projects": { {
"module_name": "Projects",
"color": "#8e44ad", "color": "#8e44ad",
"icon": "icon-puzzle-piece", "icon": "icon-puzzle-piece",
"icon": "octicon octicon-rocket", "icon": "octicon octicon-rocket",
"type": "module" "type": "module"
}, },
"Selling": { {
"color": "#1abc9c", "module_name": "Stock",
"icon": "icon-tag",
"icon": "octicon octicon-tag",
"type": "module"
},
"CRM": {
"color": "#EF4DB6",
"icon": "octicon octicon-broadcast",
"type": "module"
},
"Stock": {
"color": "#f39c12", "color": "#f39c12",
"icon": "icon-truck", "icon": "icon-truck",
"icon": "octicon octicon-package", "icon": "octicon octicon-package",
"type": "module" "type": "module"
}, },
"Support": { {
"module_name": "Support",
"color": "#2c3e50", "color": "#2c3e50",
"icon": "icon-phone", "icon": "icon-phone",
"icon": "octicon octicon-issue-opened", "icon": "octicon octicon-issue-opened",
"type": "module" "type": "module"
}, },
"Learn": { {
"module_name": "Learn",
"color": "#FF888B", "color": "#FF888B",
"force_show": True,
"icon": "octicon octicon-device-camera-video", "icon": "octicon octicon-device-camera-video",
"type": "module", "type": "module",
"is_help": True, "is_help": True,
"label": _("Learn") "label": _("Learn")
} }
} ]

View File

@ -135,7 +135,7 @@ def get_data():
{ {
"type": "help", "type": "help",
"label": _("Product Bundle"), "label": _("Product Bundle"),
"youtube_id": "yk-7kPrRyRRc" "youtube_id": "yk3kPrRyRRc"
}, },
{ {
"type": "help", "type": "help",

View File

@ -151,6 +151,10 @@ class AccountsController(TransactionBase):
if item.get("item_code"): if item.get("item_code"):
args = parent_dict.copy() args = parent_dict.copy()
args.update(item.as_dict()) args.update(item.as_dict())
args["doctype"] = self.doctype
args["name"] = self.name
if not args.get("transaction_date"): if not args.get("transaction_date"):
args["transaction_date"] = args.get("posting_date") args["transaction_date"] = args.get("posting_date")

View File

@ -32,15 +32,16 @@ def validate_item_variant_attributes(item, args):
attribute_values = {} attribute_values = {}
for t in frappe.get_all("Item Attribute Value", fields=["parent", "attribute_value"], for t in frappe.get_all("Item Attribute Value", fields=["parent", "attribute_value"],
filters={"parent": ["in", args.keys()]}): filters={"parent": ["in", args.keys()]}):
(attribute_values.setdefault(t.parent, [])).append(t.attribute_value)
numeric_attributes = frappe._dict((t.attribute, t) for t in \ (attribute_values.setdefault(t.parent.lower(), [])).append(t.attribute_value)
numeric_attributes = frappe._dict((t.attribute.lower(), t) for t in \
frappe.db.sql("""select attribute, from_range, to_range, increment from `tabItem Variant Attribute` frappe.db.sql("""select attribute, from_range, to_range, increment from `tabItem Variant Attribute`
where parent = %s and numeric_values=1""", (item), as_dict=1)) where parent = %s and numeric_values=1""", (item), as_dict=1))
for attribute, value in args.items(): for attribute, value in args.items():
if attribute in numeric_attributes: if attribute.lower() in numeric_attributes:
numeric_attribute = numeric_attributes[attribute] numeric_attribute = numeric_attributes[attribute.lower()]
from_range = numeric_attribute.from_range from_range = numeric_attribute.from_range
to_range = numeric_attribute.to_range to_range = numeric_attribute.to_range
@ -61,7 +62,7 @@ def validate_item_variant_attributes(item, args):
frappe.throw(_("Value for Attribute {0} must be within the range of {1} to {2} in the increments of {3}")\ frappe.throw(_("Value for Attribute {0} must be within the range of {1} to {2} in the increments of {3}")\
.format(attribute, from_range, to_range, increment), InvalidItemAttributeValueError) .format(attribute, from_range, to_range, increment), InvalidItemAttributeValueError)
elif value not in attribute_values.get(attribute, []): elif value not in attribute_values.get(attribute.lower(), []):
frappe.throw(_("Value {0} for Attribute {1} does not exist in the list of valid Item Attribute Values").format( frappe.throw(_("Value {0} for Attribute {1} does not exist in the list of valid Item Attribute Values").format(
value, attribute)) value, attribute))

View File

@ -33,7 +33,7 @@ cur_frm.cscript.onload = function(doc, cdt, cdn) {
cur_frm.set_value("address_title", cur_frm.doc.customer_name); cur_frm.set_value("address_title", cur_frm.doc.customer_name);
} }
} }
if(["Supplier", "Supplier Quotation", "Purchase Order", "Purchase Invoice", "Purchase Receipt"] else if(["Supplier", "Supplier Quotation", "Purchase Order", "Purchase Invoice", "Purchase Receipt"]
.indexOf(doctype)!==-1) { .indexOf(doctype)!==-1) {
var refdoc = frappe.get_doc(doctype, docname); var refdoc = frappe.get_doc(doctype, docname);
cur_frm.set_value("supplier", refdoc.supplier || refdoc.name); cur_frm.set_value("supplier", refdoc.supplier || refdoc.name);
@ -41,7 +41,7 @@ cur_frm.cscript.onload = function(doc, cdt, cdn) {
if(cur_frm.doc.doctype==="Address") if(cur_frm.doc.doctype==="Address")
cur_frm.set_value("address_title", cur_frm.doc.supplier_name); cur_frm.set_value("address_title", cur_frm.doc.supplier_name);
} }
if(["Lead", "Opportunity", "Quotation"] else if(["Lead", "Opportunity", "Quotation"]
.indexOf(doctype)!==-1) { .indexOf(doctype)!==-1) {
var refdoc = frappe.get_doc(doctype, docname); var refdoc = frappe.get_doc(doctype, docname);
@ -53,6 +53,9 @@ cur_frm.cscript.onload = function(doc, cdt, cdn) {
cur_frm.set_value("address_title", cur_frm.doc.lead_name); cur_frm.set_value("address_title", cur_frm.doc.lead_name);
} }
} }
else if(doctype == "Sales Partner") {
cur_frm.set_value("sales_partner", docname);
}
} }
} }
} }

View File

@ -158,7 +158,7 @@ def tax_account_query(doctype, txt, searchfield, start, page_len, filters):
def item_query(doctype, txt, searchfield, start, page_len, filters): def item_query(doctype, txt, searchfield, start, page_len, filters):
conditions = [] conditions = []
return frappe.db.sql("""select tabItem.name, return frappe.db.sql("""select tabItem.name,tabItem.item_group,
if(length(tabItem.item_name) > 40, if(length(tabItem.item_name) > 40,
concat(substr(tabItem.item_name, 1, 40), "..."), item_name) as item_name, concat(substr(tabItem.item_name, 1, 40), "..."), item_name) as item_name,
if(length(tabItem.description) > 40, \ if(length(tabItem.description) > 40, \

View File

@ -97,6 +97,9 @@ def validate_returned_items(doc):
frappe.throw(_("Row # {0}: Serial No {1} does not match with {2} {3}") frappe.throw(_("Row # {0}: Serial No {1} does not match with {2} {3}")
.format(d.idx, s, doc.doctype, doc.return_against)) .format(d.idx, s, doc.doctype, doc.return_against))
if not d.warehouse:
frappe.throw(_("Warehouse is mandatory"))
items_returned = True items_returned = True
if not items_returned: if not items_returned:

View File

@ -218,14 +218,14 @@ class StockController(AccountsController):
return serialized_items return serialized_items
def get_incoming_rate_for_sales_return(self, item_code, warehouse, against_document): def get_incoming_rate_for_sales_return(self, item_code, against_document):
incoming_rate = 0.0 incoming_rate = 0.0
if against_document and item_code: if against_document and item_code:
incoming_rate = frappe.db.sql("""select abs(stock_value_difference / actual_qty) incoming_rate = frappe.db.sql("""select abs(stock_value_difference / actual_qty)
from `tabStock Ledger Entry` from `tabStock Ledger Entry`
where voucher_type = %s and voucher_no = %s where voucher_type = %s and voucher_no = %s
and item_code = %s and warehouse=%s limit 1""", and item_code = %s limit 1""",
(self.doctype, against_document, item_code, warehouse)) (self.doctype, against_document, item_code))
incoming_rate = incoming_rate[0][0] if incoming_rate else 0.0 incoming_rate = incoming_rate[0][0] if incoming_rate else 0.0
return incoming_rate return incoming_rate
@ -257,8 +257,7 @@ class StockController(AccountsController):
if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1 and flt(d.qty): if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1 and flt(d.qty):
return_rate = 0 return_rate = 0
if cint(self.is_return) and self.return_against and self.docstatus==1: if cint(self.is_return) and self.return_against and self.docstatus==1:
return_rate = self.get_incoming_rate_for_sales_return(d.item_code, return_rate = self.get_incoming_rate_for_sales_return(d.item_code, self.return_against)
d.warehouse, self.return_against)
# On cancellation or if return entry submission, make stock ledger entry for # On cancellation or if return entry submission, make stock ledger entry for
# target warehouse first, to update serial no values properly # target warehouse first, to update serial no values properly

View File

@ -5,7 +5,7 @@ from __future__ import unicode_literals
import json import json
import frappe import frappe
from frappe import _, scrub from frappe import _, scrub
from frappe.utils import cint, flt, rounded from frappe.utils import cint, flt, round_based_on_smallest_currency_fraction
from erpnext.setup.utils import get_company_currency from erpnext.setup.utils import get_company_currency
from erpnext.controllers.accounts_controller import validate_conversion_rate, \ from erpnext.controllers.accounts_controller import validate_conversion_rate, \
validate_taxes_and_charges, validate_inclusive_tax validate_taxes_and_charges, validate_inclusive_tax
@ -319,9 +319,14 @@ class calculate_taxes_and_totals(object):
self.doc.round_floats_in(self.doc, ["grand_total", "base_grand_total"]) self.doc.round_floats_in(self.doc, ["grand_total", "base_grand_total"])
if self.doc.meta.get_field("rounded_total"): if self.doc.meta.get_field("rounded_total"):
self.doc.rounded_total = rounded(self.doc.grand_total) self.doc.rounded_total = round_based_on_smallest_currency_fraction(self.doc.grand_total,
self.doc.currency, self.doc.precision("rounded_total"))
if self.doc.meta.get_field("base_rounded_total"): if self.doc.meta.get_field("base_rounded_total"):
self.doc.base_rounded_total = rounded(self.doc.base_grand_total) company_currency = get_company_currency(self.doc.company)
self.doc.base_rounded_total = \
round_based_on_smallest_currency_fraction(self.doc.base_grand_total,
company_currency, self.doc.precision("base_rounded_total"))
def _cleanup(self): def _cleanup(self):
for tax in self.doc.get("taxes"): for tax in self.doc.get("taxes"):
@ -408,7 +413,8 @@ class calculate_taxes_and_totals(object):
total_amount_to_pay = flt(self.doc.grand_total - self.doc.total_advance total_amount_to_pay = flt(self.doc.grand_total - self.doc.total_advance
- flt(self.doc.write_off_amount), self.doc.precision("grand_total")) - flt(self.doc.write_off_amount), self.doc.precision("grand_total"))
else: else:
total_amount_to_pay = flt(self.doc.base_grand_total - self.doc.total_advance total_amount_to_pay = flt(flt(self.doc.grand_total *
self.doc.conversion_rate, self.doc.precision("grand_total")) - self.doc.total_advance
- flt(self.doc.base_write_off_amount), self.doc.precision("grand_total")) - flt(self.doc.base_write_off_amount), self.doc.precision("grand_total"))
if self.doc.doctype == "Sales Invoice": if self.doc.doctype == "Sales Invoice":

View File

@ -27,12 +27,10 @@ erpnext.LeadController = frappe.ui.form.Controller.extend({
erpnext.toggle_naming_series(); erpnext.toggle_naming_series();
if(!this.frm.doc.__islocal && this.frm.doc.__onload && !this.frm.doc.__onload.is_customer) { if(!this.frm.doc.__islocal && this.frm.doc.__onload && !this.frm.doc.__onload.is_customer) {
this.frm.add_custom_button(__("Create Customer"), this.create_customer, this.frm.add_custom_button(__("Customer"), this.create_customer, __("Make"));
frappe.boot.doctype_icons["Customer"], "btn-default"); this.frm.add_custom_button(__("Opportunity"), this.create_opportunity, __("Make"));
this.frm.add_custom_button(__("Create Opportunity"), this.create_opportunity, this.frm.add_custom_button(__("Quotation"), this.make_quotation, __("Make"));
frappe.boot.doctype_icons["Opportunity"], "btn-default"); cur_frm.page.set_inner_btn_group_as_primary(__("Make"));
this.frm.add_custom_button(__("Make Quotation"), this.make_quotation,
frappe.boot.doctype_icons["Quotation"], "btn-default");
} }
if(!this.frm.doc.__islocal) { if(!this.frm.doc.__islocal) {

View File

@ -3,7 +3,7 @@ frappe.ui.form.on("Newsletter List", "refresh", function(frm) {
frm.add_custom_button(__("View Subscribers"), function() { frm.add_custom_button(__("View Subscribers"), function() {
frappe.route_options = {"newsletter_list": frm.doc.name}; frappe.route_options = {"newsletter_list": frm.doc.name};
frappe.set_route("Report", "Newsletter List Subscriber"); frappe.set_route("Report", "Newsletter List Subscriber");
}); }, __("View"));
frm.add_custom_button(__("Import Subscribers"), function() { frm.add_custom_button(__("Import Subscribers"), function() {
frappe.prompt({fieldtype:"Select", options: frm.doc.__onload.import_types, frappe.prompt({fieldtype:"Select", options: frm.doc.__onload.import_types,
@ -19,7 +19,7 @@ frappe.ui.form.on("Newsletter List", "refresh", function(frm) {
} }
}) })
}, __("Import Subscribers"), __("Import")); }, __("Import Subscribers"), __("Import"));
}); }, __("Action"));
frm.add_custom_button(__("Add Subscribers"), function() { frm.add_custom_button(__("Add Subscribers"), function() {
frappe.prompt({fieldtype:"Text", frappe.prompt({fieldtype:"Text",
@ -35,12 +35,12 @@ frappe.ui.form.on("Newsletter List", "refresh", function(frm) {
} }
}) })
}, __("Add Subscribers"), __("Add")); }, __("Add Subscribers"), __("Add"));
}); }, __("Action"));
frm.add_custom_button(__("New Newsletter"), function() { frm.add_custom_button(__("New Newsletter"), function() {
frappe.route_options = {"newsletter_list": frm.doc.name}; frappe.route_options = {"newsletter_list": frm.doc.name};
new_doc("Newsletter"); new_doc("Newsletter");
}); }, __("Action"));
} }
}); });

View File

@ -78,30 +78,31 @@ $.extend(cur_frm.cscript, new erpnext.crm.Opportunity({frm: cur_frm}));
cur_frm.cscript.refresh = function(doc, cdt, cdn) { cur_frm.cscript.refresh = function(doc, cdt, cdn) {
erpnext.toggle_naming_series(); erpnext.toggle_naming_series();
if(doc.status!=="Lost") {
cur_frm.add_custom_button(__('Create Quotation'),
cur_frm.cscript.create_quotation, frappe.boot.doctype_icons["Quotation"],
"btn-default");
if(doc.status!=="Quotation")
cur_frm.add_custom_button(__('Opportunity Lost'),
cur_frm.cscript['Declare Opportunity Lost'], "icon-remove", "btn-default");
}
var frm = cur_frm; var frm = cur_frm;
if(frm.perm[0].write && doc.docstatus==0) { if(frm.perm[0].write && doc.docstatus==0) {
if(frm.doc.status==="Open") { if(frm.doc.status==="Open") {
frm.add_custom_button(__("Close"), function() { frm.add_custom_button(__("Close"), function() {
frm.set_value("status", "Closed"); frm.set_value("status", "Closed");
frm.save(); frm.save();
}); }, __("Status"));
} else { } else {
frm.add_custom_button(__("Reopen"), function() { frm.add_custom_button(__("Reopen"), function() {
frm.set_value("status", "Open"); frm.set_value("status", "Open");
frm.save(); frm.save();
}); }, __("Status"));
} }
} }
if(doc.status!=="Lost") {
if(doc.status!=="Quotation") {
cur_frm.add_custom_button(__('Lost'),
cur_frm.cscript['Declare Opportunity Lost'], __("Status"));
}
cur_frm.add_custom_button(__('Quotation'),cur_frm.cscript.create_quotation, __("Make"));
cur_frm.page.set_inner_btn_group_as_primary(__("Make"));
}
} }
cur_frm.cscript.onload_post_render = function(doc, cdt, cdn) { cur_frm.cscript.onload_post_render = function(doc, cdt, cdn) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Some files were not shown because too many files have changed in this diff Show More