Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
13bd538aca | ||
|
|
d72a24965b | ||
|
|
dc633fe360 | ||
|
|
39046d663d | ||
|
|
6b01abe9ad | ||
|
|
87edd86854 | ||
|
|
e37dd77923 | ||
|
|
e4f689184f | ||
|
|
85f825e98c | ||
|
|
89592c5180 | ||
|
|
587bd144d5 | ||
|
|
1f048b2426 | ||
|
|
1792ff3be7 | ||
|
|
fc595064e0 | ||
|
|
804b4acb9b | ||
|
|
5c7557914b | ||
|
|
381a9377d9 | ||
|
|
9bdd1aa1ed | ||
|
|
d0df28bfa0 | ||
|
|
1966225450 | ||
|
|
4cee27eec0 | ||
|
|
c7d4eaee79 | ||
|
|
43c1a9b502 | ||
|
|
b937fac3ce | ||
|
|
53d94996ad | ||
|
|
26f6752c1e | ||
|
|
bb429745c0 | ||
|
|
909f0c38f1 | ||
|
|
a790ba05f4 | ||
|
|
11fc4f85d0 | ||
|
|
17452a1695 | ||
|
|
7c3d48e353 | ||
|
|
5d288e407c | ||
|
|
f64fae752f | ||
|
|
82763f052f | ||
|
|
bafc73568a | ||
|
|
d015195617 | ||
|
|
b2f550ccb3 | ||
|
|
41413af42d | ||
|
|
ec60ebde6f |
@@ -1,2 +1,2 @@
|
||||
from __future__ import unicode_literals
|
||||
__version__ = '5.0.19'
|
||||
__version__ = '5.0.23'
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
"permlevel": 0,
|
||||
"read_only": 1,
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
"search_index": 0
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
@@ -44,7 +44,7 @@
|
||||
"label": "Is Group",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"search_index": 1
|
||||
"search_index": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "company",
|
||||
@@ -57,7 +57,7 @@
|
||||
"permlevel": 0,
|
||||
"read_only": 1,
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
"search_index": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "root_type",
|
||||
@@ -147,7 +147,8 @@
|
||||
"label": "Lft",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "rgt",
|
||||
@@ -156,7 +157,8 @@
|
||||
"label": "Rgt",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "old_parent",
|
||||
@@ -171,7 +173,7 @@
|
||||
"icon": "icon-money",
|
||||
"idx": 1,
|
||||
"in_create": 0,
|
||||
"modified": "2015-05-28 14:10:40.606010",
|
||||
"modified": "2015-06-14 20:57:55.471334",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Account",
|
||||
|
||||
@@ -4,6 +4,13 @@
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "check_supplier_invoice_uniqueness",
|
||||
"fieldtype": "Check",
|
||||
"label": "Check Supplier Invoice Number Uniqueness",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"description": "If enabled, the system will post accounting entries for inventory automatically.",
|
||||
@@ -43,7 +50,7 @@
|
||||
"icon": "icon-cog",
|
||||
"idx": 1,
|
||||
"issingle": 1,
|
||||
"modified": "2015-02-05 05:11:34.163902",
|
||||
"modified": "2015-06-11 06:06:34.047890",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Accounts Settings",
|
||||
|
||||
@@ -54,7 +54,7 @@ class CForm(Document):
|
||||
frappe.throw(_("Please enter atleast 1 invoice in the table"))
|
||||
|
||||
def set_total_invoiced_amount(self):
|
||||
total = sum([flt(d.base_grand_total) for d in self.get('invoices')])
|
||||
total = sum([flt(d.grand_total) for d in self.get('invoices')])
|
||||
frappe.db.set(self, 'total_invoiced_amount', total)
|
||||
|
||||
def get_invoice_details(self, invoice_no):
|
||||
|
||||
@@ -48,7 +48,8 @@
|
||||
"fieldtype": "Dynamic Link",
|
||||
"label": "Party",
|
||||
"options": "party_type",
|
||||
"permlevel": 0
|
||||
"permlevel": 0,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "cost_center",
|
||||
@@ -192,7 +193,7 @@
|
||||
"icon": "icon-list",
|
||||
"idx": 1,
|
||||
"in_create": 1,
|
||||
"modified": "2015-04-27 20:32:48.246818",
|
||||
"modified": "2015-06-14 20:57:19.800276",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "GL Entry",
|
||||
|
||||
@@ -458,11 +458,11 @@ def get_default_bank_cash_account(company, voucher_type, mode_of_payment=None):
|
||||
if voucher_type=="Bank Entry":
|
||||
account = frappe.db.get_value("Company", company, "default_bank_account")
|
||||
if not account:
|
||||
account = frappe.db.get_value("Account", {"company": company, "account_type": "Bank"})
|
||||
account = frappe.db.get_value("Account", {"company": company, "account_type": "Bank", "is_group": 0})
|
||||
elif voucher_type=="Cash Entry":
|
||||
account = frappe.db.get_value("Company", company, "default_cash_account")
|
||||
if not account:
|
||||
account = frappe.db.get_value("Account", {"company": company, "account_type": "Cash"})
|
||||
account = frappe.db.get_value("Account", {"company": company, "account_type": "Cash", "is_group": 0})
|
||||
|
||||
if account:
|
||||
return {
|
||||
@@ -538,15 +538,13 @@ def get_opening_accounts(company):
|
||||
|
||||
|
||||
def get_against_jv(doctype, txt, searchfield, start, page_len, filters):
|
||||
if not filters.get("party"):
|
||||
return []
|
||||
return frappe.db.sql("""select jv.name, jv.posting_date, jv.user_remark
|
||||
from `tabJournal Entry` jv, `tabJournal Entry Account` jv_detail
|
||||
where jv_detail.parent = jv.name and jv_detail.account = %s and jv_detail.party = %s
|
||||
where jv_detail.parent = jv.name and jv_detail.account = %s and ifnull(jv_detail.party, '') = %s
|
||||
and (ifnull(jv_detail.against_invoice, '') = '' and ifnull(jv_detail.against_voucher, '') = ''
|
||||
and ifnull(jv_detail.against_jv, '') = '' )
|
||||
and jv.docstatus = 1 and jv.{0} like %s order by jv.name desc limit %s, %s""".format(searchfield),
|
||||
(filters["account"], filters["party"], "%{0}%".format(txt), start, page_len))
|
||||
(filters.get("account"), cstr(filters.get("party")), "%{0}%".format(txt), start, page_len))
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_outstanding(args):
|
||||
|
||||
@@ -39,6 +39,7 @@ class PurchaseInvoice(BuyingController):
|
||||
|
||||
self.po_required()
|
||||
self.pr_required()
|
||||
self.validate_supplier_invoice()
|
||||
self.check_active_purchase_items()
|
||||
self.check_conversion_rate()
|
||||
self.validate_credit_to_acc()
|
||||
@@ -385,6 +386,16 @@ class PurchaseInvoice(BuyingController):
|
||||
project.update_purchase_costing()
|
||||
project.save()
|
||||
project_list.append(d.project_name)
|
||||
|
||||
def validate_supplier_invoice(self):
|
||||
if self.bill_date:
|
||||
if self.bill_date > self.posting_date:
|
||||
frappe.throw("Supplier Invoice Date cannot be greater than Posting Date")
|
||||
if self.bill_no:
|
||||
if cint(frappe.db.get_single_value("Accounts Settings", "check_supplier_invoice_uniqueness")):
|
||||
pi = frappe.db.exists("Purchase Invoice", {"bill_no": self.bill_no, "fiscal_year": self.fiscal_year})
|
||||
if pi:
|
||||
frappe.throw("Supplier Invoice No exists in Purchase Invoice {0}".format(pi))
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_expense_account(doctype, txt, searchfield, start, page_len, filters):
|
||||
|
||||
@@ -7,6 +7,7 @@ import frappe
|
||||
@frappe.whitelist()
|
||||
def get_items(price_list, sales_or_purchase, item=None):
|
||||
condition = ""
|
||||
order_by = ""
|
||||
args = {"price_list": price_list}
|
||||
|
||||
if sales_or_purchase == "Sales":
|
||||
@@ -30,16 +31,25 @@ def get_items(price_list, sales_or_purchase, item=None):
|
||||
item_code[0]["barcode"] = item
|
||||
return item_code
|
||||
|
||||
condition += " and (CONCAT(i.name, i.item_name) like %(name)s or (i.variant_of like %(name)s))"
|
||||
condition += " and ((CONCAT(i.name, i.item_name) like %(name)s) or (i.variant_of like %(name)s) or (i.item_group like %(name)s))"
|
||||
order_by = """if(locate(%(_name)s, i.name), locate(%(_name)s, i.name), 99999),
|
||||
if(locate(%(_name)s, i.item_name), locate(%(_name)s, i.item_name), 99999),
|
||||
if(locate(%(_name)s, i.variant_of), locate(%(_name)s, i.variant_of), 99999),
|
||||
if(locate(%(_name)s, i.item_group), locate(%(_name)s, i.item_group), 99999),"""
|
||||
args["name"] = "%%%s%%" % item
|
||||
args["_name"] = item.replace("%", "")
|
||||
|
||||
# locate function is used to sort by closest match from the beginning of the value
|
||||
return frappe.db.sql("""select i.name, i.item_name, i.image,
|
||||
item_det.price_list_rate, item_det.currency
|
||||
from `tabItem` i LEFT JOIN
|
||||
(select item_code, price_list_rate, currency from
|
||||
`tabItem Price` where price_list=%s) item_det
|
||||
`tabItem Price` where price_list=%(price_list)s) item_det
|
||||
ON
|
||||
(item_det.item_code=i.name or item_det.item_code=i.variant_of)
|
||||
where
|
||||
ifnull(i.has_variants, 0) = 0 and
|
||||
%s""" % ('%(price_list)s', condition), args, as_dict=1)
|
||||
{condition}
|
||||
order by
|
||||
{order_by}
|
||||
i.name""".format(condition=condition, order_by=order_by), args, as_dict=1)
|
||||
|
||||
@@ -51,7 +51,7 @@ class ReceivablePayableReport(object):
|
||||
currency_precision = get_currency_precision() or 2
|
||||
dr_or_cr = "debit" if args.get("party_type") == "Customer" else "credit"
|
||||
|
||||
voucher_details = self.get_voucher_details()
|
||||
voucher_details = self.get_voucher_details(args.get("party_type"))
|
||||
|
||||
future_vouchers = self.get_entries_after(self.filters.report_date, args.get("party_type"))
|
||||
|
||||
@@ -153,23 +153,26 @@ class ReceivablePayableReport(object):
|
||||
|
||||
return self.party_map
|
||||
|
||||
def get_voucher_details(self):
|
||||
def get_voucher_details(self, party_type):
|
||||
voucher_details = frappe._dict()
|
||||
|
||||
if party_type == "Customer":
|
||||
for si in frappe.db.sql("""select name, due_date
|
||||
from `tabSales Invoice` where docstatus=1""", as_dict=1):
|
||||
voucher_details.setdefault(si.name, si)
|
||||
|
||||
for si in frappe.db.sql("""select name, due_date
|
||||
from `tabSales Invoice` where docstatus=1""", as_dict=1):
|
||||
voucher_details.setdefault(si.name, si)
|
||||
|
||||
for pi in frappe.db.sql("""select name, due_date, bill_no, bill_date
|
||||
from `tabPurchase Invoice` where docstatus=1""", as_dict=1):
|
||||
voucher_details.setdefault(pi.name, pi)
|
||||
if party_type == "Supplier":
|
||||
for pi in frappe.db.sql("""select name, due_date, bill_no, bill_date
|
||||
from `tabPurchase Invoice` where docstatus=1""", as_dict=1):
|
||||
voucher_details.setdefault(pi.name, pi)
|
||||
|
||||
return voucher_details
|
||||
|
||||
def get_gl_entries(self, party_type):
|
||||
if not hasattr(self, "gl_entries"):
|
||||
conditions, values = self.prepare_conditions(party_type)
|
||||
self.gl_entries = frappe.db.sql("""select * from `tabGL Entry`
|
||||
self.gl_entries = frappe.db.sql("""select posting_date, account, party_type, party, debit, credit,
|
||||
voucher_type, voucher_no, against_voucher_type, against_voucher from `tabGL Entry`
|
||||
where docstatus < 2 and party_type=%s {0} order by posting_date, party"""
|
||||
.format(conditions), values, as_dict=True)
|
||||
|
||||
@@ -187,7 +190,7 @@ class ReceivablePayableReport(object):
|
||||
|
||||
if self.filters.get(party_type_field):
|
||||
conditions.append("party=%s")
|
||||
values.append(self.filters.get(party_type_field))
|
||||
values.append(self.filters.get(party_type_field))
|
||||
|
||||
return " and ".join(conditions), values
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ def get_data(company, root_type, balance_must_be, period_list, ignore_closing_en
|
||||
gl_entries_by_account = get_gl_entries(company, period_list[0]["from_date"], period_list[-1]["to_date"],
|
||||
accounts[0].lft, accounts[0].rgt, ignore_closing_entries=ignore_closing_entries)
|
||||
|
||||
calculate_values(accounts, gl_entries_by_account, period_list)
|
||||
calculate_values(accounts_by_name, gl_entries_by_account, period_list)
|
||||
accumulate_values_into_parents(accounts, accounts_by_name, period_list)
|
||||
out = prepare_data(accounts, balance_must_be, period_list)
|
||||
|
||||
@@ -92,16 +92,14 @@ def get_data(company, root_type, balance_must_be, period_list, ignore_closing_en
|
||||
|
||||
return out
|
||||
|
||||
def calculate_values(accounts, gl_entries_by_account, period_list):
|
||||
for d in accounts:
|
||||
for name in ([d.name] + (d.collapsed_children or [])):
|
||||
for entry in gl_entries_by_account.get(name, []):
|
||||
for period in period_list:
|
||||
entry.posting_date = getdate(entry.posting_date)
|
||||
|
||||
# check if posting date is within the period
|
||||
if entry.posting_date <= period.to_date:
|
||||
d[period.key] = d.get(period.key, 0.0) + flt(entry.debit) - flt(entry.credit)
|
||||
def calculate_values(accounts_by_name, gl_entries_by_account, period_list):
|
||||
for entries in gl_entries_by_account.values():
|
||||
for entry in entries:
|
||||
d = accounts_by_name.get(entry.account)
|
||||
for period in period_list:
|
||||
# check if posting date is within the period
|
||||
if entry.posting_date <= period.to_date:
|
||||
d[period.key] = d.get(period.key, 0.0) + flt(entry.debit) - flt(entry.credit)
|
||||
|
||||
|
||||
def accumulate_values_into_parents(accounts, accounts_by_name, period_list):
|
||||
@@ -159,22 +157,8 @@ def add_total_row(out, balance_must_be, period_list):
|
||||
out.append({})
|
||||
|
||||
def get_accounts(company, root_type):
|
||||
# root lft, rgt
|
||||
root_account = frappe.db.sql("""select lft, rgt from `tabAccount`
|
||||
where company=%s and root_type=%s and ifnull(parent_account, '') = ''
|
||||
order by lft limit 1""",
|
||||
(company, root_type), as_dict=True)
|
||||
|
||||
if not root_account:
|
||||
return None
|
||||
|
||||
lft, rgt = root_account[0].lft, root_account[0].rgt
|
||||
|
||||
accounts = frappe.db.sql("""select * from `tabAccount`
|
||||
where company=%(company)s and lft >= %(lft)s and rgt <= %(rgt)s order by lft""",
|
||||
{ "company": company, "lft": lft, "rgt": rgt }, as_dict=True)
|
||||
|
||||
return accounts
|
||||
return frappe.db.sql("""select name, parent_account, lft, rgt, root_type, report_type, account_name from `tabAccount`
|
||||
where company=%s and root_type=%s order by lft""", (company, root_type), as_dict=True)
|
||||
|
||||
def filter_accounts(accounts, depth=10):
|
||||
parent_children_map = {}
|
||||
@@ -196,14 +180,6 @@ def filter_accounts(accounts, depth=10):
|
||||
filtered_accounts.append(child)
|
||||
add_to_list(child.name, level + 1)
|
||||
|
||||
else:
|
||||
# include all children at level lower than the depth
|
||||
parent_account = accounts_by_name[parent]
|
||||
parent_account["collapsed_children"] = []
|
||||
for d in accounts:
|
||||
if d.lft > parent_account.lft and d.rgt < parent_account.rgt:
|
||||
parent_account["collapsed_children"].append(d.name)
|
||||
|
||||
add_to_list(None, 0)
|
||||
|
||||
return filtered_accounts, accounts_by_name
|
||||
@@ -234,7 +210,7 @@ def get_gl_entries(company, from_date, to_date, root_lft, root_rgt, ignore_closi
|
||||
if from_date:
|
||||
additional_conditions.append("and posting_date >= %(from_date)s")
|
||||
|
||||
gl_entries = frappe.db.sql("""select * from `tabGL Entry`
|
||||
gl_entries = frappe.db.sql("""select posting_date, account, debit, credit from `tabGL Entry`
|
||||
where company=%(company)s
|
||||
{additional_conditions}
|
||||
and posting_date <= %(to_date)s
|
||||
|
||||
@@ -66,7 +66,7 @@ def get_gl_entries(filters):
|
||||
|
||||
gl_entries = frappe.db.sql("""select posting_date, account, party_type, party,
|
||||
sum(ifnull(debit, 0)) as debit, sum(ifnull(credit, 0)) as credit,
|
||||
voucher_type, voucher_no, cost_center, remarks, is_opening, against
|
||||
voucher_type, voucher_no, cost_center, remarks, against
|
||||
from `tabGL Entry`
|
||||
where company=%(company)s {conditions}
|
||||
{group_by_condition}
|
||||
@@ -91,6 +91,9 @@ def get_conditions(filters):
|
||||
|
||||
if filters.get("party"):
|
||||
conditions.append("party=%(party)s")
|
||||
|
||||
if not (filters.get("account") or filters.get("party") or filters.get("group_by_account")):
|
||||
conditions.append("posting_date >=%(from_date)s")
|
||||
|
||||
from frappe.desk.reportview import build_match_conditions
|
||||
match_conditions = build_match_conditions("GL Entry")
|
||||
@@ -148,14 +151,15 @@ def initialize_gle_map(gl_entries):
|
||||
|
||||
def get_accountwise_gle(filters, gl_entries, gle_map):
|
||||
opening, total_debit, total_credit = 0, 0, 0
|
||||
|
||||
from_date, to_date = getdate(filters.from_date), getdate(filters.to_date)
|
||||
for gle in gl_entries:
|
||||
amount = flt(gle.debit, 3) - flt(gle.credit, 3)
|
||||
if gle.posting_date < getdate(filters.from_date):
|
||||
if (filters.get("account") or filters.get("party") or filters.get("group_by_account")) \
|
||||
and gle.posting_date < from_date:
|
||||
gle_map[gle.account].opening += amount
|
||||
if filters.get("account") or filters.get("party"):
|
||||
opening += amount
|
||||
elif gle.posting_date <= getdate(filters.to_date):
|
||||
elif gle.posting_date <= to_date:
|
||||
gle_map[gle.account].entries.append(gle)
|
||||
gle_map[gle.account].total_debit += flt(gle.debit, 3)
|
||||
gle_map[gle.account].total_credit += flt(gle.credit, 3)
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
|
||||
frappe.query_reports["Payment Period Based On Invoice Date"] = {
|
||||
"filters": [
|
||||
{
|
||||
fieldname:"company",
|
||||
label: __("Company"),
|
||||
fieldtype: "Link",
|
||||
options: "Company",
|
||||
reqd: 1,
|
||||
default: frappe.defaults.get_user_default("company")
|
||||
},
|
||||
{
|
||||
fieldname: "from_date",
|
||||
label: __("From Date"),
|
||||
@@ -23,27 +31,28 @@ frappe.query_reports["Payment Period Based On Invoice Date"] = {
|
||||
default: "Incoming"
|
||||
},
|
||||
{
|
||||
fieldname:"account",
|
||||
label: __("Account"),
|
||||
fieldtype: "Link",
|
||||
options: "Account",
|
||||
get_query: function() {
|
||||
"fieldname":"party_type",
|
||||
"label": __("Party Type"),
|
||||
"fieldtype": "Link",
|
||||
"options": "DocType",
|
||||
"get_query": function() {
|
||||
return {
|
||||
query: "erpnext.controllers.queries.get_account_list",
|
||||
filters: {
|
||||
"report_type": "Balance Sheet",
|
||||
company: frappe.query_report.filters_by_name.company.get_value()
|
||||
}
|
||||
filters: {"name": ["in", ["Customer", "Supplier"]]}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
fieldname:"company",
|
||||
label: __("Company"),
|
||||
fieldtype: "Link",
|
||||
options: "Company",
|
||||
reqd: 1,
|
||||
default: frappe.defaults.get_user_default("company")
|
||||
"fieldname":"party",
|
||||
"label": __("Party"),
|
||||
"fieldtype": "Dynamic Link",
|
||||
"get_options": function() {
|
||||
var party_type = frappe.query_report.filters_by_name.party_type.get_value();
|
||||
var party = frappe.query_report.filters_by_name.party.get_value();
|
||||
if(party && !party_type) {
|
||||
frappe.throw(__("Please select Party Type first"));
|
||||
}
|
||||
return party_type;
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
@@ -20,16 +20,16 @@ def execute(filters=None):
|
||||
for d in entries:
|
||||
if d.against_voucher:
|
||||
against_date = d.against_voucher and invoice_posting_date_map[d.against_voucher] or ""
|
||||
outstanding_amount = flt(d.debit) or -1 * flt(d.credit)
|
||||
payment_amount = flt(d.debit) or -1 * flt(d.credit)
|
||||
else:
|
||||
against_date = d.against_invoice and invoice_posting_date_map[d.against_invoice] or ""
|
||||
outstanding_amount = flt(d.credit) or -1 * flt(d.debit)
|
||||
payment_amount = flt(d.credit) or -1 * flt(d.debit)
|
||||
|
||||
row = [d.name, d.account, d.posting_date, d.against_voucher or d.against_invoice,
|
||||
row = [d.name, d.party_type, d.party, d.posting_date, d.against_voucher or d.against_invoice,
|
||||
against_date, d.debit, d.credit, d.cheque_no, d.cheque_date, d.remark]
|
||||
|
||||
if d.against_voucher or d.against_invoice:
|
||||
row += get_ageing_data(30, 60, 90, d.posting_date, against_date, outstanding_amount)
|
||||
row += get_ageing_data(30, 60, 90, d.posting_date, against_date, payment_amount)
|
||||
else:
|
||||
row += ["", "", "", "", ""]
|
||||
|
||||
@@ -38,7 +38,8 @@ def execute(filters=None):
|
||||
return columns, data
|
||||
|
||||
def get_columns():
|
||||
return [_("Journal Entry") + ":Link/Journal Entry:140", _("Account") + ":Link/Account:140",
|
||||
return [_("Journal Entry") + ":Link/Journal Entry:140",
|
||||
_("Party Type") + ":Link/DocType:100", _("Party") + ":Dynamic Link/party_type:140",
|
||||
_("Posting Date") + ":Date:100", _("Against Invoice") + ":Link/Purchase Invoice:130",
|
||||
_("Against Invoice Posting Date") + ":Date:130", _("Debit") + ":Currency:120", _("Credit") + ":Currency:120",
|
||||
_("Reference No") + "::100", _("Reference Date") + ":Date:100", _("Remarks") + "::150", _("Age") +":Int:40",
|
||||
@@ -46,41 +47,38 @@ def get_columns():
|
||||
]
|
||||
|
||||
def get_conditions(filters):
|
||||
conditions = ""
|
||||
party = None
|
||||
conditions = []
|
||||
|
||||
if filters.get("account"):
|
||||
party = filters["account"]
|
||||
else:
|
||||
conditions += " and company = '%s'" % frappe.db.escape(filters["company"])
|
||||
if not filters.get("party_type"):
|
||||
if filters.get("payment_type") == "Outgoing":
|
||||
filters["party_type"] = "Supplier"
|
||||
else:
|
||||
filters["party_type"] = "Customer"
|
||||
|
||||
if filters.get("party_type"):
|
||||
conditions.append("jvd.party_type=%(party_type)s")
|
||||
|
||||
account_type = "Receivable" if filters.get("payment_type") == "Incoming" else "Payable"
|
||||
if filters.get("party"):
|
||||
conditions.append("jvd.party=%(party)s")
|
||||
|
||||
conditions += """ and account in
|
||||
(select name from tabAccount
|
||||
where account_type = '{0}'
|
||||
and company='{1}')""".format(account_type, frappe.db.escape(filters["company"]))
|
||||
|
||||
if party:
|
||||
conditions += " and jvd.party = '%s'" % frappe.db.escape(party)
|
||||
else:
|
||||
conditions += " and ifnull(jvd.party, '') != ''"
|
||||
if filters.get("company"):
|
||||
conditions.append("jv.company=%(company)s")
|
||||
|
||||
if filters.get("from_date"):
|
||||
conditions += " and jv.posting_date >= '%s'" % filters["from_date"]
|
||||
conditions.append("jv.posting_date >= %(from_date)s")
|
||||
if filters.get("to_date"):
|
||||
conditions += " and jv.posting_date <= '%s'" % filters["to_date"]
|
||||
conditions.append("jv.posting_date <= %(to_date)s")
|
||||
|
||||
return conditions
|
||||
return "and {}".format(" and ".join(conditions)) if conditions else ""
|
||||
|
||||
def get_entries(filters):
|
||||
conditions = get_conditions(filters)
|
||||
entries = frappe.db.sql("""select jv.name, jvd.account, jv.posting_date,
|
||||
entries = frappe.db.sql("""select jv.name, jvd.party_type, jvd.party, jv.posting_date,
|
||||
jvd.against_voucher, jvd.against_invoice, jvd.debit, jvd.credit,
|
||||
jv.cheque_no, jv.cheque_date, jv.remark
|
||||
from `tabJournal Entry Account` jvd, `tabJournal Entry` jv
|
||||
where jvd.parent = jv.name and jv.docstatus=1 %s order by jv.name DESC""" %
|
||||
conditions, as_dict=1, debug=1)
|
||||
conditions, filters, as_dict=1)
|
||||
|
||||
return entries
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ from erpnext.accounts.report.financial_statements import filter_accounts, get_gl
|
||||
|
||||
value_fields = ("opening_debit", "opening_credit", "debit", "credit", "closing_debit", "closing_credit")
|
||||
|
||||
def execute(filters):
|
||||
def execute(filters=None):
|
||||
validate_filters(filters)
|
||||
data = get_data(filters)
|
||||
columns = get_columns()
|
||||
@@ -45,8 +45,8 @@ def validate_filters(filters):
|
||||
filters.to_date = filters.year_end_date
|
||||
|
||||
def get_data(filters):
|
||||
accounts = frappe.db.sql("""select * from `tabAccount` where company=%s order by lft""",
|
||||
filters.company, as_dict=True)
|
||||
accounts = frappe.db.sql("""select name, parent_account, account_name, root_type, report_type, lft, rgt
|
||||
from `tabAccount` where company=%s order by lft""", filters.company, as_dict=True)
|
||||
|
||||
if not accounts:
|
||||
return None
|
||||
@@ -56,17 +56,58 @@ def get_data(filters):
|
||||
min_lft, max_rgt = frappe.db.sql("""select min(lft), max(rgt) from `tabAccount`
|
||||
where company=%s""", (filters.company,))[0]
|
||||
|
||||
gl_entries_by_account = get_gl_entries(filters.company, None, filters.to_date, min_lft, max_rgt,
|
||||
gl_entries_by_account = get_gl_entries(filters.company, filters.from_date, filters.to_date, min_lft, max_rgt,
|
||||
ignore_closing_entries=not flt(filters.with_period_closing_entry))
|
||||
|
||||
total_row = calculate_values(accounts, gl_entries_by_account, filters)
|
||||
opening_balances = get_opening_balances(filters)
|
||||
|
||||
total_row = calculate_values(accounts, gl_entries_by_account, opening_balances, filters)
|
||||
accumulate_values_into_parents(accounts, accounts_by_name)
|
||||
|
||||
data = prepare_data(accounts, filters, total_row)
|
||||
|
||||
return data
|
||||
|
||||
def get_opening_balances(filters):
|
||||
balance_sheet_opening = get_rootwise_opening_balances(filters, "Balance Sheet")
|
||||
pl_opening = get_rootwise_opening_balances(filters, "Profit and Loss")
|
||||
|
||||
balance_sheet_opening.update(pl_opening)
|
||||
return balance_sheet_opening
|
||||
|
||||
|
||||
def get_rootwise_opening_balances(filters, report_type):
|
||||
additional_conditions = " and posting_date >= %(year_start_date)s" \
|
||||
if report_type == "Profit and Loss" else ""
|
||||
|
||||
if not flt(filters.with_period_closing_entry):
|
||||
additional_conditions += " and ifnull(voucher_type, '')!='Period Closing Voucher'"
|
||||
|
||||
gle = frappe.db.sql("""
|
||||
select
|
||||
account, sum(ifnull(debit, 0)) as opening_debit, sum(ifnull(credit, 0)) as opening_credit
|
||||
from `tabGL Entry`
|
||||
where
|
||||
company=%(company)s
|
||||
{additional_conditions}
|
||||
and posting_date < %(from_date)s
|
||||
and account in (select name from `tabAccount` where report_type=%(report_type)s)
|
||||
group by account""".format(additional_conditions=additional_conditions),
|
||||
{
|
||||
"company": filters.company,
|
||||
"from_date": filters.from_date,
|
||||
"report_type": report_type,
|
||||
"year_start_date": filters.year_start_date
|
||||
},
|
||||
as_dict=True)
|
||||
|
||||
opening = frappe._dict()
|
||||
for d in gle:
|
||||
opening.setdefault(d.account, d)
|
||||
|
||||
return opening
|
||||
|
||||
def calculate_values(accounts, gl_entries_by_account, filters):
|
||||
def calculate_values(accounts, gl_entries_by_account, opening_balances, filters):
|
||||
init = {
|
||||
"opening_debit": 0.0,
|
||||
"opening_credit": 0.0,
|
||||
@@ -88,29 +129,15 @@ def calculate_values(accounts, gl_entries_by_account, filters):
|
||||
d.update(init.copy())
|
||||
|
||||
for entry in gl_entries_by_account.get(d.name, []):
|
||||
posting_date = getdate(entry.posting_date)
|
||||
|
||||
# opening
|
||||
if posting_date < filters.from_date:
|
||||
is_valid_opening = (d.root_type in ("Asset", "Liability", "Equity") or
|
||||
(filters.year_start_date <= posting_date < filters.from_date))
|
||||
|
||||
if is_valid_opening:
|
||||
d["opening_debit"] += flt(entry.debit)
|
||||
d["opening_credit"] += flt(entry.credit)
|
||||
|
||||
elif posting_date <= filters.to_date:
|
||||
|
||||
if entry.is_opening == "Yes" and d.root_type in ("Asset", "Liability", "Equity"):
|
||||
d["opening_debit"] += flt(entry.debit)
|
||||
d["opening_credit"] += flt(entry.credit)
|
||||
|
||||
else:
|
||||
d["debit"] += flt(entry.debit)
|
||||
d["credit"] += flt(entry.credit)
|
||||
d["debit"] += flt(entry.debit)
|
||||
d["credit"] += flt(entry.credit)
|
||||
|
||||
total_row["debit"] += d["debit"]
|
||||
total_row["credit"] += d["credit"]
|
||||
|
||||
# add opening
|
||||
d["opening_debit"] = opening_balances.get(d.name, {}).get("opening_debit", 0)
|
||||
d["opening_credit"] = opening_balances.get(d.name, {}).get("opening_credit", 0)
|
||||
|
||||
return total_row
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ def get_balance_on(account=None, date=None, party_type=None, party=None):
|
||||
# different filter for group and ledger - improved performance
|
||||
if acc.is_group:
|
||||
cond.append("""exists (
|
||||
select * from `tabAccount` ac where ac.name = gle.account
|
||||
select name from `tabAccount` ac where ac.name = gle.account
|
||||
and ac.lft >= %s and ac.rgt <= %s
|
||||
)""" % (acc.lft, acc.rgt))
|
||||
else:
|
||||
@@ -397,7 +397,7 @@ def get_outstanding_invoices(amount_query, account, party_type, party):
|
||||
|
||||
for d in outstanding_voucher_list:
|
||||
payment_amount = frappe.db.sql("""
|
||||
select ifnull(sum(ifnull({amount_query}, 0)), 0)
|
||||
select ifnull(sum({amount_query}), 0)
|
||||
from
|
||||
`tabGL Entry`
|
||||
where
|
||||
|
||||
@@ -5,7 +5,7 @@ app_publisher = "Frappe Technologies Pvt. Ltd. and Contributors"
|
||||
app_description = "Open Source Enterprise Resource Planning for Small and Midsized Organizations"
|
||||
app_icon = "icon-th"
|
||||
app_color = "#e74c3c"
|
||||
app_version = "5.0.19"
|
||||
app_version = "5.0.23"
|
||||
|
||||
error_report_email = "support@erpnext.com"
|
||||
|
||||
|
||||
@@ -309,10 +309,9 @@ class ProductionOrder(Document):
|
||||
self.actual_end_date = None
|
||||
|
||||
def validate_delivery_date(self):
|
||||
if self.docstatus==1:
|
||||
if self.planned_end_date and self.expected_delivery_date \
|
||||
and getdate(self.expected_delivery_date) < getdate(self.planned_end_date):
|
||||
frappe.msgprint(_("Production might not be able to finish by the Expected Delivery Date."))
|
||||
if self.planned_start_date and self.expected_delivery_date \
|
||||
and getdate(self.expected_delivery_date) < getdate(self.planned_start_date):
|
||||
frappe.throw(_("Expected Delivery Date must be greater than Planned Start Date."))
|
||||
|
||||
def delete_time_logs(self):
|
||||
for time_log in frappe.get_all("Time Log", ["name"], {"production_order": self.name}):
|
||||
|
||||
@@ -165,4 +165,5 @@ erpnext.patches.v5_0.repost_gle_for_jv_with_multiple_party
|
||||
erpnext.patches.v5_0.portal_fixes
|
||||
erpnext.patches.v5_0.reset_values_in_tools
|
||||
execute:frappe.delete_doc("Page", "users")
|
||||
erpnext.patches.v5_0.update_material_transferred_for_manufacturing_again
|
||||
erpnext.patches.v5_0.update_material_transferred_for_manufacturing_again
|
||||
erpnext.patches.v5_0.index_on_account_and_gl_entry
|
||||
22
erpnext/patches/v5_0/index_on_account_and_gl_entry.py
Normal file
22
erpnext/patches/v5_0/index_on_account_and_gl_entry.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
index_map = {
|
||||
"Account": ["parent_account", "lft", "rgt"],
|
||||
"GL Entry": ["posting_date", "account", 'party', "voucher_no"]
|
||||
}
|
||||
|
||||
for dt, indexes in index_map.items():
|
||||
existing_indexes = [d.Key_name for d in frappe.db.sql("""show index from `tab{0}`
|
||||
where Column_name != 'name'""".format(dt), as_dict=1)]
|
||||
|
||||
for old in existing_indexes:
|
||||
if old in ("parent", "group_or_ledger", "is_pl_account", "debit_or_credit", "account_name", "company"):
|
||||
frappe.db.sql("alter table `tab{0}` drop index {1}".format(dt, old))
|
||||
existing_indexes.remove(old)
|
||||
|
||||
for new in indexes:
|
||||
if new not in existing_indexes:
|
||||
frappe.db.sql("alter table `tab{0}` add index ({1})".format(dt, new))
|
||||
1
erpnext/projects/doctype/activity_cost/activity_cost.js
Normal file
1
erpnext/projects/doctype/activity_cost/activity_cost.js
Normal file
@@ -0,0 +1 @@
|
||||
cur_frm.add_fetch('employee', 'employee_name', 'employee_name');
|
||||
@@ -2,7 +2,7 @@
|
||||
"allow_copy": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "Activity Cost - .#",
|
||||
"autoname": "AC-.#####",
|
||||
"creation": "2015-03-23 02:00:21.861546",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
@@ -31,11 +31,12 @@
|
||||
},
|
||||
{
|
||||
"fieldname": "employee_name",
|
||||
"fieldtype": "Read Only",
|
||||
"fieldtype": "Data",
|
||||
"label": "Employee Name",
|
||||
"options": "employee.employee_name",
|
||||
"options": "",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
"precision": "",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_2",
|
||||
@@ -135,7 +136,7 @@
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"modified": "2015-04-14 02:08:33.690406",
|
||||
"modified": "2015-06-11 06:50:47.999788",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Projects",
|
||||
"name": "Activity Cost",
|
||||
|
||||
@@ -15,6 +15,8 @@ class ActivityCost(Document):
|
||||
self.check_unique()
|
||||
|
||||
def set_title(self):
|
||||
if not self.employee_name:
|
||||
self.employee_name = frappe.db.get_value("Employee", self.employee, "employee_name")
|
||||
self.title = _("{0} for {1}").format(self.employee_name, self.activity_type)
|
||||
|
||||
def check_unique(self):
|
||||
|
||||
@@ -15,16 +15,23 @@ class Project(Document):
|
||||
|
||||
def onload(self):
|
||||
"""Load project tasks for quick view"""
|
||||
for task in frappe.get_all("Task", "*", {"project": self.name}, order_by="exp_start_date asc"):
|
||||
self.append("tasks", {
|
||||
"title": task.subject,
|
||||
"status": task.status,
|
||||
"start_date": task.exp_start_date,
|
||||
"end_date": task.exp_end_date,
|
||||
"description": task.description,
|
||||
"task_id": task.name
|
||||
})
|
||||
|
||||
if not self.get("tasks"):
|
||||
for task in self.get_tasks():
|
||||
self.append("tasks", {
|
||||
"title": task.subject,
|
||||
"status": task.status,
|
||||
"start_date": task.exp_start_date,
|
||||
"end_date": task.exp_end_date,
|
||||
"description": task.description,
|
||||
"task_id": task.name
|
||||
})
|
||||
|
||||
def __setup__(self):
|
||||
self.onload()
|
||||
|
||||
def get_tasks(self):
|
||||
return frappe.get_all("Task", "*", {"project": self.name}, order_by="exp_start_date asc")
|
||||
|
||||
def validate(self):
|
||||
self.validate_dates()
|
||||
self.sync_tasks()
|
||||
|
||||
@@ -28,7 +28,11 @@ class Task(Document):
|
||||
|
||||
def validate(self):
|
||||
self.validate_dates()
|
||||
|
||||
|
||||
if self.status!=self.get_db_value("status") and self.status == "Closed":
|
||||
from frappe.desk.form.assign_to import clear
|
||||
clear(self.doctype, self.name)
|
||||
|
||||
def validate_dates(self):
|
||||
if self.exp_start_date and self.exp_end_date and getdate(self.exp_start_date) > getdate(self.exp_end_date):
|
||||
frappe.throw(_("'Expected Start Date' can not be greater than 'Expected End Date'"))
|
||||
@@ -41,17 +45,17 @@ class Task(Document):
|
||||
self.reschedule_dependent_tasks()
|
||||
self.update_percentage()
|
||||
self.update_project()
|
||||
|
||||
|
||||
def update_percentage(self):
|
||||
"""update percent complete in project"""
|
||||
if self.project and not self.flags.from_project:
|
||||
project = frappe.get_doc("Project", self.project)
|
||||
project.run_method("update_percent_complete")
|
||||
|
||||
|
||||
def update_total_expense_claim(self):
|
||||
self.total_expense_claim = frappe.db.sql("""select sum(total_sanctioned_amount) from `tabExpense Claim`
|
||||
self.total_expense_claim = frappe.db.sql("""select sum(total_sanctioned_amount) from `tabExpense Claim`
|
||||
where project = %s and task = %s and approval_status = "Approved" and docstatus=1""",(self.project, self.name))
|
||||
|
||||
|
||||
def update_time_and_costing(self):
|
||||
tl = frappe.db.sql("""select min(from_time) as start_date, max(to_time) as end_date,
|
||||
sum(billing_amount) as total_billing_amount, sum(costing_amount) as total_costing_amount,
|
||||
@@ -64,14 +68,14 @@ class Task(Document):
|
||||
self.actual_time= tl.time
|
||||
self.act_start_date= tl.start_date
|
||||
self.act_end_date= tl.end_date
|
||||
|
||||
|
||||
def update_project(self):
|
||||
if self.project and frappe.db.exists("Project", self.project):
|
||||
project = frappe.get_doc("Project", self.project)
|
||||
project.flags.dont_sync_tasks = True
|
||||
project.update_costing()
|
||||
project.save()
|
||||
|
||||
|
||||
def check_recursion(self):
|
||||
if self.flags.ignore_recursion_check: return
|
||||
check_list = [['task', 'parent'], ['parent', 'task']]
|
||||
@@ -88,7 +92,7 @@ class Task(Document):
|
||||
task_list.append(b[0])
|
||||
if count == 15:
|
||||
break
|
||||
|
||||
|
||||
def reschedule_dependent_tasks(self):
|
||||
end_date = self.exp_end_date or self.act_end_date
|
||||
if end_date:
|
||||
|
||||
@@ -11,19 +11,19 @@ from erpnext.projects.doctype.task.task import CircularReferenceError
|
||||
|
||||
class TestTask(unittest.TestCase):
|
||||
def test_circular_reference(self):
|
||||
|
||||
|
||||
task1 = frappe.new_doc('Task')
|
||||
task1.update({
|
||||
"status": "Open",
|
||||
"status": "Open",
|
||||
"subject": "_Test Task 1",
|
||||
"exp_start_date": "2015-1-1",
|
||||
"exp_end_date": "2015-1-10"
|
||||
})
|
||||
task1.save()
|
||||
|
||||
|
||||
task2 = frappe.new_doc('Task')
|
||||
task2.update({
|
||||
"status": "Open",
|
||||
"status": "Open",
|
||||
"subject": "_Test Task 2",
|
||||
"exp_start_date": "2015-1-11",
|
||||
"exp_end_date": "2015-1-15",
|
||||
@@ -34,10 +34,10 @@ class TestTask(unittest.TestCase):
|
||||
]
|
||||
})
|
||||
task2.save()
|
||||
|
||||
|
||||
task3 = frappe.new_doc('Task')
|
||||
task3.update({
|
||||
"status": "Open",
|
||||
"status": "Open",
|
||||
"subject": "_Test Task 2",
|
||||
"exp_start_date": "2015-1-11",
|
||||
"exp_end_date": "2015-1-15",
|
||||
@@ -53,13 +53,13 @@ class TestTask(unittest.TestCase):
|
||||
"task": task3.name
|
||||
})
|
||||
self.assertRaises(CircularReferenceError, task1.save)
|
||||
|
||||
|
||||
task1.set("depends_on", [])
|
||||
task1.save()
|
||||
|
||||
|
||||
task4 = frappe.new_doc('Task')
|
||||
task4.update({
|
||||
"status": "Open",
|
||||
"status": "Open",
|
||||
"subject": "_Test Task 1",
|
||||
"exp_start_date": "2015-1-1",
|
||||
"exp_end_date": "2015-1-15",
|
||||
@@ -74,20 +74,20 @@ class TestTask(unittest.TestCase):
|
||||
task3.append("depends_on", {
|
||||
"task": task4.name
|
||||
})
|
||||
|
||||
|
||||
def test_reschedule_dependent_task(self):
|
||||
task1 = frappe.new_doc('Task')
|
||||
task1.update({
|
||||
"status": "Open",
|
||||
"status": "Open",
|
||||
"subject": "_Test Task 1",
|
||||
"exp_start_date": "2015-1-1",
|
||||
"exp_end_date": "2015-1-10"
|
||||
})
|
||||
task1.save()
|
||||
|
||||
|
||||
task2 = frappe.new_doc('Task')
|
||||
task2.update({
|
||||
"status": "Open",
|
||||
"status": "Open",
|
||||
"subject": "_Test Task 2",
|
||||
"exp_start_date": "2015-1-11",
|
||||
"exp_end_date": "2015-1-15",
|
||||
@@ -98,10 +98,10 @@ class TestTask(unittest.TestCase):
|
||||
]
|
||||
})
|
||||
task2.save()
|
||||
|
||||
|
||||
task3 = frappe.new_doc('Task')
|
||||
task3.update({
|
||||
"status": "Open",
|
||||
"status": "Open",
|
||||
"subject": "_Test Task 3",
|
||||
"exp_start_date": "2015-1-16",
|
||||
"exp_end_date": "2015-1-18",
|
||||
@@ -112,18 +112,18 @@ class TestTask(unittest.TestCase):
|
||||
]
|
||||
})
|
||||
task3.save()
|
||||
|
||||
|
||||
task1.update({
|
||||
"exp_end_date": "2015-1-20"
|
||||
})
|
||||
task1.save()
|
||||
|
||||
|
||||
self.assertEqual(frappe.db.get_value("Task", task2.name, "exp_start_date"), getdate('2015-1-21'))
|
||||
self.assertEqual(frappe.db.get_value("Task", task2.name, "exp_end_date"), getdate('2015-1-25'))
|
||||
|
||||
self.assertEqual(frappe.db.get_value("Task", task3.name, "exp_start_date"), getdate('2015-1-26'))
|
||||
self.assertEqual(frappe.db.get_value("Task", task3.name, "exp_end_date"), getdate('2015-1-28'))
|
||||
|
||||
|
||||
time_log = frappe.new_doc('Time Log')
|
||||
time_log.update({
|
||||
"from_time": "2015-1-1",
|
||||
@@ -131,18 +131,49 @@ class TestTask(unittest.TestCase):
|
||||
"task": task1.name
|
||||
})
|
||||
time_log.submit()
|
||||
|
||||
|
||||
self.assertEqual(frappe.db.get_value("Task", task2.name, "exp_start_date"), getdate('2015-1-21'))
|
||||
self.assertEqual(frappe.db.get_value("Task", task2.name, "exp_end_date"), getdate('2015-1-25'))
|
||||
|
||||
self.assertEqual(frappe.db.get_value("Task", task3.name, "exp_start_date"), getdate('2015-1-26'))
|
||||
self.assertEqual(frappe.db.get_value("Task", task3.name, "exp_end_date"), getdate('2015-1-28'))
|
||||
|
||||
|
||||
time_log.cancel()
|
||||
|
||||
|
||||
self.assertEqual(frappe.db.get_value("Task", task2.name, "exp_start_date"), getdate('2015-1-21'))
|
||||
self.assertEqual(frappe.db.get_value("Task", task2.name, "exp_end_date"), getdate('2015-1-25'))
|
||||
|
||||
self.assertEqual(frappe.db.get_value("Task", task3.name, "exp_start_date"), getdate('2015-1-26'))
|
||||
self.assertEqual(frappe.db.get_value("Task", task3.name, "exp_end_date"), getdate('2015-1-28'))
|
||||
|
||||
|
||||
|
||||
def test_close_assignment(self):
|
||||
task = frappe.new_doc("Task")
|
||||
task.subject = "Test Close Assignment"
|
||||
task.insert()
|
||||
|
||||
def assign():
|
||||
from frappe.desk.form import assign_to
|
||||
assign_to.add({
|
||||
"assign_to": "test@example.com",
|
||||
"doctype": task.doctype,
|
||||
"name": task.name,
|
||||
"description": "Close this task"
|
||||
})
|
||||
|
||||
def get_owner_and_status():
|
||||
return frappe.db.get_value("ToDo", filters={"reference_type": task.doctype, "reference_name": task.name,
|
||||
"description": "Close this task"}, fieldname=("owner", "status"), as_dict=True)
|
||||
|
||||
assign()
|
||||
todo = get_owner_and_status()
|
||||
self.assertEquals(todo.owner, "test@example.com")
|
||||
self.assertEquals(todo.status, "Open")
|
||||
|
||||
# assignment should be
|
||||
task.load_from_db()
|
||||
task.status = "Closed"
|
||||
task.save()
|
||||
todo = get_owner_and_status()
|
||||
self.assertEquals(todo.owner, "test@example.com")
|
||||
self.assertEquals(todo.status, "Closed")
|
||||
|
||||
@@ -105,6 +105,15 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
}
|
||||
},
|
||||
|
||||
barcode: function(doc, cdt, cdn) {
|
||||
var d = locals[cdt][cdn];
|
||||
if(d.barcode=="" || d.barcode==null) {
|
||||
// barcode cleared, remove item
|
||||
d.item_code = "";
|
||||
}
|
||||
this.item_code(doc, cdt, cdn);
|
||||
},
|
||||
|
||||
item_code: function(doc, cdt, cdn) {
|
||||
var me = this;
|
||||
var item = frappe.get_doc(cdt, cdn);
|
||||
|
||||
@@ -81,7 +81,8 @@ erpnext.feature_setup.feature_dict = {
|
||||
'Item': {'fields': ['barcode']},
|
||||
'Delivery Note': {'items': ['barcode']},
|
||||
'Sales Invoice': {'items': ['barcode']},
|
||||
'Stock Entry': {'items': ['barcode']}
|
||||
'Stock Entry': {'items': ['barcode']},
|
||||
'Purchase Receipt': {'items': ['barcode']}
|
||||
},
|
||||
'fs_item_group_in_details': {
|
||||
'Delivery Note': {'items':['item_group']},
|
||||
|
||||
@@ -8,6 +8,13 @@ frappe.query_reports["Customers Not Buying Since Long Time"] = {
|
||||
"label": __("Days Since Last Order"),
|
||||
"fieldtype": "Int",
|
||||
"default": 60
|
||||
},
|
||||
{
|
||||
"fieldname":"doctype",
|
||||
"label": __("Doctype"),
|
||||
"fieldtype": "Select",
|
||||
"default": "Sales Order",
|
||||
"options": "Sales Order\nSales Invoice"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -10,41 +10,51 @@ def execute(filters=None):
|
||||
if not filters: filters ={}
|
||||
|
||||
days_since_last_order = filters.get("days_since_last_order")
|
||||
doctype = filters.get("doctype")
|
||||
|
||||
if cint(days_since_last_order) <= 0:
|
||||
frappe.throw(_("'Days Since Last Order' must be greater than or equal to zero"))
|
||||
|
||||
columns = get_columns()
|
||||
customers = get_so_details()
|
||||
customers = get_sales_details(doctype)
|
||||
|
||||
data = []
|
||||
for cust in customers:
|
||||
if cint(cust[8]) >= cint(days_since_last_order):
|
||||
cust.insert(7,get_last_so_amt(cust[0]))
|
||||
cust.insert(7,get_last_sales_amt(cust[0], doctype))
|
||||
data.append(cust)
|
||||
return columns, data
|
||||
|
||||
def get_so_details():
|
||||
def get_sales_details(doctype):
|
||||
cond = """sum(so.base_net_total) as 'total_order_considered',
|
||||
max(so.posting_date) as 'last_order_date',
|
||||
DATEDIFF(CURDATE(), max(so.posting_date)) as 'days_since_last_order' """
|
||||
if doctype == "Sales Order":
|
||||
cond = """sum(if(so.status = "Stopped",
|
||||
so.base_net_total * so.per_delivered/100,
|
||||
so.base_net_total)) as 'total_order_considered',
|
||||
max(so.transaction_date) as 'last_order_date',
|
||||
DATEDIFF(CURDATE(), max(so.transaction_date)) as 'days_since_last_order'"""
|
||||
|
||||
return frappe.db.sql("""select
|
||||
cust.name,
|
||||
cust.customer_name,
|
||||
cust.territory,
|
||||
cust.customer_group,
|
||||
count(distinct(so.name)) as 'num_of_order',
|
||||
sum(base_net_total) as 'total_order_value',
|
||||
sum(if(so.status = "Stopped",
|
||||
so.base_net_total * so.per_delivered/100,
|
||||
so.base_net_total)) as 'total_order_considered',
|
||||
max(so.transaction_date) as 'last_sales_order_date',
|
||||
DATEDIFF(CURDATE(), max(so.transaction_date)) as 'days_since_last_order'
|
||||
from `tabCustomer` cust, `tabSales Order` so
|
||||
sum(base_net_total) as 'total_order_value', {0}
|
||||
from `tabCustomer` cust, `tab{1}` so
|
||||
where cust.name = so.customer and so.docstatus = 1
|
||||
group by cust.name
|
||||
order by 'days_since_last_order' desc """,as_list=1)
|
||||
order by 'days_since_last_order' desc """.format(cond, doctype), as_list=1)
|
||||
|
||||
def get_last_so_amt(customer):
|
||||
res = frappe.db.sql("""select base_net_total from `tabSales Order`
|
||||
where customer = %s and docstatus = 1 order by transaction_date desc
|
||||
limit 1""", customer)
|
||||
def get_last_sales_amt(customer, doctype):
|
||||
cond = "posting_date"
|
||||
if doctype =="Sales Order":
|
||||
cond = "transaction_date"
|
||||
res = frappe.db.sql("""select base_net_total from `tab{0}`
|
||||
where customer = %s and docstatus = 1 order by {1} desc
|
||||
limit 1""".format(doctype, cond), customer)
|
||||
|
||||
return res and res[0][0] or 0
|
||||
|
||||
@@ -58,6 +68,6 @@ def get_columns():
|
||||
_("Total Order Value") + ":Currency:120",
|
||||
_("Total Order Considered") + ":Currency:160",
|
||||
_("Last Order Amount") + ":Currency:160",
|
||||
_("Last Sales Order Date") + ":Date:160",
|
||||
_("Last Order Date") + ":Date:160",
|
||||
_("Days Since Last Order") + "::160"
|
||||
]
|
||||
|
||||
@@ -124,15 +124,6 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
|
||||
this.apply_pricing_rule();
|
||||
},
|
||||
|
||||
barcode: function(doc, cdt, cdn) {
|
||||
var d = locals[cdt][cdn];
|
||||
if(d.barcode=="" || d.barcode==null) {
|
||||
// barcode cleared, remove item
|
||||
d.item_code = "";
|
||||
}
|
||||
this.item_code(doc, cdt, cdn);
|
||||
},
|
||||
|
||||
selling_price_list: function() {
|
||||
this.apply_price_list();
|
||||
},
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
import urllib
|
||||
from frappe.utils.nestedset import NestedSet
|
||||
from frappe.website.website_generator import WebsiteGenerator
|
||||
from frappe.website.render import clear_cache
|
||||
@@ -91,7 +91,7 @@ def get_item_for_list_in_html(context):
|
||||
# add missing absolute link in files
|
||||
# user may forget it during upload
|
||||
if (context.get("website_image") or "").startswith("files/"):
|
||||
context["website_image"] = "/" + context["website_image"]
|
||||
context["website_image"] = "/" + urllib.quote(context["website_image"])
|
||||
return frappe.get_template("templates/includes/product_in_grid.html").render(context)
|
||||
|
||||
def get_group_item_count(item_group):
|
||||
|
||||
@@ -49,7 +49,7 @@ class NamingSeries(Document):
|
||||
self.set_series_for(self.select_doc_for_series, series_list)
|
||||
|
||||
# create series
|
||||
map(self.insert_series, [d.split('.')[0] for d in series_list])
|
||||
map(self.insert_series, [d.split('.')[0] for d in series_list if d.strip()])
|
||||
|
||||
msgprint(_("Series Updated"))
|
||||
|
||||
|
||||
@@ -221,7 +221,7 @@
|
||||
"icon": "icon-ticket",
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"modified": "2015-05-27 15:36:06.818491",
|
||||
"modified": "2015-06-09 05:47:05.934432",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Material Request",
|
||||
|
||||
@@ -6,7 +6,13 @@ frappe.listview_settings['Material Request'] = {
|
||||
} else if(doc.docstatus==1 && flt(doc.per_ordered) < 100) {
|
||||
return [__("Pending"), "orange", "per_ordered,<,100"];
|
||||
} else if(doc.docstatus==1 && flt(doc.per_ordered) == 100) {
|
||||
return [__("Ordered"), "green", "per_ordered,=,100"];
|
||||
if (doc.material_request_type == "Purchase") {
|
||||
return [__("Ordered"), "green", "per_ordered,=,100"];
|
||||
} else if (doc.material_request_type == "Material Transfer") {
|
||||
return [__("Transfered"), "green", "per_ordered,=,100"];
|
||||
} else if (doc.material_request_type == "Material Issue") {
|
||||
return [__("Issued"), "green", "per_ordered,=,100"];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -4,6 +4,19 @@
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "barcode",
|
||||
"fieldtype": "Data",
|
||||
"label": "Barcode",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_2",
|
||||
"fieldtype": "Section Break",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"fieldname": "item_code",
|
||||
"fieldtype": "Link",
|
||||
@@ -642,7 +655,7 @@
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"modified": "2015-06-02 14:19:13.528248",
|
||||
"modified": "2015-06-08 08:21:18.024324",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Purchase Receipt Item",
|
||||
|
||||
@@ -112,7 +112,7 @@ class StockEntry(StockController):
|
||||
|
||||
for f in ("uom", "stock_uom", "description", "item_name", "expense_account",
|
||||
"cost_center", "conversion_factor"):
|
||||
if f not in ["expense_account", "cost_center"] or not item.get(f):
|
||||
if f in ["stock_uom", "conversion_factor"] or not item.get(f):
|
||||
item.set(f, item_details.get(f))
|
||||
|
||||
if self.difference_account:
|
||||
@@ -185,9 +185,6 @@ class StockEntry(StockController):
|
||||
|
||||
def validate_production_order(self):
|
||||
if self.purpose in ("Manufacture", "Material Transfer for Manufacture"):
|
||||
if not self.bom_no:
|
||||
frappe.throw(_("BOM No is mandatory"))
|
||||
|
||||
# check if production order is entered
|
||||
if not self.production_order:
|
||||
frappe.throw(_("Production order number is mandatory for stock entry purpose manufacture"))
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
"doctype": "Report",
|
||||
"idx": 1,
|
||||
"is_standard": "Yes",
|
||||
"modified": "2015-04-07 08:18:14.440193",
|
||||
"modified": "2015-06-10 15:52:49.492144",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Ordered Items To Be Delivered",
|
||||
"owner": "Administrator",
|
||||
"query": "select \n `tabSales Order`.`name` as \"Sales Order:Link/Sales Order:120\",\n `tabSales Order`.`customer` as \"Customer:Link/Customer:120\",\n `tabSales Order`.`transaction_date` as \"Date:Date\",\n `tabSales Order`.`project_name` as \"Project\",\n `tabSales Order Item`.item_code as \"Item:Link/Item:120\",\n `tabSales Order Item`.qty as \"Qty:Float:140\",\n `tabSales Order Item`.delivered_qty as \"Delivered Qty:Float:140\",\n (`tabSales Order Item`.qty - ifnull(`tabSales Order Item`.delivered_qty, 0)) as \"Qty to Deliver:Float:140\",\n `tabSales Order Item`.base_rate as \"Rate:Float:140\",\n `tabSales Order Item`.base_amount as \"Amount:Float:140\",\n ((`tabSales Order Item`.qty - ifnull(`tabSales Order Item`.delivered_qty, 0))*`tabSales Order Item`.base_rate) as \"Amount to Deliver:Float:140\",\n `tabBin`.actual_qty as \"Available Qty:Float:120\",\n `tabBin`.projected_qty as \"Projected Qty:Float:120\",\n `tabSales Order`.`delivery_date` as \"Expected Delivery Date:Date:120\",\n `tabSales Order Item`.item_name as \"Item Name::150\",\n `tabSales Order Item`.description as \"Description::200\",\n `tabSales Order Item`.item_group as \"Item Group:Link/Item Group:120\"\nfrom\n `tabSales Order`, `tabSales Order Item`, `tabBin`\nwhere\n `tabSales Order Item`.`parent` = `tabSales Order`.`name`\n and `tabSales Order`.docstatus = 1\n and `tabSales Order`.status != \"Stopped\"\n and ifnull(`tabSales Order Item`.delivered_qty,0) < ifnull(`tabSales Order Item`.qty,0)\n and `tabBin`.item_code = `tabSales Order Item`.item_code\n and `tabBin`.warehouse = `tabSales Order Item`.warehouse\norder by `tabSales Order`.transaction_date asc",
|
||||
"query": "select \n `tabSales Order`.`name` as \"Sales Order:Link/Sales Order:120\",\n `tabSales Order`.`customer` as \"Customer:Link/Customer:120\",\n `tabSales Order`.`transaction_date` as \"Date:Date\",\n `tabSales Order`.`project_name` as \"Project\",\n `tabSales Order Item`.item_code as \"Item:Link/Item:120\",\n `tabSales Order Item`.qty as \"Qty:Float:140\",\n `tabSales Order Item`.delivered_qty as \"Delivered Qty:Float:140\",\n (`tabSales Order Item`.qty - ifnull(`tabSales Order Item`.delivered_qty, 0)) as \"Qty to Deliver:Float:140\",\n `tabSales Order Item`.base_rate as \"Rate:Float:140\",\n `tabSales Order Item`.base_amount as \"Amount:Float:140\",\n ((`tabSales Order Item`.qty - ifnull(`tabSales Order Item`.delivered_qty, 0))*`tabSales Order Item`.base_rate) as \"Amount to Deliver:Float:140\",\n `tabBin`.actual_qty as \"Available Qty:Float:120\",\n `tabBin`.projected_qty as \"Projected Qty:Float:120\",\n `tabSales Order`.`delivery_date` as \"Expected Delivery Date:Date:120\",\n `tabSales Order Item`.item_name as \"Item Name::150\",\n `tabSales Order Item`.description as \"Description::200\",\n `tabSales Order Item`.item_group as \"Item Group:Link/Item Group:120\",\n `tabSales Order Item`.warehouse as \"Warehouse:Link/Warehouse:200\"\nfrom\n `tabSales Order`, `tabSales Order Item`, `tabBin`\nwhere\n `tabSales Order Item`.`parent` = `tabSales Order`.`name`\n and `tabSales Order`.docstatus = 1\n and `tabSales Order`.status != \"Stopped\"\n and ifnull(`tabSales Order Item`.delivered_qty,0) < ifnull(`tabSales Order Item`.qty,0)\n and `tabBin`.item_code = `tabSales Order Item`.item_code\n and `tabBin`.warehouse = `tabSales Order Item`.warehouse\norder by `tabSales Order`.transaction_date asc",
|
||||
"ref_doctype": "Delivery Note",
|
||||
"report_name": "Ordered Items To Be Delivered",
|
||||
"report_type": "Query Report"
|
||||
|
||||
Reference in New Issue
Block a user