Merge branch 'develop' into patch-8

This commit is contained in:
Marica 2021-04-14 18:56:15 +05:30 committed by GitHub
commit f045fde9f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
79 changed files with 996 additions and 213 deletions

View File

@ -280,7 +280,7 @@
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2020-06-24 14:06:54.833738", "modified": "2020-06-26 14:06:54.833738",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Journal Entry Account", "name": "Journal Entry Account",

View File

@ -108,7 +108,6 @@ class POSInvoice(SalesInvoice):
filters = { "item_code": d.item_code, "warehouse": d.warehouse } filters = { "item_code": d.item_code, "warehouse": d.warehouse }
if d.batch_no: if d.batch_no:
filters["batch_no"] = d.batch_no filters["batch_no"] = d.batch_no
reserved_serial_nos = get_pos_reserved_serial_nos(filters) reserved_serial_nos = get_pos_reserved_serial_nos(filters)
serial_nos = get_serial_nos(d.serial_no) serial_nos = get_serial_nos(d.serial_no)
invalid_serial_nos = [s for s in serial_nos if s in reserved_serial_nos] invalid_serial_nos = [s for s in serial_nos if s in reserved_serial_nos]

View File

@ -70,6 +70,7 @@ class POSProfile(Document):
{"parent": d.mode_of_payment, "company": self.company}, {"parent": d.mode_of_payment, "company": self.company},
"default_account" "default_account"
) )
if not account: if not account:
invalid_modes.append(get_link_to_form("Mode of Payment", d.mode_of_payment)) invalid_modes.append(get_link_to_form("Mode of Payment", d.mode_of_payment))

View File

@ -92,11 +92,21 @@ def make_pos_profile(**args):
"write_off_cost_center": args.write_off_cost_center or "_Test Write Off Cost Center - _TC" "write_off_cost_center": args.write_off_cost_center or "_Test Write Off Cost Center - _TC"
}) })
payments = [{ mode_of_payment = frappe.get_doc("Mode of Payment", "Cash")
company = args.company or "_Test Company"
default_account = args.income_account or "Sales - _TC"
if not frappe.db.get_value("Mode of Payment Account", {"company": company, "parent": "Cash"}):
mode_of_payment.append("accounts", {
"company": company,
"default_account": default_account
})
mode_of_payment.save()
pos_profile.append("payments", {
'mode_of_payment': 'Cash', 'mode_of_payment': 'Cash',
'default': 1 'default': 1
}] })
pos_profile.set("payments", payments)
if not frappe.db.exists("POS Profile", args.name or "_Test POS Profile"): if not frappe.db.exists("POS Profile", args.name or "_Test POS Profile"):
pos_profile.insert() pos_profile.insert()

View File

@ -92,7 +92,7 @@ frappe.ui.form.on('Process Statement Of Accounts', {
frm.refresh_field('customers'); frm.refresh_field('customers');
} }
else{ else{
frappe.msgprint('No Customers found with selected options.'); frappe.throw('No Customers found with selected options.');
} }
} }
} }

View File

@ -126,9 +126,11 @@ def get_customers_based_on_sales_person(sales_person):
sales_person_records = frappe._dict() sales_person_records = frappe._dict()
for d in records: for d in records:
sales_person_records.setdefault(d.parenttype, set()).add(d.parent) sales_person_records.setdefault(d.parenttype, set()).add(d.parent)
customers = frappe.get_list('Customer', fields=['name', 'email_id'], \ if sales_person_records.get('Customer'):
return frappe.get_list('Customer', fields=['name', 'email_id'], \
filters=[['name', 'in', list(sales_person_records['Customer'])]]) filters=[['name', 'in', list(sales_person_records['Customer'])]])
return customers else:
return []
def get_recipients_and_cc(customer, doc): def get_recipients_and_cc(customer, doc):
recipients = [] recipients = []

View File

@ -1370,7 +1370,7 @@
"idx": 204, "idx": 204,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2021-03-30 21:45:58.334107", "modified": "2021-03-30 22:45:58.334107",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Purchase Invoice", "name": "Purchase Invoice",

View File

@ -24,6 +24,7 @@ from erpnext.accounts.deferred_revenue import validate_service_stop_date
from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import get_party_tax_withholding_details from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import get_party_tax_withholding_details
from frappe.model.utils import get_fetch_values from frappe.model.utils import get_fetch_values
from frappe.contacts.doctype.address.address import get_address_display from frappe.contacts.doctype.address.address import get_address_display
from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import get_party_tax_withholding_details
from erpnext.healthcare.utils import manage_invoice_submit_cancel from erpnext.healthcare.utils import manage_invoice_submit_cancel
@ -211,6 +212,9 @@ class SalesInvoice(SellingController):
# this sequence because outstanding may get -ve # this sequence because outstanding may get -ve
self.make_gl_entries() self.make_gl_entries()
if self.update_stock == 1:
self.repost_future_sle_and_gle()
if self.update_stock == 1: if self.update_stock == 1:
self.repost_future_sle_and_gle() self.repost_future_sle_and_gle()

View File

@ -1166,10 +1166,12 @@ class TestSalesInvoice(unittest.TestCase):
def test_create_so_with_margin(self): def test_create_so_with_margin(self):
si = create_sales_invoice(item_code="_Test Item", qty=1, do_not_submit=True) si = create_sales_invoice(item_code="_Test Item", qty=1, do_not_submit=True)
price_list_rate = 100 price_list_rate = flt(100) * flt(si.plc_conversion_rate)
si.items[0].price_list_rate = price_list_rate si.items[0].price_list_rate = price_list_rate
si.items[0].margin_type = 'Percentage' si.items[0].margin_type = 'Percentage'
si.items[0].margin_rate_or_amount = 25 si.items[0].margin_rate_or_amount = 25
si.items[0].discount_amount = 0.0
si.items[0].discount_percentage = 0.0
si.save() si.save()
self.assertEqual(si.get("items")[0].rate, flt((price_list_rate*25)/100 + price_list_rate)) self.assertEqual(si.get("items")[0].rate, flt((price_list_rate*25)/100 + price_list_rate))

View File

@ -443,6 +443,16 @@
"onboard": 0, "onboard": 0,
"type": "Link" "type": "Link"
}, },
{
"dependencies": "GL Entry",
"hidden": 0,
"is_query_report": 1,
"label": "UAE VAT 201",
"link_to": "UAE VAT 201",
"link_type": "Report",
"onboard": 0,
"type": "Link"
},
{ {
"hidden": 0, "hidden": 0,
"is_query_report": 0, "is_query_report": 0,

View File

@ -13,6 +13,8 @@
"po_required", "po_required",
"pr_required", "pr_required",
"maintain_same_rate", "maintain_same_rate",
"maintain_same_rate_action",
"role_to_override_stop_action",
"allow_multiple_items", "allow_multiple_items",
"subcontract", "subcontract",
"backflush_raw_materials_of_subcontract_based_on", "backflush_raw_materials_of_subcontract_based_on",
@ -89,6 +91,23 @@
{ {
"fieldname": "column_break_11", "fieldname": "column_break_11",
"fieldtype": "Column Break" "fieldtype": "Column Break"
},
{
"default": "Stop",
"depends_on": "maintain_same_rate",
"description": "Configure the action to stop the transaction or just warn if the same rate is not maintained.",
"fieldname": "maintain_same_rate_action",
"fieldtype": "Select",
"label": "Action If Same Rate is Not Maintained",
"mandatory_depends_on": "maintain_same_rate",
"options": "Stop\nWarn"
},
{
"depends_on": "eval:doc.maintain_same_rate_action == 'Stop'",
"fieldname": "role_to_override_stop_action",
"fieldtype": "Link",
"label": "Role Allowed to Override Stop Action",
"options": "Role"
} }
], ],
"icon": "fa fa-cog", "icon": "fa fa-cog",
@ -96,7 +115,7 @@
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"issingle": 1, "issingle": 1,
"links": [], "links": [],
"modified": "2021-03-02 17:34:04.190677", "modified": "2021-04-04 20:01:44.087066",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Buying Settings", "name": "Buying Settings",

View File

@ -0,0 +1,7 @@
## Version 13.0.2 Release Notes
### Fixes
- fix: frappe.whitelist for doc methods ([#25231](https://github.com/frappe/erpnext/pull/25231))
- fix: incorrect incoming rate for the sales return ([#25306](https://github.com/frappe/erpnext/pull/25306))
- fix(e-invoicing): validations & tax calculation fixes ([#25314](https://github.com/frappe/erpnext/pull/25314))
- fix: update scheduler check time ([#25295](https://github.com/frappe/erpnext/pull/25295))

View File

@ -0,0 +1,471 @@
# Version 13.0.0 Release Notes
### Accounting
- [New and refreshed POS](https://github.com/frappe/erpnext/pull/20789)
- [GST E-invoicing for India](https://docs.erpnext.com/docs/user/manual/en/regional/india/setup-e-invoicing)
- [Distributed Cost Center](https://docs.erpnext.com/docs/user/manual/en/accounts/distributed-cost-center)
- [Process Bulk Statement Of Accounts](https://docs.erpnext.com/docs/user/manual/en/accounts/process-statement-of-accounts)
- [More controlled deferred revenue booking](https://docs.erpnext.com/docs/user/manual/en/accounts/process-deferred-accounting)
- [Dunning](https://docs.erpnext.com/docs/user/manual/en/accounts/dunning)
- [Journal Entry Template](https://docs.erpnext.com/docs/user/manual/en/accounts/journal-entry-template)
- [POS Register report](https://github.com/frappe/erpnext/pull/23313)
- [UAE VAT 201 Report](https://github.com/frappe/erpnext/pull/23447)
### Loan Management
- [Loan Application](https://docs.erpnext.com/docs/user/manual/en/loan-management/loan-application)
- [Loan](https://docs.erpnext.com/docs/user/manual/en/loan-management/loan)
- [Loan Security Pledge](https://docs.erpnext.com/docs/user/manual/en/loan-management/loan-security-pledge)
- [Loan Disbursement](https://docs.erpnext.com/docs/user/manual/en/loan-management/loan-disbursement)
- [Loan Repayment](https://docs.erpnext.com/docs/user/manual/en/loan-management/loan-repayment)
- [Loan Interest Accrual](https://docs.erpnext.com/docs/user/manual/en/loan-management/loan-interest-accrual)
- [Loan Write Off](https://docs.erpnext.com/docs/user/manual/en/loan-management/loan-write-off)
### Healthcare
- [Refactored Healthcare Module](https://docs.erpnext.com/docs/user/manual/en/healthcare)
- [Rehabilitation Module](https://docs.erpnext.com/docs/user/manual/en/healthcare/exercise_type)
- [Laboratory Module](https://docs.erpnext.com/docs/user/manual/en/healthcare/setup_laboratory)
- [Patient Progress Page](https://github.com/frappe/erpnext/pull/22474)
- [Inpatient Medication Order and Entry](https://docs.erpnext.com/docs/user/manual/en/healthcare/inpatient_medication_entry)
- [Therapy Plan Template](https://docs.erpnext.com/docs/user/manual/en/healthcare/therapy_plan)
- [Multi company support in Healthcare](https://github.com/frappe/erpnext/pull/21290)
- [Inpatient Medication Orders Script Report](https://github.com/frappe/erpnext/pull/23984)
- [Patient History Enhancements](https://github.com/frappe/erpnext/pull/24033)
### Stock
- [Putaway](https://docs.erpnext.com/docs/user/manual/en/stock/putaway-rule)
- [More accurate stock valuation in case of back-dated stock transactions](https://github.com/frappe/erpnext/pull/24183)
- [Repost item costing via background job](https://github.com/frappe/erpnext/pull/24183)
- [Item valuation for internal stock transfers](https://github.com/frappe/erpnext/pull/24200)
- [Multi currency in Landed Cost Voucher](https://github.com/frappe/erpnext/pull/24127)
- [Formula based Quality Inspection](https://docs.erpnext.com/docs/user/manual/en/stock/quality-inspection)
- [Value Based and Numeric Quality Inspection](https://github.com/frappe/erpnext/pull/24181)
- [Shipment](https://github.com/frappe/erpnext/pull/22914)
- [Return tracking in PR/DN](https://github.com/frappe/erpnext/pull/22859)
### Manufacturing
- [Production forecasting using Exponential Smoothing method](https://docs.erpnext.com/docs/user/manual/en/manufacturing/reports/demand-driven-forecasting)
- [BOM Template](https://docs.erpnext.com/docs/user/manual/en/manufacturing/bill-of-materials#34-bom-template)
- [Downtime Entry](https://docs.erpnext.com/docs/user/manual/en/manufacturing/downtime-entry)
- [Quality Inspection on Job Card](https://github.com/frappe/erpnext/pull/23964)
- New Reports
- Production Planning Report ([#21763](https://github.com/frappe/erpnext/pull/21763))
- BOM Operations Time ([#21763](https://github.com/frappe/erpnext/pull/21763))
- Work Order Summary ([#21430](https://github.com/frappe/erpnext/pull/21430))
- Job card Summary ([#21430](https://github.com/frappe/erpnext/pull/21430))
- Downtime Analysis ([#21430](https://github.com/frappe/erpnext/pull/21430))
- Quality Inspection ([#21430](https://github.com/frappe/erpnext/pull/21430))
### HR
- [Leave policy assignment](https://github.com/frappe/erpnext/pull/23112)
- [In and Out time in attendance](https://github.com/frappe/erpnext/pull/21547)
- [Shift management](https://docs.erpnext.com/docs/user/manual/en/human-resources/shift-management)
- [Recruitment analytics](https://github.com/frappe/erpnext/pull/21732)
- [Bulk Mark Attendance](https://github.com/frappe/erpnext/pull/20062)
- [Leave type with partial payment](https://github.com/frappe/erpnext/pull/23173)
- New and enhanced reports
- Employee Analytics ([#21705](https://github.com/frappe/erpnext/pull/21705))
- Employee Leave Balance ([#20754](https://github.com/frappe/erpnext/pull/20754))
- Employee Leave Balance Summary ([#20754](https://github.com/frappe/erpnext/pull/20754))
### Payroll
- [Multi-currency payroll](https://github.com/frappe/erpnext/pull/23519)
- [Payroll based on attendance](https://github.com/frappe/erpnext/pull/21258)
- [Payroll based on employee cost center](https://github.com/frappe/erpnext/pull/21609)
- [Recurring Additional Salary](https://github.com/frappe/erpnext/pull/20936)
- [Compute Year to Date for Salary Slip components](https://github.com/frappe/erpnext/pull/24362)
- New Reports
- Income Tax Deductions
- Professional Tax Deductions
- Provident Fund Deductions
- Total Salary Payments Based on Payment Mode
- Salary Payments via ECS
### CRM
- [Social Media Post](https://docs.erpnext.com/docs/user/manual/en/CRM/social-media-post)
- [Make Quotation against Blanket Order](https://docs.erpnext.com/docs/user/manual/en/selling/blanket-order)
- [Calendar View for Opportunity](https://github.com/frappe/erpnext/pull/21280)
### Selling
- [Batch wise item pricing](https://github.com/frappe/erpnext/pull/24470)
- [Refreshed shopping cart](https://github.com/frappe/erpnext/pull/22617)
- [Territory-wise Sales Report](https://github.com/frappe/erpnext/pull/20428)
#### Buying
- [Multi UOM support in Request for Quotation](https://github.com/frappe/erpnext/pull/22249)
- [Provision to make RFQ against Opportunity](https://github.com/frappe/erpnext/pull/22765)
- [Item Rate in Stock UOM in purchase cycle](https://github.com/frappe/erpnext/pull/24315)
- New Reports
- Requested Items To Order ([#21611](https://github.com/frappe/erpnext/pull/21611))
- Purchase Order Analysis ([#21611](https://github.com/frappe/erpnext/pull/21611))
- Supplier Quotation Comparison report ([#23323](https://github.com/frappe/erpnext/pull/23323))
### Project
- [Project template with dependent tasks](https://github.com/frappe/erpnext/pull/24092)
- [Project Summary Report](https://github.com/frappe/erpnext/pull/21587)
### Support
- [Help Articles on support portal](https://github.com/frappe/erpnext/pull/22194)
- [Issue Metrics and SLA Enhancements](https://github.com/frappe/erpnext/pull/21617)
- [Issue Summary Script Report](https://docs.erpnext.com/docs/user/manual/en/support/support_reports)
- [Issue Analytics Script Report](https://docs.erpnext.com/docs/user/manual/en/support/support_reports)
### Non-Profits
- [80G Certificates and Donations](https://docs.erpnext.com/docs/user/manual/en/non_profit/tax_exemption_80g_certificate)
#### Integrations
- [Woocommerce Integration](https://docs.erpnext.com/docs/user/manual/en/erpnext_integration/woocommerce_integration)
- [Taxjar Integration](https://github.com/frappe/erpnext/pull/21047)
- [M-pesa Integration](https://docs.erpnext.com/docs/user/manual/en/erpnext_integration/mpesa-integration)
- [Telephony feature using Twillio](https://github.com/frappe/erpnext/pull/24032)
- [Voice Call Settings](https://github.com/frappe/erpnext/pull/24126)
#### Other Enhancements and Fixes
- Accounting Dimensions in Budget Variance Report ([#19973](https://github.com/frappe/erpnext/pull/19973))
- "Sync Now" option in Plaid Settings ([#23602](https://github.com/frappe/erpnext/pull/23602))
- Custom Fields in POS ([#19876](https://github.com/frappe/erpnext/pull/19876))
- [Inter Warehouse Stock Transfer in Purchase Receipt](https://docs.erpnext.com/docs/user/manual/en/stock/articles/material-transfer-from-delivery-note)
- [Accounts Payable Report based on Payment Terms](https://docs.erpnext.com/docs/user/manual/en/accounts/accounting-reports)
- Configurable accounting dimension filters and validations ([#23912](https://github.com/frappe/erpnext/pull/23912))
- Territory tree in Customer Acquisition and Loyalty report ([#21668](https://github.com/frappe/erpnext/pull/21668))
- Allow Purchase Invoice Creation Without Purchase Order Checkbox in Supplier ([#20864](https://github.com/frappe/erpnext/pull/20864))
- Gross Profit In Quotation ([#21795](https://github.com/frappe/erpnext/pull/21795))
- Notify credit controller users for credit limit extension via Email ([#22213](https://github.com/frappe/erpnext/pull/22213))
- Run MRP at parent level in the production plan and make material transfer based upon materials availability ([#21545](https://github.com/frappe/erpnext/pull/21545))
- Balance Serial Nos in Stock Ledger report ([#23675](https://github.com/frappe/erpnext/pull/23675))
- Youtube interactions via Video ([#22867](https://github.com/frappe/erpnext/pull/22867))
- Consider Holiday List in Student Leave Application and Attendance ([#23388](https://github.com/frappe/erpnext/pull/23388))
- Patient appointment status changes ([#24201](https://github.com/frappe/erpnext/pull/24201))
- Sales order status filter added for production plan ([#23805](https://github.com/frappe/erpnext/pull/23805))
- Monthly attendance sheet report group by Department, Designation, Employee Grade and Branch ([#21331](https://github.com/frappe/erpnext/pull/21331))
- Upload Attendance template now have pre-filled holiday status ([#20947](https://github.com/frappe/erpnext/pull/20947))
- Provision to disable serial no and batch selector ([#24398](https://github.com/frappe/erpnext/pull/24398))
<details>
<summary>More</summary>
- Fetch Items from BOM in Stock Entry([#19498](https://github.com/frappe/erpnext/pull/19498))
- Supplier Sourced Items in BOM ([#23557](https://github.com/frappe/erpnext/pull/23557))
- Close Production Plan ([#23728](https://github.com/frappe/erpnext/pull/23728))
- Button to create Stock Entry for Drug Shortage ([#24012](https://github.com/frappe/erpnext/pull/24012))
- Added column cost center in Accounts Receivable report ([#23835](https://github.com/frappe/erpnext/pull/23835))
- Added jinja templating in Contract Template ([#24046](https://github.com/frappe/erpnext/pull/24046))
- Make account number length configurable ([#23845](https://github.com/frappe/erpnext/pull/23845))
- Add company and correct filter in bank reconciliation statement ([#23614](https://github.com/frappe/erpnext/pull/23614))
- Added Condition field in Pricing Rule ([#23014](https://github.com/frappe/erpnext/pull/23014))
- Open lead status on next contact date ([#23445](https://github.com/frappe/erpnext/pull/23445))
- [Tax Category in POS Profile](https://docs.erpnext.com/docs/user/manual/en/accounts/pos-profile)
- Added phone field in product Inquiry ([#23170](https://github.com/frappe/erpnext/pull/23170))
- Allow Discharge despite Unbilled Healthcare Services ([#24281](https://github.com/frappe/erpnext/pull/24281))
- Do Not Bill Patient Encounters for Inpatients ([#24355](https://github.com/frappe/erpnext/pull/24355))
- Autofill Supplier pop-up when only 1 Supplier in RFQ ([#22512](https://github.com/frappe/erpnext/pull/22512))
- Accounting entries for service item in Purchase receipt ([#22223](https://github.com/frappe/erpnext/pull/22223))
- Added Project in Sales Analytics report ([#23309](https://github.com/frappe/erpnext/pull/23309))
- Added all companies option in employee tree to view employee across all companies ([#22573](https://github.com/frappe/erpnext/pull/22573))
- Email Group Option In Email Campaign ([#22731](https://github.com/frappe/erpnext/pull/22731))
- Stock Report Enhancements ([#21727](https://github.com/frappe/erpnext/pull/21727))
- Added range for age in stock ageing ([#22622](https://github.com/frappe/erpnext/pull/22622))
- Report Summary in Financial Statement([#20876](https://github.com/frappe/erpnext/pull/20876))
- Added sequence id in routing for the completion of operations sequentially ([#23641](https://github.com/frappe/erpnext/pull/23641))
- Nested Set filtering for Accounting Dimension
- Add/Remove Items from submitted Sales/Purchase Order
- Provision to edit Item Details from Marketplace
- Scan Barcode in Purchase Receipt
- Disable Rounded Totals Checkbox for Salary Slips in HR Settings
- Renamed Loan Management to Loan on Desk Page ([#21877](https://github.com/frappe/erpnext/pull/21877))
- Added Expense Approver field in Employee master ([#22244](https://github.com/frappe/erpnext/pull/22244))
- Bill all hours by default on Timesheet ([#22155](https://github.com/frappe/erpnext/pull/22155))
- Unable to cancel employee advance ([#22374](https://github.com/frappe/erpnext/pull/22374))
- Status error in purchase invoice ([#22351](https://github.com/frappe/erpnext/pull/22351))
- Item-wise sales and purchase register export ([#22184](https://github.com/frappe/erpnext/pull/22184))
- Billing address in for Purchase documents ([#22233](https://github.com/frappe/erpnext/pull/22233))
- Handle canceled entries in financial statements ([#22231](https://github.com/frappe/erpnext/pull/22231))
- Default period start date and period end date for financial statements ([#22011](https://github.com/frappe/erpnext/pull/22011))
- Update Packed Items via Update Items in Sales Order ([#22392](https://github.com/frappe/erpnext/pull/22392))
- Hide delete company transactions button if not system manager ([#21839](https://github.com/frappe/erpnext/pull/21839))
- Skipping total row for tree-view reports ([#22350](https://github.com/frappe/erpnext/pull/22350))
- Cancelled entries in tds payable monthly report ([#22131](https://github.com/frappe/erpnext/pull/22131))
- Inter-company Invoice currency for multicurrency transactions ([#21984](https://github.com/frappe/erpnext/pull/21984))
- Filter batches based on item and warehouse in Pick List (develop) ([#21780](https://github.com/frappe/erpnext/pull/21780))
- Set cost center in Expense Claim child based on parent (if missing) ([#22175](https://github.com/frappe/erpnext/pull/22175))
- Item wise backdated stock entry posting for immutable ledger ([#22366](https://github.com/frappe/erpnext/pull/22366))
- Shopping cart UI fixes ([#22137](https://github.com/frappe/erpnext/pull/22137))
- Filter Leave Type based on allocation for a particular employee ([#22050](https://github.com/frappe/erpnext/pull/22050))
- Party validation for inter-warehouse transaction ([#22186](https://github.com/frappe/erpnext/pull/22186))
- Manufacturing dashboard and work order summary chart ([#21946](https://github.com/frappe/erpnext/pull/21946))
- IP Admission and Discharge, Minor fixes ([#21817](https://github.com/frappe/erpnext/pull/21817))
- Validation of Purchase Order against Material Request missing ([#22192](https://github.com/frappe/erpnext/pull/22192))
- Staffing Plan validation ([#22379](https://github.com/frappe/erpnext/pull/22379))
- Do not allow backdated stock transactions in previous fiscal year ([#21967](https://github.com/frappe/erpnext/pull/21967))
- Employee Advance Return not working ([#21812](https://github.com/frappe/erpnext/pull/21812))
- Added card for reports on education desk ([#21853](https://github.com/frappe/erpnext/pull/21853))
- Refactored project summary report ([#21943](https://github.com/frappe/erpnext/pull/21943))
- Revenue and Customer Count only in date range in Customer Acquitition Report ([#22210](https://github.com/frappe/erpnext/pull/22210))
- Alternative item not working for subcontract ([#22386](https://github.com/frappe/erpnext/pull/22386))
- Unable to create batched Item ([#22393](https://github.com/frappe/erpnext/pull/22393))
- Filters for the manufacturing reports ([#21960](https://github.com/frappe/erpnext/pull/21960))
- Raw material warehouse in Production Planning Report ([#21982](https://github.com/frappe/erpnext/pull/21982))
- Allowed LWP leave types to select in Leave Application even if there is no allocation against them ([#22197](https://github.com/frappe/erpnext/pull/22197))
- Report not working on parameter Grade ([#21951](https://github.com/frappe/erpnext/pull/21951))
- Allow to enter Relieving date if employee status is Left ([#22242](https://github.com/frappe/erpnext/pull/22242))
- Resetting lost reason in opportunity and quotation ([#22378](https://github.com/frappe/erpnext/pull/22378))
- Filtering issues in opening invoice creation tool ([#21969](https://github.com/frappe/erpnext/pull/21969))
- Set default reference Id for "On Previous Row Amount" and "On Previous Row Total" ([#22346](https://github.com/frappe/erpnext/pull/22346))
- UX date range field separated in from and to date fields. ([#21765](https://github.com/frappe/erpnext/pull/21765))
- Enable show_configure_button when shopping cart is enabled ([#22468](https://github.com/frappe/erpnext/pull/22468))
- Setup status indicators for Job Offer and Job Applicant (develop) ([#22445](https://github.com/frappe/erpnext/pull/22445))
- Item-wise sales history report ([#22783](https://github.com/frappe/erpnext/pull/22783))
- Setting filter for project in kanban board ([#22717](https://github.com/frappe/erpnext/pull/22717))
- Dashboard For Timesheet ([#22750](https://github.com/frappe/erpnext/pull/22750))
- Handle custom statuses for the pause SLA configuration ([#22349](https://github.com/frappe/erpnext/pull/22349))
- Quality Feedback and Template ([#22571](https://github.com/frappe/erpnext/pull/22571))
- Unable to change link from new lead to existing customer ([#22787](https://github.com/frappe/erpnext/pull/22787))
- Move Issue List actions under 'Actions' dropdown (ux) ([#22710](https://github.com/frappe/erpnext/pull/22710))
- Cost center should only show option of selected company ([#22598](https://github.com/frappe/erpnext/pull/22598))
- Serial No Rename does not affect Stock Ledger Entry ([#22746](https://github.com/frappe/erpnext/pull/22746))
- Descriptions not copied while creating Fees from Fee Structure ([#22792](https://github.com/frappe/erpnext/pull/22792))
- Company filter for cost_center and expense_account in all sales and purchase transactions ([#22478](https://github.com/frappe/erpnext/pull/22478))
- Arrangements of filters for reports accounts payable & receivable ([#22636](https://github.com/frappe/erpnext/pull/22636))
- Update the project after task deletion so that the % completed shows correct value ([#22591](https://github.com/frappe/erpnext/pull/22591))
- Block Invalid Serial No updates in Maintenance Schedule ([#22665](https://github.com/frappe/erpnext/pull/22665))
- Fetch item price in sales invoice based on it's validity ([#22563](https://github.com/frappe/erpnext/pull/22563))
- Add view ledger button for cancelled docs ([#22432](https://github.com/frappe/erpnext/pull/22432))
- Allow creating SLA documents even if SLA tracking is not enabled ([#22608](https://github.com/frappe/erpnext/pull/22608))
- Quotation list view blank if quotation_to field not set as a standard filter ([#22672](https://github.com/frappe/erpnext/pull/22672))
- Salary deductions report fixes ([#22397](https://github.com/frappe/erpnext/pull/22397))
22727))
- Incorrect delivered qty in Supplier-Wise Sales Analytics ([#22631](https://github.com/frappe/erpnext/pull/22631))
- Moved parent warehouse to top section also added a section break ([#22708](https://github.com/frappe/erpnext/pull/22708))
- Skip Progress and Completed by fields on Task Duplication ([#22565](https://github.com/frappe/erpnext/pull/22565))
- Incorrect stock after merging the items ([#22526](https://github.com/frappe/erpnext/pull/22526))
- Letter head not found in opening invoice creation tool ([#22488](https://github.com/frappe/erpnext/pull/22488))
- Cannot cancel asset and asset movement ([#22441](https://github.com/frappe/erpnext/pull/22441))
- Fetch project-related info in Timesheet ([#22423](https://github.com/frappe/erpnext/pull/22423))
- Currency symbol not showing as per company currency in stock balance report ([#22724](https://github.com/frappe/erpnext/pull/22724))
- Add default cost center in payment reconciliation JV ([#22614](https://github.com/frappe/erpnext/pull/22614))
- Stock Reconciliation Invalid Quantity for Batched Item ([#22726](https://github.com/frappe/erpnext/pull/22726))
- Project link not set in accounts other than profit and loss accounts ([#22051](https://github.com/frappe/erpnext/pull/22051))
- Buying price for non stock item in gross profit report ([#22616](https://github.com/frappe/erpnext/pull/22616))
- Multi currency payment reconciliation ([#22738](https://github.com/frappe/erpnext/pull/22738))
- Cannot cancel assets with repair pending ([#22440](https://github.com/frappe/erpnext/pull/22440))
- Reset homepage to home after unchecking products page ([#22736](https://github.com/frappe/erpnext/pull/22736))
- Generic Message in previous doc validation for buying and selling ([#22546](https://github.com/frappe/erpnext/pull/22546))
- Expense claim outstanding while making payment entry ([#22735](https://github.com/frappe/erpnext/pull/22735))
- Take parent cost center for child if no cost center at child in expense claim ([#22496](https://github.com/frappe/erpnext/pull/22496))
- Consider company fiscal year for getting balance ([#22577](https://github.com/frappe/erpnext/pull/22577))
- Pick List empty table and Serial-Batch items handling ([#22426](https://github.com/frappe/erpnext/pull/22426))
- Show total row in print format of financial statement ([#22693](https://github.com/frappe/erpnext/pull/22693))
- Set Root as Parent if no parent in new tree view node ([#22497](https://github.com/frappe/erpnext/pull/22497))
- Multiple pos issues ([#23725](https://github.com/frappe/erpnext/pull/23725))
- Calculate taxes if tax is based on item quantity and inclusive on item price ([#23001](https://github.com/frappe/erpnext/pull/23001))
- Contact us button not visible in the website for the non variant items ([#23217](https://github.com/frappe/erpnext/pull/23217))
- Not able to make Material Request from Sales Order ([#23669](https://github.com/frappe/erpnext/pull/23669))
- Capture advance payments in payment order ([#23256](https://github.com/frappe/erpnext/pull/23256))
- Program and Course Enrollment fixes ([#23333](https://github.com/frappe/erpnext/pull/23333))
- Cannot create asset if cwip disabled and account not set ([#23580](https://github.com/frappe/erpnext/pull/23580))
- Cannot merge pos invoices with inclusive tax ([#23541](https://github.com/frappe/erpnext/pull/23541))
- Do not allow Company as accounting dimension ([#23755](https://github.com/frappe/erpnext/pull/23755))
- Set value of wrong Bank Account field in Payment Entry ([#22302](https://github.com/frappe/erpnext/pull/22302))
- Reverse journal entry for multi-currency ([#23165](https://github.com/frappe/erpnext/pull/23165))
- Updated integrations desk page ([#23772](https://github.com/frappe/erpnext/pull/23772))
- Assessment Result child table not visible when accessed via Assessment Plan dashboard ([#22880](https://github.com/frappe/erpnext/pull/22880))
- Conversion factor fixes in Stock Entry ([#23407](https://github.com/frappe/erpnext/pull/23407))
- Total calculations for multi-currency RCM invoices ([#23072](https://github.com/frappe/erpnext/pull/23072))
- Show accounts in financial statements upto level 20 ([#23718](https://github.com/frappe/erpnext/pull/23718))
- Consolidated financial statement sums values into wrong parent ([#23288](https://github.com/frappe/erpnext/pull/23288))
- Set SLA variance in seconds for Duration fieldtype ([#23765](https://github.com/frappe/erpnext/pull/23765))
- Added missing reports on selling desk ([#23548](https://github.com/frappe/erpnext/pull/23548))
- Fixed heading in the mobile view ([#23145](https://github.com/frappe/erpnext/pull/23145))
- Misleading filters on Item tax Template Link field ([#22918](https://github.com/frappe/erpnext/pull/22918))
- Do not consider opening entries for TDS calculation ([#23597](https://github.com/frappe/erpnext/pull/23597))
- Attendance calendar map fix ([#23245](https://github.com/frappe/erpnext/pull/23245))
- Post cancellation accounting entry on posting date instead of current ([#23361](https://github.com/frappe/erpnext/pull/23361))
- Set Customer only if Contact is present ([#23704](https://github.com/frappe/erpnext/pull/23704))
- Add Delivery Note Count in Sales Invoice Dashboard ([#23161](https://github.com/frappe/erpnext/pull/23161))
- Breadcrumbs for Maintenance Visit and Schedule ([#23369](https://github.com/frappe/erpnext/pull/23369))
- Raise Error on over receipt/consumption for sub-contracted PR ([#23195](https://github.com/frappe/erpnext/pull/23195))
- Validate if company not set in the Payment Entry ([#23419](https://github.com/frappe/erpnext/pull/23419))
- Ignore company and bank account doctype while deleting company transactions ([#22953](https://github.com/frappe/erpnext/pull/22953))
- Sales funnel data is inconsistent ([#23110](https://github.com/frappe/erpnext/pull/23110))
- Credit Limit Email not working ([#23059](https://github.com/frappe/erpnext/pull/23059))
- Add Company in list fields to fetch for Expense Claim ([#23007](https://github.com/frappe/erpnext/pull/23007))
- Issue form cleaned up and renamed Minutes to First Response field ([#23066](https://github.com/frappe/erpnext/pull/23066))
- Quotation lost reason options fix ([#22814](https://github.com/frappe/erpnext/pull/22814))
- Tax amounts in HSN Wise Outward summary ([#23076](https://github.com/frappe/erpnext/pull/23076))
- Patient Appointment not able to save ([#23434](https://github.com/frappe/erpnext/pull/23434))
- Removed Working Hours field from Company ([#23009](https://github.com/frappe/erpnext/pull/23009))
- Added check-in time validation in the Inpatient Record - Transfer ([#22958](https://github.com/frappe/erpnext/pull/22958))
- Handle Blank from/to range in Numeric Item Attribute ([#23483](https://github.com/frappe/erpnext/pull/23483))
- Sequence Matcher error in Bank Reconciliation ([#23539](https://github.com/frappe/erpnext/pull/23539))
- Fixed Conversion Factor rate for the BOM Exploded Item ([#23151](https://github.com/frappe/erpnext/pull/23151))
- Payment Schedule not fetching ([#23476](https://github.com/frappe/erpnext/pull/23476))
- Validate if removed Item Attributes exist in variant items ([#22911](https://github.com/frappe/erpnext/pull/22911))
- Set default billing address for purchase documents ([#22950](https://github.com/frappe/erpnext/pull/22950))
- Added help link in navbar settings ([#22943](https://github.com/frappe/erpnext/pull/22943))
- Apply TDS on Purchase Invoice creation from Purchase Order and Purchase Receipt ([#23282](https://github.com/frappe/erpnext/pull/23282))
- Education Module fixes ([#23714](https://github.com/frappe/erpnext/pull/23714))
- Filter out cancelled entries in customer ledger summary ([#23205](https://github.com/frappe/erpnext/pull/23205))
- Fiscal Year and Tax Rates for Italy ([#23623](https://github.com/frappe/erpnext/pull/23623))
- Production Plan incorrect Work Order qty ([#23264](https://github.com/frappe/erpnext/pull/23264))
- Added new filters in the Batch-wise Balance History report ([#23676](https://github.com/frappe/erpnext/pull/23676))
- Update state code and union territory for Daman and Diu ([#22988](https://github.com/frappe/erpnext/pull/22988))
- Set Stock UOM in item while creating Material Request from Stock Entry ([#23436](https://github.com/frappe/erpnext/pull/23436))
- Sales Order to Purchase Order flow improvement ([#23357](https://github.com/frappe/erpnext/pull/23357))
- Student Admission and Student Applicant fixes ([#23515](https://github.com/frappe/erpnext/pull/23515))
- Loan disbursement amount validation ([#24000](https://github.com/frappe/erpnext/pull/24000))
- Making company address read-only in delivery note ([#23890](https://github.com/frappe/erpnext/pull/23890))
- BOM stock report color showing always red ([#23994](https://github.com/frappe/erpnext/pull/23994))
- Added filter for customer field in Issue ([#24051](https://github.com/frappe/erpnext/pull/24051))
- Added project link in timesheet form ([#23764](https://github.com/frappe/erpnext/pull/23764))
- Update integrations desk page ([#23767](https://github.com/frappe/erpnext/pull/23767))
- Place of supply change on address change ([#23941](https://github.com/frappe/erpnext/pull/23941))
- TDS calculation, skip invoices with "Apply Tax Withholding Amount" has disabled ([#23672](https://github.com/frappe/erpnext/pull/23672))
- Auto fetch serial nos with modified conversion factor ([#23854](https://github.com/frappe/erpnext/pull/23854))
- Default cost center in item master not set in stock entry ([#23877](https://github.com/frappe/erpnext/pull/23877))
- Incorrect de-link serial no and batch ([#23947](https://github.com/frappe/erpnext/pull/23947))
- Accounting for internal transfer invoices within same company ([#24021](https://github.com/frappe/erpnext/pull/24021))
- Multiple pricing rule with margin type as Percentage is not working ([#24205](https://github.com/frappe/erpnext/pull/24205))
- Added Purchase Order to Global Search ([#24055](https://github.com/frappe/erpnext/pull/24055))
- Cannot expand row in update items dialog ([#23839](https://github.com/frappe/erpnext/pull/23839))
- Maintain stock can't be changed it there is product bundle ([#23989](https://github.com/frappe/erpnext/pull/23989))
- SO to PO Mapping Issue ([#23820](https://github.com/frappe/erpnext/pull/23820))
- Asset with value zero doesn't show up in fixed asset register ([#24091](https://github.com/frappe/erpnext/pull/24091))
- Cannot save customer email & phone ([#23797](https://github.com/frappe/erpnext/pull/23797))
- Incorrect balance value in stock balance report ([#24048](https://github.com/frappe/erpnext/pull/24048))
- Payment Terms not fetched in Purchase Invoice from Purchase Receipt ([#23735](https://github.com/frappe/erpnext/pull/23735))
- Fix for LMS Sign Up link ([#23743](https://github.com/frappe/erpnext/pull/23743))
- Incorrect stock quantity if 'Allow Multiple Material Consumption… ([#24116](https://github.com/frappe/erpnext/pull/24116))
- Added wrong absent days calculation in salary slip ([#23897](https://github.com/frappe/erpnext/pull/23897))
- Purchase receipt to purchase invoice bill date mapping ([#23967](https://github.com/frappe/erpnext/pull/23967))
- Overriding po ([#24022](https://github.com/frappe/erpnext/pull/24022))
- Do not cancel reference document on Quality Inspection cancellation ([#24198](https://github.com/frappe/erpnext/pull/24198))
- Get formatted value in 'taxes' print template ([#24035](https://github.com/frappe/erpnext/pull/24035))
- Don't overrule Item Price via Pricing Rule Rate if 0 ([#23636](https://github.com/frappe/erpnext/pull/23636))
- Job card error handling for operations field ([#23991](https://github.com/frappe/erpnext/pull/23991))
- Validation for journal entry with 0 debit and credit values ([#23975](https://github.com/frappe/erpnext/pull/23975))
- Check if customer exists in product listing ([#24030](https://github.com/frappe/erpnext/pull/24030))
- Asset finance book posting date fix ([#23778](https://github.com/frappe/erpnext/pull/23778))
- Same source and target tables in Status Updater's update query ([#24110](https://github.com/frappe/erpnext/pull/24110))
- Asset finance book depreciation posting date fix ([#23833](https://github.com/frappe/erpnext/pull/23833))
- Ignore exception during leave ledger creation from patch ([#24005](https://github.com/frappe/erpnext/pull/24005))
- Added link of bank reconciliation and clearance in accounting desk page ([#23850](https://github.com/frappe/erpnext/pull/23850))
- Sales invoice add button from sales order dashboard ([#24077](https://github.com/frappe/erpnext/pull/24077))
- Incorrect calculation for consumed qty for subcontract item ([#23257](https://github.com/frappe/erpnext/pull/23257))
- Incorrect required_qty in Production Planning Report ([#24074](https://github.com/frappe/erpnext/pull/24074))
- Email digest user not found ([#23949](https://github.com/frappe/erpnext/pull/23949))
- Delete Receive at Warehouse entry on cancellation of Send to War… ([#24115](https://github.com/frappe/erpnext/pull/24115))
- Added TDS Payable account number and an error message ([#24065](https://github.com/frappe/erpnext/pull/24065))
- Override field_map for job card gantt ([#24155](https://github.com/frappe/erpnext/pull/24155))
- Old shopify order syncing date ([#23990](https://github.com/frappe/erpnext/pull/23990))
- Shipping chanrges not sync in erpnext from shopify ([#24114](https://github.com/frappe/erpnext/pull/24114))
- GSTR B2C report ([#24039](https://github.com/frappe/erpnext/pull/24039))
- Ignore cancelled entries in stock balance report ([#23757](https://github.com/frappe/erpnext/pull/23757))
- Stock ageing report not working ([#23923](https://github.com/frappe/erpnext/pull/23923))
- Incorrect assign to in Maintenance Schedule ([#23831](https://github.com/frappe/erpnext/pull/23831))
- Improve UX of DATEV report ([#23892](https://github.com/frappe/erpnext/pull/23892))
- Set SLA variance in seconds for Duration fieldtype ([#23765](https://github.com/frappe/erpnext/pull/23765))
- dDouble exception in payroll ([#24078](https://github.com/frappe/erpnext/pull/24078))
- Make asset dashboard charts public ([#23751](https://github.com/frappe/erpnext/pull/23751))
- Don't copy terms and discount from SO to PO ([#23903](https://github.com/frappe/erpnext/pull/23903))
- Ignore doctypes on company transaction delete ([#23864](https://github.com/frappe/erpnext/pull/23864))
- Error handling in Upload Attendance ([#23907](https://github.com/frappe/erpnext/pull/23907))
- Tax template update on customer address change ([#24160](https://github.com/frappe/erpnext/pull/24160))
- Not able to save bom ([#23910](https://github.com/frappe/erpnext/pull/23910))
- Enable Allow Auto Repeat for standard doctypes having auto_repeat field ([#23776](https://github.com/frappe/erpnext/pull/23776))
- Place of Supply fix in Sales Invoices ([#23785](https://github.com/frappe/erpnext/pull/23785))
- Opening invoices in GSTR-1 report ([#24117](https://github.com/frappe/erpnext/pull/24117))
- Partial serial no return issue ([#24208](https://github.com/frappe/erpnext/pull/24208))
- Import taxjar globally in the taxjar_integration module ([#24027](https://github.com/frappe/erpnext/pull/24027))
- Payroll attendance error ([#23887](https://github.com/frappe/erpnext/pull/23887))
- Loan application link on creating loan ([#23937](https://github.com/frappe/erpnext/pull/23937))
- POS item search includes non stock items ([#23914](https://github.com/frappe/erpnext/pull/23914))
- Paid amount in Sales Invoice POS return resets to 0 ([#24057](https://github.com/frappe/erpnext/pull/24057))
- Fiscal year can be shorter than 12 months ([#23838](https://github.com/frappe/erpnext/pull/23838))
- Loan repayment type option remove ([#23582](https://github.com/frappe/erpnext/pull/23582))
- Item wise tax calculation ([#23744](https://github.com/frappe/erpnext/pull/23744))
- Enabling track changes for stock settings ([#23982](https://github.com/frappe/erpnext/pull/23982))
- Added link of bank reconciliation and clearance in accounting desk page ([#23809](https://github.com/frappe/erpnext/pull/23809))
- Location data on Asset to use command(make_demo) ([#23825](https://github.com/frappe/erpnext/pull/23825))
- Handle Account and Item None not found in Opening Invoice Creation Tool ([#23559](https://github.com/frappe/erpnext/pull/23559))
- Multiple subcontracting issues ([#23662](https://github.com/frappe/erpnext/pull/23662))
- Sequence id override with workstation column ([#23810](https://github.com/frappe/erpnext/pull/23810))
- Leave policy dashboard fix and roles ([#24170](https://github.com/frappe/erpnext/pull/24170))
- Scan barcode does not update barcode item field in sales order ([#24090](https://github.com/frappe/erpnext/pull/24090))
- Item price duplicate checking ([#23408](https://github.com/frappe/erpnext/pull/23408))
- Tax template update on supplier change for India ([#24060](https://github.com/frappe/erpnext/pull/24060))
- Consumed qty logic for subcontracted raw materials ([#23314](https://github.com/frappe/erpnext/pull/23314))
- Finance book not getting added in journal Entry of asset value adjustment ([#24100](https://github.com/frappe/erpnext/pull/24100))
- Set proper state code in ewaybill JSON when GST category is SEZ ([#23953](https://github.com/frappe/erpnext/pull/23953))
- Copying po no when mapping doc ([#23729](https://github.com/frappe/erpnext/pull/23729))
- Duplicate items validation for POS Invoice when allow multiple items is disabled ([#23896](https://github.com/frappe/erpnext/pull/23896))
- Do not allow Company as accounting dimension ([#23749](https://github.com/frappe/erpnext/pull/23749))
- Validation for duplicate Tax Category ([#23978](https://github.com/frappe/erpnext/pull/23978))
- Therapy plan and session fixes ([#23817](https://github.com/frappe/erpnext/pull/23817))
- Pricing rule with transaction not working for additional product ([#24053](https://github.com/frappe/erpnext/pull/24053))
- Inpatient Medication Order and Entry fixes ([#23799](https://github.com/frappe/erpnext/pull/23799))
- Avoid using SQL query to get fiscal year dates ([#24050](https://github.com/frappe/erpnext/pull/24050))
- Auto Statewise gst tax template ([#23832](https://github.com/frappe/erpnext/pull/23832))
- On save sequence id column override with workstation ([#23812](https://github.com/frappe/erpnext/pull/23812))
- Multiple pricing rules are not working on selling side ([#22711](https://github.com/frappe/erpnext/pull/22711))
- Salary slip popup error ([#24192](https://github.com/frappe/erpnext/pull/24192))
- Multiple pricing rule with margin type as Percentage is not working ([#24204](https://github.com/frappe/erpnext/pull/24204))
- Allow statistical component in salary structure. ([#24424](https://github.com/frappe/erpnext/pull/24424))
- Set current asset value before calculating difference amount ([#24119](https://github.com/frappe/erpnext/pull/24119))
- To use Stock UoM in BOM Stock Report ([#24339](https://github.com/frappe/erpnext/pull/24339))
- Accounting entries of asset when submitting purchase receipt ([#24191](https://github.com/frappe/erpnext/pull/24191))
- Batch/Serial Selector for Scanned Batched Item ([#24338](https://github.com/frappe/erpnext/pull/24338))
- Link timesheets with corresponding projects ([#24346](https://github.com/frappe/erpnext/pull/24346))
- Material request wrong status issue ([#24019](https://github.com/frappe/erpnext/pull/24019))
- UX issues in e-invoicing ([#24358](https://github.com/frappe/erpnext/pull/24358))
- Company Wise Valuation Rate for RM in BOM ([#24324](https://github.com/frappe/erpnext/pull/24324))
- Stock ageing should not take cancelled stock entries. ([#24437](https://github.com/frappe/erpnext/pull/24437))
- Partial loan security unpledging ([#24252](https://github.com/frappe/erpnext/pull/24252))
- Asset depreciation ledger ([#24226](https://github.com/frappe/erpnext/pull/24226))
- Back Update from QC based on Batch No ([#24329](https://github.com/frappe/erpnext/pull/24329))
- Fix for not having fiscal year while creating new company ([#24130](https://github.com/frappe/erpnext/pull/24130))
- E-invoice print format not showing other charges ([#24474](https://github.com/frappe/erpnext/pull/24474))
- Tax template update on customer address change ([#24146](https://github.com/frappe/erpnext/pull/24146))
- Do not manufacture same serial no multiple times ([#24164](https://github.com/frappe/erpnext/pull/24164))
- Ignore group cost center validation for period closing voucher ([#24375](https://github.com/frappe/erpnext/pull/24375))
- Partial serial no return issue ([#24207](https://github.com/frappe/erpnext/pull/24207))
- GSTR-1 double entry issue ([#24376](https://github.com/frappe/erpnext/pull/24376))
- Not able to create dunning from sales invoice ([#24349](https://github.com/frappe/erpnext/pull/24349))
- Set company in leave allocation and leave ledger entry ([#24296](https://github.com/frappe/erpnext/pull/24296))
- Allow leave policy assignment to be canceled. ([#24265](https://github.com/frappe/erpnext/pull/24265))
- Removed all day event from shift assignment calendar ([#24397](https://github.com/frappe/erpnext/pull/24397))
- Tax calculation on salary slip for the first month ([#24272](https://github.com/frappe/erpnext/pull/24272))
- Validate tax template for tax category ([#24402](https://github.com/frappe/erpnext/pull/24402))
- Numeric/Non-numeric QI UX ([#24517](https://github.com/frappe/erpnext/pull/24517))
- Finished good produced qty validation ([#24220](https://github.com/frappe/erpnext/pull/24220))
- Incorrect serial no in the subcontracted purchase receipt ([#24354](https://github.com/frappe/erpnext/pull/24354))
- Don't validate warehouse values between Material Request and Stock Entry ([#24294](https://github.com/frappe/erpnext/pull/24294))
- Don't cancel job card if manufacturing entry has made ([#24063](https://github.com/frappe/erpnext/pull/24063))
- Subscription prepaid date validation ([#24356](https://github.com/frappe/erpnext/pull/24356))
- Payment Period based on invoice date report fix/refactor ([#24378](https://github.com/frappe/erpnext/pull/24378))
- Drop ship partial order fixed ([#24072](https://github.com/frappe/erpnext/pull/24072))
- Payment entry multi-currency issue ([#24332](https://github.com/frappe/erpnext/pull/24332))
- Multiple pricing rule issue ([#24515](https://github.com/frappe/erpnext/pull/24515))
- Last purchase rate not updating when voucher cancelled if only one voucher is present ([#24322](https://github.com/frappe/erpnext/pull/24322))
- Do not cancel reference document on Quality Inspection cancellation ([#24197](https://github.com/frappe/erpnext/pull/24197))
- Refactored fetching & validating address from erpnext rather than gst portal ([#24297](https://github.com/frappe/erpnext/pull/24297))
- Opportunity Status fix ([#22944](https://github.com/frappe/erpnext/pull/22944))
- Fixed stock and account balance syncing ([#24644](https://github.com/frappe/erpnext/pull/24644))
- Fixed incorrect stock ledger qty in the stock ledger report and bin ([#24649](https://github.com/frappe/erpnext/pull/24649))
- Fixed Consolidated Financial Statement report ([#24580](https://github.com/frappe/erpnext/pull/24580))
- Repost incompleted backdated transactions ([#24991](https://github.com/frappe/erpnext/pull/24991))
- Unequal debit and credit issue on RCM Invoice ([#24838](https://github.com/frappe/erpnext/pull/24838))
- Period list for exponential smoothing forecasting report ([#24983](https://github.com/frappe/erpnext/pull/24983))
- POS Opening Entry with empty balance detail rows ([#24891](https://github.com/frappe/erpnext/pull/24891))
- Use account_name only in consolidated report ([#24840](https://github.com/frappe/erpnext/pull/24840))
- Validation of job card in stock entry ([#24882](https://github.com/frappe/erpnext/pull/24882))
- Incorrect Nil Exempt and Non GST amount in GSTR3B report ([#24918](https://github.com/frappe/erpnext/pull/24918))
- TDS check getting checked after reload ([#24973](https://github.com/frappe/erpnext/pull/24973))
- Membership and Donation API fixes ([#24900](https://github.com/frappe/erpnext/pull/24900))
- Allow zero valuation in stock reconciliation ([#24985](https://github.com/frappe/erpnext/pull/24985))
- Simplified logic for additional salary ([#24907](https://github.com/frappe/erpnext/pull/24907))
- Allow to select item code in batch naming ([#24825](https://github.com/frappe/erpnext/pull/24825))
- Membership renewal validation (#24963) ([#24964](https://github.com/frappe/erpnext/pull/24964))
</details>

View File

@ -6,6 +6,7 @@ import frappe
from frappe import _, msgprint from frappe import _, msgprint
from frappe.utils import flt,cint, cstr, getdate from frappe.utils import flt,cint, cstr, getdate
from six import iteritems from six import iteritems
from collections import OrderedDict
from erpnext.accounts.party import get_party_details from erpnext.accounts.party import get_party_details
from erpnext.stock.get_item_details import get_conversion_factor from erpnext.stock.get_item_details import get_conversion_factor
from erpnext.buying.utils import validate_for_items, update_last_purchase_rate from erpnext.buying.utils import validate_for_items, update_last_purchase_rate
@ -391,10 +392,12 @@ class BuyingController(StockController):
batches_qty = get_batches_with_qty(raw_material.rm_item_code, raw_material.main_item_code, batches_qty = get_batches_with_qty(raw_material.rm_item_code, raw_material.main_item_code,
qty, transferred_batch_qty_map, backflushed_batch_qty_map, item.purchase_order) qty, transferred_batch_qty_map, backflushed_batch_qty_map, item.purchase_order)
for batch_data in batches_qty: for batch_data in batches_qty:
qty = batch_data['qty'] qty = batch_data['qty']
raw_material.batch_no = batch_data['batch'] raw_material.batch_no = batch_data['batch']
self.append_raw_material_to_be_backflushed(item, raw_material, qty) if qty > 0:
self.append_raw_material_to_be_backflushed(item, raw_material, qty)
else: else:
self.append_raw_material_to_be_backflushed(item, raw_material, qty) self.append_raw_material_to_be_backflushed(item, raw_material, qty)
@ -1056,7 +1059,7 @@ def get_transferred_batch_qty_map(purchase_order, fg_item):
for batch_data in transferred_batches: for batch_data in transferred_batches:
key = ((batch_data.item_code, fg_item) key = ((batch_data.item_code, fg_item)
if batch_data.subcontracted_item else (batch_data.item_code, purchase_order)) if batch_data.subcontracted_item else (batch_data.item_code, purchase_order))
transferred_batch_qty_map.setdefault(key, {}) transferred_batch_qty_map.setdefault(key, OrderedDict())
transferred_batch_qty_map[key][batch_data.batch_no] = batch_data.qty transferred_batch_qty_map[key][batch_data.batch_no] = batch_data.qty
return transferred_batch_qty_map return transferred_batch_qty_map
@ -1109,8 +1112,14 @@ def get_batches_with_qty(item_code, fg_item, required_qty, transferred_batch_qty
if available_qty >= required_qty: if available_qty >= required_qty:
available_batches.append({'batch': batch, 'qty': required_qty}) available_batches.append({'batch': batch, 'qty': required_qty})
break break
else: elif available_qty != 0:
available_batches.append({'batch': batch, 'qty': available_qty}) available_batches.append({'batch': batch, 'qty': available_qty})
required_qty -= available_qty required_qty -= available_qty
for row in available_batches:
if backflushed_batches.get(row.get('batch'), 0) > 0:
backflushed_batches[row.get('batch')] += row.get('qty')
else:
backflushed_batches[row.get('batch')] = row.get('qty')
return available_batches return available_batches

View File

@ -325,7 +325,7 @@ def get_delivery_notes_to_be_billed(doctype, txt, searchfield, start, page_len,
and status not in ("Stopped", "Closed") %(fcond)s and status not in ("Stopped", "Closed") %(fcond)s
and ( and (
(`tabDelivery Note`.is_return = 0 and `tabDelivery Note`.per_billed < 100) (`tabDelivery Note`.is_return = 0 and `tabDelivery Note`.per_billed < 100)
or `tabDelivery Note`.grand_total = 0 or (`tabDelivery Note`.grand_total = 0 and `tabDelivery Note`.per_billed < 100)
or ( or (
`tabDelivery Note`.is_return = 1 `tabDelivery Note`.is_return = 1
and return_against in (select name from `tabDelivery Note` where per_billed < 100) and return_against in (select name from `tabDelivery Note` where per_billed < 100)

View File

@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe, erpnext import frappe, erpnext
from frappe import _ from frappe import _
from frappe.model.meta import get_field_precision from frappe.model.meta import get_field_precision
from erpnext.stock.utils import get_incoming_rate
from frappe.utils import flt, get_datetime, format_datetime from frappe.utils import flt, get_datetime, format_datetime
class StockOverReturnError(frappe.ValidationError): pass class StockOverReturnError(frappe.ValidationError): pass
@ -389,10 +390,24 @@ def make_return_doc(doctype, source_name, target_doc=None):
return doclist return doclist
def get_rate_for_return(voucher_type, voucher_no, item_code, return_against=None, item_row=None, voucher_detail_no=None): def get_rate_for_return(voucher_type, voucher_no, item_code, return_against=None,
item_row=None, voucher_detail_no=None, sle=None):
if not return_against: if not return_against:
return_against = frappe.get_cached_value(voucher_type, voucher_no, "return_against") return_against = frappe.get_cached_value(voucher_type, voucher_no, "return_against")
if not return_against and voucher_type == 'Sales Invoice' and sle:
return get_incoming_rate({
"item_code": sle.item_code,
"warehouse": sle.warehouse,
"posting_date": sle.get('posting_date'),
"posting_time": sle.get('posting_time'),
"qty": sle.actual_qty,
"serial_no": sle.get('serial_no'),
"company": sle.company,
"voucher_type": sle.voucher_type,
"voucher_no": sle.voucher_no
}, raise_error_if_no_rate=False)
return_against_item_field = get_return_against_item_fields(voucher_type) return_against_item_field = get_return_against_item_fields(voucher_type)
filters = get_filters(voucher_type, voucher_no, voucher_detail_no, filters = get_filters(voucher_type, voucher_no, voucher_detail_no,

View File

@ -311,14 +311,16 @@ class SellingController(StockController):
items = self.get("items") + (self.get("packed_items") or []) items = self.get("items") + (self.get("packed_items") or [])
for d in items: for d in items:
if not cint(self.get("is_return")): if not self.get("return_against"):
# Get incoming rate based on original item cost based on valuation method # Get incoming rate based on original item cost based on valuation method
qty = flt(d.get('stock_qty') or d.get('actual_qty'))
d.incoming_rate = get_incoming_rate({ d.incoming_rate = get_incoming_rate({
"item_code": d.item_code, "item_code": d.item_code,
"warehouse": d.warehouse, "warehouse": d.warehouse,
"posting_date": self.get('posting_date') or self.get('transaction_date'), "posting_date": self.get('posting_date') or self.get('transaction_date'),
"posting_time": self.get('posting_time') or nowtime(), "posting_time": self.get('posting_time') or nowtime(),
"qty": -1 * flt(d.get('stock_qty') or d.get('actual_qty')), "qty": qty if cint(self.get("is_return")) else (-1 * qty),
"serial_no": d.get('serial_no'), "serial_no": d.get('serial_no'),
"company": self.company, "company": self.company,
"voucher_type": self.doctype, "voucher_type": self.doctype,

View File

@ -113,10 +113,12 @@ class calculate_taxes_and_totals(object):
item.rate_with_margin, item.base_rate_with_margin = self.calculate_margin(item) item.rate_with_margin, item.base_rate_with_margin = self.calculate_margin(item)
if flt(item.rate_with_margin) > 0: if flt(item.rate_with_margin) > 0:
item.rate = flt(item.rate_with_margin * (1.0 - (item.discount_percentage / 100.0)), item.precision("rate")) item.rate = flt(item.rate_with_margin * (1.0 - (item.discount_percentage / 100.0)), item.precision("rate"))
if item.discount_amount and not item.discount_percentage: if item.discount_amount and not item.discount_percentage:
item.rate -= item.discount_amount item.rate = item.rate_with_margin - item.discount_amount
else: else:
item.discount_amount = item.rate_with_margin - item.rate item.discount_amount = item.rate_with_margin - item.rate
elif flt(item.price_list_rate) > 0: elif flt(item.price_list_rate) > 0:
item.discount_amount = item.price_list_rate - item.rate item.discount_amount = item.price_list_rate - item.rate
elif flt(item.price_list_rate) > 0 and not item.discount_amount: elif flt(item.price_list_rate) > 0 and not item.discount_amount:
@ -289,10 +291,13 @@ class calculate_taxes_and_totals(object):
# set precision in the last item iteration # set precision in the last item iteration
if n == len(self.doc.get("items")) - 1: if n == len(self.doc.get("items")) - 1:
self.round_off_totals(tax) self.round_off_totals(tax)
self._set_in_company_currency(tax,
["tax_amount", "tax_amount_after_discount_amount"])
self.round_off_base_values(tax)
self.set_cumulative_total(i, tax) self.set_cumulative_total(i, tax)
self._set_in_company_currency(tax, self._set_in_company_currency(tax, ["total"])
["total", "tax_amount", "tax_amount_after_discount_amount"])
# adjust Discount Amount loss in last tax iteration # adjust Discount Amount loss in last tax iteration
if i == (len(self.doc.get("taxes")) - 1) and self.discount_amount_applied \ if i == (len(self.doc.get("taxes")) - 1) and self.discount_amount_applied \
@ -339,20 +344,11 @@ class calculate_taxes_and_totals(object):
elif tax.charge_type == "On Item Quantity": elif tax.charge_type == "On Item Quantity":
current_tax_amount = tax_rate * item.qty current_tax_amount = tax_rate * item.qty
current_tax_amount = self.get_final_current_tax_amount(tax, current_tax_amount)
if not self.doc.get("is_consolidated"): if not self.doc.get("is_consolidated"):
self.set_item_wise_tax(item, tax, tax_rate, current_tax_amount) self.set_item_wise_tax(item, tax, tax_rate, current_tax_amount)
return current_tax_amount return current_tax_amount
def get_final_current_tax_amount(self, tax, current_tax_amount):
# Some countries need individual tax components to be rounded
# Handeled via regional doctypess
if tax.account_head in frappe.flags.round_off_applicable_accounts:
current_tax_amount = round(current_tax_amount, 0)
return current_tax_amount
def set_item_wise_tax(self, item, tax, tax_rate, current_tax_amount): def set_item_wise_tax(self, item, tax, tax_rate, current_tax_amount):
# store tax breakup for each item # store tax breakup for each item
key = item.item_code or item.item_name key = item.item_code or item.item_name
@ -363,10 +359,20 @@ class calculate_taxes_and_totals(object):
tax.item_wise_tax_detail[key] = [tax_rate,flt(item_wise_tax_amount)] tax.item_wise_tax_detail[key] = [tax_rate,flt(item_wise_tax_amount)]
def round_off_totals(self, tax): def round_off_totals(self, tax):
if tax.account_head in frappe.flags.round_off_applicable_accounts:
tax.tax_amount = round(tax.tax_amount, 0)
tax.tax_amount_after_discount_amount = round(tax.tax_amount_after_discount_amount, 0)
tax.tax_amount = flt(tax.tax_amount, tax.precision("tax_amount")) tax.tax_amount = flt(tax.tax_amount, tax.precision("tax_amount"))
tax.tax_amount_after_discount_amount = flt(tax.tax_amount_after_discount_amount, tax.tax_amount_after_discount_amount = flt(tax.tax_amount_after_discount_amount,
tax.precision("tax_amount")) tax.precision("tax_amount"))
def round_off_base_values(self, tax):
# Round off to nearest integer based on regional settings
if tax.account_head in frappe.flags.round_off_applicable_accounts:
tax.base_tax_amount = round(tax.base_tax_amount, 0)
tax.base_tax_amount_after_discount_amount = round(tax.base_tax_amount_after_discount_amount, 0)
def manipulate_grand_total_for_inclusive_tax(self): def manipulate_grand_total_for_inclusive_tax(self):
# if fully inclusive taxes and diff # if fully inclusive taxes and diff
if self.doc.get("taxes") and any([cint(t.included_in_print_rate) for t in self.doc.get("taxes")]): if self.doc.get("taxes") and any([cint(t.included_in_print_rate) for t in self.doc.get("taxes")]):

View File

@ -25,7 +25,7 @@ def get_transaction_list(doctype, txt=None, filters=None, limit_start=0, limit_p
if not filters: filters = [] if not filters: filters = []
if doctype in ['Supplier Quotation', 'Purchase Invoice', 'Quotation']: if doctype in ['Supplier Quotation', 'Purchase Invoice']:
filters.append((doctype, 'docstatus', '<', 2)) filters.append((doctype, 'docstatus', '<', 2))
else: else:
filters.append((doctype, 'docstatus', '=', 1)) filters.append((doctype, 'docstatus', '=', 1))

View File

@ -22,7 +22,7 @@ class ShopifySettings(unittest.TestCase):
frappe.db.set_value('Stock Settings', None, 'allow_negative_stock', 1) frappe.db.set_value('Stock Settings', None, 'allow_negative_stock', 1)
# use the fixture data # use the fixture data
import_doc(frappe.get_app_path("erpnext", "erpnext_integrations/doctype/shopify_settings/test_data/custom_field.json")) import_doc(path=frappe.get_app_path("erpnext", "erpnext_integrations/doctype/shopify_settings/test_data/custom_field.json"))
frappe.reload_doctype("Customer") frappe.reload_doctype("Customer")
frappe.reload_doctype("Sales Order") frappe.reload_doctype("Sales Order")

View File

@ -307,6 +307,8 @@ auto_cancel_exempted_doctypes= [
"Inpatient Medication Entry" "Inpatient Medication Entry"
] ]
after_migrate = ["erpnext.setup.install.update_select_perm_after_install"]
scheduler_events = { scheduler_events = {
"cron": { "cron": {
"0/30 * * * *": [ "0/30 * * * *": [

View File

@ -35,7 +35,8 @@ class Attendance(Document):
and docstatus != 2 and docstatus != 2
""", (self.employee, getdate(self.attendance_date), self.name)) """, (self.employee, getdate(self.attendance_date), self.name))
if res: if res:
frappe.throw(_("Attendance for employee {0} is already marked").format(self.employee)) frappe.throw(_("Attendance for employee {0} is already marked for the date {1}").format(
frappe.bold(self.employee), frappe.bold(self.attendance_date)))
def check_leave_record(self): def check_leave_record(self):
leave_record = frappe.db.sql(""" leave_record = frappe.db.sql("""

View File

@ -200,7 +200,7 @@
], ],
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2021-03-31 14:42:47.321368", "modified": "2021-03-31 22:31:53.746659",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "HR", "module": "HR",
"name": "Employee Advance", "name": "Employee Advance",

View File

@ -154,7 +154,7 @@
], ],
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2021-03-31 14:45:27.948207", "modified": "2021-03-31 22:32:55.492327",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "HR", "module": "HR",
"name": "Leave Encashment", "name": "Leave Encashment",

View File

@ -433,6 +433,7 @@ def make_material_request(source_name, target_doc=None):
def make_stock_entry(source_name, target_doc=None): def make_stock_entry(source_name, target_doc=None):
def update_item(obj, target, source_parent): def update_item(obj, target, source_parent):
target.t_warehouse = source_parent.wip_warehouse target.t_warehouse = source_parent.wip_warehouse
target.conversion_factor = 1
def set_missing_values(source, target): def set_missing_values(source, target):
target.purpose = "Material Transfer for Manufacture" target.purpose = "Material Transfer for Manufacture"

View File

@ -19,7 +19,7 @@
"documentation_url": "https://docs.erpnext.com/docs/user/manual/en/manufacturing", "documentation_url": "https://docs.erpnext.com/docs/user/manual/en/manufacturing",
"idx": 0, "idx": 0,
"is_complete": 0, "is_complete": 0,
"modified": "2020-07-08 14:05:56.197563", "modified": "2020-06-29 20:25:36.899106",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Manufacturing", "module": "Manufacturing",
"name": "Manufacturing", "name": "Manufacturing",

View File

@ -769,4 +769,6 @@ erpnext.patches.v13_0.rename_discharge_date_in_ip_record
erpnext.patches.v12_0.create_taxable_value_field erpnext.patches.v12_0.create_taxable_value_field
erpnext.patches.v12_0.add_gst_category_in_delivery_note erpnext.patches.v12_0.add_gst_category_in_delivery_note
erpnext.patches.v12_0.purchase_receipt_status erpnext.patches.v12_0.purchase_receipt_status
erpnext.patches.v13_0.fix_non_unique_represents_company
erpnext.patches.v12_0.add_document_type_field_for_italy_einvoicing erpnext.patches.v12_0.add_document_type_field_for_italy_einvoicing
erpnext.patches.v13_0.make_non_standard_user_type #13-04-2021

View File

@ -12,5 +12,5 @@ def execute():
select dl.link_name from `tabAddress` a, `tabDynamic Link` dl select dl.link_name from `tabAddress` a, `tabDynamic Link` dl
where a.gstin = %s and dl.parent = a.name and dl.link_doctype = 'Company' where a.gstin = %s and dl.parent = a.name and dl.link_doctype = 'Company'
""", (creds.get('gstin'))) """, (creds.get('gstin')))
if company_name and len(company_name) == 1: if company_name and len(company_name) > 0:
frappe.db.set_value('E Invoice User', creds.get('name'), 'company', company_name[0][0]) frappe.db.set_value('E Invoice User', creds.get('name'), 'company', company_name[0][0])

View File

@ -1,6 +1,7 @@
import frappe import frappe
def execute(): def execute():
frappe.reload_doc('custom', 'doctype', 'custom_field')
company = frappe.get_all('Company', filters = {'country': 'India'}) company = frappe.get_all('Company', filters = {'country': 'India'})
if not company: if not company:
return return

View File

@ -8,36 +8,39 @@ from erpnext.regional.india.setup import setup
def execute(): def execute():
doctypes = ['salary_component', doctypes = ['salary_component',
'Employee Tax Exemption Declaration', 'Employee Tax Exemption Declaration',
'Employee Tax Exemption Proof Submission', 'Employee Tax Exemption Proof Submission',
'Employee Tax Exemption Declaration Category', 'Employee Tax Exemption Declaration Category',
'Employee Tax Exemption Proof Submission Detail' 'Employee Tax Exemption Proof Submission Detail',
] 'gratuity_rule',
'gratuity_rule_slab',
'gratuity_applicable_component'
]
for doctype in doctypes: for doctype in doctypes:
frappe.reload_doc('Payroll', 'doctype', doctype) frappe.reload_doc('Payroll', 'doctype', doctype)
reports = ['Professional Tax Deductions', 'Provident Fund Deductions'] reports = ['Professional Tax Deductions', 'Provident Fund Deductions']
for report in reports: for report in reports:
frappe.reload_doc('Regional', 'Report', report) frappe.reload_doc('Regional', 'Report', report)
frappe.reload_doc('Regional', 'Report', report) frappe.reload_doc('Regional', 'Report', report)
if erpnext.get_region() == "India": if erpnext.get_region() == "India":
setup(patch=True) setup(patch=True)
if frappe.db.exists("Salary Component", "Income Tax"): if frappe.db.exists("Salary Component", "Income Tax"):
frappe.db.set_value("Salary Component", "Income Tax", "is_income_tax_component", 1) frappe.db.set_value("Salary Component", "Income Tax", "is_income_tax_component", 1)
if frappe.db.exists("Salary Component", "TDS"): if frappe.db.exists("Salary Component", "TDS"):
frappe.db.set_value("Salary Component", "TDS", "is_income_tax_component", 1) frappe.db.set_value("Salary Component", "TDS", "is_income_tax_component", 1)
components = frappe.db.sql("select name from `tabSalary Component` where variable_based_on_taxable_salary = 1", as_dict=1) components = frappe.db.sql("select name from `tabSalary Component` where variable_based_on_taxable_salary = 1", as_dict=1)
for component in components: for component in components:
frappe.db.set_value("Salary Component", component.name, "is_income_tax_component", 1) frappe.db.set_value("Salary Component", component.name, "is_income_tax_component", 1)
if erpnext.get_region() == "India": if erpnext.get_region() == "India":
if frappe.db.exists("Salary Component", "Provident Fund"): if frappe.db.exists("Salary Component", "Provident Fund"):
frappe.db.set_value("Salary Component", "Provident Fund", "component_type", "Provident Fund") frappe.db.set_value("Salary Component", "Provident Fund", "component_type", "Provident Fund")
if frappe.db.exists("Salary Component", "Professional Tax"): if frappe.db.exists("Salary Component", "Professional Tax"):
frappe.db.set_value("Salary Component", "Professional Tax", "component_type", "Professional Tax") frappe.db.set_value("Salary Component", "Professional Tax", "component_type", "Professional Tax")

View File

@ -11,4 +11,8 @@ def execute():
if not company: if not company:
return return
frappe.reload_doc('accounts', 'doctype', 'pos_invoice')
frappe.reload_doc('accounts', 'doctype', 'pos_invoice_item')
make_custom_fields() make_custom_fields()

View File

@ -0,0 +1,8 @@
import frappe
def execute():
frappe.db.sql("""
update tabCustomer
set represents_company = NULL
where represents_company = ''
""")

View File

@ -0,0 +1,24 @@
# Copyright (c) 2019, Frappe and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
from six import iteritems
from erpnext.setup.install import add_non_standard_user_types
def execute():
doctype_dict = {
'projects': ['Timesheet'],
'payroll': ['Salary Slip', 'Employee Tax Exemption Declaration', 'Employee Tax Exemption Proof Submission'],
'hr': ['Employee', 'Expense Claim', 'Leave Application', 'Attendance Request', 'Compensatory Leave Request']
}
for module, doctypes in iteritems(doctype_dict):
for doctype in doctypes:
frappe.reload_doc(module, 'doctype', doctype)
frappe.flags.ignore_select_perm = True
frappe.flags.update_select_perm_after_migrate = True
add_non_standard_user_types()

View File

@ -6,8 +6,8 @@ def execute():
if "Healthcare" not in frappe.get_active_domains(): if "Healthcare" not in frappe.get_active_domains():
return return
frappe.reload_doc("healthcare", "doctype", "Therapy Session")
frappe.reload_doc("healthcare", "doctype", "Inpatient Medication Order") frappe.reload_doc("healthcare", "doctype", "Inpatient Medication Order")
frappe.reload_doc("healthcare", "doctype", "Therapy Session")
frappe.reload_doc("healthcare", "doctype", "Clinical Procedure") frappe.reload_doc("healthcare", "doctype", "Clinical Procedure")
frappe.reload_doc("healthcare", "doctype", "Patient History Settings") frappe.reload_doc("healthcare", "doctype", "Patient History Settings")
frappe.reload_doc("healthcare", "doctype", "Patient History Standard Document Type") frappe.reload_doc("healthcare", "doctype", "Patient History Standard Document Type")

View File

@ -2,11 +2,15 @@
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
import frappe import frappe
from erpnext.regional.united_arab_emirates.setup import setup from erpnext.regional.united_arab_emirates.setup import setup
def execute(): def execute():
company = frappe.get_all('Company', filters = {'country': 'United Arab Emirates'}) company = frappe.get_all('Company', filters = {'country': 'United Arab Emirates'})
if not company: if not company:
return return
frappe.reload_doc('regional', 'report', 'uae_vat_201')
frappe.reload_doc('regional', 'doctype', 'uae_vat_settings')
frappe.reload_doc('regional', 'doctype', 'uae_vat_account')
setup() setup()

View File

@ -175,7 +175,7 @@
], ],
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2021-03-31 14:45:48.566756", "modified": "2021-03-31 22:33:59.098532",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Payroll", "module": "Payroll",
"name": "Additional Salary", "name": "Additional Salary",

View File

@ -147,7 +147,7 @@
], ],
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2021-03-31 14:46:22.465521", "modified": "2021-03-31 22:35:08.940087",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Payroll", "module": "Payroll",
"name": "Employee Benefit Application", "name": "Employee Benefit Application",

View File

@ -144,7 +144,7 @@
], ],
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2021-03-31 15:51:51.489269", "modified": "2021-03-31 22:37:21.024625",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Payroll", "module": "Payroll",
"name": "Employee Benefit Claim", "name": "Employee Benefit Claim",

View File

@ -94,7 +94,7 @@
], ],
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2021-03-31 14:48:00.919839", "modified": "2021-03-31 22:38:20.332316",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Payroll", "module": "Payroll",
"name": "Employee Incentive", "name": "Employee Incentive",

View File

@ -119,7 +119,7 @@
], ],
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2021-03-31 20:41:57.387749", "modified": "2021-03-31 22:39:59.237361",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Payroll", "module": "Payroll",
"name": "Employee Tax Exemption Declaration", "name": "Employee Tax Exemption Declaration",

View File

@ -142,7 +142,7 @@
], ],
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2021-03-31 20:48:32.639885", "modified": "2021-03-31 22:41:13.723339",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Payroll", "module": "Payroll",
"name": "Employee Tax Exemption Proof Submission", "name": "Employee Tax Exemption Proof Submission",

View File

@ -104,7 +104,7 @@
], ],
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2021-03-31 20:53:33.323712", "modified": "2021-03-31 22:42:08.139520",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Payroll", "module": "Payroll",
"name": "Income Tax Slab", "name": "Income Tax Slab",

View File

@ -567,6 +567,7 @@ def create_salary_slips_for_employees(employees, args, publish_progress=True):
if publish_progress: if publish_progress:
frappe.publish_progress(count*100/len(set(employees) - set(salary_slips_exists_for)), frappe.publish_progress(count*100/len(set(employees) - set(salary_slips_exists_for)),
title = _("Creating Salary Slips...")) title = _("Creating Salary Slips..."))
else: else:
salary_slips_not_created.append(emp) salary_slips_not_created.append(emp)

View File

@ -105,7 +105,7 @@
], ],
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2021-03-31 14:50:29.401020", "modified": "2021-03-31 22:43:28.363644",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Payroll", "module": "Payroll",
"name": "Retention Bonus", "name": "Retention Bonus",

View File

@ -119,6 +119,7 @@ frappe.ui.form.on("Salary Slip", {
frm.set_df_property('exchange_rate', 'hidden', 1); frm.set_df_property('exchange_rate', 'hidden', 1);
frm.set_df_property("exchange_rate", "description", "" ); frm.set_df_property("exchange_rate", "description", "" );
} }
}
} }
}, },

View File

@ -631,7 +631,7 @@
"idx": 9, "idx": 9,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2021-03-31 15:39:28.817166", "modified": "2021-03-31 22:44:09.772331",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Payroll", "module": "Payroll",
"name": "Salary Slip", "name": "Salary Slip",

View File

@ -598,10 +598,10 @@ class SalarySlip(TransactionBase):
continue continue
if ( if (
not d.additional_salary (not d.additional_salary
and (not additional_salary or additional_salary.overwrite) and (not additional_salary or additional_salary.overwrite))
or additional_salary or (additional_salary
and additional_salary.name == d.additional_salary and additional_salary.name == d.additional_salary)
): ):
component_row = d component_row = d
break break
@ -611,7 +611,7 @@ class SalarySlip(TransactionBase):
self.set(component_type, [ self.set(component_type, [
d for d in self.get(component_type) d for d in self.get(component_type)
if d.salary_component != component_data.salary_component if d.salary_component != component_data.salary_component
or d.additional_salary and additional_salary.name != d.additional_salary or (d.additional_salary and additional_salary.name != d.additional_salary)
or d == component_row or d == component_row
]) ])
@ -633,8 +633,6 @@ class SalarySlip(TransactionBase):
if additional_salary: if additional_salary:
component_row.default_amount = 0 component_row.default_amount = 0
component_row.additional_amount = amount
component_row.additional_salary = additional_salary.name
component_row.deduct_full_tax_on_selected_payroll_date = \ component_row.deduct_full_tax_on_selected_payroll_date = \
additional_salary.deduct_full_tax_on_selected_payroll_date additional_salary.deduct_full_tax_on_selected_payroll_date
else: else:

View File

@ -312,7 +312,7 @@ class TestSalarySlip(unittest.TestCase):
frappe.db.sql("DELETE FROM `tabSalary Slip` where employee_name = 'test_ytd@salary.com'") frappe.db.sql("DELETE FROM `tabSalary Slip` where employee_name = 'test_ytd@salary.com'")
create_salary_slips_for_payroll_period(applicant, salary_structure.name, create_salary_slips_for_payroll_period(applicant, salary_structure.name,
payroll_period, deduct_random=False) payroll_period, deduct_random=False, num=6)
salary_slips = frappe.get_all('Salary Slip', fields=['year_to_date', 'net_pay'], filters={'employee_name': salary_slips = frappe.get_all('Salary Slip', fields=['year_to_date', 'net_pay'], filters={'employee_name':
'test_ytd@salary.com'}, order_by = 'posting_date') 'test_ytd@salary.com'}, order_by = 'posting_date')

View File

@ -164,7 +164,13 @@ def create_salary_structure_assignment(employee, salary_structure, from_date=Non
salary_structure_assignment.employee = employee salary_structure_assignment.employee = employee
salary_structure_assignment.base = 50000 salary_structure_assignment.base = 50000
salary_structure_assignment.variable = 5000 salary_structure_assignment.variable = 5000
salary_structure_assignment.from_date = from_date or add_days(nowdate(), -1)
if getdate(nowdate()).day == 1:
date = from_date or nowdate()
else:
date = from_date or add_days(nowdate(), -1)
salary_structure_assignment.from_date = date
salary_structure_assignment.salary_structure = salary_structure salary_structure_assignment.salary_structure = salary_structure
salary_structure_assignment.currency = currency salary_structure_assignment.currency = currency
salary_structure_assignment.payroll_payable_account = get_payable_account(company) salary_structure_assignment.payroll_payable_account = get_payable_account(company)

View File

@ -145,7 +145,7 @@
], ],
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2021-03-31 15:49:36.361253", "modified": "2021-03-31 22:44:46.267974",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Payroll", "module": "Payroll",
"name": "Salary Structure Assignment", "name": "Salary Structure Assignment",

View File

@ -8,7 +8,7 @@
"is_mandatory": 1, "is_mandatory": 1,
"is_single": 0, "is_single": 0,
"is_skipped": 0, "is_skipped": 0,
"modified": "2020-06-01 11:53:54.553947", "modified": "2020-06-29 11:53:54.553947",
"modified_by": "Administrator", "modified_by": "Administrator",
"name": "Create Payroll Period", "name": "Create Payroll Period",
"owner": "Administrator", "owner": "Administrator",

View File

@ -1,19 +1,19 @@
{ {
"action": "Go to Page", "action": "Update Settings",
"creation": "2020-06-04 16:34:29.664917", "creation": "2020-06-04 16:34:29.664917",
"docstatus": 0, "docstatus": 0,
"doctype": "Onboarding Step", "doctype": "Onboarding Step",
"idx": 0, "idx": 0,
"is_complete": 0, "is_complete": 0,
"is_mandatory": 0, "is_mandatory": 0,
"is_single": 0, "is_single": 1,
"is_skipped": 0, "is_skipped": 0,
"modified": "2020-06-04 16:34:29.664917", "modified": "2020-06-29 16:34:29.664917",
"modified_by": "Administrator", "modified_by": "Administrator",
"name": "Payroll Settings", "name": "Payroll Settings",
"owner": "Administrator", "owner": "Administrator",
"path": "#Form/Payroll Settings", "reference_document": "Payroll Settings",
"show_full_form": 0, "show_full_form": 0,
"title": "Payroll Settings", "title": "Payroll Settings",
"validate_action": 1 "validate_action": 0
} }

View File

@ -323,12 +323,15 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
// set precision in the last item iteration // set precision in the last item iteration
if (n == me.frm.doc["items"].length - 1) { if (n == me.frm.doc["items"].length - 1) {
me.round_off_totals(tax); me.round_off_totals(tax);
me.set_in_company_currency(tax,
["tax_amount", "tax_amount_after_discount_amount"]);
me.round_off_base_values(tax);
// in tax.total, accumulate grand total for each item // in tax.total, accumulate grand total for each item
me.set_cumulative_total(i, tax); me.set_cumulative_total(i, tax);
me.set_in_company_currency(tax, me.set_in_company_currency(tax, ["total"]);
["total", "tax_amount", "tax_amount_after_discount_amount"]);
// adjust Discount Amount loss in last tax iteration // adjust Discount Amount loss in last tax iteration
if ((i == me.frm.doc["taxes"].length - 1) && me.discount_amount_applied if ((i == me.frm.doc["taxes"].length - 1) && me.discount_amount_applied
@ -393,20 +396,11 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
current_tax_amount = tax_rate * item.qty; current_tax_amount = tax_rate * item.qty;
} }
current_tax_amount = this.get_final_tax_amount(tax, current_tax_amount);
this.set_item_wise_tax(item, tax, tax_rate, current_tax_amount); this.set_item_wise_tax(item, tax, tax_rate, current_tax_amount);
return current_tax_amount; return current_tax_amount;
}, },
get_final_tax_amount: function(tax, current_tax_amount) {
if (frappe.flags.round_off_applicable_accounts.includes(tax.account_head)) {
current_tax_amount = Math.round(current_tax_amount);
}
return current_tax_amount;
},
set_item_wise_tax: function(item, tax, tax_rate, current_tax_amount) { set_item_wise_tax: function(item, tax, tax_rate, current_tax_amount) {
// store tax breakup for each item // store tax breakup for each item
let tax_detail = tax.item_wise_tax_detail; let tax_detail = tax.item_wise_tax_detail;
@ -420,10 +414,22 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
}, },
round_off_totals: function(tax) { round_off_totals: function(tax) {
if (frappe.flags.round_off_applicable_accounts.includes(tax.account_head)) {
tax.tax_amount= Math.round(tax.tax_amount);
tax.tax_amount_after_discount_amount = Math.round(tax.tax_amount_after_discount_amount);
}
tax.tax_amount = flt(tax.tax_amount, precision("tax_amount", tax)); tax.tax_amount = flt(tax.tax_amount, precision("tax_amount", tax));
tax.tax_amount_after_discount_amount = flt(tax.tax_amount_after_discount_amount, precision("tax_amount", tax)); tax.tax_amount_after_discount_amount = flt(tax.tax_amount_after_discount_amount, precision("tax_amount", tax));
}, },
round_off_base_values: function(tax) {
if (frappe.flags.round_off_applicable_accounts.includes(tax.account_head)) {
tax.base_tax_amount= Math.round(tax.base_tax_amount);
tax.base_tax_amount_after_discount_amount = Math.round(tax.base_tax_amount_after_discount_amount);
}
},
manipulate_grand_total_for_inclusive_tax: function() { manipulate_grand_total_for_inclusive_tax: function() {
var me = this; var me = this;
// if fully inclusive taxes and diff // if fully inclusive taxes and diff

View File

@ -0,0 +1,14 @@
// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt
frappe.ui.form.on('Website Theme', {
validate(frm) {
let theme_scss = frm.doc.theme_scss;
if (theme_scss && theme_scss.includes('frappe/public/scss/website')
&& !theme_scss.includes('erpnext/public/scss/website')
) {
frm.set_value('theme_scss',
`${frm.doc.theme_scss}\n@import "erpnext/public/scss/website";`);
}
}
});

View File

@ -3,4 +3,17 @@ import frappe
def setup(company=None, patch=True): def setup(company=None, patch=True):
pass add_custom_roles_for_reports()
def add_custom_roles_for_reports():
"""Add Access Control to UAE VAT 201."""
if not frappe.db.get_value('Custom Role', dict(report='DATEV')):
frappe.get_doc(dict(
doctype='Custom Role',
report='DATEV',
roles= [
dict(role='Accounts User'),
dict(role='Accounts Manager')
]
)).insert()

View File

@ -466,21 +466,24 @@ def make_einvoice(invoice):
try: try:
einvoice = safe_json_load(einvoice) einvoice = safe_json_load(einvoice)
einvoice = santize_einvoice_fields(einvoice) einvoice = santize_einvoice_fields(einvoice)
validate_totals(einvoice)
except Exception: except Exception:
log_error(einvoice) show_link_to_error_log(invoice, einvoice)
link_to_error_list = '<a href="List/Error Log/List?method=E Invoice Request Failed">Error Log</a>'
frappe.throw( validate_totals(einvoice)
_('An error occurred while creating e-invoice for {}. Please check {} for more information.').format(
invoice.name, link_to_error_list),
title=_('E Invoice Creation Failed')
)
return einvoice return einvoice
def show_link_to_error_log(invoice, einvoice):
err_log = log_error(einvoice)
link_to_error_log = get_link_to_form('Error Log', err_log.name, 'Error Log')
frappe.throw(
_('An error occurred while creating e-invoice for {}. Please check {} for more information.').format(
invoice.name, link_to_error_log),
title=_('E Invoice Creation Failed')
)
def log_error(data=None): def log_error(data=None):
if not isinstance(data, dict): if isinstance(data, six.string_types):
data = json.loads(data) data = json.loads(data)
seperator = "--" * 50 seperator = "--" * 50
@ -587,7 +590,7 @@ class GSPConnector():
self.credentials = self.e_invoice_settings.credentials[0] if self.e_invoice_settings.credentials else None self.credentials = self.e_invoice_settings.credentials[0] if self.e_invoice_settings.credentials else None
def get_seller_gstin(self): def get_seller_gstin(self):
gstin = self.invoice.company_gstin or frappe.db.get_value('Address', self.invoice.company_address, 'gstin') gstin = frappe.db.get_value('Address', self.invoice.company_address, 'gstin')
if not gstin: if not gstin:
frappe.throw(_('Cannot retrieve Company GSTIN. Please select company address with valid GSTIN.')) frappe.throw(_('Cannot retrieve Company GSTIN. Please select company address with valid GSTIN.'))
return gstin return gstin
@ -666,7 +669,6 @@ class GSPConnector():
except Exception: except Exception:
log_error() log_error()
self.raise_error(True) self.raise_error(True)
@staticmethod @staticmethod
def get_gstin_details(gstin): def get_gstin_details(gstin):
'''fetch and cache GSTIN details''' '''fetch and cache GSTIN details'''
@ -959,7 +961,6 @@ class GSPConnector():
'label': _('IRN Generated') 'label': _('IRN Generated')
} }
self.update_invoice() self.update_invoice()
def attach_qrcode_image(self): def attach_qrcode_image(self):
qrcode = self.invoice.signed_qr_code qrcode = self.invoice.signed_qr_code
doctype = self.invoice.doctype doctype = self.invoice.doctype

View File

@ -12,14 +12,14 @@ from erpnext.accounts.utils import get_fiscal_year, FiscalYearError
from frappe.utils import today from frappe.utils import today
def setup(company=None, patch=True): def setup(company=None, patch=True):
setup_company_independent_fixtures() setup_company_independent_fixtures(patch=patch)
if not patch: if not patch:
make_fixtures(company) make_fixtures(company)
# TODO: for all countries # TODO: for all countries
def setup_company_independent_fixtures(): def setup_company_independent_fixtures(patch=False):
make_custom_fields() make_custom_fields()
make_property_setters() make_property_setters(patch=patch)
add_permissions() add_permissions()
add_custom_roles_for_reports() add_custom_roles_for_reports()
frappe.enqueue('erpnext.regional.india.setup.add_hsn_sac_codes', now=frappe.flags.in_test) frappe.enqueue('erpnext.regional.india.setup.add_hsn_sac_codes', now=frappe.flags.in_test)
@ -112,10 +112,11 @@ def add_print_formats():
frappe.db.set_value("Print Format", "GST Tax Invoice", "disabled", 0) frappe.db.set_value("Print Format", "GST Tax Invoice", "disabled", 0)
frappe.db.set_value("Print Format", "GST E-Invoice", "disabled", 0) frappe.db.set_value("Print Format", "GST E-Invoice", "disabled", 0)
def make_property_setters(): def make_property_setters(patch=False):
# GST rules do not allow for an invoice no. bigger than 16 characters # GST rules do not allow for an invoice no. bigger than 16 characters
make_property_setter('Sales Invoice', 'naming_series', 'options', 'SINV-.YY.-\nSRET-.YY.-', '') if not patch:
make_property_setter('Purchase Invoice', 'naming_series', 'options', 'PINV-.YY.-\nPRET-.YY.-', '') make_property_setter('Sales Invoice', 'naming_series', 'options', 'SINV-.YY.-\nSRET-.YY.-', '')
make_property_setter('Purchase Invoice', 'naming_series', 'options', 'PINV-.YY.-\nPRET-.YY.-', '')
def make_custom_fields(update=True): def make_custom_fields(update=True):
hsn_sac_field = dict(fieldname='gst_hsn_code', label='HSN/SAC', hsn_sac_field = dict(fieldname='gst_hsn_code', label='HSN/SAC',

View File

@ -12,14 +12,14 @@ class TestIndiaUtils(unittest.TestCase):
mock_get_cached.return_value = "India" # mock country mock_get_cached.return_value = "India" # mock country
posting_date = "2021-05-01" posting_date = "2021-05-01"
invalid_names = [ "SI$1231", "012345678901234567", "SI 2020 05", invalid_names = ["SI$1231", "012345678901234567", "SI 2020 05",
"SI.2020.0001", "PI2021 - 001" ] "SI.2020.0001", "PI2021 - 001"]
for name in invalid_names: for name in invalid_names:
doc = frappe._dict(name=name, posting_date=posting_date) doc = frappe._dict(name=name, posting_date=posting_date)
self.assertRaises(frappe.ValidationError, validate_document_name, doc) self.assertRaises(frappe.ValidationError, validate_document_name, doc)
valid_names = [ "012345678901236", "SI/2020/0001", "SI/2020-0001", valid_names = ["012345678901236", "SI/2020/0001", "SI/2020-0001",
"2020-PI-0001", "PI2020-0001" ] "2020-PI-0001", "PI2020-0001"]
for name in valid_names: for name in valid_names:
doc = frappe._dict(name=name, posting_date=posting_date) doc = frappe._dict(name=name, posting_date=posting_date)
try: try:

View File

@ -155,6 +155,7 @@ def set_place_of_supply(doc, method=None):
def validate_document_name(doc, method=None): def validate_document_name(doc, method=None):
"""Validate GST invoice number requirements.""" """Validate GST invoice number requirements."""
country = frappe.get_cached_value("Company", doc.company, "country") country = frappe.get_cached_value("Company", doc.company, "country")
# Date was chosen as start of next FY to avoid irritating current users. # Date was chosen as start of next FY to avoid irritating current users.

View File

@ -1,29 +1,22 @@
{ {
"add_total_row": 0, "add_total_row": 0,
"apply_user_permissions": 0, "columns": [],
"creation": "2019-04-24 08:45:16.650129", "creation": "2019-04-24 08:45:16.650129",
"disabled": 0, "disable_prepared_report": 0,
"icon": "octicon octicon-repo-pull", "disabled": 0,
"color": "#4CB944", "docstatus": 0,
"docstatus": 0, "doctype": "Report",
"doctype": "Report", "filters": [],
"idx": 0, "idx": 0,
"is_standard": "Yes", "is_standard": "Yes",
"module": "Regional", "modified": "2021-04-06 12:23:00.379517",
"name": "DATEV", "modified_by": "Administrator",
"owner": "Administrator", "module": "Regional",
"ref_doctype": "GL Entry", "name": "DATEV",
"report_name": "DATEV", "owner": "Administrator",
"report_type": "Script Report", "prepared_report": 0,
"roles": [ "ref_doctype": "GL Entry",
{ "report_name": "DATEV",
"role": "Accounts User" "report_type": "Script Report",
}, "roles": []
{
"role": "Accounts Manager"
},
{
"role": "Auditor"
}
]
} }

View File

@ -199,7 +199,7 @@ class Gstr1Report(object):
self.item_tax_rate = frappe._dict() self.item_tax_rate = frappe._dict()
items = frappe.db.sql(""" items = frappe.db.sql("""
select item_code, parent, base_net_amount, item_tax_rate select item_code, parent, taxable_value, item_tax_rate
from `tab%s Item` from `tab%s Item`
where parent in (%s) where parent in (%s)
""" % (self.doctype, ', '.join(['%s']*len(self.invoices))), tuple(self.invoices), as_dict=1) """ % (self.doctype, ', '.join(['%s']*len(self.invoices))), tuple(self.invoices), as_dict=1)
@ -207,7 +207,7 @@ class Gstr1Report(object):
for d in items: for d in items:
if d.item_code not in self.invoice_items.get(d.parent, {}): if d.item_code not in self.invoice_items.get(d.parent, {}):
self.invoice_items.setdefault(d.parent, {}).setdefault(d.item_code, self.invoice_items.setdefault(d.parent, {}).setdefault(d.item_code,
sum(i.get('base_net_amount', 0) for i in items sum(i.get('taxable_value', 0) for i in items
if i.item_code == d.item_code and i.parent == d.parent)) if i.item_code == d.item_code and i.parent == d.parent))
item_tax_rate = {} item_tax_rate = {}

View File

@ -212,7 +212,8 @@
"fieldtype": "Link", "fieldtype": "Link",
"ignore_user_permissions": 1, "ignore_user_permissions": 1,
"label": "Represents Company", "label": "Represents Company",
"options": "Company" "options": "Company",
"unique": 1
}, },
{ {
"depends_on": "represents_company", "depends_on": "represents_company",

View File

@ -18,6 +18,8 @@
"dn_required", "dn_required",
"sales_update_frequency", "sales_update_frequency",
"maintain_same_sales_rate", "maintain_same_sales_rate",
"maintain_same_rate_action",
"role_to_override_stop_action",
"editable_price_list_rate", "editable_price_list_rate",
"allow_multiple_items", "allow_multiple_items",
"allow_against_multiple_purchase_orders", "allow_against_multiple_purchase_orders",
@ -133,6 +135,23 @@
"fieldname": "hide_tax_id", "fieldname": "hide_tax_id",
"fieldtype": "Check", "fieldtype": "Check",
"label": "Hide Customer's Tax ID from Sales Transactions" "label": "Hide Customer's Tax ID from Sales Transactions"
},
{
"default": "Stop",
"depends_on": "maintain_same_sales_rate",
"description": "Configure the action to stop the transaction or just warn if the same rate is not maintained.",
"fieldname": "maintain_same_rate_action",
"fieldtype": "Select",
"label": "Action If Same Rate is Not Maintained",
"mandatory_depends_on": "maintain_same_sales_rate",
"options": "Stop\nWarn"
},
{
"depends_on": "eval: doc.maintain_same_rate_action == 'Stop'",
"fieldname": "role_to_override_stop_action",
"fieldtype": "Link",
"label": "Role Allowed to Override Stop Action",
"options": "Role"
} }
], ],
"icon": "fa fa-cog", "icon": "fa fa-cog",
@ -140,7 +159,7 @@
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"issingle": 1, "issingle": 1,
"links": [], "links": [],
"modified": "2021-03-02 17:35:53.603607", "modified": "2021-04-04 20:18:12.814624",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Selling", "module": "Selling",
"name": "Selling Settings", "name": "Selling Settings",

View File

@ -7,7 +7,6 @@ erpnext.PointOfSale.ItemCart = class {
this.allowed_customer_groups = settings.customer_groups; this.allowed_customer_groups = settings.customer_groups;
this.allow_rate_change = settings.allow_rate_change; this.allow_rate_change = settings.allow_rate_change;
this.allow_discount_change = settings.allow_discount_change; this.allow_discount_change = settings.allow_discount_change;
this.init_component(); this.init_component();
} }

View File

@ -201,7 +201,6 @@ erpnext.PointOfSale.ItemDetails = class {
me.events.form_updated(me.doctype, me.name, 'rate', this.value).then(() => { me.events.form_updated(me.doctype, me.name, 'rate', this.value).then(() => {
const item_row = frappe.get_doc(me.doctype, me.name); const item_row = frappe.get_doc(me.doctype, me.name);
const doc = me.events.get_frm().doc; const doc = me.events.get_frm().doc;
me.$item_price.html(format_currency(item_row.rate, doc.currency)); me.$item_price.html(format_currency(item_row.rate, doc.currency));
me.render_discount_dom(item_row); me.render_discount_dom(item_row);
}); });

View File

@ -176,6 +176,14 @@ erpnext.PointOfSale.PastOrderSummary = class {
this.show_summary_placeholder(); this.show_summary_placeholder();
}); });
this.$summary_container.on('click', '.delete-btn', () => {
this.events.delete_order(this.doc.name);
this.show_summary_placeholder();
// this.toggle_component(false);
// this.$component.find('.no-summary-placeholder').removeClass('d-none');
// this.$summary_wrapper.addClass('d-none');
});
this.$summary_container.on('click', '.new-btn', () => { this.$summary_container.on('click', '.new-btn', () => {
this.events.new_order(); this.events.new_order();
this.toggle_component(false); this.toggle_component(false);
@ -196,11 +204,11 @@ erpnext.PointOfSale.PastOrderSummary = class {
print_receipt() { print_receipt() {
const frm = this.events.get_frm(); const frm = this.events.get_frm();
frappe.utils.print( frappe.utils.print(
frm.doctype, this.doc.doctype,
frm.docname, this.doc.name,
frm.pos_print_format, frm.pos_print_format,
frm.doc.letter_head, this.doc.letter_head,
frm.doc.language || frappe.boot.lang this.doc.language || frappe.boot.lang
); );
} }

View File

@ -252,6 +252,41 @@ erpnext.PointOfSale.Payment = class {
} }
} }
setup_listener_for_payments() {
frappe.realtime.on("process_phone_payment", (data) => {
const doc = this.events.get_frm().doc;
const { response, amount, success, failure_message } = data;
let message, title;
if (success) {
title = __("Payment Received");
if (amount >= doc.grand_total) {
frappe.dom.unfreeze();
message = __("Payment of {0} received successfully.", [format_currency(amount, doc.currency, 0)]);
this.events.submit_invoice();
cur_frm.reload_doc();
} else {
message = __("Payment of {0} received successfully. Waiting for other requests to complete...", [format_currency(amount, doc.currency, 0)]);
}
} else if (failure_message) {
message = failure_message;
title = __("Payment Failed");
}
frappe.msgprint({ "message": message, "title": title });
});
}
auto_set_remaining_amount() {
const doc = this.events.get_frm().doc;
const remaining_amount = doc.grand_total - doc.paid_amount;
const current_value = this.selected_mode ? this.selected_mode.get_value() : undefined;
if (!current_value && remaining_amount > 0 && this.selected_mode) {
this.selected_mode.set_value(remaining_amount);
}
}
attach_shortcuts() { attach_shortcuts() {
const ctrl_label = frappe.utils.is_mac() ? '⌘' : 'Ctrl'; const ctrl_label = frappe.utils.is_mac() ? '⌘' : 'Ctrl';
this.$component.find('.submit-order-btn').attr("title", `${ctrl_label}+Enter`); this.$component.find('.submit-order-btn').attr("title", `${ctrl_label}+Enter`);

View File

@ -15,7 +15,7 @@ def delete_company_transactions(company_name):
frappe.only_for("System Manager") frappe.only_for("System Manager")
doc = frappe.get_doc("Company", company_name) doc = frappe.get_doc("Company", company_name)
if frappe.session.user != doc.owner: if frappe.session.user != doc.owner and frappe.session.user != 'Administrator':
frappe.throw(_("Transactions can only be deleted by the creator of the Company"), frappe.throw(_("Transactions can only be deleted by the creator of the Company"),
frappe.PermissionError) frappe.PermissionError)

View File

@ -8,9 +8,11 @@ from erpnext.accounts.doctype.cash_flow_mapper.default_cash_flow_mapper import D
from .default_success_action import get_default_success_action from .default_success_action import get_default_success_action
from frappe import _ from frappe import _
from frappe.utils import cint from frappe.utils import cint
from frappe.installer import update_site_config
from frappe.desk.page.setup_wizard.setup_wizard import add_all_roles_to from frappe.desk.page.setup_wizard.setup_wizard import add_all_roles_to
from frappe.custom.doctype.custom_field.custom_field import create_custom_field from frappe.custom.doctype.custom_field.custom_field import create_custom_field
from erpnext.setup.default_energy_point_rules import get_default_energy_point_rules from erpnext.setup.default_energy_point_rules import get_default_energy_point_rules
from six import iteritems
default_mail_footer = """<div style="padding: 7px; text-align: right; color: #888"><small>Sent via default_mail_footer = """<div style="padding: 7px; text-align: right; color: #888"><small>Sent via
<a style="color: #888" href="http://erpnext.org">ERPNext</a></div>""" <a style="color: #888" href="http://erpnext.org">ERPNext</a></div>"""
@ -29,6 +31,7 @@ def after_install():
add_company_to_session_defaults() add_company_to_session_defaults()
add_standard_navbar_items() add_standard_navbar_items()
add_app_name() add_app_name()
add_non_standard_user_types()
frappe.db.commit() frappe.db.commit()
@ -164,3 +167,81 @@ def add_standard_navbar_items():
def add_app_name(): def add_app_name():
frappe.db.set_value('System Settings', None, 'app_name', 'ERPNext') frappe.db.set_value('System Settings', None, 'app_name', 'ERPNext')
def add_non_standard_user_types():
user_types = get_user_types_data()
user_type_limit = {}
for user_type, data in iteritems(user_types):
user_type_limit.setdefault(frappe.scrub(user_type), 10)
update_site_config('user_type_doctype_limit', user_type_limit)
for user_type, data in iteritems(user_types):
create_custom_role(data)
create_user_type(user_type, data)
def get_user_types_data():
return {
'Employee Self Service': {
'role': 'Employee Self Service',
'apply_user_permission_on': 'Employee',
'user_id_field': 'user_id',
'doctypes': {
'Salary Slip': ['read'],
'Employee': ['read', 'write'],
'Expense Claim': ['read', 'write', 'create', 'delete'],
'Leave Application': ['read', 'write', 'create', 'delete'],
'Attendance Request': ['read', 'write', 'create', 'delete'],
'Compensatory Leave Request': ['read', 'write', 'create', 'delete'],
'Employee Tax Exemption Declaration': ['read', 'write', 'create', 'delete'],
'Employee Tax Exemption Proof Submission': ['read', 'write', 'create', 'delete'],
'Timesheet': ['read', 'write', 'create', 'delete', 'submit', 'cancel', 'amend']
}
}
}
def create_custom_role(data):
if data.get('role') and not frappe.db.exists('Role', data.get('role')):
frappe.get_doc({
'doctype': 'Role',
'role_name': data.get('role'),
'desk_access': 1,
'is_custom': 1
}).insert(ignore_permissions=True)
def create_user_type(user_type, data):
if frappe.db.exists('User Type', user_type):
doc = frappe.get_cached_doc('User Type', user_type)
doc.user_doctypes = []
else:
doc = frappe.new_doc('User Type')
doc.update({
'name': user_type,
'role': data.get('role'),
'user_id_field': data.get('user_id_field'),
'apply_user_permission_on': data.get('apply_user_permission_on')
})
create_role_permissions_for_doctype(doc, data)
doc.save(ignore_permissions=True)
def create_role_permissions_for_doctype(doc, data):
for doctype, perms in iteritems(data.get('doctypes')):
args = {'document_type': doctype}
for perm in perms:
args[perm] = 1
doc.append('user_doctypes', args)
def update_select_perm_after_install():
if not frappe.flags.update_select_perm_after_migrate:
return
frappe.flags.ignore_select_perm = False
for row in frappe.get_all('User Type', filters= {'is_standard': 0}):
print('Updating user type :- ', row.name)
doc = frappe.get_doc('User Type', row.name)
doc.save()
frappe.flags.update_select_perm_after_migrate = False

View File

@ -112,9 +112,7 @@ def place_order():
def request_for_quotation(): def request_for_quotation():
quotation = _get_cart_quotation() quotation = _get_cart_quotation()
quotation.flags.ignore_permissions = True quotation.flags.ignore_permissions = True
quotation.save() quotation.submit()
if not get_shopping_cart_settings().save_quotations_as_draft:
quotation.submit()
return quotation.name return quotation.name
@frappe.whitelist() @frappe.whitelist()

View File

@ -558,7 +558,6 @@ frappe.ui.form.on('Stock Entry', {
}) })
); );
} }
for (let i in frm.doc.items) { for (let i in frm.doc.items) {
let item = frm.doc.items[i]; let item = frm.doc.items[i];

View File

@ -34,7 +34,7 @@ class TestStockLedgerEntry(unittest.TestCase):
qty=50, qty=50,
rate=100, rate=100,
company=company, company=company,
expense_account = "Stock Adjustment - _TC", expense_account = "Stock Adjustment - _TC" if frappe.get_all("Stock Ledger Entry") else "Temporary Opening - _TC",
posting_date='2020-04-10', posting_date='2020-04-10',
posting_time='14:00' posting_time='14:00'
) )
@ -46,7 +46,7 @@ class TestStockLedgerEntry(unittest.TestCase):
qty=10, qty=10,
rate=200, rate=200,
company=company, company=company,
expense_account = "Stock Adjustment - _TC", expense_account="Stock Adjustment - _TC" if frappe.get_all("Stock Ledger Entry") else "Temporary Opening - _TC",
posting_date='2020-04-20', posting_date='2020-04-20',
posting_time='14:00' posting_time='14:00'
) )
@ -58,7 +58,7 @@ class TestStockLedgerEntry(unittest.TestCase):
target="Finished Goods - _TC", target="Finished Goods - _TC",
company=company, company=company,
qty=10, qty=10,
expense_account="Stock Adjustment - _TC", expense_account="Stock Adjustment - _TC" if frappe.get_all("Stock Ledger Entry") else "Temporary Opening - _TC",
posting_date='2020-04-30', posting_date='2020-04-30',
posting_time='14:00' posting_time='14:00'
) )
@ -90,7 +90,7 @@ class TestStockLedgerEntry(unittest.TestCase):
qty=50, qty=50,
rate=150, rate=150,
company=company, company=company,
expense_account = "Stock Adjustment - _TC", expense_account ="Stock Adjustment - _TC" if frappe.get_all("Stock Ledger Entry") else "Temporary Opening - _TC",
posting_date='2020-04-12', posting_date='2020-04-12',
posting_time='14:00' posting_time='14:00'
) )

View File

@ -372,7 +372,8 @@ class update_entries_after(object):
elif sle.voucher_type in ("Purchase Receipt", "Purchase Invoice", "Delivery Note", "Sales Invoice"): elif sle.voucher_type in ("Purchase Receipt", "Purchase Invoice", "Delivery Note", "Sales Invoice"):
if frappe.get_cached_value(sle.voucher_type, sle.voucher_no, "is_return"): if frappe.get_cached_value(sle.voucher_type, sle.voucher_no, "is_return"):
from erpnext.controllers.sales_and_purchase_return import get_rate_for_return # don't move this import to top from erpnext.controllers.sales_and_purchase_return import get_rate_for_return # don't move this import to top
rate = get_rate_for_return(sle.voucher_type, sle.voucher_no, sle.item_code, voucher_detail_no=sle.voucher_detail_no) rate = get_rate_for_return(sle.voucher_type, sle.voucher_no, sle.item_code,
voucher_detail_no=sle.voucher_detail_no, sle = sle)
else: else:
if sle.voucher_type in ("Purchase Receipt", "Purchase Invoice"): if sle.voucher_type in ("Purchase Receipt", "Purchase Invoice"):
rate_field = "valuation_rate" rate_field = "valuation_rate"

View File

@ -11,7 +11,7 @@
<small class="formatted-price">({{ product_info.price.formatted_price }} / {{ product_info.uom }})</small> <small class="formatted-price">({{ product_info.price.formatted_price }} / {{ product_info.uom }})</small>
</div> </div>
{% else %} {% else %}
{{ _("Unit of Measurement") }} : {{ product_info.uom }} {{ _("UOM") }} : {{ product_info.uom }}
{% endif %} {% endif %}
{% if cart_settings.show_stock_availability %} {% if cart_settings.show_stock_availability %}

View File

@ -14,11 +14,7 @@
</div> </div>
</div> </div>
<div class="col-sm-3 text-right bold"> <div class="col-sm-3 text-right bold">
{% if doc.doctype == "Quotation" and not doc.docstatus %} {{ doc.get_formatted("grand_total") }}
{{ _("Pending") }}
{% else %}
{{ doc.get_formatted("grand_total") }}
{% endif %}
</div> </div>
</div> </div>
<a class="transaction-item-link" href="/{{ pathname }}/{{ doc.name }}">Link</a> <a class="transaction-item-link" href="/{{ pathname }}/{{ doc.name }}">Link</a>

View File

@ -12,21 +12,22 @@
{% endblock %} {% endblock %}
{% block header_actions %} {% block header_actions %}
<div class="dropdown"> <div class="dropdown">
<button class="btn btn-outline-secondary dropdown-toggle" data-toggle="dropdown" aria-expanded="false"> <button class="btn btn-outline-secondary dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
<span>{{ _('Actions') }}</span> <span>{{ _('Actions') }}</span>
<b class="caret"></b> <b class="caret"></b>
</button> </button>
<ul class="dropdown-menu dropdown-menu-right" role="menu"> <ul class="dropdown-menu dropdown-menu-right" role="menu">
{% if doc.doctype == 'Purchase Order' %} {% if doc.doctype == 'Purchase Order' %}
<a class="dropdown-item" href="/api/method/erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_invoice_from_portal?purchase_order_name={{ doc.name }}" data-action="make_purchase_invoice">{{ _("Make Purchase Invoice") }}</a> <a class="dropdown-item" href="/api/method/erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_invoice_from_portal?purchase_order_name={{ doc.name }}" data-action="make_purchase_invoice">{{ _("Make Purchase Invoice") }}</a>
{% endif %} {% endif %}
<a class="dropdown-item" href='/printview?doctype={{ doc.doctype}}&name={{ doc.name }}&format={{ print_format }}' <a class="dropdown-item" href='/printview?doctype={{ doc.doctype}}&name={{ doc.name }}&format={{ print_format }}'
target="_blank" rel="noopener noreferrer"> target="_blank" rel="noopener noreferrer">
{{ _("Print") }} {{ _("Print") }}
</a> </a>
</ul> </ul>
</div> </div>
{% endblock %} {% endblock %}
{% block page_content %} {% block page_content %}

View File

@ -7,7 +7,6 @@ import frappe.share
from frappe import _ from frappe import _
from frappe.utils import cstr, now_datetime, cint, flt, get_time, get_datetime, get_link_to_form, date_diff, nowdate from frappe.utils import cstr, now_datetime, cint, flt, get_time, get_datetime, get_link_to_form, date_diff, nowdate
from erpnext.controllers.status_updater import StatusUpdater from erpnext.controllers.status_updater import StatusUpdater
from erpnext.accounts.utils import get_fiscal_year
from six import string_types from six import string_types
@ -121,11 +120,11 @@ class TransactionBase(StatusUpdater):
buying_doctypes = ["Purchase Order", "Purchase Invoice", "Purchase Receipt"] buying_doctypes = ["Purchase Order", "Purchase Invoice", "Purchase Receipt"]
if self.doctype in buying_doctypes: if self.doctype in buying_doctypes:
to_disable = "Maintain same rate throughout Purchase cycle" action = frappe.db.get_single_value("Buying Settings", "maintain_same_rate_action")
settings_page = "Buying Settings" settings_doc = "Buying Settings"
else: else:
to_disable = "Maintain same rate throughout Sales cycle" action = frappe.db.get_single_value("Selling Settings", "maintain_same_rate_action")
settings_page = "Selling Settings" settings_doc = "Selling Settings"
for ref_dt, ref_dn_field, ref_link_field in ref_details: for ref_dt, ref_dn_field, ref_link_field in ref_details:
for d in self.get("items"): for d in self.get("items"):
@ -133,11 +132,16 @@ class TransactionBase(StatusUpdater):
ref_rate = frappe.db.get_value(ref_dt + " Item", d.get(ref_link_field), "rate") ref_rate = frappe.db.get_value(ref_dt + " Item", d.get(ref_link_field), "rate")
if abs(flt(d.rate - ref_rate, d.precision("rate"))) >= .01: if abs(flt(d.rate - ref_rate, d.precision("rate"))) >= .01:
frappe.msgprint(_("Row #{0}: Rate must be same as {1}: {2} ({3} / {4}) ") if action == "Stop":
.format(d.idx, ref_dt, d.get(ref_dn_field), d.rate, ref_rate)) role_allowed_to_override = frappe.db.get_single_value(settings_doc, 'role_to_override_stop_action')
frappe.throw(_("To allow different rates, disable the {0} checkbox in {1}.")
.format(frappe.bold(_(to_disable)), if role_allowed_to_override not in frappe.get_roles():
get_link_to_form(settings_page, settings_page, frappe.bold(settings_page)))) frappe.throw(_("Row #{0}: Rate must be same as {1}: {2} ({3} / {4})").format(
d.idx, ref_dt, d.get(ref_dn_field), d.rate, ref_rate))
else:
frappe.msgprint(_("Row #{0}: Rate must be same as {1}: {2} ({3} / {4})").format(
d.idx, ref_dt, d.get(ref_dn_field), d.rate, ref_rate), title=_("Warning"), indicator="orange")
def get_link_filters(self, for_doctype): def get_link_filters(self, for_doctype):
if hasattr(self, "prev_link_mapper") and self.prev_link_mapper.get(for_doctype): if hasattr(self, "prev_link_mapper") and self.prev_link_mapper.get(for_doctype):