Billing status in Purchase Receipt
This commit is contained in:
parent
ba5d6b5004
commit
bdab0eea0f
@ -11,6 +11,7 @@ import frappe.defaults
|
||||
from erpnext.controllers.buying_controller import BuyingController
|
||||
from erpnext.accounts.party import get_party_account, get_due_date
|
||||
from erpnext.accounts.utils import get_account_currency
|
||||
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import update_billing_amount_based_on_po
|
||||
|
||||
form_grid_templates = {
|
||||
"items": "templates/form_grid/item_grid.html"
|
||||
@ -246,6 +247,7 @@ class PurchaseInvoice(BuyingController):
|
||||
self.update_against_document_in_jv()
|
||||
self.update_prevdoc_status()
|
||||
self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
|
||||
self.update_billing_status_in_pr()
|
||||
|
||||
self.update_project()
|
||||
|
||||
@ -407,6 +409,8 @@ class PurchaseInvoice(BuyingController):
|
||||
|
||||
self.update_prevdoc_status()
|
||||
self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
|
||||
self.update_billing_status_in_pr()
|
||||
|
||||
self.make_gl_entries_on_cancel()
|
||||
self.update_project()
|
||||
|
||||
@ -430,6 +434,18 @@ class PurchaseInvoice(BuyingController):
|
||||
"fiscal_year": self.fiscal_year, "name": ("!=", self.name), "docstatus": ("<", 2)})
|
||||
if pi:
|
||||
frappe.throw("Supplier Invoice No exists in Purchase Invoice {0}".format(pi))
|
||||
|
||||
def update_billing_status_in_pr(self, set_modified=True):
|
||||
updated_pr = []
|
||||
for d in self.get("items"):
|
||||
if d.pr_detail and not d.po_detail:
|
||||
frappe.db.set_value("Purchase Receipt Item", d.pr_detail, "billed_amt", d.amount)
|
||||
updated_pr.append(d.purchase_receipt)
|
||||
elif d.po_detail:
|
||||
updated_pr += update_billing_amount_based_on_po(d.po_detail)
|
||||
|
||||
for pr in set(updated_pr):
|
||||
frappe.get_doc("Purchase Receipt", pr).update_billing_percentage(set_modified=set_modified)
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_expense_account(doctype, txt, searchfield, start, page_len, filters):
|
||||
|
@ -12,8 +12,7 @@ from frappe.model.mapper import get_mapped_doc
|
||||
|
||||
from erpnext.controllers.selling_controller import SellingController
|
||||
from erpnext.accounts.utils import get_account_currency
|
||||
from erpnext.stock.doctype.delivery_note.delivery_note \
|
||||
import update_billing_amount_based_on_so, update_billing_percentage
|
||||
from erpnext.stock.doctype.delivery_note.delivery_note import update_billing_amount_based_on_so
|
||||
|
||||
form_grid_templates = {
|
||||
"items": "templates/form_grid/item_grid.html"
|
||||
@ -635,7 +634,7 @@ class SalesInvoice(SellingController):
|
||||
}, write_off_account_currency)
|
||||
)
|
||||
|
||||
def update_billing_status_in_dn(self):
|
||||
def update_billing_status_in_dn(self, set_modified=True):
|
||||
updated_delivery_notes = []
|
||||
for d in self.get("items"):
|
||||
if d.dn_detail and not d.so_detail:
|
||||
@ -645,7 +644,7 @@ class SalesInvoice(SellingController):
|
||||
updated_delivery_notes += update_billing_amount_based_on_so(d.so_detail)
|
||||
|
||||
for dn in set(updated_delivery_notes):
|
||||
update_billing_percentage(dn)
|
||||
frappe.get_doc("Delivery Note", dn).update_billing_percentage(set_modified=set_modified)
|
||||
|
||||
def get_list_context(context=None):
|
||||
from erpnext.controllers.website_list_for_contact import get_list_context
|
||||
|
@ -59,7 +59,8 @@ status_map = {
|
||||
],
|
||||
"Purchase Receipt": [
|
||||
["Draft", None],
|
||||
["Submitted", "eval:self.docstatus==1"],
|
||||
["To Bill", "eval:self.per_billed < 100 and self.docstatus == 1"],
|
||||
["Completed", "eval:self.per_billed == 100 and self.docstatus == 1"],
|
||||
["Cancelled", "eval:self.docstatus==2"],
|
||||
["Closed", "eval:self.status=='Closed'"],
|
||||
]
|
||||
@ -178,15 +179,10 @@ class StatusUpdater(Document):
|
||||
else:
|
||||
args['cond'] = ' and parent!="%s"' % self.name.replace('"', '\"')
|
||||
|
||||
args['set_modified'] = ''
|
||||
if change_modified:
|
||||
args['set_modified'] = ', modified = now(), modified_by = "{0}"'\
|
||||
.format(frappe.db.escape(frappe.session.user))
|
||||
|
||||
self._update_children(args)
|
||||
|
||||
if "percent_join_field" in args:
|
||||
self._update_percent_field(args)
|
||||
self._update_percent_field_in_targets(args, change_modified)
|
||||
|
||||
def _update_children(self, args):
|
||||
"""Update quantities or amount in child table"""
|
||||
@ -216,40 +212,47 @@ class StatusUpdater(Document):
|
||||
from `tab%(source_dt)s` where `%(join_field)s`="%(detail_id)s"
|
||||
and (docstatus=1 %(cond)s) %(extra_cond)s) %(second_source_condition)s
|
||||
where name='%(detail_id)s'""" % args)
|
||||
|
||||
def _update_percent_field(self, args):
|
||||
|
||||
def _update_percent_field_in_targets(self, args, change_modified=True):
|
||||
"""Update percent field in parent transaction"""
|
||||
unique_transactions = set([d.get(args['percent_join_field']) for d in self.get_all_children(args['source_dt'])])
|
||||
distinct_transactions = set([d.get(args['percent_join_field'])
|
||||
for d in self.get_all_children(args['source_dt'])])
|
||||
|
||||
for name in unique_transactions:
|
||||
if not name:
|
||||
continue
|
||||
for name in distinct_transactions:
|
||||
if name:
|
||||
args['name'] = name
|
||||
self._update_percent_field(args, change_modified)
|
||||
|
||||
args['name'] = name
|
||||
def _update_percent_field(self, args, change_modified=True):
|
||||
"""Update percent field in parent transaction"""
|
||||
|
||||
args['set_modified'] = ''
|
||||
if change_modified:
|
||||
args['set_modified'] = ', modified = now(), modified_by = "{0}"'\
|
||||
.format(frappe.db.escape(frappe.session.user))
|
||||
|
||||
if args.get('target_parent_field'):
|
||||
frappe.db.sql("""update `tab%(target_parent_dt)s`
|
||||
set %(target_parent_field)s = round(
|
||||
ifnull((select
|
||||
ifnull(sum(if(%(target_ref_field)s > %(target_field)s, %(target_field)s, %(target_ref_field)s)), 0)
|
||||
/ sum(%(target_ref_field)s) * 100
|
||||
from `tab%(target_dt)s` where parent="%(name)s"), 0), 2)
|
||||
%(set_modified)s
|
||||
where name='%(name)s'""" % args)
|
||||
|
||||
# update percent complete in the parent table
|
||||
if args.get('target_parent_field'):
|
||||
frappe.db.sql("""update `tab%(target_parent_dt)s`
|
||||
set %(target_parent_field)s = round(
|
||||
ifnull((select
|
||||
ifnull(sum(if(%(target_ref_field)s > %(target_field)s, %(target_field)s, %(target_ref_field)s)), 0)
|
||||
/ sum(%(target_ref_field)s) * 100
|
||||
from `tab%(target_dt)s` where parent="%(name)s"), 0), 2)
|
||||
%(set_modified)s
|
||||
where name='%(name)s'""" % args)
|
||||
# update field
|
||||
if args.get('status_field'):
|
||||
frappe.db.sql("""update `tab%(target_parent_dt)s`
|
||||
set %(status_field)s = if(%(target_parent_field)s<0.001,
|
||||
'Not %(keyword)s', if(%(target_parent_field)s>=99.99,
|
||||
'Fully %(keyword)s', 'Partly %(keyword)s'))
|
||||
where name='%(name)s'""" % args)
|
||||
|
||||
# update field
|
||||
if args.get('status_field'):
|
||||
frappe.db.sql("""update `tab%(target_parent_dt)s`
|
||||
set %(status_field)s = if(%(target_parent_field)s<0.001,
|
||||
'Not %(keyword)s', if(%(target_parent_field)s>=99.99,
|
||||
'Fully %(keyword)s', 'Partly %(keyword)s'))
|
||||
where name='%(name)s'""" % args)
|
||||
|
||||
if args.get("set_modified"):
|
||||
target = frappe.get_doc(args["target_parent_dt"], name)
|
||||
target.set_status(update=True)
|
||||
target.notify_update()
|
||||
if args.get("set_modified"):
|
||||
target = frappe.get_doc(args["target_parent_dt"], args["name"])
|
||||
target.set_status(update=True)
|
||||
target.notify_update()
|
||||
|
||||
def update_billing_status_for_zero_amount_refdoc(self, ref_dt):
|
||||
ref_fieldname = ref_dt.lower().replace(" ", "_")
|
||||
|
@ -312,6 +312,16 @@ class StockController(AccountsController):
|
||||
|
||||
for w in warehouses:
|
||||
validate_warehouse_company(w, self.company)
|
||||
|
||||
def update_billing_percentage(self, set_modified=True):
|
||||
self._update_percent_field({
|
||||
"target_dt": self.doctype + " Item",
|
||||
"target_parent_dt": self.doctype,
|
||||
"target_parent_field": "per_billed",
|
||||
"target_ref_field": "amount",
|
||||
"target_field": "billed_amt",
|
||||
"name": self.name,
|
||||
}, set_modified)
|
||||
|
||||
def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None,
|
||||
warehouse_account=None):
|
||||
|
@ -269,33 +269,19 @@ class DeliveryNote(SellingController):
|
||||
self.notify_update()
|
||||
clear_doctype_notifications(self)
|
||||
|
||||
def update_billing_status(self):
|
||||
def update_billing_status(self, set_modified=True):
|
||||
updated_delivery_notes = [self.name]
|
||||
for d in self.get("items"):
|
||||
if d.si_detail and not d.so_detail:
|
||||
d.billed_amt = d.amount
|
||||
frappe.db.set(d, 'billed_amt', d.amount)
|
||||
elif d.so_detail:
|
||||
updated_delivery_notes += update_billing_amount_based_on_so(d.so_detail)
|
||||
d.billed_amt = frappe.db.get_value("Delivery Note Item", d.name, "billed_amt")
|
||||
|
||||
for dn in set(updated_delivery_notes):
|
||||
update_billing_percentage(dn)
|
||||
dn_doc = self if (dn == self.name) else frappe.get_doc("Delivery Note", dn)
|
||||
dn_doc.update_billing_percentage(set_modified=set_modified)
|
||||
|
||||
self.load_from_db()
|
||||
|
||||
def update_billing_percentage(delivery_note, set_modified=True):
|
||||
frappe.db.sql("""update `tabDelivery Note`
|
||||
set per_billed = round(ifnull(
|
||||
(select ifnull(sum(if(amount > billed_amt, billed_amt, amount)), 0) * 100 / sum(amount)
|
||||
from `tabDelivery Note Item` where parent=%s), 0), 2)
|
||||
, modified = now(), modified_by = %s
|
||||
where name=%s""", (delivery_note, frappe.session.user, delivery_note))
|
||||
|
||||
if set_modified:
|
||||
dn = frappe.get_doc("Delivery Note", delivery_note)
|
||||
dn.set_status(update=True)
|
||||
dn.notify_update()
|
||||
|
||||
def update_billing_amount_based_on_so(so_detail):
|
||||
# Billed against Sales Order directly
|
||||
|
@ -1812,7 +1812,7 @@
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "status",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "\nDraft\nSubmitted\nCancelled\nClosed",
|
||||
"options": "\nDraft\nTo Bill\nCompleted\nCancelled\nClosed",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
@ -1930,6 +1930,30 @@
|
||||
"unique": 0,
|
||||
"width": "50%"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"fieldname": "per_billed",
|
||||
"fieldtype": "Percent",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "% Amount Billed",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
@ -2278,7 +2302,7 @@
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2015-12-17 16:18:48.969643",
|
||||
"modified": "2015-12-30 18:15:06.678001",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Purchase Receipt",
|
||||
|
@ -242,6 +242,8 @@ class PurchaseReceipt(BuyingController):
|
||||
|
||||
self.update_prevdoc_status()
|
||||
self.update_ordered_qty()
|
||||
|
||||
self.update_billing_status()
|
||||
|
||||
if not self.is_return:
|
||||
purchase_controller.update_last_purchase_rate(self, 1)
|
||||
@ -280,6 +282,8 @@ class PurchaseReceipt(BuyingController):
|
||||
self.update_prevdoc_status()
|
||||
# Must be called after updating received qty in PO
|
||||
self.update_ordered_qty()
|
||||
|
||||
self.update_billing_status()
|
||||
|
||||
if not self.is_return:
|
||||
pc_obj.update_last_purchase_rate(self, 0)
|
||||
@ -435,6 +439,55 @@ class PurchaseReceipt(BuyingController):
|
||||
self.set_status(update=True, status = status)
|
||||
self.notify_update()
|
||||
clear_doctype_notifications(self)
|
||||
|
||||
def update_billing_status(self, set_modified=True):
|
||||
updated_pr = [self.name]
|
||||
for d in self.get("items"):
|
||||
if d.prevdoc_detail_docname:
|
||||
updated_pr += update_billing_amount_based_on_po(d.prevdoc_detail_docname)
|
||||
d.billed_amt = frappe.db.get_value("Purchase Receipt Item", d.name, "billed_amt")
|
||||
|
||||
for pr in set(updated_pr):
|
||||
pr_doc = self if (pr == self.name) else frappe.get_doc("Purchase Receipt", pr)
|
||||
pr_doc.update_billing_percentage(set_modified=set_modified)
|
||||
|
||||
self.load_from_db()
|
||||
|
||||
def update_billing_amount_based_on_po(po_detail):
|
||||
# Billed against Sales Order directly
|
||||
billed_against_po = frappe.db.sql("""select sum(amount) from `tabPurchase Invoice Item`
|
||||
where po_detail=%s and (pr_detail is null or pr_detail = '') and docstatus=1""", po_detail)
|
||||
billed_against_po = billed_against_po and billed_against_po[0][0] or 0
|
||||
|
||||
# Get all Delivery Note Item rows against the Sales Order Item row
|
||||
pr_details = frappe.db.sql("""select pr_item.name, pr_item.amount, pr_item.parent
|
||||
from `tabPurchase Receipt Item` pr_item, `tabPurchase Receipt` pr
|
||||
where pr.name=pr_item.parent and pr_item.prevdoc_detail_docname=%s
|
||||
and pr.docstatus=1 and pr.is_return = 0
|
||||
order by pr.posting_date asc, pr.posting_time asc, pr.name asc""", po_detail, as_dict=1)
|
||||
|
||||
updated_pr = []
|
||||
for pr_item in pr_details:
|
||||
# Get billed amount directly against Purchase Receipt
|
||||
billed_amt_agianst_pr = frappe.db.sql("""select sum(amount) from `tabPurchase Invoice Item`
|
||||
where pr_detail=%s and docstatus=1""", pr_item.name)
|
||||
billed_amt_agianst_pr = billed_amt_agianst_pr and billed_amt_agianst_pr[0][0] or 0
|
||||
|
||||
# Distribute billed amount directly against PO between PRs based on FIFO
|
||||
if billed_against_po and billed_amt_agianst_pr < pr_item.amount:
|
||||
pending_to_bill = flt(pr_item.amount) - billed_amt_agianst_pr
|
||||
if pending_to_bill <= billed_against_po:
|
||||
billed_amt_agianst_pr += pending_to_bill
|
||||
billed_against_po -= pending_to_bill
|
||||
else:
|
||||
billed_amt_agianst_pr += billed_against_po
|
||||
billed_against_po = 0
|
||||
|
||||
frappe.db.set_value("Purchase Receipt Item", pr_item.name, "billed_amt", billed_amt_agianst_pr)
|
||||
|
||||
updated_pr.append(pr_item.parent)
|
||||
|
||||
return updated_pr
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_purchase_invoice(source_name, target_doc=None):
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user