commit
b1d8979a59
@ -38,7 +38,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
|
||||
get_query_filters: {
|
||||
supplier: cur_frm.doc.supplier || undefined,
|
||||
docstatus: 1,
|
||||
status: ["!=", "Stopped"],
|
||||
status: ["not in", ["Stopped", "Closed"]],
|
||||
per_billed: ["<", 99.99],
|
||||
company: cur_frm.doc.company
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ class PurchaseInvoice(BuyingController):
|
||||
self.check_conversion_rate()
|
||||
self.validate_credit_to_acc()
|
||||
self.clear_unallocated_advances("Purchase Invoice Advance", "advances")
|
||||
self.check_for_stopped_status()
|
||||
self.check_for_stopped_or_closed_status()
|
||||
self.validate_with_previous_doc()
|
||||
self.validate_uom_is_integer("uom", "qty")
|
||||
self.set_against_expense_account()
|
||||
@ -103,14 +103,14 @@ class PurchaseInvoice(BuyingController):
|
||||
|
||||
self.party_account_currency = account.account_currency
|
||||
|
||||
def check_for_stopped_status(self):
|
||||
def check_for_stopped_or_closed_status(self):
|
||||
check_list = []
|
||||
pc_obj = frappe.get_doc('Purchase Common')
|
||||
|
||||
for d in self.get('items'):
|
||||
if d.purchase_order and not d.purchase_order in check_list and not d.purchase_receipt:
|
||||
check_list.append(d.purchase_order)
|
||||
stopped = frappe.db.sql("select name from `tabPurchase Order` where status = 'Stopped' and name = %s", d.purchase_order)
|
||||
if stopped:
|
||||
throw(_("Purchase Order {0} is 'Stopped'").format(d.purchase_order))
|
||||
pc_obj.check_for_stopped_or_closed_status('Purchase Order', d.purchase_order)
|
||||
|
||||
def validate_with_previous_doc(self):
|
||||
super(PurchaseInvoice, self).validate_with_previous_doc({
|
||||
@ -394,6 +394,8 @@ class PurchaseInvoice(BuyingController):
|
||||
make_gl_entries(gl_entries, cancel=(self.docstatus == 2))
|
||||
|
||||
def on_cancel(self):
|
||||
self.check_for_stopped_or_closed_status()
|
||||
|
||||
if not self.is_return:
|
||||
from erpnext.accounts.utils import remove_against_link_from_jv
|
||||
remove_against_link_from_jv(self.doctype, self.name)
|
||||
|
@ -50,6 +50,13 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
if(doc.update_stock) this.show_stock_ledger();
|
||||
|
||||
if(doc.docstatus==1 && !doc.is_return) {
|
||||
|
||||
var is_delivered_by_supplier = false;
|
||||
|
||||
is_delivered_by_supplier = cur_frm.doc.items.some(function(item){
|
||||
return item.is_delivered_by_supplier ? true : false;
|
||||
})
|
||||
|
||||
cur_frm.add_custom_button(doc.update_stock ? __('Sales Return') : __('Credit Note'),
|
||||
this.make_sales_return);
|
||||
|
||||
@ -61,7 +68,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
return item.delivery_note ? true : false;
|
||||
});
|
||||
|
||||
if(!from_delivery_note) {
|
||||
if(!from_delivery_note && !is_delivered_by_supplier) {
|
||||
cur_frm.add_custom_button(__('Delivery'), cur_frm.cscript['Make Delivery Note']).addClass("btn-primary");
|
||||
}
|
||||
}
|
||||
@ -104,7 +111,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
source_doctype: "Sales Order",
|
||||
get_query_filters: {
|
||||
docstatus: 1,
|
||||
status: ["!=", "Stopped"],
|
||||
status: ["not in", ["Stopped", "Closed"]],
|
||||
per_billed: ["<", 99.99],
|
||||
customer: cur_frm.doc.customer || undefined,
|
||||
company: cur_frm.doc.company
|
||||
|
@ -65,7 +65,7 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Series",
|
||||
"label": "Series",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "naming_series",
|
||||
"oldfieldtype": "Select",
|
||||
@ -1168,7 +1168,7 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Apply Additional Discount On",
|
||||
"label": "Apply Additional Discount On",
|
||||
"no_copy": 0,
|
||||
"options": "\nGrand Total\nNet Total",
|
||||
"permlevel": 0,
|
||||
@ -2211,7 +2211,7 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Source",
|
||||
"label": "Source",
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "source",
|
||||
"oldfieldtype": "Select",
|
||||
@ -2308,7 +2308,7 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 1,
|
||||
"in_list_view": 0,
|
||||
"label": "Is Opening Entry",
|
||||
"label": "Is Opening Entry",
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "is_opening",
|
||||
"oldfieldtype": "Select",
|
||||
@ -2332,7 +2332,7 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "C-Form Applicable",
|
||||
"label": "C-Form Applicable",
|
||||
"no_copy": 1,
|
||||
"options": "No\nYes",
|
||||
"permlevel": 0,
|
||||
@ -2700,7 +2700,7 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Recurring Type",
|
||||
"label": "Recurring Type",
|
||||
"no_copy": 1,
|
||||
"options": "\nMonthly\nQuarterly\nHalf-yearly\nYearly",
|
||||
"permlevel": 0,
|
||||
@ -2951,7 +2951,7 @@
|
||||
"is_submittable": 1,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"modified": "2015-10-02 07:39:09.123982",
|
||||
"modified": "2015-10-26 12:12:40.616546",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice",
|
||||
|
@ -52,7 +52,7 @@ class SalesInvoice(SellingController):
|
||||
self.validate_proj_cust()
|
||||
self.validate_with_previous_doc()
|
||||
self.validate_uom_is_integer("stock_uom", "qty")
|
||||
self.check_stop_sales_order("sales_order")
|
||||
self.check_stop_or_close_sales_order("sales_order")
|
||||
self.validate_debit_to_acc()
|
||||
self.validate_fixed_asset_account()
|
||||
self.clear_unallocated_advances("Sales Invoice Advance", "advances")
|
||||
@ -117,7 +117,7 @@ class SalesInvoice(SellingController):
|
||||
if cint(self.update_stock) == 1:
|
||||
self.update_stock_ledger()
|
||||
|
||||
self.check_stop_sales_order("sales_order")
|
||||
self.check_stop_or_close_sales_order("sales_order")
|
||||
|
||||
from erpnext.accounts.utils import remove_against_link_from_jv
|
||||
remove_against_link_from_jv(self.doctype, self.name)
|
||||
@ -667,7 +667,8 @@ def make_delivery_note(source_name, target_doc=None):
|
||||
"sales_order": "against_sales_order",
|
||||
"so_detail": "so_detail"
|
||||
},
|
||||
"postprocess": update_item
|
||||
"postprocess": update_item,
|
||||
"condition": lambda doc: doc.delivered_by_supplier!=1
|
||||
},
|
||||
"Sales Taxes and Charges": {
|
||||
"doctype": "Sales Taxes and Charges",
|
||||
|
@ -680,6 +680,51 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
"collapsible_depends_on": "eval:doc.delivered_by_supplier==1",
|
||||
"fieldname": "drop_ship",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Drop Ship",
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"fieldname": "delivered_by_supplier",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Delivered By Supplier",
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"read_only": 1,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
@ -1282,7 +1327,7 @@
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"modified": "2015-10-19 03:04:52.093181",
|
||||
"modified": "2015-11-02 15:14:02.306067",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice Item",
|
||||
|
@ -80,12 +80,12 @@ class PurchaseCommon(BuyingController):
|
||||
frappe.msgprint(_("Warning: Same item has been entered multiple times."))
|
||||
|
||||
|
||||
def check_for_stopped_status(self, doctype, docname):
|
||||
stopped = frappe.db.sql("""select name from `tab%s` where name = %s and
|
||||
status = 'Stopped'""" % (doctype, '%s'), docname)
|
||||
if stopped:
|
||||
frappe.throw(_("{0} {1} status is 'Stopped'").format(doctype, docname), frappe.InvalidStatusError)
|
||||
|
||||
def check_for_stopped_or_closed_status(self, doctype, docname):
|
||||
status = frappe.db.get_value(doctype, docname, "status")
|
||||
|
||||
if status in ("Stopped", "Closed"):
|
||||
frappe.throw(_("{0} {1} status is {2}").format(doctype, docname, status), frappe.InvalidStatusError)
|
||||
|
||||
def check_docstatus(self, check, doctype, docname, detail_doctype = ''):
|
||||
if check == 'Next':
|
||||
submitted = frappe.db.sql("""select t1.name from `tab%s` t1,`tab%s` t2
|
||||
|
@ -19,11 +19,17 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
||||
this._super();
|
||||
// this.frm.dashboard.reset();
|
||||
|
||||
if(doc.docstatus == 1 && doc.status != 'Stopped') {
|
||||
if(doc.docstatus == 1 && doc.status != 'Stopped' && doc.status != 'Closed') {
|
||||
|
||||
if(flt(doc.per_billed, 2) < 100 || doc.per_received < 100)
|
||||
cur_frm.add_custom_button(__('Stop'), cur_frm.cscript['Stop Purchase Order']);
|
||||
cur_frm.add_custom_button(__('Stop'), this.stop_purchase_order);
|
||||
|
||||
cur_frm.add_custom_button(__('Close'), this.close_purchase_order);
|
||||
|
||||
if(doc.delivered_by_supplier && doc.status!="Delivered"){
|
||||
cur_frm.add_custom_button(__('Delivered By Supplier'), this.delivered_by_supplier);
|
||||
}
|
||||
|
||||
if(flt(doc.per_billed)==0) {
|
||||
cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_bank_entry);
|
||||
}
|
||||
@ -46,7 +52,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
||||
}
|
||||
|
||||
if(doc.docstatus == 1 && doc.status == 'Stopped')
|
||||
cur_frm.add_custom_button(__('Unstop'), cur_frm.cscript['Unstop Purchase Order']);
|
||||
cur_frm.add_custom_button(__('Unstop'), this.unstop_purchase_order);
|
||||
},
|
||||
|
||||
make_stock_entry: function() {
|
||||
@ -156,6 +162,29 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
||||
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
|
||||
}
|
||||
});
|
||||
},
|
||||
stop_purchase_order: function(){
|
||||
cur_frm.cscript.update_status('Stop', 'Stopped')
|
||||
},
|
||||
unstop_purchase_order: function(){
|
||||
cur_frm.cscript.update_status('Resume', 'Submitted')
|
||||
},
|
||||
close_purchase_order: function(){
|
||||
cur_frm.cscript.update_status('Close', 'Closed')
|
||||
},
|
||||
delivered_by_supplier: function(){
|
||||
return frappe.call({
|
||||
method: "erpnext.buying.doctype.purchase_order.purchase_order.delivered_by_supplier",
|
||||
freeze: true,
|
||||
args:{
|
||||
purchase_order: cur_frm.doc.name
|
||||
},
|
||||
callback:function(r){
|
||||
if(!r.exc) {
|
||||
cur_frm.reload_doc();
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
});
|
||||
@ -163,6 +192,22 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
||||
// for backward compatibility: combine new and previous states
|
||||
$.extend(cur_frm.cscript, new erpnext.buying.PurchaseOrderController({frm: cur_frm}));
|
||||
|
||||
cur_frm.cscript.update_status= function(label, status){
|
||||
var doc = cur_frm.doc;
|
||||
var check = confirm(__("Do you really want to {0} {1}",[label, doc.name]));
|
||||
|
||||
if (check) {
|
||||
frappe.call({
|
||||
method: "erpnext.buying.doctype.purchase_order.purchase_order.update_status",
|
||||
args:{status: status, name: doc.name},
|
||||
callback:function(r){
|
||||
cur_frm.set_value("status", status);
|
||||
cur_frm.reload_doc();
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.fields_dict['supplier_address'].get_query = function(doc, cdt, cdn) {
|
||||
return {
|
||||
filters: {'supplier': doc.supplier}
|
||||
@ -202,28 +247,6 @@ cur_frm.cscript.get_last_purchase_rate = function(doc, cdt, cdn){
|
||||
});
|
||||
}
|
||||
|
||||
cur_frm.cscript['Stop Purchase Order'] = function() {
|
||||
var doc = cur_frm.doc;
|
||||
var check = confirm(__("Do you really want to STOP ") + doc.name);
|
||||
|
||||
if (check) {
|
||||
return $c('runserverobj', args={'method':'update_status', 'arg': 'Stopped', 'docs':doc}, function(r,rt) {
|
||||
cur_frm.refresh();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.cscript['Unstop Purchase Order'] = function() {
|
||||
var doc = cur_frm.doc;
|
||||
var check = confirm(__("Do you really want to UNSTOP ") + doc.name);
|
||||
|
||||
if (check) {
|
||||
return $c('runserverobj', args={'method':'update_status', 'arg': 'Submitted', 'docs':doc}, function(r,rt) {
|
||||
cur_frm.refresh();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.pformat.indent_no = function(doc, cdt, cdn){
|
||||
//function to make row of table
|
||||
|
||||
|
@ -147,6 +147,53 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"depends_on": "eval:doc.delivered_by_supplier==1",
|
||||
"fieldname": "customer",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Customer",
|
||||
"no_copy": 0,
|
||||
"options": "Customer",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"read_only": 1,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"depends_on": "eval:doc.delivered_by_supplier==1",
|
||||
"fieldname": "customer_name",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Customer Name",
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"read_only": 1,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
@ -168,6 +215,28 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"fieldname": "customer_address_display",
|
||||
"fieldtype": "Small Text",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Customer Address",
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
@ -189,6 +258,28 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"fieldname": "customer_contact_display",
|
||||
"fieldtype": "Small Text",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Customer Contact",
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
@ -210,6 +301,28 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"fieldname": "customer_contact_mobile",
|
||||
"fieldtype": "Small Text",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Customer Mobile No",
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
@ -231,6 +344,28 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"fieldname": "customer_contact_email",
|
||||
"fieldtype": "Small Text",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Customer Contact Email",
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
@ -326,6 +461,28 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"fieldname": "delivered_by_supplier",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Delivered By Supplier",
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"read_only": 1,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
@ -1479,7 +1636,7 @@
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "status",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "\nDraft\nTo Receive and Bill\nTo Bill\nTo Receive\nCompleted\nStopped\nCancelled",
|
||||
"options": "\nDraft\nTo Receive and Bill\nTo Bill\nTo Receive\nCompleted\nStopped\nCancelled\nClosed\nDelivered",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 1,
|
||||
@ -2033,7 +2190,7 @@
|
||||
"is_submittable": 1,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"modified": "2015-10-16 06:13:50.058318",
|
||||
"modified": "2015-10-29 16:41:30.749753",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Purchase Order",
|
||||
|
@ -39,7 +39,7 @@ class PurchaseOrder(BuyingController):
|
||||
self.set_status()
|
||||
pc_obj = frappe.get_doc('Purchase Common')
|
||||
pc_obj.validate_for_items(self)
|
||||
self.check_for_stopped_status(pc_obj)
|
||||
self.check_for_stopped_or_closed_status(pc_obj)
|
||||
|
||||
self.validate_uom_is_integer("uom", "qty")
|
||||
self.validate_uom_is_integer("stock_uom", ["qty", "required_qty"])
|
||||
@ -108,12 +108,12 @@ class PurchaseOrder(BuyingController):
|
||||
= d.rate = item_last_purchase_rate
|
||||
|
||||
# Check for Stopped status
|
||||
def check_for_stopped_status(self, pc_obj):
|
||||
def check_for_stopped_or_closed_status(self, pc_obj):
|
||||
check_list =[]
|
||||
for d in self.get('items'):
|
||||
if d.meta.get_field('prevdoc_docname') and d.prevdoc_docname and d.prevdoc_docname not in check_list:
|
||||
check_list.append(d.prevdoc_docname)
|
||||
pc_obj.check_for_stopped_status( d.prevdoc_doctype, d.prevdoc_docname)
|
||||
pc_obj.check_for_stopped_or_closed_status( d.prevdoc_doctype, d.prevdoc_docname)
|
||||
|
||||
def update_requested_qty(self):
|
||||
material_request_map = {}
|
||||
@ -162,6 +162,9 @@ class PurchaseOrder(BuyingController):
|
||||
clear_doctype_notifications(self)
|
||||
|
||||
def on_submit(self):
|
||||
if self.delivered_by_supplier == 1:
|
||||
self.update_status_updater()
|
||||
|
||||
super(PurchaseOrder, self).on_submit()
|
||||
|
||||
purchase_controller = frappe.get_doc("Purchase Common")
|
||||
@ -176,8 +179,11 @@ class PurchaseOrder(BuyingController):
|
||||
purchase_controller.update_last_purchase_rate(self, is_submit = 1)
|
||||
|
||||
def on_cancel(self):
|
||||
if self.delivered_by_supplier == 1:
|
||||
self.update_status_updater()
|
||||
|
||||
pc_obj = frappe.get_doc('Purchase Common')
|
||||
self.check_for_stopped_status(pc_obj)
|
||||
self.check_for_stopped_or_closed_status(pc_obj)
|
||||
|
||||
# Check if Purchase Receipt has been submitted against current Purchase Order
|
||||
pc_obj.check_docstatus(check = 'Next', doctype = 'Purchase Receipt', docname = self.name, detail_doctype = 'Purchase Receipt Item')
|
||||
@ -213,7 +219,15 @@ class PurchaseOrder(BuyingController):
|
||||
for field in ("received_qty", "billed_amt", "prevdoc_doctype", "prevdoc_docname",
|
||||
"prevdoc_detail_docname", "supplier_quotation", "supplier_quotation_item"):
|
||||
d.set(field, None)
|
||||
|
||||
|
||||
def update_status_updater(self):
|
||||
self.status_updater[0].update({
|
||||
"target_parent_dt": "Sales Order",
|
||||
"target_dt": "Sales Order Item",
|
||||
'target_field': 'ordered_qty',
|
||||
"target_parent_field": ''
|
||||
})
|
||||
|
||||
@frappe.whitelist()
|
||||
def stop_or_unstop_purchase_orders(names, status):
|
||||
if not frappe.has_permission("Purchase Order", "write"):
|
||||
@ -223,9 +237,9 @@ def stop_or_unstop_purchase_orders(names, status):
|
||||
for name in names:
|
||||
po = frappe.get_doc("Purchase Order", name)
|
||||
if po.docstatus == 1:
|
||||
if status=="Stopped":
|
||||
if po.status not in ("Stopped", "Cancelled") and (po.per_received < 100 or po.per_billed < 100):
|
||||
po.update_status("Stopped")
|
||||
if status in ("Stopped", "Closed"):
|
||||
if po.status not in ("Stopped", "Cancelled", "Closed") and (po.per_received < 100 or po.per_billed < 100):
|
||||
po.update_status(status)
|
||||
else:
|
||||
if po.status == "Stopped":
|
||||
po.update_status("Draft")
|
||||
@ -325,3 +339,27 @@ def make_stock_entry(purchase_order, item_code):
|
||||
stock_entry.bom_no = po_item.bom
|
||||
stock_entry.get_items()
|
||||
return stock_entry.as_dict()
|
||||
|
||||
@frappe.whitelist()
|
||||
def update_status(status, name):
|
||||
po = frappe.get_doc("Purchase Order", name)
|
||||
po.update_status(status)
|
||||
|
||||
@frappe.whitelist()
|
||||
def delivered_by_supplier(purchase_order):
|
||||
po = frappe.get_doc("Purchase Order", purchase_order)
|
||||
update_delivered_qty(po)
|
||||
po.update_status("Delivered")
|
||||
|
||||
def update_delivered_qty(purchase_order):
|
||||
sales_order_list = []
|
||||
so_name = ''
|
||||
for item in purchase_order.items:
|
||||
if item.prevdoc_doctype == "Sales Order":
|
||||
so_name = item.prevdoc_docname
|
||||
|
||||
so = frappe.get_doc("Sales Order", so_name)
|
||||
so.update_delivery_status(purchase_order.name)
|
||||
so.set_status(update=True)
|
||||
so.notify_update()
|
||||
|
@ -4,7 +4,11 @@ frappe.listview_settings['Purchase Order'] = {
|
||||
get_indicator: function(doc) {
|
||||
if(doc.status==="Stopped") {
|
||||
return [__("Stopped"), "darkgrey", "status,=,Stopped"];
|
||||
} else if(flt(doc.per_received, 2) < 100 && doc.status!=="Stopped") {
|
||||
} else if(doc.status==="Closed"){
|
||||
return [__("Closed"), "green", "status,=,Closed"];
|
||||
} else if (doc.status==="Delivered") {
|
||||
return [__("Delivered"), "green", "status,=,Closed"];
|
||||
}else if(flt(doc.per_received, 2) < 100 && doc.status!=="Stopped") {
|
||||
if(flt(doc.per_billed, 2) < 100) {
|
||||
return [__("To Receive and Bill"), "orange",
|
||||
"per_received,<,100|per_billed,<,100|status,!=,Stopped"];
|
||||
@ -28,6 +32,9 @@ frappe.listview_settings['Purchase Order'] = {
|
||||
listview.page.add_menu_item(__("Set as Unstopped"), function() {
|
||||
listview.call_for_selected_items(method, {"status": "Submitted"});
|
||||
});
|
||||
|
||||
|
||||
listview.page.add_menu_item(__("Set as Closed"), function() {
|
||||
listview.call_for_selected_items(method, {"status": "Closed"});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -70,6 +70,20 @@ class TestPurchaseOrder(unittest.TestCase):
|
||||
from erpnext.utilities.transaction_base import UOMMustBeIntegerError
|
||||
po = create_purchase_order(qty=3.4, do_not_save=True)
|
||||
self.assertRaises(UOMMustBeIntegerError, po.insert)
|
||||
|
||||
def test_ordered_qty_for_closing_po(self):
|
||||
bin = frappe.get_all("Bin", filters={"item_code": "_Test Item", "warehouse": "_Test Warehouse - _TC"},
|
||||
fields=["ordered_qty"])
|
||||
|
||||
existing_ordered_qty = bin[0].ordered_qty if bin else 0.0
|
||||
|
||||
po = create_purchase_order(item_code= "_Test Item", qty=1)
|
||||
|
||||
self.assertEquals(get_ordered_qty(item_code= "_Test Item", warehouse="_Test Warehouse - _TC"), existing_ordered_qty+1)
|
||||
|
||||
po.update_status("Closed")
|
||||
|
||||
self.assertEquals(get_ordered_qty(item_code="_Test Item", warehouse="_Test Warehouse - _TC"), existing_ordered_qty)
|
||||
|
||||
def create_purchase_order(**args):
|
||||
po = frappe.new_doc("Purchase Order")
|
||||
|
@ -848,7 +848,7 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"fieldname": "prevdoc_doctype",
|
||||
"fieldtype": "Data",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
@ -857,6 +857,7 @@
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "prevdoc_doctype",
|
||||
"oldfieldtype": "Data",
|
||||
"options": "DocType",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 1,
|
||||
@ -871,16 +872,16 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"fieldname": "prevdoc_docname",
|
||||
"fieldtype": "Link",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 1,
|
||||
"in_list_view": 0,
|
||||
"label": "Material Request No",
|
||||
"label": "Reference Name",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "prevdoc_docname",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Material Request",
|
||||
"options": "prevdoc_doctype",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_width": "120px",
|
||||
|
0
erpnext/buying/print_format/__init__.py
Normal file
0
erpnext/buying/print_format/__init__.py
Normal file
17
erpnext/buying/print_format/drop_shipping/drop_shipping.json
Normal file
17
erpnext/buying/print_format/drop_shipping/drop_shipping.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"creation": "2015-10-20 16:46:39.382799",
|
||||
"custom_format": 0,
|
||||
"disabled": 0,
|
||||
"doc_type": "Purchase Order",
|
||||
"docstatus": 0,
|
||||
"doctype": "Print Format",
|
||||
"font": "Default",
|
||||
"format_data": "[{\"fieldname\": \"print_heading_template\", \"fieldtype\": \"HTML\", \"options\": \"<h1 style=\\\"text-align: center;\\\">Purchase Order</h1><div style=\\\"text-align: center;\\\">{{doc.name}}</div><div style=\\\"text-align: center;\\\"><hr></div>\"}, {\"fieldtype\": \"Section Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"title\"}, {\"print_hide\": 0, \"fieldname\": \"supplier\"}, {\"print_hide\": 0, \"fieldname\": \"supplier_name\"}, {\"print_hide\": 0, \"fieldname\": \"address_display\"}, {\"print_hide\": 0, \"fieldname\": \"contact_display\"}, {\"print_hide\": 0, \"fieldname\": \"contact_mobile\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"transaction_date\"}, {\"print_hide\": 0, \"fieldname\": \"customer\"}, {\"print_hide\": 0, \"fieldname\": \"customer_name\"}, {\"print_hide\": 0, \"fieldname\": \"customer_address_display\"}, {\"print_hide\": 0, \"fieldname\": \"customer_contact_display\"}, {\"print_hide\": 0, \"fieldname\": \"customer_contact_mobile\"}, {\"fieldtype\": \"Section Break\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"item_code\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"description\", \"print_width\": \"300px\"}, {\"print_hide\": 0, \"fieldname\": \"image\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"qty\", \"print_width\": \"60px\"}, {\"print_hide\": 0, \"fieldname\": \"uom\", \"print_width\": \"100px\"}, {\"print_hide\": 0, \"fieldname\": \"discount_percentage\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"rate\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"amount\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"pricing_rule\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"supplier_quotation\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"supplier_quotation_item\", \"print_width\": \"\"}], \"print_hide\": 0, \"fieldname\": \"items\"}, {\"print_hide\": 0, \"fieldname\": \"get_last_purchase_rate\"}, {\"fieldtype\": \"Section Break\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"total\"}, {\"fieldtype\": \"Section Break\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"category\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"add_deduct_tax\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"charge_type\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"row_id\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"included_in_print_rate\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"account_head\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"cost_center\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"description\", \"print_width\": \"300px\"}, {\"print_hide\": 0, \"fieldname\": \"rate\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"tax_amount\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"total\", \"print_width\": \"\"}], \"print_hide\": 0, \"fieldname\": \"taxes\"}, {\"fieldtype\": \"Section Break\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"grand_total\"}, {\"print_hide\": 0, \"fieldname\": \"in_words\"}, {\"fieldtype\": \"Section Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"terms\"}, {\"fieldtype\": \"Section Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"customer_contact_person\"}, {\"fieldtype\": \"Section Break\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"recurring_print_format\"}]",
|
||||
"modified": "2015-10-20 17:21:45.810640",
|
||||
"modified_by": "saurabh@erpnext.com",
|
||||
"name": "Drop Shipping",
|
||||
"owner": "Administrator",
|
||||
"print_format_builder": 1,
|
||||
"print_format_type": "Server",
|
||||
"standard": "No"
|
||||
}
|
2
erpnext/change_log/current/drop-ship.md
Normal file
2
erpnext/change_log/current/drop-ship.md
Normal file
@ -0,0 +1,2 @@
|
||||
- **Drop Ship**
|
||||
- Make Sales Order with mrked item as **_Delivered By Supplier_** and submit SO and then make a Purchase Order.
|
@ -219,12 +219,12 @@ class SellingController(StockController):
|
||||
so_warehouse = so_item and so_item[0]["warehouse"] or ""
|
||||
return so_qty, so_warehouse
|
||||
|
||||
def check_stop_sales_order(self, ref_fieldname):
|
||||
def check_stop_or_close_sales_order(self, ref_fieldname):
|
||||
for d in self.get("items"):
|
||||
if d.get(ref_fieldname):
|
||||
status = frappe.db.get_value("Sales Order", d.get(ref_fieldname), "status")
|
||||
if status == "Stopped":
|
||||
frappe.throw(_("Sales Order {0} is stopped").format(d.get(ref_fieldname)))
|
||||
if status in ("Stopped", "Closed"):
|
||||
frappe.throw(_("Sales Order {0} is {1}").format(d.get(ref_fieldname), status))
|
||||
|
||||
def check_active_sales_items(obj):
|
||||
for d in obj.get("items"):
|
||||
|
@ -37,6 +37,7 @@ status_map = {
|
||||
["Completed", "eval:self.order_type == 'Maintenance' and self.per_billed == 100 and self.docstatus == 1"],
|
||||
["Stopped", "eval:self.status=='Stopped'"],
|
||||
["Cancelled", "eval:self.docstatus==2"],
|
||||
["Closed", "eval:self.status=='Closed'"],
|
||||
],
|
||||
"Purchase Order": [
|
||||
["Draft", None],
|
||||
@ -44,8 +45,10 @@ status_map = {
|
||||
["To Bill", "eval:self.per_received == 100 and self.per_billed < 100 and self.docstatus == 1"],
|
||||
["To Receive", "eval:self.per_received < 100 and self.per_billed == 100 and self.docstatus == 1"],
|
||||
["Completed", "eval:self.per_received == 100 and self.per_billed == 100 and self.docstatus == 1"],
|
||||
["Delivered", "eval:self.status=='Delivered'"],
|
||||
["Stopped", "eval:self.status=='Stopped'"],
|
||||
["Cancelled", "eval:self.docstatus==2"],
|
||||
["Closed", "eval:self.status=='Closed'"],
|
||||
],
|
||||
"Delivery Note": [
|
||||
["Draft", None],
|
||||
@ -170,11 +173,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:
|
||||
|
@ -735,7 +735,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
var valid = true;
|
||||
|
||||
$.each(["company", "customer"], function(i, fieldname) {
|
||||
if(frappe.meta.has_field(me.frm.doc.doctype, fieldname)) {
|
||||
if(frappe.meta.has_field(me.frm.doc.doctype, fieldname && me.frm.doc.doctype != "Purchase Order")) {
|
||||
if (!me.frm.doc[fieldname]) {
|
||||
msgprint(__("Please specify") + ": " +
|
||||
frappe.meta.get_label(me.frm.doc.doctype, fieldname, me.frm.doc.name) +
|
||||
|
@ -7,7 +7,7 @@ erpnext.utils.get_party_details = function(frm, method, args, callback) {
|
||||
method = "erpnext.accounts.party.get_party_details";
|
||||
}
|
||||
if(!args) {
|
||||
if(frm.doc.customer) {
|
||||
if(frm.doctype != "Purchase Order" && frm.doc.customer) {
|
||||
args = {
|
||||
party: frm.doc.customer,
|
||||
party_type: "Customer",
|
||||
@ -53,7 +53,7 @@ erpnext.utils.get_address_display = function(frm, address_field, display_field)
|
||||
if(frm.updating_party_details) return;
|
||||
|
||||
if(!address_field) {
|
||||
if(frm.doc.customer) {
|
||||
if(frm.doctype != "Purchase Order" && frm.doc.customer) {
|
||||
address_field = "customer_address";
|
||||
} else if(frm.doc.supplier) {
|
||||
address_field = "supplier_address";
|
||||
|
@ -15,9 +15,22 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
refresh: function(doc, dt, dn) {
|
||||
this._super();
|
||||
this.frm.dashboard.reset();
|
||||
|
||||
var is_delivered_by_supplier = false;
|
||||
var is_delivery_note = false;
|
||||
|
||||
if(doc.docstatus==1) {
|
||||
if(doc.status != 'Stopped') {
|
||||
if(doc.status != 'Stopped' && doc.status != 'Closed') {
|
||||
|
||||
$.each(cur_frm.doc.items, function(i, item){
|
||||
if(item.delivered_by_supplier == 1 || item.supplier){
|
||||
if(item.qty > item.ordered_qty)
|
||||
is_delivered_by_supplier = true;
|
||||
}
|
||||
else{
|
||||
if(item.qty > item.delivered_qty)
|
||||
is_delivery_note = true;
|
||||
}
|
||||
})
|
||||
|
||||
// cur_frm.dashboard.add_progress(cint(doc.per_delivered) + __("% Delivered"),
|
||||
// doc.per_delivered);
|
||||
@ -25,7 +38,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
// doc.per_billed);
|
||||
|
||||
// indent
|
||||
if(!doc.order_type || ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1)
|
||||
if(!doc.order_type || ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1 && flt(doc.per_delivered, 2) < 100 && !is_delivered_by_supplier)
|
||||
cur_frm.add_custom_button(__('Material Request'), this.make_material_request);
|
||||
|
||||
if(flt(doc.per_billed)==0) {
|
||||
@ -33,27 +46,35 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
}
|
||||
|
||||
// stop
|
||||
if(flt(doc.per_delivered, 2) < 100 || doc.per_billed < 100)
|
||||
cur_frm.add_custom_button(__('Stop'), cur_frm.cscript['Stop Sales Order'])
|
||||
|
||||
// maintenance
|
||||
if(flt(doc.per_delivered, 2) < 100 && ["Sales", "Shopping Cart"].indexOf(doc.order_type)===-1) {
|
||||
cur_frm.add_custom_button(__('Maint. Visit'), this.make_maintenance_visit);
|
||||
cur_frm.add_custom_button(__('Maint. Schedule'), this.make_maintenance_schedule);
|
||||
if(flt(doc.per_delivered, 2) < 100 || flt(doc.per_billed) < 100) {
|
||||
cur_frm.add_custom_button(__('Stop'), this.stop_sales_order)
|
||||
}
|
||||
|
||||
|
||||
cur_frm.add_custom_button(__('Close'), this.close_sales_order)
|
||||
|
||||
// delivery note
|
||||
if(flt(doc.per_delivered, 2) < 100 && ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1)
|
||||
cur_frm.add_custom_button(__('Delivery'), this.make_delivery_note).addClass("btn-primary");
|
||||
// maintenance
|
||||
if(flt(doc.per_delivered, 2) < 100 && ["Sales", "Shopping Cart"].indexOf(doc.order_type)===-1) {
|
||||
cur_frm.add_custom_button(__('Maint. Visit'), this.make_maintenance_visit);
|
||||
cur_frm.add_custom_button(__('Maint. Schedule'), this.make_maintenance_schedule);
|
||||
}
|
||||
|
||||
// sales invoice
|
||||
if(flt(doc.per_billed, 2) < 100) {
|
||||
cur_frm.add_custom_button(__('Invoice'), this.make_sales_invoice).addClass("btn-primary");
|
||||
}
|
||||
// delivery note
|
||||
if(flt(doc.per_delivered, 2) < 100 && ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1 && is_delivery_note)
|
||||
cur_frm.add_custom_button(__('Delivery'), this.make_delivery_note).addClass("btn-primary");
|
||||
|
||||
// sales invoice
|
||||
if(flt(doc.per_billed, 2) < 100) {
|
||||
cur_frm.add_custom_button(__('Invoice'), this.make_sales_invoice).addClass("btn-primary");
|
||||
}
|
||||
|
||||
if(flt(doc.per_delivered, 2) < 100 && is_delivered_by_supplier)
|
||||
cur_frm.add_custom_button(__('Make Purchase Order'), cur_frm.cscript.make_purchase_order).addClass("btn-primary");
|
||||
|
||||
} else {
|
||||
// un-stop
|
||||
cur_frm.add_custom_button(__('Unstop'), cur_frm.cscript['Unstop Sales Order']);
|
||||
if( doc.status != 'Closed')
|
||||
cur_frm.add_custom_button(__('Unstop'), cur_frm.cscript['Unstop Sales Order']);
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,6 +167,49 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
|
||||
}
|
||||
});
|
||||
},
|
||||
make_purchase_order: function(){
|
||||
var dialog = new frappe.ui.Dialog({
|
||||
title: __("For Supplier"),
|
||||
fields: [
|
||||
{"fieldtype": "Link", "label": __("Supplier"), "fieldname": "supplier", "options":"Supplier",
|
||||
"get_query": function () {
|
||||
return {
|
||||
query:"erpnext.selling.doctype.sales_order.sales_order.get_supplier",
|
||||
filters: {'parent': cur_frm.doc.name}
|
||||
}
|
||||
}, "reqd": 1 },
|
||||
{"fieldtype": "Button", "label": __("Make Purchase Order"), "fieldname": "make_purchase_order"},
|
||||
]
|
||||
});
|
||||
|
||||
dialog.fields_dict.make_purchase_order.$input.click(function() {
|
||||
args = dialog.get_values();
|
||||
if(!args) return;
|
||||
dialog.hide();
|
||||
return frappe.call({
|
||||
type: "GET",
|
||||
method: "erpnext.selling.doctype.sales_order.sales_order.make_purchase_order_for_drop_shipment",
|
||||
args: {
|
||||
"source_name": cur_frm.doc.name,
|
||||
"for_supplier": args.supplier
|
||||
},
|
||||
freeze: true,
|
||||
callback: function(r) {
|
||||
if(!r.exc) {
|
||||
var doc = frappe.model.sync(r.message);
|
||||
frappe.set_route("Form", r.message.doctype, r.message.name);
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
dialog.show();
|
||||
},
|
||||
stop_sales_order: function(){
|
||||
cur_frm.cscript.update_status("Stop", "Stopped")
|
||||
},
|
||||
close_sales_order: function(){
|
||||
cur_frm.cscript.update_status("Close", "Closed")
|
||||
}
|
||||
|
||||
});
|
||||
@ -169,18 +233,18 @@ cur_frm.fields_dict['project_name'].get_query = function(doc, cdt, cdn) {
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.cscript['Stop Sales Order'] = function() {
|
||||
cur_frm.cscript.update_status = function(label, status){
|
||||
var doc = cur_frm.doc;
|
||||
|
||||
var check = confirm(__("Are you sure you want to STOP ") + doc.name);
|
||||
|
||||
var check = confirm(__("Do you really want to {0} {1}",[label, doc.name]));
|
||||
|
||||
if (check) {
|
||||
return $c('runserverobj', {
|
||||
'method':'stop_sales_order',
|
||||
'docs': doc
|
||||
}, function(r,rt) {
|
||||
cur_frm.refresh();
|
||||
});
|
||||
frappe.call({
|
||||
method: "erpnext.selling.doctype.sales_order.sales_order.update_status",
|
||||
args:{status: status, name: doc.name},
|
||||
callback:function(r){
|
||||
cur_frm.reload_doc();
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,7 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Series",
|
||||
"label": "Series",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "naming_series",
|
||||
"oldfieldtype": "Select",
|
||||
@ -234,13 +234,14 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"default": "Sales",
|
||||
"depends_on": "",
|
||||
"fieldname": "order_type",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Order Type",
|
||||
"label": "Order Type",
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "order_type",
|
||||
"oldfieldtype": "Select",
|
||||
@ -381,6 +382,7 @@
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"depends_on": "",
|
||||
"description": "",
|
||||
"fieldname": "po_no",
|
||||
"fieldtype": "Data",
|
||||
@ -1134,7 +1136,7 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Apply Additional Discount On",
|
||||
"label": "Apply Additional Discount On",
|
||||
"no_copy": 0,
|
||||
"options": "\nGrand Total\nNet Total",
|
||||
"permlevel": 0,
|
||||
@ -1808,7 +1810,7 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Source",
|
||||
"label": "Source",
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "source",
|
||||
"oldfieldtype": "Select",
|
||||
@ -1973,11 +1975,11 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "Status",
|
||||
"label": "Status",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "status",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "\nDraft\nTo Deliver and Bill\nTo Bill\nTo Deliver\nCompleted\nStopped\nCancelled",
|
||||
"options": "\nDraft\nTo Deliver and Bill\nTo Bill\nTo Deliver\nCompleted\nStopped\nCancelled\nClosed",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 1,
|
||||
@ -1998,7 +2000,7 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Delivery Status",
|
||||
"label": "Delivery Status",
|
||||
"no_copy": 1,
|
||||
"options": "Not Delivered\nFully Delivered\nPartly Delivered\nClosed\nNot Applicable",
|
||||
"permlevel": 0,
|
||||
@ -2092,7 +2094,7 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Billing Status",
|
||||
"label": "Billing Status",
|
||||
"no_copy": 1,
|
||||
"options": "Not Billed\nFully Billed\nPartly Billed\nClosed",
|
||||
"permlevel": 0,
|
||||
@ -2326,7 +2328,7 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Recurring Type",
|
||||
"label": "Recurring Type",
|
||||
"no_copy": 1,
|
||||
"options": "\nMonthly\nQuarterly\nHalf-yearly\nYearly",
|
||||
"permlevel": 0,
|
||||
@ -2553,7 +2555,7 @@
|
||||
"is_submittable": 1,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"modified": "2015-10-03 07:39:10.525609",
|
||||
"modified": "2015-10-22 16:32:34.339835",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Sales Order",
|
||||
|
@ -31,6 +31,7 @@ class SalesOrder(SellingController):
|
||||
self.validate_uom_is_integer("stock_uom", "qty")
|
||||
self.validate_for_items()
|
||||
self.validate_warehouse()
|
||||
self.validate_drop_ship()
|
||||
|
||||
from erpnext.stock.doctype.packed_item.packed_item import make_packing_list
|
||||
make_packing_list(self)
|
||||
@ -147,6 +148,11 @@ class SalesOrder(SellingController):
|
||||
doc.set_status(update=True)
|
||||
doc.update_opportunity()
|
||||
|
||||
def validate_drop_ship(self):
|
||||
for d in self.get('items'):
|
||||
if d.delivered_by_supplier and not d.supplier:
|
||||
frappe.throw(_("Row #{0}: Set Supplier for item {1}").format(d.idx, d.item_code))
|
||||
|
||||
def on_submit(self):
|
||||
super(SalesOrder, self).on_submit()
|
||||
|
||||
@ -214,9 +220,9 @@ class SalesOrder(SellingController):
|
||||
if date_diff and date_diff[0][0]:
|
||||
frappe.throw(_("{0} {1} has been modified. Please refresh.").format(self.doctype, self.name))
|
||||
|
||||
def stop_sales_order(self):
|
||||
def stop_sales_order(self, status):
|
||||
self.check_modified_date()
|
||||
self.db_set('status', 'Stopped')
|
||||
self.db_set('status', status)
|
||||
self.update_reserved_qty()
|
||||
self.notify_update()
|
||||
clear_doctype_notifications(self)
|
||||
@ -252,7 +258,36 @@ class SalesOrder(SellingController):
|
||||
|
||||
def on_update(self):
|
||||
pass
|
||||
|
||||
def before_update_after_submit(self):
|
||||
self.validate_drop_ship()
|
||||
self.validate_po()
|
||||
|
||||
def validate_po(self):
|
||||
exc_list = []
|
||||
|
||||
for item in self.items:
|
||||
supplier = frappe.db.get_value("Sales Order Item", {"parent": self.name, "item_code": item.item_code},
|
||||
"supplier")
|
||||
if item.ordered_qty > 0.0 and item.supplier != supplier:
|
||||
exc_list.append("Row #{0}: Not allowed to change supplier as Purchase Order already exists".format(item.idx))
|
||||
|
||||
if exc_list:
|
||||
frappe.throw('\n'.join(exc_list))
|
||||
|
||||
def update_delivery_status(self, po_name):
|
||||
tot_qty, delivered_qty = 0.0, 0.0
|
||||
|
||||
for item in self.items:
|
||||
if item.delivered_by_supplier:
|
||||
delivered_qty = frappe.db.get_value("Purchase Order Item", {"parent": po_name, "item_code": item.item_code}, "qty")
|
||||
frappe.db.set_value("Sales Order Item", item.name, "delivered_qty", delivered_qty)
|
||||
|
||||
delivered_qty += item.delivered_qty
|
||||
tot_qty += item.qty
|
||||
|
||||
frappe.db.set_value("Sales Order", self.name, "per_delivered", flt(delivered_qty/tot_qty) * 100)
|
||||
|
||||
def get_list_context(context=None):
|
||||
from erpnext.controllers.website_list_for_contact import get_list_context
|
||||
list_context = get_list_context(context)
|
||||
@ -268,9 +303,9 @@ def stop_or_unstop_sales_orders(names, status):
|
||||
for name in names:
|
||||
so = frappe.get_doc("Sales Order", name)
|
||||
if so.docstatus == 1:
|
||||
if status=="Stop":
|
||||
if so.status not in ("Stopped", "Cancelled") and (so.per_delivered < 100 or so.per_billed < 100):
|
||||
so.stop_sales_order()
|
||||
if status in ("Stopped", "Closed"):
|
||||
if so.status not in ("Stopped", "Cancelled", "Closed") and (so.per_delivered < 100 or so.per_billed < 100):
|
||||
so.stop_sales_order(status)
|
||||
else:
|
||||
if so.status == "Stopped":
|
||||
so.unstop_sales_order()
|
||||
@ -350,7 +385,7 @@ def make_delivery_note(source_name, target_doc=None):
|
||||
"parent": "against_sales_order",
|
||||
},
|
||||
"postprocess": update_item,
|
||||
"condition": lambda doc: doc.delivered_qty < doc.qty
|
||||
"condition": lambda doc: doc.delivered_qty < doc.qty and doc.delivered_by_supplier!=1
|
||||
},
|
||||
"Sales Taxes and Charges": {
|
||||
"doctype": "Sales Taxes and Charges",
|
||||
@ -488,3 +523,96 @@ def get_events(start, end, filters=None):
|
||||
"end": end
|
||||
}, as_dict=True, update={"allDay": 0})
|
||||
return data
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_purchase_order_for_drop_shipment(source_name, for_supplier, target_doc=None):
|
||||
def set_missing_values(source, target):
|
||||
target.supplier = for_supplier
|
||||
|
||||
default_price_list = frappe.get_value("Supplier", for_supplier, "default_price_list")
|
||||
if default_price_list:
|
||||
target.buying_price_list = default_price_list
|
||||
|
||||
target.delivered_by_supplier = 1
|
||||
target.run_method("set_missing_values")
|
||||
target.run_method("calculate_taxes_and_totals")
|
||||
|
||||
def update_item(source, target, source_parent):
|
||||
target.schedule_date = source_parent.delivery_date
|
||||
target.qty = flt(source.qty) - flt(source.ordered_qty)
|
||||
|
||||
doclist = get_mapped_doc("Sales Order", source_name, {
|
||||
"Sales Order": {
|
||||
"doctype": "Purchase Order",
|
||||
"field_map": {
|
||||
"address_display": "customer_address_display",
|
||||
"contact_display": "customer_contact_display",
|
||||
"contact_mobile": "customer_contact_mobile",
|
||||
"contact_email": "customer_contact_email",
|
||||
"contact_person": "customer_contact_person"
|
||||
},
|
||||
"field_no_map": [
|
||||
"address_display",
|
||||
"contact_display",
|
||||
"contact_mobile",
|
||||
"contact_email",
|
||||
"contact_person"
|
||||
],
|
||||
"validation": {
|
||||
"docstatus": ["=", 1]
|
||||
}
|
||||
},
|
||||
"Sales Order Item": {
|
||||
"doctype": "Purchase Order Item",
|
||||
"field_map": [
|
||||
["name", "prevdoc_detail_docname"],
|
||||
["parent", "prevdoc_docname"],
|
||||
["parenttype", "prevdoc_doctype"],
|
||||
["uom", "stock_uom"],
|
||||
["delivery_date", "schedule_date"]
|
||||
],
|
||||
"field_no_map": [
|
||||
"rate",
|
||||
"price_list_rate"
|
||||
],
|
||||
"postprocess": update_item,
|
||||
"condition": lambda doc: doc.ordered_qty < doc.qty and doc.supplier == for_supplier
|
||||
}
|
||||
}, target_doc, set_missing_values)
|
||||
|
||||
return doclist
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_supplier(doctype, txt, searchfield, start, page_len, filters):
|
||||
supp_master_name = frappe.defaults.get_user_default("supp_master_name")
|
||||
if supp_master_name == "Supplier Name":
|
||||
fields = ["name", "supplier_type"]
|
||||
else:
|
||||
fields = ["name", "supplier_name", "supplier_type"]
|
||||
fields = ", ".join(fields)
|
||||
|
||||
return frappe.db.sql("""select {field} from `tabSupplier`
|
||||
where docstatus < 2
|
||||
and ({key} like %(txt)s
|
||||
or supplier_name like %(txt)s)
|
||||
and name in (select supplier from `tabSales Order Item` where parent = %(parent)s)
|
||||
order by
|
||||
if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999),
|
||||
if(locate(%(_txt)s, supplier_name), locate(%(_txt)s, supplier_name), 99999),
|
||||
name, supplier_name
|
||||
limit %(start)s, %(page_len)s """.format(**{
|
||||
'field': fields,
|
||||
'key': searchfield
|
||||
}), {
|
||||
'txt': "%%%s%%" % txt,
|
||||
'_txt': txt.replace("%", ""),
|
||||
'start': start,
|
||||
'page_len': page_len,
|
||||
'parent': filters.get('parent')
|
||||
})
|
||||
|
||||
@frappe.whitelist()
|
||||
def update_status(status, name):
|
||||
so = frappe.get_doc("Sales Order", name)
|
||||
so.stop_sales_order(status)
|
||||
|
@ -5,6 +5,9 @@ frappe.listview_settings['Sales Order'] = {
|
||||
if(doc.status==="Stopped") {
|
||||
return [__("Stopped"), "darkgrey", "status,=,Stopped"];
|
||||
|
||||
} else if(doc.status==="Closed"){
|
||||
return [__("Closed"), "green", "status,=,Closed"];
|
||||
|
||||
} else if (doc.order_type !== "Maintenance"
|
||||
&& flt(doc.per_delivered, 2) < 100 && frappe.datetime.get_diff(doc.delivery_date) < 0) {
|
||||
// to bill & overdue
|
||||
@ -42,12 +45,16 @@ frappe.listview_settings['Sales Order'] = {
|
||||
var method = "erpnext.selling.doctype.sales_order.sales_order.stop_or_unstop_sales_orders";
|
||||
|
||||
listview.page.add_menu_item(__("Set as Stopped"), function() {
|
||||
listview.call_for_selected_items(method, {"status": "Stop"});
|
||||
listview.call_for_selected_items(method, {"status": "Stoped"});
|
||||
});
|
||||
|
||||
listview.page.add_menu_item(__("Set as Unstopped"), function() {
|
||||
listview.call_for_selected_items(method, {"status": "Unstop"});
|
||||
});
|
||||
|
||||
listview.page.add_menu_item(__("Set as Closed"), function() {
|
||||
listview.call_for_selected_items(method, {"status": "Closed"});
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
};
|
@ -97,7 +97,7 @@ class TestSalesOrder(unittest.TestCase):
|
||||
|
||||
# stop so
|
||||
so.load_from_db()
|
||||
so.stop_sales_order()
|
||||
so.stop_sales_order("Stopped")
|
||||
self.assertEqual(get_reserved_qty(), existing_reserved_qty)
|
||||
|
||||
# unstop so
|
||||
@ -147,7 +147,7 @@ class TestSalesOrder(unittest.TestCase):
|
||||
|
||||
# stop so
|
||||
so.load_from_db()
|
||||
so.stop_sales_order()
|
||||
so.stop_sales_order("Stopped")
|
||||
|
||||
self.assertEqual(get_reserved_qty("_Test Item"), existing_reserved_qty_item1)
|
||||
self.assertEqual(get_reserved_qty("_Test Item Home Desktop 100"), existing_reserved_qty_item2)
|
||||
@ -295,7 +295,123 @@ class TestSalesOrder(unittest.TestCase):
|
||||
{"price_list": "_Test Price List", "item_code": "_Test Item for Auto Price List"}, "price_list_rate"), None)
|
||||
|
||||
frappe.db.set_value("Stock Settings", None, "auto_insert_price_list_rate_if_missing", 1)
|
||||
|
||||
def test_drop_shipping(self):
|
||||
from erpnext.selling.doctype.sales_order.sales_order import make_purchase_order_for_drop_shipment, make_delivery_note
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
from erpnext.buying.doctype.purchase_order.purchase_order import delivered_by_supplier
|
||||
|
||||
po_item = make_item("_Test Item for Drop Shipping", {"is_stock_item": 1, "is_sales_item": 1,
|
||||
"is_purchase_item": 1, "delivered_by_supplier": 1, 'default_supplier': '_Test Supplier',
|
||||
"expense_account": "_Test Account Cost for Goods Sold - _TC",
|
||||
"cost_center": "_Test Cost Center - _TC"
|
||||
})
|
||||
|
||||
dn_item = make_item("_Test Regular Item", {"is_stock_item": 1, "is_sales_item": 1,
|
||||
"is_purchase_item": 1, "expense_account": "_Test Account Cost for Goods Sold - _TC",
|
||||
"cost_center": "_Test Cost Center - _TC"})
|
||||
|
||||
so_items = [
|
||||
{
|
||||
"item_code": po_item.item_code,
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
"qty": 2,
|
||||
"rate": 400,
|
||||
"delivered_by_supplier": 1,
|
||||
"supplier": '_Test Supplier'
|
||||
},
|
||||
{
|
||||
"item_code": dn_item.item_code,
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
"qty": 2,
|
||||
"rate": 300,
|
||||
"conversion_factor": 1.0
|
||||
}
|
||||
]
|
||||
|
||||
#setuo existing qty from bin
|
||||
bin = frappe.get_all("Bin", filters={"item_code": po_item.item_code, "warehouse": "_Test Warehouse - _TC"},
|
||||
fields=["ordered_qty", "reserved_qty"])
|
||||
|
||||
existing_ordered_qty = bin[0].ordered_qty if bin else 0.0
|
||||
existing_reserved_qty = bin[0].reserved_qty if bin else 0.0
|
||||
|
||||
bin = frappe.get_all("Bin", filters={"item_code": dn_item.item_code, "warehouse": "_Test Warehouse - _TC"},
|
||||
fields=["reserved_qty"])
|
||||
|
||||
existing_reserved_qty_for_dn_item = bin[0].reserved_qty if bin else 0.0
|
||||
|
||||
#create so, po and partial dn
|
||||
so = make_sales_order(item_list=so_items, do_not_submit=True)
|
||||
so.submit()
|
||||
|
||||
po = make_purchase_order_for_drop_shipment(so.name, '_Test Supplier')
|
||||
po.submit()
|
||||
|
||||
dn = create_dn_against_so(so.name, delivered_qty=1)
|
||||
|
||||
self.assertEquals(so.customer, po.customer)
|
||||
self.assertEquals(po.items[0].prevdoc_doctype, "Sales Order")
|
||||
self.assertEquals(po.items[0].prevdoc_docname, so.name)
|
||||
self.assertEquals(po.items[0].item_code, po_item.item_code)
|
||||
self.assertEquals(dn.items[0].item_code, dn_item.item_code)
|
||||
|
||||
#test ordered_qty and reserved_qty
|
||||
ordered_qty, reserved_qty = frappe.db.get_value("Bin",
|
||||
{"item_code": po_item.item_code, "warehouse": "_Test Warehouse - _TC"}, ["ordered_qty", "reserved_qty"])
|
||||
|
||||
self.assertEquals(abs(ordered_qty), existing_ordered_qty + so_items[0]['qty'])
|
||||
self.assertEquals(abs(reserved_qty), existing_reserved_qty + so_items[0]['qty'])
|
||||
|
||||
reserved_qty = frappe.db.get_value("Bin",
|
||||
{"item_code": dn_item.item_code, "warehouse": "_Test Warehouse - _TC"}, "reserved_qty")
|
||||
|
||||
self.assertEquals(abs(reserved_qty), existing_reserved_qty_for_dn_item + 1)
|
||||
|
||||
#test po_item length
|
||||
self.assertEquals(len(po.items), 1)
|
||||
|
||||
#test per_delivered status
|
||||
delivered_by_supplier(po.name)
|
||||
self.assertEquals(flt(frappe.db.get_value("Sales Order", so.name, "per_delivered"), 2), 75.00)
|
||||
|
||||
#test reserved qty after complete delivery
|
||||
dn = create_dn_against_so(so.name, delivered_qty=1)
|
||||
reserved_qty = frappe.db.get_value("Bin",
|
||||
{"item_code": dn_item.item_code, "warehouse": "_Test Warehouse - _TC"}, "reserved_qty")
|
||||
|
||||
self.assertEquals(abs(reserved_qty), existing_reserved_qty_for_dn_item)
|
||||
|
||||
#test after closing so
|
||||
so.db_set('status', "Closed")
|
||||
so.update_reserved_qty()
|
||||
|
||||
ordered_qty, reserved_qty = frappe.db.get_value("Bin",
|
||||
{"item_code": po_item.item_code, "warehouse": "_Test Warehouse - _TC"}, ["ordered_qty", "reserved_qty"])
|
||||
|
||||
self.assertEquals(abs(ordered_qty), existing_ordered_qty)
|
||||
self.assertEquals(abs(reserved_qty), existing_reserved_qty)
|
||||
|
||||
reserved_qty = frappe.db.get_value("Bin",
|
||||
{"item_code": dn_item.item_code, "warehouse": "_Test Warehouse - _TC"}, "reserved_qty")
|
||||
|
||||
self.assertEquals(abs(reserved_qty), existing_reserved_qty)
|
||||
|
||||
def test_reserved_qty_for_closing_so(self):
|
||||
bin = frappe.get_all("Bin", filters={"item_code": "_Test Item", "warehouse": "_Test Warehouse - _TC"},
|
||||
fields=["reserved_qty"])
|
||||
|
||||
existing_reserved_qty = bin[0].reserved_qty if bin else 0.0
|
||||
|
||||
so = make_sales_order(item_code="_Test Item", qty=1)
|
||||
|
||||
self.assertEquals(get_reserved_qty(item_code="_Test Item", warehouse="_Test Warehouse - _TC"), existing_reserved_qty+1)
|
||||
|
||||
so.stop_sales_order("Closed")
|
||||
|
||||
self.assertEquals(get_reserved_qty(item_code="_Test Item", warehouse="_Test Warehouse - _TC"), existing_reserved_qty)
|
||||
|
||||
|
||||
def make_sales_order(**args):
|
||||
so = frappe.new_doc("Sales Order")
|
||||
args = frappe._dict(args)
|
||||
@ -311,15 +427,20 @@ def make_sales_order(**args):
|
||||
|
||||
if "warehouse" not in args:
|
||||
args.warehouse = "_Test Warehouse - _TC"
|
||||
|
||||
so.append("items", {
|
||||
"item_code": args.item or args.item_code or "_Test Item",
|
||||
"warehouse": args.warehouse,
|
||||
"qty": args.qty or 10,
|
||||
"rate": args.rate or 100,
|
||||
"conversion_factor": 1.0,
|
||||
})
|
||||
|
||||
|
||||
if args.item_list:
|
||||
for item in args.item_list:
|
||||
so.append("items", item)
|
||||
|
||||
else:
|
||||
so.append("items", {
|
||||
"item_code": args.item or args.item_code or "_Test Item",
|
||||
"warehouse": args.warehouse,
|
||||
"qty": args.qty or 10,
|
||||
"rate": args.rate or 100,
|
||||
"conversion_factor": 1.0,
|
||||
})
|
||||
|
||||
if not args.do_not_save:
|
||||
so.insert()
|
||||
if not args.do_not_submit:
|
||||
|
@ -683,6 +683,95 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
"collapsible_depends_on": "eval:doc.delivered_by_supplier==1||doc.supplier",
|
||||
"fieldname": "drop_ship",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Drop Ship",
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"fieldname": "delivered_by_supplier",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Delivered By Supplier",
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"fieldname": "column_break_32",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"fieldname": "supplier",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Supplier",
|
||||
"no_copy": 0,
|
||||
"options": "Supplier",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
@ -917,6 +1006,28 @@
|
||||
"unique": 0,
|
||||
"width": "70px"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"fieldname": "ordered_qty",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Ordered Qty",
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"read_only": 1,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
@ -1095,7 +1206,7 @@
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"modified": "2015-10-19 03:04:51.257808",
|
||||
"modified": "2015-11-02 15:15:05.774529",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Sales Order Item",
|
||||
|
@ -30,7 +30,7 @@ erpnext.stock.DeliveryNoteController = erpnext.selling.SellingController.extend(
|
||||
source_doctype: "Sales Order",
|
||||
get_query_filters: {
|
||||
docstatus: 1,
|
||||
status: ["!=", "Stopped"],
|
||||
status: ["not in", ["Stopped", "Closed"]],
|
||||
per_delivered: ["<", 99.99],
|
||||
project_name: cur_frm.doc.project_name || undefined,
|
||||
customer: cur_frm.doc.customer || undefined,
|
||||
|
@ -108,7 +108,7 @@ class DeliveryNote(SellingController):
|
||||
self.set_status()
|
||||
self.so_required()
|
||||
self.validate_proj_cust()
|
||||
self.check_stop_sales_order("against_sales_order")
|
||||
self.check_stop_or_close_sales_order("against_sales_order")
|
||||
self.validate_for_items()
|
||||
self.validate_warehouse()
|
||||
self.validate_uom_is_integer("stock_uom", "qty")
|
||||
@ -205,7 +205,7 @@ class DeliveryNote(SellingController):
|
||||
|
||||
|
||||
def on_cancel(self):
|
||||
self.check_stop_sales_order("against_sales_order")
|
||||
self.check_stop_or_close_sales_order("against_sales_order")
|
||||
self.check_next_docstatus()
|
||||
|
||||
self.update_prevdoc_status()
|
||||
|
@ -246,6 +246,28 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"fieldname": "delivered_by_supplier",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Delivered By Supplier",
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
|
@ -103,7 +103,7 @@ class MaterialRequest(BuyingController):
|
||||
def on_cancel(self):
|
||||
pc_obj = frappe.get_doc('Purchase Common')
|
||||
|
||||
pc_obj.check_for_stopped_status(self.doctype, self.name)
|
||||
pc_obj.check_for_stopped_or_closed_status(self.doctype, self.name)
|
||||
pc_obj.check_docstatus(check = 'Next', doctype = 'Purchase Order', docname = self.name, detail_doctype = 'Purchase Order Item')
|
||||
|
||||
self.update_requested_qty()
|
||||
|
@ -43,7 +43,7 @@ erpnext.stock.PurchaseReceiptController = erpnext.buying.BuyingController.extend
|
||||
get_query_filters: {
|
||||
supplier: cur_frm.doc.supplier || undefined,
|
||||
docstatus: 1,
|
||||
status: ["!=", "Stopped"],
|
||||
status: ["not in", ["Stopped", "Closed"]],
|
||||
per_received: ["<", 99.99],
|
||||
company: cur_frm.doc.company
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ class PurchaseReceipt(BuyingController):
|
||||
|
||||
pc_obj = frappe.get_doc('Purchase Common')
|
||||
pc_obj.validate_for_items(self)
|
||||
self.check_for_stopped_status(pc_obj)
|
||||
self.check_for_stopped_or_closed_status(pc_obj)
|
||||
|
||||
# sub-contracting
|
||||
self.validate_for_subcontracting()
|
||||
@ -220,12 +220,12 @@ class PurchaseReceipt(BuyingController):
|
||||
raise frappe.ValidationError
|
||||
|
||||
# Check for Stopped status
|
||||
def check_for_stopped_status(self, pc_obj):
|
||||
def check_for_stopped_or_closed_status(self, pc_obj):
|
||||
check_list =[]
|
||||
for d in self.get('items'):
|
||||
if d.meta.get_field('prevdoc_docname') and d.prevdoc_docname and d.prevdoc_docname not in check_list:
|
||||
check_list.append(d.prevdoc_docname)
|
||||
pc_obj.check_for_stopped_status(d.prevdoc_doctype, d.prevdoc_docname)
|
||||
pc_obj.check_for_stopped_or_closed_status(d.prevdoc_doctype, d.prevdoc_docname)
|
||||
|
||||
# on submit
|
||||
def on_submit(self):
|
||||
@ -261,7 +261,7 @@ class PurchaseReceipt(BuyingController):
|
||||
def on_cancel(self):
|
||||
pc_obj = frappe.get_doc('Purchase Common')
|
||||
|
||||
self.check_for_stopped_status(pc_obj)
|
||||
self.check_for_stopped_or_closed_status(pc_obj)
|
||||
# Check if Purchase Invoice has been submitted against current Purchase Order
|
||||
submitted = frappe.db.sql("""select t1.name
|
||||
from `tabPurchase Invoice` t1,`tabPurchase Invoice Item` t2
|
||||
|
@ -30,7 +30,7 @@ def get_item_details(args):
|
||||
"is_subcontracted": "Yes" / "No",
|
||||
"transaction_type": "selling",
|
||||
"ignore_pricing_rule": 0/1
|
||||
"project_name": "",
|
||||
"project_name": ""
|
||||
}
|
||||
"""
|
||||
args = process_args(args)
|
||||
@ -69,7 +69,7 @@ def get_item_details(args):
|
||||
|
||||
if args.get("is_subcontracted") == "Yes":
|
||||
out.bom = get_default_bom(args.item_code)
|
||||
|
||||
|
||||
return out
|
||||
|
||||
def process_args(args):
|
||||
@ -172,7 +172,9 @@ def get_basic_details(args, item):
|
||||
"base_amount": 0.0,
|
||||
"net_rate": 0.0,
|
||||
"net_amount": 0.0,
|
||||
"discount_percentage": 0.0
|
||||
"discount_percentage": 0.0,
|
||||
"supplier": item.default_supplier,
|
||||
"delivered_by_supplier": item.delivered_by_supplier,
|
||||
})
|
||||
|
||||
# if default specified in item is for another company, fetch from company
|
||||
|
@ -90,7 +90,7 @@ def get_reserved_qty(item_code, warehouse):
|
||||
and parenttype="Sales Order"
|
||||
and item_code != parent_item
|
||||
and exists (select * from `tabSales Order` so
|
||||
where name = dnpi_in.parent and docstatus = 1 and status != 'Stopped')
|
||||
where name = dnpi_in.parent and docstatus = 1 and status not in ('Stopped','Closed'))
|
||||
) dnpi)
|
||||
union
|
||||
(select qty as dnpi_qty, qty as so_item_qty,
|
||||
@ -99,7 +99,7 @@ def get_reserved_qty(item_code, warehouse):
|
||||
where item_code = %s and warehouse = %s
|
||||
and exists(select * from `tabSales Order` so
|
||||
where so.name = so_item.parent and so.docstatus = 1
|
||||
and so.status != 'Stopped'))
|
||||
and so.status not in ('Stopped','Closed')))
|
||||
) tab
|
||||
where
|
||||
so_item_qty >= so_item_delivered_qty
|
||||
@ -122,7 +122,7 @@ def get_ordered_qty(item_code, warehouse):
|
||||
from `tabPurchase Order Item` po_item, `tabPurchase Order` po
|
||||
where po_item.item_code=%s and po_item.warehouse=%s
|
||||
and po_item.qty > ifnull(po_item.received_qty, 0) and po_item.parent=po.name
|
||||
and po.status!='Stopped' and po.docstatus=1""", (item_code, warehouse))
|
||||
and po.status not in ('Stopped', 'Closed', 'Delivered') and po.docstatus=1""", (item_code, warehouse))
|
||||
|
||||
return flt(ordered_qty[0][0]) if ordered_qty else 0
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user