Its that time of the year again. The time when the entire team at Frappe is busy preparing for Frappeverse, our annual conference. All our engineers are busy adding new features, fixing and polishing the existing ones, and making sure that everything is ready for the big day. If you haven't already, register for the event with this link.
Table of Contents
Pegged Currency
ERPNext now supports implicit conversion of pegged currencies. For example, AED
is pegged against USD
at 3.6725. While converting AED
to INR
, the system will first convert to USD
and then to INR
(AED
-> USD
-> INR
). This can be enabled through Accounts Settings.
Contributed by: Karuppasamy
Duplicate items caused incorrect status in Quotation
If there are duplicate items in a Quotation (same item code and quantity), making partial sales orders for them will update the incorrect status on the Quotation. This has now been addressed. Contributed by: Abdeali Chharchhodawala
Validation on Inter-company Transaction
Validation have been added to prevent rate change in inter-company transactions. This can be found under Accounts Settings.
Contributed by: Karuppasamy
Confirm the posting date change
While submitting an old, draft document with Edit Posting Date and Time enabled, the system auto-resets the posting date to the current date. This behavior is now configurable in Accounts Settings. Contributed by: Debin Robert
Accounts Receivable and Accounts Payable Report
Accounts Receivable and Accounts Payable reports are now User Permission aware.
Contributed by: Logesh
MT940 Support
Bank Statement Import now supports MT940 format as well.
Contributed by: Karuppasamy
POS UX
In the POS screen, searching on barcode alone won't fetch an item if the item has a different Item Group than the one specified in the POS Profile, even if the item's group is a child of a group from the configuration. This is now fixed. Contributed by: Pugazhendhi V

Landed Cost Voucher for Stock (Manufacture) and Subcontracting Receipt
From version 16 of ERPNext, users can create a Landed Cost Voucher against a Stock Entry with the purpose set to Manufacture. This feature allows users to include additional costs such as electricity charges or rent, into the final valuation rate of the manufactured product.
Also, from version 16, users can create a Landed Cost Voucher against a Subcontracting Receipt item, which has been manufactured by the subcontractor. This feature allows users to include additional costs, such as freight charges, excise duty, into the final valuation rate of the subcontracted product.
Periodic Inventory
If you enable Perpetual Inventory in the Company master, the system will automatically create the GL entries for stock transactions. However, if Perpetual Inventory is disabled for your company, you will need to manually create periodic accounting entries.
To make a periodic accounting entry, you must create a Journal Entry manually. For the calculations, you need to compare the closing balance in the Stock Balance Report with the Trial Balance report for stock asset accounts. This process takes time, as it requires verifying and matching the differences in closing balances.
To address this in version 16, we introduced a new Journal Entry type called Periodic Accounting Entry. With this, users don’t need to perform manual calculations. The system will automatically fetch the difference in balance when the user clicks the Get Balance button.
Setup wizard Changes
If users installed any Frappe app and completed the setup wizard for it, then they were not able to install ERPNext, and the system used to throw the error ERPNext can only be installed on a fresh site where the setup wizard is not complete.
To solve this problem, we have implemented app-wise tracking of setup wizard completion. Now, users can install the ERPNext app even if the setup wizard for any Frappe app has already been completed.

Payroll
This month, we focused on fixing bugs and improving the overall payroll experience.
- Allow scheduling recurring Additional Salaries with Overwrite Salary Structure Amount enabled, but non-overlapping date ranges. Non-recurring Additional Salary within the date range of an existing recurring Additional Salary should throw an error during creation if both have the same salary component and overwrite is enabled. The error was being raised only while processing the salary. #3205
- Fixed the calculation of the number of leaves without pay in the salary slip when the employee has taken a partially paid leave. #3240
- In cases where the payroll period starts and ends in the same Month (e.g., July 16, 2023 – July 15, 2024), we have fixed the calculation of the number of future payroll cycles for which a recurring additional salary is applicable. #3247

Half Day Leave Attendance
Leave applications create attendance records On Leave or Half Day. Previously, attendance from employee check-ins couldn’t be marked on days that already had a Half Day attendance from leave applications marked. Now you can use the Employee Attendance Tool to specify employees’ attendance status for the other half, or let the auto-attendance mark it based on employee check-ins.
Now you can use the Employee Attendance Tool to specify employees’ attendance status for the other half or let the auto attendance mark it automatically based on employee check-ins.
Payroll now checks the Status for the Other Half to calculate absent days and reduces payment days as per the fraction specified in Payroll Settings. #2978
Team Attendance Requests in PWA
Check and approve attendance requests made by your team right from the PWA.
Fixes and Improvements
- You can now set shift while marking attendance in bulk #3265
- Refresh applications and requests without having to refresh the PWA #3252
- Start time, end time labels, and Shift Type search are now fixed in the shift assignment modal inside roster #3239
- Attendances on holidays are shown in the PWA calendar view #3231
- All notifications in the PWA can be loaded, 10 at time with, Load More button instead of having only recent 20 #3197
- If an approver opened any team request in the form view, the employee name would be changed to his own after saving the record, this bug is now fixed in the PWA #3200
.jpg)
Database Server Storage Breakdown
Many times, you might wonder what’s taking up so much space on your dedicated database server. You can now check this easily from the Frappe Cloud dashboard.
Check the documentation for more information.
Site Database User Logs
Many users create database users to connect to their site’s database from outside Frappe Cloud’s infrastructure. However, it’s often difficult to track whether any destructive SQL queries have been executed through those external connections.
To help with this, we have released a log viewer; you can now view all executed queries, along with their timestamps and the client IP addresses.
Check the documentation to know more.

In Video Quizzes
One of the common questions that most prospects ask me about the learning app is “Do you track how much time the user spends on the system?”. To this, my answer is always no, because learning cannot be enforced.
But then, recently, one prospect made me realize that even though we don’t track a student’s activities minute by minute, the system should have some way to capture attentiveness.
So now, in learning, instructors can add quizzes at specific timestamps in a video. Students can still move forward in the video, but once the video reaches the point where there is a quiz, they see a short prompt informing them about it, and then the quiz loads. They can then attempt the quiz, and once they submit, they can resume with the video.
The student needs to score a minimum passing percentage in all the quizzes added in the video to complete the lesson.
This will give instructors an idea of how attentive the students are while watching the video, and it will also help students to stay focused on the content.
Related courses
Instructors can now link related courses to any course they create. These related courses will appear on the course details page.
This will give students a clear idea of which course to take after completing the current course, making sure that their learning journey continues.
Programming Exercises
Instructors can now add programming exercises directly to their courses or batches.
To create an exercise, instructors define a problem statement, choose a programming language (currently supported: Python and JavaScript), and add one or more test cases. These test cases are used to automatically evaluate student submissions.
Students see the problem statement alongside a built-in code editor. When they click Run, their code is executed against all test cases. Each test case shows as Passed or Failed based on the output match. An exercise is considered complete only when all test cases pass.
If there's a compilation or runtime error, students can view it in the Compiler Message section to help debug their code.
Instructors can view a list of all student submissions. While the evaluation is fully automated, they can manually review any submission if needed. Students also have access to their submission history for reference.
We’ll be adding support for more programming languages soon.

Dashboard
Introducing a dashboard to make life a bit easier for support teams.
Whether you're managing a team or handling tickets yourself, the dashboard gives a clear view of performance. Managers can track how teams are performing, and agents can monitor their statistics.
Some of the insights it shows:
- Open tickets
- SLA achievement average
- Ticket volume trends
- Feedback trends
...and more useful metrics

Continued enhancing the Class-based client script
Intercept create lead from call log via form script #858
Introduces support for intercepting and customizing the "Create Lead" flow from a call log using class-based form scripts. Enables injecting logic like autofilling fields or preventing creation based on conditions.
class CRMCallLog { onCreateLead(doc, lead, close) { lead.source = "Call Log" // setting lead data lead.mobile_no = doc.from // doc is call log doc close() // close is a function which will close the call log modal } }
Intercept convert to deal via form script #863
Adds the ability to override or extend the "Convert to Deal" behavior using form scripts, allowing custom logic during the lead-to-deal conversion.
class CRMCallLog { convertToDeal(doc, deal, close) { // setting deal data deal.mobile_no = doc.mobile_no // doc is lead doc close() // close is a function which will close the convert to deal modal } }
Apply Class Based Form Script in New Modal #887
Ensures that class-based form scripts also run inside modals (e.g. during quick create lead/deal etc), maintaining consistent behavior across the app.
Refactor Lead/Deal Assignees #894
Refactors how assignees are handled for Lead and Deal pages, simplifying logic and aligning with newer patterns in the codebase.
onLoad & onSave #902
Adds lifecycle hooks
onLoad
andonSave
to class-based form scripts, enabling custom logic during form (controller) initialization and before saving.class CRMLead { onLoad() { // initialize actions this.doc.trigger('setActions') } onSave() { // on save update actions this.doc.trigger('setActions') console.log("Saved") } setActions() { if (this.doc.status !== "Junk") { this.actions = [{ label: "Mark as Junk", onClick: () => { this.doc.status = "Junk" this.save.submit() } }] } else { this.actions = [{ label: "Mark as New", onClick: () => { this.doc.status = "New" this.save.submit() } }] } } }
Custom actions/statuses via Class Based Script #896
Allows defining custom actions and statuses directly in form scripts, enhancing flexibility in how users interact with documents.
class CRMLead { onLoad() { // initialize actions this.actions = [{ "label": "Open in desk", "onClick": () => { let URL = `http://crmnext:8080/app/crm-lead/${this.doc.name}` window.open(URL, '_blank') } }] // initialize statuses options this.statuses = ['Junk', 'Unqualified', 'Qualified', 'Nurture', 'Contacted', 'New'] } source() { this.actions.push({"label": "Action 1"}) // update statuses options (can be concatenated or overridden) this.statuses = ['Junk', 'Nurture', 'Contacted', 'New'] } industry() { // update this.actions (can be concatenated or overridden) this.actions = this.actions.concat([{"label": "Action 2"}, {"label": "Action 3"}]) } }
Manage CRM users effectively
Frappe CRM now comes with a dedicated Users page that makes it easy to manage who can access and operate within the CRM. This update ensures better control over user access, cleaner assignment flows, and a more intuitive experience for managers and admins.
- Add existing / Invite new users
- Remove users
- Update roles

Page View Analytics
Builder now ships with integrated, simple, and effective Page View Analytics. You can now track how your website is performing.
See Total Pageviews and Unique Visitors over time with a simple visual breakdown. Also, get an option to toggle between different date ranges and intervals.
Find your top-performing pages and top sources that are generating traffic for your site.
Canonical URL
For better ranking of a page, Google recommends having a canonical URL so that it is easy for web crawlers to identify duplicate pages on your site. From now on, Builder will attach self-referencing canonical URLs to every page and provide an option to update it for a specific page via Settings
UX and Bug Fixes
- Introduced an option to toggle underline for selected text in Text block using
ctrl/cmd + u
shortcut. - Fixed text visibility for deeply nested layers in the layer panel. More info
- Fixed arrow navigation in layers panel inside component editor view.
- Fixed canvas styling in Dark Mode. Previously, scrollbars and selection text inherited dark styling, creating a visual mismatch with the white canvas background.

Writer Refactor
At Frappe, we’ve long been dissatisfied with Writer. Almost all of its features are buggy, the UI is unpolished, and compared to other Writer products, it’s very limited and slow. This month, we rewrote Writer from scratch.
We’ve now made our editor consistent with other products like Gameplan, but extending it with more power - task lists, editing font families and sizes, and a lot more.
The clunky sidebar is gone - now, all formatting is done through an easily accessible bubble menu, and everything else can be done through the navbar.
Commenting has been completely overhauled. Not only can you use rich text in comments, but the UI looks far better. You can edit, delete, or resolve comments.
Since we’re rewriting, quite a few features - like live collaboration and version history - have been removed temporarily. Over the upcoming weeks, we’ll bring them back, polished this time.
A sneak peek into how it looks now:
We will be releasing these changes in a while - until then, you can try them out here.
Drive v0.2
Drive got its updates too: importantly, we released v0.2, a stable release. Here are some of the bigger things done this month:
- Guest access is back! You can now make certain people only guests, giving them read access to your team
- For all you owls, dark mode is here.
- The move dialog has been redone - you now see an aesthetic tree.
We’re doing a UI polish throughout the product, which will continue into next month

Autocompletions
While wiring dynamic values in component props, events, and scripts, users often had to repeatedly open the Data Panel to refer to variable names, data sources, and nested properties.
It wasn’t clear what context was available at different code points:
Global context (for the page):
a. Variables & Data Sources
b. Vue Route object (with params, current path)
Local context (component data):
a. Repeater context -
dataItem
anddataIndex
if the component is inside a repeating layout
The autocompletion feature was added to make this UX better. You can now explicitly request available completions by pressing Ctrl + Space in any code editor field.
Array and object property completion
Since you mostly work with objects and arrays in your data, this provides completions for nested object properties with their types.
Page Route context in completions
Repeater context completion
For components inside a repeater, the dataItem
at that iteration is available for completion with its nested properties, if any.
JavaScript language completions along with custom completions
Applying completions
Data sources are always immutable. But variables are passed as:
- Immutable when used in the prop editing/visibility condition setting
- Mutable when used in scripts, events. Here, they are passed using toRefs to the script context, so they need to be accessed with
.value
. When you select completion for variables in scripts/events, it will automatically append.value
.
Bug Fixes
- The limit for Document List type Data Source is now configurable. Contributed by Kevin Shenk

Demo Site
Gameplan now has a demo site where the demo data is regenerated daily. When you visit /g?demo=1
you will automatically be logged in as a random user on the demo site. You can checkout the demo site and its code.
Image Grid
Going through some of the trip update posts by my colleagues, I found that multiple full width images took a lot of screen space. To handle this better, I have created a image gallery extension for TextEditor. When you upload multiple images, you will have the option to show them in a grid. You can customize the number of columns and add captions to each image. You can check the code for the extension here.
Full Text Search using SQLite
I have refactored the search again using SQLite FTS5. The previous Python-based search was too slow, although it was a great exercise of learning how full text search works. The new search uses SQLite’s bm25
function to rank the results and after that I apply some heuristics in Python to boost results based on title match, recency and document type. It also does spelling correction using trigram indexing by storing words and trigrams in sqlite tables and querying them.
The entire code is in one file.
Most of the code is generic, so I’ll be moving 80% of it to Frappe Framework. It should become the default search tool for all our search needs. The command palette also uses this for quickly searching discussions by titles. Try the new search and share feedback.

And that's it 👋
Next month, our team will be making a special announcement. Its something that we have been planning for a while now, something that we have never done before. Stay tuned on all our socials ✌️