Merge branch 'develop' of https://github.com/frappe/erpnext into show_address_in_online_pos
@ -5,7 +5,7 @@ import frappe
|
||||
from erpnext.hooks import regional_overrides
|
||||
from frappe.utils import getdate
|
||||
|
||||
__version__ = '10.0.20'
|
||||
__version__ = '10.0.21'
|
||||
|
||||
def get_default_company(user=None):
|
||||
'''Get default company for user'''
|
||||
|
@ -1177,8 +1177,17 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
$(this.wrapper).on("change", ".pos-item-disc", function () {
|
||||
var item_code = $(this).parents(".pos-selected-item-action").attr("data-item-code");
|
||||
var discount = $(this).val();
|
||||
me.update_discount(item_code, discount)
|
||||
me.update_value()
|
||||
if(discount > 100){
|
||||
discount = $(this).val('');
|
||||
frappe.show_alert({
|
||||
indicator: 'red',
|
||||
message: __('Discount amount cannot be greater than 100%')
|
||||
});
|
||||
me.update_discount(item_code, discount);
|
||||
}else{
|
||||
me.update_discount(item_code, discount);
|
||||
me.update_value();
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
@ -2014,4 +2023,4 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
frappe.throw(__("LocalStorage is full , did not save"))
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
@ -1,3 +1,11 @@
|
||||
<style>
|
||||
@media screen {
|
||||
.print-format {
|
||||
padding: 8mm;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<h2 class="text-center">{%= __(report.report_name) %}</h2>
|
||||
<h4 class="text-center">{%= filters.customer || filters.supplier %} </h4>
|
||||
<h5 class="text-center">
|
||||
@ -6,17 +14,90 @@
|
||||
{%= dateutil.str_to_user(filters.report_date) %}
|
||||
</h5>
|
||||
<hr>
|
||||
{% if(filters.show_pdc_in_print) { %}
|
||||
{% var balance_row = data.slice(-1).pop();
|
||||
var range1 = report.columns[11].label;
|
||||
var range2 = report.columns[12].label;
|
||||
var range3 = report.columns[13].label;
|
||||
var range4 = report.columns[14].label;
|
||||
%}
|
||||
{% if(balance_row) { %}
|
||||
<table class="table table-bordered table-condensed table-sm small">
|
||||
<caption class="text-right">(Amount in {%= data[0][__("currency")] || "" %})</caption>
|
||||
<colgroup>
|
||||
<col style="width: 30mm;">
|
||||
<col style="width: 18mm;">
|
||||
<col style="width: 18mm;">
|
||||
<col style="width: 18mm;">
|
||||
<col style="width: 18mm;">
|
||||
<col style="width: 18mm;">
|
||||
<col style="width: 18mm;">
|
||||
</colgroup>
|
||||
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{%= __(" ") %}</th>
|
||||
<th>{%= __(range1) %}</th>
|
||||
<th>{%= __(range2) %}</th>
|
||||
<th>{%= __(range3) %}</th>
|
||||
<th>{%= __(range4) %}</th>
|
||||
<th>{%= __("Total") %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{%= __("Total Outstanding") %}</td>
|
||||
<td class="text-right">{%= format_currency(balance_row[range1]) %}</td>
|
||||
<td class="text-right">{%= format_currency(balance_row[range2]) %}</td>
|
||||
<td class="text-right">{%= format_currency(balance_row[range3]) %}</td>
|
||||
<td class="text-right">{%= format_currency(balance_row[range4]) %}</td>
|
||||
<td class="text-right">
|
||||
{%= format_currency(flt(balance_row[__("Outstanding Amount")]), data[data.length-1]["currency"]) %}
|
||||
</td>
|
||||
</tr>
|
||||
<td>{%= __("PDC/LC") %}</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td class="text-right">
|
||||
{%= format_currency(flt(balance_row[__("PDC/LC Amount")]), data[data.length-1]["currency"]) %}
|
||||
</td>
|
||||
<tr class="cvs-footer">
|
||||
<th class="text-left">{%= __("Cheques Required") %}</th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th class="text-right">
|
||||
{%= format_currency(flt(balance_row[__("Outstanding Amount")]-balance_row[__("PDC/LC Amount")]), data[data.length-1]["currency"]) %}</th>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
{% } %}
|
||||
{% } %}
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
{% if(report.report_name === "Accounts Receivable" || report.report_name === "Accounts Payable") { %}
|
||||
<th style="width: 14%">{%= __("Date") %}</th>
|
||||
<th style="width: 16%">{%= __("Ref") %}</th>
|
||||
<th style="width: 30%">{%= (filters.customer || filters.supplier) ? __("Remarks"): __("Party") %}</th>
|
||||
<th style="width: 10%">{%= __("Date") %}</th>
|
||||
<th style="width: 10%">{%= __("Ref") %}</th>
|
||||
<th style="width: 20%">{%= (filters.customer || filters.supplier) ? __("Remarks"): __("Party") %}</th>
|
||||
<th style="width: 10%">{%= __("Invoiced Amount") %}</th>
|
||||
<th style="width: 10%">{%= __("Paid Amount") %}</th>
|
||||
<th style="width: 10%">{%= report.report_name === "Accounts Receivable" ? __('Credit Note') : __('Debit Note') %}</th>
|
||||
<th style="width: 10%">{%= __("Outstanding Amount") %}</th>
|
||||
{% if(!filters.show_pdc_in_print) { %}
|
||||
<th style="width: 10%">{%= __("Paid Amount") %}</th>
|
||||
<th style="width: 10%">{%= report.report_name === "Accounts Receivable" ? __('Credit Note') : __('Debit Note') %}</th>
|
||||
{% } %}
|
||||
<th style="width: 6%">{%= __("Outstanding Amount") %}</th>
|
||||
{% if(filters.show_pdc_in_print) { %}
|
||||
{% if(report.report_name === "Accounts Receivable") { %}
|
||||
<th style="width: 6%">{%= __("Customer LPO No.") %}</th>
|
||||
{% } %}
|
||||
<th style="width: 6%">{%= __("PDC/LC Date") %}</th>
|
||||
<th style="width: 6%">{%= __("PDC/LC Ref") %}</th>
|
||||
<th style="width: 6%">{%= __("PDC/LC Amount") %}</th>
|
||||
{% } %}
|
||||
{% } else { %}
|
||||
<th style="width: 40%">{%= (filters.customer || filters.supplier) ? __("Remarks"): __("Party") %}</th>
|
||||
<th style="width: 15%">{%= __("Total Invoiced Amount") %}</th>
|
||||
@ -48,23 +129,49 @@
|
||||
</td>
|
||||
<td style="text-align: right">
|
||||
{%= format_currency(data[i]["Invoiced Amount"], data[i]["currency"]) %}</td>
|
||||
<td style="text-align: right">
|
||||
{%= format_currency(data[i]["Paid Amount"], data[i]["currency"]) %}</td>
|
||||
<td style="text-align: right">
|
||||
{%= report.report_name === "Accounts Receivable" ? format_currency(data[i]["Credit Note"], data[i]["currency"]) : format_currency(data[i]["Debit Note"], data[i]["currency"]) %}</td>
|
||||
|
||||
{% if(!filters.show_pdc_in_print) { %}
|
||||
<td style="text-align: right">
|
||||
{%= format_currency(data[i]["Paid Amount"], data[i]["currency"]) %}</td>
|
||||
<td style="text-align: right">
|
||||
{%= report.report_name === "Accounts Receivable" ? format_currency(data[i]["Credit Note"], data[i]["currency"]) : format_currency(data[i]["Debit Note"], data[i]["currency"]) %}</td>
|
||||
{% } %}
|
||||
<td style="text-align: right">
|
||||
{%= format_currency(data[i]["Outstanding Amount"], data[i]["currency"]) %}</td>
|
||||
|
||||
{% if(filters.show_pdc_in_print) { %}
|
||||
{% if(report.report_name === "Accounts Receivable") { %}
|
||||
<td style="text-align: right">
|
||||
{%= data[i][__("Customer LPO")] %}</td>
|
||||
{% } %}
|
||||
<td style="text-align: right">{%= frappe.datetime.str_to_user(data[i][__("PDC/LC Date")]) %}</td>
|
||||
<td style="text-align: right">{%= data[i][__("PDC/LC Ref")] %}</td>
|
||||
<td style="text-align: right">{%= format_currency(data[i][__("PDC/LC Amount")], data[i]["currency"]) %}</td>
|
||||
{% } %}
|
||||
{% } else { %}
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td><b>{%= __("Total") %}</b></td>
|
||||
<td style="text-align: right">
|
||||
{%= format_currency(data[i]["Invoiced Amount"], data[i]["currency"] ) %}</td>
|
||||
<td style="text-align: right">
|
||||
{%= format_currency(data[i]["Paid Amount"], data[i]["currency"]) %}</td>
|
||||
<td style="text-align: right">{%= report.report_name === "Accounts Receivable" ? format_currency(data[i]["Credit Note"], data[i]["currency"]) : format_currency(data[i]["Debit Note"], data[i]["currency"]) %} </td>
|
||||
|
||||
{% if(!filters.show_pdc_in_print) { %}
|
||||
<td style="text-align: right">
|
||||
{%= format_currency(data[i]["Paid Amount"], data[i]["currency"]) %}</td>
|
||||
<td style="text-align: right">{%= report.report_name === "Accounts Receivable" ? format_currency(data[i]["Credit Note"], data[i]["currency"]) : format_currency(data[i]["Debit Note"], data[i]["currency"]) %} </td>
|
||||
{% } %}
|
||||
<td style="text-align: right">
|
||||
{%= format_currency(data[i]["Outstanding Amount"], data[i]["currency"]) %}</td>
|
||||
|
||||
{% if(filters.show_pdc_in_print) { %}
|
||||
{% if(report.report_name === "Accounts Receivable") { %}
|
||||
<td style="text-align: right">
|
||||
{%= data[i][__("Customer LPO")] %}</td>
|
||||
{% } %}
|
||||
<td style="text-align: right">{%= frappe.datetime.str_to_user(data[i][__("PDC/LC Date")]) %}</td>
|
||||
<td style="text-align: right">{%= data[i][__("PDC/LC Ref")] %}</td>
|
||||
<td style="text-align: right">{%= format_currency(data[i][__("PDC/LC Amount")], data[i]["currency"]) %}</td>
|
||||
{% } %}
|
||||
{% } %}
|
||||
{% } else { %}
|
||||
{% if(data[i][__("Customer")] || data[i][__("Supplier")]|| " ") { %}
|
||||
|
@ -82,6 +82,11 @@ frappe.query_reports["Accounts Receivable"] = {
|
||||
"fieldtype": "Int",
|
||||
"default": "90",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname":"show_pdc_in_print",
|
||||
"label": __("Show PDC in Print"),
|
||||
"fieldtype": "Check",
|
||||
}
|
||||
],
|
||||
|
||||
|
@ -72,6 +72,18 @@ class ReceivablePayableReport(object):
|
||||
"options": "Currency",
|
||||
"width": 100
|
||||
})
|
||||
|
||||
columns += [
|
||||
_("PDC/LC Date") + ":Date:110",
|
||||
_("PDC/LC Ref") + ":Data:110",
|
||||
_("PDC/LC Amount") + ":Currency/currency:130",
|
||||
_("Remaining Balance") + ":Currency/currency:130"
|
||||
]
|
||||
|
||||
if args.get('party_type') == 'Customer':
|
||||
columns += [_("Customer LPO") + ":Data:100"]
|
||||
columns += [_("Delivery Note") + ":Data:100"]
|
||||
|
||||
if args.get("party_type") == "Customer":
|
||||
columns += [
|
||||
_("Territory") + ":Link/Territory:80",
|
||||
@ -89,7 +101,8 @@ class ReceivablePayableReport(object):
|
||||
currency_precision = get_currency_precision() or 2
|
||||
dr_or_cr = "debit" if args.get("party_type") == "Customer" else "credit"
|
||||
|
||||
voucher_details = self.get_voucher_details(args.get("party_type"))
|
||||
dn_details = get_dn_details(args.get("party_type"))
|
||||
voucher_details = self.get_voucher_details(args.get("party_type"), dn_details)
|
||||
|
||||
future_vouchers = self.get_entries_after(self.filters.report_date, args.get("party_type"))
|
||||
|
||||
@ -101,6 +114,8 @@ class ReceivablePayableReport(object):
|
||||
return_entries = self.get_return_entries(args.get("party_type"))
|
||||
|
||||
data = []
|
||||
pdc_details = get_pdc_details(args.get("party_type"))
|
||||
|
||||
for gle in self.get_entries_till(self.filters.report_date, args.get("party_type")):
|
||||
if self.is_receivable_or_payable(gle, dr_or_cr, future_vouchers):
|
||||
outstanding_amount, credit_note_amount = self.get_outstanding_amount(gle,
|
||||
@ -144,6 +159,18 @@ class ReceivablePayableReport(object):
|
||||
else:
|
||||
row.append(company_currency)
|
||||
|
||||
pdc = pdc_details.get(gle.voucher_no, {})
|
||||
remaining_balance = outstanding_amount - flt(pdc.get("pdc_amount"))
|
||||
row += [pdc.get("pdc_date"), pdc.get("pdc_ref"),
|
||||
flt(pdc.get("pdc_amount")), remaining_balance]
|
||||
|
||||
if args.get('party_type') == 'Customer':
|
||||
# customer LPO
|
||||
row += [voucher_details.get(gle.voucher_no, {}).get("po_no")]
|
||||
|
||||
# Delivery Note
|
||||
row += [voucher_details.get(gle.voucher_no, {}).get("delivery_note")]
|
||||
|
||||
# customer territory / supplier type
|
||||
if args.get("party_type") == "Customer":
|
||||
row += [self.get_territory(gle.party), self.get_customer_group(gle.party)]
|
||||
@ -225,12 +252,13 @@ class ReceivablePayableReport(object):
|
||||
|
||||
return self.party_map
|
||||
|
||||
def get_voucher_details(self, party_type):
|
||||
def get_voucher_details(self, party_type, dn_details):
|
||||
voucher_details = frappe._dict()
|
||||
|
||||
if party_type == "Customer":
|
||||
for si in frappe.db.sql("""select name, due_date
|
||||
for si in frappe.db.sql("""select name, due_date, po_no
|
||||
from `tabSales Invoice` where docstatus=1""", as_dict=1):
|
||||
si['delivery_note'] = dn_details.get(si.name)
|
||||
voucher_details.setdefault(si.name, si)
|
||||
|
||||
if party_type == "Supplier":
|
||||
@ -363,3 +391,39 @@ def get_ageing_data(first_range, second_range, third_range, age_as_on, entry_dat
|
||||
outstanding_range[index] = outstanding_amount
|
||||
|
||||
return [age] + outstanding_range
|
||||
|
||||
def get_pdc_details(party_type):
|
||||
pdc_details = frappe._dict()
|
||||
|
||||
for pdc in frappe.db.sql("""
|
||||
select
|
||||
pref.reference_name as invoice_no, pent.party, pent.party_type,
|
||||
max(pent.reference_date) as pdc_date, sum(ifnull(pref.allocated_amount,0)) as pdc_amount,
|
||||
GROUP_CONCAT(pent.reference_no SEPARATOR ', ') as pdc_ref
|
||||
from
|
||||
`tabPayment Entry` as pent inner join `tabPayment Entry Reference` as pref
|
||||
on
|
||||
(pref.parent = pent.name)
|
||||
where
|
||||
pent.docstatus = 0 and pent.reference_date > pent.posting_date
|
||||
and pent.party_type = %s
|
||||
group by pref.reference_name""", party_type, as_dict=1):
|
||||
pdc_details.setdefault(pdc.invoice_no, pdc)
|
||||
|
||||
return pdc_details
|
||||
|
||||
def get_dn_details(party_type):
|
||||
dn_details = frappe._dict()
|
||||
|
||||
if party_type == "Customer":
|
||||
for si in frappe.db.sql("""select parent, GROUP_CONCAT(delivery_note SEPARATOR ', ') as dn
|
||||
from `tabSales Invoice Item`
|
||||
where docstatus=1 and delivery_note is not null and delivery_note != '' group by parent
|
||||
Union
|
||||
select against_sales_invoice as parent, GROUP_CONCAT(parent SEPARATOR ', ') as dn
|
||||
from `tabDelivery Note Item`
|
||||
where docstatus=1 and against_sales_invoice is not null
|
||||
and against_sales_invoice != '' group by against_sales_invoice""", as_dict=1):
|
||||
dn_details.setdefault(si.parent, si.dn)
|
||||
|
||||
return dn_details
|
||||
|
@ -336,7 +336,7 @@ def get_data():
|
||||
"color": "#009248",
|
||||
"icon": "/assets/erpnext/images/hub_logo.svg",
|
||||
"type": "page",
|
||||
"link": "hub",
|
||||
"link": "Hub/Home",
|
||||
"label": _("Hub")
|
||||
},
|
||||
{
|
||||
|
@ -415,13 +415,15 @@ class calculate_taxes_and_totals(object):
|
||||
|
||||
self.doc.total_advance = flt(total_allocated_amount, self.doc.precision("total_advance"))
|
||||
|
||||
grand_total = self.doc.rounded_total or self.doc.grand_total
|
||||
|
||||
if self.doc.party_account_currency == self.doc.currency:
|
||||
invoice_total = flt(self.doc.grand_total - flt(self.doc.write_off_amount),
|
||||
invoice_total = flt(grand_total - flt(self.doc.write_off_amount),
|
||||
self.doc.precision("grand_total"))
|
||||
else:
|
||||
base_write_off_amount = flt(flt(self.doc.write_off_amount) * self.doc.conversion_rate,
|
||||
self.doc.precision("base_write_off_amount"))
|
||||
invoice_total = flt(self.doc.grand_total * self.doc.conversion_rate,
|
||||
invoice_total = flt(grand_total * self.doc.conversion_rate,
|
||||
self.doc.precision("grand_total")) - base_write_off_amount
|
||||
|
||||
if invoice_total > 0 and self.doc.total_advance > invoice_total:
|
||||
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 498 KiB |
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 103 KiB |
BIN
erpnext/docs/assets/img/education/setup/setup.png
Normal file
After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 550 KiB After Width: | Height: | Size: 550 KiB |
BIN
erpnext/docs/assets/img/education/setup/student-category.png
Normal file
After Width: | Height: | Size: 134 KiB |
Before Width: | Height: | Size: 985 KiB After Width: | Height: | Size: 985 KiB |
@ -8,8 +8,6 @@ To create a **Course** enter the Course name and Code. Code for the course shoul
|
||||
|
||||
Once a **Course** is created, a course schedule can defined for the same.
|
||||
|
||||
<img class="screenshot" alt="Course" src="{{docs_base_url}}/assets/img/education/setup/Course.gif">
|
||||
|
||||
The Course form is further linked to **Program, Student Group and Assessment Plan** doctypes. The links allow to view/create the related documents for a **Course**.
|
||||
|
||||
#### Video Tutorial for Course
|
||||
|
@ -3,14 +3,14 @@
|
||||
The Education Settings page allow you to setup basic settings like **Academic Year and Term** for the educational setup.
|
||||
|
||||
|
||||
<img class="screenshot" alt="Student" src="{{docs_base_url}}/assets/img/education/student/education.png">
|
||||
<img class="screenshot" alt="Student" src="{{docs_base_url}}/assets/img/education/setup/education-settings.png">
|
||||
|
||||
The checkbox to Validate Batch for Students in Student Group enables the Student Batch validation for every Student from the Program Enrollment for the **Batch** based on **Student Group**
|
||||
|
||||
<img class="screenshot" alt="Student" src="{{docs_base_url}}/assets/img/education/student/student-batch-validation.gif">
|
||||
<img class="screenshot" alt="Student" src="{{docs_base_url}}/assets/img/education/setup/student-batch-validation.gif">
|
||||
|
||||
You can enable the validation of Course for every Student from the enrolled Courses in Program Enrollment,for Course based Student Group by checking the settings for **Validate Enrolled Course for Students in Student Group**
|
||||
|
||||
<img class="screenshot" alt="Student" src="{{docs_base_url}}/assets/img/education/student/student-course-validation.gif">
|
||||
<img class="screenshot" alt="Student" src="{{docs_base_url}}/assets/img/education/setup/student-course-validation.gif">
|
||||
|
||||
{next}
|
@ -1,8 +1,8 @@
|
||||
# Setup
|
||||
|
||||
The Setup section of education module provides facility to make some basic configuration. Below are doctypes for basic configuration.
|
||||
The Setup section of education module provides facility to make some basic master records and configuration. Below are doctypes for those masters and configuration.
|
||||
|
||||
<img class="screenshot" alt="Setup Section" src="{{docs_base_url}}/assets/img/education/setup/setup-section.png">
|
||||
<img class="screenshot" alt="Setup Section" src="{{docs_base_url}}/assets/img/education/setup/setup.png">
|
||||
|
||||
### Topics
|
||||
|
||||
|
@ -2,11 +2,15 @@
|
||||
|
||||
Student Category doctype allow you to classify student based various categories. In Institutions, there may be fee concession for some categories such as Handicapped students, foreign, nationals, reserved category by the government etc.
|
||||
|
||||
To create Student category go to Setup >> Student Category >> New.
|
||||
To create Student category go to:
|
||||
|
||||
> Setup > Student Category > New
|
||||
|
||||
We can create new student category by adding a name and save it
|
||||
|
||||
<img class="screenshot" alt="Student" src="{{docs_base_url}}/assets/img/education/student/student-category.gif">
|
||||
<img class="screenshot" alt="Student" src="{{docs_base_url}}/assets/img/education/setup/student-category.png">
|
||||
|
||||
You can select the Student Category while making the Fee Structure and accordingly the student from the selected groups can be filtered out while making the Fee Schedule.
|
||||
|
||||
|
||||
{next}
|
@ -15,23 +15,24 @@ def enable_hub():
|
||||
return hub_settings
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_items(start=0, limit=20, category=None, order_by=None, company=None, text=None):
|
||||
def get_list(doctype, start=0, limit=20, fields=["*"], filters="{}", order_by=None):
|
||||
connection = get_client_connection()
|
||||
filters = {
|
||||
'hub_category': category,
|
||||
}
|
||||
if text:
|
||||
filters.update({'item_name': ('like', '%' + text + '%')})
|
||||
if company:
|
||||
filters.update({'company_name': company})
|
||||
filters = json.loads(filters)
|
||||
|
||||
response = connection.get_list('Hub Item',
|
||||
response = connection.get_list(doctype,
|
||||
limit_start=start, limit_page_length=limit,
|
||||
filters=filters)
|
||||
filters=filters, fields=fields)
|
||||
return response
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_meta(doctype):
|
||||
connection = get_client_connection()
|
||||
meta = connection.get_doc('DocType', doctype)
|
||||
return meta
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_categories():
|
||||
# get categories info with parent category and stuff
|
||||
connection = get_client_connection()
|
||||
response = connection.get_list('Hub Category')
|
||||
return response
|
||||
@ -41,7 +42,9 @@ def get_item_details(hub_sync_id=None):
|
||||
if not hub_sync_id:
|
||||
return
|
||||
connection = get_client_connection()
|
||||
return connection.get_doc('Hub Item', hub_sync_id)
|
||||
item_details = connection.get_doc('Hub Item', hub_sync_id)
|
||||
print(item_details)
|
||||
return item_details
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_company_details(hub_sync_id):
|
||||
|
@ -1,8 +0,0 @@
|
||||
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Hub Category', {
|
||||
refresh: function(frm) {
|
||||
|
||||
}
|
||||
});
|
@ -1,275 +0,0 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "field:hub_category_name",
|
||||
"beta": 0,
|
||||
"creation": "2017-08-22 11:31:10.410322",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "hub_category_name",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Category Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "parent_hub_category",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Parent Category",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Hub Category",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "is_group",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Is Group",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Text Editor",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Description",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "lft",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Left",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "rgt",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Right",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "old_parent",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Old Parent",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-09-03 22:04:22.958831",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Hub Node",
|
||||
"name": "Hub Category",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "hub_category_name",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.utils.nestedset import NestedSet
|
||||
from frappe.model.document import Document
|
||||
|
||||
class HubCategory(NestedSet):
|
||||
pass
|
@ -1,4 +0,0 @@
|
||||
frappe.treeview_settings["Hub Category"] = {
|
||||
title: __("Hub Category"),
|
||||
breadcrumb: "Hub"
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
/* eslint-disable */
|
||||
// rename this file from _test_[name] to test_[name] to activate
|
||||
// and remove above this line
|
||||
|
||||
QUnit.test("test: Hub Category", function (assert) {
|
||||
let done = assert.async();
|
||||
|
||||
// number of asserts
|
||||
assert.expect(1);
|
||||
|
||||
frappe.run_serially([
|
||||
// insert a new Hub Category
|
||||
() => frappe.tests.make('Hub Category', [
|
||||
// values to be set
|
||||
{key: 'value'}
|
||||
]),
|
||||
() => {
|
||||
assert.equal(cur_frm.doc.key, 'value');
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
|
||||
});
|
@ -1,10 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
import unittest
|
||||
|
||||
class TestHubCategory(unittest.TestCase):
|
||||
pass
|
@ -1,873 +0,0 @@
|
||||
/* globals Hub, HubList */
|
||||
|
||||
frappe.provide('erpnext.hub');
|
||||
|
||||
frappe.pages['hub'].on_page_load = function(wrapper) {
|
||||
const page = frappe.ui.make_app_page({
|
||||
parent: wrapper,
|
||||
title: 'Hub',
|
||||
single_col: false
|
||||
});
|
||||
|
||||
wrapper.hub_page = new erpnext.hub.Hub({ page });
|
||||
};
|
||||
|
||||
frappe.pages['hub'].on_page_show = function(wrapper) {
|
||||
const hub_page = wrapper.hub_page;
|
||||
const [hub, type, id] = frappe.get_route();
|
||||
|
||||
if (!(hub || type || id)) {
|
||||
hub_page.go_to_home_page();
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === "Products") {
|
||||
hub_page.go_to_item_page(id);
|
||||
} else if (type === "Company") {
|
||||
hub_page.go_to_company_page(id);
|
||||
}
|
||||
}
|
||||
|
||||
erpnext.hub.Hub = class Hub {
|
||||
constructor({ page }) {
|
||||
this.page = page;
|
||||
frappe.require('/assets/erpnext/css/hub.css', () => {
|
||||
this.setup();
|
||||
});
|
||||
}
|
||||
|
||||
setup() {
|
||||
this.setup_header();
|
||||
this.company_cache = {};
|
||||
this.item_cache = {};
|
||||
this.filters = {};
|
||||
this.order_by = '';
|
||||
|
||||
this.$hub_main_section =
|
||||
$(`<div class='hub-main-section'>`).appendTo(this.page.body);
|
||||
this.bind_events();
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.$hub_main_section.empty();
|
||||
this.page.page_form.hide();
|
||||
|
||||
const $layout_main = this.page.wrapper.find('.layout-main');
|
||||
const $page_head = this.page.wrapper.find('.page-head');
|
||||
|
||||
frappe.model.with_doc('Hub Settings', 'Hub Settings', () => {
|
||||
this.hub_settings = frappe.get_doc('Hub Settings');
|
||||
|
||||
if(this.hub_settings.enabled == 0) {
|
||||
let $empty_state = this.page.get_empty_state(
|
||||
__("Register for Hub"),
|
||||
__(`Let other ERPNext users discover your products
|
||||
and automate workflow with Supplier from within ERPNext.`),
|
||||
__("Register")
|
||||
);
|
||||
|
||||
$page_head.hide();
|
||||
$layout_main
|
||||
.find('.layout-side-section, .layout-main-section-wrapper')
|
||||
.hide();
|
||||
$layout_main.append($empty_state);
|
||||
|
||||
$empty_state.find('.btn-primary').on('click', () => {
|
||||
this.register_for_hub();
|
||||
});
|
||||
} else {
|
||||
$page_head.show();
|
||||
$layout_main.find('.page-card-container').remove();
|
||||
$layout_main.find('.layout-side-section, .layout-main-section-wrapper').show();
|
||||
this.setup_live_state();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
register_for_hub() {
|
||||
if (frappe.session.user.includes('Administrator')) {
|
||||
frappe.throw(__('Please login as another user.'))
|
||||
}
|
||||
frappe.verify_password(() => {
|
||||
frappe.call({
|
||||
method: 'erpnext.hub_node.enable_hub',
|
||||
callback: (r) => {
|
||||
if(r.message.enabled == 1) {
|
||||
Object.assign(this.hub_settings, r.message);
|
||||
this.refresh();
|
||||
this.prompt_for_item_sync();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
prompt_for_item_sync() {
|
||||
frappe.call({
|
||||
method: 'frappe.client.get_list',
|
||||
args: {
|
||||
doctype: 'Data Migration Run',
|
||||
filters: {
|
||||
'data_migration_plan': 'Hub Sync'
|
||||
},
|
||||
limit_page_length: 1
|
||||
},
|
||||
callback: function(r) {
|
||||
if (!r) {
|
||||
frappe.confirm(__('Do you want to publish your Items to Hub ?'), () => {
|
||||
this.sync_items_to_hub();
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
setup_header() {
|
||||
this.page.page_title = this.page.wrapper.find('.page-title');
|
||||
this.tag_line = $(`
|
||||
<div class='tag-line-container'>
|
||||
<span class='tag-line text-muted small'>
|
||||
${__('Product listing and discovery for ERPNext users')}
|
||||
</span>
|
||||
</div>`)
|
||||
.appendTo(this.page.page_title);
|
||||
|
||||
this.bind_title();
|
||||
}
|
||||
|
||||
setup_live_state() {
|
||||
if(!this.$search) {
|
||||
this.setup_filters();
|
||||
}
|
||||
this.page.page_form.show();
|
||||
this.setup_menu();
|
||||
this.setup_sidebar();
|
||||
this.render_body();
|
||||
this.setup_lists();
|
||||
}
|
||||
|
||||
setup_filters() {
|
||||
|
||||
// frappe.call({
|
||||
// method: 'erpnext.hub_node.get_categories'
|
||||
// }).then((r) => {
|
||||
// if (r.message) {
|
||||
// const categories = r.message;
|
||||
// console.log("categories", categories);
|
||||
// categories
|
||||
// .map(c => c.hub_category_name)
|
||||
// .map(c => this.sidebar.add_item({
|
||||
// label: c,
|
||||
// on_click: () => {
|
||||
// this.home_item_list &&
|
||||
// this.home_item_list.refresh({
|
||||
// text: '',
|
||||
// start: 0,
|
||||
// limit: 20,
|
||||
// category: c && c !== 'All Categories' ? c : undefined
|
||||
// });
|
||||
// }
|
||||
// }, __('Hub Category')));
|
||||
|
||||
|
||||
// }
|
||||
// });
|
||||
|
||||
// this.category_select = this.page.add_select(__('Category'),
|
||||
// [
|
||||
// {label: __('Sort by Price ...'), value: '' },
|
||||
// {label: __('High to Low'), value: 'price desc' },
|
||||
// {label: __('Low to High'), value: 'price' },
|
||||
// ]
|
||||
// );
|
||||
|
||||
this.price_sort_select = this.page.add_select(__('Sort by Price'),
|
||||
[
|
||||
{label: __('Sort by Price ...'), value: '' },
|
||||
{label: __('High to Low'), value: 'price desc' },
|
||||
{label: __('Low to High'), value: 'price' },
|
||||
]
|
||||
);
|
||||
|
||||
this.criteria_select = this.page.add_select(__('Sort by Criteria'),
|
||||
[
|
||||
{label: __('Most Popular'), value: 'request_count' },
|
||||
{label: __('Newest'), value: 'creation' },
|
||||
]
|
||||
);
|
||||
|
||||
this.price_sort_select.on('change', () => {
|
||||
this.refresh_item_only_page();
|
||||
});
|
||||
|
||||
this.criteria_select.on('change', () => {
|
||||
this.refresh_item_only_page();
|
||||
});
|
||||
|
||||
this.setup_hub_category_filter();
|
||||
this.setup_search();
|
||||
}
|
||||
|
||||
bind_events() {
|
||||
const me = this;
|
||||
this.$hub_main_section
|
||||
.on('click', '.company-link a', function(e) {
|
||||
e.preventDefault();
|
||||
const company_name = $(this).attr('data-company-name');
|
||||
frappe.set_route('hub', 'Company', company_name);
|
||||
})
|
||||
.on('click', '.breadcrumb li', function(e) {
|
||||
e.preventDefault();
|
||||
const $li = $(this);
|
||||
if ($li.attr('data-route') === 'Home') {
|
||||
me.go_to_home_page();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
update_filters() {
|
||||
let price_sort = $(this.price_sort_select).val() || '';
|
||||
let criteria = $(this.criteria_select).val() || '';
|
||||
|
||||
let order_by_params = [];
|
||||
let query_string = '';
|
||||
if(criteria) {
|
||||
order_by_params.push(criteria);
|
||||
// query_string += 'sort_by=' + criteria
|
||||
}
|
||||
if(price_sort) order_by_params.push(price_sort);
|
||||
this.order_by = order_by_params.join(",");
|
||||
// return query_string;
|
||||
}
|
||||
|
||||
reset_filters() {
|
||||
this.order_by = '';
|
||||
$(this.category_select).val('');
|
||||
$(this.price_sort_select).val('');
|
||||
$(this.criteria_select).val('Most Popular');
|
||||
}
|
||||
|
||||
refresh_item_only_page() {
|
||||
this.reset_search();
|
||||
this.update_filters();
|
||||
this.go_to_items_only_page(
|
||||
['hub', 'Products'],
|
||||
'', 'product-list'
|
||||
);
|
||||
}
|
||||
|
||||
bind_title() {
|
||||
this.page.page_title.find('.title-text').on('click', () => {
|
||||
this.go_to_home_page();
|
||||
});
|
||||
}
|
||||
|
||||
render_body() {
|
||||
this.$home_page = $(`
|
||||
<div class = 'hub-home-page'>
|
||||
<div class='banner'></div>
|
||||
<div class='listing-body row'>
|
||||
<div class='main-list-section'></div>
|
||||
</div>
|
||||
</div>
|
||||
`).appendTo(this.$hub_main_section);
|
||||
|
||||
this.$banner = this.$hub_main_section.find('.banner');
|
||||
this.$listing_body = this.$hub_main_section.find('.listing-body');
|
||||
this.$main_list_section = this.$hub_main_section.find('.main-list-section');
|
||||
this.$side_list_section = this.$hub_main_section.find('.side-list-section');
|
||||
}
|
||||
|
||||
setup_lists() {
|
||||
this.home_item_list = new erpnext.hub.HubList({
|
||||
parent: this.$main_list_section,
|
||||
title: 'New',
|
||||
page_length: 20,
|
||||
list_css_class: 'home-product-list',
|
||||
method: 'erpnext.hub_node.get_items',
|
||||
// order_by: 'request_count',
|
||||
filters: {text: '', country: this.country}, // filters at the time of creation
|
||||
on_item_click: (item_code) => {
|
||||
frappe.set_route('hub', 'Products', item_code);
|
||||
}
|
||||
});
|
||||
|
||||
this.home_item_list.setup();
|
||||
}
|
||||
|
||||
setup_hub_category_filter() {
|
||||
const me = this;
|
||||
|
||||
this.hub_category_field = this.page.add_field({
|
||||
fieldtype: 'Autocomplete',
|
||||
label: 'Hub Category',
|
||||
change() {
|
||||
let value = this.get_value();
|
||||
let title = value;
|
||||
if (value === 'All Categories') {
|
||||
// show all items
|
||||
value = null;
|
||||
}
|
||||
|
||||
me.home_item_list.title = title;
|
||||
me.home_item_list.refresh({
|
||||
text: '',
|
||||
start: 0,
|
||||
limit: 20,
|
||||
category: value
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
frappe.call('erpnext.hub_node.get_categories')
|
||||
.then((r) => {
|
||||
if (r.message) {
|
||||
const categories = r.message;
|
||||
|
||||
this.hub_category_field.set_data(
|
||||
categories.map(c => c.hub_category_name)
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setup_search() {
|
||||
this.$search = this.page.add_data(__('Search'));
|
||||
this.$search.on('keypress', (e) => {
|
||||
if(e.which === 13) {
|
||||
var search_term = ($(this.$search).val() || '').toLowerCase();
|
||||
this.go_to_items_only_page(
|
||||
['hub', 'search', search_term],
|
||||
'Search results for \'' + search_term + '\'',
|
||||
'search-product-list',
|
||||
{text: search_term}
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
go_to_items_only_page(route, title, class_name, filters = {text: ''}, by_item_codes=0) {
|
||||
frappe.set_route(route);
|
||||
this.$hub_main_section.empty();
|
||||
this.filtered_item_list = new erpnext.hub.HubList({
|
||||
parent: this.$hub_main_section,
|
||||
title: title,
|
||||
page_length: 20,
|
||||
list_css_class: class_name,
|
||||
method: 'erpnext.hub_node.get_items',
|
||||
order_by: this.order_by,
|
||||
filters: filters,
|
||||
by_item_codes: by_item_codes
|
||||
});
|
||||
this.filtered_item_list.on_item_click = (item_code) => {
|
||||
frappe.set_route('hub', 'Products', item_code);
|
||||
}
|
||||
this.filtered_item_list.setup();
|
||||
}
|
||||
|
||||
go_to_item_page(item_code) {
|
||||
if(this.item_cache) {
|
||||
let item = this.item_cache[item_code];
|
||||
if(item) {
|
||||
this.render_item_page(item);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
this.item_cache = {};
|
||||
}
|
||||
frappe.call({
|
||||
args:{
|
||||
hub_sync_id: item_code
|
||||
},
|
||||
method: "erpnext.hub_node.get_item_details",
|
||||
callback: (r) => {
|
||||
if (!r || !r.message) return;
|
||||
let item = r.message;
|
||||
this.item_cache[item_code] = item;
|
||||
this.render_item_page(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render_item_page(item) {
|
||||
this.$hub_main_section.empty();
|
||||
|
||||
|
||||
let $item_page =
|
||||
$(this.get_item_page(item))
|
||||
.appendTo(this.$hub_main_section);
|
||||
|
||||
let $company_items = $item_page.find('.company-items');
|
||||
|
||||
let company_item_list = new erpnext.hub.HubList({
|
||||
parent: $company_items,
|
||||
title: 'More by ' + item.company_name,
|
||||
page_length: 5,
|
||||
list_css_class: 'company-item-list',
|
||||
method: 'erpnext.hub_node.get_items',
|
||||
// order_by: 'request_count',
|
||||
filters: {text: '', company_name: item.company_name, country: this.country},
|
||||
paginated: 0,
|
||||
img_size: 150
|
||||
});
|
||||
|
||||
company_item_list.on_item_click = (item_code) => {
|
||||
frappe.set_route('hub', 'Products', item_code);
|
||||
}
|
||||
company_item_list.setup();
|
||||
|
||||
$item_page.find('.rfq-btn')
|
||||
.click((e) => {
|
||||
const $btn = $(e.target);
|
||||
|
||||
this.show_rfq_modal(item)
|
||||
.then(values => {
|
||||
item.item_code = values.item_code;
|
||||
delete values.item_code;
|
||||
|
||||
const supplier = values;
|
||||
return [item, supplier];
|
||||
})
|
||||
.then(([item, supplier]) => {
|
||||
return this.make_rfq(item, supplier, $btn);
|
||||
})
|
||||
.then(r => {
|
||||
console.log(r);
|
||||
if (r.message && r.message.rfq) {
|
||||
$btn.addClass('disabled').html(`<span><i class='fa fa-check'></i> ${__('Quote Requested')}</span>`);
|
||||
} else {
|
||||
throw r;
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log(e); //eslint-disable-line
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
show_rfq_modal(item) {
|
||||
return new Promise(res => {
|
||||
let fields = [
|
||||
{ label: __('Item Code'), fieldtype: 'Data', fieldname: 'item_code', default: item.item_code },
|
||||
{ fieldtype: 'Column Break' },
|
||||
{ label: __('Item Group'), fieldtype: 'Link', fieldname: 'item_group', default: item.item_group },
|
||||
{ label: __('Supplier Details'), fieldtype: 'Section Break' },
|
||||
{ label: __('Supplier Name'), fieldtype: 'Data', fieldname: 'supplier_name', default: item.company_name },
|
||||
{ label: __('Supplier Email'), fieldtype: 'Data', fieldname: 'supplier_email', default: item.seller },
|
||||
{ fieldtype: 'Column Break' },
|
||||
{ label: __('Supplier Type'), fieldname: 'supplier_type',
|
||||
fieldtype: 'Link', options: 'Supplier Type' }
|
||||
];
|
||||
fields = fields.map(f => { f.reqd = 1; return f; });
|
||||
|
||||
const d = new frappe.ui.Dialog({
|
||||
title: __('Request for Quotation'),
|
||||
fields: fields,
|
||||
primary_action_label: __('Send'),
|
||||
primary_action: (values) => {
|
||||
res(values);
|
||||
d.hide();
|
||||
}
|
||||
});
|
||||
|
||||
d.show();
|
||||
});
|
||||
}
|
||||
|
||||
get_company_details(company_id) {
|
||||
this.company_cache = this.company_cache || {};
|
||||
|
||||
return new Promise(resolve => {
|
||||
// get from cache if exists
|
||||
let company_details = this.company_cache[company_id];
|
||||
if(company_details) {
|
||||
resolve(company_details);
|
||||
return;
|
||||
}
|
||||
frappe.call({
|
||||
method: 'erpnext.hub_node.get_company_details',
|
||||
args: {hub_sync_id: company_id}
|
||||
}).then((r) => {
|
||||
if (r.message) {
|
||||
const company_details = r.message;
|
||||
this.company_cache[company_id] = company_details;
|
||||
resolve(company_details)
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
go_to_company_page(company_id) {
|
||||
this.get_company_details(company_id)
|
||||
.then(this.show_company_page.bind(this));
|
||||
}
|
||||
|
||||
show_company_page(company_details) {
|
||||
this.$hub_main_section.empty();
|
||||
|
||||
let $company_page =
|
||||
$(this.get_company_page(company_details))
|
||||
.appendTo(this.$hub_main_section);
|
||||
|
||||
let $company_items = $company_page.find('.company-items');
|
||||
|
||||
let company_item_list = new erpnext.hub.HubList({
|
||||
parent: $company_items,
|
||||
title: 'More by ' + company_details.company_name,
|
||||
page_length: 5,
|
||||
list_css_class: 'company-item-list',
|
||||
method: 'erpnext.hub_node.get_items',
|
||||
// order_by: 'request_count',
|
||||
filters: {text: '', company: company_details.company_name, country: this.country},
|
||||
paginated: 0,
|
||||
img_size: 150
|
||||
});
|
||||
|
||||
company_item_list.on_item_click = (item_code) => {
|
||||
frappe.set_route('hub', 'Products', item_code);
|
||||
}
|
||||
company_item_list.setup();
|
||||
}
|
||||
|
||||
get_item_page(item) {
|
||||
return `
|
||||
<div class="hub-item-page">
|
||||
<div class="item-header">
|
||||
<div class="item-page-image">
|
||||
${ this.home_item_list.get_item_image(item) }
|
||||
</div>
|
||||
<div class="title-content">
|
||||
<div class="breadcrumbs">
|
||||
${this.get_breadcrumb(item.item_name, "Products") }
|
||||
</div>
|
||||
<div class="title">
|
||||
<h2>${ item.item_name }</h2>
|
||||
</div>
|
||||
<div class="company">
|
||||
<span class="">${ item.company_name }</span>
|
||||
</div>
|
||||
<div class="category">
|
||||
<span class="text-muted">Products</span>
|
||||
</div>
|
||||
<div class="description">
|
||||
<span class="small">${ item.description ? item.description : "" }</span>
|
||||
</div>
|
||||
<div class="price">
|
||||
${ item.formatted_price ? item.formatted_price : '' }
|
||||
</div>
|
||||
<div class="actions">
|
||||
<a class="btn btn-primary rfq-btn">Request A Quote</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="item-more-info"></div>
|
||||
<div class="company-items">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
get_company_page(company_details) {
|
||||
return `
|
||||
<div class="hub-item-page">
|
||||
<div class="item-header">
|
||||
<div class="title-content">
|
||||
<div class="breadcrumbs">
|
||||
${this.get_breadcrumb(company_details.company_name, "Company") }
|
||||
</div>
|
||||
<div class="title">
|
||||
<h2>${ company_details.company_name }</h2>
|
||||
</div>
|
||||
<div class="company">
|
||||
<span class="">${ company_details.country }</span>
|
||||
</div>
|
||||
<div class="description">
|
||||
<span class="small">${ company_details.site_name }</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="item-more-info"></div>
|
||||
<div class="company-items">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
get_breadcrumb(name, type) {
|
||||
return `
|
||||
<ul class="breadcrumb">
|
||||
<li data-route="Home">
|
||||
<a href><span>Home</span></a>
|
||||
</li>
|
||||
<li data-route="List">
|
||||
<a href><span>${type}</span></a>
|
||||
</li>
|
||||
<li class="active">
|
||||
<span>${name}</span>
|
||||
</li>
|
||||
</ul>
|
||||
`;
|
||||
}
|
||||
|
||||
go_to_home_page() {
|
||||
frappe.set_route('hub');
|
||||
this.reset_filters();
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
setup_menu() {
|
||||
if (this.menu_setup) return;
|
||||
|
||||
this.page.add_menu_item(__('Hub Settings'),
|
||||
() => frappe.set_route('Form', 'Hub Settings'));
|
||||
this.page.add_menu_item(__('Refresh'), () => this.refresh());
|
||||
this.page.add_menu_item(__('Sync'), () => this.sync_items_to_hub());
|
||||
|
||||
this.menu_setup = true;
|
||||
}
|
||||
|
||||
sync_items_to_hub() {
|
||||
frappe.call('erpnext.hub_node.doctype.hub_settings.hub_settings.sync')
|
||||
}
|
||||
|
||||
setup_sidebar() {
|
||||
var me = this;
|
||||
this.sidebar = new frappe.ui.Sidebar({
|
||||
wrapper: this.page.wrapper.find('.layout-side-section'),
|
||||
css_class: 'hub-sidebar'
|
||||
});
|
||||
|
||||
this.add_account_to_sidebar();
|
||||
}
|
||||
|
||||
add_account_to_sidebar() {
|
||||
this.sidebar.add_item({
|
||||
label: this.hub_settings.company,
|
||||
on_click: () => frappe.set_route('Form', 'Company', this.hub_settings.company)
|
||||
}, __("Account"));
|
||||
|
||||
this.sidebar.add_item({
|
||||
label: __("My Orders"),
|
||||
on_click: () => frappe.set_route('List', 'Request for Quotation')
|
||||
}, __("Account"));
|
||||
}
|
||||
|
||||
get_search_term() {
|
||||
return this.$search.val();
|
||||
}
|
||||
|
||||
reset_search() {
|
||||
this.$search.val('');
|
||||
}
|
||||
|
||||
make_rfq(item, supplier, btn) {
|
||||
console.log(supplier);
|
||||
return new Promise((resolve, reject) => {
|
||||
frappe.call({
|
||||
method: 'erpnext.hub_node.make_rfq_and_send_opportunity',
|
||||
args: { item, supplier },
|
||||
callback: resolve,
|
||||
btn,
|
||||
}).fail(reject);
|
||||
});
|
||||
}
|
||||
|
||||
go_to_seen_items() {
|
||||
this.go_to_items_only_page(
|
||||
['hub', 'Requested Products'],
|
||||
__('Requested Products'),
|
||||
'requested-product-list',
|
||||
{}, 1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
erpnext.hub.HubList = class HubList {
|
||||
constructor({
|
||||
parent = null,
|
||||
title = 'Products',
|
||||
page_length = 20,
|
||||
list_css_class = '',
|
||||
method = 'erpnext.hub_node.get_items',
|
||||
filters = {text: ''},
|
||||
order_by = '',
|
||||
by_item_codes = 0,
|
||||
paginated = 1,
|
||||
on_item_click = null,
|
||||
img_size = 200
|
||||
}) {
|
||||
this.parent = parent;
|
||||
this.title = title;
|
||||
this.page_length = page_length;
|
||||
this.list_css_class = list_css_class;
|
||||
this.method = method;
|
||||
this.filters = filters;
|
||||
this.order_by = order_by;
|
||||
this.by_item_codes = by_item_codes;
|
||||
this.paginated = paginated;
|
||||
|
||||
this.on_item_click = on_item_click;
|
||||
this.img_size = img_size;
|
||||
}
|
||||
|
||||
// to be called on demand
|
||||
setup() {
|
||||
this.container = $(`
|
||||
<div class='item-list-container ${this.list_css_class}' data-page-length='${this.page_length}'>
|
||||
<div class='item-list-header'>
|
||||
<h3>${this.title}</h3>
|
||||
</div>
|
||||
<div class='item-list'></div>
|
||||
<div class='list-state'>
|
||||
<div class='loading'>
|
||||
<p class='text-muted text-center'>${__('Loading...')}</p>
|
||||
</div>
|
||||
<div class='done hide'>
|
||||
<p class='text-muted text-center'>${__('No more results')}</p>
|
||||
</div>
|
||||
<div class='more text-right'>
|
||||
<button class='btn btn-default btn-sm'>${__('More')}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`)
|
||||
.appendTo(this.parent);
|
||||
|
||||
this.$item_list_title = this.container.find('.item-list-header h3');
|
||||
this.$list = this.container.find('.item-list');
|
||||
this.$loading = this.container.find('.loading').hide();
|
||||
this.$more = this.container.find('.more').hide();
|
||||
this.$done = this.container.find('.done');
|
||||
|
||||
this.$more.on('click', () => {
|
||||
this.next_page();
|
||||
});
|
||||
|
||||
this.next_page();
|
||||
}
|
||||
|
||||
refresh(filters = this.filters) {
|
||||
this.reset();
|
||||
this.set_filters(filters);
|
||||
this.next_page();
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.$list.empty();
|
||||
}
|
||||
|
||||
set_filters(filters) {
|
||||
this.filters = filters;
|
||||
}
|
||||
|
||||
next_page() {
|
||||
this.$item_list_title.html(this.title);
|
||||
const start = this.$list.find('.hub-item-wrapper').length;
|
||||
this.$loading.show();
|
||||
|
||||
// build args
|
||||
let args = {
|
||||
start: start,
|
||||
// query one extra
|
||||
limit: this.page_length + 1
|
||||
};
|
||||
Object.assign(args, this.filters);
|
||||
console.log("filters: ", args);
|
||||
args.order_by = this.order_by;
|
||||
args.by_item_codes = this.by_item_codes;
|
||||
|
||||
frappe.call({
|
||||
method: this.method,
|
||||
args: args,
|
||||
callback: (r) => {
|
||||
let items = r.message;
|
||||
console.log("items: ", items);
|
||||
this.render_items(items);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render_items(items) {
|
||||
if(items) {
|
||||
// clear any filler divs
|
||||
this.$list.find('.filler').remove();
|
||||
let done = 0;
|
||||
console.log("items length", items.length);
|
||||
if(items.length && items.length > this.page_length) {
|
||||
// remove the extra queried
|
||||
items.pop();
|
||||
} else {
|
||||
done = 1;
|
||||
}
|
||||
items.forEach((item) => {
|
||||
this.make_item_card(item).appendTo(this.$list);
|
||||
});
|
||||
|
||||
const remainder = items.length % 4;
|
||||
if (remainder > 0) {
|
||||
// fill with filler divs to make flexbox happy
|
||||
Array.from(Array(remainder))
|
||||
.map(r => $('<div class="filler">').css('width', '200px').appendTo(this.$list));
|
||||
}
|
||||
this.update_list_state(done);
|
||||
} else {
|
||||
this.update_list_state(1);
|
||||
}
|
||||
}
|
||||
|
||||
update_list_state(done=0) {
|
||||
this.$loading.hide();
|
||||
if(done) {
|
||||
this.$done.removeClass('hide');
|
||||
this.$more.hide();
|
||||
} else {
|
||||
this.$more.show();
|
||||
this.$done.addClass('hide');
|
||||
}
|
||||
}
|
||||
|
||||
make_item_card(item) {
|
||||
let $item_card = $(`
|
||||
<div class="hub-item-wrapper" style="max-width: ${this.img_size}px;">
|
||||
<a class="item-link" href>
|
||||
<div class="hub-item-image">
|
||||
${ this.get_item_image(item) }
|
||||
</div>
|
||||
<div class="hub-item-title">
|
||||
<h5 class="bold">
|
||||
${!item.seen ? item.item_name : `<span class="indicator blue">${item.item_name}</span>`}
|
||||
<h5>
|
||||
</div>
|
||||
</a>
|
||||
<div class="company-link">
|
||||
<a data-company-name="${ item.company_name }" class="">${ item.company_name }</a>
|
||||
</div>
|
||||
<div>${ item.formatted_price ? item.formatted_price : ''}</div>
|
||||
</div>
|
||||
`);
|
||||
|
||||
$item_card.find(".item-link").click((e) => {
|
||||
e.preventDefault();
|
||||
this.on_item_click && this.on_item_click(item.name);
|
||||
});
|
||||
|
||||
return $item_card;
|
||||
}
|
||||
|
||||
get_item_image(item, size=this.img_size) {
|
||||
const _size = size + 'px';
|
||||
const item_image = item.image ?
|
||||
`<img src="${item.image}"><span class="helper"></span>` :
|
||||
`<div class="standard-image">${item.item_name[0]}</div>`;
|
||||
|
||||
return `
|
||||
<div class="img-wrapper"
|
||||
style="max-width: ${_size}; width: ${_size}; height: ${_size};">
|
||||
${item_image}
|
||||
</div>`;
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
{
|
||||
"content": null,
|
||||
"creation": "2015-02-18 05:17:17.301735",
|
||||
"docstatus": 0,
|
||||
"doctype": "Page",
|
||||
"modified": "2015-02-18 05:17:17.301735",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Hub Node",
|
||||
"name": "hub",
|
||||
"owner": "Administrator",
|
||||
"page_name": "hub",
|
||||
"roles": [
|
||||
{
|
||||
"role": "All"
|
||||
}
|
||||
],
|
||||
"script": null,
|
||||
"standard": "Yes",
|
||||
"style": null,
|
||||
"title": "Hub"
|
||||
}
|
@ -36,7 +36,8 @@
|
||||
"public/js/utils/item_quick_entry.js",
|
||||
"public/js/utils/customer_quick_entry.js",
|
||||
"public/js/education/student_button.html",
|
||||
"public/js/education/assessment_result_tool.html"
|
||||
"public/js/education/assessment_result_tool.html",
|
||||
"public/js/hub/hub_factory.js"
|
||||
],
|
||||
"js/item-dashboard.min.js": [
|
||||
"stock/dashboard/item_dashboard.html",
|
||||
|
@ -1,3 +1,29 @@
|
||||
body[data-route^="Hub/"] .freeze .image-view-container .list-row-col {
|
||||
background-color: #fafbfc;
|
||||
color: #fafbfc;
|
||||
}
|
||||
body[data-route^="Hub/"] .freeze .image-view-container .placeholder-text {
|
||||
color: #fafbfc;
|
||||
}
|
||||
body[data-route^="Hub/"] .freeze {
|
||||
display: none;
|
||||
}
|
||||
body[data-route^="Hub/"] .image-view-container {
|
||||
justify-content: space-around;
|
||||
}
|
||||
.img-wrapper {
|
||||
border: 1px solid #d1d8dd;
|
||||
border-radius: 3px;
|
||||
padding: 12px;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.img-wrapper .helper {
|
||||
height: 100%;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
/* hub */
|
||||
div[data-page-route="hub"] .page-head {
|
||||
height: 80px;
|
||||
|
@ -458,7 +458,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
}
|
||||
|
||||
var party = me.frm.doc[frappe.model.scrub(party_type)];
|
||||
if(party) {
|
||||
if(party && me.frm.doc.company) {
|
||||
return frappe.call({
|
||||
method: "erpnext.accounts.party.get_party_account",
|
||||
args: {
|
||||
|
51
erpnext/public/js/hub/hub_factory.js
Normal file
@ -0,0 +1,51 @@
|
||||
frappe.provide('erpnext.hub.pages');
|
||||
|
||||
frappe.views.HubFactory = frappe.views.Factory.extend({
|
||||
make(route) {
|
||||
const page_name = frappe.get_route_str();
|
||||
const page = route[1];
|
||||
|
||||
const assets = {
|
||||
'List': [
|
||||
'/assets/erpnext/js/hub/hub_page.js',
|
||||
'/assets/erpnext/css/hub.css',
|
||||
],
|
||||
'Form': [
|
||||
'/assets/erpnext/js/hub/hub_form.js',
|
||||
'/assets/erpnext/css/hub.css',
|
||||
]
|
||||
};
|
||||
|
||||
if (!erpnext.hub.pages[page_name]) {
|
||||
if (page === 'Item' && !route[2]) {
|
||||
frappe.require(assets['List'], () => {
|
||||
erpnext.hub.pages[page_name] = new erpnext.hub.ItemListing({
|
||||
doctype: 'Hub Settings',
|
||||
parent: this.make_page(true, page_name)
|
||||
});
|
||||
window.hub_page = erpnext.hub.pages[page_name];
|
||||
});
|
||||
} if (page === 'Company' && !route[2]) {
|
||||
frappe.require(assets['List'], () => {
|
||||
erpnext.hub.pages[page_name] = new erpnext.hub.CompanyListing({
|
||||
doctype: 'Hub Settings',
|
||||
parent: this.make_page(true, page_name)
|
||||
});
|
||||
window.hub_page = erpnext.hub.pages[page_name];
|
||||
});
|
||||
} else if(route[2]) {
|
||||
frappe.require(assets['Form'], () => {
|
||||
erpnext.hub.pages[page_name] = new erpnext.hub.HubForm({
|
||||
hub_item_code: route[2],
|
||||
doctype: 'Hub Settings',
|
||||
parent: this.make_page(true, page_name)
|
||||
});
|
||||
window.hub_page = erpnext.hub.pages[page_name];
|
||||
});
|
||||
}
|
||||
} else {
|
||||
frappe.container.change_to(page_name);
|
||||
window.hub_page = erpnext.hub.pages[page_name];
|
||||
}
|
||||
}
|
||||
});
|
84
erpnext/public/js/hub/hub_form.js
Normal file
@ -0,0 +1,84 @@
|
||||
frappe.provide('erpnext.hub');
|
||||
|
||||
erpnext.hub.HubForm = class HubForm extends frappe.views.BaseList {
|
||||
setup_defaults() {
|
||||
super.setup_defaults();
|
||||
this.page_title = this.data.item_name || this.hub_item_code || __('Hub Item');
|
||||
this.method = 'erpnext.hub_node.get_item_details';
|
||||
}
|
||||
|
||||
setup_fields() {
|
||||
this.fields = ['hub_item_code', 'item_name', 'item_code', 'description', 'seller', 'company_name', 'country'];
|
||||
}
|
||||
|
||||
set_breadcrumbs() {
|
||||
frappe.breadcrumbs.add({
|
||||
label: __('Hub'),
|
||||
route: '#Hub/Item',
|
||||
type: 'Custom'
|
||||
});
|
||||
}
|
||||
|
||||
setup_side_bar() {
|
||||
this.sidebar = new frappe.ui.Sidebar({
|
||||
wrapper: this.$page.find('.layout-side-section'),
|
||||
css_class: 'hub-form-sidebar'
|
||||
});
|
||||
}
|
||||
|
||||
setup_filter_area() {
|
||||
|
||||
}
|
||||
|
||||
setup_sort_selector() {
|
||||
|
||||
}
|
||||
|
||||
get_args() {
|
||||
return {
|
||||
hub_sync_id: this.hub_item_code
|
||||
};
|
||||
}
|
||||
|
||||
prepare_data(r) {
|
||||
this.data = r.message;
|
||||
}
|
||||
|
||||
update_data(r) {
|
||||
this.data = r.message;
|
||||
}
|
||||
|
||||
render() {
|
||||
this.sidebar.add_item({
|
||||
label: `<img src="${this.data.image}" />`
|
||||
});
|
||||
|
||||
let fields = [];
|
||||
this.fields.map(fieldname => {
|
||||
fields.push({
|
||||
label: toTitle(frappe.model.unscrub(fieldname)),
|
||||
fieldname,
|
||||
fieldtype: 'Data',
|
||||
read_only: 1
|
||||
});
|
||||
});
|
||||
|
||||
this.form = new frappe.ui.FieldGroup({
|
||||
parent: this.$result,
|
||||
fields
|
||||
});
|
||||
|
||||
this.form.make();
|
||||
this.form.set_values(this.data);
|
||||
}
|
||||
|
||||
toggle_result_area() {
|
||||
this.$result.toggle(this.data.hub_item_code);
|
||||
this.$paging_area.toggle(this.data.length > 0);
|
||||
this.$no_result.toggle(this.data.length == 0);
|
||||
|
||||
const show_more = (this.start + this.page_length) <= this.data.length;
|
||||
this.$paging_area.find('.btn-more')
|
||||
.toggle(show_more);
|
||||
}
|
||||
};
|
221
erpnext/public/js/hub/hub_page.js
Normal file
@ -0,0 +1,221 @@
|
||||
frappe.provide('erpnext.hub');
|
||||
|
||||
erpnext.hub.HubListing = class HubListing extends frappe.views.BaseList {
|
||||
setup_defaults() {
|
||||
super.setup_defaults();
|
||||
this.page_title = __('Hub');
|
||||
this.method = 'erpnext.hub_node.get_list';
|
||||
|
||||
const route = frappe.get_route();
|
||||
this.page_name = route[1];
|
||||
}
|
||||
|
||||
setup_fields() {
|
||||
return this.get_meta()
|
||||
.then(r => {
|
||||
console.log('fields then', this.doctype);
|
||||
this.meta = r.message || this.meta;
|
||||
frappe.model.sync(this.meta);
|
||||
});
|
||||
}
|
||||
|
||||
get_meta() {
|
||||
console.log('get_meta', this.doctype);
|
||||
return new Promise(resolve =>
|
||||
frappe.call('erpnext.hub_node.get_meta', {doctype: this.doctype}, resolve));
|
||||
}
|
||||
|
||||
set_breadcrumbs() { }
|
||||
|
||||
setup_side_bar() { }
|
||||
|
||||
setup_sort_selector() { }
|
||||
|
||||
setup_view() { }
|
||||
|
||||
get_args() {
|
||||
return {
|
||||
doctype: this.doctype,
|
||||
start: this.start,
|
||||
limit: this.page_length,
|
||||
order_by: this.order_by,
|
||||
fields: this.fields,
|
||||
filters: this.get_filters_for_args()
|
||||
};
|
||||
}
|
||||
|
||||
update_data(r) {
|
||||
const data = r.message;
|
||||
console.log('update data', data);
|
||||
|
||||
if (this.start === 0) {
|
||||
this.data = data;
|
||||
} else {
|
||||
this.data = this.data.concat(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
freeze(toggle) {
|
||||
this.$freeze.toggle(toggle);
|
||||
if (this.$freeze.find('.image-view-container').length) return;
|
||||
|
||||
const html = Array.from(new Array(4)).map(d => this.card_html({
|
||||
name: 'Loading...',
|
||||
item_name: 'Loading...'
|
||||
})).join('');
|
||||
|
||||
this.$freeze.html(`<div class="image-view-container border-top">${html}</div>`);
|
||||
}
|
||||
|
||||
render() {
|
||||
this.render_image_view();
|
||||
}
|
||||
|
||||
render_image_view() {
|
||||
let data = this.data;
|
||||
// console.log('this.data render', this.data);
|
||||
if (this.start === 0) {
|
||||
this.$result.html('<div class="image-view-container small padding-top">');
|
||||
data = this.data.slice(this.start);
|
||||
}
|
||||
|
||||
var html = data.map(this.card_html.bind(this)).join("");
|
||||
this.$result.find('.image-view-container').append(html);
|
||||
}
|
||||
}
|
||||
|
||||
erpnext.hub.ItemListing = class ItemListing extends erpnext.hub.HubListing {
|
||||
setup_defaults() {
|
||||
super.setup_defaults();
|
||||
this.doctype = 'Hub Item';
|
||||
this.fields = ['name', 'hub_item_code', 'image', 'item_name', 'item_code', 'company_name'];
|
||||
this.filters = [];
|
||||
this.custom_filter_configs = [
|
||||
{
|
||||
fieldtype: 'Data',
|
||||
label: 'Company',
|
||||
condition: 'like',
|
||||
fieldname: 'company_name',
|
||||
},
|
||||
{
|
||||
fieldtype: 'Link',
|
||||
label: 'Country',
|
||||
options: 'Country',
|
||||
condition: 'like',
|
||||
fieldname: 'country'
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
get_filters_for_args() {
|
||||
let filters = {};
|
||||
this.filter_area.get().forEach(f => {
|
||||
let field = f[1] !== 'name' ? f[1] : 'item_name';
|
||||
filters[field] = [f[2], f[3]];
|
||||
});
|
||||
if(this.current_category) {
|
||||
filters['hub_category'] = this.current_category;
|
||||
}
|
||||
return filters;
|
||||
}
|
||||
|
||||
card_html(item) {
|
||||
item._name = encodeURI(item.name);
|
||||
const encoded_name = item._name;
|
||||
const title = strip_html(item['item_name' || 'item_code']);
|
||||
// console.log(item);
|
||||
const company_name = item['company_name'];
|
||||
|
||||
const route = `#Hub/Item/${item.hub_item_code}`;
|
||||
|
||||
const image_html = item.image ?
|
||||
`<img src="${item.image}">
|
||||
<span class="helper"></span>` :
|
||||
`<div class="standard-image">${frappe.get_abbr(title)}</div>`;
|
||||
|
||||
return `
|
||||
<div class="hub-item-wrapper margin-bottom" style="width: 200px;">
|
||||
<a href="${route}">
|
||||
<div class="hub-item-image">
|
||||
<div class="img-wrapper" style="height: 200px; width: 200px">
|
||||
${image_html}
|
||||
</div>
|
||||
</div>
|
||||
<div class="hub-item-title">
|
||||
<h5 class="bold">
|
||||
${ title }
|
||||
</h5>
|
||||
<p>${ company_name }</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
};
|
||||
|
||||
erpnext.hub.CompanyListing = class CompanyListing extends erpnext.hub.HubListing {
|
||||
setup_defaults() {
|
||||
super.setup_defaults();
|
||||
this.doctype = 'Hub Company';
|
||||
this.fields = ['name', 'site_name', 'seller_city', 'seller_description', 'seller', 'country', 'company_name'];
|
||||
this.filters = [];
|
||||
this.custom_filter_configs = [
|
||||
{
|
||||
fieldtype: 'Data',
|
||||
label: 'Company',
|
||||
condition: 'like',
|
||||
fieldname: 'company_name',
|
||||
},
|
||||
{
|
||||
fieldtype: 'Link',
|
||||
label: 'Country',
|
||||
options: 'Country',
|
||||
condition: 'like',
|
||||
fieldname: 'country'
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
get_filters_for_args() {
|
||||
let filters = {};
|
||||
this.filter_area.get().forEach(f => {
|
||||
let field = f[1] !== 'name' ? f[1] : 'company_name';
|
||||
filters[field] = [f[2], f[3]];
|
||||
});
|
||||
return filters;
|
||||
}
|
||||
|
||||
card_html(item) {
|
||||
item._name = encodeURI(item.name);
|
||||
const encoded_name = item._name;
|
||||
const title = strip_html(item['item_name' || 'item_code']);
|
||||
// console.log(item);
|
||||
const company_name = item['company_name'];
|
||||
|
||||
const route = `#Hub/Item/${item.hub_item_code}`;
|
||||
|
||||
const image_html = item.image ?
|
||||
`<img src="${item.image}">
|
||||
<span class="helper"></span>` :
|
||||
`<div class="standard-image">${frappe.get_abbr(title)}</div>`;
|
||||
|
||||
return `
|
||||
<div class="hub-item-wrapper margin-bottom" style="width: 200px;">
|
||||
<a href="${route}">
|
||||
<div class="hub-item-image">
|
||||
<div class="img-wrapper" style="height: 200px; width: 200px">
|
||||
${image_html}
|
||||
</div>
|
||||
</div>
|
||||
<div class="hub-item-title">
|
||||
<h5 class="bold">
|
||||
${ title }
|
||||
</h5>
|
||||
<p>${ company_name }</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
};
|
@ -1,5 +1,41 @@
|
||||
@import "../../../../frappe/frappe/public/less/variables.less";
|
||||
|
||||
body[data-route^="Hub/"] {
|
||||
.freeze .image-view-container {
|
||||
.list-row-col {
|
||||
background-color: @light-bg;
|
||||
color: @light-bg;
|
||||
}
|
||||
|
||||
.placeholder-text {
|
||||
color: @light-bg;
|
||||
}
|
||||
}
|
||||
|
||||
.freeze {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.image-view-container {
|
||||
justify-content: space-around;
|
||||
}
|
||||
}
|
||||
|
||||
.img-wrapper {
|
||||
border: 1px solid #d1d8dd;
|
||||
border-radius: 3px;
|
||||
padding: 12px;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
|
||||
.helper {
|
||||
height: 100%;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
/* hub */
|
||||
div[data-page-route="hub"] {
|
||||
.page-head {
|
||||
|
@ -3529,8 +3529,8 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-12-19 14:51:52.710612",
|
||||
"modified_by": "nabinhait@gmail.com",
|
||||
"modified": "2018-01-12 15:56:12.483019",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Sales Order",
|
||||
"owner": "Administrator",
|
||||
|
@ -476,13 +476,10 @@ def make_project(source_name, target_doc=None):
|
||||
@frappe.whitelist()
|
||||
def make_delivery_note(source_name, target_doc=None):
|
||||
def set_missing_values(source, target):
|
||||
if source.po_no:
|
||||
if target.po_no:
|
||||
target_po_no = target.po_no.split(", ")
|
||||
target_po_no.append(source.po_no)
|
||||
target.po_no = ", ".join(list(set(target_po_no))) if len(target_po_no) > 1 else target_po_no[0]
|
||||
else:
|
||||
target.po_no = source.po_no
|
||||
so = [d.against_sales_order for d in target.items]
|
||||
if so:
|
||||
po_no_list = frappe.get_all('Sales Order', 'po_no', filters = {'name': ('in', so)})
|
||||
target.po_no = ', '.join(d.po_no for d in po_no_list if d.po_no)
|
||||
|
||||
target.ignore_pricing_rule = 1
|
||||
target.run_method("set_missing_values")
|
||||
|
@ -780,11 +780,19 @@ class POSCart {
|
||||
return;
|
||||
}
|
||||
|
||||
const item_code = this.selected_item.attr('data-item-code');
|
||||
const field = this.selected_item.active_field;
|
||||
const value = this.numpad.get_value();
|
||||
if (this.selected_item.active_field == 'discount_percentage' && this.numpad.get_value() > cint(100)) {
|
||||
frappe.show_alert({
|
||||
indicator: 'red',
|
||||
message: __('Discount amount cannot be greater than 100%')
|
||||
});
|
||||
this.numpad.reset_value();
|
||||
} else {
|
||||
const item_code = this.selected_item.attr('data-item-code');
|
||||
const field = this.selected_item.active_field;
|
||||
const value = this.numpad.get_value();
|
||||
|
||||
this.events.on_field_change(item_code, field, value);
|
||||
this.events.on_field_change(item_code, field, value);
|
||||
}
|
||||
}
|
||||
|
||||
this.events.on_numpad(btn_value);
|
||||
@ -1600,4 +1608,4 @@ class Payment {
|
||||
this.dialog.set_value("paid_amount", this.frm.doc.paid_amount);
|
||||
this.dialog.set_value("outstanding_amount", this.frm.doc.outstanding_amount);
|
||||
}
|
||||
}
|
||||
}
|
@ -398,73 +398,6 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "po_no",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Customer's Purchase Order No",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "po_no",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"print_width": "100px",
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0,
|
||||
"width": "100px"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.po_no",
|
||||
"fieldname": "po_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Customer's Purchase Order Date",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "po_date",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"print_width": "100px",
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0,
|
||||
"width": "100px"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
@ -527,6 +460,133 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
"collapsible_depends_on": "po_no",
|
||||
"columns": 0,
|
||||
"fieldname": "customer_po_details",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Customer PO Details",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "po_no",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Customer's Purchase Order No",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "po_no",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"print_width": "100px",
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0,
|
||||
"width": "100px"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_17",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.po_no",
|
||||
"fieldname": "po_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Customer's Purchase Order Date",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "po_date",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"print_width": "100px",
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0,
|
||||
"width": "100px"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
@ -3730,7 +3790,7 @@
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2018-01-11 14:40:21.152015",
|
||||
"modified": "2018-01-12 15:27:44.471335",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Delivery Note",
|
||||
|