Merge branch 'develop'

This commit is contained in:
Anand Doshi 2015-10-22 17:12:01 +05:30
commit 54059b77a0
76 changed files with 13531 additions and 11170 deletions

View File

@ -1,2 +1,2 @@
from __future__ import unicode_literals from __future__ import unicode_literals
__version__ = '6.5.3' __version__ = '6.6.0'

View File

@ -8,10 +8,10 @@ frappe.require("assets/erpnext/js/utils.js");
frappe.ui.form.on("Journal Entry", { frappe.ui.form.on("Journal Entry", {
refresh: function(frm) { refresh: function(frm) {
erpnext.toggle_naming_series(); erpnext.toggle_naming_series();
cur_frm.cscript.voucher_type(frm.doc); frm.cscript.voucher_type(frm.doc);
if(frm.doc.docstatus==1) { if(frm.doc.docstatus==1) {
cur_frm.add_custom_button(__('View Ledger'), function() { frm.add_custom_button(__('View Ledger'), function() {
frappe.route_options = { frappe.route_options = {
"voucher_no": frm.doc.name, "voucher_no": frm.doc.name,
"from_date": frm.doc.posting_date, "from_date": frm.doc.posting_date,
@ -23,6 +23,12 @@ frappe.ui.form.on("Journal Entry", {
}, "icon-table"); }, "icon-table");
} }
if (frm.doc.__islocal) {
frm.add_custom_button(__('Quick Entry'), function() {
return erpnext.journal_entry.quick_entry(frm);
});
}
// hide /unhide fields based on currency // hide /unhide fields based on currency
erpnext.journal_entry.toggle_fields_based_on_currency(frm); erpnext.journal_entry.toggle_fields_based_on_currency(frm);
}, },
@ -32,24 +38,6 @@ frappe.ui.form.on("Journal Entry", {
} }
}) })
erpnext.journal_entry.toggle_fields_based_on_currency = function(frm) {
var fields = ["currency_section", "account_currency", "exchange_rate", "debit", "credit"];
var grid = frm.get_field("accounts").grid;
if(grid) grid.set_column_disp(fields, frm.doc.multi_currency);
// dynamic label
var field_label_map = {
"debit_in_account_currency": "Debit",
"credit_in_account_currency": "Credit"
};
$.each(field_label_map, function (fieldname, label) {
var df = frappe.meta.get_docfield("Journal Entry Account", fieldname, frm.doc.name);
df.label = frm.doc.multi_currency ? (label + " in Account Currency") : label;
})
}
erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
onload: function() { onload: function() {
this.load_defaults(); this.load_defaults();
@ -69,7 +57,7 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
} }
); );
if(!this.frm.doc.amended_from) this.frm.doc.posting_date = get_today(); if(!this.frm.doc.amended_from) this.frm.doc.posting_date = this.frm.posting_date || get_today();
} }
}, },
@ -77,16 +65,7 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
var me = this; var me = this;
me.frm.set_query("account", "accounts", function(doc, cdt, cdn) { me.frm.set_query("account", "accounts", function(doc, cdt, cdn) {
var filters = { return erpnext.journal_entry.account_query(me.frm);
company: me.frm.doc.company,
is_group: 0
};
if(!doc.multi_currency) {
$.extend(filters, {
account_currency: frappe.get_doc(":Company", me.frm.doc.company).default_currency
});
}
return { filters: filters };
}); });
me.frm.set_query("cost_center", "accounts", function(doc, cdt, cdn) { me.frm.set_query("cost_center", "accounts", function(doc, cdt, cdn) {
@ -244,6 +223,7 @@ cur_frm.cscript.company = function(doc, cdt, cdn) {
} }
cur_frm.cscript.posting_date = function(doc, cdt, cdn){ cur_frm.cscript.posting_date = function(doc, cdt, cdn){
cur_frm.posting_date = cur_frm.doc.posting_date;
erpnext.get_fiscal_year(doc.company, doc.posting_date); erpnext.get_fiscal_year(doc.company, doc.posting_date);
} }
@ -399,41 +379,132 @@ frappe.ui.form.on("Journal Entry Account", "accounts_remove", function(frm) {
cur_frm.cscript.update_totals(frm.doc); cur_frm.cscript.update_totals(frm.doc);
}); });
erpnext.journal_entry.set_debit_credit_in_company_currency = function(frm, cdt, cdn) { $.extend(erpnext.journal_entry, {
erpnext.journal_entry.set_exchange_rate(frm, cdt, cdn); toggle_fields_based_on_currency: function(frm) {
var fields = ["currency_section", "account_currency", "exchange_rate", "debit", "credit"];
var row = locals[cdt][cdn]; var grid = frm.get_field("accounts").grid;
if(grid) grid.set_column_disp(fields, frm.doc.multi_currency);
frappe.model.set_value(cdt, cdn, "debit", // dynamic label
flt(flt(row.debit_in_account_currency)*row.exchange_rate), precision("debit", row)); var field_label_map = {
frappe.model.set_value(cdt, cdn, "credit", "debit_in_account_currency": "Debit",
flt(flt(row.credit_in_account_currency)*row.exchange_rate), precision("credit", row)); "credit_in_account_currency": "Credit"
} };
erpnext.journal_entry.set_exchange_rate = function(frm, cdt, cdn) { $.each(field_label_map, function (fieldname, label) {
var company_currency = frappe.get_doc(":Company", frm.doc.company).default_currency; var df = frappe.meta.get_docfield("Journal Entry Account", fieldname, frm.doc.name);
var row = locals[cdt][cdn]; df.label = frm.doc.multi_currency ? (label + " in Account Currency") : label;
if(row.account_currency == company_currency || !frm.doc.multi_currency) {
frappe.model.set_value(cdt, cdn, "exchange_rate", 1);
} else if (!row.exchange_rate || row.account_type == "Bank") {
frappe.call({
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_exchange_rate",
args: {
account: row.account,
account_currency: row.account_currency,
company: frm.doc.company,
reference_type: cstr(row.reference_type),
reference_name: cstr(row.reference_name),
debit: flt(row.debit_in_account_currency),
credit: flt(row.credit_in_account_currency),
exchange_rate: row.exchange_rate
},
callback: function(r) {
if(r.message) {
frappe.model.set_value(cdt, cdn, "exchange_rate", r.message);
}
}
}) })
},
set_debit_credit_in_company_currency: function(frm, cdt, cdn) {
erpnext.journal_entry.set_exchange_rate(frm, cdt, cdn);
var row = locals[cdt][cdn];
frappe.model.set_value(cdt, cdn, "debit",
flt(flt(row.debit_in_account_currency)*row.exchange_rate), precision("debit", row));
frappe.model.set_value(cdt, cdn, "credit",
flt(flt(row.credit_in_account_currency)*row.exchange_rate), precision("credit", row));
},
set_exchange_rate: function(frm, cdt, cdn) {
var company_currency = frappe.get_doc(":Company", frm.doc.company).default_currency;
var row = locals[cdt][cdn];
if(row.account_currency == company_currency || !frm.doc.multi_currency) {
frappe.model.set_value(cdt, cdn, "exchange_rate", 1);
} else if (!row.exchange_rate || row.account_type == "Bank") {
frappe.call({
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_exchange_rate",
args: {
account: row.account,
account_currency: row.account_currency,
company: frm.doc.company,
reference_type: cstr(row.reference_type),
reference_name: cstr(row.reference_name),
debit: flt(row.debit_in_account_currency),
credit: flt(row.credit_in_account_currency),
exchange_rate: row.exchange_rate
},
callback: function(r) {
if(r.message) {
frappe.model.set_value(cdt, cdn, "exchange_rate", r.message);
}
}
})
}
},
quick_entry: function(frm) {
var naming_series_options = frm.fields_dict.naming_series.df.options;
var naming_series_default = frm.fields_dict.naming_series.df.default || naming_series_options.split("\n")[0];
var dialog = new frappe.ui.Dialog({
title: __("Quick Journal Entry"),
fields: [
{fieldtype: "Currency", fieldname: "debit", label: __("Amount"), reqd: 1},
{fieldtype: "Link", fieldname: "debit_account", label: __("Debit Account"), reqd: 1,
options: "Account",
get_query: function() {
return erpnext.journal_entry.account_query(frm);
}
},
{fieldtype: "Link", fieldname: "credit_account", label: __("Credit Account"), reqd: 1,
options: "Account",
get_query: function() {
return erpnext.journal_entry.account_query(frm);
}
},
{fieldtype: "Date", fieldname: "posting_date", label: __("Date"), reqd: 1,
default: frm.doc.posting_date},
{fieldtype: "Select", fieldname: "naming_series", label: __("Series"), reqd: 1,
options: naming_series_options, default: naming_series_default},
]
});
dialog.set_primary_action(__("Save"), function() {
var btn = this;
var values = dialog.get_values();
frm.set_value("posting_date", values.posting_date);
frm.set_value("naming_series", values.naming_series);
// clear table is used because there might've been an error while adding child
// and cleanup didn't happen
frm.clear_table("accounts");
// using grid.add_new_row() to add a row in UI as well as locals
// this is required because triggers try to refresh the grid
var debit_row = frm.fields_dict.accounts.grid.add_new_row();
frappe.model.set_value(debit_row.doctype, debit_row.name, "account", values.debit_account);
frappe.model.set_value(debit_row.doctype, debit_row.name, "debit_in_account_currency", values.debit);
var credit_row = frm.fields_dict.accounts.grid.add_new_row();
frappe.model.set_value(credit_row.doctype, credit_row.name, "account", values.credit_account);
frappe.model.set_value(credit_row.doctype, credit_row.name, "credit_in_account_currency", values.debit);
frm.save();
dialog.hide();
});
dialog.show();
},
account_query: function(frm) {
var filters = {
company: frm.doc.company,
is_group: 0
};
if(!frm.doc.multi_currency) {
$.extend(filters, {
account_currency: frappe.get_doc(":Company", frm.doc.company).default_currency
});
}
return { filters: filters };
} }
} });

View File

@ -13,7 +13,7 @@ cur_frm.fields_dict['closing_account_head'].get_query = function(doc, cdt, cdn)
return{ return{
filters:{ filters:{
"company": doc.company, "company": doc.company,
"report_type": "Balance Sheet", "root_type": "Liability",
"freeze_account": "No", "freeze_account": "No",
"is_group": 0 "is_group": 0
} }

View File

@ -194,29 +194,6 @@
"set_only_once": 0, "set_only_once": 0,
"unique": 0 "unique": 0
}, },
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "coa_help",
"fieldtype": "HTML",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "CoA Help",
"no_copy": 0,
"oldfieldtype": "HTML",
"options": "<a href=\"#!Accounts Browser/Account\">To manage Account Head, click here</a>",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{ {
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
@ -250,7 +227,7 @@
"is_submittable": 1, "is_submittable": 1,
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"modified": "2015-10-02 07:39:00.056337", "modified": "2015-10-21 12:40:58.278256",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Period Closing Voucher", "name": "Period Closing Voucher",

View File

@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe import frappe
from frappe.utils import flt from frappe.utils import flt
from frappe import _ from frappe import _
from erpnext.accounts.utils import get_account_currency
from erpnext.controllers.accounts_controller import AccountsController from erpnext.controllers.accounts_controller import AccountsController
class PeriodClosingVoucher(AccountsController): class PeriodClosingVoucher(AccountsController):
@ -20,51 +21,75 @@ class PeriodClosingVoucher(AccountsController):
where voucher_type = 'Period Closing Voucher' and voucher_no=%s""", self.name) where voucher_type = 'Period Closing Voucher' and voucher_no=%s""", self.name)
def validate_account_head(self): def validate_account_head(self):
if frappe.db.get_value("Account", self.closing_account_head, "report_type") \ closing_account_type = frappe.db.get_value("Account", self.closing_account_head, "root_type")
!= "Balance Sheet":
frappe.throw(_("Closing Account {0} must be of type 'Liability'").format(self.closing_account_head)) if closing_account_type != "Liability":
frappe.throw(_("Closing Account {0} must be of type 'Liability'")
.format(self.closing_account_head))
account_currency = get_account_currency(self.closing_account_head)
company_currency = frappe.db.get_value("Company", self.company, "default_currency")
if account_currency != company_currency:
frappe.throw(_("Currency of the Closing Account must be {0}").format(company_currency))
def validate_posting_date(self): def validate_posting_date(self):
from erpnext.accounts.utils import get_fiscal_year from erpnext.accounts.utils import get_fiscal_year, validate_fiscal_year
validate_fiscal_year(self.posting_date, self.fiscal_year, label=_("Posting Date"), doc=self)
self.year_start_date = get_fiscal_year(self.posting_date, self.fiscal_year)[1] self.year_start_date = get_fiscal_year(self.posting_date, self.fiscal_year)[1]
pce = frappe.db.sql("""select name from `tabPeriod Closing Voucher` pce = frappe.db.sql("""select name from `tabPeriod Closing Voucher`
where posting_date > %s and fiscal_year = %s and docstatus = 1""", where posting_date > %s and fiscal_year = %s and docstatus = 1""",
(self.posting_date, self.fiscal_year)) (self.posting_date, self.fiscal_year))
if pce and pce[0][0]: if pce and pce[0][0]:
frappe.throw(_("Another Period Closing Entry {0} has been made after {1}").format(pce[0][0], self.posting_date)) frappe.throw(_("Another Period Closing Entry {0} has been made after {1}")
.format(pce[0][0], self.posting_date))
def make_gl_entries(self):
gl_entries = []
net_pl_balance = 0
pl_accounts = self.get_pl_balances()
for acc in pl_accounts:
if flt(acc.balance_in_company_currency):
gl_entries.append(self.get_gl_dict({
"account": acc.account,
"account_currency": acc.account_currency,
"debit_in_account_currency": abs(flt(acc.balance_in_account_currency)) \
if flt(acc.balance_in_account_currency) < 0 else 0,
"debit": abs(flt(acc.balance_in_company_currency)) \
if flt(acc.balance_in_company_currency) < 0 else 0,
"credit_in_account_currency": abs(flt(acc.balance_in_account_currency)) \
if flt(acc.balance_in_account_currency) > 0 else 0,
"credit": abs(flt(acc.balance_in_company_currency)) \
if flt(acc.balance_in_company_currency) > 0 else 0
}))
net_pl_balance += flt(acc.balance_in_company_currency)
if net_pl_balance:
gl_entries.append(self.get_gl_dict({
"account": self.closing_account_head,
"debit_in_account_currency": abs(net_pl_balance) if net_pl_balance > 0 else 0,
"debit": abs(net_pl_balance) if net_pl_balance > 0 else 0,
"credit_in_account_currency": abs(net_pl_balance) if net_pl_balance < 0 else 0,
"credit": abs(net_pl_balance) if net_pl_balance < 0 else 0
}))
from erpnext.accounts.general_ledger import make_gl_entries
make_gl_entries(gl_entries)
def get_pl_balances(self): def get_pl_balances(self):
"""Get balance for pl accounts""" """Get balance for pl accounts"""
return frappe.db.sql(""" return frappe.db.sql("""
select t1.account, sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) as balance select
t1.account, t2.account_currency, sum(ifnull(t1.debit_in_account_currency,0))-sum(ifnull(t1.credit_in_account_currency,0))
as balance_in_account_currency,
sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) as balance_in_company_currency
from `tabGL Entry` t1, `tabAccount` t2 from `tabGL Entry` t1, `tabAccount` t2
where t1.account = t2.name and ifnull(t2.report_type, '') = 'Profit and Loss' where t1.account = t2.name and ifnull(t2.report_type, '') = 'Profit and Loss'
and t2.docstatus < 2 and t2.company = %s and t2.docstatus < 2 and t2.company = %s
and t1.posting_date between %s and %s and t1.posting_date between %s and %s
group by t1.account group by t1.account
""", (self.company, self.get("year_start_date"), self.posting_date), as_dict=1) """, (self.company, self.get("year_start_date"), self.posting_date), as_dict=1)
def make_gl_entries(self):
gl_entries = []
net_pl_balance = 0
pl_accounts = self.get_pl_balances()
for acc in pl_accounts:
if flt(acc.balance):
gl_entries.append(self.get_gl_dict({
"account": acc.account,
"debit": abs(flt(acc.balance)) if flt(acc.balance) < 0 else 0,
"credit": abs(flt(acc.balance)) if flt(acc.balance) > 0 else 0,
}))
net_pl_balance += flt(acc.balance)
if net_pl_balance:
gl_entries.append(self.get_gl_dict({
"account": self.closing_account_head,
"debit": abs(net_pl_balance) if net_pl_balance > 0 else 0,
"credit": abs(net_pl_balance) if net_pl_balance < 0 else 0
}))
from erpnext.accounts.general_ledger import make_gl_entries
make_gl_entries(gl_entries)

View File

@ -5,42 +5,74 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import unittest import unittest
import frappe import frappe
from frappe.utils import flt from frappe.utils import flt, today
from erpnext.accounts.utils import get_fiscal_year
from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
class TestPeriodClosingVoucher(unittest.TestCase): class TestPeriodClosingVoucher(unittest.TestCase):
def test_closing_entry(self): def test_closing_entry(self):
year_start_date = get_fiscal_year(today())[1]
make_journal_entry("_Test Bank - _TC", "Sales - _TC", 400, make_journal_entry("_Test Bank - _TC", "Sales - _TC", 400,
"_Test Cost Center - _TC", submit=True) "_Test Cost Center - _TC", submit=True)
make_journal_entry("_Test Account Cost for Goods Sold - _TC", make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", 600, "_Test Cost Center - _TC", submit=True) "_Test Bank - _TC", 600, "_Test Cost Center - _TC", submit=True)
random_expense_account = frappe.db.sql("""
select t1.account,
sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) as balance,
sum(ifnull(t1.debit_in_account_currency,0))-sum(ifnull(t1.credit_in_account_currency,0)) \
as balance_in_account_currency
from `tabGL Entry` t1, `tabAccount` t2
where t1.account = t2.name and ifnull(t2.root_type, '') = 'Expense'
and t2.docstatus < 2 and t2.company = '_Test Company'
and t1.posting_date between %s and %s
group by t1.account
having sum(ifnull(t1.debit,0)) > sum(ifnull(t1.credit,0))
limit 1""", (year_start_date, today()), as_dict=True)
profit_or_loss = frappe.db.sql("""select sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) as balance profit_or_loss = frappe.db.sql("""select sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) as balance
from `tabGL Entry` t1, `tabAccount` t2 from `tabGL Entry` t1, `tabAccount` t2
where t1.account = t2.name and ifnull(t2.report_type, '') = 'Profit and Loss' where t1.account = t2.name and ifnull(t2.report_type, '') = 'Profit and Loss'
and t2.docstatus < 2 and t2.company = '_Test Company' and t2.docstatus < 2 and t2.company = '_Test Company'
and t1.posting_date between '2013-01-01' and '2013-12-31'""") and t1.posting_date between %s and %s""", (year_start_date, today()))
profit_or_loss = flt(profit_or_loss[0][0]) if profit_or_loss else 0 profit_or_loss = flt(profit_or_loss[0][0]) if profit_or_loss else 0
pcv = self.make_period_closing_voucher() pcv = self.make_period_closing_voucher()
gle_value = frappe.db.sql("""select ifnull(debit, 0) - ifnull(credit, 0) # Check value for closing account
gle_amount_for_closing_account = frappe.db.sql("""select ifnull(debit, 0) - ifnull(credit, 0)
from `tabGL Entry` where voucher_type='Period Closing Voucher' and voucher_no=%s from `tabGL Entry` where voucher_type='Period Closing Voucher' and voucher_no=%s
and account = '_Test Account Reserves and Surplus - _TC'""", pcv.name) and account = '_Test Account Reserves and Surplus - _TC'""", pcv.name)
gle_value = flt(gle_value[0][0]) if gle_value else 0 gle_amount_for_closing_account = flt(gle_amount_for_closing_account[0][0]) \
if gle_amount_for_closing_account else 0
self.assertEqual(gle_value, profit_or_loss) self.assertEqual(gle_amount_for_closing_account, profit_or_loss)
if random_expense_account:
# Check posted value for teh above random_expense_account
gle_for_random_expense_account = frappe.db.sql("""
select ifnull(debit, 0) - ifnull(credit, 0) as amount,
ifnull(debit_in_account_currency, 0) - ifnull(credit_in_account_currency, 0)
as amount_in_account_currency
from `tabGL Entry`
where voucher_type='Period Closing Voucher' and voucher_no=%s and account =%s""",
(pcv.name, random_expense_account[0].account), as_dict=True)
self.assertEqual(gle_for_random_expense_account[0].amount, -1*random_expense_account[0].balance)
self.assertEqual(gle_for_random_expense_account[0].amount_in_account_currency,
-1*random_expense_account[0].balance_in_account_currency)
def make_period_closing_voucher(self): def make_period_closing_voucher(self):
pcv = frappe.get_doc({ pcv = frappe.get_doc({
"doctype": "Period Closing Voucher", "doctype": "Period Closing Voucher",
"closing_account_head": "_Test Account Reserves and Surplus - _TC", "closing_account_head": "_Test Account Reserves and Surplus - _TC",
"company": "_Test Company", "company": "_Test Company",
"fiscal_year": "_Test Fiscal Year 2013", "fiscal_year": get_fiscal_year(today())[0],
"posting_date": "2013-12-31", "posting_date": today(),
"remarks": "test" "remarks": "test"
}) })
pcv.insert() pcv.insert()

View File

@ -317,23 +317,22 @@ class PurchaseInvoice(BuyingController):
if auto_accounting_for_stock and self.is_opening == "No" and \ if auto_accounting_for_stock and self.is_opening == "No" and \
item.item_code in stock_items and item.item_tax_amount: item.item_code in stock_items and item.item_tax_amount:
# Post reverse entry for Stock-Received-But-Not-Billed if it is booked in Purchase Receipt # Post reverse entry for Stock-Received-But-Not-Billed if it is booked in Purchase Receipt
negative_expense_booked_in_pi = None
if item.purchase_receipt: if item.purchase_receipt:
negative_expense_booked_in_pi = frappe.db.sql("""select name from `tabGL Entry` negative_expense_booked_in_pr = frappe.db.sql("""select name from `tabGL Entry`
where voucher_type='Purchase Receipt' and voucher_no=%s and account=%s""", where voucher_type='Purchase Receipt' and voucher_no=%s and account=%s""",
(item.purchase_receipt, expenses_included_in_valuation)) (item.purchase_receipt, expenses_included_in_valuation))
if not negative_expense_booked_in_pi: if not negative_expense_booked_in_pr:
gl_entries.append( gl_entries.append(
self.get_gl_dict({ self.get_gl_dict({
"account": stock_received_but_not_billed, "account": stock_received_but_not_billed,
"against": self.supplier, "against": self.supplier,
"debit": flt(item.item_tax_amount, self.precision("item_tax_amount", item)), "debit": flt(item.item_tax_amount, self.precision("item_tax_amount", item)),
"remarks": self.remarks or "Accounting Entry for Stock" "remarks": self.remarks or "Accounting Entry for Stock"
}) })
) )
negative_expense_to_be_booked += flt(item.item_tax_amount, self.precision("item_tax_amount", item)) negative_expense_to_be_booked += flt(item.item_tax_amount, self.precision("item_tax_amount", item))
if self.is_opening == "No" and negative_expense_to_be_booked and valuation_tax: if self.is_opening == "No" and negative_expense_to_be_booked and valuation_tax:
# credit valuation tax amount in "Expenses Included In Valuation" # credit valuation tax amount in "Expenses Included In Valuation"

View File

@ -50,23 +50,7 @@ class TestPurchaseInvoice(unittest.TestCase):
pi.insert() pi.insert()
pi.submit() pi.submit()
gl_entries = frappe.db.sql("""select account, debit, credit self.check_gle_for_pi(pi.name)
from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
order by account asc""", pi.name, as_dict=1)
self.assertTrue(gl_entries)
expected_values = dict((d[0], d) for d in [
["_Test Payable - _TC", 0, 720],
["Stock Received But Not Billed - _TC", 750.0, 0],
["Expenses Included In Valuation - _TC", 0.0, 250.0],
["_Test Account Shipping Charges - _TC", 100.0, 0],
["_Test Account VAT - _TC", 120.0, 0],
])
for i, gle in enumerate(gl_entries):
self.assertEquals(expected_values[gle.account][0], gle.account)
self.assertEquals(expected_values[gle.account][1], gle.debit)
self.assertEquals(expected_values[gle.account][2], gle.credit)
set_perpetual_inventory(0) set_perpetual_inventory(0)
@ -83,9 +67,14 @@ class TestPurchaseInvoice(unittest.TestCase):
pi.insert() pi.insert()
pi.submit() pi.submit()
self.check_gle_for_pi(pi.name)
set_perpetual_inventory(0)
def check_gle_for_pi(self, pi):
gl_entries = frappe.db.sql("""select account, debit, credit gl_entries = frappe.db.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
order by account asc""", pi.name, as_dict=1) order by account asc""", pi, as_dict=1)
self.assertTrue(gl_entries) self.assertTrue(gl_entries)
expected_values = dict((d[0], d) for d in [ expected_values = dict((d[0], d) for d in [
@ -100,8 +89,6 @@ class TestPurchaseInvoice(unittest.TestCase):
self.assertEquals(expected_values[gle.account][1], gle.debit) self.assertEquals(expected_values[gle.account][1], gle.debit)
self.assertEquals(expected_values[gle.account][2], gle.credit) self.assertEquals(expected_values[gle.account][2], gle.credit)
set_perpetual_inventory(0)
def test_gl_entries_with_aia_for_non_stock_items(self): def test_gl_entries_with_aia_for_non_stock_items(self):
set_perpetual_inventory() set_perpetual_inventory()
self.assertEqual(cint(frappe.defaults.get_global_default("auto_accounting_for_stock")), 1) self.assertEqual(cint(frappe.defaults.get_global_default("auto_accounting_for_stock")), 1)

View File

@ -0,0 +1,2 @@
- **Quick Entry dialog for Journal Entry**: Just enter Amount, Accounts, Date and save!
- Period Closing Voucher as per multi-currency accounting

View File

@ -221,7 +221,7 @@ class AccountsController(TransactionBase):
if not account_currency: if not account_currency:
account_currency = get_account_currency(gl_dict.account) account_currency = get_account_currency(gl_dict.account)
if self.doctype != "Journal Entry": if self.doctype not in ["Journal Entry", "Period Closing Voucher"]:
self.validate_account_currency(gl_dict.account, account_currency) self.validate_account_currency(gl_dict.account, account_currency)
self.set_balance_in_account_currency(gl_dict, account_currency) self.set_balance_in_account_currency(gl_dict, account_currency)

View File

@ -29,7 +29,7 @@ blogs.
""" """
app_icon = "icon-th" app_icon = "icon-th"
app_color = "#e74c3c" app_color = "#e74c3c"
app_version = "6.5.3" app_version = "6.6.0"
github_link = "https://github.com/frappe/erpnext" github_link = "https://github.com/frappe/erpnext"
error_report_email = "support@erpnext.com" error_report_email = "support@erpnext.com"

View File

@ -3,113 +3,116 @@
cur_frm.add_fetch('employee','employee_name','employee_name'); cur_frm.add_fetch('employee','employee_name','employee_name');
frappe.ui.form.on("Leave Application", "leave_approver", function(frm) { frappe.ui.form.on("Leave Application", {
frm.set_value("leave_approver_name", frappe.user.full_name(frm.doc.leave_approver)); onload: function(frm) {
}); if (!frm.doc.posting_date) {
frm.set_value("posting_date", get_today());
}
cur_frm.cscript.onload = function(doc, dt, dn) { frm.set_query("leave_approver", function() {
if(!doc.posting_date) return {
set_multiple(dt,dn,{posting_date:get_today()}); query: "erpnext.hr.doctype.leave_application.leave_application.get_approvers",
if(doc.__islocal) { filters: {
cur_frm.set_value("status", "Open"); employee: frm.doc.employee
cur_frm.cscript.calculate_total_days(doc, dt, dn); }
} };
});
cur_frm.set_query("leave_approver", function() { frm.set_query("employee", erpnext.queries.employee);
return {
query: "erpnext.hr.doctype.leave_application.leave_application.get_approvers",
filters: {
employee: cur_frm.doc.employee
}
};
});
cur_frm.cscript.get_leave_balance(cur_frm.doc); },
}
cur_frm.cscript.refresh = function(doc, dt, dn) { refresh: function(frm) {
if(doc.__islocal) { if (frm.is_new()) {
cur_frm.set_value("status", "Open") frm.set_value("status", "Open");
} frm.trigger("calculate_total_days");
cur_frm.set_intro(""); }
if(doc.__islocal && !in_list(user_roles, "HR User")) {
cur_frm.set_intro(__("Fill the form and save it")) frm.set_intro("");
} else { if (frm.is_new() && !in_list(user_roles, "HR User")) {
if(doc.docstatus==0 && doc.status=="Open") { frm.set_intro(__("Fill the form and save it"));
if(user==doc.leave_approver) { } else {
cur_frm.set_intro(__("You are the Leave Approver for this record. Please Update the 'Status' and Save")); if(frm.doc.docstatus==0 && frm.doc.status=="Open") {
cur_frm.toggle_enable("status", true); if(user==frm.doc.leave_approver) {
} else { frm.set_intro(__("You are the Leave Approver for this record. Please Update the 'Status' and Save"));
cur_frm.set_intro(__("This Leave Application is pending approval. Only the Leave Approver can update status.")) frm.toggle_enable("status", true);
cur_frm.toggle_enable("status", false); } else {
frm.set_intro(__("This Leave Application is pending approval. Only the Leave Approver can update status."))
frm.toggle_enable("status", false);
}
} }
} }
} },
}
cur_frm.cscript.employee = function (doc, dt, dn){ leave_approver: function(frm) {
cur_frm.cscript.get_leave_balance(doc, dt, dn); frm.set_value("leave_approver_name", frappe.user.full_name(frm.doc.leave_approver));
} },
cur_frm.cscript.fiscal_year = function (doc, dt, dn){ employee: function(frm) {
cur_frm.cscript.get_leave_balance(doc, dt, dn); frm.trigger("get_leave_balance");
} },
cur_frm.cscript.leave_type = function (doc, dt, dn){ fiscal_year: function(frm) {
cur_frm.cscript.get_leave_balance(doc, dt, dn); frm.trigger("get_leave_balance");
} },
cur_frm.cscript.half_day = function(doc, dt, dn) { leave_type: function(frm) {
if(doc.from_date) { frm.trigger("get_leave_balance");
set_multiple(dt,dn,{to_date:doc.from_date}); },
cur_frm.cscript.calculate_total_days(doc, dt, dn);
}
}
cur_frm.cscript.from_date = function(doc, dt, dn) { half_day: function(frm) {
if(cint(doc.half_day) == 1){ if (frm.doc.from_date) {
set_multiple(dt,dn,{to_date:doc.from_date}); frm.set_value("to_date", frm.doc.from_date);
} frm.trigger("calculate_total_days");
cur_frm.cscript.calculate_total_days(doc, dt, dn); }
} },
cur_frm.cscript.to_date = function(doc, dt, dn) { from_date: function(frm) {
if(cint(doc.half_day) == 1 && cstr(doc.from_date) && doc.from_date != doc.to_date){ if (cint(frm.doc.half_day)==1) {
msgprint(__("To Date should be same as From Date for Half Day leave")); frm.set_value("to_date", frm.doc.from_date);
set_multiple(dt,dn,{to_date:doc.from_date}); }
} frm.trigger("calculate_total_days");
cur_frm.cscript.calculate_total_days(doc, dt, dn); },
}
cur_frm.cscript.get_leave_balance = function(doc, dt, dn) { to_date: function(frm) {
if(doc.docstatus==0 && doc.employee && doc.leave_type && doc.fiscal_year) { if (cint(frm.doc.half_day)==1 && cstr(frm.doc.from_date) && frm.doc.from_date != frm.doc.to_date) {
return cur_frm.call({ msgprint(__("To Date should be same as From Date for Half Day leave"));
method: "get_leave_balance", frm.set_value("to_date", frm.doc.from_date);
args: { }
employee: doc.employee,
fiscal_year: doc.fiscal_year,
leave_type: doc.leave_type
}
});
}
}
cur_frm.cscript.calculate_total_days = function(doc, dt, dn) { frm.trigger("calculate_total_days");
if(doc.from_date && doc.to_date){ },
if(cint(doc.half_day) == 1) set_multiple(dt,dn,{total_leave_days:0.5});
else{ get_leave_balance: function(frm) {
// server call is done to include holidays in leave days calculations if(frm.doc.docstatus==0 && frm.doc.employee && frm.doc.leave_type && frm.doc.fiscal_year) {
return frappe.call({ return frm.call({
method: 'erpnext.hr.doctype.leave_application.leave_application.get_total_leave_days', method: "get_leave_balance",
args: {leave_app: doc}, args: {
callback: function(response) { employee: frm.doc.employee,
if (response && response.message) { fiscal_year: frm.doc.fiscal_year,
cur_frm.set_value('total_leave_days', response.message.total_leave_days); leave_type: frm.doc.leave_type
}
} }
}); });
} }
} },
}
cur_frm.fields_dict.employee.get_query = erpnext.queries.employee; calculate_total_days: function(frm) {
if(frm.doc.from_date && frm.doc.to_date) {
if (cint(frm.doc.half_day)==1) {
frm.set_value("total_leave_days", 0.5);
} else {
// server call is done to include holidays in leave days calculations
return frappe.call({
method: 'erpnext.hr.doctype.leave_application.leave_application.get_total_leave_days',
args: { leave_app: frm.doc },
callback: function(response) {
if (response && response.message) {
frm.set_value('total_leave_days', response.message.total_leave_days);
}
}
});
}
}
},
});

View File

@ -224,8 +224,7 @@ erpnext.patches.v6_4.email_digest_update
execute:frappe.delete_doc_if_exists("DocType", "Applicable Territory") execute:frappe.delete_doc_if_exists("DocType", "Applicable Territory")
execute:frappe.delete_doc_if_exists("DocType", "Shopping Cart Price List") execute:frappe.delete_doc_if_exists("DocType", "Shopping Cart Price List")
execute:frappe.delete_doc_if_exists("DocType", "Shopping Cart Taxes and Charges Master") execute:frappe.delete_doc_if_exists("DocType", "Shopping Cart Taxes and Charges Master")
erpnext.patches.v6_4.set_user_in_contact erpnext.patches.v6_4.set_user_in_contact
erpnext.patches.v6_4.make_image_thumbnail erpnext.patches.v6_4.make_image_thumbnail #2015-10-20
erpnext.patches.v6_5.show_in_website_for_template_item erpnext.patches.v6_5.show_in_website_for_template_item
erpnext.patches.v6_4.fix_expense_included_in_valuation

View File

@ -0,0 +1,64 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
from frappe.utils import cstr
def execute():
for company in frappe.db.sql("select name, expenses_included_in_valuation from tabCompany", as_dict=1):
frozen_date = get_frozen_date(company.name, company.expenses_included_in_valuation)
# Purchase Invoices after frozen date
# which are not against Receipt, but valuation related tax is there
pi_list = frappe.db.sql("""
select distinct pi.name
from `tabPurchase Invoice` pi, `tabPurchase Invoice Item` pi_item
where
pi.name = pi_item.parent
and pi.company = %s
and pi.posting_date > %s
and pi.docstatus = 1
and pi.is_opening = 'No'
and (pi_item.item_tax_amount is not null and pi_item.item_tax_amount > 0)
and (pi_item.purchase_receipt is null or pi_item.purchase_receipt = '')
and (pi_item.item_code is not null and pi_item.item_code != '')
and exists(select name from `tabItem` where name=pi_item.item_code and is_stock_item=1)
""", (company.name, frozen_date), as_dict=1)
for pi in pi_list:
# Check whether gle exists for Expenses Included in Valuation account against the PI
gle_for_expenses_included_in_valuation = frappe.db.sql("""select name from `tabGL Entry`
where voucher_type='Purchase Invoice' and voucher_no=%s and account=%s""",
(pi.name, company.expenses_included_in_valuation))
if gle_for_expenses_included_in_valuation:
frappe.db.sql("""delete from `tabGL Entry`
where voucher_type='Purchase Invoice' and voucher_no=%s""", pi.name)
purchase_invoice = frappe.get_doc("Purchase Invoice", pi.name)
purchase_invoice.make_gl_entries()
print pi.name
def get_frozen_date(company, account):
# Accounting frozen upto
accounts_frozen_upto = frappe.db.get_single_value("Accounts Settings", "acc_frozen_upto")
# Last adjustment entry to correct Expenses Included in Valuation account balance
last_adjustment_entry = frappe.db.sql("""select posting_date from `tabGL Entry`
where account=%s and company=%s and voucher_type = 'Journal Entry'
order by posting_date desc limit 1""", (account, company))
last_adjustment_date = cstr(last_adjustment_entry[0][0]) if last_adjustment_entry else None
# Last period closing voucher
last_closing_entry = frappe.db.sql("""select posting_date from `tabGL Entry`
where company=%s and voucher_type = 'Period Closing Voucher'
order by posting_date desc limit 1""", company)
last_closing_date = cstr(last_closing_entry[0][0]) if last_closing_entry else None
frozen_date = max([accounts_frozen_upto, last_adjustment_date, last_closing_date])
return frozen_date or '1900-01-01'

View File

@ -12,6 +12,12 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
var today = get_today(), var today = get_today(),
currency = frappe.defaults.get_user_default("currency"); currency = frappe.defaults.get_user_default("currency");
$.each(["posting_date", "transaction_date"], function(i, fieldname) {
if (me.frm.fields_dict[fieldname] && !me.frm.doc[fieldname] && me.frm[fieldname]) {
me.frm.set_value(fieldname, me.frm[fieldname]);
}
});
$.each({ $.each({
posting_date: today, posting_date: today,
transaction_date: today, transaction_date: today,
@ -277,12 +283,18 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
}, },
transaction_date: function() { transaction_date: function() {
if (this.frm.doc.transaction_date) {
this.frm.transaction_date = this.frm.doc.transaction_date;
}
erpnext.get_fiscal_year(this.frm.doc.company, this.frm.doc.transaction_date); erpnext.get_fiscal_year(this.frm.doc.company, this.frm.doc.transaction_date);
}, },
posting_date: function() { posting_date: function() {
var me = this; var me = this;
if (this.frm.doc.posting_date) { if (this.frm.doc.posting_date) {
this.frm.posting_date = this.frm.doc.posting_date;
if ((this.frm.doc.doctype == "Sales Invoice" && this.frm.doc.customer) || if ((this.frm.doc.doctype == "Sales Invoice" && this.frm.doc.customer) ||
(this.frm.doc.doctype == "Purchase Invoice" && this.frm.doc.supplier)) { (this.frm.doc.doctype == "Purchase Invoice" && this.frm.doc.supplier)) {
return frappe.call({ return frappe.call({

View File

@ -50,14 +50,6 @@ class InstallationNote(TransactionBase):
if not frappe.db.exists("Serial No", x): if not frappe.db.exists("Serial No", x):
frappe.throw(_("Serial No {0} does not exist").format(x)) frappe.throw(_("Serial No {0} does not exist").format(x))
def is_serial_no_installed(self,cur_s_no,item_code):
for x in cur_s_no:
status = frappe.db.sql("select status from `tabSerial No` where name = %s", x)
status = status and status[0][0] or ''
if status == 'Installed':
frappe.throw(_("Item {0} with Serial No {1} is already installed").format(item_code, x))
def get_prevdoc_serial_no(self, prevdoc_detail_docname): def get_prevdoc_serial_no(self, prevdoc_detail_docname):
serial_nos = frappe.db.get_value("Delivery Note Item", serial_nos = frappe.db.get_value("Delivery Note Item",
prevdoc_detail_docname, "serial_no") prevdoc_detail_docname, "serial_no")
@ -80,7 +72,6 @@ class InstallationNote(TransactionBase):
if prevdoc_s_no: if prevdoc_s_no:
self.is_serial_no_match(sr_list, prevdoc_s_no, d.prevdoc_docname) self.is_serial_no_match(sr_list, prevdoc_s_no, d.prevdoc_docname)
self.is_serial_no_installed(sr_list, d.item_code)
def validate_installation_date(self): def validate_installation_date(self):
for d in self.get('items'): for d in self.get('items'):
@ -102,11 +93,5 @@ class InstallationNote(TransactionBase):
frappe.db.set(self, 'status', 'Submitted') frappe.db.set(self, 'status', 'Submitted')
def on_cancel(self): def on_cancel(self):
for d in self.get('items'):
if d.serial_no:
d.serial_no = d.serial_no.replace(",", "\n")
for sr_no in d.serial_no.split("\n"):
frappe.db.set_value("Serial No", sr_no, "status", "Delivered")
self.update_prevdoc_status() self.update_prevdoc_status()
frappe.db.set(self, 'status', 'Cancelled') frappe.db.set(self, 'status', 'Cancelled')

View File

@ -168,7 +168,7 @@ class EmailDigest(Document):
for key in ("income", "expenses_booked", "income_year_to_date", "expense_year_to_date", for key in ("income", "expenses_booked", "income_year_to_date", "expense_year_to_date",
"invoiced_amount", "payables", "bank_balance"): "invoiced_amount", "payables", "bank_balance"):
if self.get(key): if self.get(key):
cache_key = "email_digest:card:" + key cache_key = "email_digest:card:{0}:{1}".format(self.company, key)
card = cache.get(cache_key) card = cache.get(cache_key)
if card: if card:

View File

@ -292,7 +292,7 @@ def get_customer(user=None):
"customer_group": get_shopping_cart_settings().default_customer_group, "customer_group": get_shopping_cart_settings().default_customer_group,
"territory": get_root_of("Territory") "territory": get_root_of("Territory")
}) })
customer.ignore_mandatory = True customer.flags.ignore_mandatory = True
customer.insert(ignore_permissions=True) customer.insert(ignore_permissions=True)
contact = frappe.new_doc("Contact") contact = frappe.new_doc("Contact")
@ -301,7 +301,7 @@ def get_customer(user=None):
"first_name": fullname, "first_name": fullname,
"email_id": user "email_id": user
}) })
contact.ignore_mandatory = True contact.flags.ignore_mandatory = True
contact.insert(ignore_permissions=True) contact.insert(ignore_permissions=True)
return customer return customer

View File

@ -98,6 +98,8 @@ class Item(WebsiteGenerator):
}) })
except frappe.DoesNotExistError: except frappe.DoesNotExistError:
pass pass
# cleanup
frappe.local.message_log.pop()
# for CSV import # for CSV import
if not file_doc: if not file_doc:
@ -142,20 +144,21 @@ class Item(WebsiteGenerator):
filters={"variant_of": self.name, "show_in_website": 1}, order_by="name asc") filters={"variant_of": self.name, "show_in_website": 1}, order_by="name asc")
variant = frappe.form_dict.variant variant = frappe.form_dict.variant
if not variant: if not variant and context.variants:
# the case when the item is opened for the first time from its list # the case when the item is opened for the first time from its list
variant = context.variants[0] variant = context.variants[0]
context.variant = frappe.get_doc("Item", variant) if variant:
context.variant = frappe.get_doc("Item", variant)
for fieldname in ("website_image", "web_long_description", "description", for fieldname in ("website_image", "web_long_description", "description",
"website_specifications"): "website_specifications"):
if context.variant.get(fieldname): if context.variant.get(fieldname):
value = context.variant.get(fieldname) value = context.variant.get(fieldname)
if isinstance(value, list): if isinstance(value, list):
value = [d.as_dict() for d in value] value = [d.as_dict() for d in value]
context[fieldname] = value context[fieldname] = value
if self.slideshow: if self.slideshow:
if context.variant and context.variant.slideshow: if context.variant and context.variant.slideshow:
@ -410,10 +413,11 @@ class Item(WebsiteGenerator):
if not template_item.show_in_website: if not template_item.show_in_website:
template_item.show_in_website = 1 template_item.show_in_website = 1
template_item.flags.ignore_permissions = True template_item.flags.ignore_permissions = True
template_item.flags.dont_update_variants = True
template_item.save() template_item.save()
def update_variants(self): def update_variants(self):
if self.has_variants: if self.has_variants and not self.flags.dont_update_variants:
updated = [] updated = []
variants = frappe.db.get_all("Item", fields=["item_code"], filters={"variant_of": self.name }) variants = frappe.db.get_all("Item", fields=["item_code"], filters={"variant_of": self.name })
for d in variants: for d in variants:

View File

@ -325,7 +325,7 @@ def get_pos_profile(company):
def get_serial_nos_by_fifo(args, item_doc): def get_serial_nos_by_fifo(args, item_doc):
if frappe.db.get_single_value("Stock Settings", "automatically_set_serial_nos_based_on_fifo"): if frappe.db.get_single_value("Stock Settings", "automatically_set_serial_nos_based_on_fifo"):
return "\n".join(frappe.db.sql_list("""select name from `tabSerial No` return "\n".join(frappe.db.sql_list("""select name from `tabSerial No`
where item_code=%(item_code)s and warehouse=%(warehouse)s and status='Available' where item_code=%(item_code)s and warehouse=%(warehouse)s
order by timestamp(purchase_date, purchase_time) asc limit %(qty)s""", { order by timestamp(purchase_date, purchase_time) asc limit %(qty)s""", {
"item_code": args.item_code, "item_code": args.item_code,
"warehouse": args.warehouse, "warehouse": args.warehouse,

View File

@ -32,8 +32,8 @@ def get_columns(filters):
"""return columns based on filters""" """return columns based on filters"""
columns = [_("Item") + ":Link/Item:100"] + [_("Item Name") + "::150"] + [_("Description") + "::150"] + \ columns = [_("Item") + ":Link/Item:100"] + [_("Item Name") + "::150"] + [_("Description") + "::150"] + \
[_("Warehouse") + ":Link/Warehouse:100"] + [_("Batch") + ":Link/Batch:100"] + [_("Opening Qty") + "::90"] + \ [_("Warehouse") + ":Link/Warehouse:100"] + [_("Batch") + ":Link/Batch:100"] + [_("Opening Qty") + ":Float:90"] + \
[_("In Qty") + "::80"] + [_("Out Qty") + "::80"] + [_("Balance Qty") + "::90"] [_("In Qty") + ":Float:80"] + [_("Out Qty") + ":Float:80"] + [_("Balance Qty") + ":Float:90"]
return columns return columns

View File

@ -1,12 +1,14 @@
{ {
"add_total_row": 0,
"apply_user_permissions": 1, "apply_user_permissions": 1,
"creation": "2013-01-14 10:52:58", "creation": "2013-01-14 10:52:58",
"disabled": 0,
"docstatus": 0, "docstatus": 0,
"doctype": "Report", "doctype": "Report",
"idx": 1, "idx": 1,
"is_standard": "Yes", "is_standard": "Yes",
"json": "{\"filters\":[[\"Serial No\",\"status\",\"=\",\"Delivered\"]],\"columns\":[[\"name\",\"Serial No\"],[\"item_code\",\"Serial No\"],[\"amc_expiry_date\",\"Serial No\"],[\"maintenance_status\",\"Serial No\"],[\"delivery_document_no\",\"Serial No\"],[\"customer\",\"Serial No\"],[\"customer_name\",\"Serial No\"],[\"item_name\",\"Serial No\"],[\"description\",\"Serial No\"],[\"item_group\",\"Serial No\"],[\"brand\",\"Serial No\"]],\"sort_by\":\"Serial No.amc_expiry_date\",\"sort_order\":\"asc\",\"sort_by_next\":\"\",\"sort_order_next\":\"desc\"}", "json": "{\"filters\":[[\"Serial No\",\"delivery_document_type\",\"in\",[\"Delivery Note\",\"Sales Invoice\"]],[\"Serial No\",\"warehouse\",\"=\",\"\"]],\"columns\":[[\"name\",\"Serial No\"],[\"item_code\",\"Serial No\"],[\"amc_expiry_date\",\"Serial No\"],[\"maintenance_status\",\"Serial No\"],[\"delivery_document_no\",\"Serial No\"],[\"customer\",\"Serial No\"],[\"customer_name\",\"Serial No\"],[\"item_name\",\"Serial No\"],[\"description\",\"Serial No\"],[\"item_group\",\"Serial No\"],[\"brand\",\"Serial No\"]],\"sort_by\":\"Serial No.modified\",\"sort_order\":\"desc\",\"sort_by_next\":null,\"sort_order_next\":\"desc\"}",
"modified": "2014-06-03 07:18:17.322563", "modified": "2015-10-22 14:53:45.192497",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Serial No Service Contract Expiry", "name": "Serial No Service Contract Expiry",

View File

@ -7,8 +7,8 @@
"doctype": "Report", "doctype": "Report",
"idx": 1, "idx": 1,
"is_standard": "Yes", "is_standard": "Yes",
"json": "{\"filters\":[],\"columns\":[[\"name\",\"Serial No\"],[\"item_code\",\"Serial No\"],[\"warehouse\",\"Serial No\"],[\"status\",\"Serial No\"],[\"item_name\",\"Serial No\"],[\"description\",\"Serial No\"],[\"item_group\",\"Serial No\"],[\"brand\",\"Serial No\"],[\"purchase_document_no\",\"Serial No\"],[\"purchase_date\",\"Serial No\"],[\"customer\",\"Serial No\"],[\"customer_name\",\"Serial No\"],[\"purchase_rate\",\"Serial No\"],[\"delivery_document_no\",\"Serial No\"],[\"delivery_date\",\"Serial No\"],[\"supplier\",\"Serial No\"],[\"supplier_name\",\"Serial No\"]],\"sort_by\":\"Serial No.name\",\"sort_order\":\"desc\",\"sort_by_next\":null,\"sort_order_next\":\"desc\"}", "json": "{\"filters\":[],\"columns\":[[\"name\",\"Serial No\"],[\"item_code\",\"Serial No\"],[\"warehouse\",\"Serial No\"],[\"item_name\",\"Serial No\"],[\"description\",\"Serial No\"],[\"item_group\",\"Serial No\"],[\"brand\",\"Serial No\"],[\"purchase_document_no\",\"Serial No\"],[\"purchase_date\",\"Serial No\"],[\"customer\",\"Serial No\"],[\"customer_name\",\"Serial No\"],[\"purchase_rate\",\"Serial No\"],[\"delivery_document_no\",\"Serial No\"],[\"delivery_date\",\"Serial No\"],[\"supplier\",\"Serial No\"],[\"supplier_name\",\"Serial No\"]],\"sort_by\":\"Serial No.name\",\"sort_order\":\"desc\",\"sort_by_next\":null,\"sort_order_next\":\"desc\"}",
"modified": "2015-09-20 21:09:49.441973", "modified": "2015-10-22 14:49:29.491790",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Serial No Status", "name": "Serial No Status",

View File

@ -1,12 +1,14 @@
{ {
"add_total_row": 0,
"apply_user_permissions": 1, "apply_user_permissions": 1,
"creation": "2013-01-14 10:52:58", "creation": "2013-01-14 10:52:58",
"disabled": 0,
"docstatus": 0, "docstatus": 0,
"doctype": "Report", "doctype": "Report",
"idx": 1, "idx": 1,
"is_standard": "Yes", "is_standard": "Yes",
"json": "{\"filters\":[[\"Serial No\",\"status\",\"=\",\"Delivered\"]],\"columns\":[[\"name\",\"Serial No\"],[\"item_code\",\"Serial No\"],[\"warranty_expiry_date\",\"Serial No\"],[\"warranty_period\",\"Serial No\"],[\"maintenance_status\",\"Serial No\"],[\"purchase_document_no\",\"Serial No\"],[\"purchase_date\",\"Serial No\"],[\"supplier\",\"Serial No\"],[\"supplier_name\",\"Serial No\"],[\"delivery_document_no\",\"Serial No\"],[\"delivery_date\",\"Serial No\"],[\"customer\",\"Serial No\"],[\"customer_name\",\"Serial No\"],[\"item_name\",\"Serial No\"],[\"description\",\"Serial No\"],[\"item_group\",\"Serial No\"],[\"brand\",\"Serial No\"]],\"sort_by\":\"Serial No.warranty_expiry_date\",\"sort_order\":\"asc\",\"sort_by_next\":\"\",\"sort_order_next\":\"asc\"}", "json": "{\"filters\":[[\"Serial No\",\"delivery_document_type\",\"in\",[\"Delivery Note\",\"Sales Invoice\"]],[\"Serial No\",\"warehouse\",\"=\",\"\"]],\"columns\":[[\"name\",\"Serial No\"],[\"item_code\",\"Serial No\"],[\"warranty_expiry_date\",\"Serial No\"],[\"warranty_period\",\"Serial No\"],[\"maintenance_status\",\"Serial No\"],[\"purchase_document_no\",\"Serial No\"],[\"purchase_date\",\"Serial No\"],[\"supplier\",\"Serial No\"],[\"supplier_name\",\"Serial No\"],[\"delivery_document_no\",\"Serial No\"],[\"delivery_date\",\"Serial No\"],[\"customer\",\"Serial No\"],[\"customer_name\",\"Serial No\"],[\"item_name\",\"Serial No\"],[\"description\",\"Serial No\"],[\"item_group\",\"Serial No\"],[\"brand\",\"Serial No\"]],\"sort_by\":\"Serial No.modified\",\"sort_order\":\"desc\",\"sort_by_next\":null,\"sort_order_next\":\"desc\"}",
"modified": "2014-06-03 07:18:17.332902", "modified": "2015-10-22 14:53:12.575608",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Serial No Warranty Expiry", "name": "Serial No Warranty Expiry",

View File

@ -164,7 +164,7 @@ def set_stock_balance_as_per_serial_no(item_code=None, posting_date=None, postin
for d in bin: for d in bin:
serial_nos = frappe.db.sql("""select count(name) from `tabSerial No` serial_nos = frappe.db.sql("""select count(name) from `tabSerial No`
where item_code=%s and warehouse=%s and status = 'Available' and docstatus < 2""", (d[0], d[1])) where item_code=%s and warehouse=%s and docstatus < 2""", (d[0], d[1]))
if serial_nos and flt(serial_nos[0][0]) != flt(d[2]): if serial_nos and flt(serial_nos[0][0]) != flt(d[2]):
print d[0], d[1], d[2], serial_nos[0][0] print d[0], d[1], d[2], serial_nos[0][0]

View File

@ -182,7 +182,7 @@ class MaintenanceSchedule(TransactionBase):
def validate_serial_no(self, serial_nos, amc_start_date): def validate_serial_no(self, serial_nos, amc_start_date):
for serial_no in serial_nos: for serial_no in serial_nos:
sr_details = frappe.db.get_value("Serial No", serial_no, sr_details = frappe.db.get_value("Serial No", serial_no,
["warranty_expiry_date", "amc_expiry_date", "status", "delivery_date"], as_dict=1) ["warranty_expiry_date", "amc_expiry_date", "warehouse", "delivery_date"], as_dict=1)
if not sr_details: if not sr_details:
frappe.throw(_("Serial No {0} not found").format(serial_no)) frappe.throw(_("Serial No {0} not found").format(serial_no))
@ -193,9 +193,10 @@ class MaintenanceSchedule(TransactionBase):
if sr_details.amc_expiry_date and sr_details.amc_expiry_date >= amc_start_date: if sr_details.amc_expiry_date and sr_details.amc_expiry_date >= amc_start_date:
throw(_("Serial No {0} is under maintenance contract upto {1}").format(serial_no, sr_details.amc_start_date)) throw(_("Serial No {0} is under maintenance contract upto {1}").format(serial_no, sr_details.amc_start_date))
if sr_details.status=="Delivered" and sr_details.delivery_date and \ if not sr_details.warehouse and sr_details.delivery_date and \
sr_details.delivery_date >= amc_start_date: sr_details.delivery_date >= amc_start_date:
throw(_("Maintenance start date can not be before delivery date for Serial No {0}").format(serial_no)) throw(_("Maintenance start date can not be before delivery date for Serial No {0}")
.format(serial_no))
def validate_schedule(self): def validate_schedule(self):
item_lst1 =[] item_lst1 =[]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

3885
erpnext/translations/uk.csv Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -21,7 +21,7 @@ frappe.ui.form.on("Rename Tool", {
select_doctype: frm.doc.select_doctype select_doctype: frm.doc.select_doctype
}, },
callback: function(r) { callback: function(r) {
frm.get_field("rename_log").$wrapper.html(r.message); frm.get_field("rename_log").$wrapper.html(r.message.join("<br>"));
} }
}); });
}); });

View File

@ -5,9 +5,9 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe import _
from frappe.model.document import Document from frappe.model.document import Document
from frappe.model.rename_doc import bulk_rename
class RenameTool(Document): class RenameTool(Document):
pass pass
@ -20,37 +20,13 @@ def get_doctypes():
@frappe.whitelist() @frappe.whitelist()
def upload(select_doctype=None, rows=None): def upload(select_doctype=None, rows=None):
from frappe.utils.csvutils import read_csv_content_from_attached_file from frappe.utils.csvutils import read_csv_content_from_attached_file
from frappe.model.rename_doc import rename_doc
if not select_doctype: if not select_doctype:
select_doctype = frappe.form_dict.select_doctype select_doctype = frappe.form_dict.select_doctype
if not frappe.has_permission(select_doctype, "write"): if not frappe.has_permission(select_doctype, "write"):
raise frappe.PermissionError raise frappe.PermissionError
if not rows: rows = read_csv_content_from_attached_file(frappe.get_doc("Rename Tool", "Rename Tool"))
rows = read_csv_content_from_attached_file(frappe.get_doc("Rename Tool", "Rename Tool"))
if not rows:
frappe.throw(_("Please select a valid csv file with data"))
max_rows = 500 return bulk_rename(select_doctype, rows=rows)
if len(rows) > max_rows:
frappe.throw(_("Maximum {0} rows allowed").format(max_rows))
rename_log = []
for row in rows:
# if row has some content
if len(row) > 1 and row[0] and row[1]:
try:
if rename_doc(select_doctype, row[0], row[1]):
rename_log.append(_("Successful: ") + row[0] + " -> " + row[1])
frappe.db.commit()
else:
rename_log.append(_("Ignored: ") + row[0] + " -> " + row[1])
except Exception, e:
rename_log.append("<span style='color: RED'>" + \
_("Failed: ") + row[0] + " -> " + row[1] + "</span>")
rename_log.append("<span style='margin-left: 20px;'>" + repr(e) + "</span>")
frappe.db.rollback()
return rename_log

View File

@ -1,6 +1,6 @@
from setuptools import setup, find_packages from setuptools import setup, find_packages
version = "6.5.3" version = "6.6.0"
with open("requirements.txt", "r") as f: with open("requirements.txt", "r") as f:
install_requires = f.readlines() install_requires = f.readlines()