blob: 31e622166e883dcca2d4520e91aeac7c3d90fa35 [file] [log] [blame]
Nabin Hait23941aa2013-01-29 11:32:38 +05301# ERPNext - web based ERP (http://erpnext.com)
2# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
3#
4# This program is free software: you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation, either version 3 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17from __future__ import unicode_literals
18
19import webnotes
Anand Doshi7da72dd2013-03-20 17:00:41 +053020from webnotes.utils import nowdate, cstr, flt, now
Nabin Haitfb3fd6e2013-01-30 19:16:13 +053021from webnotes.model.doc import addchild
22from webnotes import msgprint, _
Rushabh Mehta2e8d0782013-02-05 11:31:27 +053023from webnotes.utils import formatdate
Nabin Haita76a0682013-02-08 14:04:13 +053024from utilities import build_filter_conditions
25
Nabin Hait23941aa2013-01-29 11:32:38 +053026
27class FiscalYearError(webnotes.ValidationError): pass
28
29def get_fiscal_year(date, verbose=1):
Rushabh Mehtac2563ef2013-02-05 23:25:37 +053030 return get_fiscal_years(date, verbose=1)[0]
31
32def get_fiscal_years(date, verbose=1):
Nabin Hait23941aa2013-01-29 11:32:38 +053033 # if year start date is 2012-04-01, year end date should be 2013-03-31 (hence subdate)
34 fy = webnotes.conn.sql("""select name, year_start_date,
35 subdate(adddate(year_start_date, interval 1 year), interval 1 day)
36 as year_end_date
37 from `tabFiscal Year`
38 where %s >= year_start_date and %s < adddate(year_start_date, interval 1 year)
39 order by year_start_date desc""", (date, date))
40
41 if not fy:
42 error_msg = """%s not in any Fiscal Year""" % formatdate(date)
43 if verbose: webnotes.msgprint(error_msg)
44 raise FiscalYearError, error_msg
45
Rushabh Mehtac2563ef2013-02-05 23:25:37 +053046 return fy
Rushabh Mehta2e8d0782013-02-05 11:31:27 +053047
48def validate_fiscal_year(date, fiscal_year, label="Date"):
Rushabh Mehtac2563ef2013-02-05 23:25:37 +053049 years = [f[0] for f in get_fiscal_years(date)]
50 if fiscal_year not in years:
Rushabh Mehta96075822013-02-05 11:39:49 +053051 webnotes.msgprint(("%(label)s '%(posting_date)s': " + _("not within Fiscal Year") + \
Rushabh Mehta2e8d0782013-02-05 11:31:27 +053052 ": '%(fiscal_year)s'") % {
53 "label": label,
54 "posting_date": formatdate(date),
55 "fiscal_year": fiscal_year
56 }, raise_exception=1)
Nabin Hait23941aa2013-01-29 11:32:38 +053057
58@webnotes.whitelist()
59def get_balance_on(account=None, date=None):
60 if not account and webnotes.form_dict.get("account"):
61 account = webnotes.form_dict.get("account")
62 date = webnotes.form_dict.get("date")
63
64 cond = []
65 if date:
66 cond.append("posting_date <= '%s'" % date)
67 else:
68 # get balance of all entries that exist
69 date = nowdate()
70
71 try:
72 year_start_date = get_fiscal_year(date, verbose=0)[1]
73 except FiscalYearError, e:
74 from webnotes.utils import getdate
75 if getdate(date) > getdate(nowdate()):
76 # if fiscal year not found and the date is greater than today
77 # get fiscal year for today's date and its corresponding year start date
78 year_start_date = get_fiscal_year(nowdate(), verbose=1)[1]
79 else:
80 # this indicates that it is a date older than any existing fiscal year.
81 # hence, assuming balance as 0.0
82 return 0.0
83
84 acc = webnotes.conn.get_value('Account', account, \
85 ['lft', 'rgt', 'debit_or_credit', 'is_pl_account', 'group_or_ledger'], as_dict=1)
86
87 # for pl accounts, get balance within a fiscal year
88 if acc.is_pl_account == 'Yes':
89 cond.append("posting_date >= '%s' and voucher_type != 'Period Closing Voucher'" \
90 % year_start_date)
91
92 # different filter for group and ledger - improved performance
93 if acc.group_or_ledger=="Group":
94 cond.append("""exists (
95 select * from `tabAccount` ac where ac.name = gle.account
96 and ac.lft >= %s and ac.rgt <= %s
97 )""" % (acc.lft, acc.rgt))
98 else:
99 cond.append("""gle.account = "%s" """ % (account, ))
100
101 # join conditional conditions
102 cond = " and ".join(cond)
103 if cond:
104 cond += " and "
105
106 bal = webnotes.conn.sql("""
107 SELECT sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))
108 FROM `tabGL Entry` gle
109 WHERE %s ifnull(is_cancelled, 'No') = 'No' """ % (cond, ))[0][0]
110
111 # if credit account, it should calculate credit - debit
112 if bal and acc.debit_or_credit == 'Credit':
113 bal = -bal
114
115 # if bal is None, return 0
Nabin Haitfb3fd6e2013-01-30 19:16:13 +0530116 return bal or 0
117
118@webnotes.whitelist()
119def add_ac(args=None):
120 if not args:
121 args = webnotes.form_dict
122 args.pop("cmd")
Rushabh Mehtaaae45532013-02-15 14:39:34 +0530123
Rushabh Mehtac53231a2013-02-18 18:24:28 +0530124 ac = webnotes.bean(args)
Nabin Haitfb3fd6e2013-01-30 19:16:13 +0530125 ac.doc.doctype = "Account"
126 ac.doc.old_parent = ""
127 ac.doc.freeze_account = "No"
128 ac.ignore_permissions = 1
129 ac.insert()
130 return ac.doc.name
131
132@webnotes.whitelist()
133def add_cc(args=None):
134 if not args:
135 args = webnotes.form_dict
136 args.pop("cmd")
137
Rushabh Mehtac53231a2013-02-18 18:24:28 +0530138 cc = webnotes.bean(args)
Nabin Haitfb3fd6e2013-01-30 19:16:13 +0530139 cc.doc.doctype = "Cost Center"
140 cc.doc.old_parent = ""
141 cc.ignore_permissions = 1
142 cc.insert()
143 return cc.doc.name
144
145def reconcile_against_document(args):
146 """
147 Cancel JV, Update aginst document, split if required and resubmit jv
148 """
149 for d in args:
150 check_if_jv_modified(d)
151
152 against_fld = {
153 'Journal Voucher' : 'against_jv',
154 'Sales Invoice' : 'against_invoice',
155 'Purchase Invoice' : 'against_voucher'
156 }
157
158 d['against_fld'] = against_fld[d['against_voucher_type']]
159
160 # cancel JV
161 jv_obj = webnotes.get_obj('Journal Voucher', d['voucher_no'], with_children=1)
162 jv_obj.make_gl_entries(cancel=1, adv_adj=1)
163
164 # update ref in JV Detail
165 update_against_doc(d, jv_obj)
166
167 # re-submit JV
168 jv_obj = webnotes.get_obj('Journal Voucher', d['voucher_no'], with_children =1)
169 jv_obj.make_gl_entries(cancel = 0, adv_adj =1)
170
171
172def check_if_jv_modified(args):
173 """
174 check if there is already a voucher reference
175 check if amount is same
176 check if jv is submitted
177 """
178 ret = webnotes.conn.sql("""
179 select t2.%(dr_or_cr)s from `tabJournal Voucher` t1, `tabJournal Voucher Detail` t2
180 where t1.name = t2.parent and t2.account = '%(account)s'
181 and ifnull(t2.against_voucher, '')=''
182 and ifnull(t2.against_invoice, '')='' and ifnull(t2.against_jv, '')=''
183 and t1.name = '%(voucher_no)s' and t2.name = '%(voucher_detail_no)s'
184 and t1.docstatus=1 and t2.%(dr_or_cr)s = %(unadjusted_amt)s""" % args)
185
186 if not ret:
187 msgprint(_("""Payment Entry has been modified after you pulled it.
188 Please pull it again."""), raise_exception=1)
189
190def update_against_doc(d, jv_obj):
191 """
192 Updates against document, if partial amount splits into rows
193 """
194
195 webnotes.conn.sql("""
196 update `tabJournal Voucher Detail` t1, `tabJournal Voucher` t2
197 set t1.%(dr_or_cr)s = '%(allocated_amt)s',
198 t1.%(against_fld)s = '%(against_voucher)s', t2.modified = now()
199 where t1.name = '%(voucher_detail_no)s' and t1.parent = t2.name""" % d)
200
201 if d['allocated_amt'] < d['unadjusted_amt']:
202 jvd = webnotes.conn.sql("""select cost_center, balance, against_account, is_advance
203 from `tabJournal Voucher Detail` where name = %s""", d['voucher_detail_no'])
204 # new entry with balance amount
205 ch = addchild(jv_obj.doc, 'entries', 'Journal Voucher Detail')
206 ch.account = d['account']
207 ch.cost_center = cstr(jvd[0][0])
208 ch.balance = cstr(jvd[0][1])
209 ch.fields[d['dr_or_cr']] = flt(d['unadjusted_amt']) - flt(d['allocated_amt'])
210 ch.fields[d['dr_or_cr']== 'debit' and 'credit' or 'debit'] = 0
211 ch.against_account = cstr(jvd[0][2])
212 ch.is_advance = cstr(jvd[0][3])
213 ch.docstatus = 1
Nabin Haita76a0682013-02-08 14:04:13 +0530214 ch.save(1)
215
216def get_account_list(doctype, txt, searchfield, start, page_len, filters):
217 if not filters.get("group_or_ledger"):
218 filters["group_or_ledger"] = "Ledger"
219
220 conditions, filter_values = build_filter_conditions(filters)
221
222 return webnotes.conn.sql("""select name, parent_account from `tabAccount`
223 where docstatus < 2 %s and %s like %s order by name limit %s, %s""" %
224 (conditions, searchfield, "%s", "%s", "%s"),
225 tuple(filter_values + ["%%%s%%" % txt, start, page_len]))
226
227def get_cost_center_list(doctype, txt, searchfield, start, page_len, filters):
228 if not filters.get("group_or_ledger"):
229 filters["group_or_ledger"] = "Ledger"
230
231 conditions, filter_values = build_filter_conditions(filters)
232
233 return webnotes.conn.sql("""select name, parent_cost_center from `tabCost Center`
234 where docstatus < 2 %s and %s like %s order by name limit %s, %s""" %
235 (conditions, searchfield, "%s", "%s", "%s"),
Anand Doshi7da72dd2013-03-20 17:00:41 +0530236 tuple(filter_values + ["%%%s%%" % txt, start, page_len]))
237
238def remove_against_link_from_jv(ref_type, ref_no, against_field):
239 webnotes.conn.sql("""update `tabJournal Voucher Detail` set `%s`=null,
240 modified=%s, modified_by=%s
241 where `%s`=%s and docstatus < 2""" % (against_field, "%s", "%s", against_field, "%s"),
242 (now(), webnotes.session.user, ref_no))
243
244 webnotes.conn.sql("""update `tabGL Entry`
245 set against_voucher_type=null, against_voucher=null,
246 modified=%s, modified_by=%s
247 where against_voucher_type=%s and against_voucher=%s
248 and voucher_no != ifnull(against_voucher, "")
249 and ifnull(is_cancelled, "No")="No" """,
250 (now(), webnotes.session.user, ref_type, ref_no))
Nabin Hait0fc24542013-03-25 11:06:00 +0530251
252@webnotes.whitelist()
253def get_company_default(company, fieldname):
254 value = webnotes.conn.get_value("Company", company, fieldname)
255
256 if not value:
257 msgprint(_("Please mention default value for '") +
258 _(webnotes.get_doctype("company").get_label(fieldname) +
259 _("' in Company: ") + company), raise_exception=True)
260
261 return value
262
263def create_stock_in_hand_jv(reverse=False):
264 from webnotes.utils import nowdate
265 today = nowdate()
266 fiscal_year = get_fiscal_year(today)[0]
Nabin Hait787c02e2013-03-29 16:42:33 +0530267 jv_list = []
Nabin Hait0fc24542013-03-25 11:06:00 +0530268
269 for company in webnotes.conn.sql_list("select name from `tabCompany`"):
270 stock_rbnb_value = get_stock_rbnb_value(company)
Nabin Hait787c02e2013-03-29 16:42:33 +0530271 stock_rbnb_value = reverse and -1*stock_rbnb_value or stock_rbnb_value
272 if stock_rbnb_value:
273 jv = webnotes.bean([
274 {
275 "doctype": "Journal Voucher",
Anand Doshi72edc3d2013-05-29 12:13:16 +0530276 "naming_series": "JV-AUTO-",
Nabin Hait787c02e2013-03-29 16:42:33 +0530277 "company": company,
278 "posting_date": today,
279 "fiscal_year": fiscal_year,
280 "voucher_type": "Journal Entry",
Anand Doshi72edc3d2013-05-29 12:13:16 +0530281 "user_remark": (_("Auto Inventory Accounting") + ": " +
282 (_("Disabled") if reverse else _("Enabled")) + ". " +
283 _("Journal Entry for inventory that is received but not yet invoiced"))
Nabin Hait787c02e2013-03-29 16:42:33 +0530284 },
285 {
286 "doctype": "Journal Voucher Detail",
287 "parentfield": "entries",
288 "account": get_company_default(company, "stock_received_but_not_billed"),
Anand Doshi72edc3d2013-05-29 12:13:16 +0530289 (stock_rbnb_value > 0 and "credit" or "debit"): abs(stock_rbnb_value)
Nabin Hait787c02e2013-03-29 16:42:33 +0530290 },
291 {
292 "doctype": "Journal Voucher Detail",
293 "parentfield": "entries",
294 "account": get_company_default(company, "stock_adjustment_account"),
Anand Doshi72edc3d2013-05-29 12:13:16 +0530295 (stock_rbnb_value > 0 and "debit" or "credit"): abs(stock_rbnb_value),
Nabin Hait787c02e2013-03-29 16:42:33 +0530296 "cost_center": get_company_default(company, "stock_adjustment_cost_center")
297 },
298 ])
299 jv.insert()
Nabin Hait787c02e2013-03-29 16:42:33 +0530300
301 jv_list.append(jv.doc.name)
302
303 if jv_list:
Anand Doshi72edc3d2013-05-29 12:13:16 +0530304 msgprint(_("Following Journal Vouchers have been created automatically") + \
305 ":\n%s" % ("\n".join([("<a href=\"#Form/Journal Voucher/%s\">%s</a>" % (jv, jv)) for jv in jv_list]),))
306
307 msgprint(_("""These adjustment vouchers book the difference between \
308 the total value of received items and the total value of invoiced items, \
309 as a required step to use Auto Inventory Accounting.
310 This is an approximation to get you started.
311 You will need to submit these vouchers after checking if the values are correct.
312 For more details, read: \
313 <a href="http://erpnext.com/auto-inventory-accounting" target="_blank">\
314 Auto Inventory Accounting</a>"""))
Nabin Hait787c02e2013-03-29 16:42:33 +0530315
316 webnotes.msgprint("""Please refresh the system to get effect of Auto Inventory Accounting""")
317
Nabin Hait0fc24542013-03-25 11:06:00 +0530318
Nabin Hait787c02e2013-03-29 16:42:33 +0530319def get_stock_rbnb_value(company):
320 total_received_amount = webnotes.conn.sql("""select sum(valuation_rate*qty*conversion_factor)
Nabin Hait0fc24542013-03-25 11:06:00 +0530321 from `tabPurchase Receipt Item` pr_item where docstatus=1
322 and exists(select name from `tabItem` where name = pr_item.item_code
323 and is_stock_item='Yes')
Nabin Hait41fe3562013-03-28 15:54:11 +0530324 and exists(select name from `tabPurchase Receipt`
Nabin Hait0fc24542013-03-25 11:06:00 +0530325 where name = pr_item.parent and company = %s)""", company)
326
Nabin Hait787c02e2013-03-29 16:42:33 +0530327 total_billed_amount = webnotes.conn.sql("""select sum(valuation_rate*qty*conversion_factor)
Nabin Hait0fc24542013-03-25 11:06:00 +0530328 from `tabPurchase Invoice Item` pi_item where docstatus=1
329 and exists(select name from `tabItem` where name = pi_item.item_code
330 and is_stock_item='Yes')
Nabin Hait41fe3562013-03-28 15:54:11 +0530331 and exists(select name from `tabPurchase Invoice`
Nabin Hait0fc24542013-03-25 11:06:00 +0530332 where name = pi_item.parent and company = %s)""", company)
Nabin Hait0fc24542013-03-25 11:06:00 +0530333 return flt(total_received_amount[0][0]) - flt(total_billed_amount[0][0])
Nabin Hait8b509f52013-05-28 16:52:30 +0530334
335
336def fix_total_debit_credit():
337 vouchers = webnotes.conn.sql("""select voucher_type, voucher_no,
338 sum(debit) - sum(credit) as diff
339 from `tabGL Entry`
340 group by voucher_type, voucher_no
341 having sum(ifnull(debit, 0)) != sum(ifnull(credit, 0))""", as_dict=1)
342
343 for d in vouchers:
344 if abs(d.diff) > 0:
345 dr_or_cr = d.voucher_type == "Sales Invoice" and "credit" or "debit"
346
347 webnotes.conn.sql("""update `tabGL Entry` set %s = %s + %s
348 where voucher_type = %s and voucher_no = %s and %s > 0 limit 1""" %
349 (dr_or_cr, dr_or_cr, '%s', '%s', '%s', dr_or_cr),
350 (d.diff, d.voucher_type, d.voucher_no), debug=1)