mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-27 21:08:33 +00:00
Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
550daf2108 | ||
|
|
959eae1b5c | ||
|
|
f2d83b1b21 | ||
|
|
f1670e922f | ||
|
|
ec780ac263 | ||
|
|
847171bd14 | ||
|
|
97488aee88 | ||
|
|
2b3a0ba9c4 | ||
|
|
5f7dc8a5b9 | ||
|
|
edc20ae8b8 | ||
|
|
6ebc9c5c82 | ||
|
|
5a4d92b1bc | ||
|
|
ff48c44496 | ||
|
|
2f81f15f02 | ||
|
|
f1bb8933c1 | ||
|
|
0f0a2b100c | ||
|
|
eef0f453d2 | ||
|
|
e4af69bc93 | ||
|
|
42fe63da2c | ||
|
|
e23d7aa968 | ||
|
|
a46aa808be | ||
|
|
f3b6b4609e | ||
|
|
7dcf0f0866 | ||
|
|
29dcce53db | ||
|
|
a450c8dce9 | ||
|
|
287411667a | ||
|
|
ab30e2a9c7 | ||
|
|
65dd72a0b0 | ||
|
|
66bf1071bb | ||
|
|
410e617834 | ||
|
|
0b952e8bba | ||
|
|
e9d85a3ee4 | ||
|
|
c20d469f31 | ||
|
|
7d0a118eab | ||
|
|
2394f64872 | ||
|
|
a50ad1d292 |
3
.github/helper/.flake8_strict
vendored
3
.github/helper/.flake8_strict
vendored
@@ -66,7 +66,8 @@ ignore =
|
||||
F841,
|
||||
E713,
|
||||
E712,
|
||||
B023
|
||||
B023,
|
||||
B028
|
||||
|
||||
|
||||
max-line-length = 200
|
||||
|
||||
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
@@ -13,10 +13,10 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
- name: Setup Node.js v14
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 14
|
||||
node-version: 18
|
||||
- name: Setup dependencies
|
||||
run: |
|
||||
npm install @semantic-release/git @semantic-release/exec --no-save
|
||||
@@ -28,4 +28,4 @@ jobs:
|
||||
GIT_AUTHOR_EMAIL: "developers@frappe.io"
|
||||
GIT_COMMITTER_NAME: "Frappe PR Bot"
|
||||
GIT_COMMITTER_EMAIL: "developers@frappe.io"
|
||||
run: npx semantic-release
|
||||
run: npx semantic-release
|
||||
|
||||
@@ -4,7 +4,7 @@ import frappe
|
||||
|
||||
from erpnext.hooks import regional_overrides
|
||||
|
||||
__version__ = "13.43.0"
|
||||
__version__ = "13.43.2"
|
||||
|
||||
|
||||
def get_default_company(user=None):
|
||||
|
||||
@@ -132,6 +132,10 @@ frappe.ui.form.on('Asset', {
|
||||
}, __("Manage"));
|
||||
}
|
||||
|
||||
if (frm.doc.depr_entry_posting_status === "Failed") {
|
||||
frm.trigger("set_depr_posting_failure_alert");
|
||||
}
|
||||
|
||||
frm.trigger("setup_chart");
|
||||
}
|
||||
|
||||
@@ -142,6 +146,19 @@ frappe.ui.form.on('Asset', {
|
||||
}
|
||||
},
|
||||
|
||||
set_depr_posting_failure_alert: function (frm) {
|
||||
const alert = `
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-sm-6">
|
||||
<span class="indicator whitespace-nowrap red">
|
||||
<span>Failed to post depreciation entries</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
frm.dashboard.set_headline_alert(alert);
|
||||
},
|
||||
|
||||
toggle_reference_doc: function(frm) {
|
||||
if (frm.doc.purchase_receipt && frm.doc.purchase_invoice && frm.doc.docstatus === 1) {
|
||||
frm.set_df_property('purchase_invoice', 'read_only', 1);
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
"column_break_51",
|
||||
"purchase_receipt_amount",
|
||||
"default_finance_book",
|
||||
"depr_entry_posting_status",
|
||||
"amended_from"
|
||||
],
|
||||
"fields": [
|
||||
@@ -473,6 +474,16 @@
|
||||
"fieldname": "section_break_36",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Finance Books"
|
||||
},
|
||||
{
|
||||
"fieldname": "depr_entry_posting_status",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 1,
|
||||
"label": "Depreciation Entry Posting Status",
|
||||
"no_copy": 1,
|
||||
"options": "\nSuccessful\nFailed",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"idx": 72,
|
||||
@@ -487,7 +498,7 @@
|
||||
{
|
||||
"group": "Repair",
|
||||
"link_doctype": "Asset Repair",
|
||||
"link_fieldname": "asset_name"
|
||||
"link_fieldname": "asset"
|
||||
},
|
||||
{
|
||||
"group": "Value",
|
||||
@@ -495,7 +506,7 @@
|
||||
"link_fieldname": "asset"
|
||||
}
|
||||
],
|
||||
"modified": "2022-07-20 16:22:44.437579",
|
||||
"modified": "2023-01-17 00:28:37.789345",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Assets",
|
||||
"name": "Asset",
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import cint, flt, getdate, today
|
||||
from frappe.utils import cint, flt, get_link_to_form, getdate, today
|
||||
from frappe.utils.user import get_users_with_role
|
||||
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
|
||||
get_checks_for_pl_and_bs_accounts,
|
||||
@@ -20,9 +21,22 @@ def post_depreciation_entries(date=None):
|
||||
|
||||
if not date:
|
||||
date = today()
|
||||
for asset in get_depreciable_assets(date):
|
||||
make_depreciation_entry(asset, date)
|
||||
frappe.db.commit()
|
||||
|
||||
failed_asset_names = []
|
||||
|
||||
for asset_name in get_depreciable_assets(date):
|
||||
try:
|
||||
make_depreciation_entry(asset_name, date)
|
||||
frappe.db.commit()
|
||||
except Exception as e:
|
||||
frappe.db.rollback()
|
||||
failed_asset_names.append(asset_name)
|
||||
|
||||
if failed_asset_names:
|
||||
set_depr_entry_posting_status_for_failed_assets(failed_asset_names)
|
||||
notify_depr_entry_posting_error(failed_asset_names)
|
||||
|
||||
frappe.db.commit()
|
||||
|
||||
|
||||
def get_depreciable_assets(date):
|
||||
@@ -121,6 +135,8 @@ def make_depreciation_entry(asset_name, date=None):
|
||||
finance_books.value_after_depreciation -= d.depreciation_amount
|
||||
finance_books.db_update()
|
||||
|
||||
frappe.db.set_value("Asset", asset_name, "depr_entry_posting_status", "Successful")
|
||||
|
||||
asset.set_status()
|
||||
|
||||
return asset
|
||||
@@ -184,6 +200,42 @@ def get_credit_and_debit_accounts(accumulated_depreciation_account, depreciation
|
||||
return credit_account, debit_account
|
||||
|
||||
|
||||
def set_depr_entry_posting_status_for_failed_assets(failed_asset_names):
|
||||
for asset_name in failed_asset_names:
|
||||
frappe.db.set_value("Asset", asset_name, "depr_entry_posting_status", "Failed")
|
||||
|
||||
|
||||
def notify_depr_entry_posting_error(failed_asset_names):
|
||||
recipients = get_users_with_role("Accounts Manager")
|
||||
|
||||
if not recipients:
|
||||
recipients = get_users_with_role("System Manager")
|
||||
|
||||
subject = _("Error while posting depreciation entries")
|
||||
|
||||
asset_links = get_comma_separated_asset_links(failed_asset_names)
|
||||
|
||||
message = (
|
||||
_("Hi,")
|
||||
+ "<br>"
|
||||
+ _("The following assets have failed to post depreciation entries: {0}").format(asset_links)
|
||||
+ "."
|
||||
)
|
||||
|
||||
frappe.sendmail(recipients=recipients, subject=subject, message=message)
|
||||
|
||||
|
||||
def get_comma_separated_asset_links(asset_names):
|
||||
asset_links = []
|
||||
|
||||
for asset_name in asset_names:
|
||||
asset_links.append(get_link_to_form("Asset", asset_name))
|
||||
|
||||
asset_links = ", ".join(asset_links)
|
||||
|
||||
return asset_links
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def scrap_asset(asset_name):
|
||||
asset = frappe.get_doc("Asset", asset_name)
|
||||
|
||||
@@ -1387,6 +1387,7 @@ def create_asset(**args):
|
||||
"location": args.location or "Test Location",
|
||||
"asset_owner": args.asset_owner or "Company",
|
||||
"is_existing_asset": args.is_existing_asset or 1,
|
||||
"depr_entry_posting_status": args.depr_entry_posting_status or "",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -86,6 +86,7 @@ def get_data(filters):
|
||||
"status",
|
||||
"department",
|
||||
"cost_center",
|
||||
"calculate_depreciation",
|
||||
"purchase_receipt",
|
||||
"asset_category",
|
||||
"purchase_date",
|
||||
@@ -98,11 +99,7 @@ def get_data(filters):
|
||||
assets_record = frappe.db.get_all("Asset", filters=conditions, fields=fields)
|
||||
|
||||
for asset in assets_record:
|
||||
asset_value = (
|
||||
asset.gross_purchase_amount
|
||||
- flt(asset.opening_accumulated_depreciation)
|
||||
- flt(depreciation_amount_map.get(asset.name))
|
||||
)
|
||||
asset_value = get_asset_value(asset, filters.finance_book)
|
||||
row = {
|
||||
"asset_id": asset.asset_id,
|
||||
"asset_name": asset.asset_name,
|
||||
@@ -125,6 +122,21 @@ def get_data(filters):
|
||||
return data
|
||||
|
||||
|
||||
def get_asset_value(asset, finance_book=None):
|
||||
if not asset.calculate_depreciation:
|
||||
return flt(asset.gross_purchase_amount) - flt(asset.opening_accumulated_depreciation)
|
||||
|
||||
finance_book_filter = ["finance_book", "is", "not set"]
|
||||
if finance_book:
|
||||
finance_book_filter = ["finance_book", "=", finance_book]
|
||||
|
||||
return frappe.db.get_value(
|
||||
doctype="Asset Finance Book",
|
||||
filters=[["parent", "=", asset.asset_id], finance_book_filter],
|
||||
fieldname="value_after_depreciation",
|
||||
)
|
||||
|
||||
|
||||
def prepare_chart_data(data, filters):
|
||||
labels_values_map = {}
|
||||
date_field = frappe.scrub(filters.date_based_on)
|
||||
|
||||
@@ -383,7 +383,7 @@ class AccountsController(TransactionBase):
|
||||
self.get("inter_company_reference")
|
||||
or self.get("inter_company_invoice_reference")
|
||||
or self.get("inter_company_order_reference")
|
||||
):
|
||||
) and not self.get("is_return"):
|
||||
msg = _("Internal Sale or Delivery Reference missing.")
|
||||
msg += _("Please create purchase from internal sale or delivery document itself")
|
||||
frappe.throw(msg, title=_("Internal Sales Reference Missing"))
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2021-06-29 18:27:02.832979",
|
||||
"modified": "2022-12-28 16:35:34.377575",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "Appointment",
|
||||
@@ -121,16 +121,6 @@
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Guest",
|
||||
"share": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
from collections import Counter
|
||||
|
||||
import frappe
|
||||
import frappe.share
|
||||
from frappe import _
|
||||
from frappe.desk.form.assign_to import add as add_assignment
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import get_url, getdate
|
||||
from frappe.utils.verified_command import get_signed_params
|
||||
@@ -118,21 +120,18 @@ class Appointment(Document):
|
||||
self.party = lead.name
|
||||
|
||||
def auto_assign(self):
|
||||
from frappe.desk.form.assign_to import add as add_assignemnt
|
||||
|
||||
existing_assignee = self.get_assignee_from_latest_opportunity()
|
||||
if existing_assignee:
|
||||
# If the latest opportunity is assigned to someone
|
||||
# Assign the appointment to the same
|
||||
add_assignemnt({"doctype": self.doctype, "name": self.name, "assign_to": [existing_assignee]})
|
||||
self.assign_agent(existing_assignee)
|
||||
return
|
||||
if self._assign:
|
||||
return
|
||||
available_agents = _get_agents_sorted_by_asc_workload(getdate(self.scheduled_time))
|
||||
for agent in available_agents:
|
||||
if _check_agent_availability(agent, self.scheduled_time):
|
||||
agent = agent[0]
|
||||
add_assignemnt({"doctype": self.doctype, "name": self.name, "assign_to": [agent]})
|
||||
self.assign_agent(agent[0])
|
||||
break
|
||||
|
||||
def get_assignee_from_latest_opportunity(self):
|
||||
@@ -187,9 +186,15 @@ class Appointment(Document):
|
||||
params = {"email": self.customer_email, "appointment": self.name}
|
||||
return get_url(verify_route + "?" + get_signed_params(params))
|
||||
|
||||
def assign_agent(self, agent):
|
||||
if not frappe.has_permission(doc=self, user=agent):
|
||||
frappe.share.add(self.doctype, self.name, agent, flags={"ignore_share_permission": True})
|
||||
|
||||
add_assignment({"doctype": self.doctype, "name": self.name, "assign_to": [agent]})
|
||||
|
||||
|
||||
def _get_agents_sorted_by_asc_workload(date):
|
||||
appointments = frappe.db.get_list("Appointment", fields="*")
|
||||
appointments = frappe.get_all("Appointment", fields="*")
|
||||
agent_list = _get_agent_list_as_strings()
|
||||
if not appointments:
|
||||
return agent_list
|
||||
@@ -214,7 +219,7 @@ def _get_agent_list_as_strings():
|
||||
|
||||
|
||||
def _check_agent_availability(agent_email, scheduled_time):
|
||||
appointemnts_at_scheduled_time = frappe.get_list(
|
||||
appointemnts_at_scheduled_time = frappe.get_all(
|
||||
"Appointment", filters={"scheduled_time": scheduled_time}
|
||||
)
|
||||
for appointment in appointemnts_at_scheduled_time:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2019-08-27 10:56:48.309824",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
@@ -101,7 +102,8 @@
|
||||
}
|
||||
],
|
||||
"issingle": 1,
|
||||
"modified": "2019-11-26 12:14:17.669366",
|
||||
"links": [],
|
||||
"modified": "2022-12-28 16:41:28.773090",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "Appointment Booking Settings",
|
||||
@@ -117,13 +119,6 @@
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"email": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"role": "Guest",
|
||||
"share": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"email": 1,
|
||||
|
||||
@@ -111,34 +111,30 @@ def get_data(filters: Filters) -> List:
|
||||
employee.leave_approver
|
||||
)
|
||||
|
||||
if (
|
||||
(leave_approvers and len(leave_approvers) and user in leave_approvers)
|
||||
or (user in ["Administrator", employee.user_id])
|
||||
or ("HR Manager" in frappe.get_roles(user))
|
||||
):
|
||||
if len(active_employees) > 1:
|
||||
row = frappe._dict()
|
||||
row.employee = employee.name
|
||||
row.employee_name = employee.employee_name
|
||||
if len(active_employees) > 1:
|
||||
row = frappe._dict()
|
||||
|
||||
leaves_taken = (
|
||||
get_leaves_for_period(employee.name, leave_type, filters.from_date, filters.to_date) * -1
|
||||
)
|
||||
row.employee = employee.name
|
||||
row.employee_name = employee.employee_name
|
||||
|
||||
new_allocation, expired_leaves, carry_forwarded_leaves = get_allocated_and_expired_leaves(
|
||||
filters.from_date, filters.to_date, employee.name, leave_type
|
||||
)
|
||||
opening = get_opening_balance(employee.name, leave_type, filters, carry_forwarded_leaves)
|
||||
leaves_taken = (
|
||||
get_leaves_for_period(employee.name, leave_type, filters.from_date, filters.to_date) * -1
|
||||
)
|
||||
|
||||
row.leaves_allocated = new_allocation
|
||||
row.leaves_expired = expired_leaves
|
||||
row.opening_balance = opening
|
||||
row.leaves_taken = leaves_taken
|
||||
new_allocation, expired_leaves, carry_forwarded_leaves = get_allocated_and_expired_leaves(
|
||||
filters.from_date, filters.to_date, employee.name, leave_type
|
||||
)
|
||||
opening = get_opening_balance(employee.name, leave_type, filters, carry_forwarded_leaves)
|
||||
|
||||
# not be shown on the basis of days left it create in user mind for carry_forward leave
|
||||
row.closing_balance = new_allocation + opening - (row.leaves_expired + leaves_taken)
|
||||
row.indent = 1
|
||||
data.append(row)
|
||||
row.leaves_allocated = new_allocation
|
||||
row.leaves_expired = expired_leaves
|
||||
row.opening_balance = opening
|
||||
row.leaves_taken = leaves_taken
|
||||
|
||||
# not be shown on the basis of days left it create in user mind for carry_forward leave
|
||||
row.closing_balance = new_allocation + opening - (row.leaves_expired + leaves_taken)
|
||||
row.indent = 1
|
||||
data.append(row)
|
||||
|
||||
return data
|
||||
|
||||
|
||||
@@ -65,21 +65,16 @@ def get_data(filters, leave_types):
|
||||
if employee.leave_approver:
|
||||
leave_approvers.append(employee.leave_approver)
|
||||
|
||||
if (
|
||||
(len(leave_approvers) and user in leave_approvers)
|
||||
or (user in ["Administrator", employee.user_id])
|
||||
or ("HR Manager" in frappe.get_roles(user))
|
||||
):
|
||||
row = [employee.name, employee.employee_name, employee.department]
|
||||
available_leave = get_leave_details(employee.name, filters.date)
|
||||
for leave_type in leave_types:
|
||||
remaining = 0
|
||||
if leave_type in available_leave["leave_allocation"]:
|
||||
# opening balance
|
||||
remaining = available_leave["leave_allocation"][leave_type]["remaining_leaves"]
|
||||
row = [employee.name, employee.employee_name, employee.department]
|
||||
available_leave = get_leave_details(employee.name, filters.date)
|
||||
for leave_type in leave_types:
|
||||
remaining = 0
|
||||
if leave_type in available_leave["leave_allocation"]:
|
||||
# opening balance
|
||||
remaining = available_leave["leave_allocation"][leave_type]["remaining_leaves"]
|
||||
|
||||
row += [remaining]
|
||||
row += [remaining]
|
||||
|
||||
data.append(row)
|
||||
data.append(row)
|
||||
|
||||
return data
|
||||
|
||||
@@ -191,14 +191,7 @@ def get_list_context(context=None):
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_sales_order(source_name, target_doc=None):
|
||||
quotation = frappe.db.get_value(
|
||||
"Quotation", source_name, ["transaction_date", "valid_till"], as_dict=1
|
||||
)
|
||||
if quotation.valid_till and (
|
||||
quotation.valid_till < quotation.transaction_date or quotation.valid_till < getdate(nowdate())
|
||||
):
|
||||
frappe.throw(_("Validity period of this quotation has ended."))
|
||||
def make_sales_order(source_name: str, target_doc=None):
|
||||
return _make_sales_order(source_name, target_doc)
|
||||
|
||||
|
||||
|
||||
@@ -118,17 +118,20 @@ class TestQuotation(FrappeTestCase):
|
||||
sales_order.payment_schedule[1].due_date, getdate(add_days(quotation.transaction_date, 30))
|
||||
)
|
||||
|
||||
def test_valid_till(self):
|
||||
from erpnext.selling.doctype.quotation.quotation import make_sales_order
|
||||
|
||||
def test_valid_till_before_transaction_date(self):
|
||||
quotation = frappe.copy_doc(test_records[0])
|
||||
quotation.valid_till = add_days(quotation.transaction_date, -1)
|
||||
self.assertRaises(frappe.ValidationError, quotation.validate)
|
||||
|
||||
def test_so_from_expired_quotation(self):
|
||||
from erpnext.selling.doctype.quotation.quotation import make_sales_order
|
||||
|
||||
quotation = frappe.copy_doc(test_records[0])
|
||||
quotation.valid_till = add_days(nowdate(), -1)
|
||||
quotation.insert()
|
||||
quotation.submit()
|
||||
self.assertRaises(frappe.ValidationError, make_sales_order, quotation.name)
|
||||
|
||||
make_sales_order(quotation.name)
|
||||
|
||||
def test_shopping_cart_without_website_item(self):
|
||||
if frappe.db.exists("Website Item", {"item_code": "_Test Item Home Desktop 100"}):
|
||||
|
||||
@@ -14,7 +14,6 @@ def get_data():
|
||||
},
|
||||
"internal_links": {
|
||||
"Quotation": ["items", "prevdoc_docname"],
|
||||
"Material Request": ["items", "material_request"],
|
||||
},
|
||||
"transactions": [
|
||||
{
|
||||
|
||||
@@ -809,7 +809,7 @@
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2022-04-27 03:15:34.366563",
|
||||
"modified": "2022-12-25 02:51:10.247569",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Sales Order Item",
|
||||
@@ -820,4 +820,4 @@
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"track_changes": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,6 +123,7 @@
|
||||
"fieldname": "route",
|
||||
"fieldtype": "Data",
|
||||
"label": "Route",
|
||||
"no_copy": 1,
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
@@ -232,11 +233,10 @@
|
||||
"is_tree": 1,
|
||||
"links": [],
|
||||
"max_attachments": 3,
|
||||
"modified": "2022-03-09 12:27:11.055782",
|
||||
"modified": "2023-01-05 12:21:30.458628",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Item Group",
|
||||
"name_case": "Title Case",
|
||||
"naming_rule": "By fieldname",
|
||||
"nsm_parent_field": "parent_item_group",
|
||||
"owner": "Administrator",
|
||||
|
||||
@@ -104,7 +104,6 @@ class TestItem(FrappeTestCase):
|
||||
"conversion_factor": 1.0,
|
||||
"reserved_qty": 1,
|
||||
"actual_qty": 5,
|
||||
"ordered_qty": 10,
|
||||
"projected_qty": 14,
|
||||
}
|
||||
|
||||
|
||||
@@ -83,8 +83,8 @@ def reset_packing_list(doc):
|
||||
# 1. items were deleted
|
||||
# 2. if bundle item replaced by another item (same no. of items but different items)
|
||||
# we maintain list to track recurring item rows as well
|
||||
items_before_save = [item.item_code for item in doc_before_save.get("items")]
|
||||
items_after_save = [item.item_code for item in doc.get("items")]
|
||||
items_before_save = [(item.name, item.item_code) for item in doc_before_save.get("items")]
|
||||
items_after_save = [(item.name, item.item_code) for item in doc.get("items")]
|
||||
reset_table = items_before_save != items_after_save
|
||||
else:
|
||||
# reset: if via Update Items OR
|
||||
|
||||
@@ -198,7 +198,8 @@ class PickList(Document):
|
||||
frappe.throw(_("Qty of Finished Goods Item should be greater than 0."))
|
||||
|
||||
def before_print(self, settings=None):
|
||||
self.group_similar_items()
|
||||
if self.group_same_items:
|
||||
self.group_similar_items()
|
||||
|
||||
def group_similar_items(self):
|
||||
group_item_qty = defaultdict(float)
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
def get_data():
|
||||
return {
|
||||
"fieldname": "pick_list",
|
||||
"internal_links": {
|
||||
"Sales Order": ["locations", "sales_order"],
|
||||
},
|
||||
"transactions": [
|
||||
{"items": ["Stock Entry", "Delivery Note"]},
|
||||
{"items": ["Stock Entry", "Sales Order", "Delivery Note"]},
|
||||
],
|
||||
}
|
||||
|
||||
@@ -432,10 +432,10 @@ class TestPickList(FrappeTestCase):
|
||||
pl.before_print()
|
||||
self.assertEqual(len(pl.locations), 4)
|
||||
|
||||
# grouping should halve the number of items
|
||||
# grouping should not happen if group_same_items is False
|
||||
pl = frappe.get_doc(
|
||||
doctype="Pick List",
|
||||
group_same_items=True,
|
||||
group_same_items=False,
|
||||
locations=[
|
||||
_dict(item_code="A", warehouse="X", qty=5, picked_qty=1),
|
||||
_dict(item_code="B", warehouse="Y", qty=4, picked_qty=2),
|
||||
@@ -444,6 +444,11 @@ class TestPickList(FrappeTestCase):
|
||||
],
|
||||
)
|
||||
pl.before_print()
|
||||
self.assertEqual(len(pl.locations), 4)
|
||||
|
||||
# grouping should halve the number of items
|
||||
pl.group_same_items = True
|
||||
pl.before_print()
|
||||
self.assertEqual(len(pl.locations), 2)
|
||||
|
||||
expected_items = [
|
||||
|
||||
@@ -1161,7 +1161,7 @@ def get_projected_qty(item_code, warehouse):
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_bin_details(item_code, warehouse, company=None, include_child_warehouses=False):
|
||||
bin_details = {"projected_qty": 0, "actual_qty": 0, "reserved_qty": 0, "ordered_qty": 0}
|
||||
bin_details = {"projected_qty": 0, "actual_qty": 0, "reserved_qty": 0}
|
||||
|
||||
if warehouse:
|
||||
from frappe.query_builder.functions import Coalesce, Sum
|
||||
@@ -1177,7 +1177,6 @@ def get_bin_details(item_code, warehouse, company=None, include_child_warehouses
|
||||
Coalesce(Sum(bin.projected_qty), 0).as_("projected_qty"),
|
||||
Coalesce(Sum(bin.actual_qty), 0).as_("actual_qty"),
|
||||
Coalesce(Sum(bin.reserved_qty), 0).as_("reserved_qty"),
|
||||
Coalesce(Sum(bin.ordered_qty), 0).as_("ordered_qty"),
|
||||
)
|
||||
.where((bin.item_code == item_code) & (bin.warehouse.isin(warehouses)))
|
||||
).run(as_dict=True)[0]
|
||||
|
||||
@@ -41,7 +41,7 @@ def get_data(report_filters):
|
||||
key = (d.voucher_type, d.voucher_no)
|
||||
gl_data = voucher_wise_gl_data.get(key) or {}
|
||||
d.account_value = gl_data.get("account_value", 0)
|
||||
d.difference_value = abs(d.stock_value - d.account_value)
|
||||
d.difference_value = d.stock_value - d.account_value
|
||||
if abs(d.difference_value) > 0.1:
|
||||
data.append(d)
|
||||
|
||||
|
||||
@@ -1184,20 +1184,6 @@ def get_valuation_rate(
|
||||
(item_code, warehouse, voucher_no, voucher_type),
|
||||
)
|
||||
|
||||
if not last_valuation_rate:
|
||||
# Get valuation rate from last sle for the item against any warehouse
|
||||
last_valuation_rate = frappe.db.sql(
|
||||
"""select valuation_rate
|
||||
from `tabStock Ledger Entry` force index (item_code)
|
||||
where
|
||||
item_code = %s
|
||||
AND valuation_rate > 0
|
||||
AND is_cancelled = 0
|
||||
AND NOT(voucher_no = %s AND voucher_type = %s)
|
||||
order by posting_date desc, posting_time desc, name desc limit 1""",
|
||||
(item_code, voucher_no, voucher_type),
|
||||
)
|
||||
|
||||
if last_valuation_rate:
|
||||
return flt(last_valuation_rate[0][0])
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ frappe.ready(async () => {
|
||||
initialise_select_date();
|
||||
})
|
||||
|
||||
window.holiday_list = [];
|
||||
|
||||
async function initialise_select_date() {
|
||||
navigate_to_page(1);
|
||||
@@ -20,7 +19,6 @@ async function get_global_variables() {
|
||||
window.timezones = (await frappe.call({
|
||||
method:'erpnext.www.book_appointment.index.get_timezones'
|
||||
})).message;
|
||||
window.holiday_list = window.appointment_settings.holiday_list;
|
||||
}
|
||||
|
||||
function setup_timezone_selector() {
|
||||
|
||||
@@ -26,8 +26,12 @@ def get_context(context):
|
||||
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def get_appointment_settings():
|
||||
settings = frappe.get_doc("Appointment Booking Settings")
|
||||
settings.holiday_list = frappe.get_doc("Holiday List", settings.holiday_list)
|
||||
settings = frappe.get_cached_value(
|
||||
"Appointment Booking Settings",
|
||||
None,
|
||||
["advance_booking_days", "appointment_duration", "success_redirect_url"],
|
||||
as_dict=True,
|
||||
)
|
||||
return settings
|
||||
|
||||
|
||||
@@ -106,7 +110,7 @@ def create_appointment(date, time, tz, contact):
|
||||
appointment.customer_details = contact.get("notes", None)
|
||||
appointment.customer_email = contact.get("email", None)
|
||||
appointment.status = "Open"
|
||||
appointment.insert()
|
||||
appointment.insert(ignore_permissions=True)
|
||||
return appointment
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ import frappe
|
||||
from frappe.utils.verified_command import verify_request
|
||||
|
||||
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def get_context(context):
|
||||
if not verify_request():
|
||||
context.success = False
|
||||
|
||||
Reference in New Issue
Block a user