blob: 3de445c68d967bccb07570324593531cb47daf0b [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
Nabin Haitcfecd2b2013-07-11 17:49:18 +053029def get_fiscal_year(date=None, fiscal_year=None, label="Date", verbose=1):
30 return get_fiscal_years(date, fiscal_year, label, verbose=1)[0]
Rushabh Mehtac2563ef2013-02-05 23:25:37 +053031
Nabin Haitcfecd2b2013-07-11 17:49:18 +053032def get_fiscal_years(date=None, fiscal_year=None, label="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)
Nabin Hait0930b942013-06-20 16:35:09 +053034 cond = ""
35 if fiscal_year:
36 cond = "name = '%s'" % fiscal_year
37 else:
38 cond = "'%s' >= year_start_date and '%s' < adddate(year_start_date, interval 1 year)" % \
39 (date, date)
Nabin Hait23941aa2013-01-29 11:32:38 +053040 fy = webnotes.conn.sql("""select name, year_start_date,
41 subdate(adddate(year_start_date, interval 1 year), interval 1 day)
42 as year_end_date
43 from `tabFiscal Year`
Nabin Hait0930b942013-06-20 16:35:09 +053044 where %s
45 order by year_start_date desc""" % cond)
Nabin Hait23941aa2013-01-29 11:32:38 +053046
47 if not fy:
Nabin Haitcfecd2b2013-07-11 17:49:18 +053048 error_msg = """%s %s not in any Fiscal Year""" % (label, formatdate(date))
Nabin Hait23941aa2013-01-29 11:32:38 +053049 if verbose: webnotes.msgprint(error_msg)
50 raise FiscalYearError, error_msg
51
Rushabh Mehtac2563ef2013-02-05 23:25:37 +053052 return fy
Rushabh Mehta2e8d0782013-02-05 11:31:27 +053053
54def validate_fiscal_year(date, fiscal_year, label="Date"):
Nabin Haitcfecd2b2013-07-11 17:49:18 +053055 years = [f[0] for f in get_fiscal_years(date, label=label)]
Rushabh Mehtac2563ef2013-02-05 23:25:37 +053056 if fiscal_year not in years:
Rushabh Mehta96075822013-02-05 11:39:49 +053057 webnotes.msgprint(("%(label)s '%(posting_date)s': " + _("not within Fiscal Year") + \
Rushabh Mehta2e8d0782013-02-05 11:31:27 +053058 ": '%(fiscal_year)s'") % {
59 "label": label,
60 "posting_date": formatdate(date),
61 "fiscal_year": fiscal_year
62 }, raise_exception=1)
Nabin Hait23941aa2013-01-29 11:32:38 +053063
64@webnotes.whitelist()
65def get_balance_on(account=None, date=None):
66 if not account and webnotes.form_dict.get("account"):
67 account = webnotes.form_dict.get("account")
68 date = webnotes.form_dict.get("date")
69
70 cond = []
71 if date:
72 cond.append("posting_date <= '%s'" % date)
73 else:
74 # get balance of all entries that exist
75 date = nowdate()
76
77 try:
78 year_start_date = get_fiscal_year(date, verbose=0)[1]
79 except FiscalYearError, e:
80 from webnotes.utils import getdate
81 if getdate(date) > getdate(nowdate()):
82 # if fiscal year not found and the date is greater than today
83 # get fiscal year for today's date and its corresponding year start date
84 year_start_date = get_fiscal_year(nowdate(), verbose=1)[1]
85 else:
86 # this indicates that it is a date older than any existing fiscal year.
87 # hence, assuming balance as 0.0
88 return 0.0
89
90 acc = webnotes.conn.get_value('Account', account, \
91 ['lft', 'rgt', 'debit_or_credit', 'is_pl_account', 'group_or_ledger'], as_dict=1)
92
93 # for pl accounts, get balance within a fiscal year
94 if acc.is_pl_account == 'Yes':
95 cond.append("posting_date >= '%s' and voucher_type != 'Period Closing Voucher'" \
96 % year_start_date)
97
98 # different filter for group and ledger - improved performance
99 if acc.group_or_ledger=="Group":
100 cond.append("""exists (
101 select * from `tabAccount` ac where ac.name = gle.account
102 and ac.lft >= %s and ac.rgt <= %s
103 )""" % (acc.lft, acc.rgt))
104 else:
105 cond.append("""gle.account = "%s" """ % (account, ))
106
107 # join conditional conditions
108 cond = " and ".join(cond)
109 if cond:
110 cond += " and "
111
112 bal = webnotes.conn.sql("""
113 SELECT sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))
114 FROM `tabGL Entry` gle
115 WHERE %s ifnull(is_cancelled, 'No') = 'No' """ % (cond, ))[0][0]
116
117 # if credit account, it should calculate credit - debit
118 if bal and acc.debit_or_credit == 'Credit':
119 bal = -bal
120
121 # if bal is None, return 0
Nabin Haitfb3fd6e2013-01-30 19:16:13 +0530122 return bal or 0
123
124@webnotes.whitelist()
125def add_ac(args=None):
126 if not args:
127 args = webnotes.form_dict
128 args.pop("cmd")
Rushabh Mehtaaae45532013-02-15 14:39:34 +0530129
Rushabh Mehtac53231a2013-02-18 18:24:28 +0530130 ac = webnotes.bean(args)
Nabin Haitfb3fd6e2013-01-30 19:16:13 +0530131 ac.doc.doctype = "Account"
132 ac.doc.old_parent = ""
133 ac.doc.freeze_account = "No"
Nabin Haitfb3fd6e2013-01-30 19:16:13 +0530134 ac.insert()
135 return ac.doc.name
136
137@webnotes.whitelist()
138def add_cc(args=None):
139 if not args:
140 args = webnotes.form_dict
141 args.pop("cmd")
142
Rushabh Mehtac53231a2013-02-18 18:24:28 +0530143 cc = webnotes.bean(args)
Nabin Haitfb3fd6e2013-01-30 19:16:13 +0530144 cc.doc.doctype = "Cost Center"
145 cc.doc.old_parent = ""
Nabin Haitfb3fd6e2013-01-30 19:16:13 +0530146 cc.insert()
147 return cc.doc.name
148
149def reconcile_against_document(args):
150 """
151 Cancel JV, Update aginst document, split if required and resubmit jv
152 """
153 for d in args:
154 check_if_jv_modified(d)
155
156 against_fld = {
157 'Journal Voucher' : 'against_jv',
158 'Sales Invoice' : 'against_invoice',
159 'Purchase Invoice' : 'against_voucher'
160 }
161
162 d['against_fld'] = against_fld[d['against_voucher_type']]
163
164 # cancel JV
165 jv_obj = webnotes.get_obj('Journal Voucher', d['voucher_no'], with_children=1)
166 jv_obj.make_gl_entries(cancel=1, adv_adj=1)
167
168 # update ref in JV Detail
169 update_against_doc(d, jv_obj)
170
171 # re-submit JV
172 jv_obj = webnotes.get_obj('Journal Voucher', d['voucher_no'], with_children =1)
173 jv_obj.make_gl_entries(cancel = 0, adv_adj =1)
174
175
176def check_if_jv_modified(args):
177 """
178 check if there is already a voucher reference
179 check if amount is same
180 check if jv is submitted
181 """
182 ret = webnotes.conn.sql("""
183 select t2.%(dr_or_cr)s from `tabJournal Voucher` t1, `tabJournal Voucher Detail` t2
184 where t1.name = t2.parent and t2.account = '%(account)s'
185 and ifnull(t2.against_voucher, '')=''
186 and ifnull(t2.against_invoice, '')='' and ifnull(t2.against_jv, '')=''
187 and t1.name = '%(voucher_no)s' and t2.name = '%(voucher_detail_no)s'
188 and t1.docstatus=1 and t2.%(dr_or_cr)s = %(unadjusted_amt)s""" % args)
189
190 if not ret:
191 msgprint(_("""Payment Entry has been modified after you pulled it.
192 Please pull it again."""), raise_exception=1)
193
194def update_against_doc(d, jv_obj):
195 """
196 Updates against document, if partial amount splits into rows
197 """
198
199 webnotes.conn.sql("""
200 update `tabJournal Voucher Detail` t1, `tabJournal Voucher` t2
201 set t1.%(dr_or_cr)s = '%(allocated_amt)s',
202 t1.%(against_fld)s = '%(against_voucher)s', t2.modified = now()
203 where t1.name = '%(voucher_detail_no)s' and t1.parent = t2.name""" % d)
204
205 if d['allocated_amt'] < d['unadjusted_amt']:
206 jvd = webnotes.conn.sql("""select cost_center, balance, against_account, is_advance
207 from `tabJournal Voucher Detail` where name = %s""", d['voucher_detail_no'])
208 # new entry with balance amount
209 ch = addchild(jv_obj.doc, 'entries', 'Journal Voucher Detail')
210 ch.account = d['account']
211 ch.cost_center = cstr(jvd[0][0])
212 ch.balance = cstr(jvd[0][1])
213 ch.fields[d['dr_or_cr']] = flt(d['unadjusted_amt']) - flt(d['allocated_amt'])
214 ch.fields[d['dr_or_cr']== 'debit' and 'credit' or 'debit'] = 0
215 ch.against_account = cstr(jvd[0][2])
216 ch.is_advance = cstr(jvd[0][3])
217 ch.docstatus = 1
Nabin Haita76a0682013-02-08 14:04:13 +0530218 ch.save(1)
219
220def get_account_list(doctype, txt, searchfield, start, page_len, filters):
221 if not filters.get("group_or_ledger"):
222 filters["group_or_ledger"] = "Ledger"
223
224 conditions, filter_values = build_filter_conditions(filters)
225
226 return webnotes.conn.sql("""select name, parent_account from `tabAccount`
227 where docstatus < 2 %s and %s like %s order by name limit %s, %s""" %
228 (conditions, searchfield, "%s", "%s", "%s"),
229 tuple(filter_values + ["%%%s%%" % txt, start, page_len]))
230
231def get_cost_center_list(doctype, txt, searchfield, start, page_len, filters):
232 if not filters.get("group_or_ledger"):
233 filters["group_or_ledger"] = "Ledger"
234
235 conditions, filter_values = build_filter_conditions(filters)
236
237 return webnotes.conn.sql("""select name, parent_cost_center from `tabCost Center`
238 where docstatus < 2 %s and %s like %s order by name limit %s, %s""" %
239 (conditions, searchfield, "%s", "%s", "%s"),
Anand Doshi7da72dd2013-03-20 17:00:41 +0530240 tuple(filter_values + ["%%%s%%" % txt, start, page_len]))
241
242def remove_against_link_from_jv(ref_type, ref_no, against_field):
243 webnotes.conn.sql("""update `tabJournal Voucher Detail` set `%s`=null,
244 modified=%s, modified_by=%s
245 where `%s`=%s and docstatus < 2""" % (against_field, "%s", "%s", against_field, "%s"),
246 (now(), webnotes.session.user, ref_no))
247
248 webnotes.conn.sql("""update `tabGL Entry`
249 set against_voucher_type=null, against_voucher=null,
250 modified=%s, modified_by=%s
251 where against_voucher_type=%s and against_voucher=%s
252 and voucher_no != ifnull(against_voucher, "")
253 and ifnull(is_cancelled, "No")="No" """,
254 (now(), webnotes.session.user, ref_type, ref_no))
Nabin Hait0fc24542013-03-25 11:06:00 +0530255
256@webnotes.whitelist()
257def get_company_default(company, fieldname):
258 value = webnotes.conn.get_value("Company", company, fieldname)
259
260 if not value:
261 msgprint(_("Please mention default value for '") +
262 _(webnotes.get_doctype("company").get_label(fieldname) +
263 _("' in Company: ") + company), raise_exception=True)
264
265 return value
266
267def create_stock_in_hand_jv(reverse=False):
268 from webnotes.utils import nowdate
269 today = nowdate()
270 fiscal_year = get_fiscal_year(today)[0]
Nabin Hait787c02e2013-03-29 16:42:33 +0530271 jv_list = []
Nabin Hait0fc24542013-03-25 11:06:00 +0530272
273 for company in webnotes.conn.sql_list("select name from `tabCompany`"):
274 stock_rbnb_value = get_stock_rbnb_value(company)
Nabin Hait787c02e2013-03-29 16:42:33 +0530275 stock_rbnb_value = reverse and -1*stock_rbnb_value or stock_rbnb_value
276 if stock_rbnb_value:
277 jv = webnotes.bean([
278 {
279 "doctype": "Journal Voucher",
Anand Doshi72edc3d2013-05-29 12:13:16 +0530280 "naming_series": "JV-AUTO-",
Nabin Hait787c02e2013-03-29 16:42:33 +0530281 "company": company,
282 "posting_date": today,
283 "fiscal_year": fiscal_year,
284 "voucher_type": "Journal Entry",
Anand Doshi72edc3d2013-05-29 12:13:16 +0530285 "user_remark": (_("Auto Inventory Accounting") + ": " +
286 (_("Disabled") if reverse else _("Enabled")) + ". " +
287 _("Journal Entry for inventory that is received but not yet invoiced"))
Nabin Hait787c02e2013-03-29 16:42:33 +0530288 },
289 {
290 "doctype": "Journal Voucher Detail",
291 "parentfield": "entries",
292 "account": get_company_default(company, "stock_received_but_not_billed"),
Anand Doshi72edc3d2013-05-29 12:13:16 +0530293 (stock_rbnb_value > 0 and "credit" or "debit"): abs(stock_rbnb_value)
Nabin Hait787c02e2013-03-29 16:42:33 +0530294 },
295 {
296 "doctype": "Journal Voucher Detail",
297 "parentfield": "entries",
298 "account": get_company_default(company, "stock_adjustment_account"),
Anand Doshi72edc3d2013-05-29 12:13:16 +0530299 (stock_rbnb_value > 0 and "debit" or "credit"): abs(stock_rbnb_value),
Nabin Hait787c02e2013-03-29 16:42:33 +0530300 "cost_center": get_company_default(company, "stock_adjustment_cost_center")
301 },
302 ])
303 jv.insert()
Nabin Hait787c02e2013-03-29 16:42:33 +0530304
305 jv_list.append(jv.doc.name)
306
307 if jv_list:
Anand Doshi72edc3d2013-05-29 12:13:16 +0530308 msgprint(_("Following Journal Vouchers have been created automatically") + \
309 ":\n%s" % ("\n".join([("<a href=\"#Form/Journal Voucher/%s\">%s</a>" % (jv, jv)) for jv in jv_list]),))
310
311 msgprint(_("""These adjustment vouchers book the difference between \
312 the total value of received items and the total value of invoiced items, \
313 as a required step to use Auto Inventory Accounting.
314 This is an approximation to get you started.
315 You will need to submit these vouchers after checking if the values are correct.
316 For more details, read: \
317 <a href="http://erpnext.com/auto-inventory-accounting" target="_blank">\
318 Auto Inventory Accounting</a>"""))
Nabin Hait787c02e2013-03-29 16:42:33 +0530319
320 webnotes.msgprint("""Please refresh the system to get effect of Auto Inventory Accounting""")
321
Nabin Hait0fc24542013-03-25 11:06:00 +0530322
Nabin Hait787c02e2013-03-29 16:42:33 +0530323def get_stock_rbnb_value(company):
324 total_received_amount = webnotes.conn.sql("""select sum(valuation_rate*qty*conversion_factor)
Nabin Hait0fc24542013-03-25 11:06:00 +0530325 from `tabPurchase Receipt Item` pr_item where docstatus=1
326 and exists(select name from `tabItem` where name = pr_item.item_code
327 and is_stock_item='Yes')
Nabin Hait41fe3562013-03-28 15:54:11 +0530328 and exists(select name from `tabPurchase Receipt`
Nabin Hait0fc24542013-03-25 11:06:00 +0530329 where name = pr_item.parent and company = %s)""", company)
330
Nabin Hait787c02e2013-03-29 16:42:33 +0530331 total_billed_amount = webnotes.conn.sql("""select sum(valuation_rate*qty*conversion_factor)
Nabin Hait0fc24542013-03-25 11:06:00 +0530332 from `tabPurchase Invoice Item` pi_item where docstatus=1
333 and exists(select name from `tabItem` where name = pi_item.item_code
334 and is_stock_item='Yes')
Nabin Hait41fe3562013-03-28 15:54:11 +0530335 and exists(select name from `tabPurchase Invoice`
Nabin Hait0fc24542013-03-25 11:06:00 +0530336 where name = pi_item.parent and company = %s)""", company)
Nabin Hait0fc24542013-03-25 11:06:00 +0530337 return flt(total_received_amount[0][0]) - flt(total_billed_amount[0][0])
Nabin Hait8b509f52013-05-28 16:52:30 +0530338
339
340def fix_total_debit_credit():
341 vouchers = webnotes.conn.sql("""select voucher_type, voucher_no,
342 sum(debit) - sum(credit) as diff
343 from `tabGL Entry`
344 group by voucher_type, voucher_no
345 having sum(ifnull(debit, 0)) != sum(ifnull(credit, 0))""", as_dict=1)
346
347 for d in vouchers:
348 if abs(d.diff) > 0:
349 dr_or_cr = d.voucher_type == "Sales Invoice" and "credit" or "debit"
350
351 webnotes.conn.sql("""update `tabGL Entry` set %s = %s + %s
352 where voucher_type = %s and voucher_no = %s and %s > 0 limit 1""" %
353 (dr_or_cr, dr_or_cr, '%s', '%s', '%s', dr_or_cr),
Anand Doshi4bef02e2013-06-28 19:21:44 +0530354 (d.diff, d.voucher_type, d.voucher_no))