Discount in purchase cycle Merge branch 'master' of git://github.com/nijil/erpnext
Conflicts:
erpnext/accounts/doctype/pv_detail/pv_detail.txt
erpnext/buying/doctype/po_detail/po_detail.txt
erpnext/stock/doctype/purchase_receipt_detail/purchase_receipt_detail.txt
diff --git a/.gitignore b/.gitignore
index 7f90378..0818a02 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@
patch.log
lib
versions-local.db
+*.sql*
diff --git a/erpnext/accounts/doctype/gl_control/gl_control.py b/erpnext/accounts/doctype/gl_control/gl_control.py
index 44a9e8d..01f31eb 100644
--- a/erpnext/accounts/doctype/gl_control/gl_control.py
+++ b/erpnext/accounts/doctype/gl_control/gl_control.py
@@ -4,8 +4,8 @@
from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, generate_hash, getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common, month_name, now, nowdate, replace_newlines, sendmail, set_default, str_esc_quote, user_format, validate_email_add
from webnotes.model import db_exists
from webnotes.model.doc import Document, addchild, removechild, getchildren, make_autoname, SuperDocType
-from webnotes.model.doclist import getlist, copy_doclist
-from webnotes.model.code import get_obj, get_server_obj, run_server_obj, updatedb, check_syntax
+from webnotes.model.doclist import getlist, copy_doclist, clone
+from webnotes.model.code import get_obj
from webnotes import session, form, is_testing, msgprint, errprint
sql = webnotes.conn.sql
@@ -24,14 +24,8 @@
# Get Company List
# ----------------
def get_companies(self,arg=''):
- #d = get_defaults()
ret = sql("select name, abbr from tabCompany where docstatus != 2")
- #pl = {}
- #for r in ret:
- # inc = get_value('Account','Income - '+r[1], 'balance')
- # exp = get_value('Account','Expenses - '+r[1], 'balance')
- # pl[r[0]] = flt(flt(inc) - flt(exp))
- return {'cl':[r[0] for r in ret]}#, 'pl':pl}
+ return {'cl':[r[0] for r in ret]}
def get_company_currency(self,arg=''):
dcc = TransactionBase().get_company_currency(arg)
@@ -506,3 +500,39 @@
for a in set(ac_list):
fy_obj.repost(a)
+
+def manage_recurring_invoices():
+ """
+ Create recurring invoices on specific date by copying the original one
+ and notify the concerned people
+ """
+ rv = sql("""select name, recurring_id from `tabReceivable Voucher` where ifnull(convert_into_recurring_invoice, 0) = 1
+ and next_date = %s and next_date <= end_date order by next_date desc""", nowdate())
+ for d in rv:
+ if not sql("""select name from `tabReceivable Voucher` where posting_date = %s and recurring_id = %s""", (nowdate(), d[1])):
+ prev_rv = get_obj('Receivable Voucher', d[0], with_children=1)
+ new_rv = create_new_invoice(prev_rv)
+
+ send_notification(new_rv)
+
+def create_new_invoice(prev_rv):
+ # clone rv
+ new_rv = clone(prev_rv)
+
+ # update new rv
+
+ new_rv.doc.voucher_date = new_rv.doc.next_date
+ new_rv.doc.posting_date = new_rv.doc.next_date
+ new_rv.doc.aging_date = new_rv.doc.next_date
+ new_rv.doc.due_date = add_days(new_rv.doc.next_date, cint(date_diff(prev_rv.doc.due_date, prev_rv.doc.posting_date)))
+ new_rv.doc.save()
+
+ # submit and after submit
+ new_rv.submit()
+ new_rv.update_after_submit()
+
+ return new_rv
+
+def send_notification(new_rv):
+ """Notify concerned persons about recurring invoice generation"""
+ pass
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.txt b/erpnext/accounts/doctype/gl_entry/gl_entry.txt
index 776cbb3..1d84e1d 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.txt
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.txt
@@ -5,24 +5,26 @@
{
'creation': '2010-08-08 17:09:03',
'docstatus': 0,
- 'modified': '2010-12-29 12:59:45',
- 'modified_by': 'umair@iwebnotes.com',
+ 'modified': '2011-11-24 15:03:45',
+ 'modified_by': 'Administrator',
'owner': 'Administrator'
},
# These values are common for all DocType
{
- '_last_update': '1309508838',
+ '_last_update': '1319016431',
'autoname': 'GL.#######',
'colour': 'White:FFF',
+ 'default_print_format': 'Standard',
'doctype': 'DocType',
+ 'in_create': 1,
'module': 'Accounts',
'name': '__common__',
'search_fields': 'voucher_no,account,posting_date,against_voucher',
'section_style': 'Simple',
'server_code_error': ' ',
'show_in_menu': 0,
- 'version': 101
+ 'version': 103
},
# These values are common for all DocField
@@ -68,7 +70,6 @@
'cancel': 0,
'create': 0,
'doctype': 'DocPerm',
- 'idx': 1,
'permlevel': 0,
'role': 'Accounts Manager',
'submit': 0,
@@ -78,7 +79,6 @@
# DocPerm
{
'doctype': 'DocPerm',
- 'idx': 2,
'permlevel': 0,
'role': 'System Manager'
},
@@ -89,7 +89,6 @@
'doctype': 'DocField',
'fieldname': 'posting_date',
'fieldtype': 'Date',
- 'idx': 1,
'in_filter': 1,
'label': 'Posting Date',
'oldfieldname': 'posting_date',
@@ -103,7 +102,6 @@
'doctype': 'DocField',
'fieldname': 'transaction_date',
'fieldtype': 'Date',
- 'idx': 2,
'label': 'Transaction Date',
'oldfieldname': 'transaction_date',
'oldfieldtype': 'Date'
@@ -114,7 +112,6 @@
'doctype': 'DocField',
'fieldname': 'aging_date',
'fieldtype': 'Date',
- 'idx': 3,
'in_filter': 1,
'label': 'Aging Date',
'oldfieldname': 'aging_date',
@@ -127,7 +124,6 @@
'doctype': 'DocField',
'fieldname': 'account',
'fieldtype': 'Link',
- 'idx': 4,
'in_filter': 1,
'label': 'Account',
'oldfieldname': 'account',
@@ -141,7 +137,6 @@
'doctype': 'DocField',
'fieldname': 'cost_center',
'fieldtype': 'Link',
- 'idx': 5,
'in_filter': 1,
'label': 'Cost Center',
'oldfieldname': 'cost_center',
@@ -155,7 +150,6 @@
'doctype': 'DocField',
'fieldname': 'debit',
'fieldtype': 'Currency',
- 'idx': 6,
'label': 'Debit Amt',
'oldfieldname': 'debit',
'oldfieldtype': 'Currency'
@@ -166,7 +160,6 @@
'doctype': 'DocField',
'fieldname': 'credit',
'fieldtype': 'Currency',
- 'idx': 7,
'label': 'Credit Amt',
'oldfieldname': 'credit',
'oldfieldtype': 'Currency'
@@ -177,7 +170,6 @@
'doctype': 'DocField',
'fieldname': 'against',
'fieldtype': 'Text',
- 'idx': 8,
'in_filter': 1,
'label': 'Against',
'oldfieldname': 'against',
@@ -189,7 +181,6 @@
'doctype': 'DocField',
'fieldname': 'against_voucher',
'fieldtype': 'Data',
- 'idx': 9,
'in_filter': 1,
'label': 'Against Voucher',
'oldfieldname': 'against_voucher',
@@ -202,7 +193,6 @@
'doctype': 'DocField',
'fieldname': 'against_voucher_type',
'fieldtype': 'Data',
- 'idx': 10,
'in_filter': 0,
'label': 'Against Voucher Type',
'oldfieldname': 'against_voucher_type',
@@ -215,7 +205,6 @@
'doctype': 'DocField',
'fieldname': 'voucher_type',
'fieldtype': 'Select',
- 'idx': 11,
'in_filter': 1,
'label': 'Voucher Type',
'oldfieldname': 'voucher_type',
@@ -229,7 +218,6 @@
'doctype': 'DocField',
'fieldname': 'voucher_no',
'fieldtype': 'Data',
- 'idx': 12,
'in_filter': 1,
'label': 'Voucher No',
'oldfieldname': 'voucher_no',
@@ -242,7 +230,6 @@
'doctype': 'DocField',
'fieldname': 'remarks',
'fieldtype': 'Text',
- 'idx': 13,
'in_filter': 1,
'label': 'Remarks',
'no_copy': 1,
@@ -256,7 +243,6 @@
'doctype': 'DocField',
'fieldname': 'is_cancelled',
'fieldtype': 'Select',
- 'idx': 14,
'in_filter': 1,
'label': 'Is Cancelled',
'oldfieldname': 'is_cancelled',
@@ -270,7 +256,6 @@
'doctype': 'DocField',
'fieldname': 'is_opening',
'fieldtype': 'Select',
- 'idx': 15,
'in_filter': 1,
'label': 'Is Opening',
'oldfieldname': 'is_opening',
@@ -284,7 +269,6 @@
'doctype': 'DocField',
'fieldname': 'is_advance',
'fieldtype': 'Select',
- 'idx': 16,
'in_filter': 0,
'label': 'Is Advance',
'oldfieldname': 'is_advance',
@@ -298,7 +282,6 @@
'doctype': 'DocField',
'fieldname': 'fiscal_year',
'fieldtype': 'Select',
- 'idx': 17,
'in_filter': 1,
'label': 'Fiscal Year',
'oldfieldname': 'fiscal_year',
@@ -312,7 +295,6 @@
'doctype': 'DocField',
'fieldname': 'company',
'fieldtype': 'Link',
- 'idx': 18,
'in_filter': 1,
'label': 'Company',
'oldfieldname': 'company',
diff --git a/erpnext/accounts/doctype/internal_reconciliation/internal_reconciliation.js b/erpnext/accounts/doctype/internal_reconciliation/internal_reconciliation.js
index bcd5c44..a5ec2b6 100644
--- a/erpnext/accounts/doctype/internal_reconciliation/internal_reconciliation.js
+++ b/erpnext/accounts/doctype/internal_reconciliation/internal_reconciliation.js
@@ -2,7 +2,6 @@
// --------------------
cur_frm.fields_dict.voucher_no.get_query = function(doc) {
-
if (!doc.account) msgprint("Please select Account first");
else {
return repl("select voucher_no, posting_date \
diff --git a/erpnext/accounts/doctype/internal_reconciliation/internal_reconciliation.py b/erpnext/accounts/doctype/internal_reconciliation/internal_reconciliation.py
index 7c34546..24a7db5 100644
--- a/erpnext/accounts/doctype/internal_reconciliation/internal_reconciliation.py
+++ b/erpnext/accounts/doctype/internal_reconciliation/internal_reconciliation.py
@@ -81,7 +81,7 @@
and ifnull(t2.against_voucher, '')='' and ifnull(t2.against_invoice, '')='' and ifnull(t2.against_jv, '')=''
and t2.%s > 0
%s
- group by t1.name
+ group by t1.name, t2.name
"""% ('%s', dc, cond), self.doc.account, as_dict=1)
return gle
@@ -112,6 +112,9 @@
2. split into multiple rows if partially adjusted, assign against voucher
3. submit payment voucher
"""
+ if not self.doc.voucher_no or not sql("select name from `tab%s` where name = %s" %(self.dt[self.doc.voucher_type], '%s'), self.doc.voucher_no):
+ msgprint("Please select valid Voucher No to proceed", raise_exception=1)
+
lst = []
for d in getlist(self.doclist, 'ir_payment_details'):
if d.selected and flt(d.amt_to_be_reconciled) > 0:
@@ -129,8 +132,7 @@
lst.append(args)
- if not sql("select name from `tab%s` where name = %s" %(self.dt[self.doc.voucher_type], '%s'), self.doc.voucher_no):
- msgprint("Please select valid Voucher No to proceed", raise_exception=1)
+
if lst:
get_obj('GL Control').reconcile_against_document(lst)
msgprint("Successfully reconciled.")
diff --git a/erpnext/accounts/doctype/pv_detail/pv_detail.txt b/erpnext/accounts/doctype/pv_detail/pv_detail.txt
index eb24976..4e05a5c 100755
--- a/erpnext/accounts/doctype/pv_detail/pv_detail.txt
+++ b/erpnext/accounts/doctype/pv_detail/pv_detail.txt
@@ -5,7 +5,7 @@
{
'creation': '2010-08-08 17:09:17',
'docstatus': 0,
- 'modified': '2011-11-24 15:07:02',
+ 'modified': '2011-12-08 15:58:58',
'modified_by': 'Administrator',
'owner': 'Administrator'
},
@@ -14,7 +14,6 @@
{
'autoname': 'EVD.######',
'colour': 'White:FFF',
- 'default_print_format': 'Standard',
'doctype': 'DocType',
'istable': 1,
'module': 'Accounts',
@@ -22,7 +21,7 @@
'section_style': 'Tray',
'server_code_error': ' ',
'show_in_menu': 0,
- 'version': 31
+ 'version': 28
},
# These values are common for all DocField
@@ -115,7 +114,7 @@
'doctype': 'DocField',
'fieldname': 'rate',
'fieldtype': 'Currency',
- 'label': 'Rate (Default Curr.)',
+ 'label': 'Rate *(Default Curr.)',
'oldfieldname': 'rate',
'oldfieldtype': 'Currency',
'permlevel': 0,
@@ -129,7 +128,7 @@
'doctype': 'DocField',
'fieldname': 'import_rate',
'fieldtype': 'Currency',
- 'label': 'Rate',
+ 'label': 'Rate ',
'oldfieldname': 'import_rate',
'oldfieldtype': 'Currency',
'permlevel': 0,
@@ -141,6 +140,15 @@
# DocField
{
'doctype': 'DocField',
+ 'fieldname': 'discount_rate',
+ 'fieldtype': 'Currency',
+ 'label': 'Discount %',
+ 'permlevel': 0
+ },
+
+ # DocField
+ {
+ 'doctype': 'DocField',
'fieldname': 'qty',
'fieldtype': 'Currency',
'label': 'Qty',
@@ -212,19 +220,6 @@
# DocField
{
- 'colour': 'White:FFF',
- 'doctype': 'DocField',
- 'fieldname': 'project_name',
- 'fieldtype': 'Link',
- 'in_filter': 1,
- 'label': 'Project Name',
- 'options': 'Project',
- 'permlevel': 0,
- 'print_hide': 1
- },
-
- # DocField
- {
'doctype': 'DocField',
'fieldname': 'purchase_order',
'fieldtype': 'Link',
@@ -324,16 +319,7 @@
'doctype': 'DocField',
'fieldname': 'import_ref_rate',
'fieldtype': 'Currency',
- 'label': 'Ref Rate',
- 'permlevel': 0
- },
-
- # DocField
- {
- 'doctype': 'DocField',
- 'fieldname': 'discount_rate',
- 'fieldtype': 'Currency',
- 'label': 'Discount Rate',
+ 'label': 'Ref Rate ',
'permlevel': 0
}
-]
\ No newline at end of file
+]
diff --git a/erpnext/accounts/doctype/receivable_voucher/receivable_voucher.js b/erpnext/accounts/doctype/receivable_voucher/receivable_voucher.js
index bb19681..363da2e 100644
--- a/erpnext/accounts/doctype/receivable_voucher/receivable_voucher.js
+++ b/erpnext/accounts/doctype/receivable_voucher/receivable_voucher.js
@@ -433,3 +433,12 @@
}
loadreport('GL Entry','General Ledger', callback);
}
+
+// Default values for recurring invoices
+cur_frm.cscript.convert_into_recurring_invoice = function(doc) {
+ if (doc.convert_into_recurring_invoice) {
+ doc.repeat_on_day_of_month = doc.posting_date.split('-')[2];
+ doc.notification_email_address = doc.owner + ', ' + doc.contact_email;
+ refresh_field(['repeat_on_day_of_month', 'notification_email_address']);
+ }
+}
diff --git a/erpnext/accounts/doctype/receivable_voucher/receivable_voucher.py b/erpnext/accounts/doctype/receivable_voucher/receivable_voucher.py
index 6d1f80a..13ed8d3 100644
--- a/erpnext/accounts/doctype/receivable_voucher/receivable_voucher.py
+++ b/erpnext/accounts/doctype/receivable_voucher/receivable_voucher.py
@@ -1,12 +1,13 @@
# Please edit this list and import only required elements
import webnotes
-from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, generate_hash, getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common, month_name, now, nowdate, replace_newlines, sendmail, set_default, str_esc_quote, user_format, validate_email_add
+from webnotes.utils import add_days, add_months, add_years, cint, cstr,date_diff, default_fields, flt, fmt_money, formatdate, generate_hash,getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common,month_name, now, nowdate, replace_newlines, sendmail, set_default,str_esc_quote, user_format, validate_email_add
from webnotes.model import db_exists
from webnotes.model.doc import Document, addchild, removechild, getchildren, make_autoname, SuperDocType
from webnotes.model.doclist import getlist, copy_doclist
from webnotes.model.code import get_obj, get_server_obj, run_server_obj, updatedb, check_syntax
from webnotes import session, form, is_testing, msgprint, errprint
+from webnotes.utils.scheduler import set_event, cancel_event, Scheduler
set = webnotes.conn.set
sql = webnotes.conn.sql
@@ -528,7 +529,6 @@
def make_gl_entries(self, is_cancel=0):
mapper = self.doc.is_pos and self.doc.write_off_account and 'POS with write off' or self.doc.is_pos and not self.doc.write_off_account and 'POS' or ''
update_outstanding = self.doc.is_pos and self.doc.write_off_account and 'No' or 'Yes'
-
get_obj(dt='GL Control').make_gl_entries(self.doc, self.doclist,cancel = is_cancel, use_mapper = mapper, update_outstanding = update_outstanding, merge_entries = cint(self.doc.is_pos) != 1 and 1 or 0)
@@ -546,7 +546,8 @@
get_obj("Sales Common").update_prevdoc_detail(1,self)
# Check for Approving Authority
- get_obj('Authorization Control').validate_approving_authority(self.doc.doctype, self.doc.company, self.doc.grand_total, self)
+ if not self.doc.recurring_id:
+ get_obj('Authorization Control').validate_approving_authority(self.doc.doctype, self.doc.company, self.doc.grand_total, self)
# this sequence because outstanding may get -ve
self.make_gl_entries()
@@ -618,9 +619,61 @@
set(self.doc,'outstanding_amount',flt(self.doc.grand_total) - flt(self.doc.total_advance) - flt(self.doc.paid_amount) - flt(self.doc.write_off_amount))
-
########################################################################
# Repair Outstanding
#######################################################################
def repair_rv_outstanding(self):
get_obj(dt = 'GL Control').repair_voucher_outstanding(self)
+
+ def on_update_after_submit(self):
+ self.convert_into_recurring()
+
+
+ def convert_into_recurring(self):
+ if self.doc.convert_into_recurring_invoice:
+ event = 'accounts.doctype.gl_control.gl_control.manage_recurring_invoices'
+ self.set_next_date()
+ if not self.doc.recurring_id:
+ set(self.doc, 'recurring_id', make_autoname('RECINV/.#####'))
+
+ if sql("select name from `tabReceivable Voucher` where ifnull(convert_into_recurring_invoice, 0) = 1 and next_date <= end_date"):
+ if not self.check_event_exists(event):
+ set_event(event, interval = 60*60, recurring = 1)
+ else:
+ cancel_event(event)
+
+ elif self.doc.recurring_id:
+ sql("""update `tabReceivable Voucher` set convert_into_recurring_invoice = 0 where recurring_id = %s""", self.doc.recurring_id)
+
+
+ def check_event_exists(self, event):
+ try:
+ ev = Scheduler().get_events()
+ except:
+ msgprint("Scheduler database not exists. Please mail to support@erpnext.com", raise_exception=1)
+
+ if event in [d['event'] for d in ev]:
+ return 1
+
+
+ def set_next_date(self):
+ """ Set next date on which auto invoice will be created"""
+
+ if not self.doc.repeat_on_day_of_month:
+ msgprint("""Please enter 'Repeat on Day of Month' field value. \nThe day of the month on which auto invoice
+ will be generated e.g. 05, 28 etc.""", raise_exception=1)
+
+ import datetime
+ m = getdate(self.doc.posting_date).month + 1
+ y = getdate(self.doc.posting_date).year
+ if m > 12:
+ m, y = 1, y+1
+ try:
+ next_date = datetime.date(y, m, cint(self.doc.repeat_on_day_of_month))
+ except:
+ import calendar
+ last_day = calendar.monthrange(y, m)[1]
+ next_date = datetime.date(y, m, last_day)
+ next_date = next_date.strftime("%Y-%m-%d")
+
+ set(self.doc, 'next_date', next_date)
diff --git a/erpnext/accounts/doctype/receivable_voucher/receivable_voucher.txt b/erpnext/accounts/doctype/receivable_voucher/receivable_voucher.txt
index 1abd6a7..e2fc0c6 100644
--- a/erpnext/accounts/doctype/receivable_voucher/receivable_voucher.txt
+++ b/erpnext/accounts/doctype/receivable_voucher/receivable_voucher.txt
@@ -5,7 +5,7 @@
{
'creation': '2010-08-08 17:09:18',
'docstatus': 0,
- 'modified': '2011-10-19 16:31:54',
+ 'modified': '2011-12-06 13:17:26',
'modified_by': 'Administrator',
'owner': 'Administrator'
},
@@ -21,7 +21,7 @@
# These values are common for all DocType
{
- '_last_update': '1319014846',
+ '_last_update': '1323156733',
'change_log': '1. Change in pull_details method dt.-26-06-2009',
'colour': 'White:FFF',
'default_print_format': 'Standard',
@@ -34,7 +34,7 @@
'server_code_error': ' ',
'show_in_menu': 0,
'subject': 'To %(customer_name)s worth %(currency)s %(grand_total_export)s due on %(due_date)s | %(outstanding_amount)s outstanding',
- 'version': 363
+ 'version': 383
},
# These values are common for all DocFormat
@@ -1343,5 +1343,115 @@
'permlevel': 0,
'print_hide': 1,
'report_hide': 1
+ },
+
+ # DocField
+ {
+ 'depends_on': 'eval:doc.docstatus==1',
+ 'doctype': 'DocField',
+ 'fieldtype': 'Section Break',
+ 'label': 'Recurring Invoice',
+ 'permlevel': 0
+ },
+
+ # DocField
+ {
+ 'doctype': 'DocField',
+ 'fieldtype': 'Column Break',
+ 'permlevel': 0,
+ 'width': '50%'
+ },
+
+ # DocField
+ {
+ 'allow_on_submit': 1,
+ 'colour': 'White:FFF',
+ 'depends_on': 'eval:doc.docstatus==1',
+ 'description': 'Check if recurring invoice, uncheck to stop recurring or put proper End Date',
+ 'doctype': 'DocField',
+ 'fieldname': 'convert_into_recurring_invoice',
+ 'fieldtype': 'Check',
+ 'label': 'Convert into Recurring Invoice',
+ 'no_copy': 1,
+ 'permlevel': 0,
+ 'print_hide': 1,
+ 'trigger': 'Client'
+ },
+
+ # DocField
+ {
+ 'allow_on_submit': 1,
+ 'depends_on': 'eval:doc.convert_into_recurring_invoice==1',
+ 'description': 'The day of the month on which auto invoice will be generated e.g. 05, 28 etc ',
+ 'doctype': 'DocField',
+ 'fieldname': 'repeat_on_day_of_month',
+ 'fieldtype': 'Data',
+ 'label': 'Repeat on Day of Month',
+ 'no_copy': 1,
+ 'permlevel': 0,
+ 'print_hide': 1
+ },
+
+ # DocField
+ {
+ 'allow_on_submit': 1,
+ 'depends_on': 'eval:doc.convert_into_recurring_invoice==1',
+ 'description': 'The date on which recurring invoice will be stop',
+ 'doctype': 'DocField',
+ 'fieldname': 'end_date',
+ 'fieldtype': 'Date',
+ 'label': 'End Date',
+ 'no_copy': 1,
+ 'permlevel': 0,
+ 'print_hide': 1
+ },
+
+ # DocField
+ {
+ 'doctype': 'DocField',
+ 'fieldtype': 'Column Break',
+ 'no_copy': 0,
+ 'permlevel': 0,
+ 'width': '50%'
+ },
+
+ # DocField
+ {
+ 'allow_on_submit': 1,
+ 'depends_on': 'eval:doc.convert_into_recurring_invoice==1',
+ 'description': 'Enter email id separated by commas, invoice will be mailed automatically on particular date',
+ 'doctype': 'DocField',
+ 'fieldname': 'notification_email_address',
+ 'fieldtype': 'Small Text',
+ 'label': 'Notification Email Address',
+ 'no_copy': 1,
+ 'permlevel': 0,
+ 'print_hide': 1
+ },
+
+ # DocField
+ {
+ 'depends_on': 'eval:doc.convert_into_recurring_invoice==1',
+ 'description': 'The unique id for tracking all recurring invoices ',
+ 'doctype': 'DocField',
+ 'fieldname': 'recurring_id',
+ 'fieldtype': 'Data',
+ 'label': 'Recurring Id',
+ 'no_copy': 1,
+ 'permlevel': 1,
+ 'print_hide': 1
+ },
+
+ # DocField
+ {
+ 'depends_on': 'eval:doc.convert_into_recurring_invoice==1',
+ 'description': 'The date on which next invoice will be generated ',
+ 'doctype': 'DocField',
+ 'fieldname': 'next_date',
+ 'fieldtype': 'Date',
+ 'label': 'Next Date',
+ 'no_copy': 1,
+ 'permlevel': 1,
+ 'print_hide': 1
}
]
\ No newline at end of file
diff --git a/erpnext/accounts/search_criteria/payment_receipt_report/payment_receipt_report.py b/erpnext/accounts/search_criteria/payment_receipt_report/payment_receipt_report.py
index 737e658..f92f72c 100644
--- a/erpnext/accounts/search_criteria/payment_receipt_report/payment_receipt_report.py
+++ b/erpnext/accounts/search_criteria/payment_receipt_report/payment_receipt_report.py
@@ -7,21 +7,18 @@
raise Exception
if not filter_values.get('company'):
- msgprint("Select Comapny.")
+ msgprint("Select Company to proceed.")
raise Exception
-#for r in res:
-# par_acc = sql("SELECT parent.name FROM `tabAccount` AS node,`tabAccount` AS parent WHERE node.lft BETWEEN parent.lft AND parent.rgt AND node.name = '%s' and parent.cash_flow_level = 'Yes' ORDER BY parent.lft DESC"% r[0])
-# r.append(par_acc and par_acc[0][0] or '')
col_list = [['Account', 'Link', '150px', 'Account']
,['Total', 'Currency', '150px', '']
-# ,['Parent Account', 'Link', '150px', 'Account']
]
+
for c in col_list:
colnames.append(c[0])
coltypes.append(c[1])
colwidths.append(c[2])
coloptions.append(c[3])
- col_idx[c[0]] = len(colnames) - 1
\ No newline at end of file
+ col_idx[c[0]] = len(colnames) - 1
diff --git a/erpnext/buying/doctype/po_detail/po_detail.txt b/erpnext/buying/doctype/po_detail/po_detail.txt
index d79c8a6..aac949d 100755
--- a/erpnext/buying/doctype/po_detail/po_detail.txt
+++ b/erpnext/buying/doctype/po_detail/po_detail.txt
@@ -5,7 +5,7 @@
{
'creation': '2010-08-08 17:09:12',
'docstatus': 0,
- 'modified': '2011-11-24 15:04:47',
+ 'modified': '2011-12-08 16:05:27',
'modified_by': 'Administrator',
'owner': 'Administrator'
},
@@ -14,7 +14,6 @@
{
'autoname': 'POD/.#####',
'colour': 'White:FFF',
- 'default_print_format': 'Standard',
'doctype': 'DocType',
'istable': 1,
'module': 'Buying',
@@ -22,7 +21,7 @@
'section_style': 'Tray',
'server_code_error': ' ',
'show_in_menu': 0,
- 'version': 68
+ 'version': 54
},
# These values are common for all DocField
@@ -107,28 +106,13 @@
{
'default': '0.00',
'doctype': 'DocField',
- 'fieldname': 'qty',
+ 'fieldname': 'purchase_rate',
'fieldtype': 'Currency',
- 'label': 'Quantity',
- 'oldfieldname': 'qty',
+ 'label': 'Rate (Default Curr.) *',
+ 'oldfieldname': 'purchase_rate',
'oldfieldtype': 'Currency',
'permlevel': 0,
- 'reqd': 1,
- 'trigger': 'Client',
- 'width': '60px'
- },
-
- # DocField
- {
- 'doctype': 'DocField',
- 'fieldname': 'uom',
- 'fieldtype': 'Link',
- 'label': 'UOM',
- 'oldfieldname': 'uom',
- 'oldfieldtype': 'Link',
- 'options': 'UOM',
- 'permlevel': 0,
- 'print_hide': 0,
+ 'print_hide': 1,
'reqd': 1,
'trigger': 'Client',
'width': '100px'
@@ -136,16 +120,6 @@
# DocField
{
- 'default': '0',
- 'doctype': 'DocField',
- 'fieldname': 'discount_rate',
- 'fieldtype': 'Currency',
- 'label': 'Discount',
- 'permlevel': 0
- },
-
- # DocField
- {
'doctype': 'DocField',
'fieldname': 'purchase_ref_rate',
'fieldtype': 'Currency',
@@ -155,18 +129,12 @@
# DocField
{
- 'default': '0.00',
'doctype': 'DocField',
- 'fieldname': 'purchase_rate',
+ 'fieldname': 'discount_rate',
'fieldtype': 'Currency',
- 'label': 'Rate (Default Curr.)',
- 'oldfieldname': 'purchase_rate',
- 'oldfieldtype': 'Currency',
+ 'label': 'Discount Rate %',
'permlevel': 0,
- 'print_hide': 1,
- 'reqd': 1,
- 'trigger': 'Client',
- 'width': '100px'
+ 'trigger': 'Client'
},
# DocField
@@ -185,6 +153,35 @@
# DocField
{
+ 'default': '0.00',
+ 'doctype': 'DocField',
+ 'fieldname': 'qty',
+ 'fieldtype': 'Currency',
+ 'label': 'Quantity',
+ 'oldfieldname': 'qty',
+ 'oldfieldtype': 'Currency',
+ 'permlevel': 0,
+ 'reqd': 1,
+ 'trigger': 'Client',
+ 'width': '60px'
+ },
+
+ # DocField
+ {
+ 'doctype': 'DocField',
+ 'fieldname': 'import_rate',
+ 'fieldtype': 'Currency',
+ 'hidden': 0,
+ 'label': 'Rate ',
+ 'oldfieldname': 'import_rate',
+ 'oldfieldtype': 'Currency',
+ 'permlevel': 0,
+ 'print_hide': 0,
+ 'trigger': 'Client'
+ },
+
+ # DocField
+ {
'doctype': 'DocField',
'fieldname': 'import_ref_rate',
'fieldtype': 'Currency',
@@ -195,15 +192,17 @@
# DocField
{
'doctype': 'DocField',
- 'fieldname': 'import_rate',
- 'fieldtype': 'Currency',
- 'hidden': 0,
- 'label': 'Rate',
- 'oldfieldname': 'import_rate',
- 'oldfieldtype': 'Currency',
+ 'fieldname': 'uom',
+ 'fieldtype': 'Link',
+ 'label': 'UOM',
+ 'oldfieldname': 'uom',
+ 'oldfieldtype': 'Link',
+ 'options': 'UOM',
'permlevel': 0,
'print_hide': 0,
- 'trigger': 'Client'
+ 'reqd': 1,
+ 'trigger': 'Client',
+ 'width': '100px'
},
# DocField
@@ -254,17 +253,15 @@
{
'colour': 'White:FFF',
'doctype': 'DocField',
- 'fieldname': 'stock_qty',
- 'fieldtype': 'Currency',
- 'hidden': 0,
- 'label': 'Stock Qty',
- 'no_copy': 1,
- 'oldfieldname': 'stock_qty',
- 'oldfieldtype': 'Currency',
- 'permlevel': 0,
- 'print_hide': 1,
- 'trigger': 'Client',
- 'width': '100px'
+ 'fieldname': 'prevdoc_doctype',
+ 'fieldtype': 'Data',
+ 'hidden': 1,
+ 'label': 'Prevdoc DocType',
+ 'no_copy': 0,
+ 'oldfieldname': 'prevdoc_doctype',
+ 'oldfieldtype': 'Data',
+ 'permlevel': 1,
+ 'print_hide': 1
},
# DocField
@@ -284,34 +281,6 @@
# DocField
{
- 'doctype': 'DocField',
- 'fieldname': 'project_name',
- 'fieldtype': 'Link',
- 'in_filter': 1,
- 'label': 'Project Name',
- 'options': 'Project',
- 'permlevel': 0,
- 'print_hide': 1,
- 'report_hide': 0
- },
-
- # DocField
- {
- 'colour': 'White:FFF',
- 'doctype': 'DocField',
- 'fieldname': 'prevdoc_doctype',
- 'fieldtype': 'Data',
- 'hidden': 1,
- 'label': 'Prevdoc DocType',
- 'no_copy': 0,
- 'oldfieldname': 'prevdoc_doctype',
- 'oldfieldtype': 'Data',
- 'permlevel': 1,
- 'print_hide': 1
- },
-
- # DocField
- {
'colour': 'White:FFF',
'doctype': 'DocField',
'fieldname': 'prevdoc_docname',
@@ -394,6 +363,22 @@
# DocField
{
'doctype': 'DocField',
+ 'fieldname': 'stock_qty',
+ 'fieldtype': 'Currency',
+ 'hidden': 0,
+ 'label': 'Stock Qty',
+ 'no_copy': 1,
+ 'oldfieldname': 'stock_qty',
+ 'oldfieldtype': 'Currency',
+ 'permlevel': 0,
+ 'print_hide': 1,
+ 'trigger': 'Client',
+ 'width': '100px'
+ },
+
+ # DocField
+ {
+ 'doctype': 'DocField',
'fieldname': 'received_qty',
'fieldtype': 'Currency',
'hidden': 0,
@@ -438,7 +423,7 @@
# DocField
{
- 'allow_on_submit': 0,
+ 'allow_on_submit': 1,
'doctype': 'DocField',
'fieldname': 'page_break',
'fieldtype': 'Check',
@@ -450,4 +435,4 @@
'permlevel': 0,
'print_hide': 1
}
-]
\ No newline at end of file
+]
diff --git a/erpnext/home/page/my_company/my_company.py b/erpnext/home/page/my_company/my_company.py
index 3ff1482..c96d998 100644
--- a/erpnext/home/page/my_company/my_company.py
+++ b/erpnext/home/page/my_company/my_company.py
@@ -140,7 +140,9 @@
if 'new_password' in args:
if cint(webnotes.conn.get_value('Control Panel',None,'sync_with_gateway')):
import server_tools.gateway_utils
- webnotes.msgprint(server_tools.gateway_utils.change_password('', args['new_password'], args['user'], args['sys_admin_pwd'])['message'])
+ res = server_tools.gateway_utils.change_password('', args['new_password'], args['user'], args['sys_admin_pwd'])
+ if 'Traceback' not in res['message']:
+ webnotes.msgprint(res['message'])
else:
webnotes.conn.sql("update tabProfile set password=password(%s) where name=%s", (args['new_password'], args['user']))
- else: webnotes.msgprint('Settings Updated')
\ No newline at end of file
+ else: webnotes.msgprint('Settings Updated')
diff --git a/erpnext/patches/index_patch.py b/erpnext/patches/index_patch.py
index 3ef8ec3..788b68d 100644
--- a/erpnext/patches/index_patch.py
+++ b/erpnext/patches/index_patch.py
@@ -293,3 +293,6 @@
sql("commit")
except:
continue
+
+def execute():
+ create_proper_index()
diff --git a/erpnext/patches/reload_address.py b/erpnext/patches/reload_address.py
new file mode 100644
index 0000000..252339b
--- /dev/null
+++ b/erpnext/patches/reload_address.py
@@ -0,0 +1,5 @@
+def execute():
+ import webnotes
+ from webnotes.modules.module_manager import reload_doc
+
+ reload_doc('utilities', 'doctype', 'address')
diff --git a/erpnext/patches/reload_doclayer.py b/erpnext/patches/reload_doclayer.py
new file mode 100644
index 0000000..8ee4919
--- /dev/null
+++ b/erpnext/patches/reload_doclayer.py
@@ -0,0 +1,16 @@
+"""
+ Reload DocLayer, DocLayerField and Print Format doctypes
+"""
+def execute():
+ from webnotes.modules.module_manager import reload_doc
+ reload_doc('core', 'doctype', 'print_format')
+ reload_doc('core', 'doctype', 'doclayer')
+ reload_doc('core', 'doctype', 'doclayerfield')
+ reload_doc('accounts', 'doctype', 'gl_entry')
+ from webnotes.model.doc import Document
+ d = Document('DocType Label')
+ d.dt = "DocLayer"
+ d.dt_label = "Customize Form View"
+ d.save(1)
+ from webnotes.session_cache import clear
+ clear()
diff --git a/erpnext/patches/reload_reco.py b/erpnext/patches/reload_reco.py
new file mode 100644
index 0000000..6b9ecc4
--- /dev/null
+++ b/erpnext/patches/reload_reco.py
@@ -0,0 +1,6 @@
+def execute():
+ import webnotes
+ from webnotes.modules.module_manager import reload_doc
+
+ reload_doc('stock', 'doctype', 'stock_reconciliation')
+ webnotes.conn.sql("delete from `tabDocField` where (label in ('Validate Data', 'Attachment HTML', 'Attachment') or fieldname in ('next_step', 'company', 'fiscal_year', 'amendment_date')) and parent = 'Stock Reconciliation'")
diff --git a/erpnext/patches/reload_rv.py b/erpnext/patches/reload_rv.py
new file mode 100644
index 0000000..5f3bc21
--- /dev/null
+++ b/erpnext/patches/reload_rv.py
@@ -0,0 +1,8 @@
+def execute():
+ import webnotes
+ from webnotes.modules.module_manager import reload_doc
+ from webnotes.model.code import get_obj
+
+ reload_doc('accounts', 'doctype', 'receivable_voucher')
+
+ get_obj('Features setup').validate()
diff --git a/erpnext/patches/repost_stock.py b/erpnext/patches/repost_stock.py
new file mode 100644
index 0000000..680e06f
--- /dev/null
+++ b/erpnext/patches/repost_stock.py
@@ -0,0 +1,22 @@
+def execute():
+ import webnotes
+ sql = webnotes.conn.sql
+ from webnotes.model.code import get_obj
+
+ # update incoming rate in serial nos
+ sr = sql("""select name, item_code, purchase_document_no from `tabSerial No`
+ where docstatus = 1 and purchase_document_type = 'Purchase Receipt'""")
+ for d in sr:
+ val_rate = sql("""select valuation_rate from `tabPurchase Receipt Detail`
+ where item_code = %s and parent = %s""", (d[1], d[2]))
+ sql("""update `tabSerial No` set purchase_rate = %s where name = %s""",
+ (val_rate and flt(val_rate[0][0]) or 0, d[0]))
+
+
+ # repost for all serialized item
+ bin = sql("""select t1.name from `tabBin` t1, tabItem t2 where t1.item_code = t2.name and ifnull(has_serial_no, 'No') = 'Yes'""")
+ for d in bin:
+ get_obj('Bin', d[0]).update_entries_after(posting_date = '2000-01-01', posting_time = '12:00')
+ sql("commit")
+ sql("start transaction")
+
diff --git a/erpnext/production/doctype/workstation/workstation.txt b/erpnext/production/doctype/workstation/workstation.txt
index bb7cc21..dd0868d 100644
--- a/erpnext/production/doctype/workstation/workstation.txt
+++ b/erpnext/production/doctype/workstation/workstation.txt
@@ -5,16 +5,19 @@
{
'creation': '2010-08-08 17:09:31',
'docstatus': 0,
- 'modified': '2011-01-04 13:40:42',
- 'modified_by': 'rahul@webnotestech.com',
+ 'modified': '2011-11-24 14:34:41',
+ 'modified_by': 'Administrator',
'owner': 'Administrator'
},
# These values are common for all DocType
{
+ '_last_update': '1322125389',
+ 'allow_email': 0,
'allow_trash': 1,
'autoname': 'field:workstation_name',
'colour': 'White:FFF',
+ 'default_print_format': 'Standard',
'doctype': 'DocType',
'document_type': 'Master',
'module': 'Production',
@@ -22,7 +25,7 @@
'section_style': 'Simple',
'server_code_error': ' ',
'show_in_menu': 0,
- 'version': 11
+ 'version': 13
},
# These values are common for all DocField
@@ -55,7 +58,6 @@
'cancel': 1,
'create': 1,
'doctype': 'DocPerm',
- 'idx': 1,
'permlevel': 0,
'role': 'System Manager',
'write': 1
@@ -64,7 +66,6 @@
# DocPerm
{
'doctype': 'DocPerm',
- 'idx': 2,
'permlevel': 1,
'role': 'System Manager'
},
@@ -74,7 +75,6 @@
'cancel': 1,
'create': 1,
'doctype': 'DocPerm',
- 'idx': 3,
'permlevel': 0,
'role': 'Production User',
'write': 1
@@ -85,7 +85,6 @@
'cancel': 1,
'create': 1,
'doctype': 'DocPerm',
- 'idx': 4,
'permlevel': 0,
'role': 'Production User',
'write': 1
@@ -94,7 +93,6 @@
# DocPerm
{
'doctype': 'DocPerm',
- 'idx': 5,
'permlevel': 1,
'role': 'Production Manager'
},
@@ -102,7 +100,6 @@
# DocPerm
{
'doctype': 'DocPerm',
- 'idx': 6,
'permlevel': 1,
'role': 'Production User'
},
@@ -112,7 +109,6 @@
'doctype': 'DocField',
'fieldname': 'trash_reason',
'fieldtype': 'Small Text',
- 'idx': 1,
'label': 'Trash Reason',
'oldfieldname': 'trash_reason',
'oldfieldtype': 'Small Text',
@@ -124,7 +120,6 @@
'doctype': 'DocField',
'fieldname': 'workstation_name',
'fieldtype': 'Data',
- 'idx': 2,
'label': 'Workstation Name',
'oldfieldname': 'workstation_name',
'oldfieldtype': 'Data',
@@ -137,7 +132,6 @@
'doctype': 'DocField',
'fieldname': 'warehouse',
'fieldtype': 'Link',
- 'idx': 3,
'label': 'Warehouse',
'oldfieldname': 'warehouse',
'oldfieldtype': 'Link',
@@ -151,7 +145,6 @@
'doctype': 'DocField',
'fieldname': 'description',
'fieldtype': 'Text',
- 'idx': 4,
'label': 'Description',
'oldfieldname': 'description',
'oldfieldtype': 'Text',
@@ -165,7 +158,6 @@
'fieldname': 'capacity',
'fieldtype': 'Data',
'hidden': 1,
- 'idx': 5,
'label': 'Capacity',
'oldfieldname': 'capacity',
'oldfieldtype': 'Data',
@@ -179,7 +171,6 @@
'fieldname': 'capacity_units',
'fieldtype': 'Select',
'hidden': 1,
- 'idx': 6,
'label': 'Capacity Units',
'oldfieldname': 'capacity_units',
'oldfieldtype': 'Select',
@@ -194,7 +185,6 @@
'doctype': 'DocField',
'fieldname': 'hour_rate_labour',
'fieldtype': 'Currency',
- 'idx': 7,
'label': 'Hour Rate Labour',
'oldfieldname': 'hour_rate_labour',
'oldfieldtype': 'Currency',
@@ -206,7 +196,6 @@
{
'doctype': 'DocField',
'fieldtype': 'Section Break',
- 'idx': 8,
'label': 'Over Heads',
'oldfieldtype': 'Section Break',
'permlevel': 0
@@ -217,7 +206,6 @@
'doctype': 'DocField',
'fieldname': 'hour_rate_electricity',
'fieldtype': 'Currency',
- 'idx': 9,
'label': 'Hour Rate Electricity',
'oldfieldname': 'hour_rate_electricity',
'oldfieldtype': 'Currency',
@@ -229,7 +217,6 @@
'doctype': 'DocField',
'fieldname': 'hour_rate_consumable',
'fieldtype': 'Currency',
- 'idx': 10,
'label': 'Hour Rate Consumable',
'oldfieldname': 'hour_rate_consumable',
'oldfieldtype': 'Currency',
@@ -241,7 +228,6 @@
'doctype': 'DocField',
'fieldname': 'hour_rate_rent',
'fieldtype': 'Currency',
- 'idx': 11,
'label': 'Hour Rate Rent',
'oldfieldname': 'hour_rate_rent',
'oldfieldtype': 'Currency',
@@ -253,7 +239,6 @@
'doctype': 'DocField',
'fieldname': 'overhead',
'fieldtype': 'Currency',
- 'idx': 12,
'label': 'Overhead',
'oldfieldname': 'overhead',
'oldfieldtype': 'Currency',
@@ -264,7 +249,6 @@
{
'doctype': 'DocField',
'fieldtype': 'Section Break',
- 'idx': 13,
'label': 'Hour Rate',
'oldfieldtype': 'Section Break',
'permlevel': 0
@@ -275,7 +259,6 @@
'doctype': 'DocField',
'fieldname': 'hour_rate',
'fieldtype': 'Currency',
- 'idx': 14,
'label': 'Hour Rate',
'oldfieldname': 'hour_rate',
'oldfieldtype': 'Currency',
diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py
index 9930bf4..4504191 100644
--- a/erpnext/projects/doctype/project/project.py
+++ b/erpnext/projects/doctype/project/project.py
@@ -34,9 +34,9 @@
'customer_name' : details and details[0]['customer_name'] or ''
}
#get primary contact details(this is done separately coz. , if join query used & no primary contact thn it would not be able to fetch customer details)
- contact_det = sql("select contact_name, contact_no, email_id from `tabContact` where customer_name='%s' and is_customer=1 and is_primary_contact='Yes' and docstatus!=2" %(self.doc.customer), as_dict = 1)
+ contact_det = sql("select contact_name, phone, email_id from `tabContact` where customer_name='%s' and is_customer=1 and is_primary_contact=1 and docstatus!=2" %(self.doc.customer), as_dict = 1)
ret['contact_person'] = contact_det and contact_det[0]['contact_name'] or ''
- ret['contact_no'] = contact_det and contact_det[0]['contact_no'] or ''
+ ret['contact_no'] = contact_det and contact_det[0]['phone'] or ''
ret['email_id'] = contact_det and contact_det[0]['email_id'] or ''
return ret
else:
diff --git a/erpnext/sandbox/test_stock_reco.py b/erpnext/sandbox/test_stock_reco.py
new file mode 100644
index 0000000..bcde49e
--- /dev/null
+++ b/erpnext/sandbox/test_stock_reco.py
@@ -0,0 +1,94 @@
+import unittest
+
+import webnotes
+import webnotes.profile
+webnotes.user = webnotes.profile.Profile()
+
+
+from webnotes.model.doc import Document
+from webnotes.model.code import get_obj
+from webnotes.utils import cstr, flt
+from webnotes.model.doclist import getlist
+sql = webnotes.conn.sql
+
+from sandbox.testdata.masters import *
+from sandbox.testdata.sle_data import sle, bin
+from sandbox.testdata.stock_reco import *
+#----------------------------------------------------------
+
+
+class TestStockEntry(unittest.TestCase):
+ def assertDoc(self, lst):
+ """assert all values"""
+ for d in lst:
+ cl, vl = [], []
+ for k in d.keys():
+ if k!='doctype':
+ cl.append('%s=%s' % (k, '%s'))
+ vl.append(d[k])
+
+ self.assertTrue(sql("select name from `tab%s` where %s limit 1" % (d['doctype'], ' and '.join(cl)), vl))
+
+ #===========================================================================
+ def setUp(self):
+ print "====================================="
+ webnotes.conn.begin()
+ create_master_records()
+ print 'Master Data Created'
+
+ for d in sle:
+ d.save(1)
+ print "Existing SLE created"
+
+ bin.save(1)
+
+ sreco.save(1)
+ print "Stock Reco saved"
+
+ #===========================================================================
+ def test_diff_in_both(self):
+ reco = get_obj('Stock Reconciliation', sreco.name)
+ reco.doc.docstatus = 1
+ reco.doc.save()
+ reco.validate()
+ reco.on_submit()
+ print "Stock Reco submitted"
+
+ print "Checking stock ledger entry........."
+ self.assertDoc(self.get_expected_sle('diff_in_both'))
+
+ #===========================================================================
+ def tearDown(self):
+ webnotes.conn.rollback()
+
+ # Expected Result Set
+ #===================================================================================================
+ def get_expected_sle(self, action):
+ expected_sle = {
+ 'diff_in_both': [{
+ 'doctype': 'Stock Ledger Entry',
+ 'item_code':'it',
+ 'warehouse':'wh1',
+ 'voucher_type': 'Stock Reconciliation',
+ 'voucher_no': sreco.name,
+ 'actual_qty': 15,
+ 'bin_aqat': 20,
+ 'valuation_rate': 150,
+ #'stock_value': 3000,
+ 'is_cancelled': 'No'
+ },{
+ 'doctype': 'Stock Ledger Entry',
+ 'posting_date': '2011-09-10',
+ 'posting_time': '15:00',
+ 'item_code': 'it',
+ 'warehouse': 'wh1',
+ 'actual_qty': 20,
+ 'incoming_rate': 200,
+ 'bin_aqat': 40,
+ 'valuation_rate': 175,
+ #'stock_value': 4500,
+ 'is_cancelled': 'No'
+ }
+ ]
+ }
+ return expected_sle[action]
diff --git a/erpnext/sandbox/testdata/sle_data.py b/erpnext/sandbox/testdata/sle_data.py
new file mode 100644
index 0000000..eab0376
--- /dev/null
+++ b/erpnext/sandbox/testdata/sle_data.py
@@ -0,0 +1,85 @@
+from webnotes.model.doc import Document
+
+# Existing SLE data
+#---------------------------
+
+sle = [
+ Document(
+ fielddata = {
+ 'doctype': 'Stock Ledger Entry',
+ 'name': 'sle1',
+ 'posting_date': '2011-09-01',
+ 'posting_time': '12:00',
+ 'item_code': 'it',
+ 'warehouse': 'wh1',
+ 'actual_qty': 10,
+ 'incoming_rate': 100,
+ 'bin_aqat': 10,
+ 'valuation_rate': 100,
+ 'fcfs_stack': '',
+ 'stock_value': 1000,
+ 'is_cancelled': 'No'
+ }
+ ),
+ Document(
+ fielddata = {
+ 'doctype': 'Stock Ledger Entry',
+ 'name': 'sle2',
+ 'posting_date': '2011-09-01',
+ 'posting_time': '12:00',
+ 'item_code': 'it',
+ 'warehouse': 'wh1',
+ 'actual_qty': -5,
+ 'incoming_rate': 100,
+ 'bin_aqat': 5,
+ 'valuation_rate': 100,
+ 'fcfs_stack': '',
+ 'stock_value': 500,
+ 'is_cancelled': 'No'
+ }
+ ),
+ Document(
+ fielddata = {
+ 'doctype': 'Stock Ledger Entry',
+ 'name': 'sle3',
+ 'posting_date': '2011-09-10',
+ 'posting_time': '15:00',
+ 'item_code': 'it',
+ 'warehouse': 'wh1',
+ 'actual_qty': 20,
+ 'incoming_rate': 200,
+ 'bin_aqat': 25,
+ 'valuation_rate': 180,
+ 'fcfs_stack': '',
+ 'stock_value': 4500,
+ 'is_cancelled': 'No'
+ }
+ ),
+ Document(
+ fielddata = {
+ 'doctype': 'Stock Ledger Entry',
+ 'name': 'sle4',
+ 'posting_date': '2011-09-15',
+ 'posting_time': '09:30',
+ 'item_code': 'it',
+ 'warehouse': 'wh1',
+ 'actual_qty': -5,
+ 'incoming_rate': 180,
+ 'bin_aqat': 20,
+ 'valuation_rate': 180,
+ 'fcfs_stack': '',
+ 'stock_value': 3600,
+ 'is_cancelled': 'No'
+ }
+ )
+]
+
+bin = Document(
+ fielddata = {
+ 'doctype': 'Bin',
+ 'name': 'bin01',
+ 'item_code': 'it',
+ 'warehouse': 'wh1',
+ 'actual_qty': 20,
+ }
+)
diff --git a/erpnext/sandbox/testdata/stock_reco.py b/erpnext/sandbox/testdata/stock_reco.py
new file mode 100644
index 0000000..efcbbc5
--- /dev/null
+++ b/erpnext/sandbox/testdata/stock_reco.py
@@ -0,0 +1,43 @@
+from webnotes.model.doc import Document
+
+# Stock Reconciliation
+#---------------------------
+
+sreco = Document(
+ fielddata = {
+ 'doctype': 'Stock Reconciliation',
+ 'name': 'sreco',
+ 'reconciliation_date': '2011-09-08',
+ 'reconciliation_time': '20:00',
+ }
+ )
+
+# diff in both
+csv_data1 = [
+ ['Item', 'Warehouse', 'Quantity', 'Rate'],
+ ['it', 'wh1', 20, 150]
+]
+
+# diff in qty, no rate
+csv_data2 = [
+ ['Item', 'Warehouse', 'Quantity'],
+ ['it', 'wh1', 20]
+]
+
+# diff in rate, no qty
+csv_data3 = [
+ ['Item', 'Warehouse', 'Rate'],
+ ['it', 'wh1', 200]
+]
+
+# diff in rate, same qty
+csv_data4 = [
+ ['Item', 'Warehouse', 'Quantity', 'Rate'],
+ ['it', 'wh1', 5, 200]
+]
+
+# no diff
+csv_data1 = [
+ ['Item', 'Warehouse', 'Quantity', 'Rate'],
+ ['it', 'wh1', 5, 100]
+]
diff --git a/erpnext/setup/doctype/email_digest/email_digest.coffee b/erpnext/setup/doctype/email_digest/email_digest.coffee
deleted file mode 100644
index 1b17d5b..0000000
--- a/erpnext/setup/doctype/email_digest/email_digest.coffee
+++ /dev/null
@@ -1,101 +0,0 @@
-content_items = ['Sales','Expenses','Bank Balance','Activity']
-
-# make a grid with items and columns of checkboxes
-# Parameters:
-# parent
-# label (main heading)
-# items = [] (rows)
-# columns = [] (columns of checks)
-# widths
-# description
-
-class CheckGrid
- constructor: (@args) ->
- $.extend @, args
- @wrapper = $a @parent, 'div', 'check-grid round'
- @render()
-
- render: ->
- $a @wrapper, 'h3', 'check-grid-title', null, @label
-
- if @description
- $a @wrapper, 'div', 'help-box', null, @description
-
- @tab = make_table @wrapper, @items.length + 1, @columns.length, '100%', @widths
- @checks = {}
-
- # render heads
- for i in [0..@columns.length-1]
- $($td(@tab, 0, i))
- .addClass('check-grid-head gradient')
- .html @columns[i]
-
- @render_rows()
-
- render_rows: ->
- # render rows
- for i in [0..@items.length-1]
- $td(@tab, i+1, 0).innerHTML = @items[i]
-
- # render checkboxes for this row
- @checks[@items[i]] = {}
- for c in [1..@columns.length-1]
- check = $a_input $td(@tab, i+1, c), 'checkbox'
-
- # tag keys to checkbox
- check.item = @items[i]
- check.column = @columns[c]
-
- # add in my checks
- @checks[@items[i]][@columns[c]] = check
-
- # get the values of the checkbox in a double dict
- get: =>
- val = {}
- for item in keys @checks
- for column in keys @checks[item]
- check = @checks[item][column]
- val[check.item] or= {}
- val[check.item][check.column] = if check.checked then 1 else 0
- val
-
- # set the values of the grid
- set: (val) =>
- for item in keys @checks
- for column in keys @checks[item]
- if val[item][column]
- @checks[item][column] .checked = val[item][column]
- return
-
-# attach it to onload
-cx = cur_frm.cscript
-cx.onload = (doc, dt, dn) ->
-
- # make the content grid
- cx.content_grid = new CheckGrid
- parent: cur_frm.fields_dict.Body.wrapper
- label: 'Email Settings'
- items: content_items
- columns: ['Item','Daily','Weekly']
- widths: ['60%', '20%', '20%']
- description: 'Select items to be compiled for Email Digest'
-
- # make the email grid
- cx.email_grid = new CheckGrid
- parent: cur_frm.fields_dict.Body.wrapper
- label: 'Send To'
- items: ['test1@erpnext', 'test2@erpnext']
- columns: ['Email','Daily','Weekly']
- widths: ['60%', '20%', '20%']
- description: 'Select who gets daily and weekly mails'
-
- cx.content_grid.set JSON.parse doc.content_config if doc.content_config
- cx.email_grid.set JSON.parse doc.email_config if doc.email_config
-
- return
-
-# update the data before sending
-cx.validate = (doc, dt, dn) ->
- doc.content_config = JSON.stringify cx.content_grid.get()
- doc.email_config = JSON.stringify cx.email_grid.get()
-
\ No newline at end of file
diff --git a/erpnext/setup/doctype/email_digest/email_digest.css b/erpnext/setup/doctype/email_digest/email_digest.css
deleted file mode 100644
index f61dacc..0000000
--- a/erpnext/setup/doctype/email_digest/email_digest.css
+++ /dev/null
@@ -1,18 +0,0 @@
-
-div.check-grid {
- margin: 17px;
-}
-
-div.check-grid table {
- border-collapse: collapse;
-}
-
-div.check-grid table td {
- padding: 3px;
- border: 1px solid #aaa;
-}
-
-td.check-grid-head {
- font-weight: bold;
- text-align: center;
-}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/email_digest/email_digest.js b/erpnext/setup/doctype/email_digest/email_digest.js
deleted file mode 100644
index ddb13f4..0000000
--- a/erpnext/setup/doctype/email_digest/email_digest.js
+++ /dev/null
@@ -1,108 +0,0 @@
-(function() {
- var CheckGrid, content_items, cx;
- var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
- content_items = ['Sales', 'Expenses', 'Bank Balance', 'Activity'];
- CheckGrid = (function() {
- function CheckGrid(args) {
- this.args = args;
- this.set = __bind(this.set, this);
- this.get = __bind(this.get, this);
- $.extend(this, args);
- this.wrapper = $a(this.parent, 'div', 'check-grid round');
- this.render();
- }
- CheckGrid.prototype.render = function() {
- var i, _ref;
- $a(this.wrapper, 'h3', 'check-grid-title', null, this.label);
- if (this.description) {
- $a(this.wrapper, 'div', 'help-box', null, this.description);
- }
- this.tab = make_table(this.wrapper, this.items.length + 1, this.columns.length, '100%', this.widths);
- this.checks = {};
- for (i = 0, _ref = this.columns.length - 1; 0 <= _ref ? i <= _ref : i >= _ref; 0 <= _ref ? i++ : i--) {
- $($td(this.tab, 0, i)).addClass('check-grid-head gradient').html(this.columns[i]);
- }
- return this.render_rows();
- };
- CheckGrid.prototype.render_rows = function() {
- var c, check, i, _ref, _results;
- _results = [];
- for (i = 0, _ref = this.items.length - 1; 0 <= _ref ? i <= _ref : i >= _ref; 0 <= _ref ? i++ : i--) {
- $td(this.tab, i + 1, 0).innerHTML = this.items[i];
- this.checks[this.items[i]] = {};
- _results.push((function() {
- var _ref2, _results2;
- _results2 = [];
- for (c = 1, _ref2 = this.columns.length - 1; 1 <= _ref2 ? c <= _ref2 : c >= _ref2; 1 <= _ref2 ? c++ : c--) {
- check = $a_input($td(this.tab, i + 1, c), 'checkbox');
- check.item = this.items[i];
- check.column = this.columns[c];
- _results2.push(this.checks[this.items[i]][this.columns[c]] = check);
- }
- return _results2;
- }).call(this));
- }
- return _results;
- };
- CheckGrid.prototype.get = function() {
- var check, column, item, val, _i, _j, _len, _len2, _name, _ref, _ref2;
- val = {};
- _ref = keys(this.checks);
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- item = _ref[_i];
- _ref2 = keys(this.checks[item]);
- for (_j = 0, _len2 = _ref2.length; _j < _len2; _j++) {
- column = _ref2[_j];
- check = this.checks[item][column];
- val[_name = check.item] || (val[_name] = {});
- val[check.item][check.column] = check.checked ? 1 : 0;
- }
- }
- return val;
- };
- CheckGrid.prototype.set = function(val) {
- var column, item, _i, _j, _len, _len2, _ref, _ref2;
- _ref = keys(this.checks);
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- item = _ref[_i];
- _ref2 = keys(this.checks[item]);
- for (_j = 0, _len2 = _ref2.length; _j < _len2; _j++) {
- column = _ref2[_j];
- if (val[item][column]) {
- this.checks[item][column].checked = val[item][column];
- }
- }
- }
- };
- return CheckGrid;
- })();
- cx = cur_frm.cscript;
- cx.onload = function(doc, dt, dn) {
- cx.content_grid = new CheckGrid({
- parent: cur_frm.fields_dict.Body.wrapper,
- label: 'Email Settings',
- items: content_items,
- columns: ['Item', 'Daily', 'Weekly'],
- widths: ['60%', '20%', '20%'],
- description: 'Select items to be compiled for Email Digest'
- });
- cx.email_grid = new CheckGrid({
- parent: cur_frm.fields_dict.Body.wrapper,
- label: 'Send To',
- items: ['test1@erpnext', 'test2@erpnext'],
- columns: ['Email', 'Daily', 'Weekly'],
- widths: ['60%', '20%', '20%'],
- description: 'Select who gets daily and weekly mails'
- });
- if (doc.content_config) {
- cx.content_grid.set(JSON.parse(doc.content_config));
- }
- if (doc.email_config) {
- cx.email_grid.set(JSON.parse(doc.email_config));
- }
- };
- cx.validate = function(doc, dt, dn) {
- doc.content_config = JSON.stringify(cx.content_grid.get());
- return doc.email_config = JSON.stringify(cx.email_grid.get());
- };
-}).call(this);
diff --git a/erpnext/setup/doctype/features_setup/features_setup.txt b/erpnext/setup/doctype/features_setup/features_setup.txt
index 909882e..d0f02d5 100644
--- a/erpnext/setup/doctype/features_setup/features_setup.txt
+++ b/erpnext/setup/doctype/features_setup/features_setup.txt
@@ -5,14 +5,14 @@
{
'creation': '2011-09-07 11:59:05',
'docstatus': 0,
- 'modified': '2011-10-05 10:50:17',
+ 'modified': '2011-12-06 18:48:53',
'modified_by': 'Administrator',
'owner': 'Administrator'
},
# These values are common for all DocType
{
- '_last_update': '1317790484',
+ '_last_update': '1323176623',
'colour': 'White:FFF',
'default_print_format': 'Standard',
'doctype': 'DocType',
@@ -22,7 +22,7 @@
'name_case': 'Title Case',
'section_style': 'Simple',
'show_in_menu': 1,
- 'version': 21
+ 'version': 24
},
# These values are common for all DocField
@@ -215,6 +215,39 @@
{
'doctype': 'DocField',
'fieldtype': 'Section Break',
+ 'label': 'Accounts'
+ },
+
+ # DocField
+ {
+ 'colour': 'White:FFF',
+ 'description': 'Check if you need automatic recurring invoices. After submitting any sales invoice, Recurring section will be visible.',
+ 'doctype': 'DocField',
+ 'fieldname': 'fs_recurring_invoice',
+ 'fieldtype': 'Check',
+ 'label': 'Recurring Invoice'
+ },
+
+ # DocField
+ {
+ 'doctype': 'DocField',
+ 'fieldtype': 'Column Break'
+ },
+
+ # DocField
+ {
+ 'colour': 'White:FFF',
+ 'description': 'To enable <b>Point of Sale</b> features',
+ 'doctype': 'DocField',
+ 'fieldname': 'fs_pos',
+ 'fieldtype': 'Check',
+ 'label': 'Point of Sale'
+ },
+
+ # DocField
+ {
+ 'doctype': 'DocField',
+ 'fieldtype': 'Section Break',
'label': 'Production'
},
@@ -246,16 +279,6 @@
# DocField
{
- 'colour': 'White:FFF',
- 'description': 'To enable <b>Point of Sale</b> features',
- 'doctype': 'DocField',
- 'fieldname': 'fs_pos',
- 'fieldtype': 'Check',
- 'label': 'Point of Sale'
- },
-
- # DocField
- {
'doctype': 'DocField',
'fieldtype': 'Section Break',
'label': 'Miscelleneous'
diff --git a/erpnext/setup/page/setup/setup.js b/erpnext/setup/page/setup/setup.js
index 7c1245a..92ba9db 100644
--- a/erpnext/setup/page/setup/setup.js
+++ b/erpnext/setup/page/setup/setup.js
@@ -169,7 +169,9 @@
['Manage Users',2,'My Company','','Add / remove users and manage their roles'],
['Web Forms',2,'Webforms','', 'Code to embed forms in yor website'],
['Permissions Manager',2,'Permission Engine','', 'Manage all permissions from one tool (beta)'],
- ['Property Setter',1,'Property Setter','', 'Customize properties of a Form (DocType) or Field'],
+ //['Property Setter',1,'Property Setter','', 'Customize properties of a Form (DocType) or Field'],
+ ['Customize Form View',3,'DocLayer','', 'Customize properties of a Form (DocType) or Field'],
+ ['Print Formats', 1, 'Print Format', '', 'Manage Print Formats'],
['Letter Head',1,'Letter Head','','Manage different letter heads for Prints'],
['SMS Settings',3,'SMS Settings','','Integrate your personalized SMS gateway which support http web service'],
['SMS Center',3,'SMS Center','','Send mass sms to your leads, contacts and partners'],
@@ -181,6 +183,7 @@
['Print Heading',1,'Print Heading','','Manage headings for printing transactions'],
['Term',1,'Term','','Manage template of standard Terms for order / invoices etc'],
['Currency',1,'Currency','','Manage list of currencies'],
+ ['Address',1,'Address','','Manage Address of customers, suppliers'],
['Country',1,'Country','','Country master'],
['State',1,'State','','State master'],
['Rename Tool',3,'Rename Tool','','Rename a record'],
diff --git a/erpnext/startup/startup.js b/erpnext/startup/startup.js
index fcb097b..291265b 100644
--- a/erpnext/startup/startup.js
+++ b/erpnext/startup/startup.js
@@ -690,6 +690,9 @@
},
'fs_pos': {
'Receivable Voucher': {'fields':['is_pos']}
+ },
+ 'fs_recurring_invoice': {
+ 'Receivable Voucher': {'fields': ['Recurring Invoice']}
}
}
diff --git a/erpnext/stock/doctype/bin/bin.py b/erpnext/stock/doctype/bin/bin.py
index e3af0a2..bb1101e 100644
--- a/erpnext/stock/doctype/bin/bin.py
+++ b/erpnext/stock/doctype/bin/bin.py
@@ -146,7 +146,7 @@
in_rate = flt(sql("select ifnull(avg(purchase_rate), 0) from `tabSerial No` where name in (%s)" % (serial_nos))[0][0])
if in_rate and val_rate == 0: # First entry
- val_rate = in_rate
+ val_rate = in_rate
# val_rate is same as previous entry if val_rate is negative
# Otherwise it will be calculated as per moving average
elif opening_qty + actual_qty > 0 and ((opening_qty * val_rate) + (actual_qty * in_rate)) > 0:
diff --git a/erpnext/stock/doctype/landed_cost_wizard/landed_cost_wizard.py b/erpnext/stock/doctype/landed_cost_wizard/landed_cost_wizard.py
index 2b828f9..c791e86 100644
--- a/erpnext/stock/doctype/landed_cost_wizard/landed_cost_wizard.py
+++ b/erpnext/stock/doctype/landed_cost_wizard/landed_cost_wizard.py
@@ -166,7 +166,7 @@
tax_amount = flt(rate) * (flt(ocd[row-1].total_tax_amount)+flt(ocd[row-1].total_amount)) / 100
elif ocd[row-1].add_deduct_tax == 'Deduct':
tax_amount = flt(rate) * (flt(ocd[row-1].total_tax_amount)-flt(ocd[row-1].total_amount)) / 100
-
+
return tax_amount
def add_deduct_taxes(self, ocd, oc, tax_amount, total, prev_total, item_tax):
@@ -202,7 +202,8 @@
for d in getlist(pr_obj.doclist, 'purchase_receipt_details'):
if flt(d.qty):
d.valuation_rate = (flt(d.purchase_rate) + (flt(d.rm_supp_cost)/flt(d.qty)) + (flt(d.item_tax_amount)/flt(d.qty))) / flt(d.conversion_factor)
- d.save()
+ d.save()
+ self.update_serial_no(d.serial_no, d.valuation_rate)
sql("update `tabStock Ledger Entry` set incoming_rate = '%s' where voucher_detail_no = '%s'"%(flt(d.valuation_rate), d.name))
bin = sql("select t1.name, t2.posting_date, t2.posting_time from `tabBin` t1, `tabStock Ledger Entry` t2 where t2.voucher_detail_no = '%s' and t2.item_code = t1.item_code and t2.warehouse = t1.warehouse LIMIT 1" % d.name)
@@ -211,6 +212,13 @@
if bin and bin[0][0]:
obj = get_obj('Bin', bin[0][0]).update_entries_after(bin[0][1], bin[0][2])
+
+ def update_serial_no(self, sr_no, rate):
+ """ update valuation rate in serial no"""
+ sr_no = sr_no.split('\n')
+ for d in sr_no:
+ sql("update `tabSerial No` set purchase_rate = %s where name = %s", (rate, d))
+
def update_landed_cost(self):
"""
diff --git a/erpnext/stock/doctype/purchase_receipt_detail/purchase_receipt_detail.txt b/erpnext/stock/doctype/purchase_receipt_detail/purchase_receipt_detail.txt
index 733e864..9fa0c40 100755
--- a/erpnext/stock/doctype/purchase_receipt_detail/purchase_receipt_detail.txt
+++ b/erpnext/stock/doctype/purchase_receipt_detail/purchase_receipt_detail.txt
@@ -5,7 +5,7 @@
{
'creation': '2010-08-08 17:09:16',
'docstatus': 0,
- 'modified': '2011-12-08 13:00:59',
+ 'modified': '2011-12-08 17:28:34',
'modified_by': 'Administrator',
'owner': 'Administrator'
},
@@ -21,7 +21,7 @@
'section_style': 'Tray',
'server_code_error': ' ',
'show_in_menu': 0,
- 'version': 60
+ 'version': 69
},
# These values are common for all DocField
@@ -117,23 +117,6 @@
# DocField
{
- 'colour': 'White:FFF',
- 'default': '0.00',
- 'doctype': 'DocField',
- 'fieldname': 'purchase_rate',
- 'fieldtype': 'Currency',
- 'label': 'Rate (Default Curr.)',
- 'oldfieldname': 'purchase_rate',
- 'oldfieldtype': 'Currency',
- 'permlevel': 0,
- 'print_hide': 1,
- 'reqd': 1,
- 'trigger': 'Client',
- 'width': '100px'
- },
-
- # DocField
- {
'default': '0.00',
'doctype': 'DocField',
'fieldname': 'qty',
@@ -148,6 +131,32 @@
# DocField
{
+ 'doctype': 'DocField',
+ 'fieldname': 'purchase_ref_rate',
+ 'fieldtype': 'Currency',
+ 'label': 'Ref Rate *',
+ 'permlevel': 0
+ },
+
+ # DocField
+ {
+ 'colour': 'White:FFF',
+ 'default': '0.00',
+ 'doctype': 'DocField',
+ 'fieldname': 'purchase_rate',
+ 'fieldtype': 'Currency',
+ 'label': 'Rate *(Default Curr.)',
+ 'oldfieldname': 'purchase_rate',
+ 'oldfieldtype': 'Currency',
+ 'permlevel': 0,
+ 'print_hide': 1,
+ 'reqd': 1,
+ 'trigger': 'Client',
+ 'width': '100px'
+ },
+
+ # DocField
+ {
'default': '0.00',
'doctype': 'DocField',
'fieldname': 'amount',
@@ -189,6 +198,15 @@
# DocField
{
+ 'doctype': 'DocField',
+ 'fieldname': 'import_ref_rate',
+ 'fieldtype': 'Currency',
+ 'label': 'Ref Rate ',
+ 'permlevel': 0
+ },
+
+ # DocField
+ {
'colour': 'White:FFF',
'default': '0.00',
'doctype': 'DocField',
@@ -206,15 +224,6 @@
# DocField
{
'doctype': 'DocField',
- 'fieldname': 'ref_rate',
- 'fieldtype': 'Currency',
- 'label': 'Ref Rate',
- 'permlevel': 0
- },
-
- # DocField
- {
- 'doctype': 'DocField',
'fieldname': 'import_amount',
'fieldtype': 'Currency',
'label': 'Amount',
@@ -546,4 +555,4 @@
'permlevel': 0,
'print_hide': 1
}
-]
\ No newline at end of file
+]
diff --git a/erpnext/stock/doctype/stock_ledger/stock_ledger.py b/erpnext/stock/doctype/stock_ledger/stock_ledger.py
index 5165cc9..0970b78 100644
--- a/erpnext/stock/doctype/stock_ledger/stock_ledger.py
+++ b/erpnext/stock/doctype/stock_ledger/stock_ledger.py
@@ -93,27 +93,27 @@
# ---------------------
def set_pur_serial_no_values(self, obj, serial_no, d, s, new_rec):
item_details = sql("select item_group, warranty_period from `tabItem` where name = '%s' and (ifnull(end_of_life,'')='' or end_of_life = '0000-00-00' or end_of_life > now()) " %(d.item_code), as_dict=1)
- s.purchase_document_type= obj.doc.doctype
- s.purchase_document_no = obj.doc.name
- s.purchase_date = obj.doc.posting_date
- s.purchase_time = obj.doc.posting_time
- s.purchase_rate = d.purchase_rate or d.incoming_rate
- s.item_code = d.item_code
- s.brand = d.brand
- s.description = d.description
- s.item_group = item_details and item_details[0]['item_group'] or ''
- s.warranty_period = item_details and item_details[0]['warranty_period'] or 0
- s.supplier = obj.doc.supplier
- s.supplier_name = obj.doc.supplier_name
- s.supplier_address = obj.doc.supplier_address
- s.warehouse = d.warehouse or d.t_warehouse
- s.docstatus = 0
- s.status = 'In Store'
- s.modified = nowdate()
- s.modified_by = session['user']
- s.serial_no = serial_no
- s.fiscal_year = obj.doc.fiscal_year
- s.company = obj.doc.company
+ s.purchase_document_type = obj.doc.doctype
+ s.purchase_document_no = obj.doc.name
+ s.purchase_date = obj.doc.posting_date
+ s.purchase_time = obj.doc.posting_time
+ s.purchase_rate = d.valuation_rate or d.incoming_rate
+ s.item_code = d.item_code
+ s.brand = d.brand
+ s.description = d.description
+ s.item_group = item_details and item_details[0]['item_group'] or ''
+ s.warranty_period = item_details and item_details[0]['warranty_period'] or 0
+ s.supplier = obj.doc.supplier
+ s.supplier_name = obj.doc.supplier_name
+ s.supplier_address = obj.doc.supplier_address
+ s.warehouse = d.warehouse or d.t_warehouse
+ s.docstatus = 0
+ s.status = 'In Store'
+ s.modified = nowdate()
+ s.modified_by = session['user']
+ s.serial_no = serial_no
+ s.fiscal_year = obj.doc.fiscal_year
+ s.company = obj.doc.company
s.save(new_rec)
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js
index de89d80..2e428df 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js
@@ -1,37 +1,7 @@
-cur_frm.cscript.onload = function(doc, cdt, cdn) {
- cfn_set_fields(doc, cdt, cdn);
+cur_frm.cscript.refresh = function(doc) {
+ if (doc.docstatus) hide_field('Steps');
}
-cur_frm.cscript.refresh = function(doc, cdt, cdn) {
- cfn_set_fields(doc, cdt, cdn);
+cur_frm.cscript['Download Template'] = function(doc, cdt, cdn) {
+ $c_obj_csv(make_doclist(cdt, cdn), 'get_template', '');
}
-
-var cfn_set_fields = function(doc, cdt, cdn) {
- refresh_field('remark');
- refresh_field('next_step');
- if (doc.docstatus == 0 && doc.next_step == 'Upload File and Save Document')
- doc.next_step = 'Validate Data';
-
- if (! doc.file_list)
- doc.next_step = 'Upload File and Save Document'
-
- if (doc.next_step == 'Upload File and Save Document') {
- //alert("Upload File and Save Document");
- cur_frm.clear_tip();
- cur_frm.set_tip("Please Enter Reconciliation Date and Attach CSV File with Columns in Following Sequence:-");
- cur_frm.append_tip("Item Code , Warehouse , Qty , MAR");
- hide_field("Validate Data");
- }
- if (doc.next_step == 'Validate Data') {
- //alert("Validate Data");
- cur_frm.clear_tip();
- cur_frm.set_tip("Please Check Remarks");
- unhide_field("Validate Data");
- }
- if (doc.next_step == 'Submit Document') {
- //alert('Submit Document');
- cur_frm.clear_tip();
- cur_frm.set_tip("Please Submit the document.");
- hide_field("Validate Data");
- }
-}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
index e133d6f..7b9d294 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -1,270 +1,23 @@
-# Please edit this list and import only required elements
import webnotes
-
-from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, generate_hash, getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common, month_name, now, nowdate, replace_newlines, sendmail, set_default, str_esc_quote, user_format, validate_email_add
-from webnotes.model import db_exists
-from webnotes.model.doc import Document, addchild, removechild, getchildren, make_autoname, SuperDocType
-from webnotes.model.doclist import getlist, copy_doclist
-from webnotes.model.code import get_obj, get_server_obj, run_server_obj, updatedb, check_syntax
-from webnotes import session, form, is_testing, msgprint, errprint
-
-set = webnotes.conn.set
+from webnotes.utils import cstr, flt, get_defaults, nowdate
+from webnotes import msgprint
+from webnotes.model.code import get_obj
sql = webnotes.conn.sql
-get_value = webnotes.conn.get_value
-in_transaction = webnotes.conn.in_transaction
-convert_to_lists = webnotes.conn.convert_to_lists
# -----------------------------------------------------------------------------------------
-
class DocType:
def __init__(self, doc, doclist=[]):
self.doc = doc
self.doclist = doclist
- self.label = { 'item_code': 0 , 'warehouse': 1 , 'qty': 2, 'mar': 3,'stock_uom':4, 'actual_qty':5, 'diff': 6} # with mar
+ self.validated = 1
+ self.data = []
- # autoname
- #-----------------
- def autoname(self):
- self.doc.name = make_autoname('SR/' + self.doc.fiscal_year + '/.######')
+ def get_template(self):
+ return [['Item Code', 'Warehouse', 'Quantity', 'Valuation Rate']]
- # -----------------
- # update next step
- # -----------------
- def update_next_step(self,next_step):
- sql("update `tabStock Reconciliation` set next_step = '%s' where name = '%s'" % (next_step,self.doc.name))
-
-
- # -----------
- # add remark
- # -----------
- def add_remark(self, text, next_step, first_time = 0):
- if first_time:
- sql("update `tabStock Reconciliation` set remark = '' where name = '%s'" % self.doc.name)
- else:
- sql("update `tabStock Reconciliation` set remark = concat(remark, '%s'), modified = '%s' where name = '%s'" % (text + "<br>", nowdate(), self.doc.name))
- self.update_next_step(next_step)
-
-
- # --------------
- # validate item
- # --------------
- def validate_item(self, item, count, check_item = 1):
- det = sql("select item_code, has_serial_no from `tabItem` where name = '%s'"% cstr(item), as_dict = 1)
- if not det:
- text = "Item: " + cstr(item) + " mentioned at Row No. " + cstr(count) + "does not exist in the system"
- msgprint(text)
- self.add_remark(text, 'Validate Data', 0)
- check_item = 0
- elif det and det[0]['has_serial_no'] == 'Yes':
- text = "You cannot make Stock Reconciliation of items having serial no. You can directly upload serial no to update their inventory. Please remove Item Code : %s at Row No. %s" %(cstr(item), cstr(count))
- msgprint(text)
- self.add_remark(text, 'Validate Data', 0)
- check_item = 0
- return check_item
-
-
- # -------------------
- # validate warehouse
- # -------------------
- def validate_warehouse(self,wh,count, check_warehouse = 1):
- if not sql("select name from `tabWarehouse` where name = '%s'" % cstr(wh)):
- text = "Warehouse: " + cstr(wh) + " mentioned at Row No. " + cstr(count) + "does not exist in the system"
- self.add_remark(text,'Validate Data',0)
- check_warehouse = 0
- return check_warehouse
-
-
- # ---------------------------
- # validate data of .csv file
- # ---------------------------
- def validate_data(self,stock):
- self.add_remark('','Validate Data',1)
-
- # check whether file uploaded
- if not self.doc.file_list:
- set(self.doc,'next_step','Upload File and Save Document')
- msgprint("Please Attach File", raise_exception=1)
-
- # validate item and warehouse
- check_item,check_warehouse,count = 1, 1, 1
- for s in stock:
- count +=1
- check_item = self.validate_item(s[self.label['item_code']],count) or 0
- check_warehouse = self.validate_warehouse(s[self.label['warehouse']],count) or 0
-
- if check_item and check_warehouse:
- text = "Validation Completed Successfully..."
- self.add_remark(text,'Submit Document',0)
- return check_item and check_warehouse
-
-
- # ------------------------------
- # convert lines in .csv to list
- # ------------------------------
- def convert_into_list(self, stock, submit):
- count, st_list = 1, []
- for s in stock:
- if submit and len(s) != 4:
- msgprint("Data entered at Row No " + cstr(count) + " in Attachment File is not in correct format.", raise_exception=1)
-
- l = [s[0].encode("ascii"), s[1].encode("ascii"), s[2].encode("ascii"), s[3].encode("ascii")]
- st_list.append(l)
- count += 1
- return st_list
-
- # ------------------
- # get current stock
- # ------------------
- def get_current_stock(self, item_code, warehouse):
- bin = sql("select name from `tabBin` where item_code = '%s' and warehouse = '%s'" % (item_code, warehouse))
- prev_sle = bin and get_obj('Bin', bin[0][0]).get_prev_sle(self.doc.reconciliation_date,self.doc.reconciliation_time) or {}
- stock_uom = sql("select stock_uom from `tabItem` where name = %s",item_code)
- return {'actual_qty': prev_sle.get('bin_aqat', 0), 'stock_uom': stock_uom[0][0]}
-
-
- # -----------
- # update mar
- # -----------
- def update_mar(self, d, qty_diff):
- """
- update item valuation in previous date and also on post date if no qty diff
- """
-
- self.update_entries_pre_date(d)
-
- if not flt(d[self.label['qty']]) and not flt(d[self.label['actual_qty']]):
- # seems like a special condition when there is no actual quanitity but there is a rate, may be only for setting a rate!
- self.make_sl_entry(1,d,1)
- self.make_sl_entry(1,d,-1)
- elif not qty_diff:
- self.update_entries_post_date(d)
-
- # update valuation rate as csv file in all sle before reconciliation date
- # ------------------------------------------------------------------------
- def update_entries_pre_date(self, d):
- mar = flt(d[self.label['mar']])
-
- # previous sle
- prev_sle = sql("""
- select name, fcfs_stack
- from `tabStock Ledger Entry`
- where item_code = %s
- and warehouse = %s
- and ifnull(is_cancelled, 'No') = 'No'
- and timestamp(posting_date, posting_time) <= timestamp(%s, %s)
- """, (d[self.label['item_code']], d[self.label['warehouse']], self.doc.reconciliation_date, self.doc.reconciliation_time))
-
- for each in prev_sle:
- # updated fifo stack
- fstack = each[1] and [[i[0], mar] for i in eval(each[1])] or ''
-
- # update incoming rate, valuation rate, stock value and fifo stack
- sql("""update `tabStock Ledger Entry`
- set incoming_rate = %s, valuation_rate = %s, stock_value = bin_aqat*%s, fcfs_stack = %s
- where name = %s
- """, (mar, mar, mar, cstr(fstack), each[0]))
-
-
- # Update item valuation in all sle after the reconcliation date
- # ---------------------------------------------------------
- def update_entries_post_date(self, d):
- bin = sql("select name from `tabBin` where item_code = '%s' and warehouse = '%s'" % (d[self.label['item_code']], d[self.label['warehouse']]))
- bin_obj = get_obj('Bin', bin[0][0])
-
- # update valuation in sle posted after reconciliation datetime
- bin_obj.update_entries_after(posting_date = self.doc.reconciliation_date, posting_time = self.doc.reconciliation_time)
-
- # --------------
- # make sl entry
- # --------------
- def make_sl_entry(self, update_stock, stock, diff):
- values = []
- values.append({
- 'item_code' : stock[self.label['item_code']],
- 'warehouse' : stock[self.label['warehouse']],
- 'transaction_date' : now(),
- 'posting_date' : self.doc.reconciliation_date,
- 'posting_time' : self.doc.reconciliation_time,
- 'voucher_type' : self.doc.doctype,
- 'voucher_no' : self.doc.name,
- 'voucher_detail_no' : self.doc.name,
- 'actual_qty' : flt(update_stock) * flt(diff),
- 'stock_uom' : stock[self.label['stock_uom']],
- 'incoming_rate' : stock[self.label['mar']] or 0,
- 'company' : self.doc.company,
- 'fiscal_year' : self.doc.fiscal_year,
- 'is_cancelled' : (update_stock==1) and 'No' or 'Yes',
- 'batch_no' : '',
- 'serial_no' : ''
- })
-
- get_obj('Stock Ledger', 'Stock Ledger').update_stock(values)
-
-
- # -----------------------
- # get stock reco details
- # -----------------------
- def get_reconciliation_stock_details(self,submit = 0):
- import csv
- stock = csv.reader(self.get_csv_file_data().splitlines())
- stock = self.convert_into_list(stock, submit)
- if stock[0][0] and stock[0][0].strip()=='Item Code':
- stock.pop(0) # remove the labels
- check = self.validate_data(stock)
- if not check:
- return 0
- return stock
-
- # validate date and time
- # ------------------------
- def validate_datetime(self):
- if not self.doc.reconciliation_date:
- msgprint("Please Enter Reconciliation Date.", raise_exception=1)
- if not self.doc.reconciliation_time:
- msgprint("Please Enter Reconciliation Time.", raise_exception=1)
-
-
-
- # ----------------------
- # stock reconciliations
- # ----------------------
- def stock_reconciliations(self, submit = 0):
- self.validate_datetime()
-
- # get reco data
- rec_stock_detail = self.get_reconciliation_stock_details(submit) or []
- if not rec_stock_detail:
- msgprint("Please Check Remarks", raise_exception=1)
-
- count = 1
- for stock in rec_stock_detail:
- count += 1
-
- # Get qty as per system
- cur_stock_detail = self.get_current_stock(stock[self.label['item_code']],stock[self.label['warehouse']])
- stock.append(cur_stock_detail['stock_uom'])
- stock.append(cur_stock_detail['actual_qty'])
-
- # Qty Diff between file and system
- diff = flt(stock[self.label['qty']]) - flt(cur_stock_detail['actual_qty'])
-
- # Update MAR
- if not stock[self.label['mar']] == '~':
- self.update_mar(stock, diff)
-
- # Make sl entry if qty differ
- if diff:
- self.make_sl_entry(submit, stock, diff)
-
- if rec_stock_detail:
- text = "Stock Reconciliation Completed Successfully..."
- self.add_data_in_CSV(rec_stock_detail)
- self.add_remark(text,'Completed', 0)
-
- # Get csv data
- #--------------------------
def get_csv_file_data(self):
+ """Get csv data"""
filename = self.doc.file_list.split(',')
if not filename:
msgprint("Please Attach File. ", raise_exception=1)
@@ -274,37 +27,160 @@
if not type(content) == str:
content = content.tostring()
+
return content
+ def convert_into_list(self, data):
+ """Convert csv data into list"""
+ count = 1
+ for s in data:
+ if s[0].strip() != 'Item Code': # remove the labels
+ # validate
+ if len(s) != 4:
+ msgprint("Data entered at Row No " + cstr(count) + " in Attachment File is not in correct format.", raise_exception=1)
+ self.validated = 0
+ self.validate_item(s[0], count)
+ self.validate_warehouse(s[1], count)
+
+ # encode as ascii
+ self.data.append([d.encode("ascii") for d in s])
+ count += 1
+
+ if not self.validated:
+ raise Exception
- def getCSVelement(self,v):
- v = cstr(v)
- if not v: return ''
- if (',' in v) or ('' in v) or ('"' in v):
- if '"' in v: v = v.replace('"', '""')
- return '"'+v+'"'
- else: return v or ''
- # Add qty diff column in attached file
- #----------------------------------------
- def add_data_in_CSV(self,data):
- filename = self.doc.file_list.split(',')
- head = []
- for h in ['Item Code','Warehouse','Qty','Actual','Difference','MAR']:
- head.append(self.getCSVelement(h))
- dset = (','.join(head) + "\n")
- for d in data:
- l = [d[self.label['item_code']],d[self.label['warehouse']],d[self.label['qty']],d[self.label['actual_qty']],flt(d[self.label['qty']])-flt(d[self.label['actual_qty']]),d[self.label['mar']]]
- s =[]
- for i in l:
- s.append(self.getCSVelement(i))
- dset +=(','.join(s)+"\n")
+ def get_reconciliation_data(self,submit = 0):
+ """Read and validate csv data"""
+ import csv
+ data = csv.reader(self.get_csv_file_data().splitlines())
+ self.convert_into_list(data)
- from webnotes.utils import file_manager
- file_manager.write_file(filename[1], dset)
- # ----------
- # on submit
- # ----------
+ def validate_item(self, item, count):
+ """ Validate item exists and non-serialized"""
+ det = sql("select item_code, has_serial_no from `tabItem` where name = '%s'"% cstr(item), as_dict = 1)
+ if not det:
+ msgprint("Item: " + cstr(item) + " mentioned at Row No. " + cstr(count) + "does not exist in the system")
+ self.validated = 0
+ elif det and det[0]['has_serial_no'] == 'Yes':
+ msgprint("""You cannot make Stock Reconciliation of items having serial no. \n
+ You can directly upload serial no to update their inventory. \n
+ Please remove Item Code : %s at Row No. %s""" %(cstr(item), cstr(count)))
+ self.validated = 0
+
+
+ def validate_warehouse(self, wh, count,):
+ """Validate warehouse exists"""
+ if not sql("select name from `tabWarehouse` where name = '%s'" % cstr(wh)):
+ msgprint("Warehouse: " + cstr(wh) + " mentioned at Row No. " + cstr(count) + " does not exist in the system")
+ self.validated = 0
+
+
+
+ def validate(self):
+ """Validate attachment data"""
+ #self.data = [['it', 'wh1', 20, 150]]
+ if self.doc.file_list:
+ self.get_reconciliation_data()
+
+
+
+ def get_system_stock(self, it, wh):
+ """get actual qty on reconciliation date and time as per system"""
+ bin = sql("select name from tabBin where item_code=%s and warehouse=%s", (it, wh))
+ prev_sle = bin and get_obj('Bin', bin[0][0]).get_sle_prev_timebucket(self.doc.reconciliation_date, self.doc.reconciliation_time) or {}
+ return {
+ 'actual_qty': prev_sle.get('bin_aqat', 0),
+ 'stock_uom' : sql("select stock_uom from tabItem where name = %s", it)[0][0],
+ 'val_rate' : prev_sle.get('valuation_rate', 0)
+ }
+
+
+ def make_sl_entry(self, is_submit, row, qty_diff, sys_stock):
+ """Make stock ledger entry"""
+ in_rate = self.get_incoming_rate(row, qty_diff, sys_stock)
+ values = [{
+ 'item_code' : row[0],
+ 'warehouse' : row[1],
+ 'transaction_date' : nowdate(),
+ 'posting_date' : self.doc.reconciliation_date,
+ 'posting_time' : self.doc.reconciliation_time,
+ 'voucher_type' : self.doc.doctype,
+ 'voucher_no' : self.doc.name,
+ 'voucher_detail_no' : self.doc.name,
+ 'actual_qty' : flt(is_submit) * flt(qty_diff),
+ 'stock_uom' : sys_stock['stock_uom'],
+ 'incoming_rate' : in_rate,
+ 'company' : get_defaults()['company'],
+ 'fiscal_year' : get_defaults()['fiscal_year'],
+ 'is_cancelled' : (is_submit==1) and 'No' or 'Yes',
+ 'batch_no' : '',
+ 'serial_no' : ''
+ }]
+ get_obj('Stock Ledger', 'Stock Ledger').update_stock(values)
+
+
+ def get_incoming_rate(self, row, qty_diff, sys_stock):
+ """Calculate incoming rate to maintain valuation rate"""
+ in_rate = flt(row[3]) + (flt(sys_stock['actual_qty'])*(flt(row[3]) - flt(sys_stock['val_rate'])))/ flt(qty_diff)
+ return in_rate
+
+
+ def do_stock_reco(self, is_submit = 1):
+ """
+ Make stock entry of qty diff, calculate incoming rate to maintain valuation rate.
+ If no qty diff, but diff in valuation rate, make (+1,-1) entry to update valuation
+ """
+ for row in self.data:
+ # Get qty as per system
+ sys_stock = self.get_system_stock(row[0],row[1])
+
+ # Diff between file and system
+ qty_diff = row[2] != '~' and flt(row[2]) - flt(sys_stock['actual_qty']) or 0
+ rate_diff = row[3] != '~' and flt(row[3]) - flt(sys_stock['val_rate']) or 0
+
+ # Make sl entry
+ if qty_diff:
+ self.make_sl_entry(is_submit, row, qty_diff, sys_stock)
+ elif rate_diff:
+ self.make_sl_entry(is_submit, row, 1, sys_stock)
+ sys_stock['val_rate'] = row[3]
+ sys_stock['actual_qty'] += 1
+ self.make_sl_entry(is_submit, row, -1, sys_stock)
+
+ if is_submit == 1:
+ self.add_data_in_CSV(qty_diff, rate_diff)
+
+ msgprint("Stock Reconciliation Completed Successfully...")
+
+
+ def add_data_in_CSV(self, qty_diff, rate_diff):
+ """Add diffs column in attached file"""
+
+ # add header
+ out = "'Item Code', 'Warehouse', 'Qty', 'Valuation Rate', 'Qty Diff', 'Val Rate Diff'"
+
+ # add data
+ for d in self.data:
+ s = [cstr(i) for i in d] + [cstr(qty_diff), cstr(rate_diff)]
+ out += "\n" + ','.join(s)
+
+ # write to file
+ fname = self.doc.file_list.split(',')
+ from webnotes.utils import file_manager
+ file_manager.write_file(fname[1], out)
+
+
+
def on_submit(self):
- self.stock_reconciliations(submit = 1)
+ if not self.doc.file_list:
+ msgprint("Please attach file before submitting.", raise_exception=1)
+ else:
+ self.do_stock_reco(is_submit = 1)
+
+
+
+ def on_cancel(self):
+ self.validate()
+ self.do_stock_reco(is_submit = -1)
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.txt b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.txt
index 771068d..9a21130 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.txt
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.txt
@@ -5,16 +5,18 @@
{
'creation': '2010-08-08 17:09:26',
'docstatus': 0,
- 'modified': '2011-04-25 11:46:21',
+ 'modified': '2011-11-24 12:04:03',
'modified_by': 'Administrator',
'owner': 'Administrator'
},
# These values are common for all DocType
{
- '_last_update': '1309508840',
+ '_last_update': '1321617741',
'allow_attach': 1,
+ 'autoname': 'SR/.######',
'colour': 'White:FFF',
+ 'default_print_format': 'Standard',
'doctype': 'DocType',
'max_attachments': 1,
'module': 'Stock',
@@ -23,7 +25,8 @@
'section_style': 'Tray',
'server_code_error': ' ',
'show_in_menu': 0,
- 'version': 85
+ 'subject': 'Date: %(reconciliation_date)s, Time: %(reconciliation_time)s',
+ 'version': 107
},
# These values are common for all DocField
@@ -37,6 +40,7 @@
# These values are common for all DocPerm
{
+ 'amend': 0,
'doctype': 'DocPerm',
'name': '__common__',
'parent': 'Stock Reconciliation',
@@ -53,11 +57,9 @@
# DocPerm
{
- 'amend': 1,
'cancel': 1,
'create': 1,
'doctype': 'DocPerm',
- 'idx': 1,
'permlevel': 0,
'role': 'Material Manager',
'submit': 1,
@@ -66,11 +68,9 @@
# DocPerm
{
- 'amend': 0,
'cancel': 0,
'create': 0,
'doctype': 'DocPerm',
- 'idx': 2,
'permlevel': 1,
'role': 'Material Manager',
'submit': 0,
@@ -79,44 +79,21 @@
# DocPerm
{
- 'amend': 1,
'cancel': 1,
'create': 1,
'doctype': 'DocPerm',
- 'idx': 3,
'permlevel': 0,
'role': 'System Manager',
'submit': 1,
'write': 1
},
- # DocPerm
- {
- 'doctype': 'DocPerm',
- 'idx': 4,
- 'permlevel': 1,
- 'role': 'System Manager'
- },
-
# DocField
{
'doctype': 'DocField',
- 'fieldtype': 'Button',
- 'hidden': 1,
- 'idx': 1,
- 'label': 'Validate Data',
- 'oldfieldtype': 'Button',
- 'options': 'get_reconciliation_stock_details',
- 'permlevel': 0
- },
-
- # DocField
- {
- 'doctype': 'DocField',
- 'fieldtype': 'Section Break',
- 'idx': 2,
- 'label': 'Summary',
- 'oldfieldtype': 'Section Break',
+ 'fieldtype': 'HTML',
+ 'label': 'Steps',
+ 'options': '<div class="field_description"><b>Steps:</b><br>1. Enter Reconciliation Date and Time<br>2. Save the document<br>3. Attach csv file as per template.<br>4. Submit the document<br>5. Enter tilde (~) sign if no difference in qty or valuation rate</div>',
'permlevel': 0
},
@@ -125,14 +102,12 @@
'doctype': 'DocField',
'fieldname': 'reconciliation_date',
'fieldtype': 'Date',
- 'idx': 3,
'in_filter': 0,
'label': 'Reconciliation Date',
'oldfieldname': 'reconciliation_date',
'oldfieldtype': 'Date',
'permlevel': 0,
- 'reqd': 1,
- 'search_index': 1
+ 'reqd': 1
},
# DocField
@@ -140,7 +115,6 @@
'doctype': 'DocField',
'fieldname': 'reconciliation_time',
'fieldtype': 'Time',
- 'idx': 4,
'in_filter': 0,
'label': 'Reconciliation Time',
'oldfieldname': 'reconciliation_time',
@@ -152,97 +126,20 @@
# DocField
{
'doctype': 'DocField',
- 'fieldname': 'next_step',
- 'fieldtype': 'Select',
- 'idx': 5,
- 'label': 'Next Steps',
- 'oldfieldname': 'next_step',
- 'oldfieldtype': 'Select',
- 'options': 'Upload File and Save Document\nValidate Data\nSubmit Document\nCompleted',
- 'permlevel': 1
- },
-
- # DocField
- {
- 'doctype': 'DocField',
'fieldname': 'remark',
'fieldtype': 'Text',
- 'idx': 6,
'label': 'Remark',
'oldfieldname': 'remark',
'oldfieldtype': 'Text',
- 'permlevel': 1
- },
-
- # DocField
- {
- 'doctype': 'DocField',
- 'fieldname': 'company',
- 'fieldtype': 'Link',
- 'idx': 7,
- 'in_filter': 1,
- 'label': 'Company',
- 'oldfieldname': 'company',
- 'oldfieldtype': 'Link',
- 'options': 'Company',
- 'permlevel': 0,
- 'search_index': 0
- },
-
- # DocField
- {
- 'doctype': 'DocField',
- 'fieldname': 'fiscal_year',
- 'fieldtype': 'Select',
- 'idx': 8,
- 'in_filter': 1,
- 'label': 'Fiscal Year',
- 'oldfieldname': 'fiscal_year',
- 'oldfieldtype': 'Select',
- 'options': 'link:Fiscal Year',
- 'permlevel': 0,
- 'search_index': 0
- },
-
- # DocField
- {
- 'doctype': 'DocField',
- 'fieldname': 'amended_from',
- 'fieldtype': 'Data',
- 'idx': 9,
- 'label': 'Amended From',
- 'permlevel': 1
- },
-
- # DocField
- {
- 'doctype': 'DocField',
- 'fieldname': 'amendment_date',
- 'fieldtype': 'Date',
- 'idx': 10,
- 'label': 'Amendment Date',
- 'permlevel': 1
- },
-
- # DocField
- {
- 'doctype': 'DocField',
- 'fieldtype': 'Section Break',
- 'idx': 11,
- 'label': 'Attachment',
- 'oldfieldtype': 'Section Break',
'permlevel': 0
},
# DocField
{
'doctype': 'DocField',
- 'fieldtype': 'HTML',
- 'idx': 12,
- 'label': 'Attachment HTML',
- 'oldfieldtype': 'HTML',
- 'options': 'The attachment must be a CSV(Comma Seperated Value) file',
- 'permlevel': 1
+ 'fieldtype': 'Button',
+ 'label': 'Download Template',
+ 'permlevel': 0
},
# DocField
@@ -251,8 +148,8 @@
'fieldname': 'file_list',
'fieldtype': 'Text',
'hidden': 1,
- 'idx': 13,
'label': 'File List',
+ 'no_copy': 1,
'oldfieldname': 'file_list',
'oldfieldtype': 'Text',
'permlevel': 1,
diff --git a/erpnext/stock/doctype/warehouse/warehouse.py b/erpnext/stock/doctype/warehouse/warehouse.py
index b59ce75..0b099fd 100644
--- a/erpnext/stock/doctype/warehouse/warehouse.py
+++ b/erpnext/stock/doctype/warehouse/warehouse.py
@@ -18,73 +18,88 @@
class DocType:
- def __init__(self, doc, doclist=[]):
- self.doc = doc
- self.doclist = doclist
-
- def get_bin(self, item_code):
- bin = sql("select name from tabBin where item_code = '%s' and warehouse = '%s'" % (item_code, self.doc.name))
- bin = bin and bin[0][0] or ''
- if not bin:
- if not self.doc.warehouse_type :
- msgprint("[Warehouse Type is Mandatory] Please Enter warehouse type in Warehouse " + self.doc.name)
- raise Exception
- bin = Document('Bin')
- bin.item_code = item_code
- bin.stock_uom = get_value('Item', item_code, 'stock_uom')
- bin.warehouse = self.doc.name
- bin.warehouse_type = self.doc.warehouse_type
- bin_obj = get_obj(doc=bin)
- bin_obj.validate()
- bin.save(1)
- bin = bin.name
- else:
- bin_obj = get_obj('Bin',bin)
+ def __init__(self, doc, doclist=[]):
+ self.doc = doc
+ self.doclist = doclist
+
+ def get_bin(self, item_code):
+ bin = sql("select name from tabBin where item_code = '%s' and warehouse = '%s'" % (item_code, self.doc.name))
+ bin = bin and bin[0][0] or ''
+ if not bin:
+ if not self.doc.warehouse_type :
+ msgprint("[Warehouse Type is Mandatory] Please Enter warehouse type in Warehouse " + self.doc.name)
+ raise Exception
+ bin = Document('Bin')
+ bin.item_code = item_code
+ bin.stock_uom = get_value('Item', item_code, 'stock_uom')
+ bin.warehouse = self.doc.name
+ bin.warehouse_type = self.doc.warehouse_type
+ bin_obj = get_obj(doc=bin)
+ bin_obj.validate()
+ bin.save(1)
+ bin = bin.name
+ else:
+ bin_obj = get_obj('Bin',bin)
- return bin_obj
-
+ return bin_obj
+
- def validate_asset(self, item_code):
- if sql("select is_asset_item from tabItem where name=%s", item_code)[0][0] == 'Yes' and self.doc.warehouse_type != 'Fixed Asset':
- msgprint("Fixed Asset Item %s can only be transacted in a Fixed Asset type Warehouse" % item_code)
- raise Exception
+ def validate_asset(self, item_code):
+ if sql("select is_asset_item from tabItem where name=%s", item_code)[0][0] == 'Yes' and self.doc.warehouse_type != 'Fixed Asset':
+ msgprint("Fixed Asset Item %s can only be transacted in a Fixed Asset type Warehouse" % item_code)
+ raise Exception
- # update bin
- # ----------
- def update_bin(self, actual_qty, reserved_qty, ordered_qty, indented_qty, planned_qty, item_code, dt, sle_id = '',posting_time = '', serial_no = '', is_cancelled = 'No'):
- self.validate_asset(item_code)
- it_det = get_value('Item', item_code, 'is_stock_item')
- if it_det and it_det == 'Yes':
- bin = self.get_bin(item_code)
- bin.update_stock(actual_qty, reserved_qty, ordered_qty, indented_qty, planned_qty, dt, sle_id, posting_time, serial_no, is_cancelled)
- return bin
- else:
- msgprint("[Stock Update] Ignored %s since it is not a stock item" % item_code)
+ # update bin
+ # ----------
+ def update_bin(self, actual_qty, reserved_qty, ordered_qty, indented_qty, planned_qty, item_code, dt, sle_id = '',posting_time = '', serial_no = '', is_cancelled = 'No'):
+ self.validate_asset(item_code)
+ it_det = get_value('Item', item_code, 'is_stock_item')
+ if it_det and it_det == 'Yes':
+ bin = self.get_bin(item_code)
+ bin.update_stock(actual_qty, reserved_qty, ordered_qty, indented_qty, planned_qty, dt, sle_id, posting_time, serial_no, is_cancelled)
+ return bin
+ else:
+ msgprint("[Stock Update] Ignored %s since it is not a stock item" % item_code)
- # repost stock
- # ------------
- def repost_stock(self):
- bl = sql("select name from tabBin where warehouse=%s", self.doc.name)
- for b in bl:
- bobj = get_obj('Bin',b[0])
- bobj.update_entries_after(posting_date = '0000-00-00', posting_time = '00:00')
+ # repost stock
+ # ------------
+ def repost_stock(self):
+ bl = sql("select name from tabBin where warehouse=%s", self.doc.name)
+ for b in bl:
+ bobj = get_obj('Bin',b[0])
+ bobj.update_entries_after(posting_date = '0000-00-00', posting_time = '00:00')
- sql("COMMIT")
- sql("START TRANSACTION")
+ sql("COMMIT")
+ sql("START TRANSACTION")
- def check_state(self):
- return "\n" + "\n".join([i[0] for i in sql("select state_name from `tabState` where `tabState`.country='%s' " % self.doc.country)])
+ def check_state(self):
+ return "\n" + "\n".join([i[0] for i in sql("select state_name from `tabState` where `tabState`.country='%s' " % self.doc.country)])
- def validate(self):
- if self.doc.email_id:
- if not validate_email_add(self.doc.email_id):
- msgprint("Please enter valid Email Id.")
- raise Exception
- if not self.doc.warehouse_type:
- msgprint("[Warehouse Type is Mandatory] Please Enter Please Entry warehouse type in Warehouse " + self.doc.name)
- raise Exception
- wt = sql("select warehouse_type from `tabWarehouse` where name ='%s'" % self.doc.name)
- if cstr(self.doc.warehouse_type) != cstr(wt and wt[0][0] or ''):
- sql("update `tabStock Ledger Entry` set warehouse_type = '%s' where warehouse = '%s'" % (self.doc.warehouse_type, self.doc.name))
- msgprint("All Stock Ledger Entries Updated.")
+ def validate(self):
+ if self.doc.email_id:
+ if not validate_email_add(self.doc.email_id):
+ msgprint("Please enter valid Email Id.")
+ raise Exception
+ if not self.doc.warehouse_type:
+ msgprint("[Warehouse Type is Mandatory] Please Enter Please Entry warehouse type in Warehouse " + self.doc.name)
+ raise Exception
+ wt = sql("select warehouse_type from `tabWarehouse` where name ='%s'" % self.doc.name)
+ if cstr(self.doc.warehouse_type) != cstr(wt and wt[0][0] or ''):
+ sql("update `tabStock Ledger Entry` set warehouse_type = '%s' where warehouse = '%s'" % (self.doc.warehouse_type, self.doc.name))
+ msgprint("All Stock Ledger Entries Updated.")
+
+ def on_trash(self):
+ # delete bin
+ bins = sql("select * from `tabBin` where warehouse = %s", self.doc.name, as_dict=1)
+ for d in bins:
+ if d['actual_qty'] or d['reserved_qty'] or d['ordered_qty'] or d['indented_qty'] or d['projected_qty'] or d['planned_qty']:
+ msgprint("Warehouse: %s can not be deleted as qty exists for item: %s" % (self.doc.name, d['item_code']), raise_exception=1)
+ else:
+ sql("delete from `tabBin` where name = %s", d['name'])
+
+ # delete cancelled sle
+ if sql("select name from `tabStock Ledger Entry` where warehouse = %s and ifnull('is_cancelled', '') = 'No'", self.doc.name):
+ mdgprint("Warehosue can not be deleted as stock ledger entry exists for this warehosue.", raise_exception=1)
+ else:
+ sql("delete from `tabStock Ledger Entry` where warehouse = %s", self.doc.name)
diff --git a/erpnext/stock/doctype/warehouse/warehouse.txt b/erpnext/stock/doctype/warehouse/warehouse.txt
index da29dfa..87b0eda 100644
--- a/erpnext/stock/doctype/warehouse/warehouse.txt
+++ b/erpnext/stock/doctype/warehouse/warehouse.txt
@@ -5,14 +5,14 @@
{
'creation': '2010-08-08 17:09:30',
'docstatus': 0,
- 'modified': '2011-09-28 16:19:59',
+ 'modified': '2011-11-15 15:06:24',
'modified_by': 'Administrator',
'owner': 'Administrator'
},
# These values are common for all DocType
{
- '_last_update': '1311621379',
+ '_last_update': '1319016431',
'allow_trash': 1,
'autoname': 'field:warehouse_name',
'colour': 'White:FFF',
@@ -25,7 +25,7 @@
'section_style': 'Tabbed',
'server_code_error': ' ',
'show_in_menu': 0,
- 'version': 56
+ 'version': 58
},
# These values are common for all DocField
@@ -319,27 +319,6 @@
# DocField
{
- 'allow_on_submit': 0,
- 'doctype': 'DocField',
- 'fieldname': 'country',
- 'fieldtype': 'Link',
- 'hidden': 0,
- 'in_filter': 0,
- 'label': 'Country',
- 'no_copy': 0,
- 'oldfieldname': 'country',
- 'oldfieldtype': 'Link',
- 'options': 'Country',
- 'permlevel': 0,
- 'print_hide': 0,
- 'report_hide': 0,
- 'reqd': 0,
- 'search_index': 0,
- 'trigger': 'Client'
- },
-
- # DocField
- {
'colour': 'White:FFF',
'doctype': 'DocField',
'fieldname': 'state',
diff --git a/erpnext/utilities/doctype/address/address.txt b/erpnext/utilities/doctype/address/address.txt
index 4f44806..776321b 100644
--- a/erpnext/utilities/doctype/address/address.txt
+++ b/erpnext/utilities/doctype/address/address.txt
@@ -3,26 +3,28 @@
# These values are common in all dictionaries
{
- 'creation': '2011-05-24 10:14:48',
+ 'creation': '2011-05-24 14:57:59',
'docstatus': 0,
- 'modified': '2011-06-09 12:28:53',
+ 'modified': '2011-11-23 13:21:00',
'modified_by': 'Administrator',
'owner': 'Administrator'
},
# These values are common for all DocType
{
- '_last_update': '1307602735',
+ '_last_update': '1319016431',
'allow_trash': 1,
'colour': 'White:FFF',
+ 'default_print_format': 'Standard',
'doctype': 'DocType',
'document_type': 'Master',
'in_dialog': 1,
'module': 'Utilities',
'name': '__common__',
+ 'search_fields': 'customer, supplier, sales_partner, country, state',
'section_style': 'Simple',
'show_in_menu': 0,
- 'version': 42
+ 'version': 43
},
# These values are common for all DocField
@@ -39,7 +41,6 @@
'cancel': 1,
'create': 1,
'doctype': 'DocPerm',
- 'idx': 1,
'name': '__common__',
'parent': 'Address',
'parentfield': 'permissions',
@@ -66,7 +67,6 @@
'colour': 'White:FFF',
'doctype': 'DocField',
'fieldtype': 'Section Break',
- 'idx': 1,
'label': 'Address Details',
'permlevel': 0
},
@@ -78,7 +78,6 @@
'doctype': 'DocField',
'fieldname': 'address_type',
'fieldtype': 'Data',
- 'idx': 2,
'label': 'Address Type',
'permlevel': 0,
'reqd': 1
@@ -90,7 +89,6 @@
'doctype': 'DocField',
'fieldname': 'address_line1',
'fieldtype': 'Data',
- 'idx': 3,
'label': 'Address Line1',
'permlevel': 0,
'reqd': 1
@@ -101,7 +99,6 @@
'doctype': 'DocField',
'fieldname': 'address_line2',
'fieldtype': 'Data',
- 'idx': 4,
'label': 'Address Line2',
'permlevel': 0
},
@@ -112,12 +109,11 @@
'doctype': 'DocField',
'fieldname': 'city',
'fieldtype': 'Data',
- 'idx': 5,
'in_filter': 1,
'label': 'City/Town',
'permlevel': 0,
'reqd': 1,
- 'search_index': 0
+ 'search_index': 1
},
# DocField
@@ -125,11 +121,10 @@
'doctype': 'DocField',
'fieldname': 'pincode',
'fieldtype': 'Data',
- 'idx': 6,
'in_filter': 1,
'label': 'Pincode',
'permlevel': 0,
- 'search_index': 0
+ 'search_index': 1
},
# DocField
@@ -138,13 +133,12 @@
'doctype': 'DocField',
'fieldname': 'country',
'fieldtype': 'Select',
- 'idx': 7,
'in_filter': 1,
'label': 'Country',
'options': 'link:Country',
'permlevel': 0,
'reqd': 1,
- 'search_index': 0,
+ 'search_index': 1,
'trigger': 'Client'
},
@@ -154,7 +148,6 @@
'doctype': 'DocField',
'fieldname': 'state',
'fieldtype': 'Data',
- 'idx': 8,
'in_filter': 1,
'label': 'State',
'options': 'Suggest',
@@ -166,7 +159,6 @@
{
'doctype': 'DocField',
'fieldtype': 'Column Break',
- 'idx': 9,
'permlevel': 0,
'print_hide': 0,
'width': '50%'
@@ -177,7 +169,6 @@
'doctype': 'DocField',
'fieldname': 'phone',
'fieldtype': 'Data',
- 'idx': 10,
'label': 'Phone',
'permlevel': 0,
'reqd': 1
@@ -188,7 +179,6 @@
'doctype': 'DocField',
'fieldname': 'email_id',
'fieldtype': 'Data',
- 'idx': 11,
'label': 'Email Id',
'permlevel': 0
},
@@ -198,7 +188,7 @@
'doctype': 'DocField',
'fieldname': 'fax',
'fieldtype': 'Data',
- 'idx': 12,
+ 'in_filter': 1,
'label': 'Fax',
'permlevel': 0
},
@@ -210,12 +200,9 @@
'doctype': 'DocField',
'fieldname': 'customer',
'fieldtype': 'Link',
- 'idx': 13,
'label': 'Customer',
'options': 'Customer',
- 'permlevel': 0,
- 'search_index': 1,
- 'trigger': 'Client'
+ 'permlevel': 0
},
# DocField
@@ -225,7 +212,7 @@
'doctype': 'DocField',
'fieldname': 'customer_name',
'fieldtype': 'Data',
- 'idx': 14,
+ 'in_filter': 1,
'label': 'Customer Name',
'permlevel': 1
},
@@ -237,12 +224,9 @@
'doctype': 'DocField',
'fieldname': 'supplier',
'fieldtype': 'Link',
- 'idx': 15,
'label': 'Supplier',
'options': 'Supplier',
- 'permlevel': 0,
- 'search_index': 1,
- 'trigger': 'Client'
+ 'permlevel': 0
},
# DocField
@@ -252,9 +236,10 @@
'doctype': 'DocField',
'fieldname': 'supplier_name',
'fieldtype': 'Data',
- 'idx': 16,
+ 'in_filter': 1,
'label': 'Supplier Name',
- 'permlevel': 1
+ 'permlevel': 1,
+ 'search_index': 0
},
# DocField
@@ -264,7 +249,6 @@
'doctype': 'DocField',
'fieldname': 'sales_partner',
'fieldtype': 'Link',
- 'idx': 17,
'label': 'Sales Partner',
'options': 'Sales Partner',
'permlevel': 0
@@ -278,7 +262,6 @@
'doctype': 'DocField',
'fieldname': 'is_primary_address',
'fieldtype': 'Check',
- 'idx': 18,
'label': 'Is Primary Address',
'permlevel': 0
},
@@ -291,7 +274,6 @@
'doctype': 'DocField',
'fieldname': 'is_shipping_address',
'fieldtype': 'Check',
- 'idx': 19,
'label': 'Is Shipping Address',
'permlevel': 0
},
@@ -301,7 +283,6 @@
'doctype': 'DocField',
'fieldname': 'trash_reason',
'fieldtype': 'Small Text',
- 'idx': 20,
'label': 'Trash Reason',
'permlevel': 0
}
diff --git a/index.html b/index.html
index c28b0aa..db7c228 100644
--- a/index.html
+++ b/index.html
@@ -3,7 +3,7 @@
<meta charset="utf-8">
<title>ERPNext</title>
<meta name="author" content="">
- <script type="text/javascript">window._version_number="325"
+ <script type="text/javascript">window._version_number="337"
wn={}
wn.provide=function(namespace){var nsl=namespace.split('.');var l=nsl.length;var parent=window;for(var i=0;i<l;i++){var n=nsl[i];if(!parent[n]){parent[n]={}}
@@ -79,4 +79,4 @@
</div>
<script>wn.require('js/app.js');</script>
<div id="dialog_back"></div>
-</body>
+</body>
\ No newline at end of file
diff --git a/versions-master.db b/versions-master.db
index 5707243..0c1c75c 100644
--- a/versions-master.db
+++ b/versions-master.db
Binary files differ