Merge branch 'develop' into multi-barcode

This commit is contained in:
tundebabzy 2018-01-10 21:49:27 +01:00 committed by GitHub
commit 76dddbf26e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
414 changed files with 105304 additions and 77387 deletions

BIN
.swp Normal file

Binary file not shown.

View File

@ -5,7 +5,7 @@ import frappe
from erpnext.hooks import regional_overrides
from frappe.utils import getdate
__version__ = '9.2.21'
__version__ = '10.0.7'
def get_default_company(user=None):
'''Get default company for user'''

View File

@ -53,14 +53,12 @@ class Account(NestedSet):
def set_root_and_report_type(self):
if self.parent_account:
par = frappe.db.get_value("Account", self.parent_account,
["report_type", "root_type", "account_type"], as_dict=1)
["report_type", "root_type"], as_dict=1)
if par.report_type:
self.report_type = par.report_type
if par.root_type:
self.root_type = par.root_type
if par.account_type and not self.account_type:
self.account_type = par.account_type
if self.is_group:
db_value = frappe.db.get_value("Account", self.name, ["report_type", "root_type"], as_dict=1)
@ -165,16 +163,16 @@ class Account(NestedSet):
if self.check_gle_exists():
throw(_("Account with existing transaction can not be deleted"))
super(Account, self).on_trash()
super(Account, self).on_trash(True)
def before_rename(self, old, new, merge=False):
# Add company abbr if not provided
from erpnext.setup.doctype.company.company import get_name_with_abbr
new_account = get_name_with_abbr(new, self.company)
new_account = get_name_with_number(new_account, self.account_number)
# Validate properties before merging
if merge:
if not merge:
new_account = get_name_with_number(new_account, self.account_number)
else:
# Validate properties before merging
if not frappe.db.exists("Account", new):
throw(_("Account {0} does not exist").format(new))

View File

@ -79,15 +79,17 @@ frappe.treeview_settings["Account"] = {
},
onrender: function(node) {
var dr_or_cr = node.data.balance < 0 ? "Cr" : "Dr";
if (node.data && node.data.balance!==undefined) {
$('<span class="balance-area pull-right text-muted small">'
+ (node.data.balance_in_account_currency ?
(format_currency(Math.abs(node.data.balance_in_account_currency),
node.data.account_currency) + " / ") : "")
+ format_currency(Math.abs(node.data.balance), node.data.company_currency)
+ " " + dr_or_cr
+ '</span>').insertBefore(node.$ul);
if(frappe.boot.user.can_read.indexOf("GL Entry") !== -1){
var dr_or_cr = node.data.balance < 0 ? "Cr" : "Dr";
if (node.data && node.data.balance!==undefined) {
$('<span class="balance-area pull-right text-muted small">'
+ (node.data.balance_in_account_currency ?
(format_currency(Math.abs(node.data.balance_in_account_currency),
node.data.account_currency) + " / ") : "")
+ format_currency(Math.abs(node.data.balance), node.data.company_currency)
+ " " + dr_or_cr
+ '</span>').insertBefore(node.$ul);
}
}
},
toolbar: [

View File

@ -52,6 +52,7 @@ def _make_test_records(verbose):
["_Test Account Customs Duty", "_Test Account Stock Expenses", 0, "Tax", None],
["_Test Account Insurance Charges", "_Test Account Stock Expenses", 0, "Chargeable", None],
["_Test Account Stock Adjustment", "_Test Account Stock Expenses", 0, "Stock Adjustment", None],
["_Test Employee Advance", "Current Liabilities", 0, None, None],
["_Test Account Tax Assets", "Current Assets", 1, None, None],
["_Test Account VAT", "_Test Account Tax Assets", 0, "Tax", None],

View File

@ -287,6 +287,125 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "print_settings",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Print Settings",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "show_inclusive_tax_in_print",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Show Inclusive Tax In Print",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_12",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "show_payment_schedule_in_print",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Show Payment Schedule in Print",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@ -392,7 +511,7 @@
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"modified": "2017-09-05 10:10:03.117505",
"modified": "2018-01-05 15:26:10.357085",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",

View File

@ -7,6 +7,7 @@ from __future__ import unicode_literals
import frappe
from frappe.utils import cint
from frappe.model.document import Document
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
class AccountsSettings(Document):
@ -15,6 +16,7 @@ class AccountsSettings(Document):
def validate(self):
self.validate_stale_days()
self.enable_payment_schedule_in_print()
def validate_stale_days(self):
if not self.allow_stale and cint(self.stale_days) <= 0:
@ -22,3 +24,8 @@ class AccountsSettings(Document):
"Stale Days should start from 1.", title='Error', indicator='red',
raise_exception=1)
def enable_payment_schedule_in_print(self):
show_in_print = cint(self.show_payment_schedule_in_print)
for doctype in ("Sales Order", "Sales Invoice", "Purchase Order", "Purchase Invoice"):
make_property_setter(doctype, "due_date", "print_hide", show_in_print, "Check")
make_property_setter(doctype, "payment_schedule", "print_hide", 0 if show_in_print else 1, "Check")

View File

@ -74,36 +74,6 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "due_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Due Date",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@ -748,7 +718,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-08-10 18:06:44.904081",
"modified": "2017-12-20 12:40:09.611951",
"modified_by": "Administrator",
"module": "Accounts",
"name": "GL Entry",

View File

@ -0,0 +1,196 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2018-01-02 15:48:58.768352",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "company",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Company",
"length": 0,
"no_copy": 0,
"options": "Company",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "cgst_account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "CGST Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "sgst_account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "SGST Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "igst_account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "IGST Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "cess_account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "CESS Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2018-01-02 15:52:22.335988",
"modified_by": "Administrator",
"module": "Accounts",
"name": "GST Account",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, 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 GSTAccount(Document):
pass

View File

@ -124,6 +124,15 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
};
}
if(jvd.reference_type==="Employee Advance") {
return {
filters: {
'status': ['=', 'Unpaid'],
'docstatus': 1
}
};
}
// journal entry
if(jvd.reference_type==="Journal Entry") {
frappe.model.validate_missing(jvd, "account");
@ -185,56 +194,21 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
})
},
due_date_options_cache: {},
reference_name: function(doc, cdt, cdn) {
var d = frappe.get_doc(cdt, cdn);
var me = this;
const get_invoice_due_dates = invoice_name => {
const options = this.due_date_options_cache[invoice_name];
const input = $(cur_frm.fields_dict["accounts"].wrapper).find("select[data-fieldname=reference_due_date]");
if (options) {
input.empty();
input.add_options(options);
frappe.model.set_value(cdt, cdn, "reference_due_date", options[0]);
}
else {
frappe.call({
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_invoice_due_dates",
args: {name: invoice_name},
callback: function(r) {
const options = [];
$.each(r.message, function(key, value) {
options.push(value.due_date);
});
input.empty();
input.add_options(options);
frappe.model.set_value(cdt, cdn, "reference_due_date", options[0]);
me.due_date_options_cache[d.reference_name] = options;
}
});
}
}
if(d.reference_name) {
if (d.reference_type==="Purchase Invoice" && !flt(d.debit)) {
this.get_outstanding('Purchase Invoice', d.reference_name, doc.company, d);
}
if (d.reference_type==="Sales Invoice" && !flt(d.credit)) {
} else if (d.reference_type==="Sales Invoice" && !flt(d.credit)) {
this.get_outstanding('Sales Invoice', d.reference_name, doc.company, d);
}
if (d.reference_type==="Journal Entry" && !flt(d.credit) && !flt(d.debit)) {
} else if (d.reference_type==="Journal Entry" && !flt(d.credit) && !flt(d.debit)) {
this.get_outstanding('Journal Entry', d.reference_name, doc.company, d);
}
if( in_list(["Sales Invoice", "Purchase Invoice"]), d.reference_type) {
get_invoice_due_dates(d.reference_name);
}
}
},
get_outstanding: function(doctype, docname, company, child) {
get_outstanding: function(doctype, docname, company, child, due_date) {
var me = this;
var args = {
"doctype": doctype,

View File

@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe, erpnext, json
from frappe.utils import cstr, flt, fmt_money, formatdate
from frappe.utils import cstr, flt, fmt_money, formatdate, getdate
from frappe import msgprint, _, scrub
from erpnext.controllers.accounts_controller import AccountsController
from erpnext.accounts.utils import get_balance_on, get_account_currency
@ -54,8 +54,8 @@ class JournalEntry(AccountsController):
def update_advance_paid(self):
advance_paid = frappe._dict()
for d in self.get("accounts"):
if d.is_advance == "Yes":
if d.reference_type in ("Sales Order", "Purchase Order"):
if d.is_advance:
if d.reference_type in ("Sales Order", "Purchase Order", "Employee Advance"):
advance_paid.setdefault(d.reference_type, []).append(d.reference_name)
for voucher_type, order_list in advance_paid.items():
@ -101,8 +101,6 @@ class JournalEntry(AccountsController):
if account_type in ["Receivable", "Payable"]:
if not (d.party_type and d.party):
frappe.throw(_("Row {0}: Party Type and Party is required for Receivable / Payable account {1}").format(d.idx, d.account))
elif d.party_type and d.party:
frappe.throw(_("Row {0}: Party Type and Party is only applicable against Receivable / Payable account").format(d.idx))
def check_credit_limit(self):
customers = list(set([d.party for d in self.get("accounts")
@ -436,8 +434,7 @@ class JournalEntry(AccountsController):
"against_voucher": d.reference_name,
"remarks": self.remark,
"cost_center": d.cost_center,
"project": d.project,
"due_date": d.reference_due_date
"project": d.project
})
)
@ -649,9 +646,8 @@ def get_payment_entry_against_invoice(dt, dn, amount=None, debit_in_account_cur
party_type = "Supplier"
party_account = ref_doc.credit_to
if (dt=="Sales Invoice" and ref_doc.outstanding_amount > 0) \
or (dt=="Purchase Invoice" and ref_doc.outstanding_amount < 0):
if (dt == "Sales Invoice" and ref_doc.outstanding_amount > 0) \
or (dt == "Purchase Invoice" and ref_doc.outstanding_amount < 0):
amount_field_party = "credit_in_account_currency"
amount_field_bank = "debit_in_account_currency"
else:
@ -672,6 +668,7 @@ def get_payment_entry_against_invoice(dt, dn, amount=None, debit_in_account_cur
"journal_entry": journal_entry
})
def get_payment_entry(ref_doc, args):
cost_center = frappe.db.get_value("Company", ref_doc.company, "cost_center")
exchange_rate = 1
@ -696,7 +693,7 @@ def get_payment_entry(ref_doc, args):
"cost_center": cost_center,
"account_type": frappe.db.get_value("Account", args.get("party_account"), "account_type"),
"account_currency": args.get("party_account_currency") or \
get_account_currency(args.get("party_account")),
get_account_currency(args.get("party_account")),
"balance": get_balance_on(args.get("party_account")),
"party_balance": get_balance_on(party=args.get("party"), party_type=args.get("party_type")),
"exchange_rate": exchange_rate,
@ -708,7 +705,7 @@ def get_payment_entry(ref_doc, args):
bank_row = je.append("accounts")
#make it bank_details
# Make it bank_details
bank_account = get_default_bank_cash_account(ref_doc.company, "Bank", account=args.get("bank_account"))
if bank_account:
bank_row.update(bank_account)
@ -727,7 +724,7 @@ def get_payment_entry(ref_doc, args):
else:
bank_row.set(args.get("amount_field_bank"), amount * exchange_rate)
# set multi currency check
# Multi currency check again
if party_row.account_currency != ref_doc.company_currency \
or (bank_row.account_currency and bank_row.account_currency != ref_doc.company_currency):
je.multi_currency = 1
@ -737,6 +734,7 @@ def get_payment_entry(ref_doc, args):
return je if args.get("journal_entry") else je.as_dict()
@frappe.whitelist()
def get_opening_accounts(company):
"""get all balance sheet accounts for opening entry"""
@ -759,6 +757,7 @@ def get_against_jv(doctype, txt, searchfield, start, page_len, filters):
and jv.docstatus = 1 and jv.`{0}` like %s order by jv.name desc limit %s, %s""".format(frappe.db.escape(searchfield)),
(filters.get("account"), cstr(filters.get("party")), "%{0}%".format(txt), start, page_len))
@frappe.whitelist()
def get_outstanding(args):
if not frappe.has_permission("Account"):
@ -820,6 +819,7 @@ def get_party_account_and_balance(company, party_type, party):
"account_currency": frappe.db.get_value("Account", account, "account_currency")
}
@frappe.whitelist()
def get_account_balance_and_party_type(account, date, company, debit=None, credit=None, exchange_rate=None):
"""Returns dict of account balance and party type to be set in Journal Entry on selection of account."""
@ -857,7 +857,7 @@ def get_account_balance_and_party_type(account, date, company, debit=None, credi
return grid_values
# Added posting_date as one of the parameters of get_exchange_rate
@frappe.whitelist()
def get_exchange_rate(posting_date, account=None, account_currency=None, company=None,
reference_type=None, reference_name=None, debit=None, credit=None, exchange_rate=None):
@ -890,6 +890,7 @@ def get_exchange_rate(posting_date, account=None, account_currency=None, company
# don't return None or 0 as it is multipled with a value and that value could be lost
return exchange_rate or 1
@frappe.whitelist()
def get_average_exchange_rate(account):
exchange_rate = 0
@ -899,14 +900,3 @@ def get_average_exchange_rate(account):
exchange_rate = bank_balance_in_company_currency / bank_balance_in_account_currency
return exchange_rate
@frappe.whitelist()
def get_invoice_due_dates(name):
result = frappe.get_list(
doctype='GL Entry', group_by='name, due_date',
filters={'voucher_no': name, "ifnull(due_date, '')": ('!=', '')},
fields=['due_date'], distinct=True
)
return result

View File

@ -618,7 +618,7 @@
"label": "Reference Type",
"length": 0,
"no_copy": 0,
"options": "\nSales Invoice\nPurchase Invoice\nJournal Entry\nSales Order\nPurchase Order\nExpense Claim\nAsset\nEmployee Loan\nPayroll Entry",
"options": "\nSales Invoice\nPurchase Invoice\nJournal Entry\nSales Order\nPurchase Order\nExpense Claim\nAsset\nEmployee Loan\nPayroll Entry\nEmployee Advance",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@ -662,38 +662,6 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.reference_type&&!in_list(doc.reference_type, ['Expense Claim', 'Asset', 'Employee Loan'])",
"fieldname": "reference_due_date",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Reference Due Date",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@ -827,7 +795,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-12-06 19:54:19.851534",
"modified": "2017-12-07 19:54:19.851534",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry Account",

View File

@ -4,10 +4,11 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import flt
from frappe import _, scrub
from frappe.utils import flt, nowdate
from frappe.model.document import Document
class OpeningInvoiceCreationTool(Document):
def onload(self):
"""Load the Opening Invoice summary"""
@ -67,29 +68,25 @@ class OpeningInvoiceCreationTool(Document):
for row in self.invoices:
if not row.qty:
row.qty = 1.0
if not row.party:
frappe.throw(mandatory_error_msg.format(
idx=row.idx,
field= _("Party"),
invoice_type=self.invoice_type
))
# set party type if not available
if not row.party_type:
row.party_type = "Customer" if self.invoice_type == "Sales" else "Supplier"
# always mandatory fields for the invoices
if not row.temporary_opening_account:
row.temporary_opening_account = get_temporary_opening_account(self.company)
row.party_type = "Customer" if self.invoice_type == "Sales" else "Supplier"
if not row.item_name:
row.item_name = _("Opening Invoice Item")
if not row.posting_date:
frappe.throw(mandatory_error_msg.format(
idx=row.idx,
field= _("Party"),
invoice_type=self.invoice_type
))
row.posting_date = nowdate()
if not row.due_date:
row.due_date = nowdate()
if not row.outstanding_amount:
frappe.throw(mandatory_error_msg.format(
idx=row.idx,
field= _("Outstanding Amount"),
invoice_type=self.invoice_type
))
for d in ("Party", "Outstanding Amount", "Temporary Opening Account"):
if not row.get(scrub(d)):
frappe.throw(mandatory_error_msg.format(
idx=row.idx,
field=_(d),
invoice_type=self.invoice_type
))
args = self.get_invoice_dict(row=row)
if not args:
@ -99,10 +96,14 @@ class OpeningInvoiceCreationTool(Document):
doc.submit()
names.append(doc.name)
if(len(self.invoices) > 5):
frappe.publish_realtime("progress",
dict(progress=[row.idx, len(self.invoices)], title=_('Creating {0}').format(doc.doctype)),
user=frappe.session.user)
if len(self.invoices) > 5:
frappe.publish_realtime(
"progress", dict(
progress=[row.idx, len(self.invoices)],
title=_('Creating {0}').format(doc.doctype)
),
user=frappe.session.user
)
return names
@ -111,8 +112,10 @@ class OpeningInvoiceCreationTool(Document):
default_uom = frappe.db.get_single_value("Stock Settings", "stock_uom") or _("Nos")
cost_center = frappe.db.get_value("Company", self.company, "cost_center")
if not cost_center:
frappe.throw(_("Please set the Default Cost Center in {0} company").format(frappe.bold(self.company)))
rate = flt(row.outstanding_amount) / row.qty
frappe.throw(
_("Please set the Default Cost Center in {0} company").format(frappe.bold(self.company))
)
rate = flt(row.outstanding_amount) / flt(row.qty)
return frappe._dict({
"uom": default_uom,
@ -143,8 +146,7 @@ class OpeningInvoiceCreationTool(Document):
"due_date": row.due_date,
"posting_date": row.posting_date,
frappe.scrub(party_type): row.party,
"doctype": "Sales Invoice" if self.invoice_type == "Sales" \
else "Purchase Invoice",
"doctype": "Sales Invoice" if self.invoice_type == "Sales" else "Purchase Invoice",
"currency": frappe.db.get_value("Company", self.company, "default_currency")
})

View File

@ -161,7 +161,7 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
@ -192,7 +192,7 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
@ -284,6 +284,66 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_4",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "1",
"fieldname": "qty",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Quantity",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
@ -300,7 +360,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-11-15 14:19:00.433148",
"modified": "2017-12-19 05:07:01.549918",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Opening Invoice Creation Tool Item",

View File

@ -266,6 +266,7 @@ frappe.ui.form.on('Payment Entry', {
}
},
() => frm.set_value("party_balance", r.message.party_balance),
() => frm.set_value("party_name", r.message.party_name),
() => frm.events.get_outstanding_documents(frm),
() => frm.events.hide_unhide_fields(frm),
() => frm.events.set_dynamic_labels(frm),
@ -408,7 +409,7 @@ frappe.ui.form.on('Payment Entry', {
}
// Make read only if Accounts Settings doesn't allow stale rates
frm.set_df_property("source_exchange_rate", "read_only", erpnext.stale_rate_allowed());
frm.set_df_property("source_exchange_rate", "read_only", erpnext.stale_rate_allowed() ? 0 : 1);
},
target_exchange_rate: function(frm) {
@ -429,7 +430,7 @@ frappe.ui.form.on('Payment Entry', {
frm.set_paid_amount_based_on_received_amount = false;
// Make read only if Accounts Settings doesn't allow stale rates
frm.set_df_property("target_exchange_rate", "read_only", erpnext.stale_rate_allowed());
frm.set_df_property("target_exchange_rate", "read_only", erpnext.stale_rate_allowed() ? 0 : 1);
},
paid_amount: function(frm) {

View File

@ -3,7 +3,7 @@
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe, json
import frappe, erpnext, json
from frappe import _, scrub, ValidationError
from frappe.utils import flt, comma_or, nowdate
from erpnext.accounts.utils import get_outstanding_invoices, get_account_currency, get_balance_on
@ -71,9 +71,10 @@ class PaymentEntry(AccountsController):
def validate_duplicate_entry(self):
reference_names = []
for d in self.get("references"):
if (d.reference_doctype, d.reference_name, d.due_date) in reference_names:
frappe.throw(_("Row #{0}: Duplicate entry in References {1} {2}").format(d.idx, d.reference_doctype, d.reference_name))
reference_names.append((d.reference_doctype, d.reference_name, d.due_date))
if (d.reference_doctype, d.reference_name) in reference_names:
frappe.throw(_("Row #{0}: Duplicate entry in References {1} {2}")
.format(d.idx, d.reference_doctype, d.reference_name))
reference_names.append((d.reference_doctype, d.reference_name))
def validate_allocated_amount(self):
for d in self.get("references"):
@ -147,7 +148,7 @@ class PaymentEntry(AccountsController):
if not frappe.db.exists(self.party_type, self.party):
frappe.throw(_("Invalid {0}: {1}").format(self.party_type, self.party))
if self.party_account:
if self.party_account and self.party_type != "Employee":
party_account_type = "Receivable" if self.party_type in ("Customer", "Student") else "Payable"
self.validate_account_type(self.party_account, [party_account_type])
@ -188,7 +189,7 @@ class PaymentEntry(AccountsController):
elif self.party_type == "Supplier":
valid_reference_doctypes = ("Purchase Order", "Purchase Invoice", "Journal Entry")
elif self.party_type == "Employee":
valid_reference_doctypes = ("Expense Claim", "Journal Entry")
valid_reference_doctypes = ("Expense Claim", "Journal Entry", "Employee Advance")
for d in self.get("references"):
if not d.allocated_amount:
@ -205,7 +206,7 @@ class PaymentEntry(AccountsController):
if d.reference_doctype != "Journal Entry":
if self.party != ref_doc.get(scrub(self.party_type)):
frappe.throw(_("{0} {1} does not associated with {2} {3}")
frappe.throw(_("{0} {1} is not associated with {2} {3}")
.format(d.reference_doctype, d.reference_name, self.party_type, self.party))
else:
self.validate_journal_entry()
@ -413,8 +414,7 @@ class PaymentEntry(AccountsController):
gle = party_gl_dict.copy()
gle.update({
"against_voucher_type": d.reference_doctype,
"against_voucher": d.reference_name,
"due_date": d.due_date
"against_voucher": d.reference_name
})
allocated_amount_in_company_currency = flt(flt(d.allocated_amount) * flt(d.exchange_rate),
@ -483,8 +483,9 @@ class PaymentEntry(AccountsController):
def update_advance_paid(self):
if self.payment_type in ("Receive", "Pay") and self.party:
for d in self.get("references"):
if d.allocated_amount and d.reference_doctype in ("Sales Order", "Purchase Order"):
frappe.get_doc(d.reference_doctype, d.reference_name).set_total_advance_paid()
if d.allocated_amount \
and d.reference_doctype in ("Sales Order", "Purchase Order", "Employee Advance"):
frappe.get_doc(d.reference_doctype, d.reference_name).set_total_advance_paid()
def update_expense_claim(self):
if self.payment_type in ("Pay") and self.party:
@ -507,13 +508,18 @@ def get_outstanding_reference_documents(args):
# Get negative outstanding sales /purchase invoices
negative_outstanding_invoices = []
if args.get("party_type") not in ["Student", "Employee"]:
if args.get("party_type") not in ["Student", "Employee"] and not args.get("voucher_no"):
negative_outstanding_invoices = get_negative_outstanding_invoices(args.get("party_type"),
args.get("party"), args.get("party_account"), party_account_currency, company_currency)
# Get positive outstanding sales /purchase invoices/ Fees
condition = ""
if args.get("voucher_type") and args.get("voucher_no"):
condition = " and voucher_type='{0}' and voucher_no='{1}'"\
.format(frappe.db.escape(args["voucher_type"]), frappe.db.escape(args["voucher_no"]))
outstanding_invoices = get_outstanding_invoices(args.get("party_type"), args.get("party"),
args.get("party_account"))
args.get("party_account"), condition=condition)
for d in outstanding_invoices:
d["exchange_rate"] = 1
@ -535,6 +541,7 @@ def get_outstanding_reference_documents(args):
return negative_outstanding_invoices + outstanding_invoices + orders_to_be_billed
def get_orders_to_be_billed(posting_date, party_type, party, party_account_currency, company_currency):
if party_type == "Customer":
voucher_type = 'Sales Order'
@ -563,18 +570,17 @@ def get_orders_to_be_billed(posting_date, party_type, party, party_account_curre
and abs(100 - per_billed) > 0.01
order by
transaction_date, name
""".format(**{
"ref_field": ref_field,
"voucher_type": voucher_type,
"party_type": scrub(party_type)
}), party, as_dict = True)
""".format(**{
"ref_field": ref_field,
"voucher_type": voucher_type,
"party_type": scrub(party_type)
}), party, as_dict=True)
order_list = []
for d in orders:
d["voucher_type"] = voucher_type
# This assumes that the exchange rate required is the one in the SO
d["exchange_rate"] = get_exchange_rate(party_account_currency,
company_currency, posting_date)
d["exchange_rate"] = get_exchange_rate(party_account_currency, company_currency, posting_date)
order_list.append(d)
return order_list
@ -608,6 +614,7 @@ def get_negative_outstanding_invoices(party_type, party, party_account, party_ac
"party_account": "debit_to" if party_type == "Customer" else "credit_to"
}), (party, party_account), as_dict=True)
@frappe.whitelist()
def get_party_details(company, party_type, party, date):
if not frappe.db.exists(party_type, party):
@ -617,15 +624,19 @@ def get_party_details(company, party_type, party, date):
account_currency = get_account_currency(party_account)
account_balance = get_balance_on(party_account, date)
_party_name = "title" if party_type == "Student" else party_type.lower() + "_name"
party_name = frappe.db.get_value(party_type, party, _party_name)
party_balance = get_balance_on(party_type=party_type, party=party)
return {
"party_account": party_account,
"party_name": party_name,
"party_account_currency": account_currency,
"party_balance": party_balance,
"account_balance": account_balance
}
@frappe.whitelist()
def get_account_details(account, date):
frappe.has_permission('Payment Entry', throw=True)
@ -635,6 +646,7 @@ def get_account_details(account, date):
"account_type": frappe.db.get_value("Account", account, "account_type")
})
@frappe.whitelist()
def get_company_defaults(company):
fields = ["write_off_account", "exchange_gain_loss_account", "cost_center"]
@ -647,19 +659,23 @@ def get_company_defaults(company):
return ret
@frappe.whitelist()
def get_reference_details(reference_doctype, reference_name, party_account_currency):
total_amount = outstanding_amount = exchange_rate = None
ref_doc = frappe.get_doc(reference_doctype, reference_name)
company_currency = ref_doc.get("company_currency") or erpnext.get_company_currency(ref_doc.company)
if reference_doctype == "Fees":
total_amount = ref_doc.get("grand_total")
exchange_rate = 1
outstanding_amount = ref_doc.get("outstanding_amount")
elif reference_doctype != "Journal Entry":
if party_account_currency == ref_doc.company_currency:
if party_account_currency == company_currency:
if ref_doc.doctype == "Expense Claim":
total_amount = ref_doc.total_sanctioned_amount
elif ref_doc.doctype == "Employee Advance":
total_amount = ref_doc.advance_amount
else:
total_amount = ref_doc.base_grand_total
exchange_rate = 1
@ -669,15 +685,18 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
# Get the exchange rate from the original ref doc
# or get it based on the posting date of the ref doc
exchange_rate = ref_doc.get("conversion_rate") or \
get_exchange_rate(party_account_currency, ref_doc.company_currency, ref_doc.posting_date)
get_exchange_rate(party_account_currency, company_currency, ref_doc.posting_date)
outstanding_amount = ref_doc.get("outstanding_amount") \
if reference_doctype in ("Sales Invoice", "Purchase Invoice", "Expense Claim") \
else flt(total_amount) - flt(ref_doc.advance_paid)
if reference_doctype in ("Sales Invoice", "Purchase Invoice", "Expense Claim"):
outstanding_amount = ref_doc.get("outstanding_amount")
elif reference_doctype == "Employee Advance":
outstanding_amount = ref_doc.advance_amount - flt(ref_doc.paid_amount)
else:
outstanding_amount = flt(total_amount) - flt(ref_doc.advance_paid)
else:
# Get the exchange rate based on the posting date of the ref doc
exchange_rate = get_exchange_rate(party_account_currency,
ref_doc.company_currency, ref_doc.posting_date)
company_currency, ref_doc.posting_date)
return frappe._dict({
"due_date": ref_doc.get("due_date"),
@ -686,6 +705,7 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
"exchange_rate": exchange_rate
})
@frappe.whitelist()
def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=None):
doc = frappe.get_doc(dt, dn)
@ -697,7 +717,7 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
party_type = "Customer"
elif dt in ("Purchase Invoice", "Purchase Order"):
party_type = "Supplier"
elif dt in ("Expense Claim"):
elif dt in ("Expense Claim", "Employee Advance"):
party_type = "Employee"
elif dt in ("Fees"):
party_type = "Student"
@ -709,6 +729,8 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
party_account = doc.credit_to
elif dt == "Fees":
party_account = doc.receivable_account
elif dt == "Employee Advance":
party_account = doc.advance_account
else:
party_account = get_party_account(party_type, doc.get(party_type.lower()), doc.company)
@ -733,7 +755,11 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
outstanding_amount = doc.outstanding_amount
elif dt in ("Expense Claim"):
grand_total = doc.total_sanctioned_amount
outstanding_amount = doc.total_sanctioned_amount - doc.total_amount_reimbursed
outstanding_amount = doc.total_sanctioned_amount \
- doc.total_amount_reimbursed - flt(doc.total_advance_amount)
elif dt == "Employee Advance":
grand_total = doc.advance_amount
outstanding_amount = flt(doc.advance_amount) - flt(doc.paid_amount)
elif dt == "Fees":
grand_total = doc.grand_total
outstanding_amount = doc.outstanding_amount
@ -776,26 +802,16 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
pe.received_amount = received_amount
pe.allocate_payment_amount = 1
pe.letter_head = doc.get("letter_head")
args = {
'party_account': party_account, 'company': pe.company, 'party_type': pe.party_type,
'party': pe.party, 'posting_date': pe.posting_date
}
references = get_outstanding_reference_documents(args=args)
for reference in references:
if reference.voucher_no == dn:
allocated_amount = min(paid_amount, reference.outstanding_amount)
pe.append("references", {
'reference_doctype': reference.voucher_type,
'reference_name': reference.voucher_no,
'due_date': reference.due_date,
'total_amount': reference.invoice_amount,
'outstanding_amount': reference.outstanding_amount,
'allocated_amount': allocated_amount,
"bill_no": reference.get("bill_no")
})
if paid_amount:
paid_amount -= allocated_amount
pe.append("references", {
'reference_doctype': dt,
'reference_name': dn,
"bill_no": doc.get("bill_no"),
"due_date": doc.get("due_date"),
'total_amount': grand_total,
'outstanding_amount': outstanding_amount,
'allocated_amount': outstanding_amount
})
pe.setup_party_account_field()
pe.set_missing_values()

View File

@ -66,18 +66,6 @@ class TestPaymentEntry(unittest.TestCase):
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"))
self.assertEqual(outstanding_amount, 100)
def test_payment_entry_against_si_multi_due_dates(self):
si = create_sales_invoice(do_not_save=1)
si.payment_terms_template = '_Test Payment Term Template'
si.insert()
si.submit()
pe = get_payment_entry(si.doctype, si.name)
pe.reference_no = "1"
pe.reference_date = "2016-01-01"
pe.insert()
pe.submit()
def test_payment_entry_against_pi(self):
pi = make_purchase_invoice(supplier="_Test Supplier USD", debit_to="_Test Payable USD - _TC",
currency="USD", conversion_rate=50)
@ -106,6 +94,7 @@ class TestPaymentEntry(unittest.TestCase):
pe.reference_no = "1"
pe.reference_date = "2016-01-01"
pe.source_exchange_rate = 1
pe.paid_to = payable
pe.insert()
pe.submit()

View File

@ -67,7 +67,7 @@
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
@ -98,7 +98,7 @@
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
@ -160,7 +160,7 @@
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
@ -179,8 +179,8 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-11-23 12:39:02.013040",
"modified_by": "Administrator",
"modified": "2017-12-19 16:20:33.546984",
"modified_by": "nabinhait@gmail.com",
"module": "Accounts",
"name": "Payment Schedule",
"name_case": "",

View File

@ -106,11 +106,6 @@ cur_frm.fields_dict['select_print_heading'].get_query = function(doc, cdt, cdn)
};
};
cur_frm.fields_dict.user.get_query = function(doc,cdt,cdn) {
return{ query:"frappe.core.doctype.user.user.user_query"};
};
cur_frm.fields_dict.write_off_account.get_query = function(doc) {
return{
filters:{

View File

@ -101,38 +101,6 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "user",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Applicable for User",
"length": 0,
"no_copy": 0,
"oldfieldname": "user",
"oldfieldtype": "Link",
"options": "User",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 1,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@ -162,7 +130,7 @@
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 1,
"set_only_once": 0,
"unique": 0
},
{
@ -1508,7 +1476,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-11-24 14:08:09.184226",
"modified": "2018-01-03 17:30:45.198147",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Profile",

View File

@ -31,8 +31,8 @@ class POSProfile(Document):
msgprint(_("Already set default in pos profile {0} for user {1}, kindly disabled default")
.format(res[0][0], row.user), raise_exception=1)
elif not row.default and not res:
msgprint(_("Row {0}: set atleast one default pos profile for user {1}")
.format(row.idx, row.user), raise_exception=1)
msgprint(_("User {0} doesn't have any default POS Profile. Check Default at Row {1} for this User.")
.format(row.user, row.idx), raise_exception=1)
def validate_all_link_fields(self):
accounts = {"Account": [self.income_account,
@ -63,7 +63,11 @@ class POSProfile(Document):
if len(default_mode_of_payment) > 1:
frappe.throw(_("Multiple default mode of payment is not allowed"))
def validate_customer_territory_group(self):
if not frappe.db.get_single_value('POS Settings', 'use_pos_in_offline_mode'):
return
if not self.territory:
frappe.throw(_("Territory is Required in POS Profile"), title="Mandatory Field")
@ -83,12 +87,12 @@ class POSProfile(Document):
frappe.defaults.clear_default("is_pos")
if not include_current_pos:
condition = " where name != '%s'" % self.name.replace("'", "\'")
condition = " where pfu.name != '%s' and pfu.default = 1 " % self.name.replace("'", "\'")
else:
condition = ""
condition = " where pfu.default = 1 "
pos_view_users = frappe.db.sql_list("""select user
from `tabPOS Profile` {0}""".format(condition))
pos_view_users = frappe.db.sql_list("""select pfu.user
from `tabPOS Profile User` as pfu {0}""".format(condition))
for user in pos_view_users:
if user:
@ -103,7 +107,7 @@ def get_item_groups(pos_profile):
if pos_profile.get('item_groups'):
# Get items based on the item groups defined in the POS profile
for data in pos_profile.get('item_groups'):
item_groups.extend(["'%s'"%d.name for d in get_child_nodes('Item Group', data.item_group)])
item_groups.extend(["'%s'" % frappe.db.escape(d.name) for d in get_child_nodes('Item Group', data.item_group)])
return list(set(item_groups))

View File

@ -140,6 +140,37 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "tax_id",
"fieldtype": "Read Only",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Tax Id",
"length": 0,
"no_copy": 0,
"options": "supplier.tax_id",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@ -161,7 +192,7 @@
"oldfieldname": "due_date",
"oldfieldtype": "Date",
"permlevel": 0,
"print_hide": 1,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@ -3086,7 +3117,7 @@
"options": "Payment Schedule",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@ -3883,7 +3914,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2017-11-29 13:44:40.722157",
"modified": "2017-12-20 17:49:51.230092",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",

View File

@ -277,6 +277,8 @@ class PurchaseInvoice(BuyingController):
.format(item.purchase_receipt))
def on_submit(self):
super(PurchaseInvoice, self).on_submit()
self.check_prev_docstatus()
self.update_status_updater_args()
@ -348,7 +350,6 @@ class PurchaseInvoice(BuyingController):
self.negative_expense_to_be_booked = 0.0
gl_entries = []
self.make_supplier_gl_entry(gl_entries)
self.make_item_gl_entries(gl_entries)
self.make_tax_gl_entries(gl_entries)
@ -363,27 +364,7 @@ class PurchaseInvoice(BuyingController):
def make_supplier_gl_entry(self, gl_entries):
grand_total = self.rounded_total or self.grand_total
if self.get("payment_schedule"):
for d in self.get("payment_schedule"):
payment_amount_in_company_currency = flt(d.payment_amount * self.conversion_rate,
d.precision("payment_amount"))
gl_entries.append(
self.get_gl_dict({
"account": self.credit_to,
"party_type": "Supplier",
"party": self.supplier,
"due_date": d.due_date,
"against": self.against_expense_account,
"credit": payment_amount_in_company_currency,
"credit_in_account_currency": payment_amount_in_company_currency \
if self.party_account_currency==self.company_currency else d.payment_amount,
"against_voucher": self.return_against if cint(self.is_return) else self.name,
"against_voucher_type": self.doctype
}, self.party_account_currency)
)
elif grand_total:
if grand_total:
# Didnot use base_grand_total to book rounding loss gle
grand_total_in_company_currency = flt(grand_total * self.conversion_rate,
self.precision("grand_total"))
@ -442,7 +423,10 @@ class PurchaseInvoice(BuyingController):
# sub-contracting warehouse
if flt(item.rm_supp_cost):
supplier_warehouse_account = warehouse_account[self.supplier_warehouse]["name"]
supplier_warehouse_account = warehouse_account[self.supplier_warehouse]["account"]
if not supplier_warehouse_account:
frappe.throw(_("Please set account in Warehouse {0}")
.format(self.supplier_warehouse))
gl_entries.append(self.get_gl_dict({
"account": supplier_warehouse_account,
"against": item.expense_account,
@ -626,6 +610,8 @@ class PurchaseInvoice(BuyingController):
))
def on_cancel(self):
super(PurchaseInvoice, self).on_cancel()
self.check_for_closed_status()
self.update_status_updater_args()

View File

@ -1,7 +1,7 @@
QUnit.module('Purchase Invoice');
QUnit.test("test purchase invoice", function(assert) {
assert.expect(6);
assert.expect(9);
let done = assert.async();
frappe.run_serially([
() => {
@ -18,7 +18,7 @@ QUnit.test("test purchase invoice", function(assert) {
{update_stock:1},
{supplier_address: 'Test1-Billing'},
{contact_person: 'Contact 3-Test Supplier'},
{taxes_and_charges: 'TEST In State GST'},
{taxes_and_charges: 'TEST In State GST - FT'},
{tc_name: 'Test Term 1'},
{terms: 'This is Test'},
{payment_terms_template: '_Test Payment Term Template UI'}
@ -29,7 +29,7 @@ QUnit.test("test purchase invoice", function(assert) {
// get_item_details
assert.ok(cur_frm.doc.items[0].item_name=='Test Product 1', "Item name correct");
// get tax details
assert.ok(cur_frm.doc.taxes_and_charges=='TEST In State GST', "Tax details correct");
assert.ok(cur_frm.doc.taxes_and_charges=='TEST In State GST - FT', "Tax details correct");
// get tax account head details
assert.ok(cur_frm.doc.taxes[0].account_head=='CGST - '+frappe.get_abbr(frappe.defaults.get_default('Company')), " Account Head abbr correct");
// grand_total Calculated
@ -39,6 +39,33 @@ QUnit.test("test purchase invoice", function(assert) {
assert.ok(cur_frm.doc.payment_schedule.length > 0, "Payment Term Schedule is not empty");
},
() => {
let date = cur_frm.doc.due_date;
frappe.tests.set_control('due_date', frappe.datetime.add_days(date, 1));
frappe.timeout(0.5);
assert.ok(cur_dialog && cur_dialog.is_visible, 'Message is displayed to user');
},
() => frappe.timeout(1),
() => frappe.tests.click_button('Close'),
() => frappe.timeout(0.5),
() => frappe.tests.set_form_values(cur_frm, [{'payment_terms_schedule': ''}]),
() => {
let date = cur_frm.doc.due_date;
frappe.tests.set_control('due_date', frappe.datetime.add_days(date, 1));
frappe.timeout(0.5);
assert.ok(cur_dialog && cur_dialog.is_visible, 'Message is displayed to user');
},
() => frappe.timeout(1),
() => frappe.tests.click_button('Close'),
() => frappe.timeout(0.5),
() => frappe.tests.set_form_values(cur_frm, [{'payment_schedule': []}]),
() => {
let date = cur_frm.doc.due_date;
frappe.tests.set_control('due_date', frappe.datetime.add_days(date, 1));
frappe.timeout(0.5);
assert.ok(!cur_dialog, 'Message is not shown');
},
() => cur_frm.save(),
() => frappe.tests.click_button('Submit'),
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(1),

View File

@ -6,7 +6,7 @@ from __future__ import unicode_literals
import unittest
import frappe, erpnext
import frappe.model
from frappe.utils import cint, flt, today, nowdate, getdate, add_days
from frappe.utils import cint, flt, today, nowdate, add_days
import frappe.defaults
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory, \
test_records as pr_test_records
@ -27,6 +27,7 @@ class TestPurchaseInvoice(unittest.TestCase):
unlink_payment_on_cancel_of_invoice(0)
def test_gl_entries_without_perpetual_inventory(self):
frappe.db.set_value("Company", "_Test Company", "round_off_account", "Round Off - _TC")
wrapper = frappe.copy_doc(test_records[0])
set_perpetual_inventory(0, wrapper.company)
self.assertTrue(not cint(erpnext.is_perpetual_inventory_enabled(wrapper.company)))
@ -647,39 +648,6 @@ class TestPurchaseInvoice(unittest.TestCase):
self.assertEquals(pi.total_taxes_and_charges, 462.3)
self.assertEquals(pi.grand_total, 1712.3)
def test_gl_entry_based_on_payment_schedule(self):
pi = make_purchase_invoice(do_not_save=True, supplier="_Test Supplier P")
pi.append("payment_schedule", {
"due_date": add_days(nowdate(), 15),
"payment_amount": 100,
"invoice_portion": 40.00
})
pi.append("payment_schedule", {
"due_date": add_days(nowdate(), 25),
"payment_amount": 150,
"invoice_portion": 60.00
})
pi.save()
pi.submit()
gl_entries = frappe.db.sql("""select account, debit, credit, due_date
from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
order by account asc, debit asc""", pi.name, as_dict=1)
self.assertTrue(gl_entries)
expected_gl_entries = sorted([
[pi.credit_to, 0.0, 100.0, add_days(nowdate(), 15)],
[pi.credit_to, 0.0, 150.0, add_days(nowdate(), 25)],
["_Test Account Cost for Goods Sold - _TC", 250.0, 0.0, None]
])
for i, gle in enumerate(sorted(gl_entries, key=lambda gle: gle.account)):
self.assertEquals(expected_gl_entries[i][0], gle.account)
self.assertEquals(expected_gl_entries[i][1], gle.debit)
self.assertEquals(expected_gl_entries[i][2], gle.credit)
self.assertEquals(getdate(expected_gl_entries[i][3]), getdate(gle.due_date))
def test_make_pi_without_terms(self):
pi = make_purchase_invoice(do_not_save=1)

View File

@ -3,6 +3,7 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
from erpnext.accounts.doctype.sales_taxes_and_charges_template.sales_taxes_and_charges_template \
import valdiate_taxes_and_charges_template
@ -10,3 +11,8 @@ from erpnext.accounts.doctype.sales_taxes_and_charges_template.sales_taxes_and_c
class PurchaseTaxesandChargesTemplate(Document):
def validate(self):
valdiate_taxes_and_charges_template(self)
def autoname(self):
if self.company and self.title:
abbr = frappe.db.get_value('Company', self.company, 'abbr')
self.name = '{0} - {1}'.format(self.title, abbr)

View File

@ -1,7 +1,7 @@
QUnit.module('Sales Taxes and Charges Template');
QUnit.test("test sales taxes and charges template", function(assert) {
assert.expect(1);
assert.expect(2);
let done = assert.async();
frappe.run_serially([
() => {
@ -19,7 +19,10 @@ QUnit.test("test sales taxes and charges template", function(assert) {
]}
]);
},
() => {assert.ok(cur_frm.doc.title=='TEST In State GST');},
() => {
assert.ok(cur_frm.doc.title=='TEST In State GST');
assert.ok(cur_frm.doc.name=='TEST In State GST - FT');
},
() => done()
]);
});

View File

@ -503,7 +503,7 @@
"oldfieldname": "due_date",
"oldfieldtype": "Date",
"permlevel": 0,
"print_hide": 1,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@ -2864,7 +2864,7 @@
"options": "Payment Schedule",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@ -4563,7 +4563,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2017-11-29 17:36:05.216046",
"modified": "2017-12-20 17:36:05.216046",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",

View File

@ -143,6 +143,7 @@ class SalesInvoice(SellingController):
self.update_time_sheet(self.name)
self.update_current_month_sales()
self.update_project()
def validate_pos_paid_amount(self):
if len(self.payments) == 0 and self.is_pos:
@ -181,6 +182,7 @@ class SalesInvoice(SellingController):
frappe.db.set(self, 'status', 'Cancelled')
self.update_current_month_sales()
self.update_project()
def update_current_month_sales(self):
if frappe.flags.in_test:
@ -635,27 +637,7 @@ class SalesInvoice(SellingController):
def make_customer_gl_entry(self, gl_entries):
grand_total = self.rounded_total or self.grand_total
if self.get("payment_schedule"):
for d in self.get("payment_schedule"):
payment_amount_in_company_currency = flt(d.payment_amount * self.conversion_rate,
d.precision("payment_amount"))
gl_entries.append(
self.get_gl_dict({
"account": self.debit_to,
"party_type": "Customer",
"party": self.customer,
"due_date": d.due_date,
"against": self.against_income_account,
"debit": payment_amount_in_company_currency,
"debit_in_account_currency": payment_amount_in_company_currency \
if self.party_account_currency==self.company_currency else d.payment_amount,
"against_voucher": self.return_against if cint(self.is_return) else self.name,
"against_voucher_type": self.doctype
}, self.party_account_currency)
)
elif grand_total:
if grand_total:
# Didnot use base_grand_total to book rounding loss gle
grand_total_in_company_currency = flt(grand_total * self.conversion_rate,
self.precision("grand_total"))
@ -912,6 +894,13 @@ class SalesInvoice(SellingController):
serial_no, sales_invoice
)))
def update_project(self):
if self.project:
project = frappe.get_doc("Project", self.project)
project.flags.dont_sync_tasks = True
project.update_billed_amount()
project.save()
def get_list_context(context=None):
from erpnext.controllers.website_list_for_contact import get_list_context
list_context = get_list_context(context)

View File

@ -1,7 +1,7 @@
QUnit.module('Sales Invoice');
QUnit.test("test sales Invoice", function(assert) {
assert.expect(6);
assert.expect(9);
let done = assert.async();
frappe.run_serially([
() => {
@ -17,7 +17,7 @@ QUnit.test("test sales Invoice", function(assert) {
{customer_address: 'Test1-Billing'},
{shipping_address_name: 'Test1-Shipping'},
{contact_person: 'Contact 1-Test Customer 1'},
{taxes_and_charges: 'TEST In State GST'},
{taxes_and_charges: 'TEST In State GST - FT'},
{tc_name: 'Test Term 1'},
{terms: 'This is Test'},
{payment_terms_template: '_Test Payment Term Template UI'}
@ -28,7 +28,7 @@ QUnit.test("test sales Invoice", function(assert) {
// get_item_details
assert.ok(cur_frm.doc.items[0].item_name=='Test Product 1', "Item name correct");
// get tax details
assert.ok(cur_frm.doc.taxes_and_charges=='TEST In State GST', "Tax details correct");
assert.ok(cur_frm.doc.taxes_and_charges=='TEST In State GST - FT', "Tax details correct");
// get tax account head details
assert.ok(cur_frm.doc.taxes[0].account_head=='CGST - '+frappe.get_abbr(frappe.defaults.get_default('Company')), " Account Head abbr correct");
// grand_total Calculated
@ -38,6 +38,33 @@ QUnit.test("test sales Invoice", function(assert) {
assert.ok(cur_frm.doc.payment_schedule.length > 0, "Payment Term Schedule is not empty");
},
() => {
let date = cur_frm.doc.due_date;
frappe.tests.set_control('due_date', frappe.datetime.add_days(date, 1));
frappe.timeout(0.5);
assert.ok(cur_dialog && cur_dialog.is_visible, 'Message is displayed to user');
},
() => frappe.timeout(1),
() => frappe.tests.click_button('Close'),
() => frappe.timeout(0.5),
() => frappe.tests.set_form_values(cur_frm, [{'payment_terms_schedule': ''}]),
() => {
let date = cur_frm.doc.due_date;
frappe.tests.set_control('due_date', frappe.datetime.add_days(date, 1));
frappe.timeout(0.5);
assert.ok(cur_dialog && cur_dialog.is_visible, 'Message is displayed to user');
},
() => frappe.timeout(1),
() => frappe.tests.click_button('Close'),
() => frappe.timeout(0.5),
() => frappe.tests.set_form_values(cur_frm, [{'payment_schedule': []}]),
() => {
let date = cur_frm.doc.due_date;
frappe.tests.set_control('due_date', frappe.datetime.add_days(date, 1));
frappe.timeout(0.5);
assert.ok(!cur_dialog, 'Message is not shown');
},
() => cur_frm.save(),
() => frappe.tests.click_button('Submit'),
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(0.3),

View File

@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe
import unittest, copy, time
from frappe.utils import nowdate, add_days, flt, getdate, cint
from frappe.utils import nowdate, flt, getdate, cint
from frappe.model.dynamic_links import get_dynamic_link_map
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry, get_qty_after_transaction
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import unlink_payment_on_cancel_of_invoice
@ -1322,40 +1322,6 @@ class TestSalesInvoice(unittest.TestCase):
si.insert()
return si
def test_gl_entry_based_on_payment_schedule(self):
si = create_sales_invoice(do_not_save=True, customer="_Test Customer P")
si.append("payment_schedule", {
"due_date": add_days(nowdate(), 15),
"payment_amount": 20,
"invoice_portion": 20.00
})
si.append("payment_schedule", {
"due_date": add_days(nowdate(), 45),
"payment_amount": 80,
"invoice_portion": 80.00
})
si.save()
si.submit()
gl_entries = frappe.db.sql("""select account, debit, credit, due_date
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
order by account asc, debit asc""", si.name, as_dict=1)
self.assertTrue(gl_entries)
expected_gl_entries = sorted([
[si.debit_to, 20.0, 0.0, add_days(nowdate(), 15)],
[si.debit_to, 80.0, 0.0, add_days(nowdate(), 45)],
["Sales - _TC", 0.0, 100.0, None]
])
for i, gle in enumerate(sorted(gl_entries, key=lambda gle: gle.account)):
self.assertEquals(expected_gl_entries[i][0], gle.account)
self.assertEquals(expected_gl_entries[i][1], gle.debit)
self.assertEquals(expected_gl_entries[i][2], gle.credit)
self.assertEquals(getdate(expected_gl_entries[i][3]), getdate(gle.due_date))
def test_company_monthly_sales(self):
existing_current_month_sales = frappe.db.get_value("Company", "_Test Company", "total_monthly_sales")

View File

@ -17,7 +17,7 @@ QUnit.test("test sales Invoice", function(assert) {
{customer_address: 'Test1-Billing'},
{shipping_address_name: 'Test1-Shipping'},
{contact_person: 'Contact 1-Test Customer 1'},
{taxes_and_charges: 'TEST In State GST'},
{taxes_and_charges: 'TEST In State GST - FT'},
{tc_name: 'Test Term 1'},
{terms: 'This is Test'}
]);
@ -27,7 +27,7 @@ QUnit.test("test sales Invoice", function(assert) {
// get_item_details
assert.ok(cur_frm.doc.items[0].item_name=='Test Product 1', "Item name correct");
// get tax details
assert.ok(cur_frm.doc.taxes_and_charges=='TEST In State GST', "Tax details correct");
assert.ok(cur_frm.doc.taxes_and_charges=='TEST In State GST - FT', "Tax details correct");
// get tax account head details
assert.ok(cur_frm.doc.taxes[0].account_head=='CGST - '+frappe.get_abbr(frappe.defaults.get_default('Company')), " Account Head abbr correct");
// grand_total Calculated

View File

@ -17,7 +17,7 @@ QUnit.test("test sales Invoice with payment", function(assert) {
{customer_address: 'Test1-Billing'},
{shipping_address_name: 'Test1-Shipping'},
{contact_person: 'Contact 1-Test Customer 1'},
{taxes_and_charges: 'TEST In State GST'},
{taxes_and_charges: 'TEST In State GST - FT'},
{tc_name: 'Test Term 1'},
{terms: 'This is Test'},
{payment_terms_template: '_Test Payment Term Template UI'}
@ -28,7 +28,7 @@ QUnit.test("test sales Invoice with payment", function(assert) {
// get_item_details
assert.ok(cur_frm.doc.items[0].item_name=='Test Product 1', "Item name correct");
// get tax details
assert.ok(cur_frm.doc.taxes_and_charges=='TEST In State GST', "Tax details correct");
assert.ok(cur_frm.doc.taxes_and_charges=='TEST In State GST - FT', "Tax details correct");
// grand_total Calculated
assert.ok(cur_frm.doc.grand_total==590, "Grad Total correct");

View File

@ -17,7 +17,7 @@ QUnit.test("test sales Invoice with payment request", function(assert) {
{customer_address: 'Test1-Billing'},
{shipping_address_name: 'Test1-Shipping'},
{contact_person: 'Contact 1-Test Customer 1'},
{taxes_and_charges: 'TEST In State GST'},
{taxes_and_charges: 'TEST In State GST - FT'},
{tc_name: 'Test Term 1'},
{terms: 'This is Test'}
]);
@ -27,7 +27,7 @@ QUnit.test("test sales Invoice with payment request", function(assert) {
// get_item_details
assert.ok(cur_frm.doc.items[0].item_name=='Test Product 1', "Item name correct");
// get tax details
assert.ok(cur_frm.doc.taxes_and_charges=='TEST In State GST', "Tax details correct");
assert.ok(cur_frm.doc.taxes_and_charges=='TEST In State GST - FT', "Tax details correct");
// grand_total Calculated
assert.ok(cur_frm.doc.grand_total==590, "Grad Total correct");

View File

@ -17,7 +17,7 @@ QUnit.test("test sales Invoice with serialize item", function(assert) {
{customer_address: 'Test1-Billing'},
{shipping_address_name: 'Test1-Shipping'},
{contact_person: 'Contact 1-Test Customer 1'},
{taxes_and_charges: 'TEST In State GST'},
{taxes_and_charges: 'TEST In State GST - FT'},
{tc_name: 'Test Term 1'},
{terms: 'This is Test'}
]);
@ -27,7 +27,7 @@ QUnit.test("test sales Invoice with serialize item", function(assert) {
// get_item_details
assert.ok(cur_frm.doc.items[0].item_name=='Test Product 4', "Item name correct");
// get tax details
assert.ok(cur_frm.doc.taxes_and_charges=='TEST In State GST', "Tax details correct");
assert.ok(cur_frm.doc.taxes_and_charges=='TEST In State GST - FT', "Tax details correct");
// get tax account head details
assert.ok(cur_frm.doc.taxes[0].account_head=='CGST - '+frappe.get_abbr(frappe.defaults.get_default('Company')), " Account Head abbr correct");
// get batch number

View File

@ -12,6 +12,11 @@ class SalesTaxesandChargesTemplate(Document):
def validate(self):
valdiate_taxes_and_charges_template(self)
def autoname(self):
if self.company and self.title:
abbr = frappe.db.get_value('Company', self.company, 'abbr')
self.name = '{0} - {1}'.format(self.title, abbr)
def set_missing_values(self):
for data in self.taxes:
if data.charge_type == 'On Net Total' and flt(data.rate) == 0.0:

View File

@ -1,7 +1,7 @@
QUnit.module('Sales Taxes and Charges Template');
QUnit.test("test sales taxes and charges template", function(assert) {
assert.expect(1);
assert.expect(2);
let done = assert.async();
frappe.run_serially([
() => {
@ -19,7 +19,10 @@ QUnit.test("test sales taxes and charges template", function(assert) {
]}
]);
},
() => {assert.ok(cur_frm.doc.title=='TEST In State GST');},
() => {
assert.ok(cur_frm.doc.title=='TEST In State GST');
assert.ok(cur_frm.doc.name=='TEST In State GST - FT');
},
() => done()
]);
});

View File

@ -2,7 +2,7 @@
{
"doctype": "Tax Rule",
"tax_type" : "Sales",
"sales_tax_template": "_Test Tax 1",
"sales_tax_template": "_Test Tax 1 - _TC",
"use_for_shopping_cart": 1,
"billing_city": "_Test City",
"billing_state": "Test State",
@ -15,7 +15,7 @@
{
"doctype": "Tax Rule",
"tax_type" : "Sales",
"sales_tax_template": "_Test Tax 2",
"sales_tax_template": "_Test Tax 2 - _TC",
"use_for_shopping_cart": 0,
"billing_city": "_Test City",
"billing_country": "India",

View File

@ -18,40 +18,40 @@ class TestTaxRule(unittest.TestCase):
def test_conflict(self):
tax_rule1 = make_tax_rule(customer= "_Test Customer",
sales_tax_template = "_Test Sales Taxes and Charges Template", priority = 1)
sales_tax_template = "_Test Sales Taxes and Charges Template - _TC", priority = 1)
tax_rule1.save()
tax_rule2 = make_tax_rule(customer= "_Test Customer",
sales_tax_template = "_Test Sales Taxes and Charges Template", priority = 1)
sales_tax_template = "_Test Sales Taxes and Charges Template - _TC", priority = 1)
self.assertRaises(ConflictingTaxRule, tax_rule2.save)
def test_conflict_with_non_overlapping_dates(self):
tax_rule1 = make_tax_rule(customer= "_Test Customer",
sales_tax_template = "_Test Sales Taxes and Charges Template", priority = 1, from_date = "2015-01-01")
sales_tax_template = "_Test Sales Taxes and Charges Template - _TC", priority = 1, from_date = "2015-01-01")
tax_rule1.save()
tax_rule2 = make_tax_rule(customer= "_Test Customer",
sales_tax_template = "_Test Sales Taxes and Charges Template", priority = 1, to_date = "2013-01-01")
sales_tax_template = "_Test Sales Taxes and Charges Template - _TC", priority = 1, to_date = "2013-01-01")
tax_rule2.save()
self.assertTrue(tax_rule2.name)
def test_for_parent_customer_group(self):
tax_rule1 = make_tax_rule(customer_group= "All Customer Groups",
sales_tax_template = "_Test Sales Taxes and Charges Template", priority = 1, from_date = "2015-01-01")
sales_tax_template = "_Test Sales Taxes and Charges Template - _TC", priority = 1, from_date = "2015-01-01")
tax_rule1.save()
self.assertEquals(get_tax_template("2015-01-01", {"customer_group" : "Commercial", "use_for_shopping_cart":0}),
"_Test Sales Taxes and Charges Template")
"_Test Sales Taxes and Charges Template - _TC")
def test_conflict_with_overlapping_dates(self):
tax_rule1 = make_tax_rule(customer= "_Test Customer",
sales_tax_template = "_Test Sales Taxes and Charges Template", priority = 1, from_date = "2015-01-01", to_date = "2015-01-05")
sales_tax_template = "_Test Sales Taxes and Charges Template - _TC", priority = 1, from_date = "2015-01-01", to_date = "2015-01-05")
tax_rule1.save()
tax_rule2 = make_tax_rule(customer= "_Test Customer",
sales_tax_template = "_Test Sales Taxes and Charges Template", priority = 1, from_date = "2015-01-03", to_date = "2015-01-09")
sales_tax_template = "_Test Sales Taxes and Charges Template - _TC", priority = 1, from_date = "2015-01-03", to_date = "2015-01-09")
self.assertRaises(ConflictingTaxRule, tax_rule2.save)
@ -62,66 +62,66 @@ class TestTaxRule(unittest.TestCase):
def test_select_tax_rule_based_on_customer(self):
make_tax_rule(customer= "_Test Customer",
sales_tax_template = "_Test Sales Taxes and Charges Template", save=1)
sales_tax_template = "_Test Sales Taxes and Charges Template - _TC", save=1)
make_tax_rule(customer= "_Test Customer 1",
sales_tax_template = "_Test Sales Taxes and Charges Template 1", save=1)
sales_tax_template = "_Test Sales Taxes and Charges Template 1 - _TC", save=1)
make_tax_rule(customer= "_Test Customer 2",
sales_tax_template = "_Test Sales Taxes and Charges Template 2", save=1)
sales_tax_template = "_Test Sales Taxes and Charges Template 2 - _TC", save=1)
self.assertEquals(get_tax_template("2015-01-01", {"customer":"_Test Customer 2"}),
"_Test Sales Taxes and Charges Template 2")
"_Test Sales Taxes and Charges Template 2 - _TC")
def test_select_tax_rule_based_on_better_match(self):
make_tax_rule(customer= "_Test Customer", billing_city = "Test City", billing_state = "Test State",
sales_tax_template = "_Test Sales Taxes and Charges Template", save=1)
sales_tax_template = "_Test Sales Taxes and Charges Template - _TC", save=1)
make_tax_rule(customer= "_Test Customer", billing_city = "Test City1", billing_state = "Test State",
sales_tax_template = "_Test Sales Taxes and Charges Template 1", save=1)
sales_tax_template = "_Test Sales Taxes and Charges Template 1 - _TC", save=1)
self.assertEquals(get_tax_template("2015-01-01", {"customer":"_Test Customer", "billing_city": "Test City", "billing_state": "Test State"}),
"_Test Sales Taxes and Charges Template")
"_Test Sales Taxes and Charges Template - _TC")
def test_select_tax_rule_based_on_state_match(self):
make_tax_rule(customer= "_Test Customer", shipping_state = "Test State",
sales_tax_template = "_Test Sales Taxes and Charges Template", save=1)
sales_tax_template = "_Test Sales Taxes and Charges Template - _TC", save=1)
make_tax_rule(customer= "_Test Customer", shipping_state = "Test State12",
sales_tax_template = "_Test Sales Taxes and Charges Template 1", priority=2, save=1)
sales_tax_template = "_Test Sales Taxes and Charges Template 1 - _TC", priority=2, save=1)
self.assertEquals(get_tax_template("2015-01-01", {"customer":"_Test Customer", "shipping_state": "Test State"}),
"_Test Sales Taxes and Charges Template")
"_Test Sales Taxes and Charges Template - _TC")
def test_select_tax_rule_based_on_better_priority(self):
make_tax_rule(customer= "_Test Customer", billing_city = "Test City",
sales_tax_template = "_Test Sales Taxes and Charges Template", priority=1, save=1)
sales_tax_template = "_Test Sales Taxes and Charges Template - _TC", priority=1, save=1)
make_tax_rule(customer= "_Test Customer", billing_city = "Test City",
sales_tax_template = "_Test Sales Taxes and Charges Template 1", priority=2, save=1)
sales_tax_template = "_Test Sales Taxes and Charges Template 1 - _TC", priority=2, save=1)
self.assertEquals(get_tax_template("2015-01-01", {"customer":"_Test Customer", "billing_city": "Test City"}),
"_Test Sales Taxes and Charges Template 1")
"_Test Sales Taxes and Charges Template 1 - _TC")
def test_select_tax_rule_based_cross_matching_keys(self):
make_tax_rule(customer= "_Test Customer", billing_city = "Test City",
sales_tax_template = "_Test Sales Taxes and Charges Template", save=1)
sales_tax_template = "_Test Sales Taxes and Charges Template - _TC", save=1)
make_tax_rule(customer= "_Test Customer 1", billing_city = "Test City 1",
sales_tax_template = "_Test Sales Taxes and Charges Template 1", save=1)
sales_tax_template = "_Test Sales Taxes and Charges Template 1 - _TC", save=1)
self.assertEquals(get_tax_template("2015-01-01", {"customer":"_Test Customer", "billing_city": "Test City 1"}),
None)
def test_select_tax_rule_based_cross_partially_keys(self):
make_tax_rule(customer= "_Test Customer", billing_city = "Test City",
sales_tax_template = "_Test Sales Taxes and Charges Template", save=1)
sales_tax_template = "_Test Sales Taxes and Charges Template - _TC", save=1)
make_tax_rule(billing_city = "Test City 1",
sales_tax_template = "_Test Sales Taxes and Charges Template 1", save=1)
sales_tax_template = "_Test Sales Taxes and Charges Template 1 - _TC", save=1)
self.assertEquals(get_tax_template("2015-01-01", {"customer":"_Test Customer", "billing_city": "Test City 1"}),
"_Test Sales Taxes and Charges Template 1")
"_Test Sales Taxes and Charges Template 1 - _TC")
def make_tax_rule(**args):

View File

@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe, erpnext
from frappe.utils import flt, cstr, cint, getdate
from frappe.utils import flt, cstr, cint
from frappe import _
from frappe.model.meta import get_field_precision
from erpnext.accounts.doctype.budget.budget import validate_expense_against_budget
@ -75,8 +75,7 @@ def check_if_in_list(gle, gl_map):
and cstr(e.get('against_voucher'))==cstr(gle.get('against_voucher')) \
and cstr(e.get('against_voucher_type')) == cstr(gle.get('against_voucher_type')) \
and cstr(e.get('cost_center')) == cstr(gle.get('cost_center')) \
and cstr(e.get('project')) == cstr(gle.get('project')) \
and getdate(e.get('due_date')) == getdate(gle.get('due_date')):
and cstr(e.get('project')) == cstr(gle.get('project')):
return e
def save_entries(gl_map, adv_adj, update_outstanding, from_repost=False):

View File

@ -2,15 +2,15 @@
"align_labels_right": 0,
"creation": "2017-08-08 12:33:04.773099",
"custom_format": 1,
"disabled": 0,
"disabled": 1,
"doc_type": "Sales Invoice",
"docstatus": 0,
"doctype": "Print Format",
"font": "Default",
"html": "<style>\n\t.print-format table, .print-format tr, \n\t.print-format td, .print-format div, .print-format p {\n\t\tfont-family: Monospace;\n\t\tline-height: 200%;\n\t\tvertical-align: middle;\n\t}\n\t@media screen {\n\t\t.print-format {\n\t\t\twidth: 4in;\n\t\t\tpadding: 0.25in;\n\t\t\tmin-height: 8in;\n\t\t}\n\t}\n</style>\n\n<p class=\"text-center\">\n\t{{ doc.company }}<br>\n\t{% if doc.company_address_display %}\n\t\t{% set company_address = doc.company_address_display.replace(\"\\n\", \" \").replace(\"<br>\", \" \") %}\n\t\t{% if \"GSTIN\" not in company_address %}\n\t\t\t{{ company_address }}\n\t\t\t<b>{{ _(\"GSTIN\") }}:</b>{{ doc.company_gstin }}\n\t\t{% else %}\n\t\t\t{{ company_address.replace(\"GSTIN\", \"<br>GSTIN\") }}\n\t\t{% endif %}\n\t{% endif %}\n\t<br>\n\t<b>{{ doc.select_print_heading or _(\"Invoice\") }}</b><br>\n</p>\n<p>\n\t<b>{{ _(\"Receipt No\") }}:</b> {{ doc.name }}<br>\n\t<b>{{ _(\"Date\") }}:</b> {{ doc.get_formatted(\"posting_date\") }}<br>\n\t{% if doc.grand_total > 50000 %}\n\t\t{% set customer_address = doc.address_display.replace(\"\\n\", \" \").replace(\"<br>\", \" \") %}\n\t\t<b>{{ _(\"Customer\") }}:</b><br>\n\t\t{{ doc.customer_name }}<br>\n\t\t{{ customer_address }}\n\t{% endif %}\n</p>\n\n<hr>\n<table class=\"table table-condensed cart no-border\">\n\t<thead>\n\t\t<tr>\n\t\t\t<th width=\"40%\">{{ _(\"Item\") }}</b></th>\n\t\t\t<th width=\"30%\" class=\"text-right\">{{ _(\"Qty\") }}</th>\n\t\t\t<th width=\"30%\" class=\"text-right\">{{ _(\"Amount\") }}</th>\n\t\t</tr>\n\t</thead>\n\t<tbody>\n\t\t{%- for item in doc.items -%}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t{{ item.item_code }}\n\t\t\t\t{%- if item.item_name != item.item_code -%}\n\t\t\t\t\t<br>{{ item.item_name }}\n\t\t\t\t{%- endif -%}\n\t\t\t\t{%- if item.gst_hsn_code -%}\n\t\t\t\t\t<br><b>{{ _(\"HSN/SAC\") }}:</b> {{ item.gst_hsn_code }}\n\t\t\t\t{%- endif -%}\n\t\t\t\t{%- if item.serial_no -%}\n\t\t\t\t\t<br><b>{{ _(\"Serial No\") }}:</b> {{ item.serial_no }}\n\t\t\t\t{%- endif -%}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">{{ item.qty }}<br>@ {{ item.rate }}</td>\n\t\t\t<td class=\"text-right\">{{ item.get_formatted(\"amount\") }}</td>\n\t\t</tr>\n\t\t{%- endfor -%}\n\t</tbody>\n</table>\n<table class=\"table table-condensed no-border\">\n\t<tbody>\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ _(\"Net Total\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"net_total\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- for row in doc.taxes -%}\n\t\t{%- if not row.included_in_print_rate -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ row.description }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ row.get_formatted(\"tax_amount\", doc) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t\t{%- endfor -%}\n\t\t{%- if doc.discount_amount -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t{{ _(\"Discount\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"discount_amount\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ _(\"Grand Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"grand_total\") }}\n\t\t\t</td>\n\t\t</tr>\n\t</tbody>\n</table>\n<p><b>Tax Breakup:</b></p>\n<div style=\"font-size: 8px\">\n\t{{ doc.other_charges_calculation }}\n</div>\n<p>{{ doc.terms or \"\" }}</p>\n<p class=\"text-center\">{{ _(\"Thank you, please visit again.\") }}</p>",
"html": "<style>\n\t.print-format table, .print-format tr, \n\t.print-format td, .print-format div, .print-format p {\n\t\tfont-family: Monospace;\n\t\tline-height: 200%;\n\t\tvertical-align: middle;\n\t}\n\t@media screen {\n\t\t.print-format {\n\t\t\twidth: 4in;\n\t\t\tpadding: 0.25in;\n\t\t\tmin-height: 8in;\n\t\t}\n\t}\n</style>\n\n<p class=\"text-center\">\n\t{{ doc.company }}<br>\n\t{% if doc.company_address_display %}\n\t\t{% set company_address = doc.company_address_display.replace(\"\\n\", \" \").replace(\"<br>\", \" \") %}\n\t\t{% if \"GSTIN\" not in company_address %}\n\t\t\t{{ company_address }}\n\t\t\t<b>{{ _(\"GSTIN\") }}:</b>{{ doc.company_gstin }}\n\t\t{% else %}\n\t\t\t{{ company_address.replace(\"GSTIN\", \"<br>GSTIN\") }}\n\t\t{% endif %}\n\t{% endif %}\n\t<br>\n\t<b>{{ doc.select_print_heading or _(\"Invoice\") }}</b><br>\n</p>\n<p>\n\t<b>{{ _(\"Receipt No\") }}:</b> {{ doc.name }}<br>\n\t<b>{{ _(\"Date\") }}:</b> {{ doc.get_formatted(\"posting_date\") }}<br>\n\t{% if doc.grand_total > 50000 %}\n\t\t{% set customer_address = doc.address_display.replace(\"\\n\", \" \").replace(\"<br>\", \" \") %}\n\t\t<b>{{ _(\"Customer\") }}:</b><br>\n\t\t{{ doc.customer_name }}<br>\n\t\t{{ customer_address }}\n\t{% endif %}\n</p>\n\n<hr>\n<table class=\"table table-condensed cart no-border\">\n\t<thead>\n\t\t<tr>\n\t\t\t<th width=\"40%\">{{ _(\"Item\") }}</b></th>\n\t\t\t<th width=\"30%\" class=\"text-right\">{{ _(\"Qty\") }}</th>\n\t\t\t<th width=\"30%\" class=\"text-right\">{{ _(\"Amount\") }}</th>\n\t\t</tr>\n\t</thead>\n\t<tbody>\n\t\t{%- for item in doc.items -%}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t{{ item.item_code }}\n\t\t\t\t{%- if item.item_name != item.item_code -%}\n\t\t\t\t\t<br>{{ item.item_name }}\n\t\t\t\t{%- endif -%}\n\t\t\t\t{%- if item.gst_hsn_code -%}\n\t\t\t\t\t<br><b>{{ _(\"HSN/SAC\") }}:</b> {{ item.gst_hsn_code }}\n\t\t\t\t{%- endif -%}\n\t\t\t\t{%- if item.serial_no -%}\n\t\t\t\t\t<br><b>{{ _(\"Serial No\") }}:</b> {{ item.serial_no }}\n\t\t\t\t{%- endif -%}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">{{ item.qty }}<br>@ {{ item.rate }}</td>\n\t\t\t<td class=\"text-right\">{{ item.get_formatted(\"amount\") }}</td>\n\t\t</tr>\n\t\t{%- endfor -%}\n\t</tbody>\n</table>\n<table class=\"table table-condensed no-border\">\n\t<tbody>\n\t\t<tr>\n\t\t\t{% if doc.flags.show_inclusive_tax_in_print %}\n\t\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t\t{{ _(\"Total Excl. Tax\") }}\n\t\t\t\t</td>\n\t\t\t\t<td class=\"text-right\">\n\t\t\t\t\t{{ doc.get_formatted(\"net_total\", doc) }}\n\t\t\t\t</td>\n\t\t\t{% else %}\n\t\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t\t{{ _(\"Total\") }}\n\t\t\t\t</td>\n\t\t\t\t<td class=\"text-right\">\n\t\t\t\t\t{{ doc.get_formatted(\"total\", doc) }}\n\t\t\t\t</td>\n\t\t\t{% endif %}\n\t\t</tr>\n\t\t{%- for row in doc.taxes -%}\n\t\t {%- if not row.included_in_print_rate or doc.flags.show_inclusive_tax_in_print -%}\n\t\t\t<tr>\n\t\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t\t{{ row.description }}\n\t\t\t\t</td>\n\t\t\t\t<td class=\"text-right\">\n\t\t\t\t\t{{ row.get_formatted(\"tax_amount\", doc) }}\n\t\t\t\t</td>\n\t\t\t<tr>\n\t\t {%- endif -%}\n\t\t{%- endfor -%}\n\t\t{%- if doc.discount_amount -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t{{ _(\"Discount\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"discount_amount\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ _(\"Grand Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"grand_total\") }}\n\t\t\t</td>\n\t\t</tr>\n\t</tbody>\n</table>\n<p><b>Tax Breakup:</b></p>\n<div style=\"font-size: 8px\">\n\t{{ doc.other_charges_calculation }}\n</div>\n<p>{{ doc.terms or \"\" }}</p>\n<p class=\"text-center\">{{ _(\"Thank you, please visit again.\") }}</p>",
"idx": 0,
"line_breaks": 0,
"modified": "2017-09-14 15:54:19.467642",
"modified": "2018-01-05 17:25:59.181985",
"modified_by": "Administrator",
"module": "Accounts",
"name": "GST POS Invoice",

View File

@ -1,15 +1,21 @@
{
"align_labels_right": 0,
"creation": "2011-12-21 11:08:55",
"custom_format": 1,
"disabled": 0,
"doc_type": "Sales Invoice",
"docstatus": 0,
"doctype": "Print Format",
"html": "<style>\n\t.print-format table, .print-format tr, \n\t.print-format td, .print-format div, .print-format p {\n\t\tfont-family: Monospace;\n\t\tline-height: 200%;\n\t\tvertical-align: middle;\n\t}\n\t@media screen {\n\t\t.print-format {\n\t\t\twidth: 4in;\n\t\t\tpadding: 0.25in;\n\t\t\tmin-height: 8in;\n\t\t}\n\t}\n</style>\n\n<p class=\"text-center\">\n\t{{ doc.company }}<br>\n\t{{ doc.select_print_heading or _(\"Invoice\") }}<br>\n</p>\n<p>\n\t<b>{{ _(\"Receipt No\") }}:</b> {{ doc.name }}<br>\n\t<b>{{ _(\"Date\") }}:</b> {{ doc.get_formatted(\"posting_date\") }}<br>\n\t<b>{{ _(\"Customer\") }}:</b> {{ doc.customer_name }}\n</p>\n\n<hr>\n<table class=\"table table-condensed cart no-border\">\n\t<thead>\n\t\t<tr>\n\t\t\t<th width=\"50%\">{{ _(\"Item\") }}</b></th>\n\t\t\t<th width=\"25%\" class=\"text-right\">{{ _(\"Qty\") }}</th>\n\t\t\t<th width=\"25%\" class=\"text-right\">{{ _(\"Amount\") }}</th>\n\t\t</tr>\n\t</thead>\n\t<tbody>\n\t\t{%- for item in doc.items -%}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t{{ item.item_code }}\n\t\t\t\t{%- if item.item_name != item.item_code -%}\n\t\t\t\t\t<br>{{ item.item_name }}{%- endif -%}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">{{ item.qty }}<br>@ {{ item.get_formatted(\"rate\") }}</td>\n\t\t\t<td class=\"text-right\">{{ item.get_formatted(\"amount\") }}</td>\n\t\t</tr>\n\t\t{%- endfor -%}\n\t</tbody>\n</table>\n<table class=\"table table-condensed no-border\">\n\t<tbody>\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ _(\"Net Total\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"net_total\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- for row in doc.taxes -%}\n\t\t{%- if not row.included_in_print_rate -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ row.description }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ row.get_formatted(\"tax_amount\", doc) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t\t{%- endfor -%}\n\t\t{%- if doc.discount_amount -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t{{ _(\"Discount\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"discount_amount\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ _(\"Grand Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"grand_total\") }}\n\t\t\t</td>\n\t\t</tr>\n\t</tbody>\n</table>\n{% if doc.get(\"taxes\", filters={\"included_in_print_rate\": 1}) %}\n<hr>\n<p><b>Taxes Included:</b></p>\n<table class=\"table table-condensed no-border\">\n\t<tbody>\n\t\t{%- for row in doc.taxes -%}\n\t\t{%- if row.included_in_print_rate -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ row.description }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ row.get_formatted(\"tax_amount_after_discount_amount\", doc) }}\n\t\t\t</td>\n\t\t<tr>\n\t\t{%- endif -%}\n\t\t{%- endfor -%}\n\t</tbody>\n</table>\n{%- endif -%}\n<hr>\n<p>{{ doc.terms or \"\" }}</p>\n<p class=\"text-center\">{{ _(\"Thank you, please visit again.\") }}</p>",
"html": "<style>\n\t.print-format table, .print-format tr, \n\t.print-format td, .print-format div, .print-format p {\n\t\tfont-family: Monospace;\n\t\tline-height: 200%;\n\t\tvertical-align: middle;\n\t}\n\t@media screen {\n\t\t.print-format {\n\t\t\twidth: 4in;\n\t\t\tpadding: 0.25in;\n\t\t\tmin-height: 8in;\n\t\t}\n\t}\n</style>\n\n<p class=\"text-center\">\n\t{{ doc.company }}<br>\n\t{{ doc.select_print_heading or _(\"Invoice\") }}<br>\n</p>\n<p>\n\t<b>{{ _(\"Receipt No\") }}:</b> {{ doc.name }}<br>\n\t<b>{{ _(\"Date\") }}:</b> {{ doc.get_formatted(\"posting_date\") }}<br>\n\t<b>{{ _(\"Customer\") }}:</b> {{ doc.customer_name }}\n</p>\n\n<hr>\n<table class=\"table table-condensed cart no-border\">\n\t<thead>\n\t\t<tr>\n\t\t\t<th width=\"50%\">{{ _(\"Item\") }}</b></th>\n\t\t\t<th width=\"25%\" class=\"text-right\">{{ _(\"Qty\") }}</th>\n\t\t\t<th width=\"25%\" class=\"text-right\">{{ _(\"Amount\") }}</th>\n\t\t</tr>\n\t</thead>\n\t<tbody>\n\t\t{%- for item in doc.items -%}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t{{ item.item_code }}\n\t\t\t\t{%- if item.item_name != item.item_code -%}\n\t\t\t\t\t<br>{{ item.item_name }}{%- endif -%}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">{{ item.qty }}<br>@ {{ item.get_formatted(\"rate\") }}</td>\n\t\t\t<td class=\"text-right\">{{ item.get_formatted(\"amount\") }}</td>\n\t\t</tr>\n\t\t{%- endfor -%}\n\t</tbody>\n</table>\n<table class=\"table table-condensed no-border\">\n\t<tbody>\n\t\t<tr>\n\t\t\t{% if doc.flags.show_inclusive_tax_in_print %}\n\t\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t\t{{ _(\"Total Excl. Tax\") }}\n\t\t\t\t</td>\n\t\t\t\t<td class=\"text-right\">\n\t\t\t\t\t{{ doc.get_formatted(\"net_total\", doc) }}\n\t\t\t\t</td>\n\t\t\t{% else %}\n\t\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t\t{{ _(\"Total\") }}\n\t\t\t\t</td>\n\t\t\t\t<td class=\"text-right\">\n\t\t\t\t\t{{ doc.get_formatted(\"total\", doc) }}\n\t\t\t\t</td>\n\t\t\t{% endif %}\n\t\t</tr>\n\t\t{%- for row in doc.taxes -%}\n\t\t {%- if not row.included_in_print_rate or doc.flags.show_inclusive_tax_in_print -%}\n\t\t\t<tr>\n\t\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t\t{{ row.description }}\n\t\t\t\t</td>\n\t\t\t\t<td class=\"text-right\">\n\t\t\t\t\t{{ row.get_formatted(\"tax_amount\", doc) }}\n\t\t\t\t</td>\n\t\t\t<tr>\n\t\t {%- endif -%}\n\t\t{%- endfor -%}\n\n\t\t{%- if doc.discount_amount -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t{{ _(\"Discount\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"discount_amount\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ _(\"Grand Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"grand_total\") }}\n\t\t\t</td>\n\t\t</tr>\n\t</tbody>\n</table>\n<hr>\n<p>{{ doc.terms or \"\" }}</p>\n<p class=\"text-center\">{{ _(\"Thank you, please visit again.\") }}</p>",
"idx": 1,
"modified": "2015-04-21 05:06:29.380856",
"line_breaks": 0,
"modified": "2018-01-05 17:23:40.403289",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Invoice",
"owner": "Administrator",
"print_format_builder": 0,
"print_format_type": "Server",
"show_section_headings": 0,
"standard": "Yes"
}

View File

@ -113,7 +113,7 @@ class ReceivablePayableReport(object):
row += [self.get_party_name(gle.party_type, gle.party)]
# get due date
due_date = gle.due_date or voucher_details.get(gle.voucher_no, {}).get("due_date", "")
due_date = voucher_details.get(gle.voucher_no, {}).get("due_date", "")
row += [gle.voucher_type, gle.voucher_no, due_date]
@ -188,8 +188,7 @@ class ReceivablePayableReport(object):
reverse_dr_or_cr = "credit" if dr_or_cr=="debit" else "debit"
for e in self.get_gl_entries_for(gle.party, gle.party_type, gle.voucher_type, gle.voucher_no):
if getdate(e.posting_date) <= report_date and e.name!=gle.name \
and (not gle.due_date or getdate(e.due_date) == getdate(gle.due_date)):
if getdate(e.posting_date) <= report_date and e.name!=gle.name:
amount = flt(e.get(reverse_dr_or_cr)) - flt(e.get(dr_or_cr))
if e.voucher_no not in return_entries:
payment_amount += amount
@ -251,11 +250,11 @@ class ReceivablePayableReport(object):
select_fields = "sum(debit) as debit, sum(credit) as credit"
self.gl_entries = frappe.db.sql("""select name, posting_date, account, party_type, party,
voucher_type, voucher_no, against_voucher_type, against_voucher, due_date,
voucher_type, voucher_no, against_voucher_type, against_voucher,
account_currency, remarks, {0}
from `tabGL Entry`
where docstatus < 2 and party_type=%s and (party is not null and party != '') {1}
group by voucher_type, voucher_no, against_voucher_type, against_voucher, party, due_date
group by voucher_type, voucher_no, against_voucher_type, against_voucher, party
order by posting_date, party"""
.format(select_fields, conditions), values, as_dict=True)

View File

@ -193,6 +193,24 @@ def get_data_with_opening_closing(filters, account_details, gl_entries):
# closing
data.append(totals.closing)
#total closing
total_closing = totals.total_closing
total_debit = totals.closing.get('debit', 0)
total_credit = totals.closing.get('credit', 0)
debit_in_account_currency = totals.closing.get('debit_in_account_currency', 0)
credit_in_account_currency = totals.closing.get('credit_in_account_currency', 0)
total_amount = total_debit - total_credit
if total_amount > 0:
total_closing['debit'] = total_amount
total_closing['debit_in_account_currency'] = debit_in_account_currency - credit_in_account_currency
else:
total_closing['credit'] = abs(total_amount)
total_closing['credit_in_account_currency'] = abs(debit_in_account_currency - credit_in_account_currency)
data.append(totals.total_closing)
return data
def get_totals_dict():
@ -207,7 +225,8 @@ def get_totals_dict():
return _dict(
opening = _get_debit_credit_dict(_('Opening')),
total = _get_debit_credit_dict(_('Total')),
closing = _get_debit_credit_dict(_('Closing (Opening + Total)'))
closing = _get_debit_credit_dict(_('Closing (Opening + Total)')),
total_closing = _get_debit_credit_dict(_('Closing Balance (Dr - Cr)'))
)
def initialize_gle_map(gl_entries):
@ -234,6 +253,9 @@ def get_accountwise_gle(filters, gl_entries, gle_map):
update_value_in_dict(gle_map[gle.account].totals, 'opening', gle)
update_value_in_dict(totals, 'opening', gle)
update_value_in_dict(gle_map[gle.account].totals, 'closing', gle)
update_value_in_dict(totals, 'closing', gle)
elif gle.posting_date <= to_date:
update_value_in_dict(gle_map[gle.account].totals, 'total', gle)
update_value_in_dict(totals, 'total', gle)
@ -242,8 +264,8 @@ def get_accountwise_gle(filters, gl_entries, gle_map):
else:
entries.append(gle)
update_value_in_dict(gle_map[gle.account].totals, 'closing', gle)
update_value_in_dict(totals, 'closing', gle)
update_value_in_dict(gle_map[gle.account].totals, 'closing', gle)
update_value_in_dict(totals, 'closing', gle)
return totals, entries

View File

@ -1,7 +1,7 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
frappe.query_reports["Item-wise Sales Register"] = frappe.query_reports["Sales Register"] = {
frappe.query_reports["Item-wise Sales Register"] = {
"filters": [
{
"fieldname":"from_date",

View File

@ -6,6 +6,7 @@ import frappe, erpnext
from frappe import _
from frappe.utils import flt
from frappe.model.meta import get_field_precision
from frappe.utils.xlsxutils import handle_html
from erpnext.accounts.report.sales_register.sales_register import get_mode_of_payments
def execute(filters=None):
@ -188,10 +189,10 @@ def get_tax_accounts(item_list, columns, company_currency,
tuple([doctype] + invoice_item_row.keys()))
for parent, description, item_wise_tax_detail, charge_type, tax_amount in tax_details:
description = handle_html(description)
if description not in tax_columns and tax_amount:
# as description is text editor earlier and markup can break the column convention in reports
from frappe.utils.xlsxutils import handle_html
tax_columns.append(handle_html(description))
tax_columns.append(description)
if item_wise_tax_detail:
try:

View File

@ -15,7 +15,7 @@ def execute(filters=None):
def get_column():
return [
_("Purchase Receipt") + ":Link/Purchase Receipt:120", _("Date") + ":Date:100",
_("Suplier") + ":Link/Supplier:120", _("Suplier Name") + "::120",
_("Supplier") + ":Link/Supplier:120", _("Supplier Name") + "::120",
_("Project") + ":Link/Project:120", _("Item Code") + ":Link/Item:120",
_("Amount") + ":Currency:100", _("Billed Amount") + ":Currency:100", _("Amount to Bill") + ":Currency:100",
_("Item Name") + "::120", _("Description") + "::120", _("Company") + ":Link/Company:120",

View File

@ -12,7 +12,7 @@
"module": "Accounts",
"name": "Sales Partners Commission",
"owner": "Administrator",
"query": "SELECT\n sales_partner as \"Sales Partner:Link/Sales Partner:150\",\n\tsum(base_net_total) as \"Invoiced Amount (Exculsive Tax):Currency:210\",\n\tsum(total_commission) as \"Total Commission:Currency:150\",\n\tsum(total_commission)*100/sum(base_net_total) as \"Average Commission Rate:Currency:170\"\nFROM\n\t`tabSales Invoice`\nWHERE\n\tdocstatus = 1 and ifnull(base_net_total, 0) > 0 and ifnull(total_commission, 0) > 0\nGROUP BY\n\tsales_partner\nORDER BY\n\t\"Total Commission:Currency:120\"",
"query": "SELECT\n sales_partner as \"Sales Partner:Link/Sales Partner:150\",\n\tsum(base_net_total) as \"Invoiced Amount (Exclusive Tax):Currency:210\",\n\tsum(total_commission) as \"Total Commission:Currency:150\",\n\tsum(total_commission)*100/sum(base_net_total) as \"Average Commission Rate:Currency:170\"\nFROM\n\t`tabSales Invoice`\nWHERE\n\tdocstatus = 1 and ifnull(base_net_total, 0) > 0 and ifnull(total_commission, 0) > 0\nGROUP BY\n\tsales_partner\nORDER BY\n\t\"Total Commission:Currency:120\"",
"ref_doctype": "Sales Invoice",
"report_name": "Sales Partners Commission",
"report_type": "Query Report",

View File

@ -1,6 +1,5 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
frappe.query_reports["Sales Payment Summary"] = {
"filters": [
{
@ -8,12 +7,14 @@ frappe.query_reports["Sales Payment Summary"] = {
"label": __("From Date"),
"fieldtype": "Date",
"default": frappe.datetime.get_today(),
"reqd": 1,
"width": "80"
},
{
"fieldname":"to_date",
"label": __("To Date"),
"fieldtype": "Date",
"reqd": 1,
"default": frappe.datetime.get_today()
},
{
@ -23,12 +24,6 @@ frappe.query_reports["Sales Payment Summary"] = {
"options": "Company",
"default": frappe.defaults.get_user_default("Company")
},
{
"fieldname":"mode_of_payment",
"label": __("Mode of Payment"),
"fieldtype": "Link",
"options": "Mode of Payment"
},
{
"fieldname":"owner",
"label": __("Owner"),
@ -36,22 +31,15 @@ frappe.query_reports["Sales Payment Summary"] = {
"options": "User",
"defaults": user
},
{
"fieldname":"cost_center",
"label": __("Cost Center"),
"fieldtype": "Link",
"options": "Cost Center"
},
{
"fieldname":"warehouse",
"label": __("Warehouse"),
"fieldtype": "Link",
"options": "Warehouse"
},
{
"fieldname":"is_pos",
"label": __("POS?"),
"label": __("Show only POS"),
"fieldtype": "Check"
}
},
{
"fieldname":"payment_detail",
"label": __("Show Payment Details"),
"fieldtype": "Check"
},
]
};

View File

@ -1,9 +1,9 @@
# Copyright (c) 2013, 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.utils import cstr
def execute(filters=None):
columns, data = [], []
@ -14,53 +14,133 @@ def execute(filters=None):
def get_columns():
return [
_("Date") + ":Date:80",
_("Owner") + "::150",
_("Payment Mode") + "::120",
_("Warehouse") + ":Link/Cost Center:100",
_("Cost Center") + ":Link/Warehouse:100",
_("Owner") + ":Data:200",
_("Payment Mode") + ":Data:240",
_("Sales and Returns") + ":Currency/currency:120",
_("Taxes") + ":Currency/currency:120",
_("Payments") + ":Currency/currency:120",
_("Reconciliation") + ":Currency/currency:120"
_("Payments") + ":Currency/currency:120"
]
def get_sales_payment_data(filters, columns):
sales_invoice_data = get_sales_invoice_data(filters)
data = []
show_payment_detail = False
sales_invoice_data = get_sales_invoice_data(filters)
mode_of_payments = get_mode_of_payments(filters)
mode_of_payment_details = get_mode_of_payment_details(filters)
if filters.get("payment_detail"):
show_payment_detail = True
else:
show_payment_detail = False
for inv in sales_invoice_data:
row = [inv.posting_date, inv.owner, inv.mode_of_payment,inv.warehouse,
inv.cost_center,inv.net_total, inv.total_taxes, inv.paid_amount,
(inv.net_total + inv.total_taxes - inv.paid_amount)]
data.append(row)
owner_posting_date = inv["owner"]+cstr(inv["posting_date"])
if show_payment_detail:
row = [inv.posting_date, inv.owner," ",inv.net_total,inv.total_taxes, 0]
data.append(row)
for mop_detail in mode_of_payment_details.get(owner_posting_date,[]):
row = [inv.posting_date, inv.owner,mop_detail[0],0,0,mop_detail[1],0]
data.append(row)
else:
total_payment = 0
for mop_detail in mode_of_payment_details.get(owner_posting_date,[]):
total_payment = total_payment + mop_detail[1]
row = [inv.posting_date, inv.owner,", ".join(mode_of_payments.get(owner_posting_date, [])),
inv.net_total,inv.total_taxes,total_payment]
data.append(row)
return data
def get_conditions(filters):
conditions = ""
if filters.get("company"): conditions += " a.company=%(company)s"
if filters.get("from_date"): conditions += "a.posting_date >= %(from_date)s"
if filters.get("to_date"): conditions += " and a.posting_date <= %(to_date)s"
if filters.get("company"): conditions += " and a.company=%(company)s"
if filters.get("customer"): conditions += " and a.customer = %(customer)s"
if filters.get("owner"): conditions += " and a.owner = %(owner)s"
if filters.get("from_date"): conditions += " and a.posting_date >= %(from_date)s"
if filters.get("to_date"): conditions += " and a.posting_date <= %(to_date)s"
if filters.get("mode_of_payment"): conditions += " and c.mode_of_payment >= %(mode_of_payment)s"
if filters.get("warehouse"): conditions += " and b.warehouse <= %(warehouse)s"
if filters.get("cost_center"): conditions += " and b.cost_center <= %(cost_center)s"
if filters.get("is_pos"): conditions += " and a.is_pos = %(is_pos)s"
return conditions
def get_sales_invoice_data(filters):
conditions = get_conditions(filters)
return frappe.db.sql("""
select
a.owner, a.posting_date, c.mode_of_payment, b.warehouse, b.cost_center,
a.posting_date, a.owner,
sum(a.net_total) as "net_total",
sum(a.total_taxes_and_charges) as "total_taxes",
sum(a.base_paid_amount) as "paid_amount"
from `tabSales Invoice` a, `tabSales Invoice Item` b, `tabSales Invoice Payment` c
where
a.name = b.parent
and a.name = c.parent
sum(a.base_paid_amount) as "paid_amount",
sum(a.outstanding_amount) as "outstanding_amount"
from `tabSales Invoice` a
where a.docstatus = 1
and {conditions}
group by
a.owner, a.posting_date, c.mode_of_payment, b.warehouse, b.cost_center
a.owner, a.posting_date
""".format(conditions=conditions), filters, as_dict=1)
def get_mode_of_payments(filters):
mode_of_payments = {}
invoice_list = get_invoices(filters)
invoice_list_names = ",".join(['"' + invoice['name'] + '"' for invoice in invoice_list])
if invoice_list:
inv_mop = frappe.db.sql("""select a.owner,a.posting_date, ifnull(b.mode_of_payment, '') as mode_of_payment
from `tabSales Invoice` a, `tabSales Invoice Payment` b
where a.name = b.parent
and a.name in ({invoice_list_names})
union
select a.owner,a.posting_date, ifnull(b.mode_of_payment, '') as mode_of_payment
from `tabSales Invoice` a, `tabPayment Entry` b,`tabPayment Entry Reference` c
where a.name = c.reference_name
and b.name = c.parent
and a.name in ({invoice_list_names})
union
select a.owner, a.posting_date,
ifnull(a.voucher_type,'') as mode_of_payment
from `tabJournal Entry` a, `tabJournal Entry Account` b
where a.name = b.parent
and a.docstatus = 1
and b.reference_type = "Sales Invoice"
and b.reference_name in ({invoice_list_names})
""".format(invoice_list_names=invoice_list_names), as_dict=1)
for d in inv_mop:
mode_of_payments.setdefault(d["owner"]+cstr(d["posting_date"]), []).append(d.mode_of_payment)
return mode_of_payments
def get_invoices(filters):
conditions = get_conditions(filters)
return frappe.db.sql("""select a.name
from `tabSales Invoice` a
where a.docstatus = 1 and {conditions}""".format(conditions=conditions),
filters, as_dict=1)
def get_mode_of_payment_details(filters):
mode_of_payment_details = {}
invoice_list = get_invoices(filters)
invoice_list_names = ",".join(['"' + invoice['name'] + '"' for invoice in invoice_list])
if invoice_list:
inv_mop_detail = frappe.db.sql("""select a.owner, a.posting_date,
ifnull(b.mode_of_payment, '') as mode_of_payment, sum(b.base_amount) as paid_amount
from `tabSales Invoice` a, `tabSales Invoice Payment` b
where a.name = b.parent
and a.name in ({invoice_list_names})
group by a.owner, a.posting_date, mode_of_payment
union
select a.owner,a.posting_date,
ifnull(b.mode_of_payment, '') as mode_of_payment, sum(b.base_paid_amount) as paid_amount
from `tabSales Invoice` a, `tabPayment Entry` b,`tabPayment Entry Reference` c
where a.name = c.reference_name
and b.name = c.parent
and a.name in ({invoice_list_names})
group by a.owner, a.posting_date, mode_of_payment
union
select a.owner, a.posting_date,
ifnull(a.voucher_type,'') as mode_of_payment, sum(b.credit)
from `tabJournal Entry` a, `tabJournal Entry Account` b
where a.name = b.parent
and a.docstatus = 1
and b.reference_type = "Sales Invoice"
and b.reference_name in ({invoice_list_names})
group by a.owner, a.posting_date, mode_of_payment
""".format(invoice_list_names=invoice_list_names), as_dict=1)
for d in inv_mop_detail:
mode_of_payment_details.setdefault(d["owner"]+cstr(d["posting_date"]), []).append((d.mode_of_payment,d.paid_amount))
return mode_of_payment_details

View File

@ -252,6 +252,9 @@ def add_ac(args=None):
if not ac.parent_account:
ac.parent_account = args.get("parent")
if ac.is_root:
ac.parent_account=''
ac.old_parent = ""
ac.freeze_account = "No"
if cint(ac.get("is_root")):
@ -576,16 +579,17 @@ def get_outstanding_invoices(party_type, party, account, condition=None):
outstanding_invoices = []
precision = frappe.get_precision("Sales Invoice", "outstanding_amount")
if party_type == "Customer" or party_type == "Student":
if party_type in ("Customer", "Student"):
dr_or_cr = "debit_in_account_currency - credit_in_account_currency"
payment_dr_or_cr = "payment_gl_entry.credit_in_account_currency - payment_gl_entry.debit_in_account_currency"
else:
dr_or_cr = "credit_in_account_currency - debit_in_account_currency"
payment_dr_or_cr = "payment_gl_entry.debit_in_account_currency - payment_gl_entry.credit_in_account_currency"
invoice = 'Sales Invoice' if party_type == 'Customer' else 'Purchase Invoice'
invoice_list = frappe.db.sql("""
select
voucher_no, voucher_type, posting_date, ifnull(sum({dr_or_cr}), 0) as invoice_amount, due_date,
voucher_no, voucher_type, posting_date, ifnull(sum({dr_or_cr}), 0) as invoice_amount,
(
select ifnull(sum({payment_dr_or_cr}), 0)
from `tabGL Entry` payment_gl_entry
@ -596,7 +600,6 @@ def get_outstanding_invoices(party_type, party, account, condition=None):
and payment_gl_entry.party_type = invoice_gl_entry.party_type
and payment_gl_entry.party = invoice_gl_entry.party
and payment_gl_entry.account = invoice_gl_entry.account
and payment_gl_entry.due_date = invoice_gl_entry.due_date
and {payment_dr_or_cr} > 0
) as payment_amount
from
@ -608,10 +611,11 @@ def get_outstanding_invoices(party_type, party, account, condition=None):
and ((voucher_type = 'Journal Entry'
and (against_voucher = '' or against_voucher is null))
or (voucher_type not in ('Journal Entry', 'Payment Entry')))
group by voucher_type, voucher_no, due_date
group by voucher_type, voucher_no
having (invoice_amount - payment_amount) > 0.005
order by posting_date, name, due_date""".format(
order by posting_date, name""".format(
dr_or_cr=dr_or_cr,
invoice = invoice,
payment_dr_or_cr=payment_dr_or_cr,
condition=condition or ""
), {
@ -621,12 +625,8 @@ def get_outstanding_invoices(party_type, party, account, condition=None):
}, as_dict=True)
for d in invoice_list:
due_date = d.due_date or (
frappe.db.get_value(
d.voucher_type, d.voucher_no,
"posting_date" if party_type == "Employee" else "due_date"
)
)
due_date = frappe.db.get_value(d.voucher_type, d.voucher_no,
"posting_date" if party_type == "Employee" else "due_date")
outstanding_invoices.append(
frappe._dict({
@ -704,7 +704,7 @@ def get_children(doctype, parent, company, is_root=False):
return acc
def create_payment_gateway_account(gateway):
from erpnext.setup.setup_wizard.setup_wizard import create_bank_account
from erpnext.setup.setup_wizard.operations.company_setup import create_bank_account
company = frappe.db.get_value("Global Defaults", None, "default_company")
if not company:

View File

@ -1,7 +1,55 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.provide("erpnext.crop");
frappe.ui.form.on('Crop', {
validate: (frm) => {
refresh: (frm) => {
frm.fields_dict.materials_required.grid.set_column_disp('bom_no', false);
}
});
frappe.ui.form.on("BOM Item", {
item_code: (frm, cdt, cdn) => {
erpnext.crop.update_item_rate_uom(frm, cdt, cdn);
},
qty: (frm, cdt, cdn) => {
erpnext.crop.update_item_qty_amount(frm, cdt, cdn);
},
rate: (frm, cdt, cdn) => {
erpnext.crop.update_item_qty_amount(frm, cdt, cdn);
}
});
erpnext.crop.update_item_rate_uom = function(frm, cdt, cdn) {
let material_list = ['materials_required', 'produce', 'byproducts'];
material_list.forEach((material) => {
frm.doc[material].forEach((item, index) => {
if (item.name == cdn && item.item_code){
frappe.call({
method:'erpnext.agriculture.doctype.crop.crop.get_item_details',
args: {
item_code: item.item_code
},
callback: (r) => {
frappe.model.set_value('BOM Item', item.name, 'uom', r.message.uom);
frappe.model.set_value('BOM Item', item.name, 'rate', r.message.rate);
}
});
}
});
});
};
erpnext.crop.update_item_qty_amount = function(frm, cdt, cdn) {
let material_list = ['materials_required', 'produce', 'byproducts'];
material_list.forEach((material) => {
frm.doc[material].forEach((item, index) => {
if (item.name == cdn){
if (!frappe.model.get_value('BOM Item', item.name, 'qty'))
frappe.model.set_value('BOM Item', item.name, 'qty', 1);
frappe.model.set_value('BOM Item', item.name, 'amount', item.qty * item.rate);
}
});
});
};

View File

@ -16,3 +16,8 @@ class Crop(Document):
# to calculate the period of the Crop Cycle
if task.end_day > max_period: max_period = task.end_day
if max_period > self.period: self.period = max_period
@frappe.whitelist()
def get_item_details(item_code):
item = frappe.get_doc('Item', item_code)
return { "uom": item.stock_uom, "rate": item.valuation_rate }

View File

@ -15,7 +15,7 @@ frappe.ui.form.on('Crop Cycle', {
output[doctype].forEach( (analysis_doc) => {
let point_to_be_tested = JSON.parse(analysis_doc.location).features[0].geometry.coordinates;
let poly_of_land = JSON.parse(land_doc.location).features[0].geometry.coordinates[0];
if (test_analysis_position(point_to_be_tested, poly_of_land)){
if (is_in_land_unit(point_to_be_tested, poly_of_land)){
obj_to_append[analysis_doctypes_docs[analysis_doctypes.indexOf(doctype)]].push(analysis_doc.name);
}
});
@ -28,7 +28,7 @@ frappe.ui.form.on('Crop Cycle', {
}
});
function test_analysis_position(point, vs) {
function is_in_land_unit(point, vs) {
// ray-casting algorithm based on
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html

View File

@ -599,6 +599,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:!doc.__islocal",
"description": "List of diseases detected on the field. When selected it'll automatically add a list of tasks to deal with the disease ",
"fieldname": "section_break_14",
"fieldtype": "Section Break",
@ -790,7 +791,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-12-06 01:47:26.656870",
"modified": "2017-12-18 12:54:29.071743",
"modified_by": "Administrator",
"module": "Agriculture",
"name": "Crop Cycle",

View File

@ -12,11 +12,37 @@ class CropCycle(Document):
if self.is_new():
crop = frappe.get_doc('Crop', self.crop)
self.create_project(crop.period, crop.agriculture_task)
if not self.project:
self.project = self.name
for detected_disease in self.detected_disease:
disease = frappe.get_doc('Disease', detected_disease.disease)
self.create_task(disease.treatment_task, self.name, detected_disease.start_date)
if not self.crop_spacing_uom:
self.crop_spacing_uom = crop.crop_spacing_uom
if not self.row_spacing_uom:
self.row_spacing_uom = crop.row_spacing_uom
if not self.project:
self.project = self.name
disease = []
for detected_disease in self.detected_disease:
disease.append(detected_disease.name)
if disease != []:
self.update_disease(disease)
else:
old_disease, new_disease = [], []
for detected_disease in self.detected_disease:
new_disease.append(detected_disease.name)
for detected_disease in self.get_doc_before_save().get('detected_disease'):
old_disease.append(detected_disease.name)
if list(set(new_disease)-set(old_disease)) != []:
self.update_disease(list(set(new_disease)-set(old_disease)))
frappe.msgprint("All tasks for the detected diseases were imported")
def update_disease(self, disease_hashes):
new_disease = []
for disease in self.detected_disease:
for disease_hash in disease_hashes:
if disease.name == disease_hash:
self.import_disease_tasks(disease.disease, disease.start_date)
def import_disease_tasks(self, disease, start_date):
disease_doc = frappe.get_doc('Disease', disease)
self.create_task(disease_doc.treatment_task, self.name, start_date)
def create_project(self, period, crop_tasks):
project = frappe.new_doc("Project")
@ -60,3 +86,18 @@ class CropCycle(Document):
def get_geometry_type(self, doc):
return ast.literal_eval(doc.location).get('features')[0].get('geometry').get('type')
def is_in_land_unit(self, point, vs):
x, y = point
inside = False
j = len(vs)-1
i = 0
while i < len(vs):
xi, yi = vs[i]
xj, yj = vs[j]
intersect = ((yi > y) != (yj > y)) and (x < (xj - xi) * (y - yi) / (yj - yi) + xi)
if intersect:
inside = not inside
i = j
j += 1
return inside

View File

@ -102,66 +102,6 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "description",
"fieldtype": "Long Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Description",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_2",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Treatment Task",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@ -222,6 +162,66 @@
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_2",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Treatment Task",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "description",
"fieldtype": "Long Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Description",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"has_web_view": 0,
@ -234,7 +234,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-12-04 19:20:19.352479",
"modified": "2017-12-07 16:24:22.923154",
"modified_by": "Administrator",
"module": "Agriculture",
"name": "Disease",

View File

@ -9,6 +9,13 @@ frappe.ui.form.on('Land Unit', {
setup: function(frm) {
frm.add_fetch("parent_land_unit", "latitude", "latitude");
frm.add_fetch("parent_land_unit", "longitude", "longitude");
frm.set_query("parent_land_unit", function() {
return {
"filters": {
"is_group": 1
}
};
});
},
onload_post_render(frm){
@ -20,12 +27,4 @@ frappe.ui.form.on('Land Unit', {
frm.doc.longitude = frm.fields_dict.location.map.getCenter()['lng'];
}
},
refresh: function(frm) {
if(!frm.doc.parent_land_unit) {
frm.set_read_only();
frm.set_intro(__("This is a root land unit and cannot be edited."));
} else {
frm.set_intro(null);
}
},
});

View File

@ -431,7 +431,7 @@
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
@ -502,7 +502,7 @@
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"collapsible": 1,
"columns": 0,
"fieldname": "section_break_17",
"fieldtype": "Section Break",
@ -513,6 +513,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Linked Analysis",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@ -631,7 +632,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-12-05 10:57:33.108504",
"modified": "2017-12-14 18:16:15.124188",
"modified_by": "Administrator",
"module": "Agriculture",
"name": "Land Unit",
@ -679,7 +680,7 @@
"write": 1
}
],
"quick_entry": 0,
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 1,

View File

@ -10,6 +10,7 @@ import math
from frappe import _
from frappe.utils.nestedset import NestedSet
from frappe.utils import flt
# from frappe.model.document import Document
RADIUS = 6378137
@ -31,6 +32,7 @@ class LandUnit(NestedSet):
ancestor_features[index] = json.loads(feature)
ancestor_doc.set_location_value(features = ancestor_features)
ancestor_doc.db_set(fieldname='area', value=ancestor_doc.get('area')-self.get('area'),commit=True)
super(LandUnit, self).on_update()
def validate(self):
if not self.is_new():
@ -39,10 +41,10 @@ class LandUnit(NestedSet):
else:
features = json.loads(self.get('location')).get('features')
new_area = compute_area(features)
self.area_difference = new_area - self.area
self.area_difference = new_area - flt(self.area)
self.area = new_area
if self.get('parent'):
if self.get('parent_land_unit'):
ancestors = self.get_ancestors()
self_features = self.add_child_property()
self_features = set(self_features)
@ -78,7 +80,6 @@ class LandUnit(NestedSet):
def on_update(self):
super(LandUnit, self).on_update()
self.validate_one_root()
def add_child_property(self):
location = self.get('location')
@ -118,7 +119,7 @@ def compute_area(features):
layer_area += polygon_area(coords = feature.get('geometry').get('coordinates'))
elif feature.get('geometry').get('type') == 'Point' and feature.get('properties').get('point_type') == 'circle':
layer_area += math.pi * math.pow(feature.get('properties').get('radius'), 2)
return layer_area
return flt(layer_area)
def rad(angle_in_degrees):
return angle_in_degrees*math.pi/180
@ -163,3 +164,17 @@ def ring_area(coords):
area = area * RADIUS * RADIUS / 2
return area
@frappe.whitelist()
def get_children(doctype, parent, is_root=False):
if is_root:
parent = ''
land_units = frappe.db.sql("""select name as value,
is_group as expandable
from `tabLand Unit`
where ifnull(`parent_land_unit`,'') = %s
order by name""", (parent), as_dict=1)
# return nodes
return land_units

View File

@ -1,15 +1,30 @@
frappe.treeview_settings["Land Unit"] = {
get_tree_nodes: "erpnext.agriculture.doctype.land_unit.land_unit.get_children",
ignore_fields:["parent_land_unit"],
get_tree_root: false,
disable_add_node: true,
root_label: "All Land Units",
onload: function(me) {
me.make_tree();
},
toolbar: [
{ toggle_btn: true },
{
label:__("Add Child"),
label:__("Edit"),
condition: function(node) { return (node.label!='All Land Units'); },
click: function(node) {
frappe.set_route('Form', 'Land Unit', node.data.value);
}
},
{
label:__("Add Child"),
condition: function(node) { return node.expandable; },
click: function(node) {
if(node.label=='All Land Units') node.label='';
var lu = frappe.new_doc("Land Unit", {
"parent_land_unit": node.label
})
});
}
}
],
}
};

View File

@ -12,7 +12,6 @@ QUnit.test("test: Land Unit", function (assert) {
// insert a new Land Unit
() => frappe.tests.make('Land Unit', [
// values to be set
{parent_land_unit: 'All Land Units'},
{land_unit_name: 'Basil Farm'}
]),
() => {

View File

@ -21,6 +21,6 @@ class TestLandUnit(unittest.TestCase):
temp['features'][0]['properties']['feature_of'] = land_unit
formatted_land_units.extend(temp['features'])
formatted_land_unit_string = str(formatted_land_units)
all_land_units = frappe.get_doc('Land Unit', 'All Land Units')
self.assertEquals(formatted_land_unit_string, str(json.loads(all_land_units.get('location'))['features']))
self.assertEquals(area, all_land_units.get('area'))
test_land = frappe.get_doc('Land Unit', 'Test Land')
self.assertEquals(formatted_land_unit_string, str(json.loads(test_land.get('location'))['features']))
self.assertEquals(area, test_land.get('area'))

View File

@ -1,10 +1,16 @@
[
{
"doctype": "Land Unit",
"land_unit_name": "Test Land",
"is_group": 1,
"is_container": 1
},
{
"doctype": "Land Unit",
"land_unit_name": "Basil Farm",
"location": "{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"properties\":{\"point_type\":\"circle\",\"radius\":884.5625420736483},\"geometry\":{\"type\":\"Point\",\"coordinates\":[72.875834,19.100566]}}]}",
"parent_land_unit": "All Land Units",
"parent": "All Land Units",
"parent_land_unit": "Test Land",
"parent": "Test Land",
"is_group": 1,
"is_container": 1
},

View File

@ -4,12 +4,13 @@ from frappe import _
from erpnext.setup.utils import insert_record
def setup_agriculture():
if frappe.get_all('Agriculture Analysis Criteria'):
# already setup
return
create_agriculture_data()
def create_agriculture_data():
records = [
dict(
doctype="Land Unit",
land_unit_name="All Land Units",
is_group=1,
is_container=1),
dict(
doctype='Item Group',
item_group_name='Fertilizer',
@ -182,7 +183,7 @@ def setup_agriculture():
linked_doctype='Soil Analysis'),
dict(
doctype='Agriculture Analysis Criteria',
title='pH',
title='Soil pH',
standard=1,
linked_doctype='Soil Analysis'),
dict(
@ -272,7 +273,7 @@ def setup_agriculture():
linked_doctype='Soil Analysis'),
dict(
doctype='Agriculture Analysis Criteria',
title='pH',
title='Water pH',
standard=1,
linked_doctype='Water Analysis'),
dict(
@ -424,11 +425,6 @@ def setup_agriculture():
doctype='Agriculture Analysis Criteria',
title='Degree Days',
standard=1,
linked_doctype='Weather'),
dict(
doctype='Agriculture Analysis Criteria',
title='Degree Days',
standard=1,
linked_doctype='Water Analysis')
linked_doctype='Weather')
]
insert_record(records)

View File

@ -175,7 +175,7 @@ frappe.ui.form.on('Asset', {
"item_code": frm.doc.item_code,
"company": frm.doc.company
},
method: "erpnext.accounts.doctype.asset.asset.make_sales_invoice",
method: "erpnext.assets.doctype.asset.asset.make_sales_invoice",
callback: function(r) {
var doclist = frappe.model.sync(r.message);
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);

View File

@ -154,7 +154,7 @@
"label": "Status",
"length": 0,
"no_copy": 1,
"options": "Draft\nSubmitted\nPartially Depreciated\nFully Depreciated\nSold\nScrapped\nIn Repair\nOut of Order",
"options": "Draft\nSubmitted\nPartially Depreciated\nFully Depreciated\nSold\nScrapped\nIn Maintenance\nOut of Order",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@ -193,7 +193,7 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
@ -1221,7 +1221,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-12-01 15:11:47.466859",
"modified": "2017-12-19 12:58:44.137460",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset",

View File

@ -5,7 +5,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import flt, add_months, cint, nowdate, getdate
from frappe.utils import flt, add_months, cint, nowdate, getdate, today
from frappe.model.document import Document
from erpnext.accounts.doctype.purchase_invoice.purchase_invoice import get_fixed_asset_account
from erpnext.assets.doctype.asset.depreciation \
@ -193,6 +193,16 @@ class Asset(Document):
status = "Cancelled"
return status
def update_maintenance_status():
assets = frappe.get_all('Asset', filters = {'docstatus': 1, 'maintenance_required': 1})
for asset in assets:
asset = frappe.get_doc("Asset", asset.name)
if frappe.db.exists('Asset Maintenance Task', {'parent': asset.name, 'next_due_date': today()}):
asset.set_status('In Maintenance')
if frappe.db.exists('Asset Repair', {'asset_name': asset.name, 'repair_status': 'Pending'}):
asset.set_status('Out of Order')
@frappe.whitelist()
def make_purchase_invoice(asset, item_code, gross_purchase_amount, company, posting_date):
pi = frappe.new_doc("Purchase Invoice")

View File

@ -225,7 +225,7 @@
"is_submittable": 0,
"issingle": 1,
"istable": 0,
"modified": "2015-08-25 04:55:06.052342",
"modified": "2017-12-27 15:20:06.052342",
"modified_by": "Administrator",
"module": "Buying",
"name": "Buying Settings",

View File

@ -12,6 +12,15 @@ frappe.ui.form.on("Purchase Order", {
'Purchase Invoice': 'Invoice',
'Stock Entry': 'Material to Supplier'
}
frm.set_query("reserve_warehouse", "supplied_items", function() {
return {
filters: {
"company": frm.doc.company,
"is_group": 0
}
}
});
},
onload: function(frm) {
@ -21,22 +30,17 @@ frappe.ui.form.on("Purchase Order", {
return erpnext.queries.warehouse(frm.doc);
});
frappe.db.get_value('Buying Settings', {name: 'Buying Settings'}, 'disable_fetch_last_purchase_rate', (r) => {
value = r && cint(r.disable_fetch_last_purchase_rate);
frm.toggle_display('get_last_purchase_rate', !value);
});
frm.set_indicator_formatter('item_code',
function(doc) { return (doc.qty<=doc.received_qty) ? "green" : "orange" })
},
});
frappe.ui.form.on("Purchase Order Item", {
item_code: function(frm) {
frappe.call({
method: "get_last_purchase_rate",
doc: frm.doc,
callback: function(r, rt) {
frm.trigger('calculate_taxes_and_totals');
}
})
},
schedule_date: function(frm, cdt, cdn) {
var row = locals[cdt][cdn];
if (row.schedule_date) {
@ -289,7 +293,8 @@ cur_frm.fields_dict['items'].grid.get_field('bom').get_query = function(doc, cdt
filters: [
['BOM', 'item', '=', d.item_code],
['BOM', 'is_active', '=', '1'],
['BOM', 'docstatus', '=', '1']
['BOM', 'docstatus', '=', '1'],
['BOM', 'company', '=', doc.company]
]
}
}

View File

@ -1238,6 +1238,37 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 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,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 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,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@ -2552,7 +2583,7 @@
"options": "Payment Schedule",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@ -3071,6 +3102,38 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_subcontracted",
"fieldname": "supplied_items_section",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Supplied Items",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fieldname": "supplied_items",
"fieldtype": "Table",
"hidden": 0,
@ -3261,7 +3324,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-11-29 14:06:33.636401",
"modified": "2018-01-05 14:44:56.132189",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order",

View File

@ -11,9 +11,8 @@ from erpnext.controllers.buying_controller import BuyingController
from erpnext.stock.doctype.item.item import get_last_purchase_details
from erpnext.stock.stock_balance import update_bin_qty, get_ordered_qty
from frappe.desk.notifications import clear_doctype_notifications
from erpnext.buying.utils import (validate_for_items, check_for_closed_status,
update_last_purchase_rate)
from erpnext.buying.utils import validate_for_items, check_for_closed_status
from erpnext.stock.utils import get_bin
form_grid_templates = {
"items": "templates/form_grid/item_grid.html"
@ -72,8 +71,10 @@ class PurchaseOrder(BuyingController):
def validate_supplier(self):
prevent_po = frappe.db.get_value("Supplier", self.supplier, 'prevent_pos')
if prevent_po:
standing = frappe.db.get_value("Supplier Scorecard",self.supplier, 'status')
frappe.throw(_("Purchase Orders are not allowed for {0} due to a scorecard standing of {1}.").format(self.supplier, standing))
standing = frappe.db.get_value("Supplier Scorecard", self.supplier, 'status')
if standing:
frappe.throw(_("Purchase Orders are not allowed for {0} due to a scorecard standing of {1}.")
.format(self.supplier, standing))
warn_po = frappe.db.get_value("Supplier", self.supplier, 'warn_pos')
if warn_po:
@ -112,27 +113,26 @@ class PurchaseOrder(BuyingController):
def get_last_purchase_rate(self):
"""get last purchase rates for all items"""
if cint(frappe.db.get_single_value("Buying Settings", "disable_fetch_last_purchase_rate")): return
if not cint(frappe.db.get_single_value("Buying Settings", "disable_fetch_last_purchase_rate")):
conversion_rate = flt(self.get('conversion_rate')) or 1.0
conversion_rate = flt(self.get('conversion_rate')) or 1.0
for d in self.get("items"):
if d.item_code:
last_purchase_details = get_last_purchase_details(d.item_code, self.name)
if last_purchase_details:
d.base_price_list_rate = (last_purchase_details['base_price_list_rate'] *
(flt(d.conversion_factor) or 1.0))
d.discount_percentage = last_purchase_details['discount_percentage']
d.base_rate = last_purchase_details['base_rate'] * (flt(d.conversion_factor) or 1.0)
d.price_list_rate = d.base_price_list_rate / conversion_rate
d.rate = d.base_rate / conversion_rate
d.last_purchase_rate = d.rate
else:
for d in self.get("items"):
if d.item_code:
last_purchase_details = get_last_purchase_details(d.item_code, self.name)
if last_purchase_details:
d.base_price_list_rate = (last_purchase_details['base_price_list_rate'] *
(flt(d.conversion_factor) or 1.0))
d.discount_percentage = last_purchase_details['discount_percentage']
d.base_rate = last_purchase_details['base_rate'] * (flt(d.conversion_factor) or 1.0)
d.price_list_rate = d.base_price_list_rate / conversion_rate
d.last_purchase_rate = d.base_rate / conversion_rate
else:
item_last_purchase_rate = frappe.db.get_value("Item", d.item_code, "last_purchase_rate")
if item_last_purchase_rate:
d.base_price_list_rate = d.base_rate = d.price_list_rate \
= d.last_purchase_rate = item_last_purchase_rate
item_last_purchase_rate = frappe.db.get_value("Item", d.item_code, "last_purchase_rate")
if item_last_purchase_rate:
d.base_price_list_rate = d.base_rate = d.price_list_rate \
= d.rate = d.last_purchase_rate = item_last_purchase_rate
# Check for Closed status
def check_for_closed_status(self):
@ -185,29 +185,39 @@ class PurchaseOrder(BuyingController):
self.set_status(update=True, status=status)
self.update_requested_qty()
self.update_ordered_qty()
if self.is_subcontracted == "Yes":
self.update_reserved_qty_for_subcontract()
self.notify_update()
clear_doctype_notifications(self)
def on_submit(self):
super(PurchaseOrder, self).on_submit()
if self.is_against_so():
self.update_status_updater()
self.update_prevdoc_status()
self.update_requested_qty()
self.update_ordered_qty()
if self.is_subcontracted == "Yes":
self.update_reserved_qty_for_subcontract()
frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype,
self.company, self.base_grand_total)
update_last_purchase_rate(self, is_submit = 1)
def on_cancel(self):
super(PurchaseOrder, self).on_cancel()
if self.is_against_so():
self.update_status_updater()
if self.has_drop_ship_item():
self.update_delivered_qty_in_sales_order()
if self.is_subcontracted == "Yes":
self.update_reserved_qty_for_subcontract()
self.check_for_closed_status()
frappe.db.set(self,'status','Cancelled')
@ -218,8 +228,6 @@ class PurchaseOrder(BuyingController):
self.update_requested_qty()
self.update_ordered_qty()
update_last_purchase_rate(self, is_submit = 0)
def on_update(self):
pass
@ -257,6 +265,27 @@ class PurchaseOrder(BuyingController):
if item.delivered_by_supplier == 1:
item.received_qty = item.qty
def update_reserved_qty_for_subcontract(self):
for d in self.supplied_items:
if d.rm_item_code:
stock_bin = get_bin(d.rm_item_code, d.reserve_warehouse)
stock_bin.update_reserved_qty_for_sub_contracting()
def item_last_purchase_rate(name, conversion_rate, item_code, conversion_factor= 1.0):
"""get last purchase rate for an item"""
if cint(frappe.db.get_single_value("Buying Settings", "disable_fetch_last_purchase_rate")): return
conversion_rate = flt(conversion_rate) or 1.0
last_purchase_details = get_last_purchase_details(item_code, name)
if last_purchase_details:
last_purchase_rate = (last_purchase_details['base_rate'] * (flt(conversion_factor) or 1.0)) / conversion_rate
return last_purchase_rate
else:
item_last_purchase_rate = frappe.db.get_value("Item", item_code, "last_purchase_rate")
if item_last_purchase_rate:
return item_last_purchase_rate
@frappe.whitelist()
def close_or_unclose_purchase_orders(names, status):
if not frappe.has_permission("Purchase Order", "write"):

View File

@ -6,8 +6,8 @@ import unittest
import frappe
import frappe.defaults
from frappe.utils import flt, add_days, nowdate
from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_receipt, make_purchase_invoice
from erpnext.buying.doctype.purchase_order.purchase_order import (make_purchase_receipt, make_purchase_invoice, make_stock_entry as make_subcontract_transfer_entry)
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
class TestPurchaseOrder(unittest.TestCase):
def test_make_purchase_receipt(self):
@ -182,24 +182,129 @@ class TestPurchaseOrder(unittest.TestCase):
pi.insert()
self.assertTrue(pi.get('payment_schedule'))
def test_reserved_qty_subcontract_po(self):
# Make stock available for raw materials
make_stock_entry(target="_Test Warehouse - _TC", qty=10, basic_rate=100)
make_stock_entry(target="_Test Warehouse - _TC", item_code="_Test Item Home Desktop 100",
qty=20, basic_rate=100)
bin1 = frappe.db.get_value("Bin",
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname=["reserved_qty_for_sub_contract", "projected_qty"], as_dict=1)
# Submit PO
po = create_purchase_order(item_code="_Test FG Item", is_subcontracted="Yes")
bin2 = frappe.db.get_value("Bin",
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname=["reserved_qty_for_sub_contract", "projected_qty"], as_dict=1)
self.assertEquals(bin2.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract + 10)
self.assertEquals(bin2.projected_qty, bin1.projected_qty - 10)
# Create stock transfer
se = frappe.get_doc(make_subcontract_transfer_entry(po.name, "_Test FG Item"))
se.to_warehouse = "_Test Warehouse 1 - _TC"
for d in se.get("items"):
if d.item_code == "_Test Item":
d.qty = 6
se.save()
se.submit()
bin3 = frappe.db.get_value("Bin",
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname="reserved_qty_for_sub_contract", as_dict=1)
self.assertEquals(bin3.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
# close PO
po.update_status("Closed")
bin4 = frappe.db.get_value("Bin",
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname="reserved_qty_for_sub_contract", as_dict=1)
self.assertEquals(bin4.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
# Re-open PO
po.update_status("Submitted")
bin5 = frappe.db.get_value("Bin",
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname="reserved_qty_for_sub_contract", as_dict=1)
self.assertEquals(bin5.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
# make Purchase Receipt against PO
pr = make_purchase_receipt(po.name)
pr.supplier_warehouse = "_Test Warehouse 1 - _TC"
pr.save()
pr.submit()
bin6 = frappe.db.get_value("Bin",
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname="reserved_qty_for_sub_contract", as_dict=1)
self.assertEquals(bin6.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
# Cancel PR
pr.cancel()
bin7 = frappe.db.get_value("Bin",
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname="reserved_qty_for_sub_contract", as_dict=1)
self.assertEquals(bin7.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
# Make Purchase Invoice
pi = make_purchase_invoice(po.name)
pi.update_stock = 1
pi.supplier_warehouse = "_Test Warehouse 1 - _TC"
pi.insert()
pi.submit()
bin8 = frappe.db.get_value("Bin",
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname="reserved_qty_for_sub_contract", as_dict=1)
self.assertEquals(bin8.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
# Cancel PR
pi.cancel()
bin9 = frappe.db.get_value("Bin",
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname="reserved_qty_for_sub_contract", as_dict=1)
self.assertEquals(bin9.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
# Cancel Stock Entry
se.cancel()
bin10 = frappe.db.get_value("Bin",
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname="reserved_qty_for_sub_contract", as_dict=1)
self.assertEquals(bin10.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract + 10)
# Cancel PO
po.reload()
po.cancel()
bin11 = frappe.db.get_value("Bin",
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
fieldname="reserved_qty_for_sub_contract", as_dict=1)
self.assertEquals(bin11.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
def get_same_items():
return [
{
"item_code": "_Test FG Item",
"warehouse": "_Test Warehouse - _TC",
"qty": 1,
"rate": 500,
"schedule_date": add_days(nowdate(), 1)
},
{
"item_code": "_Test FG Item",
"warehouse": "_Test Warehouse - _TC",
"qty": 4,
"rate": 500,
"schedule_date": add_days(nowdate(), 1)
}
]
{
"item_code": "_Test FG Item",
"warehouse": "_Test Warehouse - _TC",
"qty": 1,
"rate": 500,
"schedule_date": add_days(nowdate(), 1)
},
{
"item_code": "_Test FG Item",
"warehouse": "_Test Warehouse - _TC",
"qty": 4,
"rate": 500,
"schedule_date": add_days(nowdate(), 1)
}
]
def create_purchase_order(**args):
po = frappe.new_doc("Purchase Order")
@ -224,6 +329,10 @@ def create_purchase_order(**args):
if not args.do_not_save:
po.insert()
if not args.do_not_submit:
if po.is_subcontracted == "Yes":
supp_items = po.get("supplied_items")
for d in supp_items:
d.reserve_warehouse = args.warehouse or "_Test Warehouse - _TC"
po.submit()
return po

View File

@ -24,7 +24,7 @@ QUnit.test("test: purchase order with taxes and charges", function(assert) {
]
]},
{taxes_and_charges: 'TEST In State GST'}
{taxes_and_charges: 'TEST In State GST - FT'}
]);
},

View File

@ -1169,7 +1169,7 @@
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
@ -1259,7 +1259,7 @@
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
@ -1897,7 +1897,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-11-30 14:17:15.817754",
"modified": "2017-12-14 09:36:40.837027",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order Item",

View File

@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
@ -10,16 +11,20 @@
"editable_grid": 1,
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 2,
"fieldname": "main_item_code",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Item Code",
"length": 0,
"no_copy": 0,
@ -29,6 +34,7 @@
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@ -36,16 +42,20 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 2,
"fieldname": "rm_item_code",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Raw Material Item Code",
"length": 0,
"no_copy": 0,
@ -55,6 +65,7 @@
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@ -62,16 +73,20 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 2,
"fieldname": "required_qty",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Supplied Qty",
"length": 0,
"no_copy": 0,
@ -81,6 +96,7 @@
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@ -88,16 +104,20 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 2,
"fieldname": "rate",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Rate",
"length": 0,
"no_copy": 0,
@ -108,6 +128,7 @@
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@ -115,16 +136,20 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Amount",
"length": 0,
"no_copy": 0,
@ -135,6 +160,7 @@
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@ -142,16 +168,49 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_6",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "bom_detail_no",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "BOM Detail No",
"length": 0,
"no_copy": 0,
@ -161,6 +220,7 @@
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@ -168,16 +228,20 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "reference_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Reference Name",
"length": 0,
"no_copy": 0,
@ -187,6 +251,7 @@
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@ -194,16 +259,20 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "conversion_factor",
"fieldtype": "Float",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Conversion Factor",
"length": 0,
"no_copy": 0,
@ -213,6 +282,7 @@
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@ -220,16 +290,20 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "stock_uom",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Stock Uom",
"length": 0,
"no_copy": 0,
@ -240,6 +314,38 @@
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 2,
"fieldname": "reserve_warehouse",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Reserve Warehouse",
"length": 0,
"no_copy": 0,
"options": "Warehouse",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@ -247,17 +353,17 @@
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 1,
"idx": 1,
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2016-07-11 03:28:05.533063",
"modified": "2018-01-05 14:47:15.400785",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order Item Supplied",
@ -266,5 +372,7 @@
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"track_changes": 0,
"track_seen": 0
}

View File

@ -941,8 +941,8 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-08-31 16:10:44.049915",
"modified_by": "tundebabzy@gmail.com",
"modified": "2017-12-26 04:50:15.317590",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier",
"name_case": "Title Case",

View File

@ -17,7 +17,7 @@ QUnit.test("test: supplier quotation with taxes and charges", function(assert) {
{"warehouse": 'Stores - '+frappe.get_abbr(frappe.defaults.get_default('Company'))},
]
]},
{taxes_and_charges:'TEST In State GST'},
{taxes_and_charges:'TEST In State GST - FT'},
]);
},
() => {supplier_quotation_name = cur_frm.doc.name;},

View File

@ -1072,7 +1072,7 @@
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
@ -1162,7 +1162,7 @@
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
@ -1614,7 +1614,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-11-30 14:22:10.542868",
"modified": "2017-12-14 09:37:47.427897",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier Quotation Item",

View File

@ -0,0 +1,61 @@
- Account Numbers
- Default Chart of accounts with account number
- Set account number for your existing chart of accounts
- Payment Terms
- Create Sales Invoice with multiple due dates and payment slab
- Agriculture (New Domain)
- Manage Crop, Crop Cycle, Land Unit, Disease and Fertilizer records
- Maintain records of Plant / Soil / Water Analysis
- Non Profits (New Domain)
- Manage records of Members, Donors, Volunteers and Chapters
- Portal for Grant Application
- Delivery Trip
- Track each of your delivery trips with their associated stops and timing
- Item Variants Update
- Create variants from Quick Entry dialog
- Create multiple variants from a single screen
- Shipping Rule
- Now available in Buying cycle
- Apply based on Net Weight / Fixed Amount / Net Total
- Updated POS
- Single POS Profile for multiple Users
- Sales Payment Summary (X & Z) report
- Fixed multiple bugs
- Employee Advance
- Manage Advances given to your employee and adjust with Expense Claim
- Payroll Entry
- Maintain records of each payroll processing
- Deprecated Process Payroll tool
- Schools to Education
- School module is renamed to Education
- Opening Invoice Tool
- A new tool to create opening invoices
- Asset Maintenance
- Maintain records of Asset Maintenance and Asset Repair
- Employee Tree
- Employee document now has a tree view, so you can create your organisation chart based on it
- Task Tree
- Task also has a Tree view now
- Education module update
- Course Scheduling Tool
- Batch selection based on earlier expiry date of the batch
- Invoice GL Entry based on rounded total (instead of grand total)
- Multiple UOM in Material Request

View File

@ -134,6 +134,14 @@ def get_data():
"link": "pos",
"label": _("POS")
},
{
"module_name": "Leaderboard",
"color": "#589494",
"icon": "octicon octicon-graph",
"type": "page",
"link": "leaderboard",
"label": _("Leaderboard")
},
{
"module_name": "Projects",
"color": "#8e44ad",
@ -292,18 +300,21 @@ def get_data():
"label": _("Hub")
},
{
"module_name": "Data Import Tool",
"color": "#7f8c8d",
"icon": "octicon octicon-circuit-board",
"type": "page",
"link": "data-import-tool",
"label": _("Data Import Tool")
"module_name": "Data Import",
"color": "#FFF168",
"reverse": 1,
"doctype": "Data Import",
"icon": "octicon octicon-cloud-upload",
"label": _("Data Import"),
"link": "List/Data Import",
"type": "list"
},
{
"module_name": "Restaurant",
"color": "#EA81E8",
"icon": "🍔",
"_doctype": "Restaurant",
"type": "list",
"link": "List/Restaurant",
"label": _("Restaurant"),
"hidden": 1
@ -322,7 +333,7 @@ def get_data():
"label": _("Crop"),
"color": "#8BC34A",
"icon": "fa fa-tree",
"type": "link",
"type": "list",
"link": "List/Crop",
"hidden": 1
},
@ -332,7 +343,7 @@ def get_data():
"label": _("Crop Cycle"),
"color": "#8BC34A",
"icon": "fa fa-circle-o-notch",
"type": "link",
"type": "list",
"link": "List/Crop Cycle",
"hidden": 1
},
@ -342,7 +353,7 @@ def get_data():
"label": _("Fertilizer"),
"color": "#8BC34A",
"icon": "fa fa-leaf",
"type": "link",
"type": "list",
"link": "List/Fertilizer",
"hidden": 1
},
@ -352,7 +363,7 @@ def get_data():
"label": _("Land Unit"),
"color": "#8BC34A",
"icon": "fa fa-map",
"type": "link",
"type": "list",
"link": "List/Land Unit",
"hidden": 1
},
@ -362,7 +373,7 @@ def get_data():
"label": _("Disease"),
"color": "#8BC34A",
"icon": "octicon octicon-bug",
"type": "link",
"type": "list",
"link": "List/Disease",
"hidden": 1
},
@ -372,7 +383,7 @@ def get_data():
"label": _("Plant Analysis"),
"color": "#8BC34A",
"icon": "fa fa-pagelines",
"type": "link",
"type": "list",
"link": "List/Plant Analysis",
"hidden": 1
},
@ -382,7 +393,7 @@ def get_data():
"label": _("Soil Analysis"),
"color": "#8BC34A",
"icon": "fa fa-flask",
"type": "link",
"type": "list",
"link": "List/Soil Analysis",
"hidden": 1
},
@ -392,7 +403,7 @@ def get_data():
"label": _("Soil Texture"),
"color": "#8BC34A",
"icon": "octicon octicon-beaker",
"type": "link",
"type": "list",
"link": "List/Soil Texture",
"hidden": 1
},
@ -402,7 +413,7 @@ def get_data():
"label": _("Water Analysis"),
"color": "#8BC34A",
"icon": "fa fa-tint",
"type": "link",
"type": "list",
"link": "List/Water Analysis",
"hidden": 1
},
@ -412,7 +423,7 @@ def get_data():
"label": _("Weather"),
"color": "#8BC34A",
"icon": "fa fa-sun-o",
"type": "link",
"type": "list",
"link": "List/Weather",
"hidden": 1
},
@ -429,6 +440,7 @@ def get_data():
"color": "#E9AB17",
"icon": "fa fa-gift",
"_doctype": "Grant Application",
"type": "list",
"link": "List/Grant Application",
"label": _("Grant Application"),
"hidden": 1
@ -439,6 +451,7 @@ def get_data():
"color": "#7F5A58",
"icon": "fa fa-tint",
"_doctype": "Donor",
"type": "list",
"link": "List/Donor",
"label": _("Donor"),
"hidden": 1
@ -448,6 +461,7 @@ def get_data():
"color": "#7E587E",
"icon": "fa fa-angellist",
"_doctype": "Volunteer",
"type": "list",
"link": "List/Volunteer",
"label": _("Volunteer"),
"hidden": 1
@ -457,6 +471,7 @@ def get_data():
"color": "#79BAEC",
"icon": "fa fa-users",
"_doctype": "Member",
"type": "list",
"link": "List/Member",
"label": _("Member"),
"hidden": 1
@ -466,6 +481,7 @@ def get_data():
"color": "#3B9C9C",
"icon": "fa fa-handshake-o",
"_doctype": "Chapter",
"type": "list",
"link": "List/Chapter",
"label": _("Chapter"),
"hidden": 1

View File

@ -11,7 +11,7 @@ def get_data():
{
"type": "doctype",
"name": "Patient Appointment",
"description": _("Patient Appointment"),
"label": _("Patient Appointment"),
},
{
"type": "doctype",
@ -43,7 +43,7 @@ def get_data():
{
"type": "doctype",
"name": "Lab Test",
"description": _("Results"),
"label": _("Lab Test"),
},
{
"type": "doctype",
@ -53,7 +53,8 @@ def get_data():
{
"type": "report",
"name": "Lab Test Report",
"is_query_report": True
"is_query_report": True,
"label": _("Lab Test Report"),
}
]
},
@ -69,7 +70,7 @@ def get_data():
{
"type": "doctype",
"name": "Physician",
"label": "Physician",
"label": _("Physician"),
},
{
"type": "doctype",
@ -100,57 +101,57 @@ def get_data():
{
"type": "doctype",
"name": "Medical Department",
"label": "Medical Department"
"label": _("Medical Department"),
},
{
"type": "doctype",
"name": "Appointment Type",
"description": _("Appointment Type Master"),
"label": _("Appointment Type"),
},
{
"type": "doctype",
"name": "Prescription Dosage",
"description": _("Prescription Dosage")
"label": _("Prescription Dosage")
},
{
"type": "doctype",
"name": "Prescription Duration",
"description": _("Prescription Period")
"label": _("Prescription Duration")
},
{
"type": "doctype",
"name": "Complaint",
"description": _("Complaint")
"label": _("Complaint")
},
{
"type": "doctype",
"name": "Diagnosis",
"description": _("Diagnosis")
"label": _("Diagnosis")
},
{
"type": "doctype",
"name": "Lab Test Sample",
"description": _("Test Sample Master."),
"label": _("Test Sample."),
},
{
"type": "doctype",
"name": "Lab Test UOM",
"description": _("Lab Test UOM.")
"label": _("Lab Test UOM.")
},
{
"type": "doctype",
"name": "Antibiotic",
"description": _("Antibiotic.")
"label": _("Antibiotic.")
},
{
"type": "doctype",
"name": "Sensitivity",
"description": _("Sensitivity Naming.")
"label": _("Sensitivity Naming.")
},
{
"type": "doctype",
"name": "Lab Test Template",
"description": _("Lab Test Configurations.")
"label": _("Lab Test Template.")
}
]
}

View File

@ -121,6 +121,11 @@ def get_data():
{
"label": _("Expense Claims"),
"items": [
{
"type": "doctype",
"name": "Employee Advance",
"description": _("Manage advance amount given to the Employee"),
},
{
"type": "doctype",
"name": "Expense Claim",

View File

@ -24,7 +24,7 @@ def get_data():
{
"type": "help",
"label": _("Report Builder"),
"youtube_id": "y0o5iYZOioU"
"youtube_id": "TxJGUNarcQs"
},
]
@ -40,7 +40,7 @@ def get_data():
{
"type": "help",
"label": _("Opening Stock Balance"),
"youtube_id": "0yPgrtfeCTs"
"youtube_id": "nlHX0ZZ84Lw"
},
{
"type": "help",
@ -55,7 +55,7 @@ def get_data():
{
"type": "help",
"label": _("Users and Permissions"),
"youtube_id": "fnBoRhBrwR4"
"youtube_id": "8Slw1hsTmUI"
},
{
"type": "help",
@ -120,7 +120,7 @@ def get_data():
{
"type": "help",
"label": _("Sales Order to Payment"),
"youtube_id": "7AMq4lqkN4A"
"youtube_id": "1eP90MWoDQM"
},
{
"type": "help",
@ -195,12 +195,12 @@ def get_data():
{
"type": "help",
"label": _("Material Request to Purchase Order"),
"youtube_id": "4TN9kPyfIqM"
"youtube_id": "55Gk2j7Q8Zw"
},
{
"type": "help",
"label": _("Purchase Order to Payment"),
"youtube_id": "EK65tLdVUDk"
"youtube_id": "efFajTTQBa8"
},
{
"type": "help",
@ -261,7 +261,7 @@ def get_data():
{
"type": "help",
"label": _("Managing Projects"),
"youtube_id": "egxIGwtoKI4"
"youtube_id": "gCzShu9Niu4"
},
]
},

View File

@ -56,7 +56,12 @@ def get_data():
"name": "Stock Ageing",
"doctype": "Item",
},
{
"type": "report",
"is_query_report": True,
"name": "Item Price Stock",
"doctype": "Item",
}
]
},
{

View File

@ -64,15 +64,14 @@ class AccountsController(TransactionBase):
def validate_invoice_documents_schedule(self):
self.validate_payment_schedule_dates()
self.set_due_date()
self.validate_invoice_portion()
self.set_payment_schedule()
self.validate_payment_schedule_amount()
self.validate_due_date()
self.validate_advance_entries()
def validate_non_invoice_documents_schedule(self):
self.validate_invoice_portion()
self.set_payment_schedule()
self.validate_payment_schedule_dates()
self.validate_payment_schedule_amount()
def validate_all_documents_schedule(self):
@ -233,9 +232,10 @@ class AccountsController(TransactionBase):
tax_master_doctype = self.meta.get_field("taxes_and_charges").options
if self.is_new() and not self.get("taxes"):
if not self.get("taxes_and_charges"):
if self.company and not self.get("taxes_and_charges"):
# get the default tax master
self.taxes_and_charges = frappe.db.get_value(tax_master_doctype, {"is_default": 1})
self.taxes_and_charges = frappe.db.get_value(tax_master_doctype,
{"is_default": 1, 'company': self.company})
self.append_taxes_from_master(tax_master_doctype)
@ -375,6 +375,17 @@ class AccountsController(TransactionBase):
return res
def is_inclusive_tax(self):
is_inclusive = cint(frappe.db.get_single_value("Accounts Settings",
"show_inclusive_tax_in_print"))
if is_inclusive:
is_inclusive = 0
if self.get("taxes", filters={"included_in_print_rate": 1}):
is_inclusive = 1
return is_inclusive
def validate_advance_entries(self):
order_field = "sales_order" if self.doctype == "Sales Invoice" else "purchase_order"
order_list = list(set([d.get(order_field)
@ -650,6 +661,8 @@ class AccountsController(TransactionBase):
date = self.get("due_date")
due_date = date or posting_date
grand_total = self.get("rounded_total") or self.grand_total
if self.doctype in ("Sales Invoice", "Purchase Invoice"):
grand_total = grand_total - flt(self.write_off_amount)
if not self.get("payment_schedule"):
if self.get("payment_terms_template"):
@ -661,7 +674,8 @@ class AccountsController(TransactionBase):
self.append("payment_schedule", data)
else:
for d in self.get("payment_schedule"):
d.payment_amount = grand_total * flt(d.invoice_portion) / 100
if d.invoice_portion:
d.payment_amount = grand_total * flt(d.invoice_portion) / 100
def set_due_date(self):
due_dates = [d.due_date for d in self.get("payment_schedule") if d.due_date]
@ -671,15 +685,12 @@ class AccountsController(TransactionBase):
def validate_payment_schedule_dates(self):
dates = []
li = []
if self.due_date and getdate(self.due_date) < getdate(self.posting_date):
frappe.throw(_("Due Date cannot be before posting date"))
for d in self.get("payment_schedule"):
if getdate(d.due_date) < getdate(self.posting_date):
if self.doctype == "Sales Order" and getdate(d.due_date) < getdate(self.transaction_date):
frappe.throw(_("Row {0}: Due Date cannot be before posting date").format(d.idx))
elif d.due_date in dates:
li.append('{0} in row {1}'.format(d.due_date, d.idx))
# frappe.throw(_("Row {0}: Duplicate due date found").format(d.idx))
dates.append(d.due_date)
if li:
@ -692,20 +703,14 @@ class AccountsController(TransactionBase):
total = 0
for d in self.get("payment_schedule"):
total += flt(d.payment_amount)
total = flt(total, self.precision("grand_total"))
grand_total = self.get("rounded_total") or self.grand_total
grand_total = flt(self.get("rounded_total") or self.grand_total, self.precision('grand_total'))
if self.doctype in ("Sales Invoice", "Purchase Invoice"):
grand_total = grand_total - flt(self.write_off_amount)
if total != grand_total:
frappe.throw(_("Total Payment Amount in Payment Schedule must be equal to Grand / Rounded Total"))
def validate_invoice_portion(self):
if self.get("payment_schedule"):
total_portion = 0
for term in self.payment_schedule:
total_portion += flt(term.get('invoice_portion', 0))
if flt(total_portion, 2) != 100.00:
frappe.throw(_('Combined invoice portion must equal 100%'), indicator='red')
def is_rounded_total_disabled(self):
if self.meta.get_field("disable_rounded_total"):
return self.disable_rounded_total
@ -717,8 +722,12 @@ def get_tax_rate(account_head):
return frappe.db.get_value("Account", account_head, ["tax_rate", "account_name"], as_dict=True)
@frappe.whitelist()
def get_default_taxes_and_charges(master_doctype):
default_tax = frappe.db.get_value(master_doctype, {"is_default": 1})
def get_default_taxes_and_charges(master_doctype, company=None):
if not company: return {}
default_tax = frappe.db.get_value(master_doctype,
{"is_default": 1, "company": company})
return {
'taxes_and_charges': default_tax,
'taxes': get_taxes_and_charges(master_doctype, default_tax)

View File

@ -8,7 +8,7 @@ from frappe.utils import flt,cint, cstr, getdate
from erpnext.accounts.party import get_party_details
from erpnext.stock.get_item_details import get_conversion_factor
from erpnext.buying.utils import validate_for_items
from erpnext.buying.utils import validate_for_items, update_last_purchase_rate
from erpnext.stock.stock_ledger import get_valuation_rate
from erpnext.controllers.stock_controller import StockController
@ -18,7 +18,10 @@ class BuyingController(StockController):
if hasattr(self, "taxes"):
self.flags.print_taxes_with_zero_amount = cint(frappe.db.get_single_value("Print Settings",
"print_taxes_with_zero_amount"))
self.flags.show_inclusive_tax_in_print = self.is_inclusive_tax()
self.print_templates = {
"total": "templates/print_formats/includes/total.html",
"taxes": "templates/print_formats/includes/taxes.html"
}
@ -160,6 +163,11 @@ class BuyingController(StockController):
if item in self.sub_contracted_items and not item.bom:
frappe.throw(_("Please select BOM in BOM field for Item {0}").format(item.item_code))
if self.doctype == "Purchase Order":
for supplied_item in self.get("supplied_items"):
if not supplied_item.reserve_warehouse:
frappe.throw(_("Reserved Warehouse is mandatory for Item {0} in Raw Materials supplied").format(frappe.bold(supplied_item.rm_item_code)))
else:
for item in self.get("items"):
if item.bom:
@ -189,8 +197,16 @@ class BuyingController(StockController):
def update_raw_materials_supplied(self, item, raw_material_table):
bom_items = self.get_items_from_bom(item.item_code, item.bom)
raw_materials_cost = 0
items = list(set([d.item_code for d in bom_items]))
item_wh = frappe._dict(frappe.db.sql("""select item_code, default_warehouse
from `tabItem` where name in ({0})""".format(", ".join(["%s"] * len(items))), items))
for bom_item in bom_items:
if self.doctype == "Purchase Order":
reserve_warehouse = bom_item.source_warehouse or item_wh.get(bom_item.item_code)
if frappe.db.get_value("Warehouse", reserve_warehouse, "company") != self.company:
reserve_warehouse = None
# check if exists
exists = 0
for d in self.get(raw_material_table):
@ -210,6 +226,8 @@ class BuyingController(StockController):
rm.rm_item_code = bom_item.item_code
rm.stock_uom = bom_item.stock_uom
rm.required_qty = required_qty
if self.doctype == "Purchase Order" and not rm.reserve_warehouse:
rm.reserve_warehouse = reserve_warehouse
rm.conversion_factor = item.conversion_factor
@ -261,7 +279,7 @@ class BuyingController(StockController):
def get_items_from_bom(self, item_code, bom):
bom_items = frappe.db.sql("""select t2.item_code,
t2.stock_qty / ifnull(t1.quantity, 1) as qty_consumed_per_unit,
t2.rate, t2.stock_uom, t2.name, t2.description
t2.rate, t2.stock_uom, t2.name, t2.description, t2.source_warehouse
from `tabBOM` t1, `tabBOM Item` t2, tabItem t3
where t2.parent = t1.name and t1.item = %s
and t1.docstatus = 1 and t1.is_active = 1 and t1.name = %s
@ -336,7 +354,7 @@ class BuyingController(StockController):
frappe.get_meta(item_row.doctype).get_label(fieldname), item_row['item_code'])))
def update_stock_ledger(self, allow_negative_stock=False, via_landed_cost_voucher=False):
self.update_ordered_qty()
self.update_ordered_and_reserved_qty()
sl_entries = []
stock_items = self.get_stock_items()
@ -378,7 +396,7 @@ class BuyingController(StockController):
self.make_sl_entries(sl_entries, allow_negative_stock=allow_negative_stock,
via_landed_cost_voucher=via_landed_cost_voucher)
def update_ordered_qty(self):
def update_ordered_and_reserved_qty(self):
po_map = {}
for d in self.get("items"):
if self.doctype=="Purchase Receipt" \
@ -397,6 +415,8 @@ class BuyingController(StockController):
frappe.InvalidStatusError)
po_obj.update_ordered_qty(po_item_rows)
if self.is_subcontracted:
po_obj.update_reserved_qty_for_subcontract()
def make_sl_entries_for_supplier_warehouse(self, sl_entries):
if hasattr(self, 'supplied_items'):
@ -409,6 +429,18 @@ class BuyingController(StockController):
"actual_qty": -1*flt(d.consumed_qty),
}))
def on_submit(self):
if self.get('is_return'):
return
update_last_purchase_rate(self, is_submit = 1)
def on_cancel(self):
if self.get('is_return'):
return
update_last_purchase_rate(self, is_submit = 0)
def validate_schedule_date(self):
if not self.schedule_date:
self.schedule_date = min([d.schedule_date for d in self.get("items")])
@ -418,8 +450,9 @@ class BuyingController(StockController):
if not d.schedule_date:
d.schedule_date = self.schedule_date
if d.schedule_date and getdate(d.schedule_date) < getdate(self.transaction_date):
frappe.throw(_("Expected Date cannot be before Transaction Date"))
if (d.schedule_date and self.transaction_date and
getdate(d.schedule_date) < getdate(self.transaction_date)):
frappe.throw(_("Row #{0}: Reqd by Date cannot be before Transaction Date").format(d.idx))
else:
frappe.throw(_("Please enter Schedule Date"))
frappe.throw(_("Please enter Reqd by Date"))

View File

@ -56,7 +56,7 @@ def validate_item_variant_attributes(item, args=None):
if not args:
args = {d.attribute.lower():d.attribute_value for d in item.attributes}
attribute_values, numeric_values = get_attribute_values()
attribute_values, numeric_values = get_attribute_values(item)
for attribute, value in args.items():
if not value:
@ -96,16 +96,17 @@ def validate_item_attribute_value(attributes_list, attribute, attribute_value, i
frappe.throw(_("Value {0} for Attribute {1} does not exist in the list of valid Item Attribute Values for Item {2}").format(
attribute_value, attribute, item), InvalidItemAttributeValueError, title=_('Invalid Attribute'))
def get_attribute_values():
def get_attribute_values(item):
if not frappe.flags.attribute_values:
attribute_values = {}
numeric_values = {}
for t in frappe.get_all("Item Attribute Value", fields=["parent", "attribute_value"]):
attribute_values.setdefault(t.parent.lower(), []).append(t.attribute_value)
for t in frappe.get_all('Item Attribute',
fields=["name", "from_range", "to_range", "increment"], filters={'numeric_values': 1}):
numeric_values[t.name.lower()] = t
for t in frappe.get_all('Item Variant Attribute',
fields=["attribute", "from_range", "to_range", "increment"],
filters={'numeric_values': 1, 'parent': item.variant_of}):
numeric_values[t.attribute.lower()] = t
frappe.flags.attribute_values = attribute_values
frappe.flags.numeric_values = numeric_values

View File

@ -418,6 +418,6 @@ def get_batch_numbers(doctype, txt, searchfield, start, page_len, filters):
'where (`tabBatch`.expiry_date >= CURDATE() or `tabBatch`.expiry_date IS NULL)'
if filters and filters.get('item_code'):
query += 'where item = %(item_code)s' % filters
query += 'and item = %(item_code)s'
return frappe.db.sql(query)
return frappe.db.sql(query, filters)

View File

@ -16,7 +16,10 @@ class SellingController(StockController):
if hasattr(self, "taxes"):
self.flags.print_taxes_with_zero_amount = cint(frappe.db.get_single_value("Print Settings",
"print_taxes_with_zero_amount"))
self.flags.show_inclusive_tax_in_print = self.is_inclusive_tax()
self.print_templates = {
"total": "templates/print_formats/includes/total.html",
"taxes": "templates/print_formats/includes/taxes.html"
}
@ -185,7 +188,10 @@ class SellingController(StockController):
'batch_no': cstr(p.batch_no).strip(),
'serial_no': cstr(p.serial_no).strip(),
'name': d.name,
'target_warehouse': p.target_warehouse
'target_warehouse': p.target_warehouse,
'company': self.company,
'voucher_type': self.doctype,
'allow_zero_valuation': d.allow_zero_valuation_rate
}))
else:
il.append(frappe._dict({
@ -198,7 +204,10 @@ class SellingController(StockController):
'batch_no': cstr(d.get("batch_no")).strip(),
'serial_no': cstr(d.get("serial_no")).strip(),
'name': d.name,
'target_warehouse': d.target_warehouse
'target_warehouse': d.target_warehouse,
'company': self.company,
'voucher_type': self.doctype,
'allow_zero_valuation': d.allow_zero_valuation_rate
}))
return il
@ -293,7 +302,11 @@ class SellingController(StockController):
"posting_date": self.posting_date,
"posting_time": self.posting_time,
"qty": -1*flt(d.qty),
"serial_no": d.serial_no
"serial_no": d.serial_no,
"company": d.company,
"voucher_type": d.voucher_type,
"voucher_no": d.name,
"allow_zero_valuation": d.allow_zero_valuation
})
target_warehouse_sle.update({
"incoming_rate": get_incoming_rate(args)

View File

@ -70,7 +70,6 @@ class calculate_taxes_and_totals(object):
item.net_rate = item.rate
item.amount = flt(item.rate * item.qty, item.precision("amount"))
item.net_amount = item.amount
item.total_weight = flt(item.weight_per_unit * item.qty)
self._set_in_company_currency(item, ["price_list_rate", "rate", "net_rate", "amount", "net_amount"])
@ -164,13 +163,12 @@ class calculate_taxes_and_totals(object):
return tax.rate
def calculate_net_total(self):
self.doc.total = self.doc.base_total = self.doc.net_total = self.doc.base_net_total = self.doc.total_net_weight= 0.0
self.doc.total = self.doc.base_total = self.doc.net_total = self.doc.base_net_total = 0.0
for item in self.doc.get("items"):
self.doc.total += item.amount
self.doc.base_total += item.base_amount
self.doc.net_total += item.net_amount
self.doc.base_net_total += item.base_net_amount
self.doc.total_net_weight += item.total_weight
self.doc.round_floats_in(self.doc, ["total", "base_total", "net_total", "base_net_total"])
@ -400,7 +398,8 @@ class calculate_taxes_and_totals(object):
for tax in self.doc.get("taxes"):
if tax.charge_type == "Actual":
actual_taxes_dict.setdefault(tax.idx, tax.tax_amount)
tax_amount = self.get_tax_amount_if_for_valuation_or_deduction(tax.tax_amount, tax)
actual_taxes_dict.setdefault(tax.idx, tax_amount)
elif tax.row_id in actual_taxes_dict:
actual_tax_amount = flt(actual_taxes_dict.get(tax.row_id, 0)) * flt(tax.rate) / 100
actual_taxes_dict.setdefault(tax.idx, actual_tax_amount)
@ -535,7 +534,7 @@ def get_itemised_tax_breakup_html(doc):
for tax in doc.taxes:
if getattr(tax, "category", None) and tax.category=="Valuation":
continue
if tax.description not in tax_accounts and tax.tax_amount_after_discount_amount:
if tax.description not in tax_accounts:
tax_accounts.append(tax.description)
headers = get_itemised_tax_breakup_header(doc.doctype + " Item", tax_accounts)
@ -545,6 +544,7 @@ def get_itemised_tax_breakup_html(doc):
get_rounded_tax_amount(itemised_tax, doc.precision("tax_amount", "taxes"))
update_itemised_tax_data(doc)
frappe.flags.company = None
return frappe.render_template(
@ -557,6 +557,12 @@ def get_itemised_tax_breakup_html(doc):
)
)
@erpnext.allow_regional
def update_itemised_tax_data(doc):
#Don't delete this method, used for localization
pass
@erpnext.allow_regional
def get_itemised_tax_breakup_header(item_doctype, tax_accounts):
return [_("Item"), _("Taxable Amount")] + tax_accounts

View File

@ -101,7 +101,7 @@ class Lead(SellingController):
def set_lead_name(self):
if not self.lead_name:
frappe.db.set_value("Lead", self.name, "lead_name", self.organization_name)
frappe.db.set_value("Lead", self.name, "lead_name", self.company_name)
@frappe.whitelist()
def make_customer(source_name, target_doc=None):
@ -129,7 +129,6 @@ def _make_customer(source_name, target_doc=None, ignore_permissions=False):
}
}}, target_doc, set_missing_values, ignore_permissions=ignore_permissions)
print(doclist)
return doclist
@frappe.whitelist()

View File

@ -29,7 +29,7 @@
"email_id": "test_lead4@example.com",
"organization_lead": 1,
"lead_name": "_Test Lead 4",
"organization_name": "_Test Lead 4",
"company_name": "_Test Lead 4",
"status": "Open"
}
]

View File

@ -232,7 +232,7 @@ def make_quotation(source_name, target_doc=None):
quotation.conversion_rate = exchange_rate
# get default taxes
taxes = get_default_taxes_and_charges("Sales Taxes and Charges Template")
taxes = get_default_taxes_and_charges("Sales Taxes and Charges Template", quotation.company)
if taxes.get('taxes'):
quotation.update(taxes)

View File

@ -2,36 +2,43 @@
{
"asset_name": "Macbook Pro - 1",
"item_code": "Computer",
"gross_purchase_amount": 100000
"gross_purchase_amount": 100000,
"asset_owner": "Company"
},
{
"asset_name": "Macbook Air - 1",
"item_code": "Computer",
"gross_purchase_amount": 60000
"gross_purchase_amount": 60000,
"asset_owner": "Company"
},
{
"asset_name": "Conferrence Table",
"item_code": "Table",
"gross_purchase_amount": 30000
"gross_purchase_amount": 30000,
"asset_owner": "Company"
},
{
"asset_name": "Lunch Table",
"item_code": "Table",
"gross_purchase_amount": 20000
"gross_purchase_amount": 20000,
"asset_owner": "Company"
},
{
"asset_name": "ERPNext",
"item_code": "ERP",
"gross_purchase_amount": 100000
"gross_purchase_amount": 100000,
"asset_owner": "Company"
},
{
"asset_name": "Chair 1",
"item_code": "Chair",
"gross_purchase_amount": 10000
"gross_purchase_amount": 10000,
"asset_owner": "Company"
},
{
"asset_name": "Chair 2",
"item_code": "Chair",
"gross_purchase_amount": 10000
"gross_purchase_amount": 10000,
"asset_owner": "Company"
}
]

View File

@ -55,7 +55,7 @@ def complete_setup(domain='Manufacturing'):
"fy_start_date": "2015-01-01",
"fy_end_date": "2015-12-31",
"bank_account": "National Bank",
"domain": domain,
"domains": [domain],
"company_name": data.get(domain).get('company_name'),
"chart_of_accounts": "Standard",
"company_abbr": ''.join([d[0] for d in data.get(domain).get('company_name').split()]).upper(),

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 377 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

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