Merge pull request #8080 from rmehta/item-variants-by-mfg
[feature] ability to have variants based on manufacturer
diff --git a/erpnext/accounts/doctype/sales_invoice/pos.py b/erpnext/accounts/doctype/sales_invoice/pos.py
index 471263f..49e2f15 100644
--- a/erpnext/accounts/doctype/sales_invoice/pos.py
+++ b/erpnext/accounts/doctype/sales_invoice/pos.py
@@ -139,7 +139,7 @@
select
name, item_code, item_name, description, item_group, expense_account, has_batch_no,
has_serial_no, expense_account, selling_cost_center, stock_uom, image,
- default_warehouse, is_stock_item, barcode
+ default_warehouse, is_stock_item, barcode, brand
from
tabItem
where
diff --git a/erpnext/accounts/page/pos/pos.js b/erpnext/accounts/page/pos/pos.js
index 1dafb87..c021000 100644
--- a/erpnext/accounts/page/pos/pos.js
+++ b/erpnext/accounts/page/pos/pos.js
@@ -26,6 +26,7 @@
this.onload();
this.make_menu_list();
this.bind_events();
+ this.bind_items_event();
this.si_docs = this.get_doc_from_localstorage();
},
@@ -78,6 +79,7 @@
make_menu_list: function () {
var me = this;
+ this.page.clear_menu();
this.page.add_menu_item(__("New Sales Invoice"), function () {
me.save_previous_entry();
me.create_new();
@@ -96,12 +98,6 @@
me.sync_sales_invoice()
});
- this.page.add_menu_item(__("Email"), function () {
- if(me.frm.doc.docstatus == 1) {
- me.email_prompt()
- }
- });
-
this.page.add_menu_item(__("POS Profile"), function () {
frappe.set_route('List', 'POS Profile');
});
@@ -1043,12 +1039,12 @@
bind_qty_event: function () {
var me = this;
-
+
$(this.wrapper).on("change", ".pos-item-qty", function () {
var item_code = $(this).parents(".pos-selected-item-action").attr("data-item-code");
var qty = $(this).val();
me.update_qty(item_code, qty)
- me.render_selected_item()
+ me.update_value()
})
$(this.wrapper).find("[data-action='increase-qty']").on("click", function () {
@@ -1067,7 +1063,7 @@
var item_code = $(this).parents(".pos-selected-item-action").attr("data-item-code");
var discount = $(this).val();
me.update_discount(item_code, discount)
- me.render_selected_item()
+ me.update_value()
})
},
@@ -1082,6 +1078,7 @@
if (me.frm.doc.docstatus == 0) {
me.items = me.get_items($(this).attr("data-item-code"))
me.add_to_cart();
+ me.clear_selected_row();
}
});
@@ -1106,18 +1103,42 @@
$(this.wrapper).on("change", ".pos-item-price", function () {
var item_code = $(this).parents(".pos-selected-item-action").attr("data-item-code");
me.set_item_details(item_code, "rate", $(this).val());
+ me.update_value()
})
},
- render_selected_item: function() {
- doc = this.get_child_item(this.item_code);
- $(this.wrapper).find('.selected-item').empty();
- if(doc.length) {
- this.selected_row = $(frappe.render_template("pos_selected_item", doc[0]))
- $(this.wrapper).find('.selected-item').html(this.selected_row)
+ update_value: function() {
+ var me = this;
+ var fields = {qty: ".pos-item-qty", "discount_percentage": ".pos-item-disc",
+ "rate": ".pos-item-price", "amount": ".pos-amount"}
+ this.child_doc = this.get_child_item(this.item_code);
+
+ if(me.child_doc.length) {
+ $.each(fields, function(key, field) {
+ $(me.selected_row).find(field).val(me.child_doc[0][key])
+ })
+ } else {
+ this.clear_selected_row();
}
},
-
+
+ clear_selected_row: function() {
+ $(this.wrapper).find('.selected-item').empty();
+ },
+
+ render_selected_item: function() {
+ this.child_doc = this.get_child_item(this.item_code);
+ $(this.wrapper).find('.selected-item').empty();
+ if(this.child_doc.length) {
+ this.selected_row = $(frappe.render_template("pos_selected_item", this.child_doc[0]))
+ $(this.wrapper).find('.selected-item').html(this.selected_row)
+ }
+
+ $(this.selected_row).find('.form-control').click(function(){
+ $(this).select();
+ })
+ },
+
get_child_item: function(item_code) {
var me = this;
return $.map(me.frm.doc.items, function(doc){
@@ -1145,6 +1166,10 @@
if (d.qty == 0) {
me.remove_item.push(d.idx)
}
+
+ if(field=="discount_percentage" && value == 0) {
+ d.rate = d.price_list_rate;
+ }
}
});
@@ -1243,6 +1268,7 @@
this.child.item_code = this.items[0].item_code;
this.child.item_name = this.items[0].item_name;
this.child.stock_uom = this.items[0].stock_uom;
+ this.child.brand = this.items[0].brand;
this.child.description = this.items[0].description;
this.child.discount_percentage = 0.0;
this.child.qty = 1;
@@ -1272,7 +1298,6 @@
refresh: function (update_paid_amount) {
var me = this;
this.refresh_fields(update_paid_amount);
- this.bind_items_event();
this.set_primary_action();
},
@@ -1361,6 +1386,7 @@
var me = this;
this.page.set_primary_action(__("New Cart"), function () {
me.make_new_cart()
+ me.make_menu_list()
}, "fa fa-plus")
if (this.frm.doc.docstatus == 1) {
@@ -1368,10 +1394,14 @@
html = frappe.render(me.print_template_data, me.frm.doc)
me.print_document(html)
})
+ this.page.add_menu_item(__("Email"), function () {
+ me.email_prompt()
+ })
}
},
make_new_cart: function (){
+ this.page.clear_secondary_action();
this.save_previous_entry();
this.create_new();
this.refresh();
@@ -1715,7 +1745,7 @@
var me = this;
return $.grep(this.pricing_rules, function (data) {
if (item.qty >= data.min_qty && (item.qty <= (data.max_qty ? data.max_qty : item.qty))) {
- if (data.item_code == item.item_code || in_list(['All Item Groups', item.item_group], data.item_group)) {
+ if (data.item_code == item.item_code || in_list(['All Item Groups', item.item_group], data.item_group) || item.brand == data.brand) {
if (in_list(['Customer', 'Customer Group', 'Territory', 'Campaign'], data.applicable_for)) {
return me.validate_condition(data)
} else {
diff --git a/erpnext/docs/assets/img/setup/workflow-1.png b/erpnext/docs/assets/img/setup/workflow-1.png
index 632e1fb..7fd6f17 100644
--- a/erpnext/docs/assets/img/setup/workflow-1.png
+++ b/erpnext/docs/assets/img/setup/workflow-1.png
Binary files differ
diff --git a/erpnext/docs/assets/img/setup/workflow-2.png b/erpnext/docs/assets/img/setup/workflow-2.png
index 2041860..1023a39 100644
--- a/erpnext/docs/assets/img/setup/workflow-2.png
+++ b/erpnext/docs/assets/img/setup/workflow-2.png
Binary files differ
diff --git a/erpnext/docs/assets/img/setup/workflow-3.png b/erpnext/docs/assets/img/setup/workflow-3.png
new file mode 100644
index 0000000..fc29c88
--- /dev/null
+++ b/erpnext/docs/assets/img/setup/workflow-3.png
Binary files differ
diff --git a/erpnext/docs/assets/img/setup/workflow-4.png b/erpnext/docs/assets/img/setup/workflow-4.png
new file mode 100644
index 0000000..ee991f9
--- /dev/null
+++ b/erpnext/docs/assets/img/setup/workflow-4.png
Binary files differ
diff --git a/erpnext/docs/assets/img/setup/workflow-5.png b/erpnext/docs/assets/img/setup/workflow-5.png
new file mode 100644
index 0000000..ad360c6
--- /dev/null
+++ b/erpnext/docs/assets/img/setup/workflow-5.png
Binary files differ
diff --git a/erpnext/docs/user/manual/en/setting-up/workflows.md b/erpnext/docs/user/manual/en/setting-up/workflows.md
index a4ddc38..5593a53 100644
--- a/erpnext/docs/user/manual/en/setting-up/workflows.md
+++ b/erpnext/docs/user/manual/en/setting-up/workflows.md
@@ -4,9 +4,9 @@
Example of a leave application workflow is given below:
-If an user applies for a leave, then his request will be sent to the HR
-department. The HR department(HR User) will either reject or approve this
-request. Once this process is completed, the user's Manager(leave approver)
+If a user applies for a leave, then his request will be sent to the HR
+department. The HR department (HR User) will either reject or approve this
+request. Once this process is completed, the user's Manager (leave approver)
will get an indication that the HR department has Accepted or Rejected. The
Manager, who is the approving authority, will either Approve or Reject this
request. Accordingly,the user will get his Approved or Rejected status.
@@ -44,23 +44,17 @@
#### Example of a Leave Application Process:
-Go to the Human Resources Module and click on Leave Application. Apply for a
-Leave.
+When a Leave Application is saved by Employee, the status of the document changes to "Applied"
-When a Leave Application is submitted, the status on the right hand corner of
-the page shows as "Applied"
-
-![Workflow Employee LA]({{docs_base_url}}/assets/old_images/erpnext/workflow-employee-la.png)
+![Workflow Employee LA]({{docs_base_url}}/assets/img/setup/workflow-3.png)
When the HR User logs in, he can either Approve or Reject. If approved the
-status on the right hand corner of the page shows as Approved. However, a blue
-band of information is displayed saying approval is pending by leave approver.
+status of the document changes to "Approved by HR". However, it is yet to be approved by Leave Approver.
-![Leave Approver]({{docs_base_url}}/assets/old_images/erpnext/workflow-hr-user-la.png)
+![Leave Approver]({{docs_base_url}}/assets/img/setup/workflow-4.png)
-When the leave approver opens the Leave Application page, he should select the
-status and convert to Approved or Rejected.
+When the Leave Approver opens the Leave Application page, he can finally "Approve" or "Reject" the Leave Application.
-![Workflow Leave Approver]({{docs_base_url}}/assets/old_images/erpnext/workflow-leave-approver-la.png)
+![Workflow Leave Approver]({{docs_base_url}}/assets/img/setup/workflow-5.png)
{next}
diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py
index b8382ec..c629e87 100644
--- a/erpnext/hr/doctype/salary_slip/salary_slip.py
+++ b/erpnext/hr/doctype/salary_slip/salary_slip.py
@@ -148,10 +148,9 @@
})
def get_date_details(self):
- if not self.end_date:
- date_details = get_start_end_dates(self.payroll_frequency, self.start_date or self.posting_date)
- self.start_date = date_details.start_date
- self.end_date = date_details.end_date
+ date_details = get_start_end_dates(self.payroll_frequency, self.start_date or self.posting_date)
+ self.start_date = date_details.start_date
+ self.end_date = date_details.end_date
def check_sal_struct(self, joining_date, relieving_date):
cond = ''
diff --git a/erpnext/public/js/pos/pos_selected_item.html b/erpnext/public/js/pos/pos_selected_item.html
index 30cf0f0..dfc9915 100644
--- a/erpnext/public/js/pos/pos_selected_item.html
+++ b/erpnext/public/js/pos/pos_selected_item.html
@@ -1,12 +1,13 @@
<div class="pos-selected-item-action" data-item-code="{%= item_code %}">
<div class="pos-list-row">
- <span class="cell bold">{{item_name}}</span>
- </div>
- <div class="pos-list-row">
<div class="cell">Quantity:</div>
<input class="form-control cell pos-item-qty" value="{%= qty %}"/>
</div>
<div class="pos-list-row">
+ <div class="cell">Price List Rate:</div>
+ <input class="form-control cell" disabled value="{%= price_list_rate %}"/>
+ </div>
+ <div class="pos-list-row">
<div class="cell">Discount:</div>
<input class="form-control cell pos-item-disc" value="{%= discount_percentage %}">
</div>
@@ -16,6 +17,6 @@
</div>
<div class="pos-list-row">
<div class="cell">Amount:</div>
- <input class="form-control cell" value="{%= amount %}"/>
+ <input class="form-control cell pos-amount" value="{%= amount %}"/>
</div>
</div>
\ No newline at end of file
diff --git a/erpnext/schools/api.py b/erpnext/schools/api.py
index 316f0dd..623b1e0 100644
--- a/erpnext/schools/api.py
+++ b/erpnext/schools/api.py
@@ -16,6 +16,7 @@
:param source_name: Student Applicant.
"""
+ frappe.publish_realtime('enroll_student_progress', {"progress": [1, 4]}, user=frappe.session.user)
student = get_mapped_doc("Student Applicant", source_name,
{"Student Applicant": {
"doctype": "Student",
@@ -28,6 +29,7 @@
program_enrollment.student = student.name
program_enrollment.student_name = student.title
program_enrollment.program = frappe.db.get_value("Student Applicant", source_name, "program")
+ frappe.publish_realtime('enroll_student_progress', {"progress": [4, 4]}, user=frappe.session.user)
return program_enrollment
@frappe.whitelist()
diff --git a/erpnext/schools/doctype/guardian/guardian.json b/erpnext/schools/doctype/guardian/guardian.json
index 22b8bd8..ba56c9d 100644
--- a/erpnext/schools/doctype/guardian/guardian.json
+++ b/erpnext/schools/doctype/guardian/guardian.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 0,
"autoname": "GARD.####",
@@ -144,7 +145,7 @@
"in_standard_filter": 0,
"label": "Date of Birth",
"length": 0,
- "no_copy": 0,
+ "no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -317,7 +318,7 @@
"in_standard_filter": 0,
"label": "Image",
"length": 0,
- "no_copy": 0,
+ "no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -449,18 +450,18 @@
"unique": 0
}
],
+ "has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_field": "image",
"image_view": 0,
"in_create": 0,
- "in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2017-02-20 13:17:43.366116",
+ "modified": "2017-03-15 17:48:11.739730",
"modified_by": "Administrator",
"module": "Schools",
"name": "Guardian",
diff --git a/erpnext/schools/doctype/student/student.json b/erpnext/schools/doctype/student/student.json
index 9b64439..08b0f17 100644
--- a/erpnext/schools/doctype/student/student.json
+++ b/erpnext/schools/doctype/student/student.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
"autoname": "naming_series:",
@@ -143,7 +144,7 @@
"in_standard_filter": 0,
"label": "Naming Series",
"length": 0,
- "no_copy": 0,
+ "no_copy": 1,
"options": "STUD.",
"permlevel": 0,
"precision": "",
@@ -979,19 +980,19 @@
"unique": 0
}
],
+ "has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_field": "image",
"image_view": 0,
"in_create": 0,
- "in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
- "modified": "2017-02-17 17:21:51.693028",
+ "modified": "2017-03-15 17:50:09.677184",
"modified_by": "Administrator",
"module": "Schools",
"name": "Student",
diff --git a/erpnext/schools/doctype/student_applicant/student_applicant.js b/erpnext/schools/doctype/student_applicant/student_applicant.js
index c14c6f7..9b08ee5 100644
--- a/erpnext/schools/doctype/student_applicant/student_applicant.js
+++ b/erpnext/schools/doctype/student_applicant/student_applicant.js
@@ -20,7 +20,18 @@
frm.add_custom_button(__("Enroll"), function() {
frm.events.enroll(frm)
}).addClass("btn-primary");
+ frm.add_custom_button(__("Reject"), function() {
+ frm.set_value("application_status", "Rejected");
+ frm.save_or_update();
+ }, 'Actions');
}
+
+ frappe.realtime.on("enroll_student_progress", function(data) {
+ if(data.progress) {
+ frappe.hide_msgprint(true);
+ frappe.show_progress(__("Enrolling student"), data.progress[0],data.progress[1]);
+ }
+ })
},
enroll: function(frm) {
@@ -39,3 +50,4 @@
frm.add_fetch("student", "date_of_birth", "date_of_birth");
}
});
+
diff --git a/erpnext/schools/doctype/student_applicant/student_applicant.json b/erpnext/schools/doctype/student_applicant/student_applicant.json
index 315ba8cd..d405b7f 100644
--- a/erpnext/schools/doctype/student_applicant/student_applicant.json
+++ b/erpnext/schools/doctype/student_applicant/student_applicant.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 0,
"autoname": "naming_series:",
@@ -203,7 +204,7 @@
"in_standard_filter": 0,
"label": "Naming Series",
"length": 0,
- "no_copy": 0,
+ "no_copy": 1,
"options": "AP",
"permlevel": 0,
"precision": "",
@@ -851,7 +852,7 @@
"in_standard_filter": 0,
"label": "Guardians",
"length": 0,
- "no_copy": 0,
+ "no_copy": 1,
"options": "Student Guardian",
"permlevel": 0,
"precision": "",
@@ -1011,19 +1012,19 @@
"unique": 0
}
],
+ "has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_field": "image",
"image_view": 0,
"in_create": 0,
- "in_dialog": 0,
"is_submittable": 1,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
- "modified": "2017-02-21 01:14:59.352772",
+ "modified": "2017-03-15 17:49:15.345022",
"modified_by": "Administrator",
"module": "Schools",
"name": "Student Applicant",
@@ -1051,10 +1052,10 @@
"write": 1
}
],
- "quick_entry": 1,
+ "quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
- "show_name_in_global_search": 1,
+ "show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "title",
diff --git a/erpnext/shopping_cart/cart.py b/erpnext/shopping_cart/cart.py
index b427b94..61ec78c 100644
--- a/erpnext/shopping_cart/cart.py
+++ b/erpnext/shopping_cart/cart.py
@@ -31,10 +31,14 @@
doc = quotation
set_cart_count(quotation)
+ addresses = get_address_docs(party=party)
+
return {
"doc": decorate_quotation_doc(doc),
- "addresses": [{"name": address.name, "display": address.display}
- for address in get_address_docs(party=party)],
+ "shipping_addresses": [{"name": address.name, "display": address.display}
+ for address in addresses if address.address_type == "Shipping"],
+ "billing_addresses": [{"name": address.name, "display": address.display}
+ for address in addresses if address.address_type == "Billing"],
"shipping_rules": get_applicable_shipping_rules(party)
}
diff --git a/erpnext/templates/includes/cart/cart_address.html b/erpnext/templates/includes/cart/cart_address.html
index 29d4f4b..d83f609 100644
--- a/erpnext/templates/includes/cart/cart_address.html
+++ b/erpnext/templates/includes/cart/cart_address.html
@@ -7,7 +7,7 @@
<div class="h6 text-uppercase">{{ _("Shipping Address") }}</div>
<div id="cart-shipping-address" class="panel-group"
data-fieldname="shipping_address_name">
- {% for address in addresses %}
+ {% for address in shipping_addresses %}
{{ show_address(address, doc, "shipping_address_name", select_address) }}
{% endfor %}
</div>
@@ -18,7 +18,7 @@
<div class="h6 text-uppercase">Billing Address</div>
<div id="cart-billing-address" class="panel-group"
data-fieldname="customer_address">
- {% for address in addresses %}
+ {% for address in billing_addresses %}
{{ show_address(address, doc, "customer_address", select_address) }}
{% endfor %}
</div>