[status updater] managed by controllers and commonified for sales and purchase
This commit is contained in:
parent
df33532280
commit
0feebc1a67
@ -158,7 +158,7 @@ class DocType(AccountsController):
|
||||
if r:
|
||||
self.doc.remark = ("\n").join(r)
|
||||
else:
|
||||
webnotes.msgprint("Remarks is mandatory", raise_exception=1)
|
||||
webnotes.msgprint("User Remarks is mandatory", raise_exception=1)
|
||||
|
||||
def set_aging_date(self):
|
||||
if self.doc.is_opening != 'Yes':
|
||||
|
@ -33,6 +33,28 @@ class DocType(BuyingController):
|
||||
self.doc, self.doclist = d, dl
|
||||
self.tname = 'Purchase Invoice Item'
|
||||
self.fname = 'entries'
|
||||
self.status_updater = [{
|
||||
'source_dt': 'Purchase Invoice Item',
|
||||
'target_dt': 'Purchase Order Item',
|
||||
'join_field': 'po_detail',
|
||||
'target_field': 'billed_amt',
|
||||
'target_parent_dt': 'Purchase Order',
|
||||
'target_parent_field': 'per_billed',
|
||||
'target_ref_field': 'import_amount',
|
||||
'source_field': 'import_amount',
|
||||
'percent_join_field': 'purchase_order',
|
||||
},
|
||||
{
|
||||
'source_dt': 'Purchase Invoice Item',
|
||||
'target_dt': 'Purchase Receipt Item',
|
||||
'join_field': 'pr_detail',
|
||||
'target_field': 'billed_amt',
|
||||
'target_parent_dt': 'Purchase Receipt',
|
||||
'target_parent_field': 'per_billed',
|
||||
'target_ref_field': 'import_amount',
|
||||
'source_field': 'import_amount',
|
||||
'percent_join_field': 'purchase_receipt',
|
||||
}]
|
||||
|
||||
def validate(self):
|
||||
super(DocType, self).validate()
|
||||
@ -411,8 +433,8 @@ class DocType(BuyingController):
|
||||
self.make_gl_entries()
|
||||
|
||||
self.update_against_document_in_jv()
|
||||
purchase_controller.update_prevdoc_detail(self, is_submit = 1)
|
||||
|
||||
|
||||
self.update_prevdoc_status()
|
||||
|
||||
def make_gl_entries(self):
|
||||
from accounts.general_ledger import make_gl_entries
|
||||
@ -523,7 +545,8 @@ class DocType(BuyingController):
|
||||
def on_cancel(self):
|
||||
from accounts.utils import remove_against_link_from_jv
|
||||
remove_against_link_from_jv(self.doc.doctype, self.doc.name, "against_voucher")
|
||||
get_obj(dt = 'Purchase Common').update_prevdoc_detail(self, is_submit = 0)
|
||||
|
||||
self.update_prevdoc_status()
|
||||
|
||||
self.make_cancel_gl_entries()
|
||||
|
||||
|
@ -38,6 +38,35 @@ class DocType(SellingController):
|
||||
self.log = []
|
||||
self.tname = 'Sales Invoice Item'
|
||||
self.fname = 'entries'
|
||||
self.status_updater = [{
|
||||
'source_dt': 'Sales Invoice Item',
|
||||
'target_field': 'billed_amt',
|
||||
'target_ref_field': 'export_amount',
|
||||
'target_dt': 'Sales Order Item',
|
||||
'join_field': 'so_detail',
|
||||
'target_parent_dt': 'Sales Order',
|
||||
'target_parent_field': 'per_billed',
|
||||
'source_field': 'export_amount',
|
||||
'join_field': 'so_detail',
|
||||
'percent_join_field': 'sales_order',
|
||||
'status_field': 'billing_status',
|
||||
'keyword': 'Billed'
|
||||
},
|
||||
{
|
||||
'source_dt': 'Sales Invoice Item',
|
||||
'target_dt': 'Delivery Note Item',
|
||||
'join_field': 'dn_detail',
|
||||
'target_field': 'billed_amt',
|
||||
'target_parent_dt': 'Delivery Note',
|
||||
'target_parent_field': 'per_billed',
|
||||
'target_ref_field': 'export_amount',
|
||||
'source_field': 'export_amount',
|
||||
'percent_join_field': 'delivery_note',
|
||||
'status_field': 'billing_status',
|
||||
'keyword': 'Billed',
|
||||
'no_tolerance': True,
|
||||
}]
|
||||
|
||||
|
||||
def validate(self):
|
||||
super(DocType, self).validate()
|
||||
@ -98,7 +127,9 @@ class DocType(SellingController):
|
||||
|
||||
self.set_buying_amount()
|
||||
self.check_prev_docstatus()
|
||||
get_obj("Sales Common").update_prevdoc_detail(1,self)
|
||||
|
||||
self.update_status_updater_args()
|
||||
self.update_prevdoc_status()
|
||||
|
||||
# this sequence because outstanding may get -ve
|
||||
self.make_gl_entries()
|
||||
@ -128,10 +159,30 @@ class DocType(SellingController):
|
||||
from accounts.utils import remove_against_link_from_jv
|
||||
remove_against_link_from_jv(self.doc.doctype, self.doc.name, "against_invoice")
|
||||
|
||||
sales_com_obj.update_prevdoc_detail(0, self)
|
||||
self.update_status_updater_args()
|
||||
self.update_prevdoc_status()
|
||||
|
||||
self.make_cancel_gl_entries()
|
||||
|
||||
def update_status_updater_args(self):
|
||||
if cint(self.doc.is_pos) and cint(self.doc.update_stock):
|
||||
self.status_updater.append({
|
||||
'source_dt':'Sales Invoice Item',
|
||||
'target_dt':'Sales Order Item',
|
||||
'target_parent_dt':'Sales Order',
|
||||
'target_parent_field':'per_delivered',
|
||||
'target_field':'delivered_qty',
|
||||
'target_ref_field':'qty',
|
||||
'source_field':'qty',
|
||||
'join_field':'so_detail',
|
||||
'percent_join_field':'sales_order',
|
||||
'status_field':'delivery_status',
|
||||
'keyword':'Delivered',
|
||||
'second_source_dt': 'Delivery Note Item',
|
||||
'second_source_field': 'qty',
|
||||
'second_join_field': 'prevdoc_detail_docname'
|
||||
})
|
||||
|
||||
def on_update_after_submit(self):
|
||||
self.validate_recurring_invoice()
|
||||
self.convert_to_recurring()
|
||||
@ -351,7 +402,7 @@ class DocType(SellingController):
|
||||
|
||||
if ret.get("warehouse"):
|
||||
ret["actual_qty"] = flt(webnotes.conn.get_value("Bin",
|
||||
{"item_code": args.get("item_code"), "warehouse": args.get("warehouse")},
|
||||
{"item_code": args.get("item_code"), "warehouse": ret.get("warehouse")},
|
||||
"actual_qty"))
|
||||
return ret
|
||||
|
||||
@ -435,13 +486,15 @@ class DocType(SellingController):
|
||||
|
||||
def validate_customer(self):
|
||||
""" 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:
|
||||
dt_no = d.delivery_note or d.sales_order
|
||||
cust = webnotes.conn.sql("select customer from `tab%s` where name = %s" % (dt, '%s'), dt_no)
|
||||
if cust and cstr(cust[0][0]) != cstr(self.doc.customer):
|
||||
msgprint("Customer %s does not match with customer of %s: %s." %(self.doc.customer, dt, dt_no), raise_exception=1)
|
||||
if self.doc.customer:
|
||||
for d in getlist(self.doclist,'entries'):
|
||||
dt = d.delivery_note and 'Delivery Note' or d.sales_order and 'Sales Order' or ''
|
||||
if dt:
|
||||
dt_no = d.delivery_note or d.sales_order
|
||||
cust = webnotes.conn.get_value(dt, dt_no, "customer")
|
||||
if cust and cstr(cust) != cstr(self.doc.customer):
|
||||
msgprint("Customer %s does not match with customer of %s: %s."
|
||||
%(self.doc.customer, dt, dt_no), raise_exception=1)
|
||||
|
||||
|
||||
def validate_customer_account(self):
|
||||
@ -1084,4 +1137,4 @@ def get_bank_cash_account(mode_of_payment):
|
||||
webnotes.msgprint("Default Bank / Cash Account not set in Mode of Payment: %s. Please add a Default Account in Mode of Payment master." % mode_of_payment)
|
||||
return {
|
||||
"cash_bank_account": val
|
||||
}
|
||||
}
|
@ -213,10 +213,11 @@ class DocType(BuyingController):
|
||||
msgprint("Please check Item %s is not present in %s %s ." % (d.item_code, d.prevdoc_doctype, d.prevdoc_docname))
|
||||
raise Exception
|
||||
|
||||
# Check if Warehouse has been modified.
|
||||
if not cstr(data[0]['warehouse']) == cstr(d.warehouse):
|
||||
msgprint("Please check warehouse %s of Item %s which is not present in %s %s ." % (d.warehouse, d.item_code, d.prevdoc_doctype, d.prevdoc_docname))
|
||||
raise Exception
|
||||
if cstr(data[0]['warehouse']) and \
|
||||
not cstr(data[0]['warehouse']) == cstr(d.warehouse):
|
||||
msgprint("""Please check warehouse %s of Item %s
|
||||
which is not present in %s %s""" % (d.warehouse, d.item_code,
|
||||
d.prevdoc_doctype, d.prevdoc_docname), raise_exception=1)
|
||||
|
||||
# Check if UOM has been modified.
|
||||
if not cstr(data[0]['uom']) == cstr(d.uom) and not cstr(d.prevdoc_doctype) == 'Material Request':
|
||||
|
@ -2,7 +2,7 @@
|
||||
{
|
||||
"creation": "2013-03-07 11:42:55",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-05-22 11:59:52",
|
||||
"modified": "2013-05-31 14:26:22",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
@ -377,15 +377,12 @@
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"default": "0.00",
|
||||
"doctype": "DocField",
|
||||
"fieldname": "billed_qty",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"label": "Billed Quantity",
|
||||
"fieldname": "billed_amt",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Billed Amt",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "billed_qty",
|
||||
"oldfieldtype": "Currency",
|
||||
"options": "currency",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
|
177
controllers/status_updater.py
Normal file
177
controllers/status_updater.py
Normal file
@ -0,0 +1,177 @@
|
||||
# ERPNext - web based ERP (http://erpnext.com)
|
||||
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
from webnotes.utils import flt, cstr
|
||||
from webnotes import msgprint
|
||||
|
||||
from webnotes.model.controller import DocListController
|
||||
|
||||
class StatusUpdater(DocListController):
|
||||
"""
|
||||
Updates the status of the calling records
|
||||
Delivery Note: Update Delivered Qty, Update Percent and Validate over delivery
|
||||
Sales Invoice: Update Billed Amt, Update Percent and Validate over billing
|
||||
Installation Note: Update Installed Qty, Update Percent Qty and Validate over installation
|
||||
"""
|
||||
|
||||
def update_prevdoc_status(self):
|
||||
self.update_qty()
|
||||
self.validate_qty()
|
||||
|
||||
def validate_qty(self):
|
||||
"""
|
||||
Validates qty at row level
|
||||
"""
|
||||
self.tolerance = {}
|
||||
self.global_tolerance = None
|
||||
|
||||
for args in self.status_updater:
|
||||
# get unique transactions to update
|
||||
for d in self.doclist:
|
||||
if d.doctype == args['source_dt'] and d.fields.get(args["join_field"]):
|
||||
args['name'] = d.fields[args['join_field']]
|
||||
|
||||
# get all qty where qty > target_field
|
||||
item = webnotes.conn.sql("""select item_code, `%(target_ref_field)s`,
|
||||
`%(target_field)s`, parenttype, parent from `tab%(target_dt)s`
|
||||
where `%(target_ref_field)s` < `%(target_field)s`
|
||||
and name="%(name)s" and docstatus=1""" % args, as_dict=1)
|
||||
if item:
|
||||
item = item[0]
|
||||
item['idx'] = d.idx
|
||||
item['target_ref_field'] = args['target_ref_field'].replace('_', ' ')
|
||||
|
||||
if not item[args['target_ref_field']]:
|
||||
msgprint("""As %(target_ref_field)s for item: %(item_code)s in \
|
||||
%(parenttype)s: %(parent)s is zero, system will not check \
|
||||
over-delivery or over-billed""" % item)
|
||||
elif args.get('no_tolerance'):
|
||||
item['reduce_by'] = item[args['target_field']] - \
|
||||
item[args['target_ref_field']]
|
||||
if item['reduce_by'] > .01:
|
||||
msgprint("""
|
||||
Row #%(idx)s: Max %(target_ref_field)s allowed for <b>Item \
|
||||
%(item_code)s</b> against <b>%(parenttype)s %(parent)s</b> \
|
||||
is <b>""" % item + cstr(item[args['target_ref_field']]) +
|
||||
"""</b>.<br>You must reduce the %(target_ref_field)s by \
|
||||
%(reduce_by)s""" % item, raise_exception=1)
|
||||
|
||||
else:
|
||||
self.check_overflow_with_tolerance(item, args)
|
||||
|
||||
def check_overflow_with_tolerance(self, item, args):
|
||||
"""
|
||||
Checks if there is overflow condering a relaxation tolerance
|
||||
"""
|
||||
|
||||
# check if overflow is within tolerance
|
||||
tolerance = self.get_tolerance_for(item['item_code'])
|
||||
overflow_percent = ((item[args['target_field']] - item[args['target_ref_field']]) /
|
||||
item[args['target_ref_field']]) * 100
|
||||
|
||||
if overflow_percent - tolerance > 0.01:
|
||||
item['max_allowed'] = flt(item[args['target_ref_field']] * (100+tolerance)/100)
|
||||
item['reduce_by'] = item[args['target_field']] - item['max_allowed']
|
||||
|
||||
msgprint("""
|
||||
Row #%(idx)s: Max %(target_ref_field)s allowed for <b>Item %(item_code)s</b> \
|
||||
against <b>%(parenttype)s %(parent)s</b> is <b>%(max_allowed)s</b>.
|
||||
|
||||
If you want to increase your overflow tolerance, please increase tolerance %% in \
|
||||
Global Defaults or Item master.
|
||||
|
||||
Or, you must reduce the %(target_ref_field)s by %(reduce_by)s
|
||||
|
||||
Also, please check if the order item has already been billed in the Sales Order""" %
|
||||
item, raise_exception=1)
|
||||
|
||||
def get_tolerance_for(self, item_code):
|
||||
"""
|
||||
Returns the tolerance for the item, if not set, returns global tolerance
|
||||
"""
|
||||
if self.tolerance.get(item_code): return self.tolerance[item_code]
|
||||
|
||||
tolerance = flt(webnotes.conn.get_value('Item',item_code,'tolerance') or 0)
|
||||
|
||||
if not tolerance:
|
||||
if self.global_tolerance == None:
|
||||
self.global_tolerance = flt(webnotes.conn.get_value('Global Defaults', None,
|
||||
'tolerance'))
|
||||
tolerance = self.global_tolerance
|
||||
|
||||
self.tolerance[item_code] = tolerance
|
||||
return tolerance
|
||||
|
||||
|
||||
def update_qty(self, change_modified=True):
|
||||
"""
|
||||
Updates qty at row level
|
||||
"""
|
||||
for args in self.status_updater:
|
||||
# condition to include current record (if submit or no if cancel)
|
||||
if self.doc.docstatus == 1:
|
||||
args['cond'] = ' or parent="%s"' % self.doc.name
|
||||
else:
|
||||
args['cond'] = ' and parent!="%s"' % self.doc.name
|
||||
|
||||
args['modified_cond'] = ''
|
||||
if change_modified:
|
||||
args['modified_cond'] = ', modified = now()'
|
||||
|
||||
# update quantities in child table
|
||||
for d in self.doclist:
|
||||
if d.doctype == args['source_dt']:
|
||||
# updates qty in the child table
|
||||
args['detail_id'] = d.fields.get(args['join_field'])
|
||||
|
||||
args['second_source_condition'] = ""
|
||||
if args.get('second_source_dt') and args.get('second_source_field') \
|
||||
and args.get('second_join_field'):
|
||||
args['second_source_condition'] = """ + (select sum(%(second_source_field)s)
|
||||
from `tab%(second_source_dt)s`
|
||||
where `%(second_join_field)s`="%(detail_id)s"
|
||||
and (docstatus=1))""" % args
|
||||
|
||||
if args['detail_id']:
|
||||
webnotes.conn.sql("""update `tab%(target_dt)s`
|
||||
set %(target_field)s = (select sum(%(source_field)s)
|
||||
from `tab%(source_dt)s` where `%(join_field)s`="%(detail_id)s"
|
||||
and (docstatus=1 %(cond)s)) %(second_source_condition)s
|
||||
where name='%(detail_id)s'""" % args)
|
||||
|
||||
# get unique transactions to update
|
||||
for name in set([d.fields.get(args['percent_join_field']) for d in self.doclist
|
||||
if d.doctype == args['source_dt']]):
|
||||
if name:
|
||||
args['name'] = name
|
||||
|
||||
# update percent complete in the parent table
|
||||
webnotes.conn.sql("""update `tab%(target_parent_dt)s`
|
||||
set %(target_parent_field)s = (select sum(if(%(target_ref_field)s >
|
||||
ifnull(%(target_field)s, 0), %(target_field)s,
|
||||
%(target_ref_field)s))/sum(%(target_ref_field)s)*100
|
||||
from `tab%(target_dt)s` where parent="%(name)s") %(modified_cond)s
|
||||
where name='%(name)s'""" % args)
|
||||
|
||||
# update field
|
||||
if args.get('status_field'):
|
||||
webnotes.conn.sql("""update `tab%(target_parent_dt)s`
|
||||
set %(status_field)s = if(ifnull(%(target_parent_field)s,0)<0.001,
|
||||
'Not %(keyword)s', if(%(target_parent_field)s>=99.99,
|
||||
'Fully %(keyword)s', 'Partly %(keyword)s'))
|
||||
where name='%(name)s'""" % args)
|
24
patches/may_2013/p06_update_billed_amt_po_pr.py
Normal file
24
patches/may_2013/p06_update_billed_amt_po_pr.py
Normal file
@ -0,0 +1,24 @@
|
||||
# ERPNext - web based ERP (http://erpnext.com)
|
||||
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import unicode_literals
|
||||
def execute():
|
||||
import webnotes
|
||||
webnotes.reload_doc("buying", "doctype", "purchase_order_item")
|
||||
webnotes.reload_doc("stock", "doctype", "purchase_receipt_item")
|
||||
for pi in webnotes.conn.sql("""select name from `tabPurchase Invoice` where docstatus = 1"""):
|
||||
webnotes.get_obj("Purchase Invoice", pi[0],
|
||||
with_children=1).update_qty(change_modified=False)
|
@ -252,4 +252,5 @@ patch_list = [
|
||||
"patches.may_2013.p03_update_support_ticket",
|
||||
"patches.may_2013.p04_reorder_level",
|
||||
"patches.may_2013.p05_update_cancelled_gl_entries",
|
||||
"patches.may_2013.p06_update_billed_amt_po_pr",
|
||||
]
|
@ -21,10 +21,7 @@ from webnotes.utils import cstr, getdate
|
||||
from webnotes.model.bean import getlist
|
||||
from webnotes.model.code import get_obj
|
||||
from webnotes import msgprint
|
||||
from stock.utils import get_valid_serial_nos
|
||||
|
||||
sql = webnotes.conn.sql
|
||||
|
||||
from stock.utils import get_valid_serial_nos
|
||||
|
||||
from utilities.transaction_base import TransactionBase
|
||||
|
||||
@ -34,6 +31,19 @@ class DocType(TransactionBase):
|
||||
self.doclist = doclist
|
||||
self.tname = 'Installation Note Item'
|
||||
self.fname = 'installed_item_details'
|
||||
self.status_updater = [{
|
||||
'source_dt': 'Installation Note Item',
|
||||
'target_dt': 'Delivery Note Item',
|
||||
'target_field': 'installed_qty',
|
||||
'target_ref_field': 'qty',
|
||||
'join_field': 'prevdoc_detail_docname',
|
||||
'target_parent_dt': 'Delivery Note',
|
||||
'target_parent_field': 'per_installed',
|
||||
'source_field': 'qty',
|
||||
'percent_join_field': 'prevdoc_docname',
|
||||
'status_field': 'installation_status',
|
||||
'keyword': 'Installed'
|
||||
}]
|
||||
|
||||
def validate(self):
|
||||
self.validate_fiscal_year()
|
||||
@ -45,153 +55,114 @@ class DocType(TransactionBase):
|
||||
self.validate_mandatory()
|
||||
self.validate_reference_value()
|
||||
|
||||
|
||||
#fetch delivery note details
|
||||
#====================================
|
||||
def pull_delivery_note_details(self):
|
||||
self.validate_prev_docname()
|
||||
self.doclist = get_obj('DocType Mapper', 'Delivery Note-Installation Note').dt_map('Delivery Note', 'Installation Note', self.doc.delivery_note_no, self.doc, self.doclist, "[['Delivery Note', 'Installation Note'],['Delivery Note Item', 'Installation Note Item']]")
|
||||
self.doclist = get_obj('DocType Mapper', 'Delivery Note-Installation Note').dt_map(
|
||||
'Delivery Note', 'Installation Note', self.doc.delivery_note_no,
|
||||
self.doc, self.doclist, "[['Delivery Note', 'Installation Note'], \
|
||||
['Delivery Note Item', 'Installation Note Item']]")
|
||||
|
||||
# Validates that Delivery Note is not pulled twice
|
||||
#============================================
|
||||
def validate_prev_docname(self):
|
||||
for d in getlist(self.doclist, 'installed_item_details'):
|
||||
if self.doc.delivery_note_no == d.prevdoc_docname:
|
||||
msgprint(cstr(self.doc.delivery_note_no) + " delivery note details have already been pulled. ")
|
||||
raise Exception, "Validation Error. "
|
||||
|
||||
#Fiscal Year Validation
|
||||
#================================
|
||||
msgprint(cstr(self.doc.delivery_note_no) +
|
||||
" delivery note details have already been pulled", raise_exception=1)
|
||||
|
||||
def validate_fiscal_year(self):
|
||||
get_obj('Sales Common').validate_fiscal_year(self.doc.fiscal_year,self.doc.inst_date,'Installation Date')
|
||||
|
||||
# Validate Mandatory
|
||||
#===============================
|
||||
get_obj('Sales Common').validate_fiscal_year(self.doc.fiscal_year, self.doc.inst_date,
|
||||
'Installation Date')
|
||||
|
||||
def validate_mandatory(self):
|
||||
# Amendment Date
|
||||
if self.doc.amended_from and not self.doc.amendment_date:
|
||||
msgprint("Please Enter Amendment Date")
|
||||
raise Exception, "Validation Error. "
|
||||
|
||||
# Validate values with reference document
|
||||
#----------------------------------------
|
||||
|
||||
def validate_reference_value(self):
|
||||
get_obj('DocType Mapper', 'Delivery Note-Installation Note', with_children = 1).validate_reference_value(self, self.doc.name)
|
||||
mapper = get_obj('DocType Mapper', 'Delivery Note-Installation Note', with_children = 1)
|
||||
mapper.validate_reference_value(self, self.doc.name)
|
||||
|
||||
#check if serial no added
|
||||
#-----------------------------
|
||||
def is_serial_no_added(self,item_code,serial_no):
|
||||
ar_required = sql("select has_serial_no from tabItem where name = '%s'" % item_code)
|
||||
ar_required = ar_required and ar_required[0][0] or ''
|
||||
def is_serial_no_added(self, item_code, serial_no):
|
||||
ar_required = webnotes.conn.get_value("Item", item_code, "has_serial_no")
|
||||
if ar_required == 'Yes' and not serial_no:
|
||||
msgprint("Serial No is mandatory for item: "+ item_code)
|
||||
raise Exception
|
||||
msgprint("Serial No is mandatory for item: " + item_code, raise_exception=1)
|
||||
elif ar_required != 'Yes' and cstr(serial_no).strip():
|
||||
msgprint("If serial no required, please select 'Yes' in 'Has Serial No' in Item :"+item_code)
|
||||
raise Exception
|
||||
msgprint("If serial no required, please select 'Yes' in 'Has Serial No' in Item :" +
|
||||
item_code, raise_exception=1)
|
||||
|
||||
#check if serial no exist in system
|
||||
#-------------------------------------
|
||||
def is_serial_no_exist(self, item_code, serial_no):
|
||||
for x in serial_no:
|
||||
chk = sql("select name from `tabSerial No` where name =%s", x)
|
||||
if not chk:
|
||||
msgprint("Serial No "+x+" does not exist in the system")
|
||||
raise Exception
|
||||
if not webnotes.conn.exists("Serial No", x):
|
||||
msgprint("Serial No " + x + " does not exist in the system", raise_exception=1)
|
||||
|
||||
#check if serial no already installed
|
||||
#------------------------------------------
|
||||
def is_serial_no_installed(self,cur_s_no,item_code):
|
||||
for x in cur_s_no:
|
||||
status = sql("select status from `tabSerial No` where name = %s", x)
|
||||
status = webnotes.conn.sql("select status from `tabSerial No` where name = %s", x)
|
||||
status = status and status[0][0] or ''
|
||||
|
||||
if status == 'Installed':
|
||||
msgprint("Item "+item_code+" with serial no. "+x+" already installed")
|
||||
raise Exception, "Validation Error."
|
||||
msgprint("Item "+item_code+" with serial no. " + x + " already installed",
|
||||
raise_exception=1)
|
||||
|
||||
#get list of serial no from previous_doc
|
||||
#----------------------------------------------
|
||||
def get_prevdoc_serial_no(self, prevdoc_detail_docname, prevdoc_docname):
|
||||
res = sql("select serial_no from `tabDelivery Note Item` where name = '%s' and parent ='%s'" % (prevdoc_detail_docname, prevdoc_docname))
|
||||
return get_valid_serial_nos(res[0][0])
|
||||
def get_prevdoc_serial_no(self, prevdoc_detail_docname):
|
||||
serial_nos = webnotes.conn.get_value("Delivery Note Item",
|
||||
prevdoc_detail_docname, "serial_no")
|
||||
return get_valid_serial_nos(serial_nos)
|
||||
|
||||
#check if all serial nos from current record exist in resp delivery note
|
||||
#---------------------------------------------------------------------------------
|
||||
def is_serial_no_match(self, cur_s_no, prevdoc_s_no, prevdoc_docname):
|
||||
for x in cur_s_no:
|
||||
if not(x in prevdoc_s_no):
|
||||
msgprint("Serial No. "+x+" not present in the Delivery Note "+prevdoc_docname, raise_exception = 1)
|
||||
raise Exception, "Validation Error."
|
||||
|
||||
#validate serial number
|
||||
#----------------------------------------
|
||||
for sr in cur_s_no:
|
||||
if sr not in prevdoc_s_no:
|
||||
msgprint("Serial No. " + sr + " is not matching with the Delivery Note " +
|
||||
prevdoc_docname, raise_exception = 1)
|
||||
|
||||
def validate_serial_no(self):
|
||||
cur_s_no, prevdoc_s_no, sr_list = [], [], []
|
||||
for d in getlist(self.doclist, 'installed_item_details'):
|
||||
self.is_serial_no_added(d.item_code, d.serial_no)
|
||||
|
||||
if d.serial_no:
|
||||
|
||||
sr_list = get_valid_serial_nos(d.serial_no, d.qty, d.item_code)
|
||||
self.is_serial_no_exist(d.item_code, sr_list)
|
||||
|
||||
prevdoc_s_no = self.get_prevdoc_serial_no(d.prevdoc_detail_docname, d.prevdoc_docname)
|
||||
prevdoc_s_no = self.get_prevdoc_serial_no(d.prevdoc_detail_docname)
|
||||
if prevdoc_s_no:
|
||||
self.is_serial_no_match(sr_list, prevdoc_s_no, d.prevdoc_docname)
|
||||
|
||||
self.is_serial_no_installed(sr_list, d.item_code)
|
||||
return sr_list
|
||||
|
||||
#validate installation date
|
||||
#-------------------------------
|
||||
|
||||
def validate_installation_date(self):
|
||||
for d in getlist(self.doclist, 'installed_item_details'):
|
||||
if d.prevdoc_docname:
|
||||
d_date = sql("select posting_date from `tabDelivery Note` where name=%s", d.prevdoc_docname)
|
||||
d_date = d_date and d_date[0][0] or ''
|
||||
|
||||
d_date = webnotes.conn.get_value("Delivery Note", d.prevdoc_docname, "posting_date")
|
||||
if d_date > getdate(self.doc.inst_date):
|
||||
msgprint("Installation Date can not be before Delivery Date "+cstr(d_date)+" for item "+d.item_code)
|
||||
raise Exception
|
||||
msgprint("Installation Date can not be before Delivery Date " + cstr(d_date) +
|
||||
" for item "+d.item_code, raise_exception=1)
|
||||
|
||||
def check_item_table(self):
|
||||
if not(getlist(self.doclist, 'installed_item_details')):
|
||||
msgprint("Please fetch items from Delivery Note selected")
|
||||
raise Exception
|
||||
msgprint("Please fetch items from Delivery Note selected", raise_exception=1)
|
||||
|
||||
def on_update(self):
|
||||
get_obj("Stock Ledger").scrub_serial_nos(self, 'installed_item_details')
|
||||
webnotes.conn.set(self.doc, 'status', 'Draft')
|
||||
|
||||
def on_submit(self):
|
||||
valid_lst = []
|
||||
valid_lst = self.validate_serial_no()
|
||||
|
||||
get_obj("Sales Common").update_prevdoc_detail(1,self)
|
||||
|
||||
for x in valid_lst:
|
||||
wp = sql("select warranty_period from `tabSerial No` where name = '%s'"% x)
|
||||
wp = wp and wp[0][0] or 0
|
||||
if wp:
|
||||
sql("update `tabSerial No` set maintenance_status = 'Under Warranty' where name = '%s'" % x)
|
||||
|
||||
sql("update `tabSerial No` set status = 'Installed' where name = '%s'" % x)
|
||||
|
||||
webnotes.conn.set(self.doc, 'status', 'Submitted')
|
||||
if webnotes.conn.get_value("Serial No", x, "warranty_period"):
|
||||
webnotes.conn.set_value("Serial No", x, "maintenance_status", "Under Warranty")
|
||||
webnotes.conn.set_value("Serial No", x, "status", "Installed")
|
||||
|
||||
self.update_prevdoc_status()
|
||||
webnotes.conn.set(self.doc, 'status', 'Submitted')
|
||||
|
||||
def on_cancel(self):
|
||||
cur_s_no = []
|
||||
sales_com_obj = get_obj(dt = 'Sales Common')
|
||||
sales_com_obj.update_prevdoc_detail(0,self)
|
||||
|
||||
for d in getlist(self.doclist, 'installed_item_details'):
|
||||
if d.serial_no:
|
||||
#get current list of serial no
|
||||
cur_serial_no = d.serial_no.replace(' ', '')
|
||||
cur_s_no = cur_serial_no.split(',')
|
||||
|
||||
for x in cur_s_no:
|
||||
sql("update `tabSerial No` set status = 'Delivered' where name = '%s'" % x)
|
||||
|
||||
d.serial_no = d.serial_no.replace(",", "\n")
|
||||
for sr_no in d.serial_no.split("\n"):
|
||||
webnotes.conn.set_value("Serial No", sr_no, "status", "Delivered")
|
||||
|
||||
self.update_prevdoc_status()
|
||||
webnotes.conn.set(self.doc, 'status', 'Cancelled')
|
||||
|
@ -17,7 +17,7 @@
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
|
||||
from webnotes.utils import cstr, flt, getdate, cint
|
||||
from webnotes.utils import cstr, flt, cint
|
||||
from webnotes.model.bean import getlist
|
||||
from webnotes.model.code import get_obj
|
||||
from webnotes import msgprint, _
|
||||
@ -34,6 +34,19 @@ class DocType(SellingController):
|
||||
self.doclist = doclist
|
||||
self.tname = 'Delivery Note Item'
|
||||
self.fname = 'delivery_note_details'
|
||||
self.status_updater = [{
|
||||
'source_dt': 'Delivery Note Item',
|
||||
'target_dt': 'Sales Order Item',
|
||||
'join_field': 'prevdoc_detail_docname',
|
||||
'target_field': 'delivered_qty',
|
||||
'target_parent_dt': 'Sales Order',
|
||||
'target_parent_field': 'per_delivered',
|
||||
'target_ref_field': 'qty',
|
||||
'source_field': 'qty',
|
||||
'percent_join_field': 'prevdoc_docname',
|
||||
'status_field': 'delivery_status',
|
||||
'keyword': 'Delivered'
|
||||
}]
|
||||
|
||||
def validate_fiscal_year(self):
|
||||
get_obj('Sales Common').validate_fiscal_year(self.doc.fiscal_year,self.doc.posting_date,'Posting Date')
|
||||
@ -261,8 +274,8 @@ class DocType(SellingController):
|
||||
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)
|
||||
# update delivered qty in sales order
|
||||
self.update_prevdoc_status()
|
||||
|
||||
# create stock ledger entry
|
||||
self.update_stock_ledger(update_stock = 1)
|
||||
@ -309,7 +322,8 @@ class DocType(SellingController):
|
||||
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_prevdoc_status()
|
||||
|
||||
self.update_stock_ledger(update_stock = -1)
|
||||
webnotes.conn.set(self.doc, 'status', 'Cancelled')
|
||||
self.cancel_packing_slips()
|
||||
|
@ -33,6 +33,17 @@ class DocType(BuyingController):
|
||||
self.tname = 'Purchase Receipt Item'
|
||||
self.fname = 'purchase_receipt_details'
|
||||
self.count = 0
|
||||
self.status_updater = [{
|
||||
'source_dt': 'Purchase Receipt Item',
|
||||
'target_dt': 'Purchase Order Item',
|
||||
'join_field': 'prevdoc_detail_docname',
|
||||
'target_field': 'received_qty',
|
||||
'target_parent_dt': 'Purchase Order',
|
||||
'target_parent_field': 'per_received',
|
||||
'target_ref_field': 'qty',
|
||||
'source_field': 'qty',
|
||||
'percent_join_field': 'prevdoc_docname',
|
||||
}]
|
||||
|
||||
def validate_fiscal_year(self):
|
||||
get_obj(dt = 'Purchase Common').validate_fiscal_year(self.doc.fiscal_year,self.doc.posting_date,'Transaction Date')
|
||||
@ -243,8 +254,7 @@ class DocType(BuyingController):
|
||||
# Set status as Submitted
|
||||
webnotes.conn.set(self.doc,'status', 'Submitted')
|
||||
|
||||
# Update Previous Doc i.e. update pending_qty and Status accordingly
|
||||
purchase_controller.update_prevdoc_detail(self, is_submit = 1)
|
||||
self.update_prevdoc_status()
|
||||
|
||||
# Update Serial Record
|
||||
get_obj('Stock Ledger').update_serial_record(self, 'purchase_receipt_details', is_submit = 1, is_incoming = 1)
|
||||
@ -285,8 +295,7 @@ class DocType(BuyingController):
|
||||
# 4.Update Bin
|
||||
self.update_stock(is_submit = 0)
|
||||
|
||||
# 5.Update Material Requests Pending Qty and accordingly it's Status
|
||||
pc_obj.update_prevdoc_detail(self, is_submit = 0)
|
||||
self.update_prevdoc_status()
|
||||
|
||||
# 6. Update last purchase rate
|
||||
pc_obj.update_last_purchase_rate(self, 0)
|
||||
|
@ -6,7 +6,7 @@ wn.listview_settings['Purchase Receipt'] = {
|
||||
group_by: "`tabPurchase Receipt`.name",
|
||||
prepare_data: function(data) {
|
||||
if(data.purchase_order_no) {
|
||||
data.purchase_order_no = data.purchase_order_no.split(",");
|
||||
data.purchase_order_no = $.unique(data.purchase_order_no.split(","));
|
||||
var po_list = [];
|
||||
$.each(data.purchase_order_no, function(i, v){
|
||||
if(po_list.indexOf(v)==-1) po_list.push(
|
||||
|
@ -2,7 +2,7 @@
|
||||
{
|
||||
"creation": "2013-03-07 11:42:59",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-05-22 12:01:08",
|
||||
"modified": "2013-05-31 14:26:41",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
@ -453,18 +453,14 @@
|
||||
"width": "150px"
|
||||
},
|
||||
{
|
||||
"default": "0.00",
|
||||
"doctype": "DocField",
|
||||
"fieldname": "billed_qty",
|
||||
"fieldtype": "Float",
|
||||
"label": "Billed Quantity",
|
||||
"fieldname": "billed_amt",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Billed Amt",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "billed_qty",
|
||||
"oldfieldtype": "Currency",
|
||||
"options": "currency",
|
||||
"print_hide": 1,
|
||||
"print_width": "100px",
|
||||
"read_only": 1,
|
||||
"width": "100px"
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
|
@ -19,9 +19,9 @@ import webnotes
|
||||
from webnotes.utils import load_json, cstr, flt, now_datetime
|
||||
from webnotes.model.doc import addchild
|
||||
|
||||
from webnotes.model.controller import DocListController
|
||||
from controllers.status_updater import StatusUpdater
|
||||
|
||||
class TransactionBase(DocListController):
|
||||
class TransactionBase(StatusUpdater):
|
||||
def get_default_address_and_contact(self, party_type):
|
||||
"""get a dict of default field values of address and contact for a given party type
|
||||
party_type can be one of: customer, supplier"""
|
||||
|
Loading…
x
Reference in New Issue
Block a user