Merge branch 'dev' of github.com:webnotes/erpnext into dev

This commit is contained in:
Rushabh Mehta 2012-07-12 18:01:31 +05:30
commit 8cbbab2e75
16 changed files with 526 additions and 428 deletions

View File

@ -204,9 +204,6 @@ class DocType:
if sql("select name from `tabFiscal Year` where year_start_date < %s", self.doc.year_start_date) and not self.doc.past_year:
msgprint("Please enter Past Year", raise_exception=1)
if not self.doc.is_fiscal_year_closed:
self.doc.is_fiscal_year_closed = 'No'
# on update
def on_update(self):

View File

@ -40,18 +40,12 @@ class DocType(TransactionBase):
self.fname = 'entries'
# Autoname
# ---------
def autoname(self):
self.doc.name = make_autoname(self.doc.naming_series+ '.#####')
# ********************************* Trigger Functions ******************************
#Set retail related fields from pos settings
#-------------------------------------------------------------------------
def set_pos_fields(self):
"""Set retail related fields from pos settings"""
pos = webnotes.conn.sql("select * from `tabPOS Setting` where ifnull(user,'') = '%s' and company = '%s'" % (session['user'], self.doc.company), as_dict=1)
if not pos:
pos = webnotes.conn.sql("select * from `tabPOS Setting` where ifnull(user,'') = '' and company = '%s'" % (self.doc.company), as_dict=1)
@ -79,9 +73,8 @@ class DocType(TransactionBase):
if self.doc.charge: self.get_other_charges()
# Set default values related to pos for previously created sales invoice.
# --------------------------------------------------------------------------
def set_pos_item_values(self):
"""Set default values related to pos for previously created sales invoice."""
if cint(self.doc.is_pos) ==1:
dtl = webnotes.conn.sql("select income_account, warehouse, cost_center from `tabPOS Setting` where ifnull(user,'') = '%s' and company = '%s'" % (session['user'], self.doc.company), as_dict=1)
if not dtl:
@ -94,10 +87,8 @@ class DocType(TransactionBase):
d.warehouse = item and item[0]['default_warehouse'] or dtl and dtl[0]['warehouse'] or d.warehouse
# Get Account Head to which amount needs to be Debited based on Customer
# ----------------------------------------------------------------------
def get_customer_account(self):
"""Get Account Head to which amount needs to be Debited based on Customer"""
if not self.doc.company:
msgprint("Please select company first and re-select the customer after doing so", raise_exception=1)
@ -115,10 +106,8 @@ class DocType(TransactionBase):
return acc_head and {'debit_to' : acc_head} or {}
# Set Due Date = Posting Date + Credit Days
# -----------------------------------------
def get_cust_and_due_date(self):
"""Set Due Date = Posting Date + Credit Days"""
credit_days = 0
if self.doc.debit_to:
credit_days = webnotes.conn.sql("select credit_days from `tabAccount` where name='%s' and docstatus != 2" % self.doc.debit_to)
@ -134,9 +123,8 @@ class DocType(TransactionBase):
self.doc.customer = webnotes.conn.get_value('Account',self.doc.debit_to,'master_name')
# Pull Details of Delivery Note or Sales Order Selected
# ------------------------------------------------------
def pull_details(self):
"""Pull Details of Delivery Note or Sales Order Selected"""
# Delivery Note
if self.doc.delivery_note_main:
self.validate_prev_docname('delivery note')
@ -153,14 +141,14 @@ class DocType(TransactionBase):
ret = self.get_debit_to()
self.doc.debit_to = ret.get('debit_to')
# onload pull income account
# --------------------------
def load_default_accounts(self):
"""
Loads default accounts from items, customer when called from mapper
"""
self.get_income_account('entries')
def get_income_account(self,doctype):
for d in getlist(self.doclist, doctype):
if d.item_code:
@ -168,8 +156,7 @@ class DocType(TransactionBase):
d.income_account = item and item[0]['default_income_account'] or ''
d.cost_center = item and item[0]['default_sales_cost_center'] or ''
# Item Details
# -------------
def get_item_details(self, args=None):
import json
args = args and json.loads(args) or {}
@ -215,61 +202,49 @@ class DocType(TransactionBase):
return get_obj('Sales Common').get_barcode_details(barcode)
# Fetch ref rate from item master as per selected price list
def get_adj_percent(self, arg=''):
"""Fetch ref rate from item master as per selected price list"""
get_obj('Sales Common').get_adj_percent(self)
# Get tax rate if account type is tax
# ------------------------------------
def get_rate(self,arg):
"""Get tax rate if account type is tax"""
get_obj('Sales Common').get_rate(arg)
# Get Commission rate of Sales Partner
# -------------------------------------
def get_comm_rate(self, sales_partner):
"""Get Commission rate of Sales Partner"""
return get_obj('Sales Common').get_comm_rate(sales_partner, self)
# GET TERMS & CONDITIONS
# -------------------------------------
def get_tc_details(self):
return get_obj('Sales Common').get_tc_details(self)
# Load Default Charges
# ----------------------------------------------------------
def load_default_taxes(self):
self.doclist = get_obj('Sales Common').load_default_taxes(self)
# Get Sales Taxes and Charges Master Details
# --------------------------
def get_other_charges(self):
self.doclist = get_obj('Sales Common').get_other_charges(self)
# Get Advances
# -------------
def get_advances(self):
self.doclist = get_obj('GL Control').get_advances(self, self.doc.debit_to, 'Sales Invoice Advance', 'advance_adjustment_details', 'credit')
#pull project customer
#-------------------------
def pull_project_customer(self):
res = webnotes.conn.sql("select customer from `tabProject` where name = '%s'"%self.doc.project_name)
if res:
get_obj('DocType Mapper', 'Project-Sales Invoice').dt_map('Project', 'Sales Invoice', self.doc.project_name, self.doc, self.doclist, "[['Project', 'Sales Invoice']]")
# ********************************** Server Utility Functions ******************************
# Get Company Abbr.
# ------------------
def get_company_abbr(self):
return webnotes.conn.sql("select abbr from tabCompany where name=%s", self.doc.company)[0][0]
# Check whether sales order / delivery note items already pulled
#----------------------------------------------------------------
def validate_prev_docname(self,doctype):
"""Check whether sales order / delivery note items already pulled"""
for d in getlist(self.doclist, 'entries'):
if doctype == 'delivery note' and self.doc.delivery_note_main == d.delivery_note:
msgprint(cstr(self.doc.delivery_note_main) + " delivery note details have already been pulled.")
@ -279,7 +254,6 @@ class DocType(TransactionBase):
raise Exception , "Validation Error. Sales order details have already been pulled."
#-----------------------------------------------------------------
def update_against_document_in_jv(self):
"""
Links invoice and advance voucher:
@ -308,11 +282,8 @@ class DocType(TransactionBase):
get_obj('GL Control').reconcile_against_document(lst)
# ------------------------------------------------------------------------
def validate_customer(self):
"""
Validate customer name with SO and DN
"""
""" Validate customer name with SO and DN"""
for d in getlist(self.doclist,'entries'):
dt = d.delivery_note and 'Delivery Note' or d.sales_order and 'Sales Order' or ''
if dt:
@ -322,9 +293,8 @@ class DocType(TransactionBase):
msgprint("Customer %s does not match with customer of %s: %s." %(self.doc.customer, dt, dt_no), raise_exception=1)
# Validates Debit To Account and Customer Matches
# ------------------------------------------------
def validate_debit_to_acc(self):
def validate_customer_account(self):
"""Validates Debit To Account and Customer Matches"""
if self.doc.customer and self.doc.debit_to and not cint(self.doc.is_pos):
acc_head = webnotes.conn.sql("select master_name from `tabAccount` where name = %s and docstatus != 2", self.doc.debit_to)
@ -334,11 +304,6 @@ class DocType(TransactionBase):
and Master Name in account master." %(self.doc.debit_to, self.doc.customer,self.doc.company), raise_exception=1)
# Validate Debit To Account
# 1. Account Exists
# 2. Is a Debit Account
# 3. Is a PL Account
# ---------------------------
def validate_debit_acc(self):
acc = webnotes.conn.sql("select debit_or_credit, is_pl_account from tabAccount where name = '%s' and docstatus != 2" % self.doc.debit_to)
if not acc:
@ -352,9 +317,8 @@ class DocType(TransactionBase):
raise Exception
# Validate Fixed Asset Account and whether Income Account Entered Exists
# -----------------------------------------------------------------------
def validate_fixed_asset_account(self):
"""Validate Fixed Asset Account and whether Income Account Entered Exists"""
for d in getlist(self.doclist,'entries'):
item = webnotes.conn.sql("select name,is_asset_item,is_sales_item 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)
acc = webnotes.conn.sql("select account_type from `tabAccount` where name = '%s' and docstatus != 2" % d.income_account)
@ -366,22 +330,16 @@ class DocType(TransactionBase):
raise Exception
# Set totals in words
#--------------------
def set_in_words(self):
dcc = TransactionBase().get_company_currency(self.doc.company)
self.doc.in_words = get_obj('Sales Common').get_total_in_words(dcc, self.doc.rounded_total)
self.doc.in_words_export = get_obj('Sales Common').get_total_in_words(self.doc.currency, self.doc.rounded_total_export)
# Clear Advances
# --------------
def clear_advances(self):
get_obj('GL Control').clear_advances(self, 'Sales Invoice Advance','advance_adjustment_details')
# set aging date
#-------------------
def set_aging_date(self):
if self.doc.is_opening != 'Yes':
self.doc.aging_date = self.doc.posting_date
@ -390,20 +348,21 @@ class DocType(TransactionBase):
raise Exception
# Set against account for debit to account
#------------------------------------------
def set_against_income_account(self):
"""Set against account for debit to account"""
against_acc = []
for d in getlist(self.doclist, 'entries'):
if d.income_account not in against_acc:
against_acc.append(d.income_account)
self.doc.against_income_account = ','.join(against_acc)
def add_remarks(self):
if not self.doc.remarks: self.doc.remarks = 'No Remarks'
#check in manage account if sales order / delivery note required or not.
def so_dn_required(self):
"""check in manage account if sales order / delivery note required or not."""
dict = {'Sales Order':'so_required','Delivery Note':'dn_required'}
for i in dict:
res = webnotes.conn.sql("select value from `tabSingles` where doctype = 'Global Defaults' and field = '%s'"%dict[i])
@ -413,9 +372,9 @@ class DocType(TransactionBase):
msgprint("%s No. required against item %s"%(i,d.item_code))
raise Exception
#check for does customer belong to same project as entered..
#-------------------------------------------------------------------------------------------------
def validate_proj_cust(self):
"""check for does customer belong to same project as entered.."""
if self.doc.project_name and self.doc.customer:
res = webnotes.conn.sql("select name from `tabProject` where name = '%s' and (customer = '%s' or ifnull(customer,'')='')"%(self.doc.project_name, self.doc.customer))
if not res:
@ -431,20 +390,13 @@ class DocType(TransactionBase):
raise Exception
# ********* UPDATE CURRENT STOCK *****************************
def update_current_stock(self):
for d in getlist(self.doclist, 'entries'):
bin = webnotes.conn.sql("select actual_qty from `tabBin` where item_code = %s and warehouse = %s", (d.item_code, d.warehouse), as_dict = 1)
d.actual_qty = bin and flt(bin[0]['actual_qty']) or 0
def validate_item_code(self):
for d in getlist(self.doclist, 'entries'):
if not d.item_code:
msgprint("Please enter Item Code at line no : %s to update stock for POS or remove check from Update Stock in Basic Info Tab." % (d.idx))
raise Exception
# Validate Write Off Account
# -------------------------------
def validate_write_off_account(self):
if flt(self.doc.write_off_amount) and not self.doc.write_off_account:
msgprint("Please enter Write Off Account", raise_exception=1)
@ -457,12 +409,22 @@ class DocType(TransactionBase):
and parent = %s""", (self.doc.amended_from, self.doc.c_form_no))
webnotes.conn.set(self.doc, 'c_form_no', '')
def update_current_stock(self):
for d in getlist(self.doclist, 'entries'):
if d.item_code and d.warehouse:
bin = webnotes.conn.sql("select actual_qty from `tabBin` where item_code = %s and warehouse = %s", (d.item_code, d.warehouse), as_dict = 1)
d.actual_qty = bin and flt(bin[0]['actual_qty']) or 0
for d in getlist(self.doclist, 'packing_details'):
bin = sql("select actual_qty, projected_qty from `tabBin` where item_code = %s and warehouse = %s", (d.item_code, d.warehouse), as_dict = 1)
d.actual_qty = bin and flt(bin[0]['actual_qty']) or 0
d.projected_qty = bin and flt(bin[0]['projected_qty']) or 0
# VALIDATE
# ====================================================================================
def validate(self):
self.so_dn_required()
#self.dn_required()
self.validate_proj_cust()
sales_com_obj = get_obj('Sales Common')
sales_com_obj.check_stop_sales_order(self)
@ -472,7 +434,7 @@ class DocType(TransactionBase):
sales_com_obj.get_allocated_sum(self) # this is to verify that the allocated % of sales persons is 100%
sales_com_obj.validate_fiscal_year(self.doc.fiscal_year,self.doc.posting_date,'Posting Date')
self.validate_customer()
self.validate_debit_to_acc()
self.validate_customer_account()
self.validate_debit_acc()
self.validate_fixed_asset_account()
self.add_remarks()
@ -480,7 +442,9 @@ class DocType(TransactionBase):
self.validate_pos()
self.validate_write_off_account()
if cint(self.doc.update_stock):
get_obj('Stock Ledger').validate_serial_no(self, 'entries')
sl = get_obj('Stock Ledger')
sl.validate_serial_no(self, 'entries')
sl.validate_serial_no(self, 'packing_details')
self.validate_item_code()
self.update_current_stock()
self.set_in_words()
@ -488,14 +452,62 @@ class DocType(TransactionBase):
self.doc.is_opening = 'No'
self.set_aging_date()
self.clear_advances()
# Set against account
self.set_against_income_account()
self.validate_c_form()
def get_warehouse(self):
w = webnotes.conn.sql("select warehouse from `tabPOS Setting` where ifnull(user,'') = '%s' and company = '%s'" % (session['user'], self.doc.company))
w = w and w[0][0] or ''
if not w:
ps = webnotes.conn.sql("select name, warehouse from `tabPOS Setting` where ifnull(user,'') = '' and company = '%s'" % self.doc.company)
if not ps:
msgprint("To make POS entry, please create POS Setting from Accounts --> POS Setting page and refresh the system.")
raise Exception
elif not ps[0][1]:
msgprint("Please enter warehouse in POS Setting")
else:
w = ps[0][1]
return w
def make_packing_list(self):
get_obj('Sales Common').make_packing_list(self,'entries')
sl = get_obj('Stock Ledger')
sl.scrub_serial_nos(self)
sl.scrub_serial_nos(self, 'packing_details')
def on_update(self):
# Set default warehouse from pos setting
if cint(self.doc.is_pos) == 1:
if cint(self.doc.update_stock) == 1:
w = self.get_warehouse()
if w:
for d in getlist(self.doclist, 'entries'):
if not d.warehouse:
d.warehouse = cstr(w)
self.make_packing_list()
else:
self.doclist = self.doc.clear_table(self.doclist, 'packing_details')
if flt(self.doc.paid_amount) == 0:
if self.doc.cash_bank_account:
webnotes.conn.set(self.doc, 'paid_amount',
(flt(self.doc.grand_total) - flt(self.doc.write_off_amount)))
else:
# show message that the amount is not paid
webnotes.conn.set(self.doc,'paid_amount',0)
webnotes.msgprint("Note: Payment Entry will not be created since 'Cash/Bank Account' was not specified.")
else:
self.doclist = self.doc.clear_table(self.doclist, 'packing_details')
webnotes.conn.set(self.doc,'paid_amount',0)
webnotes.conn.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))
# *************************************************** ON SUBMIT **********************************************
# Check Ref Document's docstatus
# -------------------------------
def check_prev_docstatus(self):
for d in getlist(self.doclist,'entries'):
if d.sales_order:
@ -511,56 +523,45 @@ class DocType(TransactionBase):
raise Exception , "Validation Error."
#Set Actual Qty based on item code and warehouse
#------------------------------------------------------
def set_actual_qty(self):
for d in getlist(self.doclist, 'entries'):
if d.item_code and d.warehouse:
actual_qty = webnotes.conn.sql("select actual_qty from `tabBin` where item_code = '%s' and warehouse = '%s'" % (d.item_code, d.warehouse))
d.actual_qty = actual_qty and flt(actual_qty[0][0]) or 0
# ********************** Make Stock Entry ************************************
def make_sl_entry(self, d, wh, qty, in_value, update_stock):
st_uom = webnotes.conn.sql("select stock_uom from `tabItem` where name = '%s'"%d.item_code)
st_uom = webnotes.conn.sql("select stock_uom from `tabItem` where name = '%s'"%d['item_code'])
self.values.append({
'item_code' : d.item_code,
'item_code' : d['item_code'],
'warehouse' : wh,
'transaction_date' : getdate(self.doc.modified).strftime('%Y-%m-%d'),
'posting_date' : self.doc.posting_date,
'posting_time' : self.doc.posting_time,
'voucher_type' : 'Sales Invoice',
'voucher_no' : cstr(self.doc.name),
'voucher_detail_no' : cstr(d.name),
'voucher_detail_no' : cstr(d['name']),
'actual_qty' : qty,
'stock_uom' : st_uom and st_uom[0][0] or '',
'incoming_rate' : in_value,
'company' : self.doc.company,
'fiscal_year' : self.doc.fiscal_year,
'is_cancelled' : (update_stock==1) and 'No' or 'Yes',
'batch_no' : cstr(d.batch_no),
'serial_no' : d.serial_no
})
'batch_no' : cstr(d['batch_no']),
'serial_no' : d['serial_no']
})
# UPDATE STOCK LEDGER
# ---------------------------------------------------------------------------
def update_stock_ledger(self, update_stock, clear = 0):
def update_stock_ledger(self, update_stock):
self.values = []
for d in getlist(self.doclist, 'entries'):
stock_item = webnotes.conn.sql("SELECT is_stock_item, is_sample_item FROM tabItem where name = '%s'"%(d.item_code), as_dict = 1) # stock ledger will be updated only if it is a stock item
items = get_obj('Sales Common').get_item_list(self)
for d in items:
stock_item = webnotes.conn.sql("SELECT is_stock_item, is_sample_item \
FROM tabItem where name = '%s'"%(d['item_code']), as_dict = 1)
if stock_item[0]['is_stock_item'] == "Yes":
if not d['warehouse']:
msgprint("Message: Please enter Warehouse for item %s as it is stock item." \
% d['item_code'], raise_exception=1)
# Reduce actual qty from warehouse
self.make_sl_entry( d, d.warehouse, - flt(d.qty) , 0, update_stock)
get_obj('Stock Ledger', 'Stock Ledger').update_stock(self.values, self.doc.amended_from and 'Yes' or 'No')
#-------------------POS Stock Updatation Part----------------------------------------------
def pos_update_stock(self):
self.update_stock_ledger(update_stock = 1)
self.make_sl_entry( d, d['warehouse'], - flt(d['qty']) , 0, update_stock)
get_obj('Stock Ledger', 'Stock Ledger').update_stock(self.values)
# ********** Get Actual Qty of item in warehouse selected *************
def get_actual_qty(self,args):
args = eval(args)
actual_qty = webnotes.conn.sql("select actual_qty from `tabBin` where item_code = '%s' and warehouse = '%s'" % (args['item_code'], args['warehouse']), as_dict=1)
@ -569,23 +570,39 @@ class DocType(TransactionBase):
}
return ret
# Make GL Entries
# -------------------------
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)
# On Submit
# ---------
def update_c_form(self):
"""Update amended id in C-form"""
if self.doc.c_form_no and self.doc.amended_from:
webnotes.conn.sql("""update `tabC-Form Invoice Detail` set invoice_no = %s,
invoice_date = %s, territory = %s, net_total = %s,
grand_total = %s where invoice_no = %s and parent = %s""", (self.doc.name, self.doc.amended_from, self.doc.c_form_no))
def check_next_docstatus(self):
submit_jv = webnotes.conn.sql("select t1.name from `tabJournal Voucher` t1,`tabJournal Voucher Detail` t2 where t1.name = t2.parent and t2.against_invoice = '%s' and t1.docstatus = 1" % (self.doc.name))
if submit_jv:
msgprint("Journal Voucher : " + cstr(submit_jv[0][0]) + " has been created against " + cstr(self.doc.doctype) + ". So " + cstr(self.doc.doctype) + " cannot be Cancelled.")
raise Exception, "Validation Error."
def on_submit(self):
if cint(self.doc.is_pos) == 1:
if cint(self.doc.update_stock) == 1:
sl_obj = get_obj("Stock Ledger")
sl_obj.validate_serial_no_warehouse(self, 'entries')
sl_obj.validate_serial_no_warehouse(self, 'packing_details')
sl_obj.update_serial_record(self, 'entries', is_submit = 1, is_incoming = 0)
self.pos_update_stock()
sl_obj.update_serial_record(self, 'packing_details', is_submit = 1, is_incoming = 0)
self.update_stock_ledger(update_stock=1)
else:
self.check_prev_docstatus()
get_obj("Sales Common").update_prevdoc_detail(1,self)
@ -603,31 +620,13 @@ class DocType(TransactionBase):
self.update_c_form()
def update_c_form(self):
"""Update amended id in C-form"""
if self.doc.c_form_no and self.doc.amended_from:
webnotes.conn.sql("""update `tabC-Form Invoice Detail` set invoice_no = %s,
invoice_date = %s, territory = %s, net_total = %s,
grand_total = %s where invoice_no = %s and parent = %s""", (self.doc.name, self.doc.amended_from, self.doc.c_form_no))
# *************************************************** ON CANCEL **********************************************
# Check Next Document's docstatus
# --------------------------------
def check_next_docstatus(self):
submit_jv = webnotes.conn.sql("select t1.name from `tabJournal Voucher` t1,`tabJournal Voucher Detail` t2 where t1.name = t2.parent and t2.against_invoice = '%s' and t1.docstatus = 1" % (self.doc.name))
if submit_jv:
msgprint("Journal Voucher : " + cstr(submit_jv[0][0]) + " has been created against " + cstr(self.doc.doctype) + ". So " + cstr(self.doc.doctype) + " cannot be Cancelled.")
raise Exception, "Validation Error."
# On Cancel
# ----------
def on_cancel(self):
if cint(self.doc.is_pos) == 1:
if cint(self.doc.update_stock) == 1:
get_obj('Stock Ledger').update_serial_record(self, 'entries', is_submit = 0, is_incoming = 0)
sl = get_obj('Stock Ledger')
sl.update_serial_record(self, 'entries', is_submit = 0, is_incoming = 0)
sl.update_serial_record(self, 'packing_details', is_submit = 0, is_incoming = 0)
self.update_stock_ledger(update_stock = -1)
else:
sales_com_obj = get_obj(dt = 'Sales Common')
@ -636,51 +635,6 @@ class DocType(TransactionBase):
sales_com_obj.update_prevdoc_detail(0,self)
self.make_gl_entries(is_cancel=1)
# Get Warehouse
def get_warehouse(self):
w = webnotes.conn.sql("select warehouse from `tabPOS Setting` where ifnull(user,'') = '%s' and company = '%s'" % (session['user'], self.doc.company))
w = w and w[0][0] or ''
if not w:
ps = webnotes.conn.sql("select name, warehouse from `tabPOS Setting` where ifnull(user,'') = '' and company = '%s'" % self.doc.company)
if not ps:
msgprint("To make POS entry, please create POS Setting from Setup --> Accounts --> POS Setting and refresh the system.")
raise Exception
elif not ps[0][1]:
msgprint("Please enter warehouse in POS Setting")
else:
w = ps[0][1]
return w
# on update
def on_update(self):
# Set default warehouse from pos setting
#----------------------------------------
if cint(self.doc.is_pos) == 1:
self.set_actual_qty()
w = self.get_warehouse()
if w:
for d in getlist(self.doclist, 'entries'):
if not d.warehouse:
d.warehouse = cstr(w)
if flt(self.doc.paid_amount) == 0:
if self.doc.cash_bank_account:
webnotes.conn.set(self.doc, 'paid_amount',
(flt(self.doc.grand_total) - flt(self.doc.write_off_amount)))
else:
# show message that the amount is not paid
webnotes.conn.set(self.doc,'paid_amount',0)
webnotes.msgprint("Note: Payment Entry not created since 'Cash/Bank Account' was not specified.")
else:
webnotes.conn.set(self.doc,'paid_amount',0)
webnotes.conn.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))
#-------------------------------------------------------------------------------------
def on_update_after_submit(self):
self.convert_into_recurring()
def convert_into_recurring(self):
@ -717,3 +671,7 @@ class DocType(TransactionBase):
next_date = next_date.strftime("%Y-%m-%d")
webnotes.conn.set(self.doc, 'next_date', next_date)
def on_update_after_submit(self):
self.convert_into_recurring()

View File

@ -3,9 +3,9 @@
# These values are common in all dictionaries
{
'creation': '2012-06-11 12:09:54',
'creation': '2012-07-05 11:04:09',
'docstatus': 0,
'modified': '2012-06-17 21:37:40',
'modified': '2012-07-11 12:19:49',
'modified_by': u'Administrator',
'owner': u'Administrator'
},
@ -350,6 +350,16 @@
'permlevel': 0
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'sales_bom_help',
'fieldtype': u'HTML',
'label': u'Sales BOM Help',
'permlevel': 0,
'print_hide': 1
},
# DocField
{
'doctype': u'DocField',
@ -1343,6 +1353,27 @@
'print_hide': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'packing_list',
'fieldtype': u'Section Break',
'label': u'Packing List',
'permlevel': 0,
'print_hide': 1
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'packing_details',
'fieldtype': u'Table',
'label': u'Packing Details',
'options': u'Delivery Note Packing Item',
'permlevel': 0,
'print_hide': 1
},
# DocField
{
'doctype': u'DocField',

View File

@ -24,7 +24,6 @@ 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
sql = webnotes.conn.sql
get_value = webnotes.conn.get_value
in_transaction = webnotes.conn.in_transaction
@ -46,14 +45,14 @@ class DocType:
"""
cond = self.get_filter_condition()
cond += self.get_joining_releiving_condition()
emp_list = sql("""
select t1.name
from `tabEmployee` t1, `tabSalary Structure` t2
where t1.docstatus!=2 and t2.docstatus != 2
and ifnull(t1.status, 'Left') = 'Active' and ifnull(t2.is_active, 'No') = 'Yes'
and t1.name = t2.employee
%s """% cond)
%s """% cond, debug=1)
return emp_list
@ -64,9 +63,19 @@ class DocType:
cond = ''
for f in ['company', 'branch', 'department', 'designation', 'grade']:
if self.doc.fields.get(f):
cond += " and t1." + f + " = '" + self.doc.fields.get(f) + "'"
cond += " and t1." + f + " = '" + self.doc.fields.get(f) + "'"
return cond
def get_joining_releiving_condition(self):
m = self.get_month_details(self.doc.fiscal_year, self.doc.month)
cond = """
and ifnull(t1.date_of_joining, '0000-00-00') <= '%(month_end_date)s'
and ifnull(t1.relieving_date, '2199-12-31') >= '%(month_start_date)s'
""" % m
return cond
def check_mandatory(self):
@ -74,6 +83,26 @@ class DocType:
if not self.doc.fields[f]:
msgprint("Please select %s to proceed" % f, raise_exception=1)
def get_month_details(self, year, month):
ysd = sql("select year_start_date from `tabFiscal Year` where name ='%s'"%year)[0][0]
if ysd:
from dateutil.relativedelta import relativedelta
import calendar, datetime
diff_mnt = cint(month)-cint(ysd.month)
if diff_mnt<0:
diff_mnt = 12-int(ysd.month)+cint(month)
msd = ysd + relativedelta(months=diff_mnt) # month start date
month_days = cint(calendar.monthrange(cint(msd.year) ,cint(month))[1]) # days in month
med = datetime.date(msd.year, cint(month), month_days) # month end date
return {
'year': msd.year,
'month_start_date': msd,
'month_end_date': med,
'month_days': month_days
}
def create_sal_slip(self):
"""
@ -82,12 +111,7 @@ class DocType:
"""
emp_list = self.get_emp_list()
log = ""
if emp_list:
log = "<table><tr><td colspan = 2>Following Salary Slip has been created: </td></tr><tr><td><u>SAL SLIP ID</u></td><td><u>EMPLOYEE NAME</u></td></tr>"
else:
log = "<table><tr><td colspan = 2>No employee found for the above selected criteria</td></tr>"
ss_list = []
for emp in emp_list:
if not sql("""select name from `tabSalary Slip`
where docstatus!= 2 and employee = %s and month = %s and fiscal_year = %s and company = %s
@ -111,9 +135,18 @@ class DocType:
for d in getlist(ss_obj.doclist, 'deduction_details'):
d.save()
log += '<tr><td>' + ss.name + '</td><td>' + ss_obj.doc.employee_name + '</td></tr>'
log += '</table>'
return log
ss_list.append(ss.name)
return self.create_log(ss_list)
def create_log(self, ss_list):
log = "<b>No employee for the above selected criteria OR salary slip already created</b>"
if ss_list:
log = "<b>Created Salary Slip has been created: </b>\
<br><br>%s" % '<br>'.join(ss_list)
return log
def get_sal_slip_list(self):
"""
@ -132,28 +165,49 @@ class DocType:
"""
Submit all salary slips based on selected criteria
"""
ss_list = self.get_sal_slip_list()
log = ""
if ss_list:
log = """<table>
<tr>
<td colspan = 2>Following Salary Slip has been submitted: </td>
</tr>
<tr>
<td><u>SAL SLIP ID</u></td>
<td><u>EMPLOYEE NAME</u></td>
</tr>
"""
else:
log = "<table><tr><td colspan = 2>No salary slip found to submit for the above selected criteria</td></tr>"
ss_list = self.get_sal_slip_list()
not_submitted_ss = []
for ss in ss_list:
ss_obj = get_obj("Salary Slip",ss[0],with_children=1)
set(ss_obj.doc, 'docstatus', 1)
ss_obj.on_submit()
try:
webnotes.conn.set(ss_obj.doc, 'email_check', cint(self.doc.send_mail))
if cint(self.doc.send_email) == 1:
ss_obj.send_mail_funct()
webnotes.conn.set(ss_obj.doc, 'docstatus', 1)
except Exception,e:
not_submitted_ss.append(ss[0])
msgprint(e)
continue
return self.create_submit_log(ss_list, not_submitted_ss)
def create_submit_log(self, all_ss, not_submitted_ss):
log = ''
if not all_ss:
log = "No salary slip found to submit for the above selected criteria"
else:
all_ss = [d[0] for d in all_ss]
log += '<tr><td>' + ss[0] + '</td><td>' + ss_obj.doc.employee_name + '</td></tr>'
log += '</table>'
submitted_ss = list(set(all_ss) - set(not_submitted_ss))
if submitted_ss:
mail_sent_msg = self.doc.send_email and " (Mail has been sent to the employee)" or ""
log = """
<b>Submitted Salary Slips%s:</b>\
<br><br> %s <br><br>
""" % (mail_sent_msg, '<br>'.join(submitted_ss))
if not_submitted_ss:
log += """
<b>Not Submitted Salary Slips: </b>\
<br><br> %s <br><br> \
Reason: <br>\
May be company email id specified in employee master is not valid. <br> \
Please mention correct email id in employee master or if you don't want to \
send mail, uncheck 'Send Email' checkbox. <br>\
Then try to submit Salary Slip again.
"""% ('<br>'.join(not_submitted_ss))
return log
@ -168,7 +222,7 @@ class DocType:
""" % (self.doc.month, self.doc.fiscal_year, cond))
return flt(tot[0][0])
def get_acc_details(self):
"""

View File

@ -45,9 +45,13 @@ cur_frm.cscript.month = cur_frm.cscript.employee = cur_frm.cscript.fiscal_year;
// Calculate total if lwp exists
// ------------------------------------------------------------------------
cur_frm.cscript.leave_without_pay = function(doc,dt,dn){
doc.payment_days = flt(doc.total_days_in_month) - flt(doc.leave_without_pay);
refresh_field('payment_days');
calculate_all(doc, dt, dn);
if (doc.employee && doc.fiscal_year && doc.month) {
$c_obj(make_doclist(doc.doctype,doc.name), 'get_leave_details',doc.leave_without_pay,function(r, rt) {
var doc = locals[dt][dn];
cur_frm.refresh();
calculate_all(doc, dt, dn);
});
}
}
// Calculate all

View File

@ -39,27 +39,22 @@ class DocType(TransactionBase):
self.doclist = doclist
# autoname
#=======================================================
def autoname(self):
self.doc.name = make_autoname('Sal Slip/' +self.doc.employee + '/.#####')
# Get employee details
#=======================================================
def get_emp_and_leave_details(self):
# Get payment days
if self.doc.fiscal_year and self.doc.month:
self.get_leave_details()
# check sal structure
def get_emp_and_leave_details(self):
if self.doc.employee:
# Get payment days
if self.doc.fiscal_year and self.doc.month:
self.get_leave_details()
# check sal structure
struct = self.check_sal_struct()
if struct:
self.pull_sal_struct(struct)
# Check sal structure
#=======================================================
def check_sal_struct(self):
struct = sql("select name from `tabSalary Structure` where employee ='%s' and is_active = 'Yes' "%self.doc.employee)
if not struct:
@ -67,8 +62,7 @@ class DocType(TransactionBase):
self.doc.employee = ''
return struct and struct[0][0] or ''
# Pull struct details
#=======================================================
def pull_sal_struct(self, struct):
self.doclist = self.doc.clear_table(self.doclist, 'earning_details')
self.doclist = self.doc.clear_table(self.doclist, 'deduction_details')
@ -81,41 +75,48 @@ class DocType(TransactionBase):
self.doc.esic_no = basic_info[0][2]
self.doc.pf_no = basic_info[0][3]
# Get leave details
#=======================================================
def get_leave_details(self):
m = self.get_month_details()
lwp = self.calculate_lwp(m)
self.doc.total_days_in_month = m[3]
def get_leave_details(self, lwp=None):
m = get_obj('Salary Manager').get_month_details(self.doc.fiscal_year, self.doc.month)
if not lwp:
lwp = self.calculate_lwp(m)
self.doc.total_days_in_month = m['month_days']
self.doc.leave_without_pay = lwp
self.doc.payment_days = flt(m[3]) - flt(lwp)
payment_days = flt(self.get_payment_days(m)) - flt(lwp)
self.doc.payment_days = payment_days > 0 and payment_days or 0
def get_payment_days(self, m):
payment_days = m['month_days']
emp = webnotes.conn.sql("select date_of_joining, relieving_date from `tabEmployee` \
where name = %s", self.doc.employee, as_dict=1)[0]
if emp['relieving_date']:
if getdate(emp['relieving_date']) > m['month_start_date'] and getdate(emp['relieving_date']) < m['month_end_date']:
payment_days = getdate(emp['relieving_date']).day
elif getdate(emp['relieving_date']) < m['month_start_date']:
payment_days = 0
if emp['date_of_joining']:
if getdate(emp['date_of_joining']) > m['month_start_date'] and getdate(emp['date_of_joining']) < m['month_end_date']:
payment_days = payment_days - getdate(emp['date_of_joining']).day + 1
elif getdate(emp['date_of_joining']) > m['month_end_date']:
payment_days = 0
return payment_days
# Get month details
#=======================================================
def get_month_details(self):
ysd = sql("select year_start_date from `tabFiscal Year` where name ='%s'"%self.doc.fiscal_year)[0][0]
if ysd:
from dateutil.relativedelta import relativedelta
import calendar, datetime
mnt = int(self.doc.month)
diff_mnt = int(mnt)-int(ysd.month)
if diff_mnt<0:
diff_mnt = 12-int(ysd.month)+int(mnt)
msd = ysd + relativedelta(months=diff_mnt) # month start date
month_days = cint(calendar.monthrange(cint(msd.year) ,cint(self.doc.month))[1]) # days in month
med = datetime.date(msd.year, cint(self.doc.month), month_days) # month end date
return msd.year, msd, med, month_days
# Calculate LWP
#=======================================================
def calculate_lwp(self, m):
holidays = sql("select t1.holiday_date from `tabHoliday` t1, tabEmployee t2 where t1.parent = t2.holiday_list and t2.name = '%s' and t1.holiday_date between '%s' and '%s'" % (self.doc.employee, m[1], m[2]))
holidays = sql("select t1.holiday_date from `tabHoliday` t1, tabEmployee t2 where t1.parent = t2.holiday_list and t2.name = '%s' and t1.holiday_date between '%s' and '%s'" % (self.doc.employee, m['month_start_date'], m['month_end_date']))
if not holidays:
holidays = sql("select t1.holiday_date from `tabHoliday` t1, `tabHoliday List` t2 where t1.parent = t2.name and ifnull(t2.is_default, 0) = 1 and t2.fiscal_year = '%s'" % self.doc.fiscal_year)
holidays = [cstr(i[0]) for i in holidays]
lwp = 0
for d in range(m[3]):
dt = add_days(cstr(m[1]), d)
for d in range(m['month_days']):
dt = add_days(cstr(m['month_start_date']), d)
if dt not in holidays:
leave = sql("""
select t1.name, t1.half_day
@ -130,8 +131,7 @@ class DocType(TransactionBase):
lwp = cint(leave[0][1]) and lwp + 0.5 or lwp + 1
return lwp
# Check existing
#=======================================================
def check_existing(self):
ret_exist = sql("select name from `tabSalary Slip` where month = '%s' and fiscal_year = '%s' and docstatus != 2 and employee = '%s' and name !='%s'" % (self.doc.month,self.doc.fiscal_year,self.doc.employee,self.doc.name))
if ret_exist:
@ -139,8 +139,7 @@ class DocType(TransactionBase):
self.doc.employee = ''
raise Exception
# Validate
#=======================================================
def validate(self):
self.check_existing()
dcc = TransactionBase().get_company_currency(self.doc.company)
@ -155,6 +154,8 @@ class DocType(TransactionBase):
for d in getlist(self.doclist, 'earning_details'):
if cint(d.e_depends_on_lwp) == 1:
d.e_modified_amount = round(flt(d.e_amount)*flt(self.doc.payment_days)/cint(self.doc.total_days_in_month), 2)
elif not self.doc.payment_days:
d.e_modified_amount = 0
self.doc.gross_pay += d.e_modified_amount
def calculate_ded_total(self):
@ -165,6 +166,9 @@ class DocType(TransactionBase):
for d in getlist(self.doclist, 'deduction_details'):
if cint(d.d_depends_on_lwp) == 1:
d.d_modified_amount = round(flt(d.d_amount)*flt(self.doc.payment_days)/cint(self.doc.total_days_in_month), 2)
elif not self.doc.payment_days:
d.d_modified_amount = 0
self.doc.total_deduction += d.d_modified_amount
def calculate_net_pay(self):
@ -176,17 +180,12 @@ class DocType(TransactionBase):
self.doc.net_pay = flt(self.doc.gross_pay) - flt(self.doc.total_deduction)
self.doc.rounded_total = round(self.doc.net_pay)
# ON SUBMIT
#=======================================================
def on_submit(self):
if(self.doc.email_check == 1):
self.send_mail_funct()
# Send mail
#=======================================================
def send_mail_funct(self):
from webnotes.utils.email_lib import sendmail
emailid_ret=sql("select company_email from `tabEmployee` where name = '%s'"%self.doc.employee)
@ -281,4 +280,4 @@ class DocType(TransactionBase):
</table></div>'''%(cstr(letter_head[0][0]),cstr(self.doc.employee), cstr(self.doc.employee_name), cstr(self.doc.month), cstr(self.doc.fiscal_year), cstr(self.doc.department), cstr(self.doc.branch), cstr(self.doc.designation), cstr(self.doc.grade), cstr(self.doc.bank_account_no), cstr(self.doc.bank_name), cstr(self.doc.arrear_amount), cstr(self.doc.payment_days), earn_table, ded_table, cstr(flt(self.doc.gross_pay)), cstr(flt(self.doc.total_deduction)), cstr(flt(self.doc.net_pay)), cstr(self.doc.total_in_words))
sendmail([receiver], subject=subj, msg = msg)
else:
msgprint("Company Email ID not found.")
msgprint("Company Email ID not found, hence mail not sent")

View File

@ -0,0 +1,47 @@
// render
wn.doclistviews['Salary Structure'] = wn.views.ListView.extend({
init: function(d) {
this._super(d)
this.fields = this.fields.concat([
"`tabSalary Structure`.employee_name",
"`tabSalary Structure`.designation",
"`tabSalary Structure`.branch",
"`tabSalary Structure`.net_pay",
"`tabSalary Structure`.from_date",
"`tabSalary Structure`.to_date",
"`tabSalary Structure`.company"
]);
this.stats = this.stats.concat(['company']);
},
prepare_data: function(data) {
this._super(data);
var concat_list = [];
data.designation && concat_list.push(data.designation);
data.branch && concat_list.push(data.branch);
data.description = concat_list.join(", ");
data.period = data.from_date + (data.to_date && ' to ' + data.to_date);
},
columns: [
{width: '2%', content: 'check'},
{width: '2%', content: 'docstatus'},
{width: '13%', content: 'name'},
{width: '18%', content: 'employee_name'},
{width: '24%', content: 'description+tags', css: {'color': '#aaa'}},
{width: '26%', content:'period', css: {'text-align': 'right', 'color':'#aaa'}},
{
width: '15%',
content: function(parent, data) {
$(parent).html(
(
data.company
? wn.boot.company[data.company].default_currency
: sys_defaults.currency
)
+ ' ' + fmt_money(data.net_pay));
},
css: {'text-align': 'right'},
},
]
});

View File

@ -106,7 +106,6 @@ class DocType:
return ret_item
def get_rm_rate(self, arg):
""" Get raw material rate as per selected method, if bom exists takes bom cost """
@ -293,7 +292,6 @@ class DocType:
self.validate_main_item()
self.validate_operations()
self.validate_materials()
self.validate_operations()
@ -353,8 +351,6 @@ class DocType:
})
# Get Current Flat BOM Items
# -----------------------------
def get_current_flat_bom_items(self):

View File

@ -127,10 +127,34 @@ cur_frm.cscript.dynamic_label = function(doc, cdt, cdn, base_curr, callback) {
cur_frm.cscript.base_currency = base_curr;
set_dynamic_label_par(doc, cdt, cdn, base_curr);
set_dynamic_label_child(doc, cdt, cdn, base_curr);
set_sales_bom_help(doc);
if (callback) callback(doc, cdt, cdn);
}
// Help for Sales BOM items
var set_sales_bom_help = function(doc) {
if (getchildren('Delivery Note Packing Item', doc.name, 'packing_details').length) {
$(cur_frm.fields_dict.packing_list.row.wrapper).toggle(true);
if (inList(['Delivery Note', 'Sales Invoice'], doc.doctype)) {
help_msg = "<div class='help-box'> \
For 'Sales BOM' items, warehouse, serial no and batch no \
will be considered from the 'Packing List' table. \
If warehouse and batch no are same for all packing items for any 'Sales BOM' item, \
those values can be entered in the main item table, values will be copied to 'Packing List' table. \
</div>";
get_field(doc.doctype, 'sales_bom_help', doc.name).options = help_msg;
}
} else {
$(cur_frm.fields_dict.packing_list.row.wrapper).toggle(false);
if (inList(['Delivery Note', 'Sales Invoice'], doc.doctype)) {
get_field(doc.doctype, 'sales_bom_help', doc.name).options = '';
}
}
refresh_field('sales_bom_help');
}
// hide / unhide price list currency based on availability of price list in customer's currency
//---------------------------------------------------------------------------------------------------

View File

@ -385,7 +385,7 @@ class DocType(TransactionBase):
return ret
def get_item_list(self, obj, is_stopped):
def get_item_list(self, obj, is_stopped=0):
"""get item list"""
il = []
for d in getlist(obj.doclist,obj.fname):
@ -394,7 +394,7 @@ class DocType(TransactionBase):
if is_stopped:
qty = flt(d.qty) > flt(d.delivered_qty) and flt(flt(d.qty) - flt(d.delivered_qty)) or 0
if d.prevdoc_doctype == 'Sales Order':
if d.prevdoc_doctype == 'Sales Order':
# used in delivery note to reduce reserved_qty
# Eg.: if SO qty is 10 and there is tolerance of 20%, then it will allow DN of 12.
# But in this case reserved qty should only be reduced by 10 and not 12.
@ -413,7 +413,7 @@ class DocType(TransactionBase):
if p.parent_detail_docname == d.name:
# the packing details table's qty is already multiplied with parent's qty
il.append({
'warehouse': d.warehouse,
'warehouse': p.warehouse,
'reserved_warehouse': reserved_wh,
'item_code': p.item_code,
'qty': flt(p.qty),
@ -496,23 +496,21 @@ class DocType(TransactionBase):
pi.qty = flt(qty)
pi.actual_qty = bin and flt(bin['actual_qty']) or 0
pi.projected_qty = bin and flt(bin['projected_qty']) or 0
pi.warehouse = warehouse
pi.prevdoc_doctype = line.prevdoc_doctype
if packing_item_code == line.item_code:
pi.serial_no = cstr(line.serial_no)
if not pi.warehouse:
pi.warehouse = warehouse
if not pi.batch_no:
pi.batch_no = cstr(line.batch_no)
pi.idx = self.packing_list_idx
# has to be saved, since this function is called on_update of delivery note
# saved, since this function is called on_update of delivery note
pi.save()
self.packing_list_idx += 1
# ------------------
# make packing list from sales bom if exists or directly copy item with balance
# ------------------
def make_packing_list(self, obj, fname):
"""make packing list for sales bom item"""
self.packing_list_idx = 0
parent_items = []
for d in getlist(obj.doclist, fname):
@ -520,10 +518,9 @@ class DocType(TransactionBase):
if self.has_sales_bom(d.item_code):
for i in self.get_sales_bom_items(d.item_code):
self.update_packing_list_item(obj, i['item_code'], flt(i['qty'])*flt(d.qty), warehouse, d)
else:
self.update_packing_list_item(obj, d.item_code, d.qty, warehouse, d)
if [d.item_code, d.name] not in parent_items:
parent_items.append([d.item_code, d.name])
if [d.item_code, d.name] not in parent_items:
parent_items.append([d.item_code, d.name])
self.cleanup_packing_list(obj, parent_items)

View File

@ -49,8 +49,7 @@ class DocType:
master_dict = {'Fiscal Year':{
'year': curr_fiscal_year,
'year_start_date': fy_start_date,
'company': args.get('company_name'),
'is_fiscal_year_closed': 'No'}}
'company': args.get('company_name')}}
self.create_records(master_dict)
# Company

View File

@ -138,7 +138,7 @@ $.extend(erpnext.complete_setup, {
'Dominican Republic', 'East Timor', 'Ecuador', 'Egypt', 'El Salvador',
'Equatorial Guinea', 'Eritrea', 'Estonia', 'Ethiopia', 'Federated States of Micronesia',
'Fiji', 'Finland', 'France', 'Gabon', 'Georgia', 'Germany', 'Ghana', 'Greece',
'Grenada', 'Guatemala', 'Guinea', 'Guinea-Bissau', 'Guyana', 'Haiti', 'Honduras',
'Grenada', 'Guatemala', 'Guinea', 'Guinea-Bissau', 'Guyana', 'Haiti', 'Honduras', 'Hong Kong'
'Hungary', 'Iceland', 'India', 'Indonesia', 'Iran', 'Iraq', 'Israel', 'Italy',
'Jamaica', 'Japan', 'Jordan', 'Kazakhstan', 'Kenya', 'Kingdom of the Netherlands',
'Kiribati', 'Kuwait', 'Kyrgyzstan', 'Laos', 'Latvia', 'Lebanon', 'Lesotho', 'Liberia',
@ -147,7 +147,7 @@ $.extend(erpnext.complete_setup, {
'Mexico', 'Moldova', 'Monaco', 'Mongolia', 'Montenegro', 'Morocco', 'Mozambique',
'Myanmar', 'Namibia', 'Nauru', 'Nepal', 'New Zealand', 'Nicaragua', 'Niger', 'Nigeria',
'North Korea', 'Norway', 'Oman', 'Pakistan', 'Palau', 'Panama', 'Papua New Guinea',
'Paraguay', "People's Republic of China", 'Peru', 'Philippines', 'Poland', 'Portugal',
'Paraguay', "China", 'Peru', 'Philippines', 'Poland', 'Portugal',
'Qatar', 'Republic of Ireland', 'Republic of the Congo', 'Romania', 'Russia', 'Rwanda',
'Saint Kitts and Nevis', 'Saint Lucia', 'Saint Vincent and the Grenadines', 'Samoa',
'San Marino', 'Saudi Arabia', 'Senegal', 'Serbia', 'Seychelles', 'Sierra Leone',
@ -252,6 +252,11 @@ $.extend(erpnext.complete_setup, {
'Cape Verde': ['Atlantic/Cape_Verde'],
'Central African Republic': ['Africa/Bangui'],
'Chad': ['Africa/Ndjamena'],
'China': ['Asia/Shanghai',
'Asia/Harbin',
'Asia/Chongqing',
'Asia/Urumqi',
'Asia/Kashgar'],
'Chile': ['America/Santiago', 'Pacific/Easter'],
'Colombia': ['America/Bogota'],
'Comoros': ['Indian/Comoro'],
@ -292,6 +297,7 @@ $.extend(erpnext.complete_setup, {
'Guyana': ['America/Guyana'],
'Haiti': ['America/Guatemala'],
'Honduras': ['America/Tegucigalpa'],
'Hong Kong': ['Asia/Hong_Kong'],
'Hungary': ['Europe/Budapest'],
'Iceland': ['Atlantic/Reykjavik'],
'India': ['Asia/Calcutta'],
@ -365,11 +371,6 @@ $.extend(erpnext.complete_setup, {
'Panama': ['America/Panama'],
'Papua New Guinea': ['Pacific/Port_Moresby'],
'Paraguay': ['America/Asuncion'],
"People's Republic of China": ['Asia/Shanghai',
'Asia/Harbin',
'Asia/Chongqing',
'Asia/Urumqi',
'Asia/Kashgar'],
'Peru': ['America/Lima'],
'Philippines': ['Asia/Manila'],
'Poland': ['Europe/Warsaw'],

View File

@ -197,51 +197,6 @@ class DocType(TransactionBase):
get_obj('DocType Mapper', 'Sales Order-Delivery Note', with_children = 1).validate_reference_value(self, self.doc.name)
def validate_prevdoc_details(self):
for d in getlist(self.doclist,'delivery_note_details'):
prevdoc = d.prevdoc_doctype
prevdoc_docname = d.prevdoc_docname
if prevdoc_docname and prevdoc:
# Validates Transaction Date of DN and previous doc (i.e. SO , PO, PR)
trans_date = sql("select posting_date from `tab%s` where name = '%s'" %(prevdoc,prevdoc_docname))[0][0]
if trans_date and getdate(self.doc.posting_date) < (trans_date):
msgprint("Your Posting Date cannot be before "+cstr(prevdoc)+" Date.")
raise Exception
# Validates DN and previous doc details
get_name = sql("select name from `tab%s` where name = '%s'" % (prevdoc, prevdoc_docname))
name = get_name and get_name[0][0] or ''
if name: #check for incorrect docname
if prevdoc == 'Sales Order':
dt = sql("select company, docstatus, customer, currency, sales_partner from `tab%s` where name = '%s'" % (prevdoc, name))
cust_name = dt and dt[0][2] or ''
if cust_name != self.doc.customer:
msgprint(cstr(prevdoc) + ": " + cstr(prevdoc_docname) + " customer :" + cstr(cust_name) + " does not match with customer : " + cstr(self.doc.customer) + " of current document.")
raise Exception, "Validation Error. "
sal_partner = dt and dt[0][4] or ''
if sal_partner != self.doc.sales_partner:
msgprint(cstr(prevdoc) + ": " + cstr(prevdoc_docname) + " sales partner name :" + cstr(sal_partner) + " does not match with sales partner name : " + cstr(self.doc.sales_partner_name) + " of current document.")
raise Exception, "Validation Error. "
else:
dt = sql("select company, docstatus, supplier, currency from `tab%s` where name = '%s'" % (prevdoc, name))
supp_name = dt and dt[0][2] or ''
company_name = dt and dt[0][0] or ''
docstatus = dt and dt[0][1] or 0
currency = dt and dt[0][3] or ''
if (currency != self.doc.currency):
msgprint(cstr(prevdoc) + ": " + cstr(prevdoc_docname) + " currency : "+ cstr(currency) + "does not match with Currency: " + cstr(self.doc.currency) + "of current document")
raise Exception, "Validation Error."
if (company_name != self.doc.company):
msgprint(cstr(prevdoc) + ": " + cstr(prevdoc_docname) + " does not belong to the Company: " + cstr(self.doc.company_name))
raise Exception, "Validation Error."
if (docstatus != 1):
msgprint(cstr(prevdoc) + ": " + cstr(prevdoc_docname) + " is not Submitted Document.")
raise Exception, "Validation Error."
else:
msgprint(cstr(prevdoc) + ": " + cstr(prevdoc_docname) + " is not a valid " + cstr(prevdoc))
raise Exception, "Validation Error."
def validate_for_items(self):
check_list, chk_dupl_itm = [], []
for d in getlist(self.doclist,'delivery_note_details'):
@ -292,11 +247,22 @@ class DocType(TransactionBase):
set(self.doc, 'message', 'Items against your Order #%s have been delivered. Delivery #%s: ' % (self.doc.po_no, self.doc.name))
# Check for Approving Authority
get_obj('Authorization Control').validate_approving_authority(self.doc.doctype, self.doc.company, self.doc.grand_total, self)
# validate serial no for item table (non-sales-bom item) and packing list (sales-bom item)
sl_obj = get_obj("Stock Ledger")
sl_obj.validate_serial_no(self, 'delivery_note_details')
sl_obj.validate_serial_no_warehouse(self, 'delivery_note_details')
sl_obj.validate_serial_no(self, 'packing_details')
sl_obj.validate_serial_no_warehouse(self, 'packing_details')
# update delivery details in serial no
sl_obj.update_serial_record(self, 'delivery_note_details', is_submit = 1, is_incoming = 0)
sl_obj.update_serial_record(self, 'packing_details', is_submit = 1, is_incoming = 0)
# update delivered qty in sales order
get_obj("Sales Common").update_prevdoc_detail(1,self)
# create stock ledger entry
self.update_stock_ledger(update_stock = 1)
self.credit_limit()
@ -332,10 +298,14 @@ class DocType(TransactionBase):
sales_com_obj = get_obj(dt = 'Sales Common')
sales_com_obj.check_stop_sales_order(self)
self.check_next_docstatus()
get_obj('Stock Ledger').update_serial_record(self, 'packing_details', is_submit = 0, is_incoming = 0)
# remove delivery details from serial no
sl = get_obj('Stock Ledger')
sl.update_serial_record(self, 'delivery_note_details', is_submit = 0, is_incoming = 0)
sl.update_serial_record(self, 'packing_details', is_submit = 0, is_incoming = 0)
sales_com_obj.update_prevdoc_detail(0,self)
self.update_stock_ledger(update_stock = -1)
# :::::: set DN status :::::::
set(self.doc, 'status', 'Cancelled')
self.cancel_packing_slips()
@ -435,7 +405,8 @@ class DocType(TransactionBase):
def on_update(self):
get_obj('Sales Common').make_packing_list(self,'delivery_note_details')
self.set_actual_qty()
get_obj('Stock Ledger').scrub_serial_nos(self)
sl = get_obj('Stock Ledger')
sl.scrub_serial_nos(self)
sl.scrub_serial_nos(self, 'packing_details')

View File

@ -3,9 +3,9 @@
# These values are common in all dictionaries
{
'creation': '2012-05-15 12:15:05',
'creation': '2012-06-11 12:10:09',
'docstatus': 0,
'modified': '2012-05-18 18:06:26',
'modified': '2012-07-11 11:56:53',
'modified_by': u'Administrator',
'owner': u'Administrator'
},
@ -72,26 +72,14 @@
# DocPerm
{
'amend': 1,
'cancel': 1,
'create': 1,
'amend': 0,
'cancel': 0,
'create': 0,
'doctype': u'DocPerm',
'permlevel': 0,
'role': u'Sales User',
'submit': 1,
'write': 1
},
# DocPerm
{
'amend': 1,
'cancel': 1,
'create': 1,
'doctype': u'DocPerm',
'permlevel': 0,
'role': u'Material Master Manager',
'submit': 1,
'write': 1
'permlevel': 1,
'role': u'Material User',
'submit': 0,
'write': 0
},
# DocPerm
@ -108,16 +96,72 @@
# DocPerm
{
'amend': 0,
'cancel': 0,
'create': 0,
'doctype': u'DocPerm',
'permlevel': 1,
'role': u'All'
'role': u'Material Manager',
'submit': 0,
'write': 0
},
# DocPerm
{
'amend': 1,
'cancel': 1,
'create': 1,
'doctype': u'DocPerm',
'permlevel': 0,
'role': u'Sales User',
'submit': 1,
'write': 1
},
# DocPerm
{
'amend': 0,
'cancel': 0,
'create': 0,
'doctype': u'DocPerm',
'permlevel': 1,
'role': u'Sales User',
'submit': 0,
'write': 0
},
# DocPerm
{
'cancel': 0,
'create': 0,
'doctype': u'DocPerm',
'permlevel': 0,
'role': u'Accounts User',
'submit': 0,
'write': 0
},
# DocPerm
{
'doctype': u'DocPerm',
'permlevel': 1,
'role': u'Accounts User'
},
# DocPerm
{
'doctype': u'DocPerm',
'match': u'customer_name',
'permlevel': 0,
'role': u'Customer'
},
# DocPerm
{
'doctype': u'DocPerm',
'permlevel': 2,
'role': u'All'
'role': u'All',
'write': 1
},
# DocField
@ -340,6 +384,7 @@
# DocField
{
'allow_on_submit': 1,
'colour': u'White:FFF',
'doctype': u'DocField',
'fieldname': u'delivery_note_details',
'fieldtype': u'Table',
@ -352,6 +397,16 @@
'print_hide': 0
},
# DocField
{
'doctype': u'DocField',
'fieldname': u'sales_bom_help',
'fieldtype': u'HTML',
'label': u'Sales BOM Help',
'permlevel': 0,
'print_hide': 1
},
# DocField
{
'doctype': u'DocField',

View File

@ -3,9 +3,9 @@
# These values are common in all dictionaries
{
'creation': '2012-04-13 11:56:35',
'creation': '2012-06-11 12:10:10',
'docstatus': 0,
'modified': '2012-05-09 12:55:23',
'modified': '2012-07-10 12:05:31',
'modified_by': u'Administrator',
'owner': u'Administrator'
},
@ -111,7 +111,7 @@
'oldfieldname': u'warehouse',
'oldfieldtype': u'Link',
'options': u'Warehouse',
'permlevel': 1
'permlevel': 0
},
# DocField

View File

@ -51,19 +51,16 @@ class DocType:
self.doclist = doclist
# -----------------
# scrub serial nos
# -----------------
def scrub_serial_nos(self, obj):
for d in getlist(obj.doclist, obj.fname):
def scrub_serial_nos(self, obj, table_name = ''):
if not table_name:
table_name = obj.fname
for d in getlist(obj.doclist, table_name):
if d.serial_no:
d.serial_no = d.serial_no.replace(',', '\n')
d.save()
# -----------------------------
# validate serial no warehouse
# -----------------------------
def validate_serial_no_warehouse(self, obj, fname):
for d in getlist(obj.doclist, fname):
wh = d.warehouse or d.s_warehouse
@ -80,10 +77,8 @@ class DocType:
msgprint("Serial No : %s for Item : %s doesn't exists in Warehouse : %s" % (s, d.item_code, wh), raise_exception = 1)
# ------------------------------------
# check whether serial no is required
# ------------------------------------
def validate_serial_no(self, obj, fname):
"""check whether serial no is required"""
for d in getlist(obj.doclist, fname):
is_stock_item = get_value('Item', d.item_code, 'is_stock_item')
ar_required = get_value('Item', d.item_code, 'has_serial_no')
@ -101,18 +96,10 @@ class DocType:
msgprint("Rejected serial no is mandatory for rejected qty of item: "+ d.item_code, raise_exception = 1)
# -------------------
# get serial no list
# -------------------
def get_sr_no_list(self, sr_nos, qty = 0, item_code = ''):
return get_sr_no_list(sr_nos, qty, item_code)
# ---------------------
# set serial no values
# ---------------------
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)
@ -143,9 +130,6 @@ class DocType:
s.save(new_rec)
# ----------------------------------
# update serial no purchase details
# ----------------------------------
def update_serial_purchase_details(self, obj, d, serial_no, is_submit, purpose = ''):
exists = sql("select name, status, docstatus from `tabSerial No` where name = '%s'" % (serial_no))
if is_submit:
@ -168,9 +152,6 @@ class DocType:
sql("update `tabSerial No` set docstatus = 2, status = 'Not in Use', purchase_document_type = '', purchase_document_no = '', purchase_date = null, purchase_rate = 0, supplier = null, supplier_name = '', supplier_address = '', warehouse = '' where name = '%s'" % serial_no)
# -------------------------------
# check whether serial no exists
# -------------------------------
def check_serial_no_exists(self, serial_no, item_code):
chk = sql("select name, status, docstatus, item_code from `tabSerial No` where name = %s", (serial_no), as_dict=1)
if not chk:
@ -182,9 +163,7 @@ class DocType:
elif chk and chk[0]['status'] == 'Delivered':
msgprint("Serial No: %s of Item : %s is already delivered." % (serial_no, item_code), raise_exception = 1)
# ---------------------
# set serial no values
# ---------------------
def set_delivery_serial_no_values(self, obj, serial_no):
s = Document('Serial No', serial_no)
s.delivery_document_type = obj.doc.doctype
@ -203,9 +182,6 @@ class DocType:
s.save()
# ----------------------------------
# update serial no delivery details
# ----------------------------------
def update_serial_delivery_details(self, obj, d, serial_no, is_submit):
if is_submit:
self.check_serial_no_exists(serial_no, d.item_code)
@ -214,9 +190,6 @@ class DocType:
sql("update `tabSerial No` set docstatus = 0, status = 'In Store', delivery_document_type = '', delivery_document_no = '', delivery_date = null, customer = null, customer_name = '', delivery_address = '', territory = null where name = '%s'" % (serial_no))
# ---------------------
# update serial record
# ---------------------
def update_serial_record(self, obj, fname, is_submit = 1, is_incoming = 0):
import datetime
for d in getlist(obj.doclist, fname):
@ -235,11 +208,6 @@ class DocType:
self.update_serial_purchase_details(obj, d, a, is_submit)
# -------------
# update stock
# -------------
def update_stock(self, values, is_amended = 'No'):
for v in values:
sle_id, serial_nos = '', ''
@ -261,9 +229,6 @@ class DocType:
v["posting_date"], sle_id, v["posting_time"], '', v["is_cancelled"],v["voucher_type"],v["voucher_no"], is_amended)
# -----------
# make entry
# -----------
def make_entry(self, args):
sle = Document(doctype = 'Stock Ledger Entry')
for k in args.keys():