Compare commits
142 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0064dc6f4a | ||
|
|
11bf06ad76 | ||
|
|
5c6a2acff7 | ||
|
|
cdbd4218a8 | ||
|
|
701cddfb15 | ||
|
|
4bbf91bea1 | ||
|
|
e481e81e67 | ||
|
|
102b417b52 | ||
|
|
efc2a45835 | ||
|
|
5c119a7e95 | ||
|
|
f7a102ffe3 | ||
|
|
d659343541 | ||
|
|
dbf5e54eab | ||
|
|
5eb139a531 | ||
|
|
9e2358c544 | ||
|
|
8d0ef21911 | ||
|
|
9a8f37c579 | ||
|
|
029f698c65 | ||
|
|
806017c92a | ||
|
|
69951e5d1c | ||
|
|
10fd91c78e | ||
|
|
63d71d7f2f | ||
|
|
777bff6e8d | ||
|
|
1e42a3d028 | ||
|
|
da282d405f | ||
|
|
8f1bb82ab9 | ||
|
|
f2b46635b5 | ||
|
|
a11e14424c | ||
|
|
01441ef37f | ||
|
|
cb665285db | ||
|
|
6b66c387ad | ||
|
|
5e702de710 | ||
|
|
7e79f300a1 | ||
|
|
955902ccad | ||
|
|
b882fa14f4 | ||
|
|
d12d7142c6 | ||
|
|
42db5d76a9 | ||
|
|
bd4030bf85 | ||
|
|
a83337a2dd | ||
|
|
e51e5238ec | ||
|
|
5d5fe5d9d5 | ||
|
|
b476c989a4 | ||
|
|
7f0406f281 | ||
|
|
33f6b9d6e8 | ||
|
|
c196037cb0 | ||
|
|
866103bf66 | ||
|
|
528eb4e4ff | ||
|
|
481454298d | ||
|
|
8a0b7cece1 | ||
|
|
b4eba77f7b | ||
|
|
b0a9581e59 | ||
|
|
6472bdace2 | ||
|
|
c95b9f9221 | ||
|
|
a4db83a934 | ||
|
|
28acaeb345 | ||
|
|
5fbb757c2c | ||
|
|
df07c964f7 | ||
|
|
0e2a088ac4 | ||
|
|
ffc2f8885b | ||
|
|
a1ffacaf0b | ||
|
|
8c52258e6d | ||
|
|
ffe8af3f2f | ||
|
|
fe5728718f | ||
|
|
424b4a4b36 | ||
|
|
2a3d7e660f | ||
|
|
a0a43ca4e4 | ||
|
|
9cd9836e18 | ||
|
|
39a3f50732 | ||
|
|
ba7221c332 | ||
|
|
6a45588a2c | ||
|
|
ab9d755e4d | ||
|
|
1cf8bd8767 | ||
|
|
a4f99428d7 | ||
|
|
e761fe89e2 | ||
|
|
d51f805b78 | ||
|
|
9a064e9ced | ||
|
|
9dc1b00d87 | ||
|
|
9373ba96d5 | ||
|
|
a402079cd4 | ||
|
|
2ca388b0a5 | ||
|
|
6ebcc5c006 | ||
|
|
6a2edee914 | ||
|
|
de69ad0a48 | ||
|
|
25a4bd02f4 | ||
|
|
a3d058938e | ||
|
|
4cae8a0d54 | ||
|
|
454b6f9f8a | ||
|
|
9f1b59dfc6 | ||
|
|
74f64b67db | ||
|
|
2117afba07 | ||
|
|
e409d0d70b | ||
|
|
50125b35d2 | ||
|
|
c38527ef5f | ||
|
|
facde47c6c | ||
|
|
20dc79ac99 | ||
|
|
61da43f793 | ||
|
|
af30c3fdfd | ||
|
|
68888a21ec | ||
|
|
7d7661c9ed | ||
|
|
fbda00eef0 | ||
|
|
a0212d8014 | ||
|
|
c8d2604afc | ||
|
|
861453279d | ||
|
|
be96600c1c | ||
|
|
8709c51e84 | ||
|
|
6fc0262cb6 | ||
|
|
4b5ced03ec | ||
|
|
a888e29b0a | ||
|
|
ae2e8996b0 | ||
|
|
1c2bbd77a0 | ||
|
|
2ffba327ac | ||
|
|
4764f3ea1d | ||
|
|
104deeebb5 | ||
|
|
2a9e4e9a32 | ||
|
|
a38a7b8e76 | ||
|
|
88eedb7397 | ||
|
|
605cc93c90 | ||
|
|
1644fce273 | ||
|
|
8cc2bf7fcf | ||
|
|
fe6409debf | ||
|
|
edc58619d1 | ||
|
|
85800fa929 | ||
|
|
60ec0128a2 | ||
|
|
90e0700e24 | ||
|
|
48156e3d8b | ||
|
|
8b353e5e15 | ||
|
|
fcbd4d7638 | ||
|
|
9409efe02a | ||
|
|
b645a217fd | ||
|
|
ef295d2977 | ||
|
|
2d0e31b479 | ||
|
|
2678ed181a | ||
|
|
1fce0b1f79 | ||
|
|
649660d9f0 | ||
|
|
797e0713ea | ||
|
|
6a0ffabbd0 | ||
|
|
56f58cfa68 | ||
|
|
677ef0c3cf | ||
|
|
64367a905a | ||
|
|
c565de2c12 | ||
|
|
908f2dc0fd | ||
|
|
0b1a8e13fd |
File diff suppressed because one or more lines are too long
@@ -95,9 +95,10 @@ cur_frm.cscript.add_toolbar_buttons = function(doc) {
|
||||
wn.route_options = {
|
||||
"account": doc.name,
|
||||
"from_date": sys_defaults.year_start_date,
|
||||
"to_date": sys_defaults.year_end_date
|
||||
"to_date": sys_defaults.year_end_date,
|
||||
"company": doc.company
|
||||
};
|
||||
wn.set_route("general-ledger");
|
||||
wn.set_route("query-report", "General Ledger");
|
||||
}, "icon-table");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,6 +211,9 @@ class DocType:
|
||||
|
||||
# Validate properties before merging
|
||||
if merge:
|
||||
if not webnotes.conn.exists("Account", new):
|
||||
webnotes.throw(_("Account ") + new +_(" does not exists"))
|
||||
|
||||
val = list(webnotes.conn.get_value("Account", new_account,
|
||||
["group_or_ledger", "debit_or_credit", "is_pl_account"]))
|
||||
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
from webnotes.utils import cint, cstr
|
||||
from webnotes import msgprint, _
|
||||
from webnotes import _
|
||||
|
||||
class DocType:
|
||||
def __init__(self, d, dl):
|
||||
@@ -16,6 +15,11 @@ class DocType:
|
||||
webnotes.conn.set_default("auto_accounting_for_stock", self.doc.auto_accounting_for_stock)
|
||||
|
||||
if self.doc.auto_accounting_for_stock:
|
||||
for wh in webnotes.conn.sql("select name from `tabWarehouse`"):
|
||||
wh_bean = webnotes.bean("Warehouse", wh[0])
|
||||
warehouse_list = webnotes.conn.sql("select name, company from tabWarehouse", as_dict=1)
|
||||
warehouse_with_no_company = [d.name for d in warehouse_list if not d.company]
|
||||
if warehouse_with_no_company:
|
||||
webnotes.throw(_("Company is missing in following warehouses") + ": \n" +
|
||||
"\n".join(warehouse_with_no_company))
|
||||
for wh in warehouse_list:
|
||||
wh_bean = webnotes.bean("Warehouse", wh.name)
|
||||
wh_bean.save()
|
||||
@@ -120,8 +120,10 @@ cur_frm.cscript.refresh = function(doc) {
|
||||
"voucher_no": doc.name,
|
||||
"from_date": doc.posting_date,
|
||||
"to_date": doc.posting_date,
|
||||
"company": doc.company,
|
||||
group_by_voucher: 0
|
||||
};
|
||||
wn.set_route("general-ledger");
|
||||
wn.set_route("query-report", "General Ledger");
|
||||
}, "icon-table");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,13 +140,13 @@ def gl_entry_details(doctype, txt, searchfield, start, page_len, filters):
|
||||
and ifnull(gle.%(account_type)s, 0) > 0
|
||||
and (select ifnull(abs(sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))), 0)
|
||||
from `tabGL Entry`
|
||||
where against_voucher_type = '%(dt)s'
|
||||
where account = '%(acc)s'
|
||||
and against_voucher_type = '%(dt)s'
|
||||
and against_voucher = gle.voucher_no
|
||||
and voucher_no != gle.voucher_no)
|
||||
!= abs(ifnull(gle.debit, 0) - ifnull(gle.credit, 0)
|
||||
)
|
||||
and if(gle.voucher_type='Sales Invoice', (select is_pos from `tabSales Invoice`
|
||||
where name=gle.voucher_no), 0)=0
|
||||
!= abs(ifnull(gle.debit, 0) - ifnull(gle.credit, 0))
|
||||
and if(gle.voucher_type='Sales Invoice', ifnull((select is_pos from `tabSales Invoice`
|
||||
where name=gle.voucher_no), 0), 0)=0
|
||||
%(mcond)s
|
||||
ORDER BY gle.posting_date desc, gle.voucher_no desc
|
||||
limit %(start)s, %(page_len)s""" % {
|
||||
|
||||
@@ -7,7 +7,7 @@ cur_frm.cscript.onload = function(doc,cdt,cdn){
|
||||
});
|
||||
|
||||
cur_frm.set_query("selling_price_list", function() {
|
||||
return { filters: { buying_or_selling: "Selling" } };
|
||||
return { filters: { selling: 1 } };
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -35,8 +35,10 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
|
||||
"voucher_no": doc.name,
|
||||
"from_date": doc.posting_date,
|
||||
"to_date": doc.posting_date,
|
||||
"company": doc.company,
|
||||
group_by_voucher: 0
|
||||
};
|
||||
wn.set_route("general-ledger");
|
||||
wn.set_route("query-report", "General Ledger");
|
||||
}, "icon-table");
|
||||
}
|
||||
|
||||
|
||||
@@ -350,7 +350,6 @@ class DocType(BuyingController):
|
||||
# item gl entries
|
||||
stock_item_and_auto_accounting_for_stock = False
|
||||
stock_items = self.get_stock_items()
|
||||
rounding_diff = 0.0
|
||||
for item in self.doclist.get({"parentfield": "entries"}):
|
||||
if auto_accounting_for_stock and item.item_code in stock_items:
|
||||
if flt(item.valuation_rate):
|
||||
@@ -359,13 +358,7 @@ class DocType(BuyingController):
|
||||
# expense will be booked in sales invoice
|
||||
stock_item_and_auto_accounting_for_stock = True
|
||||
|
||||
valuation_amt = flt(flt(item.valuation_rate) * flt(item.qty) * \
|
||||
flt(item.conversion_factor), self.precision("valuation_rate", item))
|
||||
|
||||
rounding_diff += (flt(item.amount, self.precision("amount", item)) +
|
||||
flt(item.item_tax_amount, self.precision("item_tax_amount", item)) +
|
||||
flt(item.rm_supp_cost, self.precision("rm_supp_cost", item)) -
|
||||
valuation_amt)
|
||||
valuation_amt = item.amount + item.item_tax_amount + item.rm_supp_cost
|
||||
|
||||
gl_entries.append(
|
||||
self.get_gl_dict({
|
||||
@@ -393,12 +386,6 @@ class DocType(BuyingController):
|
||||
# this will balance out valuation amount included in cost of goods sold
|
||||
expenses_included_in_valuation = \
|
||||
self.get_company_default("expenses_included_in_valuation")
|
||||
|
||||
if rounding_diff:
|
||||
import operator
|
||||
cost_center_with_max_value = max(valuation_tax.iteritems(),
|
||||
key=operator.itemgetter(1))[0]
|
||||
valuation_tax[cost_center_with_max_value] -= flt(rounding_diff)
|
||||
|
||||
for cost_center, amount in valuation_tax.items():
|
||||
gl_entries.append(
|
||||
|
||||
@@ -54,8 +54,10 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
"voucher_no": doc.name,
|
||||
"from_date": doc.posting_date,
|
||||
"to_date": doc.posting_date,
|
||||
"company": doc.company,
|
||||
group_by_voucher: 0
|
||||
};
|
||||
wn.set_route("general-ledger");
|
||||
wn.set_route("query-report", "General Ledger");
|
||||
}, "icon-table");
|
||||
|
||||
var percent_paid = cint(flt(doc.grand_total - doc.outstanding_amount) / flt(doc.grand_total) * 100);
|
||||
|
||||
@@ -364,7 +364,6 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
|
||||
order by account asc, debit asc""", si.doc.name, as_dict=1)
|
||||
self.assertTrue(gl_entries)
|
||||
# print gl_entries
|
||||
|
||||
stock_in_hand = webnotes.conn.get_value("Account", {"master_name": "_Test Warehouse - _TC"})
|
||||
|
||||
@@ -566,16 +565,17 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
where against_invoice=%s""", si.doc.name))
|
||||
|
||||
def test_recurring_invoice(self):
|
||||
from webnotes.utils import now_datetime, get_first_day, get_last_day, add_to_date
|
||||
today = now_datetime().date()
|
||||
|
||||
from webnotes.utils import get_first_day, get_last_day, add_to_date, nowdate, getdate
|
||||
from accounts.utils import get_fiscal_year
|
||||
today = nowdate()
|
||||
base_si = webnotes.bean(copy=test_records[0])
|
||||
base_si.doc.fields.update({
|
||||
"convert_into_recurring_invoice": 1,
|
||||
"recurring_type": "Monthly",
|
||||
"notification_email_address": "test@example.com, test1@example.com, test2@example.com",
|
||||
"repeat_on_day_of_month": today.day,
|
||||
"repeat_on_day_of_month": getdate(today).day,
|
||||
"posting_date": today,
|
||||
"fiscal_year": get_fiscal_year(today)[0],
|
||||
"invoice_period_from_date": get_first_day(today),
|
||||
"invoice_period_to_date": get_last_day(today)
|
||||
})
|
||||
|
||||
@@ -45,7 +45,7 @@ def merge_similar_entries(gl_map):
|
||||
same_head.credit = flt(same_head.credit) + flt(entry.credit)
|
||||
else:
|
||||
merged_gl_map.append(entry)
|
||||
|
||||
|
||||
# filter zero debit and credit entries
|
||||
merged_gl_map = filter(lambda x: flt(x.debit)!=0 or flt(x.credit)!=0, merged_gl_map)
|
||||
return merged_gl_map
|
||||
|
||||
@@ -175,9 +175,10 @@ erpnext.AccountsChart = Class.extend({
|
||||
wn.route_options = {
|
||||
"account": node.data('label'),
|
||||
"from_date": sys_defaults.year_start_date,
|
||||
"to_date": sys_defaults.year_end_date
|
||||
"to_date": sys_defaults.year_end_date,
|
||||
"company": me.company
|
||||
};
|
||||
wn.set_route("general-ledger");
|
||||
wn.set_route("query-report", "General Ledger");
|
||||
},
|
||||
rename: function() {
|
||||
var node = this.selected_node();
|
||||
|
||||
@@ -9,17 +9,19 @@ from accounts.report.accounts_receivable.accounts_receivable import get_ageing_d
|
||||
|
||||
def execute(filters=None):
|
||||
if not filters: filters = {}
|
||||
columns = get_columns()
|
||||
supplier_naming_by = webnotes.conn.get_value("Buying Settings", None, "supp_master_name")
|
||||
columns = get_columns(supplier_naming_by)
|
||||
entries = get_gl_entries(filters)
|
||||
account_supplier = dict(webnotes.conn.sql("""select account.name, supplier.supplier_name
|
||||
from `tabAccount` account, `tabSupplier` supplier
|
||||
where account.master_type="Supplier" and supplier.name=account.master_name"""))
|
||||
|
||||
account_map = dict(((r.name, r) for r in webnotes.conn.sql("""select acc.name,
|
||||
supp.supplier_name, supp.name as supplier
|
||||
from `tabAccount` acc, `tabSupplier` supp
|
||||
where acc.master_type="Supplier" and supp.name=acc.master_name""", as_dict=1)))
|
||||
|
||||
entries_after_report_date = [[gle.voucher_type, gle.voucher_no]
|
||||
for gle in get_gl_entries(filters, before_report_date=False)]
|
||||
|
||||
|
||||
account_supplier_type_map = get_account_supplier_type_map()
|
||||
pi_map = get_pi_map()
|
||||
voucher_detail_map = get_voucher_details()
|
||||
|
||||
# Age of the invoice on this date
|
||||
age_on = getdate(filters.get("report_date")) > getdate(nowdate()) \
|
||||
@@ -29,46 +31,57 @@ def execute(filters=None):
|
||||
for gle in entries:
|
||||
if cstr(gle.against_voucher) == gle.voucher_no or not gle.against_voucher \
|
||||
or [gle.against_voucher_type, gle.against_voucher] in entries_after_report_date:
|
||||
if gle.voucher_type == "Purchase Invoice":
|
||||
pi_info = pi_map.get(gle.voucher_no)
|
||||
due_date = pi_info.get("due_date")
|
||||
bill_no = pi_info.get("bill_no")
|
||||
bill_date = pi_info.get("bill_date")
|
||||
else:
|
||||
due_date = bill_no = bill_date = ""
|
||||
|
||||
voucher_details = voucher_detail_map.get(gle.voucher_type, {}).get(gle.voucher_no, {})
|
||||
|
||||
invoiced_amount = gle.credit > 0 and gle.credit or 0
|
||||
outstanding_amount = get_outstanding_amount(gle,
|
||||
filters.get("report_date") or nowdate())
|
||||
|
||||
if abs(flt(outstanding_amount)) > 0.01:
|
||||
paid_amount = invoiced_amount - outstanding_amount
|
||||
row = [gle.posting_date, gle.account, account_supplier.get(gle.account, ""),
|
||||
gle.voucher_type, gle.voucher_no,
|
||||
gle.remarks, account_supplier_type_map.get(gle.account), due_date, bill_no,
|
||||
bill_date, invoiced_amount, paid_amount, outstanding_amount]
|
||||
row = [gle.posting_date, gle.account, gle.voucher_type, gle.voucher_no,
|
||||
voucher_details.get("due_date", ""), voucher_details.get("bill_no", ""),
|
||||
voucher_details.get("bill_date", ""), invoiced_amount,
|
||||
paid_amount, outstanding_amount]
|
||||
|
||||
# Ageing
|
||||
if filters.get("ageing_based_on") == "Due Date":
|
||||
ageing_based_on_date = due_date
|
||||
ageing_based_on_date = voucher_details.get("due_date", "")
|
||||
else:
|
||||
ageing_based_on_date = gle.posting_date
|
||||
|
||||
row += get_ageing_data(age_on, ageing_based_on_date, outstanding_amount)
|
||||
row += get_ageing_data(age_on, ageing_based_on_date, outstanding_amount) + \
|
||||
[account_map.get(gle.account).get("supplier") or ""]
|
||||
|
||||
if supplier_naming_by == "Naming Series":
|
||||
row += [account_map.get(gle.account).get("supplier_name") or ""]
|
||||
|
||||
row += [account_supplier_type_map.get(gle.account), gle.remarks]
|
||||
data.append(row)
|
||||
|
||||
|
||||
for i in range(0, len(data)):
|
||||
data[i].insert(4, """<a href="%s"><i class="icon icon-share" style="cursor: pointer;"></i></a>""" \
|
||||
% ("/".join(["#Form", data[i][2], data[i][3]]),))
|
||||
|
||||
return columns, data
|
||||
|
||||
def get_columns():
|
||||
return [
|
||||
"Posting Date:Date:80", "Account:Link/Account:150", "Supplier::150", "Voucher Type::110",
|
||||
"Voucher No::120", "Remarks::150", "Supplier Type:Link/Supplier Type:120",
|
||||
"Due Date:Date:80", "Bill No::80", "Bill Date:Date:80",
|
||||
def get_columns(supplier_naming_by):
|
||||
columns = [
|
||||
"Posting Date:Date:80", "Account:Link/Account:150", "Voucher Type::110",
|
||||
"Voucher No::120", "::30", "Due Date:Date:80", "Bill No::80", "Bill Date:Date:80",
|
||||
"Invoiced Amount:Currency:100", "Paid Amount:Currency:100",
|
||||
"Outstanding Amount:Currency:100", "Age:Int:50", "0-30:Currency:100",
|
||||
"30-60:Currency:100", "60-90:Currency:100", "90-Above:Currency:100"
|
||||
"30-60:Currency:100", "60-90:Currency:100", "90-Above:Currency:100",
|
||||
"Supplier:Link/Supplier:150"
|
||||
]
|
||||
|
||||
|
||||
if supplier_naming_by == "Naming Series":
|
||||
columns += ["Supplier Name::110"]
|
||||
|
||||
columns += ["Supplier Type:Link/Supplier Type:120", "Remarks::150"]
|
||||
|
||||
return columns
|
||||
|
||||
def get_gl_entries(filters, before_report_date=True):
|
||||
conditions, supplier_accounts = get_conditions(filters, before_report_date)
|
||||
gl_entries = []
|
||||
@@ -106,20 +119,21 @@ def get_conditions(filters, before_report_date=True):
|
||||
|
||||
def get_account_supplier_type_map():
|
||||
account_supplier_type_map = {}
|
||||
for each in webnotes.conn.sql("""select t2.name, t1.supplier_type from `tabSupplier` t1,
|
||||
`tabAccount` t2 where t1.name = t2.master_name group by t2.name"""):
|
||||
for each in webnotes.conn.sql("""select acc.name, supp.supplier_type from `tabSupplier` supp,
|
||||
`tabAccount` acc where supp.name = acc.master_name group by acc.name"""):
|
||||
account_supplier_type_map[each[0]] = each[1]
|
||||
|
||||
|
||||
return account_supplier_type_map
|
||||
|
||||
def get_pi_map():
|
||||
""" get due_date from sales invoice """
|
||||
pi_map = {}
|
||||
for t in webnotes.conn.sql("""select name, due_date, bill_no, bill_date
|
||||
from `tabPurchase Invoice`""", as_dict=1):
|
||||
pi_map[t.name] = t
|
||||
def get_voucher_details():
|
||||
voucher_details = {}
|
||||
for dt in ["Purchase Invoice", "Journal Voucher"]:
|
||||
voucher_details.setdefault(dt, webnotes._dict())
|
||||
for t in webnotes.conn.sql("""select name, due_date, bill_no, bill_date
|
||||
from `tab%s`""" % dt, as_dict=1):
|
||||
voucher_details[dt].setdefault(t.name, t)
|
||||
|
||||
return pi_map
|
||||
return voucher_details
|
||||
|
||||
def get_outstanding_amount(gle, report_date):
|
||||
payment_amount = webnotes.conn.sql("""
|
||||
|
||||
@@ -15,20 +15,28 @@ class AccountsReceivableReport(object):
|
||||
else self.filters.report_date
|
||||
|
||||
def run(self):
|
||||
return self.get_columns(), self.get_data()
|
||||
customer_naming_by = webnotes.conn.get_value("Selling Settings", None, "cust_master_name")
|
||||
return self.get_columns(customer_naming_by), self.get_data(customer_naming_by)
|
||||
|
||||
def get_columns(self):
|
||||
return [
|
||||
def get_columns(self, customer_naming_by):
|
||||
columns = [
|
||||
"Posting Date:Date:80", "Account:Link/Account:150",
|
||||
"Voucher Type::110", "Voucher No::120", "::30",
|
||||
"Due Date:Date:80",
|
||||
"Invoiced Amount:Currency:100", "Payment Received:Currency:100",
|
||||
"Outstanding Amount:Currency:100", "Age:Int:50", "0-30:Currency:100",
|
||||
"30-60:Currency:100", "60-90:Currency:100", "90-Above:Currency:100",
|
||||
"Customer:Link/Customer:200", "Territory:Link/Territory:80", "Remarks::200"
|
||||
"Customer:Link/Customer:200"
|
||||
]
|
||||
|
||||
def get_data(self):
|
||||
|
||||
if customer_naming_by == "Naming Series":
|
||||
columns += ["Customer Name::110"]
|
||||
|
||||
columns += ["Territory:Link/Territory:80", "Remarks::200"]
|
||||
|
||||
return columns
|
||||
|
||||
def get_data(self, customer_naming_by):
|
||||
data = []
|
||||
future_vouchers = self.get_entries_after(self.filters.report_date)
|
||||
for gle in self.get_entries_till(self.filters.report_date):
|
||||
@@ -42,18 +50,23 @@ class AccountsReceivableReport(object):
|
||||
gle.voucher_type, gle.voucher_no, due_date,
|
||||
invoiced_amount, payment_received,
|
||||
outstanding_amount]
|
||||
entry_date = due_date if self.filters.ageing_based_on=="Due Date" \
|
||||
entry_date = due_date if self.filters.ageing_based_on == "Due Date" \
|
||||
else gle.posting_date
|
||||
row += get_ageing_data(self.age_as_on, entry_date, outstanding_amount)
|
||||
row += [self.get_customer(gle.account), self.get_territory(gle.account), gle.remarks]
|
||||
row += get_ageing_data(self.age_as_on, entry_date, outstanding_amount) + \
|
||||
[self.get_customer(gle.account)]
|
||||
|
||||
if customer_naming_by == "Naming Series":
|
||||
row += [self.get_customer_name(gle.account)]
|
||||
|
||||
row += [self.get_territory(gle.account), gle.remarks]
|
||||
data.append(row)
|
||||
|
||||
for i in range(0,len(data)):
|
||||
for i in range(0, len(data)):
|
||||
data[i].insert(4, """<a href="%s"><i class="icon icon-share" style="cursor: pointer;"></i></a>""" \
|
||||
% ("/".join(["#Form", data[i][2], data[i][3]]),))
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def get_entries_after(self, report_date):
|
||||
# returns a distinct list
|
||||
return list(set([(e.voucher_type, e.voucher_no) for e in self.get_gl_entries()
|
||||
@@ -65,30 +78,41 @@ class AccountsReceivableReport(object):
|
||||
if getdate(e.posting_date) <= report_date)
|
||||
|
||||
def is_receivable(self, gle, future_vouchers):
|
||||
return ((not gle.against_voucher) or (gle.against_voucher==gle.voucher_no) or
|
||||
((gle.against_voucher_type, gle.against_voucher) in future_vouchers))
|
||||
return (
|
||||
# advance
|
||||
(not gle.against_voucher) or
|
||||
|
||||
# sales invoice
|
||||
(gle.against_voucher==gle.voucher_no and gle.debit > 0) or
|
||||
|
||||
# entries adjusted with future vouchers
|
||||
((gle.against_voucher_type, gle.against_voucher) in future_vouchers)
|
||||
)
|
||||
|
||||
def get_outstanding_amount(self, gle, report_date):
|
||||
payment_received = 0.0
|
||||
for e in self.get_gl_entries_for(gle.account, gle.voucher_type, gle.voucher_no):
|
||||
if getdate(e.posting_date) <= report_date and e.name!=gle.name:
|
||||
payment_received += (flt(e.credit) - flt(e.debit))
|
||||
|
||||
|
||||
return flt(gle.debit) - flt(gle.credit) - payment_received
|
||||
|
||||
def get_customer(self, account):
|
||||
return self.get_account_map().get(account).get("customer") or ""
|
||||
|
||||
def get_customer_name(self, account):
|
||||
return self.get_account_map().get(account).get("customer_name") or ""
|
||||
|
||||
|
||||
def get_territory(self, account):
|
||||
return self.get_account_map().get(account).get("territory") or ""
|
||||
|
||||
def get_account_map(self):
|
||||
if not hasattr(self, "account_map"):
|
||||
self.account_map = dict(((r.name, r) for r in webnotes.conn.sql("""select
|
||||
account.name, customer.name as customer_name, customer.territory
|
||||
from `tabAccount` account, `tabCustomer` customer
|
||||
where account.master_type="Customer"
|
||||
and customer.name=account.master_name""", as_dict=True)))
|
||||
acc.name, cust.name as customer, cust.customer_name, cust.territory
|
||||
from `tabAccount` acc, `tabCustomer` cust
|
||||
where acc.master_type="Customer"
|
||||
and cust.name=acc.master_name""", as_dict=True)))
|
||||
|
||||
return self.account_map
|
||||
|
||||
@@ -147,7 +171,7 @@ class AccountsReceivableReport(object):
|
||||
|
||||
def execute(filters=None):
|
||||
return AccountsReceivableReport(filters).run()
|
||||
|
||||
|
||||
def get_ageing_data(age_as_on, entry_date, outstanding_amount):
|
||||
# [0-30, 30-60, 60-90, 90-above]
|
||||
outstanding_range = [0.0, 0.0, 0.0, 0.0]
|
||||
|
||||
@@ -11,26 +11,6 @@ wn.query_reports["General Ledger"] = {
|
||||
"default": wn.defaults.get_user_default("company"),
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname":"account",
|
||||
"label": wn._("Account"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Account"
|
||||
},
|
||||
{
|
||||
"fieldname":"voucher_no",
|
||||
"label": wn._("Voucher No"),
|
||||
"fieldtype": "Data",
|
||||
},
|
||||
{
|
||||
"fieldname":"group_by",
|
||||
"label": wn._("Group by"),
|
||||
"fieldtype": "Select",
|
||||
"options": "\nGroup by Account\nGroup by Voucher"
|
||||
},
|
||||
{
|
||||
"fieldtype": "Break",
|
||||
},
|
||||
{
|
||||
"fieldname":"from_date",
|
||||
"label": wn._("From Date"),
|
||||
@@ -46,6 +26,40 @@ wn.query_reports["General Ledger"] = {
|
||||
"default": wn.datetime.get_today(),
|
||||
"reqd": 1,
|
||||
"width": "60px"
|
||||
},
|
||||
{
|
||||
"fieldtype": "Break",
|
||||
},
|
||||
{
|
||||
"fieldname":"account",
|
||||
"label": wn._("Account"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Account",
|
||||
"get_query": function() {
|
||||
var company = wn.query_report.filters_by_name.company.get_value();
|
||||
return {
|
||||
"doctype": "Account",
|
||||
"filters": {
|
||||
"company": company,
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"fieldname":"voucher_no",
|
||||
"label": wn._("Voucher No"),
|
||||
"fieldtype": "Data",
|
||||
},
|
||||
{
|
||||
"fieldname":"group_by_voucher",
|
||||
"label": wn._("Group by Voucher"),
|
||||
"fieldtype": "Check",
|
||||
"default": 1
|
||||
},
|
||||
{
|
||||
"fieldname":"group_by_account",
|
||||
"label": wn._("Group by Account"),
|
||||
"fieldtype": "Check",
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -3,77 +3,175 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
from webnotes.utils import flt
|
||||
from webnotes.utils import cstr, flt
|
||||
from webnotes import _
|
||||
|
||||
def execute(filters=None):
|
||||
validate_filters(filters)
|
||||
account_details = {}
|
||||
for acc in webnotes.conn.sql("""select name, debit_or_credit, group_or_ledger
|
||||
from tabAccount""", as_dict=1):
|
||||
account_details.setdefault(acc.name, acc)
|
||||
|
||||
validate_filters(filters, account_details)
|
||||
|
||||
columns = get_columns()
|
||||
|
||||
if filters.get("group_by"):
|
||||
data = get_grouped_gle(filters)
|
||||
else:
|
||||
data = get_gl_entries(filters)
|
||||
if data:
|
||||
data.append(get_total_row(data))
|
||||
res = get_result(filters, account_details)
|
||||
|
||||
return columns, data
|
||||
return columns, res
|
||||
|
||||
def validate_filters(filters):
|
||||
if filters.get("account") and filters.get("group_by") == "Group by Account":
|
||||
def validate_filters(filters, account_details):
|
||||
if filters.get("account") and filters.get("group_by_account") \
|
||||
and account_details[filters.account].group_or_ledger == "Ledger":
|
||||
webnotes.throw(_("Can not filter based on Account, if grouped by Account"))
|
||||
|
||||
if filters.get("voucher_no") and filters.get("group_by") == "Group by Voucher":
|
||||
if filters.get("voucher_no") and filters.get("group_by_voucher"):
|
||||
webnotes.throw(_("Can not filter based on Voucher No, if grouped by Voucher"))
|
||||
|
||||
if filters.from_date > filters.to_date:
|
||||
webnotes.throw(_("From Date must be before To Date"))
|
||||
|
||||
def get_columns():
|
||||
return ["Posting Date:Date:100", "Account:Link/Account:200", "Debit:Currency:100",
|
||||
"Credit:Currency:100", "Voucher Type::120", "Voucher No::160",
|
||||
"Cost Center:Link/Cost Center:100", "Remarks::200"]
|
||||
return ["Posting Date:Date:100", "Account:Link/Account:200", "Debit:Float:100",
|
||||
"Credit:Float:100", "Voucher Type::120", "Voucher No::160", "Link::20",
|
||||
"Against Account::120", "Cost Center:Link/Cost Center:100", "Remarks::200"]
|
||||
|
||||
def get_result(filters, account_details):
|
||||
gl_entries = get_gl_entries(filters)
|
||||
|
||||
data = get_data_with_opening_closing(filters, account_details, gl_entries)
|
||||
|
||||
result = get_result_as_list(data)
|
||||
|
||||
return result
|
||||
|
||||
def get_gl_entries(filters):
|
||||
return webnotes.conn.sql("""select
|
||||
posting_date, account, debit, credit, voucher_type, voucher_no, cost_center, remarks
|
||||
group_by_condition = "group by voucher_type, voucher_no, account" \
|
||||
if filters.get("group_by_voucher") else "group by name"
|
||||
|
||||
gl_entries = webnotes.conn.sql("""select posting_date, account,
|
||||
sum(ifnull(debit, 0)) as debit, sum(ifnull(credit, 0)) as credit,
|
||||
voucher_type, voucher_no, cost_center, remarks, is_advance, against
|
||||
from `tabGL Entry`
|
||||
where company=%(company)s
|
||||
and posting_date between %(from_date)s and %(to_date)s
|
||||
{conditions}
|
||||
where company=%(company)s {conditions}
|
||||
{group_by_condition}
|
||||
order by posting_date, account"""\
|
||||
.format(conditions=get_conditions(filters)), filters, as_list=1)
|
||||
|
||||
.format(conditions=get_conditions(filters), group_by_condition=group_by_condition),
|
||||
filters, as_dict=1)
|
||||
|
||||
return gl_entries
|
||||
|
||||
def get_conditions(filters):
|
||||
conditions = []
|
||||
if filters.get("account"):
|
||||
conditions.append("account=%(account)s")
|
||||
lft, rgt = webnotes.conn.get_value("Account", filters["account"], ["lft", "rgt"])
|
||||
conditions.append("""account in (select name from tabAccount
|
||||
where lft>=%s and rgt<=%s and docstatus<2)""" % (lft, rgt))
|
||||
else:
|
||||
conditions.append("posting_date between %(from_date)s and %(to_date)s")
|
||||
|
||||
if filters.get("voucher_no"):
|
||||
conditions.append("voucher_no=%(voucher_no)s")
|
||||
|
||||
|
||||
from webnotes.widgets.reportview import build_match_conditions
|
||||
match_conditions = build_match_conditions("GL Entry")
|
||||
if match_conditions: conditions.append(match_conditions)
|
||||
|
||||
return "and {}".format(" and ".join(conditions)) if conditions else ""
|
||||
|
||||
def get_grouped_gle(filters):
|
||||
gle_map = {}
|
||||
gle = get_gl_entries(filters)
|
||||
for d in gle:
|
||||
gle_map.setdefault(d[1 if filters["group_by"]=="Group by Account" else 5], []).append(d)
|
||||
|
||||
|
||||
def get_data_with_opening_closing(filters, account_details, gl_entries):
|
||||
data = []
|
||||
for entries in gle_map.values():
|
||||
subtotal_debit = subtotal_credit = 0.0
|
||||
for entry in entries:
|
||||
data.append(entry)
|
||||
subtotal_debit += flt(entry[2])
|
||||
subtotal_credit += flt(entry[3])
|
||||
|
||||
data.append(["", "Total", subtotal_debit, subtotal_credit, "", "", ""])
|
||||
gle_map = initialize_gle_map(gl_entries)
|
||||
|
||||
opening, total_debit, total_credit, gle_map = get_accountwise_gle(filters, gl_entries, gle_map)
|
||||
|
||||
# Opening for filtered account
|
||||
if filters.get("account"):
|
||||
data += [get_balance_row("Opening", account_details[filters.account].debit_or_credit,
|
||||
opening), {}]
|
||||
|
||||
for acc, acc_dict in gle_map.items():
|
||||
if acc_dict.entries:
|
||||
# Opening for individual ledger, if grouped by account
|
||||
if filters.get("group_by_account"):
|
||||
data.append(get_balance_row("Opening", account_details[acc].debit_or_credit,
|
||||
acc_dict.opening))
|
||||
|
||||
data += acc_dict.entries
|
||||
|
||||
# Totals and closing for individual ledger, if grouped by account
|
||||
if filters.get("group_by_account"):
|
||||
data += [{"account": "Totals", "debit": acc_dict.total_debit,
|
||||
"credit": acc_dict.total_credit},
|
||||
get_balance_row("Closing (Opening + Totals)",
|
||||
account_details[acc].debit_or_credit, (acc_dict.opening
|
||||
+ acc_dict.total_debit - acc_dict.total_credit)), {}]
|
||||
|
||||
# Total debit and credit between from and to date
|
||||
if total_debit or total_credit:
|
||||
data.append({"account": "Totals", "debit": total_debit, "credit": total_credit})
|
||||
|
||||
# Closing for filtered account
|
||||
if filters.get("account"):
|
||||
data.append(get_balance_row("Closing (Opening + Totals)",
|
||||
account_details[filters.account].debit_or_credit,
|
||||
(opening + total_debit - total_credit)))
|
||||
|
||||
if data:
|
||||
data.append(get_total_row(gle))
|
||||
return data
|
||||
|
||||
def initialize_gle_map(gl_entries):
|
||||
gle_map = webnotes._dict()
|
||||
for gle in gl_entries:
|
||||
gle_map.setdefault(gle.account, webnotes._dict({
|
||||
"opening": 0,
|
||||
"entries": [],
|
||||
"total_debit": 0,
|
||||
"total_credit": 0,
|
||||
"closing": 0
|
||||
}))
|
||||
return gle_map
|
||||
|
||||
def get_accountwise_gle(filters, gl_entries, gle_map):
|
||||
opening, total_debit, total_credit = 0, 0, 0
|
||||
|
||||
def get_total_row(gle):
|
||||
total_debit = total_credit = 0.0
|
||||
for d in gle:
|
||||
total_debit += flt(d[2])
|
||||
total_credit += flt(d[3])
|
||||
for gle in gl_entries:
|
||||
amount = flt(gle.debit) - flt(gle.credit)
|
||||
if filters.get("account") and (gle.posting_date < filters.from_date
|
||||
or cstr(gle.is_advance) == "Yes"):
|
||||
gle_map[gle.account].opening += amount
|
||||
opening += amount
|
||||
elif gle.posting_date <= filters.to_date:
|
||||
gle_map[gle.account].entries.append(gle)
|
||||
gle_map[gle.account].total_debit += flt(gle.debit)
|
||||
gle_map[gle.account].total_credit += flt(gle.credit)
|
||||
|
||||
total_debit += flt(gle.debit)
|
||||
total_credit += flt(gle.credit)
|
||||
|
||||
return opening, total_debit, total_credit, gle_map
|
||||
|
||||
def get_balance_row(label, debit_or_credit, balance):
|
||||
return {
|
||||
"account": label,
|
||||
"debit": balance if debit_or_credit=="Debit" else 0,
|
||||
"credit": -1*balance if debit_or_credit=="Credit" else 0,
|
||||
}
|
||||
|
||||
def get_result_as_list(data):
|
||||
result = []
|
||||
for d in data:
|
||||
result.append([d.get("posting_date"), d.get("account"), d.get("debit"),
|
||||
d.get("credit"), d.get("voucher_type"), d.get("voucher_no"),
|
||||
get_voucher_link(d.get("voucher_type"), d.get("voucher_no")),
|
||||
d.get("against"), d.get("cost_center"), d.get("remarks")])
|
||||
|
||||
return result
|
||||
|
||||
def get_voucher_link(voucher_type, voucher_no):
|
||||
icon = ""
|
||||
if voucher_type and voucher_no:
|
||||
icon = """<a href="%s"><i class="icon icon-share" style="cursor: pointer;">
|
||||
</i></a>""" % ("/".join(["#Form", voucher_type, voucher_no]))
|
||||
|
||||
return ["", "Total Debit/Credit", total_debit, total_credit, "", "", ""]
|
||||
return icon
|
||||
@@ -12,7 +12,8 @@ def execute(filters=None):
|
||||
|
||||
item_list = get_items(filters)
|
||||
aii_account_map = get_aii_accounts()
|
||||
item_tax, tax_accounts = get_tax_accounts(item_list, columns)
|
||||
if item_list:
|
||||
item_tax, tax_accounts = get_tax_accounts(item_list, columns)
|
||||
|
||||
data = []
|
||||
for d in item_list:
|
||||
|
||||
@@ -11,7 +11,8 @@ def execute(filters=None):
|
||||
last_col = len(columns)
|
||||
|
||||
item_list = get_items(filters)
|
||||
item_tax, tax_accounts = get_tax_accounts(item_list, columns)
|
||||
if item_list:
|
||||
item_tax, tax_accounts = get_tax_accounts(item_list, columns)
|
||||
|
||||
data = []
|
||||
for d in item_list:
|
||||
@@ -39,7 +40,6 @@ def get_columns():
|
||||
"Qty:Float:120", "Rate:Currency:120", "Amount:Currency:120"
|
||||
]
|
||||
|
||||
|
||||
def get_conditions(filters):
|
||||
conditions = ""
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import webnotes
|
||||
from webnotes.utils import nowdate, nowtime, cstr, flt, now, getdate, add_months
|
||||
from webnotes.utils import nowdate, cstr, flt, now, getdate, add_months
|
||||
from webnotes.model.doc import addchild
|
||||
from webnotes import msgprint, _
|
||||
from webnotes.utils import formatdate
|
||||
@@ -16,7 +16,7 @@ class BudgetError(webnotes.ValidationError): pass
|
||||
|
||||
|
||||
def get_fiscal_year(date=None, fiscal_year=None, label="Date", verbose=1):
|
||||
return get_fiscal_years(date, fiscal_year, label, verbose=1)[0]
|
||||
return get_fiscal_years(date, fiscal_year, label, verbose)[0]
|
||||
|
||||
def get_fiscal_years(date=None, fiscal_year=None, label="Date", verbose=1):
|
||||
# if year start date is 2012-04-01, year end date should be 2013-03-31 (hence subdate)
|
||||
@@ -31,6 +31,8 @@ def get_fiscal_years(date=None, fiscal_year=None, label="Date", verbose=1):
|
||||
|
||||
if not fy:
|
||||
error_msg = """%s %s not in any Fiscal Year""" % (label, formatdate(date))
|
||||
error_msg = """{msg}: {date}""".format(msg=_("Fiscal Year does not exist for date"),
|
||||
date=formatdate(date))
|
||||
if verbose: webnotes.msgprint(error_msg)
|
||||
raise FiscalYearError, error_msg
|
||||
|
||||
@@ -62,7 +64,6 @@ def get_balance_on(account=None, date=None):
|
||||
try:
|
||||
year_start_date = get_fiscal_year(date, verbose=0)[1]
|
||||
except FiscalYearError, e:
|
||||
from webnotes.utils import getdate
|
||||
if getdate(date) > getdate(nowdate()):
|
||||
# if fiscal year not found and the date is greater than today
|
||||
# get fiscal year for today's date and its corresponding year start date
|
||||
@@ -220,17 +221,26 @@ def get_cost_center_list(doctype, txt, searchfield, start, page_len, filters):
|
||||
tuple(filter_values + ["%%%s%%" % txt, start, page_len]))
|
||||
|
||||
def remove_against_link_from_jv(ref_type, ref_no, against_field):
|
||||
webnotes.conn.sql("""update `tabJournal Voucher Detail` set `%s`=null,
|
||||
modified=%s, modified_by=%s
|
||||
where `%s`=%s and docstatus < 2""" % (against_field, "%s", "%s", against_field, "%s"),
|
||||
(now(), webnotes.session.user, ref_no))
|
||||
linked_jv = webnotes.conn.sql_list("""select parent from `tabJournal Voucher Detail`
|
||||
where `%s`=%s and docstatus < 2""" % (against_field, "%s"), (ref_no))
|
||||
|
||||
if linked_jv:
|
||||
webnotes.conn.sql("""update `tabJournal Voucher Detail` set `%s`=null,
|
||||
modified=%s, modified_by=%s
|
||||
where `%s`=%s and docstatus < 2""" % (against_field, "%s", "%s", against_field, "%s"),
|
||||
(now(), webnotes.session.user, ref_no))
|
||||
|
||||
webnotes.conn.sql("""update `tabGL Entry`
|
||||
set against_voucher_type=null, against_voucher=null,
|
||||
modified=%s, modified_by=%s
|
||||
where against_voucher_type=%s and against_voucher=%s
|
||||
and voucher_no != ifnull(against_voucher, '')""",
|
||||
(now(), webnotes.session.user, ref_type, ref_no))
|
||||
webnotes.conn.sql("""update `tabGL Entry`
|
||||
set against_voucher_type=null, against_voucher=null,
|
||||
modified=%s, modified_by=%s
|
||||
where against_voucher_type=%s and against_voucher=%s
|
||||
and voucher_no != ifnull(against_voucher, '')""",
|
||||
(now(), webnotes.session.user, ref_type, ref_no))
|
||||
|
||||
webnotes.msgprint("{msg} {linked_jv}".format(msg = _("""Following linked Journal Vouchers \
|
||||
made against this transaction has been unlinked. You can link them again with other \
|
||||
transactions via Payment Reconciliation Tool."""), linked_jv="\n".join(linked_jv)))
|
||||
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_company_default(company, fieldname):
|
||||
@@ -368,4 +378,4 @@ def get_account_for(account_for_doctype, account_for):
|
||||
account_for_field = "account_type"
|
||||
|
||||
return webnotes.conn.get_value("Account", {account_for_field: account_for_doctype,
|
||||
"master_name": account_for})
|
||||
"master_name": account_for})
|
||||
@@ -22,7 +22,7 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
||||
if(this.frm.fields_dict.buying_price_list) {
|
||||
this.frm.set_query("buying_price_list", function() {
|
||||
return{
|
||||
filters: { 'buying_or_selling': "Buying" }
|
||||
filters: { 'buying': 1 }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ class TestPurchaseOrder(unittest.TestCase):
|
||||
|
||||
pr = make_purchase_receipt(po.doc.name)
|
||||
pr[0]["supplier_warehouse"] = "_Test Warehouse 1 - _TC"
|
||||
|
||||
pr[0]["posting_date"] = "2013-05-12"
|
||||
self.assertEquals(pr[0]["doctype"], "Purchase Receipt")
|
||||
self.assertEquals(len(pr), len(test_records[0]))
|
||||
|
||||
@@ -52,7 +52,7 @@ class TestPurchaseOrder(unittest.TestCase):
|
||||
|
||||
self.assertEquals(pr[0]["doctype"], "Purchase Receipt")
|
||||
self.assertEquals(len(pr), len(test_records[0]))
|
||||
|
||||
pr[0]["posting_date"] = "2013-05-12"
|
||||
pr[0].naming_series = "_T-Purchase Receipt-"
|
||||
pr[1].qty = 4.0
|
||||
pr_bean = webnotes.bean(pr)
|
||||
@@ -66,6 +66,7 @@ class TestPurchaseOrder(unittest.TestCase):
|
||||
|
||||
pr1 = make_purchase_receipt(po.doc.name)
|
||||
pr1[0].naming_series = "_T-Purchase Receipt-"
|
||||
pr1[0]["posting_date"] = "2013-05-12"
|
||||
pr1[1].qty = 8
|
||||
pr1_bean = webnotes.bean(pr1)
|
||||
pr1_bean.insert()
|
||||
@@ -88,7 +89,7 @@ class TestPurchaseOrder(unittest.TestCase):
|
||||
|
||||
self.assertEquals(pi[0]["doctype"], "Purchase Invoice")
|
||||
self.assertEquals(len(pi), len(test_records[0]))
|
||||
|
||||
pi[0]["posting_date"] = "2013-05-12"
|
||||
pi[0].bill_no = "NA"
|
||||
webnotes.bean(pi).insert()
|
||||
|
||||
|
||||
@@ -95,6 +95,6 @@ cur_frm.cscript.make_contact = function() {
|
||||
|
||||
cur_frm.fields_dict['default_price_list'].get_query = function(doc,cdt,cdn) {
|
||||
return{
|
||||
filters:{'buying_or_selling': "Buying"}
|
||||
filters:{'buying': 1}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
from webnotes import msgprint, _
|
||||
from webnotes import msgprint, _, throw
|
||||
from webnotes.utils import getdate, flt, add_days, cstr
|
||||
import json
|
||||
|
||||
@@ -90,7 +90,7 @@ def _get_price_list_rate(args, item_bean, meta):
|
||||
# try fetching from price list
|
||||
if args.buying_price_list and args.price_list_currency:
|
||||
price_list_rate = webnotes.conn.sql("""select ref_rate from `tabItem Price`
|
||||
where price_list=%s and item_code=%s and buying_or_selling='Buying'""",
|
||||
where price_list=%s and item_code=%s and buying=1""",
|
||||
(args.buying_price_list, args.item_code), as_dict=1)
|
||||
|
||||
if price_list_rate:
|
||||
@@ -122,14 +122,12 @@ def _validate_item_details(args, item):
|
||||
|
||||
# validate if purchase item or subcontracted item
|
||||
if item.is_purchase_item != "Yes":
|
||||
msgprint(_("Item") + (" %s: " % item.name) + _("not a purchase item"),
|
||||
raise_exception=True)
|
||||
throw(_("Item") + (" %s: " % item.name) + _("not a purchase item"))
|
||||
|
||||
if args.is_subcontracted == "Yes" and item.is_sub_contracted_item != "Yes":
|
||||
msgprint(_("Item") + (" %s: " % item.name) +
|
||||
throw(_("Item") + (" %s: " % item.name) +
|
||||
_("not a sub-contracted item.") +
|
||||
_("Please select a sub-contracted item or do not sub-contract the transaction."),
|
||||
raise_exception=True)
|
||||
_("Please select a sub-contracted item or do not sub-contract the transaction."))
|
||||
|
||||
def get_last_purchase_details(item_code, doc_name=None, conversion_rate=1.0):
|
||||
"""returns last purchase details in stock uom"""
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"app_name": "ERPNext",
|
||||
"app_version": "3.3.0",
|
||||
"app_version": "3.5.0",
|
||||
"base_template": "app/portal/templates/base.html",
|
||||
"modules": {
|
||||
"Accounts": {
|
||||
@@ -74,5 +74,5 @@
|
||||
"type": "module"
|
||||
}
|
||||
},
|
||||
"requires_framework_version": "==3.3.0"
|
||||
"requires_framework_version": "==3.5.0"
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
from webnotes import _, msgprint
|
||||
from webnotes import _, msgprint, throw
|
||||
from webnotes.utils import flt, cint, today, cstr
|
||||
from webnotes.model.code import get_obj
|
||||
from setup.utils import get_company_currency
|
||||
@@ -50,8 +50,8 @@ class AccountsController(TransactionBase):
|
||||
|
||||
if accounts:
|
||||
if not filter(lambda x: cstr(x.freeze_account) in ["", "No"], accounts):
|
||||
msgprint(_("Account for this ") + fieldname + _(" has been freezed. ") +
|
||||
self.doc.doctype + _(" can not be made."), raise_exception=1)
|
||||
throw(_("Account for this ") + fieldname + _(" has been freezed. ") +
|
||||
self.doc.doctype + _(" can not be made."))
|
||||
|
||||
def set_price_list_currency(self, buying_or_selling):
|
||||
if self.meta.get_field("currency"):
|
||||
@@ -179,17 +179,17 @@ class AccountsController(TransactionBase):
|
||||
"""
|
||||
if tax.charge_type in ["On Previous Row Amount", "On Previous Row Total"] and \
|
||||
(not tax.row_id or cint(tax.row_id) >= tax.idx):
|
||||
msgprint((_("Row") + " # %(idx)s [%(taxes_doctype)s]: " + \
|
||||
throw((_("Row") + " # %(idx)s [%(taxes_doctype)s]: " + \
|
||||
_("Please specify a valid") + " %(row_id_label)s") % {
|
||||
"idx": tax.idx,
|
||||
"taxes_doctype": tax.doctype,
|
||||
"row_id_label": self.meta.get_label("row_id",
|
||||
parentfield=self.other_fname)
|
||||
}, raise_exception=True)
|
||||
})
|
||||
|
||||
def validate_inclusive_tax(self, tax):
|
||||
def _on_previous_row_error(row_range):
|
||||
msgprint((_("Row") + " # %(idx)s [%(doctype)s]: " +
|
||||
throw((_("Row") + " # %(idx)s [%(doctype)s]: " +
|
||||
_("to be included in Item's rate, it is required that: ") +
|
||||
" [" + _("Row") + " # %(row_range)s] " + _("also be included in Item's rate")) % {
|
||||
"idx": tax.idx,
|
||||
@@ -200,12 +200,12 @@ class AccountsController(TransactionBase):
|
||||
parentfield=self.other_fname),
|
||||
"charge_type": tax.charge_type,
|
||||
"row_range": row_range
|
||||
}, raise_exception=True)
|
||||
})
|
||||
|
||||
if cint(tax.included_in_print_rate):
|
||||
if tax.charge_type == "Actual":
|
||||
# inclusive tax cannot be of type Actual
|
||||
msgprint((_("Row")
|
||||
throw((_("Row")
|
||||
+ " # %(idx)s [%(doctype)s]: %(charge_type_label)s = \"%(charge_type)s\" "
|
||||
+ "cannot be included in Item's rate") % {
|
||||
"idx": tax.idx,
|
||||
@@ -213,7 +213,7 @@ class AccountsController(TransactionBase):
|
||||
"charge_type_label": self.meta.get_label("charge_type",
|
||||
parentfield=self.other_fname),
|
||||
"charge_type": tax.charge_type,
|
||||
}, raise_exception=True)
|
||||
})
|
||||
elif tax.charge_type == "On Previous Row Amount" and \
|
||||
not cint(self.tax_doclist[tax.row_id - 1].included_in_print_rate):
|
||||
# referred row should also be inclusive
|
||||
@@ -231,9 +231,6 @@ class AccountsController(TransactionBase):
|
||||
# tax_amount represents the amount of tax for the current step
|
||||
current_tax_amount = self.get_current_tax_amount(item, tax, item_tax_map)
|
||||
|
||||
if hasattr(self, "set_item_tax_amount"):
|
||||
self.set_item_tax_amount(item, tax, current_tax_amount)
|
||||
|
||||
# case when net total is 0 but there is an actual type charge
|
||||
# in this case add the actual amount to tax.tax_amount
|
||||
# and tax.grand_total_for_current_item for the first such iteration
|
||||
@@ -384,24 +381,45 @@ class AccountsController(TransactionBase):
|
||||
})
|
||||
|
||||
def validate_multiple_billing(self, ref_dt, item_ref_dn, based_on, parentfield):
|
||||
from controllers.status_updater import get_tolerance_for
|
||||
item_tolerance = {}
|
||||
global_tolerance = None
|
||||
|
||||
for item in self.doclist.get({"parentfield": "entries"}):
|
||||
if item.fields.get(item_ref_dn):
|
||||
already_billed = webnotes.conn.sql("""select sum(%s) from `tab%s`
|
||||
where %s=%s and docstatus=1""" % (based_on, self.tname, item_ref_dn, '%s'),
|
||||
item.fields[item_ref_dn])[0][0]
|
||||
|
||||
max_allowed_amt = flt(webnotes.conn.get_value(ref_dt + " Item",
|
||||
ref_amt = flt(webnotes.conn.get_value(ref_dt + " Item",
|
||||
item.fields[item_ref_dn], based_on), self.precision(based_on, item))
|
||||
if not ref_amt:
|
||||
webnotes.msgprint(_("As amount for item") + ": " + item.item_code + _(" in ") +
|
||||
ref_dt + _(" is zero, system will not check for over-billed"))
|
||||
else:
|
||||
already_billed = webnotes.conn.sql("""select sum(%s) from `tab%s`
|
||||
where %s=%s and docstatus=1 and parent != %s""" %
|
||||
(based_on, self.tname, item_ref_dn, '%s', '%s'),
|
||||
(item.fields[item_ref_dn], self.doc.name))[0][0]
|
||||
|
||||
total_billed_amt = flt(flt(already_billed) + flt(item.fields[based_on]),
|
||||
self.precision(based_on, item))
|
||||
total_billed_amt = flt(flt(already_billed) + flt(item.fields[based_on]),
|
||||
self.precision(based_on, item))
|
||||
|
||||
tolerance, item_tolerance, global_tolerance = get_tolerance_for(item.item_code,
|
||||
item_tolerance, global_tolerance)
|
||||
|
||||
if max_allowed_amt and total_billed_amt - max_allowed_amt > 0.02:
|
||||
webnotes.msgprint(_("Row ")+ cstr(item.idx) + ": " + cstr(item.item_code) +
|
||||
_(" will be over-billed against mentioned ") + cstr(ref_dt) +
|
||||
_(". Max allowed " + cstr(based_on) + ": " + cstr(max_allowed_amt)),
|
||||
raise_exception=1)
|
||||
|
||||
max_allowed_amt = flt(ref_amt * (100 + tolerance) / 100)
|
||||
|
||||
if total_billed_amt - max_allowed_amt > 0.01:
|
||||
reduce_by = total_billed_amt - max_allowed_amt
|
||||
|
||||
webnotes.throw(_("Row #") + cstr(item.idx) + ": " +
|
||||
_(" Max amount allowed for Item ") + cstr(item.item_code) +
|
||||
_(" against ") + ref_dt + " " +
|
||||
cstr(item.fields[ref_dt.lower().replace(" ", "_")]) + _(" is ") +
|
||||
cstr(max_allowed_amt) + ". \n" +
|
||||
_("""If you want to increase your overflow tolerance, please increase \
|
||||
tolerance % in Global Defaults or Item master.
|
||||
Or, you must reduce the amount by """) + cstr(reduce_by) + "\n" +
|
||||
_("""Also, please check if the order item has already been billed \
|
||||
in the Sales Order"""))
|
||||
|
||||
def get_company_default(self, fieldname):
|
||||
from accounts.utils import get_company_default
|
||||
return get_company_default(self.doc.company, fieldname)
|
||||
|
||||
@@ -108,10 +108,11 @@ class BuyingController(StockController):
|
||||
item.import_amount = flt(item.import_rate * item.qty,
|
||||
self.precision("import_amount", item))
|
||||
item.item_tax_amount = 0.0;
|
||||
|
||||
|
||||
self._set_in_company_currency(item, "import_amount", "amount")
|
||||
self._set_in_company_currency(item, "import_ref_rate", "purchase_ref_rate")
|
||||
self._set_in_company_currency(item, "import_rate", "rate")
|
||||
self._set_in_company_currency(item, "import_amount", "amount")
|
||||
|
||||
|
||||
def calculate_net_total(self):
|
||||
self.doc.net_total = self.doc.net_total_import = 0.0
|
||||
@@ -162,35 +163,44 @@ class BuyingController(StockController):
|
||||
if not self.meta.get_field("item_tax_amount", parentfield=self.fname):
|
||||
for item in self.item_doclist:
|
||||
del item.fields["item_tax_amount"]
|
||||
|
||||
def set_item_tax_amount(self, item, tax, current_tax_amount):
|
||||
|
||||
# update valuation rate
|
||||
def update_valuation_rate(self, parentfield):
|
||||
"""
|
||||
item_tax_amount is the total tax amount applied on that item
|
||||
stored for valuation
|
||||
|
||||
TODO: rename item_tax_amount to valuation_tax_amount
|
||||
"""
|
||||
if tax.category in ["Valuation", "Valuation and Total"] and \
|
||||
self.meta.get_field("item_tax_amount", parentfield=self.fname):
|
||||
item.item_tax_amount += flt(current_tax_amount, self.precision("item_tax_amount", item))
|
||||
|
||||
# update valuation rate
|
||||
def update_valuation_rate(self, parentfield):
|
||||
for item in self.doclist.get({"parentfield": parentfield}):
|
||||
item.conversion_factor = item.conversion_factor or flt(webnotes.conn.get_value(
|
||||
"UOM Conversion Detail", {"parent": item.item_code, "uom": item.uom},
|
||||
"conversion_factor")) or 1
|
||||
stock_items = self.get_stock_items()
|
||||
|
||||
stock_items_qty, stock_items_amount = 0, 0
|
||||
for d in self.doclist.get({"parentfield": parentfield}):
|
||||
if d.item_code and d.item_code in stock_items:
|
||||
stock_items_qty += flt(d.qty)
|
||||
stock_items_amount += flt(d.amount)
|
||||
|
||||
if item.item_code and item.qty:
|
||||
total_valuation_amount = sum([flt(d.tax_amount) for d in
|
||||
self.doclist.get({"parentfield": "purchase_tax_details"})
|
||||
if d.category in ["Valuation", "Valuation and Total"]])
|
||||
|
||||
|
||||
for item in self.doclist.get({"parentfield": parentfield}):
|
||||
if item.item_code and item.qty and item.item_code in stock_items:
|
||||
item_proportion = flt(item.amount) / stock_items_amount if stock_items_amount \
|
||||
else flt(item.qty) / stock_items_qty
|
||||
|
||||
item.item_tax_amount = flt(item_proportion * total_valuation_amount,
|
||||
self.precision("item_tax_amount", item))
|
||||
|
||||
self.round_floats_in(item)
|
||||
|
||||
purchase_rate = item.rate if self.doc.doctype == "Purchase Invoice" else item.purchase_rate
|
||||
|
||||
# if no item code, which is sometimes the case in purchase invoice,
|
||||
# then it is not possible to track valuation against it
|
||||
item.valuation_rate = flt((purchase_rate +
|
||||
(item.item_tax_amount + item.rm_supp_cost) / item.qty) / item.conversion_factor,
|
||||
self.precision("valuation_rate", item))
|
||||
item.conversion_factor = item.conversion_factor or flt(webnotes.conn.get_value(
|
||||
"UOM Conversion Detail", {"parent": item.item_code, "uom": item.uom},
|
||||
"conversion_factor")) or 1
|
||||
qty_in_stock_uom = flt(item.qty * item.conversion_factor)
|
||||
item.valuation_rate = ((item.amount + item.item_tax_amount + item.rm_supp_cost)
|
||||
/ qty_in_stock_uom)
|
||||
else:
|
||||
item.valuation_rate = 0.0
|
||||
|
||||
|
||||
@@ -151,7 +151,9 @@ class StatusUpdater(DocListController):
|
||||
"""
|
||||
|
||||
# check if overflow is within tolerance
|
||||
tolerance = self.get_tolerance_for(item['item_code'])
|
||||
tolerance, self.tolerance, self.global_tolerance = get_tolerance_for(item['item_code'],
|
||||
self.tolerance, self.global_tolerance)
|
||||
|
||||
overflow_percent = ((item[args['target_field']] - item[args['target_ref_field']]) /
|
||||
item[args['target_ref_field']]) * 100
|
||||
|
||||
@@ -170,23 +172,6 @@ class StatusUpdater(DocListController):
|
||||
|
||||
Also, please check if the order item has already been billed in the Sales Order""" %
|
||||
item, raise_exception=1)
|
||||
|
||||
def get_tolerance_for(self, item_code):
|
||||
"""
|
||||
Returns the tolerance for the item, if not set, returns global tolerance
|
||||
"""
|
||||
if self.tolerance.get(item_code): return self.tolerance[item_code]
|
||||
|
||||
tolerance = flt(webnotes.conn.get_value('Item',item_code,'tolerance') or 0)
|
||||
|
||||
if not tolerance:
|
||||
if self.global_tolerance == None:
|
||||
self.global_tolerance = flt(webnotes.conn.get_value('Global Defaults', None,
|
||||
'tolerance'))
|
||||
tolerance = self.global_tolerance
|
||||
|
||||
self.tolerance[item_code] = tolerance
|
||||
return tolerance
|
||||
|
||||
|
||||
def update_qty(self, change_modified=True):
|
||||
@@ -245,4 +230,22 @@ class StatusUpdater(DocListController):
|
||||
set %(status_field)s = if(ifnull(%(target_parent_field)s,0)<0.001,
|
||||
'Not %(keyword)s', if(%(target_parent_field)s>=99.99,
|
||||
'Fully %(keyword)s', 'Partly %(keyword)s'))
|
||||
where name='%(name)s'""" % args)
|
||||
where name='%(name)s'""" % args)
|
||||
|
||||
def get_tolerance_for(item_code, item_tolerance={}, global_tolerance=None):
|
||||
"""
|
||||
Returns the tolerance for the item, if not set, returns global tolerance
|
||||
"""
|
||||
if item_tolerance.get(item_code):
|
||||
return item_tolerance[item_code], item_tolerance, global_tolerance
|
||||
|
||||
tolerance = flt(webnotes.conn.get_value('Item',item_code,'tolerance') or 0)
|
||||
|
||||
if not tolerance:
|
||||
if global_tolerance == None:
|
||||
global_tolerance = flt(webnotes.conn.get_value('Global Defaults', None,
|
||||
'tolerance'))
|
||||
tolerance = global_tolerance
|
||||
|
||||
item_tolerance[item_code] = tolerance
|
||||
return tolerance, item_tolerance, global_tolerance
|
||||
@@ -5,6 +5,7 @@
|
||||
from __future__ import unicode_literals
|
||||
import os, sys
|
||||
import argparse
|
||||
import subprocess
|
||||
|
||||
is_redhat = is_debian = None
|
||||
root_password = None
|
||||
@@ -19,7 +20,7 @@ requirements = [
|
||||
"jinja2",
|
||||
"markdown2",
|
||||
"markupsafe",
|
||||
"mysql-python",
|
||||
"mysql-python==1.2.4",
|
||||
"pygeoip",
|
||||
"python-dateutil",
|
||||
"python-memcached",
|
||||
@@ -80,7 +81,7 @@ def validate_install():
|
||||
return is_redhat, is_debian
|
||||
|
||||
def install_using_yum():
|
||||
packages = "python python-setuptools gcc python-devel MySQL-python git memcached ntp vim-enhanced screen"
|
||||
packages = "gcc MySQL-python git memcached ntp vim-enhanced screen"
|
||||
|
||||
print "-"*80
|
||||
print "Installing Packages: (This may take some time)"
|
||||
@@ -88,7 +89,10 @@ def install_using_yum():
|
||||
print "-"*80
|
||||
exec_in_shell("yum install -y %s" % packages)
|
||||
|
||||
if not exec_in_shell("which mysql"):
|
||||
|
||||
try:
|
||||
exec_in_shell("which mysql")
|
||||
except subprocess.CalledProcessError:
|
||||
packages = "mysql mysql-server mysql-devel"
|
||||
print "Installing Packages:", packages
|
||||
exec_in_shell("yum install -y %s" % packages)
|
||||
@@ -101,26 +105,19 @@ def install_using_yum():
|
||||
exec_in_shell('mysqladmin -u root password "%s"' % (root_password,))
|
||||
print "Root password set as", root_password
|
||||
|
||||
# install htop
|
||||
if not exec_in_shell("which htop"):
|
||||
try:
|
||||
exec_in_shell("cd /tmp && rpm -i --force http://packages.sw.be/rpmforge-release/rpmforge-release-0.5.2-2.el6.rf.x86_64.rpm && yum install -y htop")
|
||||
except:
|
||||
pass
|
||||
|
||||
update_config_for_redhat()
|
||||
|
||||
def update_config_for_redhat():
|
||||
import re
|
||||
|
||||
# set to autostart on startup
|
||||
for service in ("mysqld", "memcached", "ntpd"):
|
||||
for service in ("mysqld", "memcached"):
|
||||
exec_in_shell("chkconfig --level 2345 %s on" % service)
|
||||
exec_in_shell("service %s restart" % service)
|
||||
|
||||
def install_using_apt():
|
||||
exec_in_shell("apt-get update")
|
||||
packages = "python python-setuptools python-dev build-essential python-pip python-mysqldb git memcached ntp vim screen htop"
|
||||
packages = "python python-setuptools python-dev build-essential python-mysqldb git memcached ntp vim screen htop"
|
||||
print "-"*80
|
||||
print "Installing Packages: (This may take some time)"
|
||||
print packages
|
||||
@@ -132,7 +129,9 @@ def install_using_apt():
|
||||
exec_in_shell("echo mysql-server mysql-server/root_password password %s | sudo debconf-set-selections" % root_password)
|
||||
exec_in_shell("echo mysql-server mysql-server/root_password_again password %s | sudo debconf-set-selections" % root_password)
|
||||
|
||||
if not exec_in_shell("which mysql"):
|
||||
try:
|
||||
exec_in_shell("which mysql")
|
||||
except subprocess.CalledProcessError:
|
||||
packages = "mysql-server libmysqlclient-dev"
|
||||
print "Installing Packages:", packages
|
||||
exec_in_shell("apt-get install -y %s" % packages)
|
||||
@@ -140,7 +139,7 @@ def install_using_apt():
|
||||
update_config_for_debian()
|
||||
|
||||
def update_config_for_debian():
|
||||
for service in ("mysql", "ntpd"):
|
||||
for service in ("mysql",):
|
||||
exec_in_shell("service %s restart" % service)
|
||||
|
||||
def install_python_modules():
|
||||
@@ -148,13 +147,14 @@ def install_python_modules():
|
||||
print "Installing Python Modules: (This may take some time)"
|
||||
print "-"*80
|
||||
|
||||
if not exec_in_shell("which pip"):
|
||||
exec_in_shell("easy_install pip")
|
||||
try:
|
||||
exec_in_shell("which pip2.7")
|
||||
except subprocess.CalledProcessError:
|
||||
exec_in_shell("easy_install-2.7 pip")
|
||||
|
||||
exec_in_shell("pip install --upgrade pip")
|
||||
exec_in_shell("pip install --upgrade setuptools")
|
||||
exec_in_shell("pip install --upgrade virtualenv")
|
||||
exec_in_shell("pip install {}".format(' '.join(requirements)))
|
||||
exec_in_shell("pip2.7 install --upgrade setuptools --no-use-wheel")
|
||||
exec_in_shell("pip2.7 install --upgrade setuptools")
|
||||
exec_in_shell("pip2.7 install {}".format(' '.join(requirements)))
|
||||
|
||||
def install_erpnext(install_path):
|
||||
print
|
||||
@@ -200,7 +200,7 @@ def setup_folders(install_path):
|
||||
app = os.path.join(install_path, "app")
|
||||
if not os.path.exists(app):
|
||||
print "Cloning erpnext"
|
||||
exec_in_shell("cd %s && git clone https://github.com/webnotes/erpnext.git app" % install_path)
|
||||
exec_in_shell("cd %s && git clone --branch master https://github.com/webnotes/erpnext.git app" % install_path)
|
||||
exec_in_shell("cd app && git config core.filemode false")
|
||||
if not os.path.exists(app):
|
||||
raise Exception, "Couldn't clone erpnext repository"
|
||||
@@ -208,7 +208,7 @@ def setup_folders(install_path):
|
||||
lib = os.path.join(install_path, "lib")
|
||||
if not os.path.exists(lib):
|
||||
print "Cloning wnframework"
|
||||
exec_in_shell("cd %s && git clone https://github.com/webnotes/wnframework.git lib" % install_path)
|
||||
exec_in_shell("cd %s && git clone --branch master https://github.com/webnotes/wnframework.git lib" % install_path)
|
||||
exec_in_shell("cd lib && git config core.filemode false")
|
||||
if not os.path.exists(lib):
|
||||
raise Exception, "Couldn't clone wnframework repository"
|
||||
@@ -243,28 +243,8 @@ def post_install(install_path):
|
||||
|
||||
def exec_in_shell(cmd):
|
||||
# using Popen instead of os.system - as recommended by python docs
|
||||
from subprocess import Popen
|
||||
import tempfile
|
||||
|
||||
with tempfile.TemporaryFile() as stdout:
|
||||
with tempfile.TemporaryFile() as stderr:
|
||||
p = Popen(cmd, shell=True, stdout=stdout, stderr=stderr)
|
||||
p.wait()
|
||||
|
||||
stdout.seek(0)
|
||||
out = stdout.read()
|
||||
if out: out = out.decode('utf-8')
|
||||
|
||||
stderr.seek(0)
|
||||
err = stderr.read()
|
||||
if err: err = err.decode('utf-8')
|
||||
|
||||
if err and any((kw in err.lower() for kw in ["traceback", "error", "exception"])):
|
||||
print out
|
||||
raise Exception, err
|
||||
else:
|
||||
print "."
|
||||
|
||||
import subprocess
|
||||
out = subprocess.check_output(cmd, shell=True)
|
||||
return out
|
||||
|
||||
def parse_args():
|
||||
|
||||
@@ -1,28 +1,56 @@
|
||||
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||
// License: GNU General Public License v3. See license.txt
|
||||
|
||||
cur_frm.cscript.onload = function(doc, dt, dn) {
|
||||
if (!doc.status) doc.status = 'Draft';
|
||||
cfn_set_fields(doc, dt, dn);
|
||||
}
|
||||
$.extend(cur_frm.cscript, {
|
||||
onload: function (doc, dt, dn) {
|
||||
|
||||
cur_frm.cscript.refresh = function(doc, dt, dn) {
|
||||
cur_frm.dashboard.reset();
|
||||
erpnext.hide_naming_series();
|
||||
cur_frm.set_intro("");
|
||||
cfn_set_fields(doc, dt, dn);
|
||||
if (!doc.status) doc.status = 'Draft';
|
||||
cfn_set_fields(doc, dt, dn);
|
||||
|
||||
if(doc.docstatus===0 && !doc.__islocal) {
|
||||
cur_frm.set_intro(wn._("Submit this Production Order for further processing."));
|
||||
} else if(doc.docstatus===1) {
|
||||
var percent = flt(doc.produced_qty) / flt(doc.qty) * 100;
|
||||
cur_frm.dashboard.add_progress(cint(percent) + "% " + wn._("Complete"), percent);
|
||||
this.frm.add_fetch("sales_order", "delivery_date", "expected_delivery_date");
|
||||
},
|
||||
|
||||
if(doc.status === "Stopped") {
|
||||
cur_frm.dashboard.set_headline_alert(wn._("Stopped"), "alert-danger", "icon-stop");
|
||||
refresh: function(doc, dt, dn) {
|
||||
this.frm.dashboard.reset();
|
||||
erpnext.hide_naming_series();
|
||||
this.frm.set_intro("");
|
||||
cfn_set_fields(doc, dt, dn);
|
||||
|
||||
if (doc.docstatus === 0 && !doc.__islocal) {
|
||||
this.frm.set_intro(wn._("Submit this Production Order for further processing."));
|
||||
} else if (doc.docstatus === 1) {
|
||||
var percent = flt(doc.produced_qty) / flt(doc.qty) * 100;
|
||||
this.frm.dashboard.add_progress(cint(percent) + "% " + wn._("Complete"), percent);
|
||||
|
||||
if(doc.status === "Stopped") {
|
||||
this.frm.dashboard.set_headline_alert(wn._("Stopped"), "alert-danger", "icon-stop");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
production_item: function(doc) {
|
||||
return this.frm.call({
|
||||
method: "get_item_details",
|
||||
args: { item: doc.production_item }
|
||||
});
|
||||
},
|
||||
|
||||
make_se: function(purpose) {
|
||||
var me = this;
|
||||
|
||||
wn.call({
|
||||
method:"manufacturing.doctype.production_order.production_order.make_stock_entry",
|
||||
args: {
|
||||
"production_order_id": me.frm.doc.name,
|
||||
"purpose": purpose
|
||||
},
|
||||
callback: function(r) {
|
||||
var doclist = wn.model.sync(r.message);
|
||||
wn.set_route("Form", doclist[0].doctype, doclist[0].name);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var cfn_set_fields = function(doc, dt, dn) {
|
||||
if (doc.docstatus == 1) {
|
||||
@@ -38,13 +66,6 @@ var cfn_set_fields = function(doc, dt, dn) {
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.cscript.production_item = function(doc) {
|
||||
return cur_frm.call({
|
||||
method: "get_item_details",
|
||||
args: { item: doc.production_item }
|
||||
});
|
||||
}
|
||||
|
||||
cur_frm.cscript['Stop Production Order'] = function() {
|
||||
var doc = cur_frm.doc;
|
||||
var check = confirm(wn._("Do you really want to stop production order: " + doc.name));
|
||||
@@ -57,7 +78,7 @@ cur_frm.cscript['Unstop Production Order'] = function() {
|
||||
var doc = cur_frm.doc;
|
||||
var check = confirm(wn._("Do really want to unstop production order: " + doc.name));
|
||||
if (check)
|
||||
return $c_obj(make_doclist(doc.doctype, doc.name), 'stop_unstop', 'Unstopped', function(r, rt) {cur_frm.refresh();});
|
||||
return $c_obj(make_doclist(doc.doctype, doc.name), 'stop_unstop', 'Unstopped', function(r, rt) {cur_frm.refresh();});
|
||||
}
|
||||
|
||||
cur_frm.cscript['Transfer Raw Materials'] = function() {
|
||||
@@ -68,20 +89,6 @@ cur_frm.cscript['Update Finished Goods'] = function() {
|
||||
cur_frm.cscript.make_se('Manufacture/Repack');
|
||||
}
|
||||
|
||||
cur_frm.cscript.make_se = function(purpose) {
|
||||
wn.call({
|
||||
method:"manufacturing.doctype.production_order.production_order.make_stock_entry",
|
||||
args: {
|
||||
"production_order_id": cur_frm.doc.name,
|
||||
"purpose": purpose
|
||||
},
|
||||
callback: function(r) {
|
||||
var doclist = wn.model.sync(r.message);
|
||||
wn.set_route("Form", doclist[0].doctype, doclist[0].name);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
cur_frm.fields_dict['production_item'].get_query = function(doc) {
|
||||
return {
|
||||
filters:[
|
||||
@@ -98,7 +105,6 @@ cur_frm.fields_dict['project_name'].get_query = function(doc, dt, dn) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cur_frm.set_query("bom_no", function(doc) {
|
||||
if (doc.production_item) {
|
||||
return{
|
||||
|
||||
@@ -8,7 +8,6 @@ from webnotes.utils import cstr, flt, nowdate
|
||||
from webnotes.model.code import get_obj
|
||||
from webnotes import msgprint, _
|
||||
|
||||
|
||||
class OverProductionError(webnotes.ValidationError): pass
|
||||
|
||||
class DocType:
|
||||
@@ -37,15 +36,20 @@ class DocType:
|
||||
and is_active=1 and item=%s"""
|
||||
, (self.doc.bom_no, self.doc.production_item), as_dict =1)
|
||||
if not bom:
|
||||
msgprint("""Incorrect BOM: %s entered.
|
||||
webnotes.throw("""Incorrect BOM: %s entered.
|
||||
May be BOM not exists or inactive or not submitted
|
||||
or for some other item.""" % cstr(self.doc.bom_no), raise_exception=1)
|
||||
or for some other item.""" % cstr(self.doc.bom_no))
|
||||
|
||||
def validate_sales_order(self):
|
||||
if self.doc.sales_order:
|
||||
if not webnotes.conn.sql("""select name from `tabSales Order`
|
||||
where name=%s and docstatus = 1""", self.doc.sales_order):
|
||||
msgprint("Sales Order: %s is not valid" % self.doc.sales_order, raise_exception=1)
|
||||
so = webnotes.conn.sql("""select name, delivery_date from `tabSales Order`
|
||||
where name=%s and docstatus = 1""", self.doc.sales_order, as_dict=1)[0]
|
||||
|
||||
if not so.name:
|
||||
webnotes.throw("Sales Order: %s is not valid" % self.doc.sales_order)
|
||||
|
||||
if not self.doc.expected_delivery_date:
|
||||
self.doc.expected_delivery_date = so.delivery_date
|
||||
|
||||
self.validate_production_order_against_so()
|
||||
|
||||
@@ -76,11 +80,11 @@ class DocType:
|
||||
so_qty = flt(so_item_qty) + flt(dnpi_qty)
|
||||
|
||||
if total_qty > so_qty:
|
||||
webnotes.msgprint(_("Total production order qty for item") + ": " +
|
||||
webnotes.throw(_("Total production order qty for item") + ": " +
|
||||
cstr(self.doc.production_item) + _(" against sales order") + ": " +
|
||||
cstr(self.doc.sales_order) + _(" will be ") + cstr(total_qty) + ", " +
|
||||
_("which is greater than sales order qty ") + "(" + cstr(so_qty) + ")" +
|
||||
_("Please reduce qty."), raise_exception=OverProductionError)
|
||||
_("Please reduce qty."), exc=OverProductionError)
|
||||
|
||||
def stop_unstop(self, status):
|
||||
""" Called from client side on Stop/Unstop event"""
|
||||
@@ -114,8 +118,8 @@ class DocType:
|
||||
stock_entry = webnotes.conn.sql("""select name from `tabStock Entry`
|
||||
where production_order = %s and docstatus = 1""", self.doc.name)
|
||||
if stock_entry:
|
||||
msgprint("""Submitted Stock Entry %s exists against this production order.
|
||||
Hence can not be cancelled.""" % stock_entry[0][0], raise_exception=1)
|
||||
webnotes.throw("""Submitted Stock Entry %s exists against this production order.
|
||||
Hence can not be cancelled.""" % stock_entry[0][0])
|
||||
|
||||
webnotes.conn.set(self.doc,'status', 'Cancelled')
|
||||
self.update_planned_qty(-self.doc.qty)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"creation": "2013-01-10 16:34:16",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-11-02 14:05:44",
|
||||
"modified": "2013-12-18 13:22:14",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
@@ -136,6 +136,14 @@
|
||||
"oldfieldtype": "Currency",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "sales_order",
|
||||
"doctype": "DocField",
|
||||
"fieldname": "expected_delivery_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Expected Delivery Date",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "warehouses",
|
||||
|
||||
@@ -34,6 +34,7 @@ class TestProductionOrder(unittest.TestCase):
|
||||
stock_entry = webnotes.bean(stock_entry)
|
||||
|
||||
stock_entry.doc.fg_completed_qty = 4
|
||||
stock_entry.doc.posting_date = "2013-05-12"
|
||||
stock_entry.run_method("get_items")
|
||||
stock_entry.submit()
|
||||
|
||||
@@ -50,7 +51,7 @@ class TestProductionOrder(unittest.TestCase):
|
||||
|
||||
stock_entry = make_stock_entry(pro_order, "Manufacture/Repack")
|
||||
stock_entry = webnotes.bean(stock_entry)
|
||||
|
||||
stock_entry.doc.posting_date = "2013-05-12"
|
||||
stock_entry.doc.fg_completed_qty = 15
|
||||
stock_entry.run_method("get_items")
|
||||
stock_entry.insert()
|
||||
|
||||
@@ -186,7 +186,6 @@ class DocType:
|
||||
else :
|
||||
msgprint(_("No Production Order created."))
|
||||
|
||||
|
||||
def get_distinct_items_and_boms(self):
|
||||
""" Club similar BOM and item for processing
|
||||
bom_dict {
|
||||
|
||||
@@ -5,19 +5,28 @@ from __future__ import unicode_literals
|
||||
import webnotes
|
||||
|
||||
def execute():
|
||||
webnotes.reload_doc("setup", "doctype", "email_digest")
|
||||
|
||||
from webnotes.profile import get_system_managers
|
||||
system_managers = get_system_managers(only_name=True)
|
||||
if not system_managers:
|
||||
return
|
||||
|
||||
# no default company
|
||||
company = webnotes.conn.sql_list("select name from `tabCompany`")
|
||||
if company:
|
||||
company = company[0]
|
||||
if not company:
|
||||
return
|
||||
|
||||
# scheduler errors digest
|
||||
edigest = webnotes.new_bean("Email Digest")
|
||||
edigest.doc.fields.update({
|
||||
"name": "Scheduler Errors",
|
||||
"company": webnotes.conn.get_default("company"),
|
||||
"company": company,
|
||||
"frequency": "Daily",
|
||||
"enabled": 1,
|
||||
"recipient_list": "\n".join(system_managers),
|
||||
"scheduler_errors": 1
|
||||
})
|
||||
edigest.insert()
|
||||
edigest.insert()
|
||||
|
||||
10
patches/1312/p02_update_item_details_in_item_price.py
Normal file
10
patches/1312/p02_update_item_details_in_item_price.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
|
||||
def execute():
|
||||
webnotes.conn.sql("""update `tabItem Price` ip INNER JOIN `tabItem` i
|
||||
ON (ip.item_code = i.name)
|
||||
set ip.item_name = i.item_name, ip.item_description = i.description""")
|
||||
0
patches/1401/__init__.py
Normal file
0
patches/1401/__init__.py
Normal file
@@ -0,0 +1,29 @@
|
||||
# Copyright (c) 2014, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
|
||||
def execute():
|
||||
webnotes.reload_doc("stock", "doctype", "price_list")
|
||||
webnotes.reload_doc("stock", "doctype", "item_price")
|
||||
|
||||
if "buying_or_selling" in webnotes.conn.get_table_columns("Price List"):
|
||||
webnotes.conn.sql("""update `tabPrice List` set
|
||||
selling =
|
||||
case
|
||||
when buying_or_selling='Selling'
|
||||
then 1
|
||||
end,
|
||||
buying =
|
||||
case
|
||||
when buying_or_selling='Buying'
|
||||
then 1
|
||||
end
|
||||
""")
|
||||
webnotes.conn.sql("""update `tabItem Price` ip, `tabPrice List` pl
|
||||
set ip.buying=pl.buying, ip.selling=pl.selling
|
||||
where ip.price_list=pl.name""")
|
||||
|
||||
webnotes.conn.sql("""update `tabItem Price` set selling=1 where ifnull(selling, 0)=0 and
|
||||
ifnull(buying, 0)=0""")
|
||||
@@ -5,7 +5,8 @@ from __future__ import unicode_literals
|
||||
|
||||
def execute():
|
||||
import webnotes
|
||||
webnotes.reload_doc('stock', 'doctype', 'packed_item')
|
||||
for si in webnotes.conn.sql("""select name from `tabSales Invoice` where docstatus = 1"""):
|
||||
webnotes.get_obj("Sales Invoice", si[0],
|
||||
with_children=1).update_qty(change_modified=False)
|
||||
webnotes.conn.commit()
|
||||
webnotes.conn.commit()
|
||||
|
||||
@@ -8,20 +8,7 @@ from webnotes.utils import cint
|
||||
def execute():
|
||||
webnotes.reload_doc("stock", "doctype", "price_list")
|
||||
webnotes.reload_doc("stock", "doctype", "item_price")
|
||||
|
||||
try:
|
||||
for price_list in webnotes.conn.sql_list("""select name from `tabPrice List`"""):
|
||||
buying, selling = False, False
|
||||
for b, s in webnotes.conn.sql("""select distinct buying, selling
|
||||
from `tabItem Price` where price_list_name=%s""", price_list):
|
||||
buying = buying or cint(b)
|
||||
selling = selling or cint(s)
|
||||
|
||||
buying_or_selling = "Selling" if selling else "Buying"
|
||||
webnotes.conn.set_value("Price List", price_list, "buying_or_selling", buying_or_selling)
|
||||
except webnotes.SQLError, e:
|
||||
if e.args[0] == 1054:
|
||||
webnotes.conn.sql("""update `tabPrice List` set buying_or_selling='Selling'
|
||||
where ifnull(buying_or_selling, '')='' """)
|
||||
else:
|
||||
raise
|
||||
|
||||
webnotes.conn.sql("""update `tabPrice List` pl, `tabItem Price` ip
|
||||
set pl.selling=ip.selling, pl.buying=ip.buying
|
||||
where pl.name=ip.price_list_name""")
|
||||
@@ -12,9 +12,7 @@ def execute():
|
||||
where ip.item_code=i.name""")
|
||||
|
||||
webnotes.conn.sql("""update `tabItem Price` ip, `tabPrice List` pl
|
||||
set ip.price_list=pl.name, ip.currency=pl.currency,
|
||||
ip.buying_or_selling=pl.buying_or_selling
|
||||
where ip.parent=pl.name""")
|
||||
set ip.price_list=pl.name, ip.currency=pl.currency where ip.parent=pl.name""")
|
||||
|
||||
webnotes.conn.sql("""update `tabItem Price`
|
||||
set parent=null, parenttype=null, parentfield=null, idx=null""")
|
||||
@@ -261,4 +261,7 @@ patch_list = [
|
||||
"execute:webnotes.delete_doc('Report', 'Payment Made With Ageing')",
|
||||
"patches.1311.p07_scheduler_errors_digest",
|
||||
"patches.1311.p08_email_digest_recipients",
|
||||
"execute:webnotes.delete_doc('DocType', 'Warehouse Type')",
|
||||
"patches.1312.p02_update_item_details_in_item_price",
|
||||
"patches.1401.p01_make_buying_selling_as_check_box_in_price_list",
|
||||
]
|
||||
@@ -28,7 +28,7 @@ class DocType:
|
||||
})
|
||||
|
||||
def validate_time_log_is_submitted(self, tl):
|
||||
if tl.status != "Submitted":
|
||||
if tl.status != "Submitted" and self.doc.docstatus == 0:
|
||||
webnotes.msgprint(_("Time Log must have status 'Submitted'") + \
|
||||
" :" + tl.name + " (" + _(tl.status) + ")", raise_exception=True)
|
||||
|
||||
@@ -57,7 +57,4 @@ class DocType:
|
||||
tl = webnotes.bean("Time Log", d.time_log)
|
||||
tl.doc.time_log_batch = time_log_batch
|
||||
tl.doc.sales_invoice = self.doc.sales_invoice
|
||||
tl.update_after_submit()
|
||||
|
||||
|
||||
|
||||
tl.update_after_submit()
|
||||
@@ -26,9 +26,10 @@ erpnext.AccountTreeGrid = wn.views.TreeGridReport.extend({
|
||||
show: true,
|
||||
parent_field: "parent_account",
|
||||
formatter: function(item) {
|
||||
return repl('<a href="#general-ledger/account=%(enc_value)s">%(value)s</a>', {
|
||||
return repl("<a \
|
||||
onclick='wn.cur_grid_report.show_general_ledger(\"%(value)s\")'>\
|
||||
%(value)s</a>", {
|
||||
value: item.name,
|
||||
enc_value: encodeURIComponent(item.name)
|
||||
});
|
||||
}
|
||||
},
|
||||
@@ -211,4 +212,14 @@ erpnext.AccountTreeGrid = wn.views.TreeGridReport.extend({
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
show_general_ledger: function(account) {
|
||||
wn.route_options = {
|
||||
account: account,
|
||||
company: this.company,
|
||||
from_date: this.from_date,
|
||||
to_date: this.to_date
|
||||
};
|
||||
wn.set_route("query-report", "General Ledger");
|
||||
}
|
||||
});
|
||||
@@ -11,9 +11,10 @@ erpnext.stock.StockController = wn.ui.form.Controller.extend({
|
||||
wn.route_options = {
|
||||
voucher_no: me.frm.doc.name,
|
||||
from_date: me.frm.doc.posting_date,
|
||||
to_date: me.frm.doc.posting_date
|
||||
to_date: me.frm.doc.posting_date,
|
||||
company: me.frm.doc.company
|
||||
};
|
||||
wn.set_route('stock-ledger');
|
||||
wn.set_route("query-report", "Stock Ledger");
|
||||
}, "icon-bar-chart");
|
||||
}
|
||||
|
||||
@@ -24,11 +25,13 @@ erpnext.stock.StockController = wn.ui.form.Controller.extend({
|
||||
if(this.frm.doc.docstatus===1 && cint(wn.defaults.get_default("auto_accounting_for_stock"))) {
|
||||
cur_frm.appframe.add_button(wn._('Accounting Ledger'), function() {
|
||||
wn.route_options = {
|
||||
"voucher_no": me.frm.doc.name,
|
||||
"from_date": me.frm.doc.posting_date,
|
||||
"to_date": me.frm.doc.posting_date,
|
||||
voucher_no: me.frm.doc.name,
|
||||
from_date: me.frm.doc.posting_date,
|
||||
to_date: me.frm.doc.posting_date,
|
||||
company: me.frm.doc.company,
|
||||
group_by_voucher: false
|
||||
};
|
||||
wn.set_route("general-ledger");
|
||||
wn.set_route("query-report", "General Ledger");
|
||||
}, "icon-table");
|
||||
}
|
||||
},
|
||||
|
||||
@@ -17,10 +17,10 @@ erpnext.StockAnalytics = erpnext.StockGridReport.extend({
|
||||
parent_field: "parent_item_group",
|
||||
formatter: function(item) {
|
||||
if(!item.is_group) {
|
||||
return repl('<a href="#stock-ledger/item_code=%(enc_value)s">%(value)s</a>',
|
||||
{
|
||||
return repl("<a \
|
||||
onclick='wn.cur_grid_report.show_stock_ledger(\"%(value)s\")'>\
|
||||
%(value)s</a>", {
|
||||
value: item.name,
|
||||
enc_value: encodeURIComponent(item.name)
|
||||
});
|
||||
} else {
|
||||
return item.name;
|
||||
@@ -183,5 +183,13 @@ erpnext.StockAnalytics = erpnext.StockGridReport.extend({
|
||||
},
|
||||
get_plot_points: function(item, col, idx) {
|
||||
return [[dateutil.user_to_obj(col.name).getTime(), item[col.field]]]
|
||||
},
|
||||
show_stock_ledger: function(item_code) {
|
||||
wn.route_options = {
|
||||
item_code: item_code,
|
||||
from_date: this.from_date,
|
||||
to_date: this.to_date
|
||||
};
|
||||
wn.set_route("query-report", "Stock Ledger");
|
||||
}
|
||||
});
|
||||
@@ -330,8 +330,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
||||
doctype: tax.doctype,
|
||||
row_id_label: wn.meta.get_label(tax.doctype, "row_id", tax.name)
|
||||
});
|
||||
msgprint(msg);
|
||||
throw msg;
|
||||
wn.throw(msg);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -347,8 +346,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
||||
charge_type_label: wn.meta.get_label(tax.doctype, "charge_type", tax.name),
|
||||
charge_type: tax.charge_type
|
||||
});
|
||||
msgprint(msg);
|
||||
throw msg;
|
||||
wn.throw(msg);
|
||||
};
|
||||
|
||||
var on_previous_row_error = function(row_range) {
|
||||
@@ -363,8 +361,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
||||
row_range: row_range,
|
||||
});
|
||||
|
||||
msgprint(msg);
|
||||
throw msg;
|
||||
wn.throw(msg);
|
||||
};
|
||||
|
||||
if(cint(tax.included_in_print_rate)) {
|
||||
|
||||
@@ -122,6 +122,6 @@ cur_frm.fields_dict.lead_name.get_query = function(doc,cdt,cdn) {
|
||||
|
||||
cur_frm.fields_dict['default_price_list'].get_query = function(doc,cdt,cdn) {
|
||||
return{
|
||||
filters:{'buying_or_selling': "Selling"}
|
||||
filters:{'selling': 1}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"creation": "2013-06-11 14:26:44",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-11-03 14:01:33",
|
||||
"modified": "2013-12-25 11:15:05",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
@@ -16,7 +16,7 @@
|
||||
"icon": "icon-user",
|
||||
"module": "Selling",
|
||||
"name": "__common__",
|
||||
"search_fields": "customer_name,customer_group,country,territory"
|
||||
"search_fields": "customer_name,customer_group,territory"
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
|
||||
@@ -28,6 +28,7 @@ class TestQuotation(unittest.TestCase):
|
||||
|
||||
sales_order[0]["delivery_date"] = "2014-01-01"
|
||||
sales_order[0]["naming_series"] = "_T-Quotation-"
|
||||
sales_order[0]["transaction_date"] = "2013-05-12"
|
||||
webnotes.bean(sales_order).insert()
|
||||
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ class TestSalesOrder(unittest.TestCase):
|
||||
self.assertEquals(len([d for d in si if d["doctype"]=="Sales Invoice Item"]), 1)
|
||||
|
||||
si = webnotes.bean(si)
|
||||
si.doc.posting_date = "2013-10-10"
|
||||
si.insert()
|
||||
si.submit()
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
|
||||
|
||||
if(this.frm.fields_dict.selling_price_list) {
|
||||
this.frm.set_query("selling_price_list", function() {
|
||||
return { filters: { buying_or_selling: "Selling" } };
|
||||
return { filters: { selling: 1 } };
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
from webnotes import msgprint, _
|
||||
from webnotes import msgprint, _, throw
|
||||
from webnotes.utils import flt, cint, comma_and
|
||||
import json
|
||||
|
||||
@@ -100,7 +100,7 @@ def _get_item_code(barcode=None, serial_no=None):
|
||||
where name=%s""", serial_no)
|
||||
|
||||
if not item_code:
|
||||
msgprint(_("No Item found with ") + input_type + ": %s" % (barcode or serial_no), raise_exception=True)
|
||||
throw(_("No Item found with ") + input_type + ": %s" % (barcode or serial_no))
|
||||
|
||||
return item_code[0]
|
||||
|
||||
@@ -111,14 +111,12 @@ def _validate_item_details(args, item):
|
||||
# validate if sales item or service item
|
||||
if args.order_type == "Maintenance":
|
||||
if item.is_service_item != "Yes":
|
||||
msgprint(_("Item") + (" %s: " % item.name) +
|
||||
throw(_("Item") + (" %s: " % item.name) +
|
||||
_("not a service item.") +
|
||||
_("Please select a service item or change the order type to Sales."),
|
||||
raise_exception=True)
|
||||
_("Please select a service item or change the order type to Sales."))
|
||||
|
||||
elif item.is_sales_item != "Yes":
|
||||
msgprint(_("Item") + (" %s: " % item.name) + _("not a sales item"),
|
||||
raise_exception=True)
|
||||
throw(_("Item") + (" %s: " % item.name) + _("not a sales item"))
|
||||
|
||||
def _get_basic_details(args, item_bean, warehouse_fieldname):
|
||||
item = item_bean.doc
|
||||
@@ -147,7 +145,7 @@ def _get_basic_details(args, item_bean, warehouse_fieldname):
|
||||
|
||||
def _get_price_list_rate(args, item_bean, meta):
|
||||
ref_rate = webnotes.conn.sql("""select ref_rate from `tabItem Price`
|
||||
where price_list=%s and item_code=%s and buying_or_selling='Selling'""",
|
||||
where price_list=%s and item_code=%s and selling=1""",
|
||||
(args.selling_price_list, args.item_code), as_dict=1)
|
||||
|
||||
if not ref_rate:
|
||||
|
||||
@@ -16,8 +16,6 @@ import webnotes
|
||||
from webnotes.utils import get_request_site_address, cstr
|
||||
from webnotes import _
|
||||
|
||||
from backup_manager import ignore_list
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_dropbox_authorize_url():
|
||||
sess = get_dropbox_session()
|
||||
@@ -100,9 +98,7 @@ def backup_to_dropbox():
|
||||
path = get_files_path()
|
||||
for filename in os.listdir(path):
|
||||
filename = cstr(filename)
|
||||
if filename in ignore_list:
|
||||
continue
|
||||
|
||||
|
||||
found = False
|
||||
filepath = os.path.join(path, filename)
|
||||
for file_metadata in response["contents"]:
|
||||
|
||||
@@ -87,7 +87,7 @@ $.extend(cur_frm.cscript, {
|
||||
cur_frm.save();
|
||||
},
|
||||
|
||||
upload_backups_to_gdrive: function() {
|
||||
cur_frm.save();
|
||||
},
|
||||
// upload_backups_to_gdrive: function() {
|
||||
// cur_frm.save();
|
||||
// },
|
||||
});
|
||||
@@ -7,8 +7,6 @@ from __future__ import unicode_literals
|
||||
import webnotes
|
||||
from webnotes import _
|
||||
|
||||
ignore_list = []
|
||||
|
||||
class DocType:
|
||||
def __init__(self, d, dl):
|
||||
self.doc, self.doclist = d, dl
|
||||
@@ -39,10 +37,6 @@ def take_backups_dropbox():
|
||||
file_and_error = [" - ".join(f) for f in zip(did_not_upload, error_log)]
|
||||
error_message = ("\n".join(file_and_error) + "\n" + webnotes.getTraceback())
|
||||
webnotes.errprint(error_message)
|
||||
|
||||
if not webnotes.conn:
|
||||
webnotes.connect()
|
||||
|
||||
send_email(False, "Dropbox", error_message)
|
||||
|
||||
#backup to gdrive
|
||||
@@ -62,6 +56,7 @@ def take_backups_gdrive():
|
||||
send_email(False, "Google Drive", error_message)
|
||||
|
||||
def send_email(success, service_name, error_status=None):
|
||||
from webnotes.utils.email_lib import sendmail
|
||||
if success:
|
||||
subject = "Backup Upload Successful"
|
||||
message ="""<h3>Backup Uploaded Successfully</h3><p>Hi there, this is just to inform you
|
||||
@@ -76,7 +71,8 @@ def send_email(success, service_name, error_status=None):
|
||||
<p>Please contact your system manager for more information.</p>
|
||||
""" % (service_name, error_status)
|
||||
|
||||
# email system managers
|
||||
from webnotes.utils.email_lib import sendmail
|
||||
sendmail(webnotes.conn.get_value("Backup Manager", None, "send_notifications_to").split(","),
|
||||
subject=subject, msg=message)
|
||||
if not webnotes.conn:
|
||||
webnotes.connect()
|
||||
|
||||
recipients = webnotes.conn.get_value("Backup Manager", None, "send_notifications_to").split(",")
|
||||
sendmail(recipients, subject=subject, msg=message)
|
||||
|
||||
@@ -9,6 +9,7 @@ from webnotes.utils import fmt_money, formatdate, now_datetime, cstr, esc, \
|
||||
from webnotes.utils.dateutils import datetime_in_user_format
|
||||
from datetime import timedelta
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from webnotes.utils.email_lib import sendmail
|
||||
|
||||
content_sequence = [
|
||||
["Income / Expenses", ["income_year_to_date", "bank_balance",
|
||||
@@ -80,15 +81,15 @@ class DocType(DocListController):
|
||||
for user_id in recipients:
|
||||
msg_for_this_receipient = self.get_msg_html(self.get_user_specific_content(user_id) + \
|
||||
common_msg)
|
||||
from webnotes.utils.email_lib import sendmail
|
||||
sendmail(recipients=user_id,
|
||||
subject="[ERPNext] [{frequency} Digest] {name}".format(
|
||||
frequency=self.doc.frequency, name=self.doc.name),
|
||||
msg=msg_for_this_receipient)
|
||||
if msg_for_this_receipient:
|
||||
sendmail(recipients=user_id,
|
||||
subject="[ERPNext] [{frequency} Digest] {name}".format(
|
||||
frequency=self.doc.frequency, name=self.doc.name),
|
||||
msg=msg_for_this_receipient)
|
||||
|
||||
def get_digest_msg(self):
|
||||
return self.get_msg_html(self.get_user_specific_content(webnotes.session.user) + \
|
||||
self.get_common_content())
|
||||
self.get_common_content(), send_only_if_updates=False)
|
||||
|
||||
def get_common_content(self):
|
||||
out = []
|
||||
@@ -119,14 +120,19 @@ class DocType(DocListController):
|
||||
|
||||
return out
|
||||
|
||||
def get_msg_html(self, out):
|
||||
def get_msg_html(self, out, send_only_if_updates=True):
|
||||
with_value = [o[1] for o in out if o[0]]
|
||||
|
||||
if with_value:
|
||||
has_updates = True
|
||||
with_value = "\n".join(with_value)
|
||||
else:
|
||||
has_updates = False
|
||||
with_value = "<p>There were no updates in the items selected for this digest.</p><hr>"
|
||||
|
||||
if not has_updates and send_only_if_updates:
|
||||
return
|
||||
|
||||
# seperate out no value items
|
||||
no_value = [o[1] for o in out if not o[0]]
|
||||
if no_value:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"creation": "2012-12-20 12:50:49",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-11-03 14:20:18",
|
||||
"modified": "2013-12-24 11:40:19",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
@@ -90,7 +90,7 @@
|
||||
"doctype": "DocField",
|
||||
"fieldname": "fs_packing_details",
|
||||
"fieldtype": "Check",
|
||||
"label": "Packing Detials"
|
||||
"label": "Packing Details"
|
||||
},
|
||||
{
|
||||
"description": "To get Item Group in details table",
|
||||
|
||||
@@ -98,7 +98,8 @@ def create_price_lists(args):
|
||||
{
|
||||
"doctype": "Price List",
|
||||
"price_list_name": "Standard " + pl_type,
|
||||
"buying_or_selling": pl_type,
|
||||
"buying": 1 if pl_type == "Buying" else 0,
|
||||
"selling": 1 if pl_type == "Selling" else 0,
|
||||
"currency": args["currency"]
|
||||
},
|
||||
{
|
||||
@@ -158,6 +159,10 @@ def set_defaults(args):
|
||||
hr_settings.doc.emp_created_by = "Naming Series"
|
||||
hr_settings.save()
|
||||
|
||||
email_settings = webnotes.bean("Email Settings")
|
||||
email_settings.doc.send_print_in_body_and_attachment = 1
|
||||
email_settings.save()
|
||||
|
||||
# control panel
|
||||
cp = webnotes.doc("Control Panel", "Control Panel")
|
||||
cp.company_name = args["company_name"]
|
||||
@@ -175,7 +180,8 @@ def create_email_digest():
|
||||
if not system_managers:
|
||||
return
|
||||
|
||||
for company in webnotes.conn.sql_list("select name FROM `tabCompany`"):
|
||||
companies = webnotes.conn.sql_list("select name FROM `tabCompany`")
|
||||
for company in companies:
|
||||
if not webnotes.conn.exists("Email Digest", "Default Weekly Digest - " + company):
|
||||
edigest = webnotes.bean({
|
||||
"doctype": "Email Digest",
|
||||
@@ -192,16 +198,17 @@ def create_email_digest():
|
||||
edigest.insert()
|
||||
|
||||
# scheduler errors digest
|
||||
edigest = webnotes.new_bean("Email Digest")
|
||||
edigest.doc.fields.update({
|
||||
"name": "Scheduler Errors",
|
||||
"company": webnotes.conn.get_default("company"),
|
||||
"frequency": "Daily",
|
||||
"recipient_list": "\n".join(system_managers),
|
||||
"scheduler_errors": 1,
|
||||
"enabled": 1
|
||||
})
|
||||
edigest.insert()
|
||||
if companies:
|
||||
edigest = webnotes.new_bean("Email Digest")
|
||||
edigest.doc.fields.update({
|
||||
"name": "Scheduler Errors",
|
||||
"company": companies[0],
|
||||
"frequency": "Daily",
|
||||
"recipient_list": "\n".join(system_managers),
|
||||
"scheduler_errors": 1,
|
||||
"enabled": 1
|
||||
})
|
||||
edigest.insert()
|
||||
|
||||
def get_fy_details(fy_start_date, fy_end_date):
|
||||
start_year = getdate(fy_start_date).year
|
||||
|
||||
@@ -53,6 +53,10 @@ def execute_daily():
|
||||
# email digest
|
||||
from setup.doctype.email_digest.email_digest import send
|
||||
run_fn(send)
|
||||
|
||||
# auto close support tickets
|
||||
from support.doctype.support_ticket.support_ticket import auto_close_tickets
|
||||
run_fn(auto_close_tickets)
|
||||
|
||||
def execute_weekly():
|
||||
from setup.doctype.backup_manager.backup_manager import take_backups_weekly
|
||||
|
||||
@@ -58,11 +58,6 @@ class TestDeliveryNote(unittest.TestCase):
|
||||
self.assertEqual(stock_value, 0)
|
||||
self.assertEqual(stock_value_difference, -375)
|
||||
|
||||
|
||||
gl_entries = webnotes.conn.sql("""select account, debit, credit
|
||||
from `tabGL Entry` where voucher_type='Delivery Note' and voucher_no=%s
|
||||
order by account desc""", dn.doc.name, as_dict=1)
|
||||
|
||||
self.assertFalse(get_gl_entries("Delivery Note", dn.doc.name))
|
||||
|
||||
def test_delivery_note_gl_entry(self):
|
||||
@@ -111,8 +106,8 @@ class TestDeliveryNote(unittest.TestCase):
|
||||
gl_entries = get_gl_entries("Delivery Note", dn.doc.name)
|
||||
self.assertTrue(gl_entries)
|
||||
expected_values = {
|
||||
stock_in_hand_account: [0.0, 666.65],
|
||||
"Cost of Goods Sold - _TC": [666.65, 0.0]
|
||||
stock_in_hand_account: [0.0, 666.67],
|
||||
"Cost of Goods Sold - _TC": [666.67, 0.0]
|
||||
}
|
||||
for i, gle in enumerate(gl_entries):
|
||||
self.assertEquals([gle.debit, gle.credit], expected_values.get(gle.account))
|
||||
|
||||
@@ -49,6 +49,7 @@ class DocType(DocListController, WebsiteGenerator):
|
||||
def on_update(self):
|
||||
self.validate_name_with_item_group()
|
||||
self.update_website()
|
||||
self.update_item_price()
|
||||
|
||||
def check_warehouse_is_set_for_stock_item(self):
|
||||
if self.doc.is_stock_item=="Yes" and not self.doc.default_warehouse:
|
||||
@@ -123,14 +124,14 @@ class DocType(DocListController, WebsiteGenerator):
|
||||
msgprint("'Has Serial No' can not be 'Yes' for non-stock item", raise_exception=1)
|
||||
|
||||
def check_for_active_boms(self):
|
||||
if self.doc.is_active != "Yes" or self.doc.is_purchase_item != "Yes":
|
||||
if self.doc.is_purchase_item != "Yes":
|
||||
bom_mat = webnotes.conn.sql("""select distinct t1.parent
|
||||
from `tabBOM Item` t1, `tabBOM` t2 where t2.name = t1.parent
|
||||
and t1.item_code =%s and ifnull(t1.bom_no, '') = '' and t2.is_active = 1
|
||||
and t2.docstatus = 1 and t1.docstatus =1 """, self.doc.name)
|
||||
|
||||
if bom_mat and bom_mat[0][0]:
|
||||
webnotes.throw(_("Item must be active and purchase item, \
|
||||
webnotes.throw(_("Item must be a purchase item, \
|
||||
as it is present in one or many Active BOMs"))
|
||||
|
||||
if self.doc.is_manufactured_item != "Yes":
|
||||
@@ -210,6 +211,11 @@ class DocType(DocListController, WebsiteGenerator):
|
||||
|
||||
WebsiteGenerator.on_update(self)
|
||||
|
||||
def update_item_price(self):
|
||||
webnotes.conn.sql("""update `tabItem Price` set item_name=%s,
|
||||
item_description=%s, modified=NOW() where item_code=%s""",
|
||||
(self.doc.item_name, self.doc.description, self.doc.name))
|
||||
|
||||
def get_page_title(self):
|
||||
if self.doc.name==self.doc.item_name:
|
||||
page_name_from = self.doc.name
|
||||
@@ -246,6 +252,9 @@ class DocType(DocListController, WebsiteGenerator):
|
||||
def before_rename(self, olddn, newdn, merge=False):
|
||||
if merge:
|
||||
# Validate properties before merging
|
||||
if not webnotes.conn.exists("Item", newdn):
|
||||
webnotes.throw(_("Item ") + newdn +_(" does not exists"))
|
||||
|
||||
field_list = ["stock_uom", "is_stock_item", "has_serial_no", "has_batch_no"]
|
||||
new_properties = [cstr(d) for d in webnotes.conn.get_value("Item", newdn, field_list)]
|
||||
if new_properties != [cstr(self.doc.fields[fld]) for fld in field_list]:
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
// License: GNU General Public License v3. See license.txt
|
||||
|
||||
$.extend(cur_frm.cscript, {
|
||||
|
||||
onload: function () {
|
||||
|
||||
// Fetch price list details
|
||||
cur_frm.add_fetch("price_list", "buying_or_selling", "buying_or_selling");
|
||||
cur_frm.add_fetch("price_list", "buying", "buying");
|
||||
cur_frm.add_fetch("price_list", "selling", "selling");
|
||||
cur_frm.add_fetch("price_list", "currency", "currency");
|
||||
|
||||
// Fetch item details
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||
# MIT License. See license.txt
|
||||
|
||||
# For license information, please see license.txt
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
@@ -19,8 +17,8 @@ class DocType:
|
||||
self.update_item_details()
|
||||
|
||||
def update_price_list_details(self):
|
||||
self.doc.buying_or_selling, self.doc.currency = webnotes.conn.get_value("Price List",
|
||||
self.doc.price_list, ["buying_or_selling", "currency"])
|
||||
self.doc.buying, self.doc.selling, self.doc.currency = webnotes.conn.get_value("Price List",
|
||||
self.doc.price_list, ["buying", "selling", "currency"])
|
||||
|
||||
def update_item_details(self):
|
||||
self.doc.item_name, self.doc.item_description = webnotes.conn.get_value("Item",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"creation": "2013-05-02 16:29:48",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-10-31 12:59:02",
|
||||
"modified": "2014-01-07 19:16:49",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
@@ -43,6 +43,13 @@
|
||||
"doctype": "DocType",
|
||||
"name": "Item Price"
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "price_list_details",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Price List",
|
||||
"options": "icon-tags"
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "price_list",
|
||||
@@ -52,6 +59,29 @@
|
||||
"options": "Price List",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "buying",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"label": "Buying",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "selling",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"label": "Selling",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "item_details",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Item",
|
||||
"options": "icon-tag"
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "item_code",
|
||||
@@ -83,16 +113,6 @@
|
||||
"fieldname": "col_br_1",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "buying_or_selling",
|
||||
"fieldtype": "Select",
|
||||
"in_filter": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "Valid for Buying or Selling?",
|
||||
"options": "Selling\nBuying",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "item_name",
|
||||
|
||||
@@ -125,6 +125,7 @@ class TestMaterialRequest(unittest.TestCase):
|
||||
from stock.doctype.material_request.material_request import make_purchase_order
|
||||
po_doclist = make_purchase_order(mr.doc.name)
|
||||
po_doclist[0].supplier = "_Test Supplier"
|
||||
po_doclist[0].transaction_date = "2013-07-07"
|
||||
po_doclist[1].qty = 27.0
|
||||
po_doclist[2].qty = 1.5
|
||||
po_doclist[1].schedule_date = "2013-07-09"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"creation": "2013-02-22 01:28:02",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-11-03 20:36:45",
|
||||
"modified": "2013-12-18 14:52:02",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
@@ -219,7 +219,7 @@
|
||||
"fieldname": "sales_order_no",
|
||||
"fieldtype": "Link",
|
||||
"label": "Sales Order No",
|
||||
"no_copy": 1,
|
||||
"no_copy": 0,
|
||||
"options": "Sales Order",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
.table-grid tbody tr {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.table-grid thead tr {
|
||||
height: 50px;
|
||||
}
|
||||
@@ -3,16 +3,15 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
from webnotes import msgprint, _
|
||||
from webnotes.utils import comma_or, cint
|
||||
from webnotes import msgprint, _, throw
|
||||
from webnotes.utils import cint
|
||||
from webnotes.model.controller import DocListController
|
||||
import webnotes.defaults
|
||||
|
||||
class DocType(DocListController):
|
||||
def validate(self):
|
||||
if self.doc.buying_or_selling not in ["Buying", "Selling"]:
|
||||
msgprint(_(self.meta.get_label("buying_or_selling")) + " " + _("must be one of") + " " +
|
||||
comma_or(["Buying", "Selling"]), raise_exception=True)
|
||||
if not cint(self.doc.buying) and not cint(self.doc.selling):
|
||||
throw(_("Price List must be applicable for Buying or Selling"))
|
||||
|
||||
if not self.doclist.get({"parentfield": "valid_for_territories"}):
|
||||
# if no territory, set default territory
|
||||
@@ -25,24 +24,24 @@ class DocType(DocListController):
|
||||
else:
|
||||
# at least one territory
|
||||
self.validate_table_has_rows("valid_for_territories")
|
||||
|
||||
|
||||
def on_update(self):
|
||||
self.set_default_if_missing()
|
||||
self.update_item_price()
|
||||
cart_settings = webnotes.get_obj("Shopping Cart Settings")
|
||||
if cint(cart_settings.doc.enabled):
|
||||
cart_settings.validate_price_lists()
|
||||
|
||||
|
||||
def set_default_if_missing(self):
|
||||
if self.doc.buying_or_selling=="Selling":
|
||||
if cint(self.doc.selling):
|
||||
if not webnotes.conn.get_value("Selling Settings", None, "selling_price_list"):
|
||||
webnotes.set_value("Selling Settings", "Selling Settings", "selling_price_list", self.doc.name)
|
||||
|
||||
elif self.doc.buying_or_selling=="Buying":
|
||||
elif cint(self.doc.buying):
|
||||
if not webnotes.conn.get_value("Buying Settings", None, "buying_price_list"):
|
||||
webnotes.set_value("Buying Settings", "Buying Settings", "buying_price_list", self.doc.name)
|
||||
|
||||
def update_item_price(self):
|
||||
webnotes.conn.sql("""update `tabItem Price` set currency=%s,
|
||||
buying_or_selling=%s where price_list=%s""",
|
||||
(self.doc.currency, self.doc.buying_or_selling, self.doc.name))
|
||||
buying=%s, selling=%s, modified=NOW() where price_list=%s""",
|
||||
(self.doc.currency, cint(self.doc.buying), cint(self.doc.selling), self.doc.name))
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"creation": "2013-01-25 11:35:09",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-10-31 19:24:33",
|
||||
"modified": "2014-01-06 18:28:23",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
@@ -61,14 +61,19 @@
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"default": "Selling",
|
||||
"doctype": "DocField",
|
||||
"fieldname": "buying_or_selling",
|
||||
"fieldtype": "Select",
|
||||
"fieldname": "buying",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"label": "Valid for Buying or Selling?",
|
||||
"options": "Buying\nSelling",
|
||||
"reqd": 1
|
||||
"label": "Buying"
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "selling",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"label": "Selling",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
|
||||
@@ -12,7 +12,7 @@ test_records = [
|
||||
"doctype": "Price List",
|
||||
"price_list_name": "_Test Price List",
|
||||
"currency": "INR",
|
||||
"buying_or_selling": "Selling"
|
||||
"selling": 1
|
||||
},
|
||||
{
|
||||
"doctype": "Applicable Territory",
|
||||
@@ -25,7 +25,7 @@ test_records = [
|
||||
"doctype": "Price List",
|
||||
"price_list_name": "_Test Price List 2",
|
||||
"currency": "INR",
|
||||
"buying_or_selling": "Selling"
|
||||
"selling": 1
|
||||
},
|
||||
{
|
||||
"doctype": "Applicable Territory",
|
||||
@@ -38,7 +38,7 @@ test_records = [
|
||||
"doctype": "Price List",
|
||||
"price_list_name": "_Test Price List India",
|
||||
"currency": "INR",
|
||||
"buying_or_selling": "Selling"
|
||||
"selling": 1
|
||||
},
|
||||
{
|
||||
"doctype": "Applicable Territory",
|
||||
@@ -51,7 +51,7 @@ test_records = [
|
||||
"doctype": "Price List",
|
||||
"price_list_name": "_Test Price List Rest of the World",
|
||||
"currency": "USD",
|
||||
"buying_or_selling": "Selling"
|
||||
"selling": 1
|
||||
},
|
||||
{
|
||||
"doctype": "Applicable Territory",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"creation": "2013-05-24 19:29:10",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-11-02 19:41:45",
|
||||
"modified": "2014-01-03 18:28:20",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
@@ -326,7 +326,7 @@
|
||||
"fieldname": "schedule_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Required By",
|
||||
"no_copy": 1,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "schedule_date",
|
||||
"oldfieldtype": "Date",
|
||||
"print_hide": 1,
|
||||
@@ -334,6 +334,16 @@
|
||||
"report_hide": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"default": ":Company",
|
||||
"depends_on": "eval:sys_defaults.auto_accounting_for_stock",
|
||||
"doctype": "DocField",
|
||||
"fieldname": "cost_center",
|
||||
"fieldtype": "Link",
|
||||
"label": "Cost Center",
|
||||
"options": "Cost Center",
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "project_name",
|
||||
|
||||
@@ -287,9 +287,16 @@ class DocType(StockController):
|
||||
# validate quantity <= ref item's qty - qty already returned
|
||||
ref_item = ref.doclist.getone({"item_code": item.item_code})
|
||||
returnable_qty = ref_item.qty - flt(already_returned_item_qty.get(item.item_code))
|
||||
self.validate_value("transfer_qty", "<=", returnable_qty, item,
|
||||
raise_exception=StockOverReturnError)
|
||||
|
||||
if not returnable_qty:
|
||||
webnotes.throw("{item}: {item_code} {returned}".format(
|
||||
item=_("Item"), item_code=item.item_code,
|
||||
returned=_("already returned though some other documents")),
|
||||
StockOverReturnError)
|
||||
elif item.transfer_qty > returnable_qty:
|
||||
webnotes.throw("{item}: {item_code}, {returned}: {qty}".format(
|
||||
item=_("Item"), item_code=item.item_code,
|
||||
returned=_("Max Returnable Qty"), qty=returnable_qty), StockOverReturnError)
|
||||
|
||||
def get_already_returned_item_qty(self, ref_fieldname):
|
||||
return dict(webnotes.conn.sql("""select item_code, sum(transfer_qty) as qty
|
||||
from `tabStock Entry Detail` where parent in (
|
||||
|
||||
@@ -20,6 +20,19 @@ class DocType:
|
||||
if self.doc.email_id and not validate_email_add(self.doc.email_id):
|
||||
msgprint("Please enter valid Email Id", raise_exception=1)
|
||||
|
||||
self.update_parent_account()
|
||||
|
||||
def update_parent_account(self):
|
||||
if not self.doc.__islocal and (self.doc.create_account_under !=
|
||||
webnotes.conn.get_value("Warehouse", self.doc.name, "create_account_under")):
|
||||
warehouse_account = webnotes.conn.get_value("Account",
|
||||
{"account_type": "Warehouse", "company": self.doc.company,
|
||||
"master_name": self.doc.name}, ["name", "parent_account"])
|
||||
if warehouse_account and warehouse_account[1] != self.doc.create_account_under:
|
||||
acc_bean = webnotes.bean("Account", warehouse_account[0])
|
||||
acc_bean.doc.parent_account = self.doc.create_account_under
|
||||
acc_bean.save()
|
||||
|
||||
def on_update(self):
|
||||
self.create_account_head()
|
||||
|
||||
@@ -84,6 +97,9 @@ class DocType:
|
||||
new_warehouse = get_name_with_abbr(newdn, self.doc.company)
|
||||
|
||||
if merge:
|
||||
if not webnotes.conn.exists("Warehouse", newdn):
|
||||
webnotes.throw(_("Warehouse ") + newdn +_(" does not exists"))
|
||||
|
||||
if self.doc.company != webnotes.conn.get_value("Warehouse", new_warehouse, "company"):
|
||||
webnotes.throw(_("Both Warehouse must belong to same Company"))
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ def execute(filters=None):
|
||||
bom_rate = get_item_bom_rate()
|
||||
val_rate_map = get_valuation_rate()
|
||||
|
||||
precision = webnotes.conn.get_value("Global Defaults", None, "float_precision") or 2
|
||||
|
||||
precision = get_currency_precision or 2
|
||||
|
||||
data = []
|
||||
for item in sorted(item_map):
|
||||
data.append([item, item_map[item]["item_name"],
|
||||
@@ -30,6 +30,14 @@ def execute(filters=None):
|
||||
])
|
||||
|
||||
return columns, data
|
||||
|
||||
def get_currency_precision():
|
||||
company_currency = webnotes.conn.get_value("Company",
|
||||
webnotes.conn.get_default("company"), "default_currency")
|
||||
currency_format = webnotes.conn.get_value("Currency", company_currency, "number_format")
|
||||
|
||||
from webnotes.utils import get_number_format_info
|
||||
return get_number_format_info(currency_format)[2]
|
||||
|
||||
def get_columns(filters):
|
||||
"""return columns based on filters"""
|
||||
@@ -57,13 +65,13 @@ def get_price_list():
|
||||
|
||||
rate = {}
|
||||
|
||||
price_list = webnotes.conn.sql("""select item_code, buying_or_selling,
|
||||
price_list = webnotes.conn.sql("""select item_code, buying, selling,
|
||||
concat(price_list, " - ", currency, " ", ref_rate) as price
|
||||
from `tabItem Price`""", as_dict=1)
|
||||
|
||||
for j in price_list:
|
||||
if j.price:
|
||||
rate.setdefault(j.item_code, {}).setdefault(j.buying_or_selling, []).append(j.price)
|
||||
rate.setdefault(j.item_code, {}).setdefault("Buying" if j.buying else "Selling", []).append(j.price)
|
||||
item_rate_map = {}
|
||||
|
||||
for item in rate:
|
||||
|
||||
0
stock/report/item_wise_price_list_rate/__init__.py
Normal file
0
stock/report/item_wise_price_list_rate/__init__.py
Normal file
@@ -0,0 +1,22 @@
|
||||
[
|
||||
{
|
||||
"creation": "2013-09-25 10:21:15",
|
||||
"docstatus": 0,
|
||||
"modified": "2014-01-07 18:35:22",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
{
|
||||
"doctype": "Report",
|
||||
"is_standard": "Yes",
|
||||
"json": "{\"filters\":[[\"Item Price\",\"price_list\",\"like\",\"%\"],[\"Item Price\",\"item_code\",\"like\",\"%\"]],\"columns\":[[\"name\",\"Item Price\"],[\"price_list\",\"Item Price\"],[\"item_code\",\"Item Price\"],[\"item_name\",\"Item Price\"],[\"item_description\",\"Item Price\"],[\"ref_rate\",\"Item Price\"],[\"buying\",\"Item Price\"],[\"selling\",\"Item Price\"],[\"currency\",\"Item Price\"]],\"sort_by\":\"Item Price.modified\",\"sort_order\":\"desc\",\"sort_by_next\":\"\",\"sort_order_next\":\"desc\"}",
|
||||
"name": "__common__",
|
||||
"ref_doctype": "Price List",
|
||||
"report_name": "Item-wise Price List Rate",
|
||||
"report_type": "Report Builder"
|
||||
},
|
||||
{
|
||||
"doctype": "Report",
|
||||
"name": "Item-wise Price List Rate"
|
||||
}
|
||||
]
|
||||
@@ -67,7 +67,7 @@ def get_stock_ledger_entries(filters):
|
||||
item.name, item.item_name, item_group, brand, description, item.stock_uom,
|
||||
actual_qty, posting_date
|
||||
from `tabStock Ledger Entry` sle,
|
||||
(select name, item_name, description, stock_uom, brand
|
||||
(select name, item_name, description, stock_uom, brand, item_group
|
||||
from `tabItem` {item_conditions}) item
|
||||
where item_code = item.name and
|
||||
company = %(company)s and
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
from webnotes import _
|
||||
|
||||
def execute(filters=None):
|
||||
columns = get_columns()
|
||||
@@ -13,10 +12,14 @@ def execute(filters=None):
|
||||
data = []
|
||||
for sle in sl_entries:
|
||||
item_detail = item_details[sle.item_code]
|
||||
voucher_link_icon = """<a href="%s"><i class="icon icon-share"
|
||||
style="cursor: pointer;"></i></a>""" \
|
||||
% ("/".join(["#Form", sle.voucher_type, sle.voucher_no]),)
|
||||
|
||||
data.append([sle.date, sle.item_code, item_detail.item_name, item_detail.item_group,
|
||||
item_detail.brand, item_detail.description, sle.warehouse, item_detail.stock_uom,
|
||||
sle.actual_qty, sle.qty_after_transaction, sle.stock_value, sle.voucher_type,
|
||||
sle.voucher_no, sle.batch_no, sle.serial_no, sle.company])
|
||||
sle.voucher_no, voucher_link_icon, sle.batch_no, sle.serial_no, sle.company])
|
||||
|
||||
return columns, data
|
||||
|
||||
@@ -25,17 +28,10 @@ def get_columns():
|
||||
"Item Group:Link/Item Group:100", "Brand:Link/Brand:100",
|
||||
"Description::200", "Warehouse:Link/Warehouse:100",
|
||||
"Stock UOM:Link/UOM:100", "Qty:Float:50", "Balance Qty:Float:80",
|
||||
"Balance Value:Currency:100", "Voucher Type::100", "Voucher #::100",
|
||||
"Balance Value:Currency:100", "Voucher Type::100", "Voucher #::100", "Link::30",
|
||||
"Batch:Link/Batch:100", "Serial #:Link/Serial No:100", "Company:Link/Company:100"]
|
||||
|
||||
def get_stock_ledger_entries(filters):
|
||||
if not filters.get("company"):
|
||||
webnotes.throw(_("Company is mandatory"))
|
||||
if not filters.get("from_date"):
|
||||
webnotes.throw(_("From Date is mandatory"))
|
||||
if not filters.get("to_date"):
|
||||
webnotes.throw(_("To Date is mandatory"))
|
||||
|
||||
return webnotes.conn.sql("""select concat_ws(" ", posting_date, posting_time) as date,
|
||||
item_code, warehouse, actual_qty, qty_after_transaction,
|
||||
stock_value, voucher_type, voucher_no, batch_no, serial_no, company
|
||||
@@ -66,6 +62,10 @@ def get_item_conditions(filters):
|
||||
|
||||
def get_sle_conditions(filters):
|
||||
conditions = []
|
||||
item_conditions=get_item_conditions(filters)
|
||||
if item_conditions:
|
||||
conditions.append("""item_code in (select name from tabItem
|
||||
{item_conditions})""".format(item_conditions=item_conditions))
|
||||
if filters.get("warehouse"):
|
||||
conditions.append("warehouse=%(warehouse)s")
|
||||
if filters.get("voucher_no"):
|
||||
|
||||
@@ -7,9 +7,7 @@ wn.query_reports["Stock Projected Qty"] = {
|
||||
"fieldname":"company",
|
||||
"label": wn._("Company"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Company",
|
||||
"default": wn.defaults.get_user_default("company"),
|
||||
"reqd": 1
|
||||
"options": "Company"
|
||||
},
|
||||
{
|
||||
"fieldname":"warehouse",
|
||||
|
||||
@@ -13,23 +13,23 @@ def execute(filters=None):
|
||||
projected_qty, item.re_order_level, item.re_order_qty
|
||||
from `tabBin` bin,
|
||||
(select name, company from tabWarehouse
|
||||
where company=%(company)s {warehouse_conditions}) wh,
|
||||
{warehouse_conditions}) wh,
|
||||
(select name, item_name, description, stock_uom, item_group,
|
||||
brand, re_order_level, re_order_qty
|
||||
from `tabItem` {item_conditions}) item
|
||||
where item_code = item.name and warehouse = wh.name
|
||||
order by item.name, wh.name"""\
|
||||
.format(item_conditions=get_item_conditions(filters),
|
||||
warehouse_conditions=get_warehouse_conditions(filters)), filters, debug=1)
|
||||
warehouse_conditions=get_warehouse_conditions(filters)), filters)
|
||||
|
||||
return columns, data
|
||||
|
||||
def get_columns():
|
||||
return ["Item Code:Link/Item:140", "Item Name::100", "Description::200",
|
||||
"Brand:Link/Brand:100", "Warehouse:Link/Warehouse:120", "UOM:Link/UOM:100",
|
||||
"Actual Qty:Float:100", "Planned Qty:Float:100", "Requested Qty:Float:110",
|
||||
"Ordered Qty:Float:100", "Reserved Qty:Float:100", "Projected Qty:Float:100",
|
||||
"Reorder Level:Float:100", "Reorder Qty:Float:100"]
|
||||
"Item Group:Link/Item Group:100", "Brand:Link/Brand:100", "Warehouse:Link/Warehouse:120",
|
||||
"UOM:Link/UOM:100", "Actual Qty:Float:100", "Planned Qty:Float:100",
|
||||
"Requested Qty:Float:110", "Ordered Qty:Float:100", "Reserved Qty:Float:100",
|
||||
"Projected Qty:Float:100", "Reorder Level:Float:100", "Reorder Qty:Float:100"]
|
||||
|
||||
def get_item_conditions(filters):
|
||||
conditions = []
|
||||
@@ -41,4 +41,10 @@ def get_item_conditions(filters):
|
||||
return "where {}".format(" and ".join(conditions)) if conditions else ""
|
||||
|
||||
def get_warehouse_conditions(filters):
|
||||
return " and name=%(warehouse)s" if filters.get("warehouse") else ""
|
||||
conditions = []
|
||||
if filters.get("company"):
|
||||
conditions.append("company=%(company)s")
|
||||
if filters.get("warehouse"):
|
||||
conditions.append("name=%(warehouse)s")
|
||||
|
||||
return "where {}".format(" and ".join(conditions)) if conditions else ""
|
||||
@@ -113,7 +113,14 @@ def update_entries_after(args, verbose=1):
|
||||
(qty_after_transaction * valuation_rate) or 0
|
||||
else:
|
||||
stock_value = sum((flt(batch[0]) * flt(batch[1]) for batch in stock_queue))
|
||||
|
||||
|
||||
# rounding as per precision
|
||||
from webnotes.model.meta import get_field_precision
|
||||
meta = webnotes.get_doctype("Stock Ledger Entry")
|
||||
|
||||
stock_value = flt(stock_value, get_field_precision(meta.get_field("stock_value"),
|
||||
webnotes._dict({"fields": sle})))
|
||||
|
||||
stock_value_difference = stock_value - prev_stock_value
|
||||
prev_stock_value = stock_value
|
||||
|
||||
|
||||
@@ -52,11 +52,6 @@ Original Query:
|
||||
subject = '['+cstr(d.name)+'] ' + cstr(d.subject), \
|
||||
msg = cstr(response))
|
||||
|
||||
def auto_close_tickets(self):
|
||||
webnotes.conn.sql("""update `tabSupport Ticket` set status = 'Closed'
|
||||
where status = 'Replied'
|
||||
and date_sub(curdate(),interval 15 Day) > modified""")
|
||||
|
||||
def get_support_mails():
|
||||
if cint(webnotes.conn.get_value('Email Settings', None, 'sync_support_mails')):
|
||||
SupportMailbox()
|
||||
|
||||
@@ -66,4 +66,9 @@ class DocType(TransactionBase):
|
||||
def set_status(name, status):
|
||||
st = webnotes.bean("Support Ticket", name)
|
||||
st.doc.status = status
|
||||
st.save()
|
||||
st.save()
|
||||
|
||||
def auto_close_tickets():
|
||||
webnotes.conn.sql("""update `tabSupport Ticket` set status = 'Closed'
|
||||
where status = 'Replied'
|
||||
and date_sub(curdate(),interval 15 Day) > modified""")
|
||||
@@ -1,49 +1,49 @@
|
||||
Data Import Template,,,,,,,
|
||||
Table:,Item Price,,,,,,
|
||||
,,,,,,,
|
||||
,,,,,,,
|
||||
Notes:,,,,,,,
|
||||
Please do not change the template headings.,,,,,,,
|
||||
First data column must be blank.,,,,,,,
|
||||
"If you are uploading new records, leave the ""name"""" (ID) column blank.""",,,,,,,
|
||||
"If you are uploading new records, ""Naming Series"""" becomes mandatory"," if present.""",,,,,,
|
||||
Only mandatory fields are necessary for new records. You can delete non-mandatory columns if you wish.,,,,,,,
|
||||
"For updating, you can update only selective columns.",,,,,,,
|
||||
You can only upload upto 5000 records in one go. (may be less in some cases),,,,,,,
|
||||
,,,,,,,
|
||||
DocType:,Item Price,,,,,,
|
||||
Column Labels:,ID,Price List,Item Code,Rate,Valid for Buying or Selling?,Item Name,Item Description
|
||||
Column Name:,name,price_list,item_code,ref_rate,buying_or_selling,item_name,item_description
|
||||
Mandatory:,Yes,Yes,Yes,Yes,No,No,No
|
||||
Type:,Data (text),Link,Link,Currency,Select,Data,Text
|
||||
Info:,,Valid Price List,Valid Item,,"One of: Selling, Buying",,
|
||||
Start entering data below this line,,,,,,,
|
||||
,,Standard Buying,Base Bearing Plate,15,Buying,,
|
||||
,,Standard Buying,Base Plate,20,Buying,,
|
||||
,,Standard Buying,Bearing Block,10,Buying,,
|
||||
,,Standard Buying,Bearing Collar,20,Buying,,
|
||||
,,Standard Buying,Bearing Pipe,15,Buying,,
|
||||
,,Standard Buying,Blade Rib,10,Buying,,
|
||||
,,Standard Buying,Disc Collars,74,Buying,,
|
||||
,,Standard Buying,External Disc,45,Buying,,
|
||||
,,Standard Buying,Internal Disc,33,Buying,,
|
||||
,,Standard Buying,Shaft,30,Buying,,
|
||||
,,Standard Buying,Stand,40,Buying,,
|
||||
,,Standard Buying,Upper Bearing Plate,50,Buying,,
|
||||
,,Standard Buying,Wing Sheet,22,Buying,,
|
||||
,,Standard Selling,Wind Turbine,21,Selling,,
|
||||
,,Standard Selling,Wind Mill A Series,28,Selling,,
|
||||
,,Standard Selling,Wind MIll C Series,14,Selling,,
|
||||
,,Standard Selling,Base Bearing Plate,28,Selling,,
|
||||
,,Standard Selling,Base Plate,21,Selling,,
|
||||
,,Standard Selling,Bearing Block,14,Selling,,
|
||||
,,Standard Selling,Bearing Collar,103.6,Selling,,
|
||||
,,Standard Selling,Bearing Pipe,63,Selling,,
|
||||
,,Standard Selling,Blade Rib,46.2,Selling,,
|
||||
,,Standard Selling,Disc Collars,42,Selling,,
|
||||
,,Standard Selling,External Disc,56,Selling,,
|
||||
,,Standard Selling,Internal Disc,70,Selling,,
|
||||
,,Standard Selling,Shaft,340,Selling,,
|
||||
,,Standard Selling,Stand,400,Selling,,
|
||||
,,Standard Selling,Upper Bearing Plate,300,Selling,,
|
||||
,,Standard Selling,Wing Sheet,30.8,Selling,,
|
||||
Data Import Template,,,,,,,,
|
||||
Table:,Item Price,,,,,,,
|
||||
,,,,,,,,
|
||||
,,,,,,,,
|
||||
Notes:,,,,,,,,
|
||||
Please do not change the template headings.,,,,,,,,
|
||||
First data column must be blank.,,,,,,,,
|
||||
"If you are uploading new records, leave the ""name"" (ID) column blank.",,,,,,,,
|
||||
"If you are uploading new records, ""Naming Series"" becomes mandatory, if present.",,,,,,,,
|
||||
Only mandatory fields are necessary for new records. You can delete non-mandatory columns if you wish.,,,,,,,,
|
||||
"For updating, you can update only selective columns.",,,,,,,,
|
||||
You can only upload upto 5000 records in one go. (may be less in some cases),,,,,,,,
|
||||
,,,,,,,,
|
||||
DocType:,Item Price,,,,,,,
|
||||
Column Labels:,ID,Price List,Item Code,Rate,Buying,Selling,Item Name,Item Description
|
||||
Column Name:,name,price_list,item_code,ref_rate,buying,selling,item_name,item_description
|
||||
Mandatory:,Yes,Yes,Yes,Yes,No,No,No,No
|
||||
Type:,Data (text),Link,Link,Currency,Check,Check,Data,Text
|
||||
Info:,,Valid Price List,Valid Item,,0 or 1,0 or 1,,
|
||||
Start entering data below this line,,,,,,,,
|
||||
,,Standard Buying,Base Bearing Plate,15,1,,,
|
||||
,,Standard Buying,Base Plate,20,1,,,
|
||||
,,Standard Buying,Bearing Block,10,1,,,
|
||||
,,Standard Buying,Bearing Collar,20,1,,,
|
||||
,,Standard Buying,Bearing Pipe,15,1,,,
|
||||
,,Standard Buying,Blade Rib,10,1,,,
|
||||
,,Standard Buying,Disc Collars,74,1,,,
|
||||
,,Standard Buying,External Disc,45,1,,,
|
||||
,,Standard Buying,Internal Disc,33,1,,,
|
||||
,,Standard Buying,Shaft,30,1,,,
|
||||
,,Standard Buying,Stand,40,1,,,
|
||||
,,Standard Buying,Upper Bearing Plate,50,1,,,
|
||||
,,Standard Buying,Wing Sheet,22,1,,,
|
||||
,,Standard Selling,Wind Turbine,21,,1,,
|
||||
,,Standard Selling,Wind Mill A Series,28,,1,,
|
||||
,,Standard Selling,Wind MIll C Series,14,,1,,
|
||||
,,Standard Selling,Base Bearing Plate,28,,1,,
|
||||
,,Standard Selling,Base Plate,21,,1,,
|
||||
,,Standard Selling,Bearing Block,14,,1,,
|
||||
,,Standard Selling,Bearing Collar,103.6,,1,,
|
||||
,,Standard Selling,Bearing Pipe,63,,1,,
|
||||
,,Standard Selling,Blade Rib,46.2,,1,,
|
||||
,,Standard Selling,Disc Collars,42,,1,,
|
||||
,,Standard Selling,External Disc,56,,1,,
|
||||
,,Standard Selling,Internal Disc,70,,1,,
|
||||
,,Standard Selling,Shaft,340,,1,,
|
||||
,,Standard Selling,Stand,400,,1,,
|
||||
,,Standard Selling,Upper Bearing Plate,300,,1,,
|
||||
,,Standard Selling,Wing Sheet,30.8,,1,,
|
||||
|
||||
|
Reference in New Issue
Block a user