Skip to content

Commit

Permalink
Cleanup and test cases for serialized item
Browse files Browse the repository at this point in the history
  • Loading branch information
nabinhait committed Jul 24, 2015
1 parent f061877 commit 3cf67a4
Show file tree
Hide file tree
Showing 21 changed files with 275 additions and 218 deletions.
12 changes: 5 additions & 7 deletions erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,10 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({

// Show / Hide button
if(doc.docstatus==1 && doc.outstanding_amount > 0)
this.frm.add_custom_button(__('Make Payment Entry'), this.make_bank_entry,
frappe.boot.doctype_icons["Journal Entry"]);
this.frm.add_custom_button(__('Make Payment Entry'), this.make_bank_entry);

if(doc.docstatus==1) {
cur_frm.add_custom_button(__('Make Purchase Return'), this.make_purchase_return,
frappe.boot.doctype_icons["Purchase Invoice"]);
cur_frm.add_custom_button(__('Make Purchase Return'), this.make_purchase_return);

cur_frm.add_custom_button(__('View Ledger'), function() {
frappe.route_options = {
Expand All @@ -37,7 +35,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
group_by_voucher: 0
};
frappe.set_route("query-report", "General Ledger");
}, "icon-table");
});
}

if(doc.docstatus===0) {
Expand All @@ -54,7 +52,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
company: cur_frm.doc.company
}
})
}, "icon-download", "btn-default");
});

cur_frm.add_custom_button(__('From Purchase Receipt'),
function() {
Expand All @@ -67,7 +65,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
company: cur_frm.doc.company
}
})
}, "icon-download", "btn-default");
});

}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@
"fieldname": "is_return",
"fieldtype": "Check",
"label": "Is Return",
"no_copy": 1,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 1,
Expand All @@ -169,7 +169,7 @@
"fieldname": "return_against",
"fieldtype": "Link",
"label": "Return Against Purchase Invoice",
"no_copy": 1,
"no_copy": 0,
"options": "Purchase Invoice",
"permlevel": 0,
"precision": "",
Expand Down Expand Up @@ -962,7 +962,7 @@
"icon": "icon-file-text",
"idx": 1,
"is_submittable": 1,
"modified": "2015-07-17 14:09:19.666457",
"modified": "2015-07-24 11:49:59.762109",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -412,5 +412,5 @@ def get_expense_account(doctype, txt, searchfield, start, page_len, filters):

@frappe.whitelist()
def make_purchase_return(source_name, target_doc=None):
from erpnext.utilities.transaction_base import make_return_doc
from erpnext.controllers.sales_and_purchase_return import make_return_doc
return make_return_doc("Purchase Invoice", source_name, target_doc)
9 changes: 4 additions & 5 deletions erpnext/accounts/doctype/sales_invoice/sales_invoice.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
group_by_voucher: 0
};
frappe.set_route("query-report", "General Ledger");
}, "icon-table");
});

if(cint(doc.update_stock)!=1) {
// show Make Delivery Note button only if Sales Invoice is not created from Delivery Note
Expand All @@ -64,16 +64,15 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
});

if(!from_delivery_note) {
cur_frm.add_custom_button(__('Make Delivery'), cur_frm.cscript['Make Delivery Note'], "icon-truck")
cur_frm.add_custom_button(__('Make Delivery'), cur_frm.cscript['Make Delivery Note'])
}
}

if(doc.outstanding_amount!=0 && !cint(doc.is_return)) {
cur_frm.add_custom_button(__('Make Payment Entry'), cur_frm.cscript.make_bank_entry, "icon-money");
cur_frm.add_custom_button(__('Make Payment Entry'), cur_frm.cscript.make_bank_entry);
}

cur_frm.add_custom_button(__('Make Sales Return'), this.make_sales_return,
frappe.boot.doctype_icons["Sales Invoice"]);
cur_frm.add_custom_button(__('Make Sales Return'), this.make_sales_return);
}

// Show buttons only when pos view is active
Expand Down
6 changes: 3 additions & 3 deletions erpnext/accounts/doctype/sales_invoice/sales_invoice.json
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@
"fieldname": "is_return",
"fieldtype": "Check",
"label": "Is Return",
"no_copy": 1,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 1,
Expand All @@ -184,7 +184,7 @@
"fieldname": "return_against",
"fieldtype": "Link",
"label": "Return Against Sales Invoice",
"no_copy": 1,
"no_copy": 0,
"options": "Sales Invoice",
"permlevel": 0,
"precision": "",
Expand Down Expand Up @@ -1275,7 +1275,7 @@
"icon": "icon-file-text",
"idx": 1,
"is_submittable": 1,
"modified": "2015-07-22 16:53:52.995407",
"modified": "2015-07-24 11:48:07.544569",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
Expand Down
2 changes: 1 addition & 1 deletion erpnext/accounts/doctype/sales_invoice/sales_invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -663,5 +663,5 @@ def update_item(source_doc, target_doc, source_parent):

@frappe.whitelist()
def make_sales_return(source_name, target_doc=None):
from erpnext.utilities.transaction_base import make_return_doc
from erpnext.controllers.sales_and_purchase_return import make_return_doc
return make_return_doc("Sales Invoice", source_name, target_doc)
33 changes: 13 additions & 20 deletions erpnext/buying/doctype/purchase_order/purchase_order.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,39 +11,32 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
this._super();
// this.frm.dashboard.reset();

if(doc.docstatus == 1 && doc.status != 'Stopped'){
// cur_frm.dashboard.add_progress(cint(doc.per_received) + __("% Received"),
// doc.per_received);
// cur_frm.dashboard.add_progress(cint(doc.per_billed) + __("% Billed"),
// doc.per_billed);

if(doc.docstatus == 1 && doc.status != 'Stopped') {
if(flt(doc.per_received, 2) < 100) {
cur_frm.add_custom_button(__('Make Purchase Receipt'),
this.make_purchase_receipt);
cur_frm.add_custom_button(__('Make Purchase Receipt'), this.make_purchase_receipt);

if(doc.is_subcontracted==="Yes") {
cur_frm.add_custom_button(__('Transfer Material to Supplier'),
function() { me.make_stock_entry() });
cur_frm.add_custom_button(__('Transfer Material to Supplier'), this.make_stock_entry);
}
}
if(flt(doc.per_billed, 2) < 100)
cur_frm.add_custom_button(__('Make Invoice'), this.make_purchase_invoice,
frappe.boot.doctype_icons["Purchase Invoice"]);
cur_frm.add_custom_button(__('Make Invoice'), this.make_purchase_invoice);

if(flt(doc.per_billed, 2) < 100 || doc.per_received < 100)
cur_frm.add_custom_button(__('Stop'), cur_frm.cscript['Stop Purchase Order'],
"icon-exclamation", "btn-default");
cur_frm.add_custom_button(__('Stop'), cur_frm.cscript['Stop Purchase Order']);

} else if(doc.docstatus===0) {
cur_frm.cscript.add_from_mappers();
}

if(doc.docstatus == 1 && doc.status == 'Stopped')
cur_frm.add_custom_button(__('Unstop Purchase Order'),
cur_frm.cscript['Unstop Purchase Order'], "icon-check");
cur_frm.add_custom_button(__('Unstop Purchase Order'), cur_frm.cscript['Unstop Purchase Order']);
},

make_stock_entry: function() {
var items = $.map(cur_frm.doc.items, function(d) { return d.bom ? d.item_code : false; }),
me = this;
var me = this;

if(items.length===1) {
me._make_stock_entry(items[0]);
return;
Expand Down Expand Up @@ -96,7 +89,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
company: cur_frm.doc.company
}
})
}, "icon-download", "btn-default"
}
);

cur_frm.add_custom_button(__('From Supplier Quotation'),
Expand All @@ -110,7 +103,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
company: cur_frm.doc.company
}
})
}, "icon-download", "btn-default"
}
);

cur_frm.add_custom_button(__('For Supplier'),
Expand All @@ -122,7 +115,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
docstatus: ["!=", 2],
}
})
}, "icon-download", "btn-default"
}
);
},

Expand Down
100 changes: 3 additions & 97 deletions erpnext/controllers/accounts_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@
from __future__ import unicode_literals
import frappe
from frappe import _, throw
from frappe.utils import today, flt, cint, format_datetime, get_datetime
from frappe.utils import today, flt, cint
from erpnext.setup.utils import get_company_currency, get_exchange_rate
from erpnext.accounts.utils import get_fiscal_year, validate_fiscal_year
from erpnext.utilities.transaction_base import TransactionBase
from erpnext.controllers.recurring_document import convert_to_recurring, validate_recurring_document

class StockOverReturnError(frappe.ValidationError): pass

from erpnext.controllers.sales_and_purchase_return import validate_return

class AccountsController(TransactionBase):
def validate(self):
Expand All @@ -23,7 +21,7 @@ def validate(self):
if not self.meta.get_field("is_return") or not self.is_return:
self.validate_value("base_grand_total", ">=", 0)

self.validate_return_doc()
validate_return(self)
self.set_total_in_words()

if self.doctype in ("Sales Invoice", "Purchase Invoice") and not self.is_return:
Expand Down Expand Up @@ -58,98 +56,6 @@ def set_missing_values(self, for_validate=False):
self.fiscal_year = get_fiscal_year(self.get(fieldname))[0]
break

def validate_return_doc(self):
if not self.meta.get_field("is_return") or not self.is_return:
return

self.validate_return_against()
self.validate_returned_items()

def validate_return_against(self):
if not self.return_against:
frappe.throw(_("{0} is mandatory for Return").format(self.meta.get_label("return_against")))
else:
filters = {"doctype": self.doctype, "docstatus": 1, "company": self.company}
if self.meta.get_field("customer"):
filters["customer"] = self.customer
elif self.meta.get_field("supplier"):
filters["supplier"] = self.supplier

if not frappe.db.exists(filters):
frappe.throw(_("Invalid {0}: {1}")
.format(self.meta.get_label("return_against"), self.return_against))
else:
ref_doc = frappe.get_doc(self.doctype, self.return_against)

# validate posting date time
return_posting_datetime = "%s %s" % (self.posting_date, self.get("posting_time") or "00:00:00")
ref_posting_datetime = "%s %s" % (ref_doc.posting_date, ref_doc.get("posting_time") or "00:00:00")

if get_datetime(return_posting_datetime) < get_datetime(ref_posting_datetime):
frappe.throw(_("Posting timestamp must be after {0}").format(format_datetime(ref_posting_datetime)))

# validate same exchange rate
if self.conversion_rate != ref_doc.conversion_rate:
frappe.throw(_("Exchange Rate must be same as {0} {1} ({2})")
.format(self.doctype, self.return_against, ref_doc.conversion_rate))

# validate update stock
if self.doctype == "Sales Invoice" and self.update_stock \
and not frappe.db.get_value("Sales Invoice", self.return_against, "update_stock"):
frappe.throw(_("'Update Stock' can not be checked because items are not delivered via {0}")
.format(self.return_against))

def validate_returned_items(self):
valid_items = frappe._dict()
for d in frappe.db.sql("""select item_code, sum(qty) as qty, rate from `tab{0} Item`
where parent = %s group by item_code""".format(self.doctype), self.return_against, as_dict=1):
valid_items.setdefault(d.item_code, d)

if self.doctype in ("Delivery Note", "Sales Invoice"):
for d in frappe.db.sql("""select item_code, sum(qty) as qty from `tabPacked Item`
where parent = %s group by item_code""".format(self.doctype), self.return_against, as_dict=1):
valid_items.setdefault(d.item_code, d)

already_returned_items = self.get_already_returned_items()

items_returned = False
for d in self.get("items"):
if flt(d.qty) < 0:
if d.item_code not in valid_items:
frappe.throw(_("Row # {0}: Returned Item {1} does not exists in {2} {3}")
.format(d.idx, d.item_code, self.doctype, self.return_against))
else:
ref = valid_items.get(d.item_code, frappe._dict())
already_returned_qty = flt(already_returned_items.get(d.item_code))
max_return_qty = flt(ref.qty) - already_returned_qty

if already_returned_qty >= ref.qty:
frappe.throw(_("Item {0} has already been returned").format(d.item_code), StockOverReturnError)
elif abs(d.qty) > max_return_qty:
frappe.throw(_("Row # {0}: Cannot return more than {1} for Item {2}")
.format(d.idx, ref.qty, d.item_code), StockOverReturnError)
elif ref.rate and flt(d.rate) != ref.rate:
frappe.throw(_("Row # {0}: Rate must be same as {1} {2}")
.format(d.idx, self.doctype, self.return_against))


items_returned = True

if not items_returned:
frappe.throw(_("Atleast one item should be entered with negative quantity in return document"))

def get_already_returned_items(self):
return frappe._dict(frappe.db.sql("""
select
child.item_code, sum(abs(child.qty)) as qty
from
`tab{0} Item` child, `tab{1}` par
where
child.parent = par.name and par.docstatus = 1
and ifnull(par.is_return, 0) = 1 and par.return_against = %s and child.qty < 0
group by item_code
""".format(self.doctype, self.doctype), self.return_against))

def calculate_taxes_and_totals(self):
from erpnext.controllers.taxes_and_totals import calculate_taxes_and_totals
calculate_taxes_and_totals(self)
Expand Down
Loading

0 comments on commit 3cf67a4

Please sign in to comment.