blob: eb240e796c02b3ccdfad173faa197438ed09950f [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"
Nabin Haitfb3fd6e2013-01-30 19:16:13 +0530128 ac.insert()
129 return ac.doc.name
130
131@webnotes.whitelist()
132def add_cc(args=None):
133 if not args:
134 args = webnotes.form_dict
135 args.pop("cmd")
136
Rushabh Mehtac53231a2013-02-18 18:24:28 +0530137 cc = webnotes.bean(args)
Nabin Haitfb3fd6e2013-01-30 19:16:13 +0530138 cc.doc.doctype = "Cost Center"
139 cc.doc.old_parent = ""
Nabin Haitfb3fd6e2013-01-30 19:16:13 +0530140 cc.insert()
141 return cc.doc.name
142
143def reconcile_against_document(args):
144 """
145 Cancel JV, Update aginst document, split if required and resubmit jv
146 """
147 for d in args:
148 check_if_jv_modified(d)
149
150 against_fld = {
151 'Journal Voucher' : 'against_jv',
152 'Sales Invoice' : 'against_invoice',
153 'Purchase Invoice' : 'against_voucher'
154 }
155
156 d['against_fld'] = against_fld[d['against_voucher_type']]
157
158 # cancel JV
159 jv_obj = webnotes.get_obj('Journal Voucher', d['voucher_no'], with_children=1)
160 jv_obj.make_gl_entries(cancel=1, adv_adj=1)
161
162 # update ref in JV Detail
163 update_against_doc(d, jv_obj)
164
165 # re-submit JV
166 jv_obj = webnotes.get_obj('Journal Voucher', d['voucher_no'], with_children =1)
167 jv_obj.make_gl_entries(cancel = 0, adv_adj =1)
168
169
170def check_if_jv_modified(args):
171 """
172 check if there is already a voucher reference
173 check if amount is same
174 check if jv is submitted
175 """
176 ret = webnotes.conn.sql("""
177 select t2.%(dr_or_cr)s from `tabJournal Voucher` t1, `tabJournal Voucher Detail` t2
178 where t1.name = t2.parent and t2.account = '%(account)s'
179 and ifnull(t2.against_voucher, '')=''
180 and ifnull(t2.against_invoice, '')='' and ifnull(t2.against_jv, '')=''
181 and t1.name = '%(voucher_no)s' and t2.name = '%(voucher_detail_no)s'
182 and t1.docstatus=1 and t2.%(dr_or_cr)s = %(unadjusted_amt)s""" % args)
183
184 if not ret:
185 msgprint(_("""Payment Entry has been modified after you pulled it.
186 Please pull it again."""), raise_exception=1)
187
188def update_against_doc(d, jv_obj):
189 """
190 Updates against document, if partial amount splits into rows
191 """
192
193 webnotes.conn.sql("""
194 update `tabJournal Voucher Detail` t1, `tabJournal Voucher` t2
195 set t1.%(dr_or_cr)s = '%(allocated_amt)s',
196 t1.%(against_fld)s = '%(against_voucher)s', t2.modified = now()
197 where t1.name = '%(voucher_detail_no)s' and t1.parent = t2.name""" % d)
198
199 if d['allocated_amt'] < d['unadjusted_amt']:
200 jvd = webnotes.conn.sql("""select cost_center, balance, against_account, is_advance
201 from `tabJournal Voucher Detail` where name = %s""", d['voucher_detail_no'])
202 # new entry with balance amount
203 ch = addchild(jv_obj.doc, 'entries', 'Journal Voucher Detail')
204 ch.account = d['account']
205 ch.cost_center = cstr(jvd[0][0])
206 ch.balance = cstr(jvd[0][1])
207 ch.fields[d['dr_or_cr']] = flt(d['unadjusted_amt']) - flt(d['allocated_amt'])
208 ch.fields[d['dr_or_cr']== 'debit' and 'credit' or 'debit'] = 0
209 ch.against_account = cstr(jvd[0][2])
210 ch.is_advance = cstr(jvd[0][3])
211 ch.docstatus = 1
Nabin Haita76a0682013-02-08 14:04:13 +0530212 ch.save(1)
213
214def get_account_list(doctype, txt, searchfield, start, page_len, filters):
215 if not filters.get("group_or_ledger"):
216 filters["group_or_ledger"] = "Ledger"
217
218 conditions, filter_values = build_filter_conditions(filters)
219
220 return webnotes.conn.sql("""select name, parent_account from `tabAccount`
221 where docstatus < 2 %s and %s like %s order by name limit %s, %s""" %
222 (conditions, searchfield, "%s", "%s", "%s"),
223 tuple(filter_values + ["%%%s%%" % txt, start, page_len]))
224
225def get_cost_center_list(doctype, txt, searchfield, start, page_len, filters):
226 if not filters.get("group_or_ledger"):
227 filters["group_or_ledger"] = "Ledger"
228
229 conditions, filter_values = build_filter_conditions(filters)
230
231 return webnotes.conn.sql("""select name, parent_cost_center from `tabCost Center`
232 where docstatus < 2 %s and %s like %s order by name limit %s, %s""" %
233 (conditions, searchfield, "%s", "%s", "%s"),
Anand Doshi7da72dd2013-03-20 17:00:41 +0530234 tuple(filter_values + ["%%%s%%" % txt, start, page_len]))
235
236def remove_against_link_from_jv(ref_type, ref_no, against_field):
237 webnotes.conn.sql("""update `tabJournal Voucher Detail` set `%s`=null,
238 modified=%s, modified_by=%s
239 where `%s`=%s and docstatus < 2""" % (against_field, "%s", "%s", against_field, "%s"),
240 (now(), webnotes.session.user, ref_no))
241
242 webnotes.conn.sql("""update `tabGL Entry`
243 set against_voucher_type=null, against_voucher=null,
244 modified=%s, modified_by=%s
245 where against_voucher_type=%s and against_voucher=%s
246 and voucher_no != ifnull(against_voucher, "")
247 and ifnull(is_cancelled, "No")="No" """,
248 (now(), webnotes.session.user, ref_type, ref_no))
Nabin Hait0fc24542013-03-25 11:06:00 +0530249
250@webnotes.whitelist()
251def get_company_default(company, fieldname):
252 value = webnotes.conn.get_value("Company", company, fieldname)
253
254 if not value:
255 msgprint(_("Please mention default value for '") +
256 _(webnotes.get_doctype("company").get_label(fieldname) +
257 _("' in Company: ") + company), raise_exception=True)
258
259 return value
260
261def create_stock_in_hand_jv(reverse=False):
262 from webnotes.utils import nowdate
263 today = nowdate()
264 fiscal_year = get_fiscal_year(today)[0]
Nabin Hait787c02e2013-03-29 16:42:33 +0530265 jv_list = []
Nabin Hait0fc24542013-03-25 11:06:00 +0530266
267 for company in webnotes.conn.sql_list("select name from `tabCompany`"):
268 stock_rbnb_value = get_stock_rbnb_value(company)
Nabin Hait787c02e2013-03-29 16:42:33 +0530269 stock_rbnb_value = reverse and -1*stock_rbnb_value or stock_rbnb_value
270 if stock_rbnb_value:
271 jv = webnotes.bean([
272 {
273 "doctype": "Journal Voucher",
Anand Doshi72edc3d2013-05-29 12:13:16 +0530274 "naming_series": "JV-AUTO-",
Nabin Hait787c02e2013-03-29 16:42:33 +0530275 "company": company,
276 "posting_date": today,
277 "fiscal_year": fiscal_year,
278 "voucher_type": "Journal Entry",
Anand Doshi72edc3d2013-05-29 12:13:16 +0530279 "user_remark": (_("Auto Inventory Accounting") + ": " +
280 (_("Disabled") if reverse else _("Enabled")) + ". " +
281 _("Journal Entry for inventory that is received but not yet invoiced"))
Nabin Hait787c02e2013-03-29 16:42:33 +0530282 },
283 {
284 "doctype": "Journal Voucher Detail",
285 "parentfield": "entries",
286 "account": get_company_default(company, "stock_received_but_not_billed"),
Anand Doshi72edc3d2013-05-29 12:13:16 +0530287 (stock_rbnb_value > 0 and "credit" or "debit"): abs(stock_rbnb_value)
Nabin Hait787c02e2013-03-29 16:42:33 +0530288 },
289 {
290 "doctype": "Journal Voucher Detail",
291 "parentfield": "entries",
292 "account": get_company_default(company, "stock_adjustment_account"),
Anand Doshi72edc3d2013-05-29 12:13:16 +0530293 (stock_rbnb_value > 0 and "debit" or "credit"): abs(stock_rbnb_value),
Nabin Hait787c02e2013-03-29 16:42:33 +0530294 "cost_center": get_company_default(company, "stock_adjustment_cost_center")
295 },
296 ])
297 jv.insert()
Nabin Hait787c02e2013-03-29 16:42:33 +0530298
299 jv_list.append(jv.doc.name)
300
301 if jv_list:
Anand Doshi72edc3d2013-05-29 12:13:16 +0530302 msgprint(_("Following Journal Vouchers have been created automatically") + \
303 ":\n%s" % ("\n".join([("<a href=\"#Form/Journal Voucher/%s\">%s</a>" % (jv, jv)) for jv in jv_list]),))
304
305 msgprint(_("""These adjustment vouchers book the difference between \
306 the total value of received items and the total value of invoiced items, \
307 as a required step to use Auto Inventory Accounting.
308 This is an approximation to get you started.
309 You will need to submit these vouchers after checking if the values are correct.
310 For more details, read: \
311 <a href="http://erpnext.com/auto-inventory-accounting" target="_blank">\
312 Auto Inventory Accounting</a>"""))
Nabin Hait787c02e2013-03-29 16:42:33 +0530313
314 webnotes.msgprint("""Please refresh the system to get effect of Auto Inventory Accounting""")
315
Nabin Hait0fc24542013-03-25 11:06:00 +0530316
Nabin Hait787c02e2013-03-29 16:42:33 +0530317def get_stock_rbnb_value(company):
318 total_received_amount = webnotes.conn.sql("""select sum(valuation_rate*qty*conversion_factor)
Nabin Hait0fc24542013-03-25 11:06:00 +0530319 from `tabPurchase Receipt Item` pr_item where docstatus=1
320 and exists(select name from `tabItem` where name = pr_item.item_code
321 and is_stock_item='Yes')
Nabin Hait41fe3562013-03-28 15:54:11 +0530322 and exists(select name from `tabPurchase Receipt`
Nabin Hait0fc24542013-03-25 11:06:00 +0530323 where name = pr_item.parent and company = %s)""", company)
324
Nabin Hait787c02e2013-03-29 16:42:33 +0530325 total_billed_amount = webnotes.conn.sql("""select sum(valuation_rate*qty*conversion_factor)
Nabin Hait0fc24542013-03-25 11:06:00 +0530326 from `tabPurchase Invoice Item` pi_item where docstatus=1
327 and exists(select name from `tabItem` where name = pi_item.item_code
328 and is_stock_item='Yes')
Nabin Hait41fe3562013-03-28 15:54:11 +0530329 and exists(select name from `tabPurchase Invoice`
Nabin Hait0fc24542013-03-25 11:06:00 +0530330 where name = pi_item.parent and company = %s)""", company)
Nabin Hait0fc24542013-03-25 11:06:00 +0530331 return flt(total_received_amount[0][0]) - flt(total_billed_amount[0][0])
Nabin Hait8b509f52013-05-28 16:52:30 +0530332
333
334def fix_total_debit_credit():
335 vouchers = webnotes.conn.sql("""select voucher_type, voucher_no,
336 sum(debit) - sum(credit) as diff
337 from `tabGL Entry`
338 group by voucher_type, voucher_no
339 having sum(ifnull(debit, 0)) != sum(ifnull(credit, 0))""", as_dict=1)
340
341 for d in vouchers:
342 if abs(d.diff) > 0:
343 dr_or_cr = d.voucher_type == "Sales Invoice" and "credit" or "debit"
344
345 webnotes.conn.sql("""update `tabGL Entry` set %s = %s + %s
346 where voucher_type = %s and voucher_no = %s and %s > 0 limit 1""" %
347 (dr_or_cr, dr_or_cr, '%s', '%s', '%s', dr_or_cr),
348 (d.diff, d.voucher_type, d.voucher_no), debug=1)