mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-31 18:59:08 +00:00
Merge branch 'develop' of https://github.com/frappe/erpnext into move-exotel-to-separate-app
This commit is contained in:
8
.github/helper/install.sh
vendored
8
.github/helper/install.sh
vendored
@@ -2,13 +2,6 @@
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# Check for merge conflicts before proceeding
|
|
||||||
python -m compileall -f "${GITHUB_WORKSPACE}"
|
|
||||||
if grep -lr --exclude-dir=node_modules "^<<<<<<< " "${GITHUB_WORKSPACE}"
|
|
||||||
then echo "Found merge conflicts"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd ~ || exit
|
cd ~ || exit
|
||||||
|
|
||||||
sudo apt update && sudo apt install redis-server libcups2-dev
|
sudo apt update && sudo apt install redis-server libcups2-dev
|
||||||
@@ -63,6 +56,7 @@ sed -i 's/schedule:/# schedule:/g' Procfile
|
|||||||
sed -i 's/socketio:/# socketio:/g' Procfile
|
sed -i 's/socketio:/# socketio:/g' Procfile
|
||||||
sed -i 's/redis_socketio:/# redis_socketio:/g' Procfile
|
sed -i 's/redis_socketio:/# redis_socketio:/g' Procfile
|
||||||
|
|
||||||
|
bench get-app payments
|
||||||
bench get-app erpnext "${GITHUB_WORKSPACE}"
|
bench get-app erpnext "${GITHUB_WORKSPACE}"
|
||||||
|
|
||||||
if [ "$TYPE" == "server" ]; then bench setup requirements --dev; fi
|
if [ "$TYPE" == "server" ]; then bench setup requirements --dev; fi
|
||||||
|
|||||||
12
.github/workflows/patch.yml
vendored
12
.github/workflows/patch.yml
vendored
@@ -34,6 +34,14 @@ jobs:
|
|||||||
- name: Clone
|
- name: Clone
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Check for valid Python & Merge Conflicts
|
||||||
|
run: |
|
||||||
|
python -m compileall -f "${GITHUB_WORKSPACE}"
|
||||||
|
if grep -lr --exclude-dir=node_modules "^<<<<<<< " "${GITHUB_WORKSPACE}"
|
||||||
|
then echo "Found merge conflicts"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Setup Python
|
- name: Setup Python
|
||||||
uses: "gabrielfalcao/pyenv-action@v9"
|
uses: "gabrielfalcao/pyenv-action@v9"
|
||||||
with:
|
with:
|
||||||
@@ -105,7 +113,6 @@ jobs:
|
|||||||
echo "Updating to v$version"
|
echo "Updating to v$version"
|
||||||
branch_name="version-$version-hotfix"
|
branch_name="version-$version-hotfix"
|
||||||
|
|
||||||
|
|
||||||
git -C "apps/frappe" fetch --depth 1 upstream $branch_name:$branch_name
|
git -C "apps/frappe" fetch --depth 1 upstream $branch_name:$branch_name
|
||||||
git -C "apps/erpnext" fetch --depth 1 upstream $branch_name:$branch_name
|
git -C "apps/erpnext" fetch --depth 1 upstream $branch_name:$branch_name
|
||||||
|
|
||||||
@@ -114,6 +121,7 @@ jobs:
|
|||||||
|
|
||||||
rm -rf ~/frappe-bench/env
|
rm -rf ~/frappe-bench/env
|
||||||
bench setup env
|
bench setup env
|
||||||
|
bench pip install -e ./apps/payments
|
||||||
bench pip install -e ./apps/erpnext
|
bench pip install -e ./apps/erpnext
|
||||||
|
|
||||||
bench --site test_site migrate
|
bench --site test_site migrate
|
||||||
@@ -127,6 +135,8 @@ jobs:
|
|||||||
pyenv global $(pyenv versions | grep '3.10')
|
pyenv global $(pyenv versions | grep '3.10')
|
||||||
rm -rf ~/frappe-bench/env
|
rm -rf ~/frappe-bench/env
|
||||||
bench -v setup env
|
bench -v setup env
|
||||||
|
bench pip install -e ./apps/payments
|
||||||
bench pip install -e ./apps/erpnext
|
bench pip install -e ./apps/erpnext
|
||||||
|
|
||||||
bench --site test_site migrate
|
bench --site test_site migrate
|
||||||
|
bench --site test_site install-app payments
|
||||||
|
|||||||
8
.github/workflows/server-tests-mariadb.yml
vendored
8
.github/workflows/server-tests-mariadb.yml
vendored
@@ -61,6 +61,14 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
python-version: '3.10'
|
python-version: '3.10'
|
||||||
|
|
||||||
|
- name: Check for valid Python & Merge Conflicts
|
||||||
|
run: |
|
||||||
|
python -m compileall -f "${GITHUB_WORKSPACE}"
|
||||||
|
if grep -lr --exclude-dir=node_modules "^<<<<<<< " "${GITHUB_WORKSPACE}"
|
||||||
|
then echo "Found merge conflicts"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v2
|
||||||
with:
|
with:
|
||||||
|
|||||||
9
.github/workflows/server-tests-postgres.yml
vendored
9
.github/workflows/server-tests-postgres.yml
vendored
@@ -48,6 +48,14 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
python-version: '3.10'
|
python-version: '3.10'
|
||||||
|
|
||||||
|
- name: Check for valid Python & Merge Conflicts
|
||||||
|
run: |
|
||||||
|
python -m compileall -f "${GITHUB_WORKSPACE}"
|
||||||
|
if grep -lr --exclude-dir=node_modules "^<<<<<<< " "${GITHUB_WORKSPACE}"
|
||||||
|
then echo "Found merge conflicts"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v2
|
||||||
with:
|
with:
|
||||||
@@ -90,7 +98,6 @@ jobs:
|
|||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-yarn-
|
${{ runner.os }}-yarn-
|
||||||
|
|
||||||
|
|
||||||
- name: Install
|
- name: Install
|
||||||
run: bash ${GITHUB_WORKSPACE}/.github/helper/install.sh
|
run: bash ${GITHUB_WORKSPACE}/.github/helper/install.sh
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ import json
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.integrations.utils import get_payment_gateway_controller
|
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import flt, get_url, nowdate
|
from frappe.utils import flt, get_url, nowdate
|
||||||
from frappe.utils.background_jobs import enqueue
|
from frappe.utils.background_jobs import enqueue
|
||||||
|
from payments.utils import get_payment_gateway_controller
|
||||||
|
|
||||||
from erpnext.accounts.doctype.payment_entry.payment_entry import (
|
from erpnext.accounts.doctype.payment_entry.payment_entry import (
|
||||||
get_company_defaults,
|
get_company_defaults,
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ class TestPeriodClosingVoucher(unittest.TestCase):
|
|||||||
(pcv.name),
|
(pcv.name),
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(pcv_gle, expected_gle)
|
self.assertSequenceEqual(pcv_gle, expected_gle)
|
||||||
|
|
||||||
pcv.reload()
|
pcv.reload()
|
||||||
pcv.cancel()
|
pcv.cancel()
|
||||||
@@ -175,7 +175,7 @@ class TestPeriodClosingVoucher(unittest.TestCase):
|
|||||||
(pcv.name),
|
(pcv.name),
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(pcv_gle, expected_gle)
|
self.assertSequenceEqual(pcv_gle, expected_gle)
|
||||||
|
|
||||||
def make_period_closing_voucher(self, submit=True):
|
def make_period_closing_voucher(self, submit=True):
|
||||||
surplus_account = create_account()
|
surplus_account = create_account()
|
||||||
|
|||||||
@@ -162,6 +162,7 @@ class PurchaseInvoice(BuyingController):
|
|||||||
if tds_category and not for_validate:
|
if tds_category and not for_validate:
|
||||||
self.apply_tds = 1
|
self.apply_tds = 1
|
||||||
self.tax_withholding_category = tds_category
|
self.tax_withholding_category = tds_category
|
||||||
|
self.set_onload("supplier_tds", tds_category)
|
||||||
|
|
||||||
super(PurchaseInvoice, self).set_missing_values(for_validate)
|
super(PurchaseInvoice, self).set_missing_values(for_validate)
|
||||||
|
|
||||||
|
|||||||
@@ -412,7 +412,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"depends_on": "eval: doc.is_return && doc.return_against",
|
"depends_on": "eval: doc.is_return",
|
||||||
"fieldname": "update_billed_amount_in_sales_order",
|
"fieldname": "update_billed_amount_in_sales_order",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hide_days": 1,
|
"hide_days": 1,
|
||||||
@@ -2022,7 +2022,7 @@
|
|||||||
"link_fieldname": "consolidated_invoice"
|
"link_fieldname": "consolidated_invoice"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"modified": "2022-06-16 16:22:44.870575",
|
"modified": "2022-07-11 17:43:56.435382",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Sales Invoice",
|
"name": "Sales Invoice",
|
||||||
|
|||||||
@@ -136,6 +136,11 @@ frappe.query_reports["Accounts Payable"] = {
|
|||||||
"label": __("Tax Id"),
|
"label": __("Tax Id"),
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 1
|
"hidden": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "show_future_payments",
|
||||||
|
"label": __("Show Future Payments"),
|
||||||
|
"fieldtype": "Check",
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|||||||
@@ -164,6 +164,8 @@ class ReceivablePayableReport(object):
|
|||||||
"range3",
|
"range3",
|
||||||
"range4",
|
"range4",
|
||||||
"range5",
|
"range5",
|
||||||
|
"future_amount",
|
||||||
|
"remaining_balance"
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_voucher_balance(self, ple):
|
def get_voucher_balance(self, ple):
|
||||||
@@ -545,7 +547,7 @@ class ReceivablePayableReport(object):
|
|||||||
jea.party,
|
jea.party,
|
||||||
jea.party_type,
|
jea.party_type,
|
||||||
je.posting_date as future_date,
|
je.posting_date as future_date,
|
||||||
sum({0}) as future_amount,
|
sum('{0}') as future_amount,
|
||||||
je.cheque_no as future_ref
|
je.cheque_no as future_ref
|
||||||
from
|
from
|
||||||
`tabJournal Entry` as je inner join `tabJournal Entry Account` as jea
|
`tabJournal Entry` as je inner join `tabJournal Entry Account` as jea
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ class TestAsset(AssetSetup):
|
|||||||
order by account""",
|
order by account""",
|
||||||
pi.name,
|
pi.name,
|
||||||
)
|
)
|
||||||
self.assertEqual(gle, expected_gle)
|
self.assertSequenceEqual(gle, expected_gle)
|
||||||
|
|
||||||
pi.cancel()
|
pi.cancel()
|
||||||
asset.cancel()
|
asset.cancel()
|
||||||
@@ -208,7 +208,7 @@ class TestAsset(AssetSetup):
|
|||||||
order by account""",
|
order by account""",
|
||||||
asset.journal_entry_for_scrap,
|
asset.journal_entry_for_scrap,
|
||||||
)
|
)
|
||||||
self.assertEqual(gle, expected_gle)
|
self.assertSequenceEqual(gle, expected_gle)
|
||||||
|
|
||||||
restore_asset(asset.name)
|
restore_asset(asset.name)
|
||||||
|
|
||||||
@@ -253,7 +253,7 @@ class TestAsset(AssetSetup):
|
|||||||
si.name,
|
si.name,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(gle, expected_gle)
|
self.assertSequenceEqual(gle, expected_gle)
|
||||||
|
|
||||||
si.cancel()
|
si.cancel()
|
||||||
self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Partially Depreciated")
|
self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Partially Depreciated")
|
||||||
@@ -361,7 +361,7 @@ class TestAsset(AssetSetup):
|
|||||||
pr.name,
|
pr.name,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(pr_gle, expected_gle)
|
self.assertSequenceEqual(pr_gle, expected_gle)
|
||||||
|
|
||||||
pi = make_invoice(pr.name)
|
pi = make_invoice(pr.name)
|
||||||
pi.submit()
|
pi.submit()
|
||||||
@@ -381,7 +381,7 @@ class TestAsset(AssetSetup):
|
|||||||
pi.name,
|
pi.name,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(pi_gle, expected_gle)
|
self.assertSequenceEqual(pi_gle, expected_gle)
|
||||||
|
|
||||||
asset = frappe.db.get_value("Asset", {"purchase_receipt": pr.name, "docstatus": 0}, "name")
|
asset = frappe.db.get_value("Asset", {"purchase_receipt": pr.name, "docstatus": 0}, "name")
|
||||||
|
|
||||||
@@ -414,7 +414,7 @@ class TestAsset(AssetSetup):
|
|||||||
asset_doc.name,
|
asset_doc.name,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(gle, expected_gle)
|
self.assertSequenceEqual(gle, expected_gle)
|
||||||
|
|
||||||
def test_asset_cwip_toggling_cases(self):
|
def test_asset_cwip_toggling_cases(self):
|
||||||
cwip = frappe.db.get_value("Asset Category", "Computers", "enable_cwip_accounting")
|
cwip = frappe.db.get_value("Asset Category", "Computers", "enable_cwip_accounting")
|
||||||
@@ -1287,7 +1287,7 @@ class TestDepreciationBasics(AssetSetup):
|
|||||||
asset.name,
|
asset.name,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(gle, expected_gle)
|
self.assertSequenceEqual(gle, expected_gle)
|
||||||
self.assertEqual(asset.get("value_after_depreciation"), 0)
|
self.assertEqual(asset.get("value_after_depreciation"), 0)
|
||||||
|
|
||||||
def test_expected_value_change(self):
|
def test_expected_value_change(self):
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ class TestAssetValueAdjustment(unittest.TestCase):
|
|||||||
adj_doc.journal_entry,
|
adj_doc.journal_entry,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(gle, expected_gle)
|
self.assertSequenceEqual(gle, expected_gle)
|
||||||
|
|
||||||
|
|
||||||
def make_asset_value_adjustment(**args):
|
def make_asset_value_adjustment(**args):
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ erpnext.LeadController = class LeadController extends frappe.ui.form.Controller
|
|||||||
frappe.contacts.clear_address_and_contact(this.frm);
|
frappe.contacts.clear_address_and_contact(this.frm);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.frm.dashboard.links_area.hide();
|
|
||||||
this.show_notes();
|
this.show_notes();
|
||||||
this.show_activities();
|
this.show_activities();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,7 +74,8 @@
|
|||||||
"all_activities_html",
|
"all_activities_html",
|
||||||
"notes_tab",
|
"notes_tab",
|
||||||
"notes_html",
|
"notes_html",
|
||||||
"notes"
|
"notes",
|
||||||
|
"dashboard_tab"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@@ -337,9 +338,10 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "no_of_employees",
|
"fieldname": "no_of_employees",
|
||||||
"fieldtype": "Int",
|
"fieldtype": "Select",
|
||||||
"label": "No. of Employees"
|
"label": "No of Employees",
|
||||||
},
|
"options": "1-10\n11-20\n21-30\n31-100\n11-50\n51-200\n201-500\n101-500\n500-1000\n501-1000\n>1000\n1000+"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "column_break_22",
|
"fieldname": "column_break_22",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
@@ -500,13 +502,19 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Country",
|
"label": "Country",
|
||||||
"options": "Country"
|
"options": "Country"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "dashboard_tab",
|
||||||
|
"fieldtype": "Tab Break",
|
||||||
|
"label": "Dashboard",
|
||||||
|
"show_dashboard": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-user",
|
"icon": "fa fa-user",
|
||||||
"idx": 5,
|
"idx": 5,
|
||||||
"image_field": "image",
|
"image_field": "image",
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-06-27 21:56:17.392756",
|
"modified": "2022-07-22 15:55:03.176094",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "CRM",
|
"module": "CRM",
|
||||||
"name": "Lead",
|
"name": "Lead",
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ frappe.ui.form.on("Opportunity", {
|
|||||||
erpnext.toggle_naming_series();
|
erpnext.toggle_naming_series();
|
||||||
|
|
||||||
if(!frm.is_new() && doc.status!=="Lost") {
|
if(!frm.is_new() && doc.status!=="Lost") {
|
||||||
if(doc.with_items){
|
if(doc.items){
|
||||||
frm.add_custom_button(__('Supplier Quotation'),
|
frm.add_custom_button(__('Supplier Quotation'),
|
||||||
function() {
|
function() {
|
||||||
frm.trigger("make_supplier_quotation")
|
frm.trigger("make_supplier_quotation")
|
||||||
|
|||||||
@@ -225,16 +225,12 @@
|
|||||||
"fieldname": "items_section",
|
"fieldname": "items_section",
|
||||||
"fieldtype": "Tab Break",
|
"fieldtype": "Tab Break",
|
||||||
"label": "Items",
|
"label": "Items",
|
||||||
"oldfieldtype": "Section Break",
|
|
||||||
"options": "fa fa-shopping-cart"
|
"options": "fa fa-shopping-cart"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "items",
|
"fieldname": "items",
|
||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"label": "Items",
|
"label": "Items",
|
||||||
"mandatory_depends_on": "eval: doc.with_items == 1",
|
|
||||||
"oldfieldname": "enquiry_details",
|
|
||||||
"oldfieldtype": "Table",
|
|
||||||
"options": "Opportunity Item"
|
"options": "Opportunity Item"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -409,7 +405,6 @@
|
|||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "with_items",
|
|
||||||
"fieldname": "section_break_32",
|
"fieldname": "section_break_32",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hide_border": 1
|
"hide_border": 1
|
||||||
@@ -466,8 +461,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "no_of_employees",
|
"fieldname": "no_of_employees",
|
||||||
"fieldtype": "Int",
|
"fieldtype": "Select",
|
||||||
"label": "No of Employees"
|
"label": "No of Employees",
|
||||||
|
"options": "1-10\n11-20\n21-30\n31-100\n11-50\n51-200\n201-500\n101-500\n500-1000\n501-1000\n>1000\n1000+"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "annual_revenue",
|
"fieldname": "annual_revenue",
|
||||||
@@ -626,7 +622,7 @@
|
|||||||
"icon": "fa fa-info-sign",
|
"icon": "fa fa-info-sign",
|
||||||
"idx": 195,
|
"idx": 195,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-06-27 18:44:32.858696",
|
"modified": "2022-07-22 18:46:32.858696",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "CRM",
|
"module": "CRM",
|
||||||
"name": "Opportunity",
|
"name": "Opportunity",
|
||||||
|
|||||||
@@ -218,7 +218,7 @@
|
|||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-06-21 15:10:26.887502",
|
"modified": "2022-06-22 15:10:26.887502",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "CRM",
|
"module": "CRM",
|
||||||
"name": "Prospect",
|
"name": "Prospect",
|
||||||
|
|||||||
@@ -201,26 +201,21 @@ class OpportunitySummaryBySalesStage(object):
|
|||||||
def get_chart_data(self):
|
def get_chart_data(self):
|
||||||
labels = []
|
labels = []
|
||||||
datasets = []
|
datasets = []
|
||||||
values = [0] * 8
|
values = [0] * len(self.sales_stage_list)
|
||||||
|
|
||||||
for sales_stage in self.sales_stage_list:
|
|
||||||
labels.append(sales_stage)
|
|
||||||
|
|
||||||
options = {"Number": "count", "Amount": "amount"}[self.filters.get("data_based_on")]
|
options = {"Number": "count", "Amount": "amount"}[self.filters.get("data_based_on")]
|
||||||
|
|
||||||
for data in self.query_result:
|
for data in self.query_result:
|
||||||
for count in range(len(values)):
|
for count in range(len(self.sales_stage_list)):
|
||||||
if data["sales_stage"] == labels[count]:
|
if data["sales_stage"] == self.sales_stage_list[count]:
|
||||||
values[count] = values[count] + data[options]
|
values[count] = values[count] + data[options]
|
||||||
|
|
||||||
datasets.append({"name": options, "values": values})
|
datasets.append({"name": options, "values": values})
|
||||||
|
self.chart = {"data": {"labels": self.sales_stage_list, "datasets": datasets}, "type": "line"}
|
||||||
|
|
||||||
self.chart = {"data": {"labels": labels, "datasets": datasets}, "type": "line"}
|
def get_exchange_rate(self, from_currency, to_currency):
|
||||||
|
|
||||||
def currency_conversion(self, from_currency, to_currency):
|
|
||||||
cacheobj = frappe.cache()
|
cacheobj = frappe.cache()
|
||||||
|
if cacheobj and cacheobj.get(from_currency):
|
||||||
if cacheobj.get(from_currency):
|
|
||||||
return flt(str(cacheobj.get(from_currency), "UTF-8"))
|
return flt(str(cacheobj.get(from_currency), "UTF-8"))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@@ -235,7 +230,7 @@ class OpportunitySummaryBySalesStage(object):
|
|||||||
def convert_to_base_currency(self):
|
def convert_to_base_currency(self):
|
||||||
default_currency = self.get_default_currency()
|
default_currency = self.get_default_currency()
|
||||||
for data in self.query_result:
|
for data in self.query_result:
|
||||||
if data.get("currency") != default_currency:
|
if data.get("currency") and data.get("currency") != default_currency:
|
||||||
opportunity_currency = data.get("currency")
|
opportunity_currency = data.get("currency")
|
||||||
value = self.currency_conversion(opportunity_currency, default_currency)
|
exchange_rate = self.get_exchange_rate(opportunity_currency, default_currency)
|
||||||
data["amount"] = data["amount"] * value
|
data["amount"] = data["amount"] * exchange_rate
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import frappe
|
import frappe
|
||||||
|
from frappe.desk.notifications import notify_mentions
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import cstr, now, today
|
from frappe.utils import cstr, now, today
|
||||||
from pypika import functions
|
from pypika import functions
|
||||||
@@ -204,6 +205,7 @@ class CRMNote(Document):
|
|||||||
def add_note(self, note):
|
def add_note(self, note):
|
||||||
self.append("notes", {"note": note, "added_by": frappe.session.user, "added_on": now()})
|
self.append("notes", {"note": note, "added_by": frappe.session.user, "added_on": now()})
|
||||||
self.save()
|
self.save()
|
||||||
|
notify_mentions(self.doctype, self.name, note)
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def edit_note(self, note, row_id):
|
def edit_note(self, note, row_id):
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
"label": "Territory Wise Sales"
|
"label": "Territory Wise Sales"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"content": "[{\"type\":\"onboarding\",\"data\":{\"onboarding_name\":\"CRM\",\"col\":12}},{\"type\":\"chart\",\"data\":{\"chart_name\":\"Territory Wise Sales\",\"col\":12}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Your Shortcuts</b></span>\",\"col\":12}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Lead\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Opportunity\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Customer\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Analytics\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Dashboard\",\"col\":3}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports & Masters</b></span>\",\"col\":12}},{\"type\":\"card\",\"data\":{\"card_name\":\"Sales Pipeline\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Maintenance\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Campaign\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}}]",
|
"content": "[{\"type\":\"chart\",\"data\":{\"chart_name\":\"Territory Wise Sales\",\"col\":12}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Your Shortcuts</b></span>\",\"col\":12}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Lead\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Opportunity\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Customer\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Analytics\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Dashboard\",\"col\":3}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports & Masters</b></span>\",\"col\":12}},{\"type\":\"card\",\"data\":{\"card_name\":\"Sales Pipeline\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Campaign\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Maintenance\",\"col\":4}}]",
|
||||||
"creation": "2020-01-23 14:48:30.183272",
|
"creation": "2020-01-23 14:48:30.183272",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "Workspace",
|
"doctype": "Workspace",
|
||||||
@@ -45,6 +45,17 @@
|
|||||||
"onboard": 1,
|
"onboard": 1,
|
||||||
"type": "Link"
|
"type": "Link"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"dependencies": "",
|
||||||
|
"hidden": 0,
|
||||||
|
"is_query_report": 0,
|
||||||
|
"label": "Prospect",
|
||||||
|
"link_count": 0,
|
||||||
|
"link_to": "Prospect",
|
||||||
|
"link_type": "DocType",
|
||||||
|
"onboard": 1,
|
||||||
|
"type": "Link"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"dependencies": "",
|
"dependencies": "",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@@ -78,17 +89,6 @@
|
|||||||
"onboard": 0,
|
"onboard": 0,
|
||||||
"type": "Link"
|
"type": "Link"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"dependencies": "",
|
|
||||||
"hidden": 0,
|
|
||||||
"is_query_report": 0,
|
|
||||||
"label": "Lead Source",
|
|
||||||
"link_count": 0,
|
|
||||||
"link_to": "Lead Source",
|
|
||||||
"link_type": "DocType",
|
|
||||||
"onboard": 0,
|
|
||||||
"type": "Link"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"dependencies": "",
|
"dependencies": "",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@@ -122,6 +122,60 @@
|
|||||||
"onboard": 0,
|
"onboard": 0,
|
||||||
"type": "Link"
|
"type": "Link"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"dependencies": "",
|
||||||
|
"hidden": 0,
|
||||||
|
"is_query_report": 0,
|
||||||
|
"label": "Lead Source",
|
||||||
|
"link_count": 0,
|
||||||
|
"link_to": "Lead Source",
|
||||||
|
"link_type": "DocType",
|
||||||
|
"onboard": 0,
|
||||||
|
"type": "Link"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dependencies": "",
|
||||||
|
"hidden": 0,
|
||||||
|
"is_query_report": 0,
|
||||||
|
"label": "Territory",
|
||||||
|
"link_count": 0,
|
||||||
|
"link_to": "Territory",
|
||||||
|
"link_type": "DocType",
|
||||||
|
"onboard": 1,
|
||||||
|
"type": "Link"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dependencies": "",
|
||||||
|
"hidden": 0,
|
||||||
|
"is_query_report": 0,
|
||||||
|
"label": "Customer Group",
|
||||||
|
"link_count": 0,
|
||||||
|
"link_to": "Customer Group",
|
||||||
|
"link_type": "DocType",
|
||||||
|
"onboard": 1,
|
||||||
|
"type": "Link"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dependencies": "",
|
||||||
|
"hidden": 0,
|
||||||
|
"is_query_report": 0,
|
||||||
|
"label": "Sales Person",
|
||||||
|
"link_count": 0,
|
||||||
|
"link_to": "Sales Person",
|
||||||
|
"link_type": "DocType",
|
||||||
|
"onboard": 1,
|
||||||
|
"type": "Link"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": 0,
|
||||||
|
"is_query_report": 0,
|
||||||
|
"label": "Sales Stage",
|
||||||
|
"link_count": 0,
|
||||||
|
"link_to": "Sales Stage",
|
||||||
|
"link_type": "DocType",
|
||||||
|
"onboard": 0,
|
||||||
|
"type": "Link"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"is_query_report": 0,
|
"is_query_report": 0,
|
||||||
@@ -227,47 +281,6 @@
|
|||||||
"onboard": 0,
|
"onboard": 0,
|
||||||
"type": "Link"
|
"type": "Link"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"hidden": 0,
|
|
||||||
"is_query_report": 0,
|
|
||||||
"label": "Maintenance",
|
|
||||||
"link_count": 0,
|
|
||||||
"onboard": 0,
|
|
||||||
"type": "Card Break"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"dependencies": "",
|
|
||||||
"hidden": 0,
|
|
||||||
"is_query_report": 0,
|
|
||||||
"label": "Maintenance Schedule",
|
|
||||||
"link_count": 0,
|
|
||||||
"link_to": "Maintenance Schedule",
|
|
||||||
"link_type": "DocType",
|
|
||||||
"onboard": 1,
|
|
||||||
"type": "Link"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"dependencies": "",
|
|
||||||
"hidden": 0,
|
|
||||||
"is_query_report": 0,
|
|
||||||
"label": "Maintenance Visit",
|
|
||||||
"link_count": 0,
|
|
||||||
"link_to": "Maintenance Visit",
|
|
||||||
"link_type": "DocType",
|
|
||||||
"onboard": 0,
|
|
||||||
"type": "Link"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"dependencies": "",
|
|
||||||
"hidden": 0,
|
|
||||||
"is_query_report": 0,
|
|
||||||
"label": "Warranty Claim",
|
|
||||||
"link_count": 0,
|
|
||||||
"link_to": "Warranty Claim",
|
|
||||||
"link_type": "DocType",
|
|
||||||
"onboard": 0,
|
|
||||||
"type": "Link"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"is_query_report": 0,
|
"is_query_report": 0,
|
||||||
@@ -309,47 +322,6 @@
|
|||||||
"onboard": 0,
|
"onboard": 0,
|
||||||
"type": "Link"
|
"type": "Link"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"hidden": 0,
|
|
||||||
"is_query_report": 0,
|
|
||||||
"label": "Settings",
|
|
||||||
"link_count": 0,
|
|
||||||
"onboard": 0,
|
|
||||||
"type": "Card Break"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"dependencies": "",
|
|
||||||
"hidden": 0,
|
|
||||||
"is_query_report": 0,
|
|
||||||
"label": "Customer Group",
|
|
||||||
"link_count": 0,
|
|
||||||
"link_to": "Customer Group",
|
|
||||||
"link_type": "DocType",
|
|
||||||
"onboard": 1,
|
|
||||||
"type": "Link"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"dependencies": "",
|
|
||||||
"hidden": 0,
|
|
||||||
"is_query_report": 0,
|
|
||||||
"label": "Territory",
|
|
||||||
"link_count": 0,
|
|
||||||
"link_to": "Territory",
|
|
||||||
"link_type": "DocType",
|
|
||||||
"onboard": 1,
|
|
||||||
"type": "Link"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"dependencies": "",
|
|
||||||
"hidden": 0,
|
|
||||||
"is_query_report": 0,
|
|
||||||
"label": "Sales Person",
|
|
||||||
"link_count": 0,
|
|
||||||
"link_to": "Sales Person",
|
|
||||||
"link_type": "DocType",
|
|
||||||
"onboard": 1,
|
|
||||||
"type": "Link"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"dependencies": "",
|
"dependencies": "",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@@ -376,9 +348,27 @@
|
|||||||
"dependencies": "",
|
"dependencies": "",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"is_query_report": 0,
|
"is_query_report": 0,
|
||||||
"label": "SMS Settings",
|
"label": "Email Group",
|
||||||
"link_count": 0,
|
"link_count": 0,
|
||||||
"link_to": "SMS Settings",
|
"link_to": "Email Group",
|
||||||
|
"link_type": "DocType",
|
||||||
|
"onboard": 0,
|
||||||
|
"type": "Link"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": 0,
|
||||||
|
"is_query_report": 0,
|
||||||
|
"label": "Settings",
|
||||||
|
"link_count": 0,
|
||||||
|
"onboard": 0,
|
||||||
|
"type": "Card Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": 0,
|
||||||
|
"is_query_report": 0,
|
||||||
|
"label": "CRM Settings",
|
||||||
|
"link_count": 0,
|
||||||
|
"link_to": "CRM Settings",
|
||||||
"link_type": "DocType",
|
"link_type": "DocType",
|
||||||
"onboard": 0,
|
"onboard": 0,
|
||||||
"type": "Link"
|
"type": "Link"
|
||||||
@@ -387,9 +377,9 @@
|
|||||||
"dependencies": "",
|
"dependencies": "",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"is_query_report": 0,
|
"is_query_report": 0,
|
||||||
"label": "Email Group",
|
"label": "SMS Settings",
|
||||||
"link_count": 0,
|
"link_count": 0,
|
||||||
"link_to": "Email Group",
|
"link_to": "SMS Settings",
|
||||||
"link_type": "DocType",
|
"link_type": "DocType",
|
||||||
"onboard": 0,
|
"onboard": 0,
|
||||||
"type": "Link"
|
"type": "Link"
|
||||||
@@ -415,15 +405,57 @@
|
|||||||
"link_type": "DocType",
|
"link_type": "DocType",
|
||||||
"onboard": 0,
|
"onboard": 0,
|
||||||
"type": "Link"
|
"type": "Link"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden": 0,
|
||||||
|
"is_query_report": 0,
|
||||||
|
"label": "Maintenance",
|
||||||
|
"link_count": 0,
|
||||||
|
"onboard": 0,
|
||||||
|
"type": "Card Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dependencies": "",
|
||||||
|
"hidden": 0,
|
||||||
|
"is_query_report": 0,
|
||||||
|
"label": "Maintenance Schedule",
|
||||||
|
"link_count": 0,
|
||||||
|
"link_to": "Maintenance Schedule",
|
||||||
|
"link_type": "DocType",
|
||||||
|
"onboard": 1,
|
||||||
|
"type": "Link"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dependencies": "",
|
||||||
|
"hidden": 0,
|
||||||
|
"is_query_report": 0,
|
||||||
|
"label": "Maintenance Visit",
|
||||||
|
"link_count": 0,
|
||||||
|
"link_to": "Maintenance Visit",
|
||||||
|
"link_type": "DocType",
|
||||||
|
"onboard": 0,
|
||||||
|
"type": "Link"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dependencies": "",
|
||||||
|
"hidden": 0,
|
||||||
|
"is_query_report": 0,
|
||||||
|
"label": "Warranty Claim",
|
||||||
|
"link_count": 0,
|
||||||
|
"link_to": "Warranty Claim",
|
||||||
|
"link_type": "DocType",
|
||||||
|
"onboard": 0,
|
||||||
|
"type": "Link"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"modified": "2022-01-13 17:53:17.509844",
|
"modified": "2022-07-22 15:03:30.755417",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "CRM",
|
"module": "CRM",
|
||||||
"name": "CRM",
|
"name": "CRM",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"parent_page": "",
|
"parent_page": "",
|
||||||
"public": 1,
|
"public": 1,
|
||||||
|
"quick_lists": [],
|
||||||
"restrict_to_domain": "",
|
"restrict_to_domain": "",
|
||||||
"roles": [],
|
"roles": [],
|
||||||
"sequence_id": 7.0,
|
"sequence_id": 7.0,
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fetch_from": "website_item.image",
|
"fetch_from": "website_item.website_image",
|
||||||
"fieldname": "website_item_image",
|
"fieldname": "website_item_image",
|
||||||
"fieldtype": "Attach",
|
"fieldtype": "Attach",
|
||||||
"label": "Website Item Image",
|
"label": "Website Item Image",
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-07-13 21:02:19.031652",
|
"modified": "2022-06-28 16:44:24.718728",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "E-commerce",
|
"module": "E-commerce",
|
||||||
"name": "Recommended Items",
|
"name": "Recommended Items",
|
||||||
@@ -83,5 +83,6 @@
|
|||||||
"permissions": [],
|
"permissions": [],
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
|
"states": [],
|
||||||
"track_changes": 1
|
"track_changes": 1
|
||||||
}
|
}
|
||||||
@@ -30,10 +30,6 @@ frappe.ui.form.on('Website Item', {
|
|||||||
}, __("View"));
|
}, __("View"));
|
||||||
},
|
},
|
||||||
|
|
||||||
image: () => {
|
|
||||||
refresh_field("image_view");
|
|
||||||
},
|
|
||||||
|
|
||||||
copy_from_item_group: (frm) => {
|
copy_from_item_group: (frm) => {
|
||||||
return frm.call({
|
return frm.call({
|
||||||
doc: frm.doc,
|
doc: frm.doc,
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
"column_break_11",
|
"column_break_11",
|
||||||
"description",
|
"description",
|
||||||
"brand",
|
"brand",
|
||||||
"image",
|
|
||||||
"display_section",
|
"display_section",
|
||||||
"website_image",
|
"website_image",
|
||||||
"website_image_alt",
|
"website_image_alt",
|
||||||
@@ -113,8 +112,11 @@
|
|||||||
{
|
{
|
||||||
"description": "Item Image (if not slideshow)",
|
"description": "Item Image (if not slideshow)",
|
||||||
"fieldname": "website_image",
|
"fieldname": "website_image",
|
||||||
"fieldtype": "Attach",
|
"fieldtype": "Attach Image",
|
||||||
"label": "Website Image"
|
"hidden": 1,
|
||||||
|
"in_preview": 1,
|
||||||
|
"label": "Website Image",
|
||||||
|
"print_hide": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Image Alternative Text",
|
"description": "Image Alternative Text",
|
||||||
@@ -188,14 +190,6 @@
|
|||||||
"options": "Item Group",
|
"options": "Item Group",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "image",
|
|
||||||
"fieldtype": "Attach Image",
|
|
||||||
"hidden": 1,
|
|
||||||
"in_preview": 1,
|
|
||||||
"label": "Image",
|
|
||||||
"print_hide": 1
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"default": "1",
|
"default": "1",
|
||||||
"fieldname": "published",
|
"fieldname": "published",
|
||||||
@@ -348,13 +342,14 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 1,
|
"has_web_view": 1,
|
||||||
"image_field": "image",
|
"image_field": "website_image",
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-09-02 13:08:41.942726",
|
"modified": "2022-06-28 17:10:30.613251",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "E-commerce",
|
"module": "E-commerce",
|
||||||
"name": "Website Item",
|
"name": "Website Item",
|
||||||
|
"naming_rule": "Expression (old style)",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
@@ -410,6 +405,7 @@
|
|||||||
"show_name_in_global_search": 1,
|
"show_name_in_global_search": 1,
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
|
"states": [],
|
||||||
"title_field": "web_item_name",
|
"title_field": "web_item_name",
|
||||||
"track_changes": 1
|
"track_changes": 1
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,12 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
from typing import TYPE_CHECKING, List, Union
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from erpnext.stock.doctype.item.item import Item
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
@@ -114,11 +118,6 @@ class WebsiteItem(WebsiteGenerator):
|
|||||||
return
|
return
|
||||||
|
|
||||||
"""Validate if the website image is a public file"""
|
"""Validate if the website image is a public file"""
|
||||||
auto_set_website_image = False
|
|
||||||
if not self.website_image and self.image:
|
|
||||||
auto_set_website_image = True
|
|
||||||
self.website_image = self.image
|
|
||||||
|
|
||||||
if not self.website_image:
|
if not self.website_image:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -135,18 +134,16 @@ class WebsiteItem(WebsiteGenerator):
|
|||||||
file_doc = file_doc[0]
|
file_doc = file_doc[0]
|
||||||
|
|
||||||
if not file_doc:
|
if not file_doc:
|
||||||
if not auto_set_website_image:
|
frappe.msgprint(
|
||||||
frappe.msgprint(
|
_("Website Image {0} attached to Item {1} cannot be found").format(
|
||||||
_("Website Image {0} attached to Item {1} cannot be found").format(
|
self.website_image, self.name
|
||||||
self.website_image, self.name
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
self.website_image = None
|
self.website_image = None
|
||||||
|
|
||||||
elif file_doc.is_private:
|
elif file_doc.is_private:
|
||||||
if not auto_set_website_image:
|
frappe.msgprint(_("Website Image should be a public file or website URL"))
|
||||||
frappe.msgprint(_("Website Image should be a public file or website URL"))
|
|
||||||
|
|
||||||
self.website_image = None
|
self.website_image = None
|
||||||
|
|
||||||
@@ -157,9 +154,8 @@ class WebsiteItem(WebsiteGenerator):
|
|||||||
|
|
||||||
import requests.exceptions
|
import requests.exceptions
|
||||||
|
|
||||||
if not self.is_new() and self.website_image != frappe.db.get_value(
|
db_website_image = frappe.db.get_value(self.doctype, self.name, "website_image")
|
||||||
self.doctype, self.name, "website_image"
|
if not self.is_new() and self.website_image != db_website_image:
|
||||||
):
|
|
||||||
self.thumbnail = None
|
self.thumbnail = None
|
||||||
|
|
||||||
if self.website_image and not self.thumbnail:
|
if self.website_image and not self.thumbnail:
|
||||||
@@ -431,7 +427,9 @@ def check_if_user_is_customer(user=None):
|
|||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def make_website_item(doc, save=True):
|
def make_website_item(doc: "Item", save: bool = True) -> Union["WebsiteItem", List[str]]:
|
||||||
|
"Make Website Item from Item. Used via Form UI or patch."
|
||||||
|
|
||||||
if not doc:
|
if not doc:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -451,7 +449,6 @@ def make_website_item(doc, save=True):
|
|||||||
"item_group",
|
"item_group",
|
||||||
"stock_uom",
|
"stock_uom",
|
||||||
"brand",
|
"brand",
|
||||||
"image",
|
|
||||||
"has_variants",
|
"has_variants",
|
||||||
"variant_of",
|
"variant_of",
|
||||||
"description",
|
"description",
|
||||||
@@ -459,6 +456,10 @@ def make_website_item(doc, save=True):
|
|||||||
for field in fields_to_map:
|
for field in fields_to_map:
|
||||||
website_item.update({field: doc.get(field)})
|
website_item.update({field: doc.get(field)})
|
||||||
|
|
||||||
|
# Needed for publishing/mapping via Form UI only
|
||||||
|
if not frappe.flags.in_migrate and (doc.get("image") and not website_item.website_image):
|
||||||
|
website_item.website_image = doc.get("image")
|
||||||
|
|
||||||
if not save:
|
if not save:
|
||||||
return website_item
|
return website_item
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
frappe.listview_settings['Website Item'] = {
|
frappe.listview_settings['Website Item'] = {
|
||||||
add_fields: ["item_name", "web_item_name", "published", "image", "has_variants", "variant_of"],
|
add_fields: ["item_name", "web_item_name", "published", "website_image", "has_variants", "variant_of"],
|
||||||
filters: [["published", "=", "1"]],
|
filters: [["published", "=", "1"]],
|
||||||
|
|
||||||
get_indicator: function(doc) {
|
get_indicator: function(doc) {
|
||||||
|
|||||||
@@ -20,7 +20,15 @@ def add_to_wishlist(item_code):
|
|||||||
web_item_data = frappe.db.get_value(
|
web_item_data = frappe.db.get_value(
|
||||||
"Website Item",
|
"Website Item",
|
||||||
{"item_code": item_code},
|
{"item_code": item_code},
|
||||||
["image", "website_warehouse", "name", "web_item_name", "item_name", "item_group", "route"],
|
[
|
||||||
|
"website_image",
|
||||||
|
"website_warehouse",
|
||||||
|
"name",
|
||||||
|
"web_item_name",
|
||||||
|
"item_name",
|
||||||
|
"item_group",
|
||||||
|
"route",
|
||||||
|
],
|
||||||
as_dict=1,
|
as_dict=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,7 +38,7 @@ def add_to_wishlist(item_code):
|
|||||||
"item_group": web_item_data.get("item_group"),
|
"item_group": web_item_data.get("item_group"),
|
||||||
"website_item": web_item_data.get("name"),
|
"website_item": web_item_data.get("name"),
|
||||||
"web_item_name": web_item_data.get("web_item_name"),
|
"web_item_name": web_item_data.get("web_item_name"),
|
||||||
"image": web_item_data.get("image"),
|
"image": web_item_data.get("website_image"),
|
||||||
"warehouse": web_item_data.get("website_warehouse"),
|
"warehouse": web_item_data.get("website_warehouse"),
|
||||||
"route": web_item_data.get("route"),
|
"route": web_item_data.get("route"),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ class ProductQuery:
|
|||||||
"variant_of",
|
"variant_of",
|
||||||
"has_variants",
|
"has_variants",
|
||||||
"item_group",
|
"item_group",
|
||||||
"image",
|
|
||||||
"web_long_description",
|
"web_long_description",
|
||||||
"short_description",
|
"short_description",
|
||||||
"route",
|
"route",
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ erpnext.ProductGrid = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get_image_html(item, title) {
|
get_image_html(item, title) {
|
||||||
let image = item.website_image || item.image;
|
let image = item.website_image;
|
||||||
|
|
||||||
if (image) {
|
if (image) {
|
||||||
return `
|
return `
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ erpnext.ProductList = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get_image_html(item, title, settings) {
|
get_image_html(item, title, settings) {
|
||||||
let image = item.website_image || item.image;
|
let image = item.website_image;
|
||||||
let wishlist_enabled = !item.has_variants && settings.enable_wishlist;
|
let wishlist_enabled = !item.has_variants && settings.enable_wishlist;
|
||||||
let image_html = ``;
|
let image_html = ``;
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,10 @@ from urllib.parse import urlencode
|
|||||||
import frappe
|
import frappe
|
||||||
import gocardless_pro
|
import gocardless_pro
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.integrations.utils import create_payment_gateway, create_request_log
|
from frappe.integrations.utils import create_request_log
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import call_hook_method, cint, flt, get_url
|
from frappe.utils import call_hook_method, cint, flt, get_url
|
||||||
|
from payments.utils import create_payment_gateway
|
||||||
|
|
||||||
|
|
||||||
class GoCardlessSettings(Document):
|
class GoCardlessSettings(Document):
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ from json import dumps, loads
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.integrations.utils import create_payment_gateway, create_request_log
|
from frappe.integrations.utils import create_request_log
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import call_hook_method, fmt_money, get_request_site_address
|
from frappe.utils import call_hook_method, fmt_money, get_request_site_address
|
||||||
|
from payments.utils import create_payment_gateway
|
||||||
|
|
||||||
from erpnext.erpnext_integrations.doctype.mpesa_settings.mpesa_connector import MpesaConnector
|
from erpnext.erpnext_integrations.doctype.mpesa_settings.mpesa_connector import MpesaConnector
|
||||||
from erpnext.erpnext_integrations.doctype.mpesa_settings.mpesa_custom_fields import (
|
from erpnext.erpnext_integrations.doctype.mpesa_settings.mpesa_custom_fields import (
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ app_email = "info@erpnext.com"
|
|||||||
app_license = "GNU General Public License (v3)"
|
app_license = "GNU General Public License (v3)"
|
||||||
source_link = "https://github.com/frappe/erpnext"
|
source_link = "https://github.com/frappe/erpnext"
|
||||||
app_logo_url = "/assets/erpnext/images/erpnext-logo.svg"
|
app_logo_url = "/assets/erpnext/images/erpnext-logo.svg"
|
||||||
|
required_apps = ["payments"]
|
||||||
|
|
||||||
|
|
||||||
develop_version = "14.x.x-develop"
|
develop_version = "14.x.x-develop"
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ def execute():
|
|||||||
"item_group",
|
"item_group",
|
||||||
"stock_uom",
|
"stock_uom",
|
||||||
"brand",
|
"brand",
|
||||||
"image",
|
|
||||||
"has_variants",
|
"has_variants",
|
||||||
"variant_of",
|
"variant_of",
|
||||||
"description",
|
"description",
|
||||||
@@ -30,6 +29,7 @@ def execute():
|
|||||||
"website_warehouse",
|
"website_warehouse",
|
||||||
"web_long_description",
|
"web_long_description",
|
||||||
"website_content",
|
"website_content",
|
||||||
|
"website_image",
|
||||||
"thumbnail",
|
"thumbnail",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -31,22 +31,22 @@ def execute():
|
|||||||
"Professional Tax Deductions",
|
"Professional Tax Deductions",
|
||||||
"Provident Fund Deductions",
|
"Provident Fund Deductions",
|
||||||
]:
|
]:
|
||||||
frappe.delete_doc("Report", report, ignore_missing=True)
|
frappe.delete_doc("Report", report, ignore_missing=True, force=True)
|
||||||
|
|
||||||
doctypes = frappe.get_all(
|
doctypes = frappe.get_all(
|
||||||
"DocType", {"module": ("in", ["HR", "Payroll"]), "custom": 0}, pluck="name"
|
"DocType", {"module": ("in", ["HR", "Payroll"]), "custom": 0}, pluck="name"
|
||||||
)
|
)
|
||||||
for doctype in doctypes:
|
for doctype in doctypes:
|
||||||
frappe.delete_doc("DocType", doctype, ignore_missing=True)
|
frappe.delete_doc("DocType", doctype, ignore_missing=True, force=True)
|
||||||
|
|
||||||
frappe.delete_doc("DocType", "Salary Slip Loan", ignore_missing=True)
|
frappe.delete_doc("DocType", "Salary Slip Loan", ignore_missing=True, force=True)
|
||||||
frappe.delete_doc("DocType", "Salary Component Account", ignore_missing=True)
|
frappe.delete_doc("DocType", "Salary Component Account", ignore_missing=True, force=True)
|
||||||
|
|
||||||
notifications = frappe.get_all(
|
notifications = frappe.get_all(
|
||||||
"Notification", {"module": ("in", ["HR", "Payroll"]), "is_standard": 1}, pluck="name"
|
"Notification", {"module": ("in", ["HR", "Payroll"]), "is_standard": 1}, pluck="name"
|
||||||
)
|
)
|
||||||
for notifcation in notifications:
|
for notifcation in notifications:
|
||||||
frappe.delete_doc("Notification", notifcation, ignore_missing=True)
|
frappe.delete_doc("Notification", notifcation, ignore_missing=True, force=True)
|
||||||
|
|
||||||
frappe.delete_doc("User Type", "Employee Self Service", ignore_missing=True, force=True)
|
frappe.delete_doc("User Type", "Employee Self Service", ignore_missing=True, force=True)
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class Homepage(Document):
|
|||||||
def setup_items(self):
|
def setup_items(self):
|
||||||
for d in frappe.get_all(
|
for d in frappe.get_all(
|
||||||
"Website Item",
|
"Website Item",
|
||||||
fields=["name", "item_name", "description", "image", "route"],
|
fields=["name", "item_name", "description", "website_image", "route"],
|
||||||
filters={"published": 1},
|
filters={"published": 1},
|
||||||
limit=3,
|
limit=3,
|
||||||
):
|
):
|
||||||
@@ -31,7 +31,7 @@ class Homepage(Document):
|
|||||||
item_code=d.name,
|
item_code=d.name,
|
||||||
item_name=d.item_name,
|
item_name=d.item_name,
|
||||||
description=d.description,
|
description=d.description,
|
||||||
image=d.image,
|
image=d.website_image,
|
||||||
route=d.route,
|
route=d.route,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -143,7 +143,8 @@ erpnext.utils.CRMNotes = class CRMNotes {
|
|||||||
"label": "Note",
|
"label": "Note",
|
||||||
"fieldname": "note",
|
"fieldname": "note",
|
||||||
"fieldtype": "Text Editor",
|
"fieldtype": "Text Editor",
|
||||||
"reqd": 1
|
"reqd": 1,
|
||||||
|
"enable_mentions": true,
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
primary_action: function() {
|
primary_action: function() {
|
||||||
|
|||||||
@@ -527,11 +527,14 @@ def check_credit_limit(customer, company, ignore_outstanding_sales_order=False,
|
|||||||
_("Please contact your administrator to extend the credit limits for {0}.").format(customer)
|
_("Please contact your administrator to extend the credit limits for {0}.").format(customer)
|
||||||
)
|
)
|
||||||
|
|
||||||
message = """Please contact any of the following users to extend the credit limits for {0}:
|
user_list = "<br><br><ul><li>{0}</li></ul>".format(
|
||||||
<br><br><ul><li>{1}</li></ul>""".format(
|
"<li>".join(credit_controller_users_formatted)
|
||||||
customer, "<li>".join(credit_controller_users_formatted)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
message = _(
|
||||||
|
"Please contact any of the following users to extend the credit limits for {0}: {1}"
|
||||||
|
).format(customer, user_list)
|
||||||
|
|
||||||
# if the current user does not have permissions to override credit limit,
|
# if the current user does not have permissions to override credit limit,
|
||||||
# prompt them to send out an email to the controller users
|
# prompt them to send out an email to the controller users
|
||||||
frappe.msgprint(
|
frappe.msgprint(
|
||||||
|
|||||||
@@ -1620,6 +1620,65 @@ class TestSalesOrder(FrappeTestCase):
|
|||||||
so.load_from_db()
|
so.load_from_db()
|
||||||
self.assertEqual(so.billing_status, "Fully Billed")
|
self.assertEqual(so.billing_status, "Fully Billed")
|
||||||
|
|
||||||
|
def test_so_billing_status_with_crnote_against_sales_return(self):
|
||||||
|
"""
|
||||||
|
| Step | Document creation | |
|
||||||
|
|------+--------------------------------------+-------------------------------|
|
||||||
|
| 1 | SO -> DN -> SI | SO Fully Billed and Completed |
|
||||||
|
| 2 | DN -> Sales Return(Partial) | SO 50% Delivered, 100% billed |
|
||||||
|
| 3 | Sales Return(Partial) -> Credit Note | SO 50% Delivered, 50% billed |
|
||||||
|
|
||||||
|
"""
|
||||||
|
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
||||||
|
|
||||||
|
so = make_sales_order(uom="Nos", do_not_save=1)
|
||||||
|
so.save()
|
||||||
|
so.submit()
|
||||||
|
|
||||||
|
self.assertEqual(so.billing_status, "Not Billed")
|
||||||
|
|
||||||
|
dn1 = make_delivery_note(so.name)
|
||||||
|
dn1.taxes_and_charges = ""
|
||||||
|
dn1.taxes.clear()
|
||||||
|
dn1.save().submit()
|
||||||
|
|
||||||
|
si = create_sales_invoice(qty=10, do_not_save=1)
|
||||||
|
si.items[0].sales_order = so.name
|
||||||
|
si.items[0].so_detail = so.items[0].name
|
||||||
|
si.items[0].delivery_note = dn1.name
|
||||||
|
si.items[0].dn_detail = dn1.items[0].name
|
||||||
|
si.save()
|
||||||
|
si.submit()
|
||||||
|
|
||||||
|
so.reload()
|
||||||
|
self.assertEqual(so.billing_status, "Fully Billed")
|
||||||
|
self.assertEqual(so.status, "Completed")
|
||||||
|
|
||||||
|
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
|
||||||
|
|
||||||
|
dn1.reload()
|
||||||
|
dn_ret = create_delivery_note(is_return=1, return_against=dn1.name, qty=-5, do_not_submit=True)
|
||||||
|
dn_ret.items[0].against_sales_order = so.name
|
||||||
|
dn_ret.items[0].so_detail = so.items[0].name
|
||||||
|
dn_ret.submit()
|
||||||
|
|
||||||
|
so.reload()
|
||||||
|
self.assertEqual(so.per_billed, 100)
|
||||||
|
self.assertEqual(so.per_delivered, 50)
|
||||||
|
|
||||||
|
cr_note = create_sales_invoice(is_return=1, qty=-1, do_not_submit=True)
|
||||||
|
cr_note.items[0].qty = -5
|
||||||
|
cr_note.items[0].sales_order = so.name
|
||||||
|
cr_note.items[0].so_detail = so.items[0].name
|
||||||
|
cr_note.items[0].delivery_note = dn_ret.name
|
||||||
|
cr_note.items[0].dn_detail = dn_ret.items[0].name
|
||||||
|
cr_note.update_billed_amount_in_sales_order = True
|
||||||
|
cr_note.submit()
|
||||||
|
|
||||||
|
so.reload()
|
||||||
|
self.assertEqual(so.per_billed, 50)
|
||||||
|
self.assertEqual(so.per_delivered, 50)
|
||||||
|
|
||||||
def test_so_back_updated_from_wo_via_mr(self):
|
def test_so_back_updated_from_wo_via_mr(self):
|
||||||
"SO -> MR (Manufacture) -> WO. Test if WO Qty is updated in SO."
|
"SO -> MR (Manufacture) -> WO. Test if WO Qty is updated in SO."
|
||||||
from erpnext.manufacturing.doctype.work_order.work_order import (
|
from erpnext.manufacturing.doctype.work_order.work_order import (
|
||||||
|
|||||||
@@ -497,7 +497,10 @@ erpnext.PointOfSale.Controller = class {
|
|||||||
|
|
||||||
set_pos_profile_data() {
|
set_pos_profile_data() {
|
||||||
if (this.company && !this.frm.doc.company) this.frm.doc.company = this.company;
|
if (this.company && !this.frm.doc.company) this.frm.doc.company = this.company;
|
||||||
if (this.pos_profile && !this.frm.doc.pos_profile) this.frm.doc.pos_profile = this.pos_profile;
|
if ((this.pos_profile && !this.frm.doc.pos_profile) | (this.frm.doc.is_return && this.pos_profile != this.frm.doc.pos_profile)) {
|
||||||
|
this.frm.doc.pos_profile = this.pos_profile;
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.frm.doc.company) return;
|
if (!this.frm.doc.company) return;
|
||||||
|
|
||||||
return this.frm.trigger("set_pos_data");
|
return this.frm.trigger("set_pos_data");
|
||||||
|
|||||||
@@ -30,18 +30,20 @@ class GlobalDefaults(Document):
|
|||||||
frappe.db.set_default(key, self.get(keydict[key], ""))
|
frappe.db.set_default(key, self.get(keydict[key], ""))
|
||||||
|
|
||||||
# update year start date and year end date from fiscal_year
|
# update year start date and year end date from fiscal_year
|
||||||
year_start_end_date = frappe.db.sql(
|
if self.current_fiscal_year:
|
||||||
"""select year_start_date, year_end_date
|
if fiscal_year := frappe.get_all(
|
||||||
from `tabFiscal Year` where name=%s""",
|
"Fiscal Year",
|
||||||
self.current_fiscal_year,
|
filters={"name": self.current_fiscal_year},
|
||||||
)
|
fields=["year_start_date", "year_end_date"],
|
||||||
if year_start_end_date:
|
limit=1,
|
||||||
ysd = year_start_end_date[0][0] or ""
|
order_by=None,
|
||||||
yed = year_start_end_date[0][1] or ""
|
):
|
||||||
|
ysd = fiscal_year[0].year_start_date or ""
|
||||||
|
yed = fiscal_year[0].year_end_date or ""
|
||||||
|
|
||||||
if ysd and yed:
|
if ysd and yed:
|
||||||
frappe.db.set_default("year_start_date", ysd.strftime("%Y-%m-%d"))
|
frappe.db.set_default("year_start_date", ysd.strftime("%Y-%m-%d"))
|
||||||
frappe.db.set_default("year_end_date", yed.strftime("%Y-%m-%d"))
|
frappe.db.set_default("year_end_date", yed.strftime("%Y-%m-%d"))
|
||||||
|
|
||||||
# enable default currency
|
# enable default currency
|
||||||
if self.default_currency:
|
if self.default_currency:
|
||||||
@@ -50,7 +52,6 @@ class GlobalDefaults(Document):
|
|||||||
self.toggle_rounded_total()
|
self.toggle_rounded_total()
|
||||||
self.toggle_in_words()
|
self.toggle_in_words()
|
||||||
|
|
||||||
# clear cache
|
|
||||||
frappe.clear_cache()
|
frappe.clear_cache()
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ import frappe
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils.dashboard import cache_source
|
from frappe.utils.dashboard import cache_source
|
||||||
|
|
||||||
from erpnext.stock.utils import get_stock_value_from_bin
|
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
@cache_source
|
@cache_source
|
||||||
@@ -30,26 +28,24 @@ def get(
|
|||||||
warehouse_filters.append(["company", "=", filters.get("company")])
|
warehouse_filters.append(["company", "=", filters.get("company")])
|
||||||
|
|
||||||
warehouses = frappe.get_list(
|
warehouses = frappe.get_list(
|
||||||
"Warehouse", fields=["name"], filters=warehouse_filters, order_by="name"
|
"Warehouse", pluck="name", filters=warehouse_filters, order_by="name"
|
||||||
)
|
)
|
||||||
|
|
||||||
for wh in warehouses:
|
warehouses = frappe.get_list(
|
||||||
balance = get_stock_value_from_bin(warehouse=wh.name)
|
"Bin",
|
||||||
wh["balance"] = balance[0][0]
|
fields=["warehouse", "sum(stock_value) stock_value"],
|
||||||
|
filters={"warehouse": ["IN", warehouses], "stock_value": [">", 0]},
|
||||||
warehouses = [x for x in warehouses if not (x.get("balance") == None)]
|
group_by="warehouse",
|
||||||
|
order_by="stock_value DESC",
|
||||||
|
limit_page_length=10,
|
||||||
|
)
|
||||||
|
|
||||||
if not warehouses:
|
if not warehouses:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
sorted_warehouse_map = sorted(warehouses, key=lambda i: i["balance"], reverse=True)
|
for warehouse in warehouses:
|
||||||
|
labels.append(_(warehouse.get("warehouse")))
|
||||||
if len(sorted_warehouse_map) > 10:
|
datapoints.append(warehouse.get("stock_value"))
|
||||||
sorted_warehouse_map = sorted_warehouse_map[:10]
|
|
||||||
|
|
||||||
for warehouse in sorted_warehouse_map:
|
|
||||||
labels.append(_(warehouse.get("name")))
|
|
||||||
datapoints.append(warehouse.get("balance"))
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"labels": labels,
|
"labels": labels,
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ def format_report_data(filters: Filters, item_details: Dict, to_date: str) -> Li
|
|||||||
precision = cint(frappe.db.get_single_value("System Settings", "float_precision", cache=True))
|
precision = cint(frappe.db.get_single_value("System Settings", "float_precision", cache=True))
|
||||||
|
|
||||||
for item, item_dict in item_details.items():
|
for item, item_dict in item_details.items():
|
||||||
|
if not flt(item_dict.get("total_qty"), precision):
|
||||||
|
continue
|
||||||
|
|
||||||
earliest_age, latest_age = 0, 0
|
earliest_age, latest_age = 0, 0
|
||||||
details = item_dict["details"]
|
details = item_dict["details"]
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ product_image(doc.website_image or doc.image, alt=doc.website_image_alt or doc.item_name) }}
|
{{ product_image(doc.website_image, alt=doc.website_image_alt or doc.item_name) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<!-- Simple image preview -->
|
<!-- Simple image preview -->
|
||||||
|
|||||||
@@ -74,7 +74,7 @@
|
|||||||
{%- set col_size = 3 if is_full_width else 4 -%}
|
{%- set col_size = 3 if is_full_width else 4 -%}
|
||||||
{%- set title = item.web_item_name or item.item_name or item.item_code -%}
|
{%- set title = item.web_item_name or item.item_name or item.item_code -%}
|
||||||
{%- set title = title[:50] + "..." if title|len > 50 else title -%}
|
{%- set title = title[:50] + "..." if title|len > 50 else title -%}
|
||||||
{%- set image = item.website_image or item.image -%}
|
{%- set image = item.website_image -%}
|
||||||
{%- set description = item.website_description or item.description-%}
|
{%- set description = item.website_description or item.description-%}
|
||||||
|
|
||||||
{% if is_featured %}
|
{% if is_featured %}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
/* csslint ignore:start */
|
/* csslint ignore:start */
|
||||||
{% if homepage.hero_image %}
|
{% if homepage.hero_image %}
|
||||||
.hero-image {
|
.hero-image {
|
||||||
background-image: url("{{ homepage.hero_image }}");
|
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
padding: 10rem 0;
|
padding: 10rem 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,11 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<main>
|
<main>
|
||||||
{% if homepage.hero_section_based_on == 'Default' %}
|
{% if homepage.hero_section_based_on == 'Default' %}
|
||||||
<section class="hero-section border-bottom {%if homepage.hero_image%}hero-image{%endif%}">
|
<section class="hero-section border-bottom {%if homepage.hero_image%}hero-image{%endif%}"
|
||||||
|
{% if homepage.hero_image %}
|
||||||
|
style="background-image: url('{{ homepage.hero_image }}');"
|
||||||
|
{%- endif %}
|
||||||
|
>
|
||||||
<div class="container py-5">
|
<div class="container py-5">
|
||||||
<h1 class="d-none d-sm-block display-4">{{ homepage.tag_line }}</h1>
|
<h1 class="d-none d-sm-block display-4">{{ homepage.tag_line }}</h1>
|
||||||
<h1 class="d-block d-sm-none">{{ homepage.tag_line }}</h1>
|
<h1 class="d-block d-sm-none">{{ homepage.tag_line }}</h1>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user