add en pages with corrects links
This commit is contained in:
parent
fbde9e1a7a
commit
bdcdc2db76
82 changed files with 3158 additions and 0 deletions
0
frappe/docs/user/en/guides/.txt
Executable file
0
frappe/docs/user/en/guides/.txt
Executable file
34
frappe/docs/user/en/guides/app-development/adding-module-icons-on-desktop.md
Executable file
34
frappe/docs/user/en/guides/app-development/adding-module-icons-on-desktop.md
Executable file
|
|
@ -0,0 +1,34 @@
|
|||
To create a module icon for a Page, List or Module, you will have to edit the `config/desktop.py` file in your app.
|
||||
|
||||
In this file you will have to write the `get_data` method that will return a dict object with the module icon parameters
|
||||
|
||||
### Example 1: Module Icon
|
||||
|
||||
def get_data():
|
||||
return {
|
||||
"Accounts": {
|
||||
"color": "#3498db",
|
||||
"icon": "octicon octicon-repo",
|
||||
"type": "module"
|
||||
},
|
||||
}
|
||||
|
||||
### Example 2: List Icon
|
||||
|
||||
def get_data():
|
||||
return {
|
||||
"To Do": {
|
||||
"color": "#f1c40f",
|
||||
"icon": "icon-check",
|
||||
"icon": "octicon octicon-check",
|
||||
"label": _("To Do"),
|
||||
"link": "List/ToDo",
|
||||
"doctype": "ToDo",
|
||||
"type": "list"
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
Note: Module views are visible based on permissions.
|
||||
|
||||
<!-- markdown -->
|
||||
21
frappe/docs/user/en/guides/app-development/custom-module-icon.md
Executable file
21
frappe/docs/user/en/guides/app-development/custom-module-icon.md
Executable file
|
|
@ -0,0 +1,21 @@
|
|||
If you want to create a custom icon for your module, you will have to create an SVG file for your module and set the path to this file in the `desktop/config.py` of your app.<br>
|
||||
|
||||
This icon is loaded via AJAX first time, then it will be rendered.
|
||||
|
||||
Example:
|
||||
|
||||
from frappe import _
|
||||
|
||||
def get_data():
|
||||
return {
|
||||
"Frappe Apps": {
|
||||
"color": "orange",
|
||||
"icon": "assets/frappe/images/frappe.svg",
|
||||
"label": _("Frappe.io Portal"),
|
||||
"type": "module"
|
||||
}
|
||||
}
|
||||
|
||||
> PS: A great place to buy SVG icons for a low cost is the awesome [Noun Project](http://thenounproject.com/)
|
||||
|
||||
<!-- markdown -->
|
||||
118
frappe/docs/user/en/guides/app-development/dialogs-types.md
Executable file
118
frappe/docs/user/en/guides/app-development/dialogs-types.md
Executable file
|
|
@ -0,0 +1,118 @@
|
|||
Frappe provide a group of standard dialogs that are very usefull while coding.
|
||||
|
||||
## Alert Dialog
|
||||
|
||||

|
||||
|
||||
Is helpfull for show a non-obstrutive message.
|
||||
|
||||
This dialog have 2 parameters `txt`that is the message and `seconds` that is the time that the message will be showed for the user, the standard is `3 seconds`.
|
||||
|
||||
### Example
|
||||
|
||||
show_alert('Hi, do you have a new message', 5);
|
||||
|
||||
---
|
||||
|
||||
## Prompt Dialog
|
||||
|
||||

|
||||
|
||||
Is helpful for ask a value for the user
|
||||
|
||||
This dialog have 4 parameters, they are:
|
||||
|
||||
- **fields:** a list with the fields objects
|
||||
- **callback:** the function that manage the received values
|
||||
- **title:** the title of the dialog
|
||||
- **primary_label:** the label of the primary button
|
||||
|
||||
### Example
|
||||
|
||||
frappe.prompt([
|
||||
{'fieldname': 'birth', 'fieldtype': 'Date', 'label': 'Birth Date', 'reqd': 1}
|
||||
],
|
||||
function(values){
|
||||
show_alert(values, 5);
|
||||
},
|
||||
'Age verification',
|
||||
'Subscribe me'
|
||||
)
|
||||
|
||||
---
|
||||
## Confirm Dialog
|
||||
|
||||

|
||||
|
||||
Usefull to get a confirmation from the user before do an action
|
||||
|
||||
This dialog have 3 arguments, they are:
|
||||
|
||||
- **mesage:** The message content
|
||||
- **onyes:** The callback on positive confirmation
|
||||
- **oncancel:** The callback on negative confirmation
|
||||
|
||||
### Example
|
||||
|
||||
frappe.confirm(
|
||||
'Are you sure to leave this page?',
|
||||
function(){
|
||||
window.close();
|
||||
},
|
||||
function(){
|
||||
show_alert('Thanks for continue here!')
|
||||
}
|
||||
)
|
||||
|
||||
---
|
||||
|
||||
## Message Print
|
||||
|
||||

|
||||
|
||||
Is helpfull for show a informational dialog for the user;
|
||||
|
||||
This dialog have 2 arguments, they are:
|
||||
|
||||
- **message:** The message content, can be a HTML string too
|
||||
- **title:** The title of the dialog
|
||||
|
||||
### Example
|
||||
|
||||
msgprint("<b>Server Status</b>"
|
||||
+ "<hr>"
|
||||
+ "<ul>"
|
||||
+ "<li><b>28%</b> Memory</li>"
|
||||
+ "<li><b>12%</b> Processor</li>"
|
||||
+ "<li><b>0.3%</b> Disk</li>"
|
||||
"</ul>", 'Server Info')
|
||||
|
||||
---
|
||||
|
||||
### Custom Dialog
|
||||
|
||||

|
||||
|
||||
Frappé provide too a `Class` that you can extend and build your own custom dialogs
|
||||
|
||||
`frappe.ui.Dialog`
|
||||
|
||||
### Example
|
||||
|
||||
var d = new frappe.ui.Dialog({
|
||||
'fields': [
|
||||
{'fieldname': 'ht', 'fieldtype': 'HTML'},
|
||||
{'fieldname': 'today', 'fieldtype': 'Date', 'default': frappe.datetime.nowdate()}
|
||||
],
|
||||
primary_action: function(){
|
||||
d.hide();
|
||||
show_alert(d.get_values());
|
||||
}
|
||||
});
|
||||
d.fields_dict.ht.$wrapper.html('Hello World');
|
||||
d.show();
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- markdown -->
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
To execute code when a DocType is inserted, validated (before saving), updated, submitted, cancelled, deleted, you must write in the DocType's controller module.
|
||||
|
||||
#### 1. Controller Module
|
||||
|
||||
The controller module exists in the `doctype` folder in the Module of the `DocType`. For example, the controller for **ToDo** exists in `frappe/desk/doctype/todo/todo.py` (version 5). A controller template is created when the DocType is created. which looks like
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class CustomType(Document):
|
||||
pass
|
||||
|
||||
#### 2. Document Properties
|
||||
|
||||
All the fields and child tables are available to the class as attributes. For example the **name** property is `self.name`
|
||||
|
||||
#### 3. Adding Methods
|
||||
|
||||
In this module, you can add standard methods to the class that are called when a document of that type is created. Standard Handlers are:
|
||||
|
||||
1. `autoname`: Called while naming. You can set the `self.name` property in the method.
|
||||
1. `before_insert`: Called before a document is inserted.
|
||||
1. `validate`: Called before document is saved. You can throw an exception if you don't want the document to be saved
|
||||
1. `on_update`: Called after the document is inserted or updated in the database.
|
||||
1. `on_submit`: Called after submission.
|
||||
1. `on_cancel`: Called after cancellation.
|
||||
1. `on_trash`: Called after document is deleted.
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
# Fetch a Field Value from a Document into a Transaction
|
||||
|
||||
Let's say, there is a custom field "VAT Number" in Supplier, which should be fetched in Purchase Order.
|
||||
|
||||
#### Steps:
|
||||
|
||||
1. Create a Custom Field **VAT Number** for *Supplier* document with *Field Type* as **Data**.
|
||||
<img class="screenshot" src="{{ docs_base_url }}/assets/img/add-vat-number-in-supplier.png">
|
||||
|
||||
1. Create another Custom Field **VAT Number** for *Purchase Order* document, but in this case with *Field Type* as **Read Only** or check **Read Only** checkbox. Set the **Options** as `supplier.vat_number`.
|
||||
<img class="screenshot" src="{{ docs_base_url }}/assets/img/add-vat-number-in-purchase-order.png">
|
||||
|
||||
1. Go to the user menu and click "Reload".
|
||||
1. Now, on selection of Supplier in a new Purchase Order, **VAT Number** will be fetched automatically from the selected Supplier.
|
||||
<img class="screenshot" src="{{ docs_base_url }}/assets/img/vat-number-fetched.png">
|
||||
110
frappe/docs/user/en/guides/app-development/generating-docs.md
Executable file
110
frappe/docs/user/en/guides/app-development/generating-docs.md
Executable file
|
|
@ -0,0 +1,110 @@
|
|||
# Generating Documentation Website for your App
|
||||
|
||||
Frappe version 6.7 onwards includes a full-blown documentation generator so that you can easily create a website for your app that has both user docs and developers docs (auto-generated). These pages are generated as static HTML pages so that you can add them as GitHub pages.
|
||||
|
||||
## Writing Docs
|
||||
|
||||
### 1. Setting up docs
|
||||
|
||||
#### 1.1. Setup `docs.py`
|
||||
|
||||
The first step is to setup the docs folder. For that you must create a new file in your app `config/docs.py` if it is not auto-generated. In your `docs.py` file, add the following module properties.
|
||||
|
||||
|
||||
source_link = "https://github.com/[orgname]/[reponame]"
|
||||
docs_base_url = "https://[orgname].github.io/[reponame]"
|
||||
headline = "This is what my app does"
|
||||
sub_heading = "Slightly more details with key features"
|
||||
long_description = """(long description in markdown)"""
|
||||
|
||||
def get_context(context):
|
||||
# optional settings
|
||||
|
||||
# context.brand_html = 'Brand info on the top left'
|
||||
# context.favicon = 'path to favicon'
|
||||
#
|
||||
# context.top_bar_items = [
|
||||
# {"label": "About", "url": context.docs_base_url + "/about"},
|
||||
# ]
|
||||
|
||||
pass
|
||||
|
||||
#### 1.2. Generate `/docs`
|
||||
|
||||
To generate the docs for the `current` version, go to the command line and write
|
||||
|
||||
bench --site sitename make-docs app_name current
|
||||
|
||||
If you want to maintain versions of your docs, then you can add a version number instead of `current`
|
||||
|
||||
This will create a `/docs` folder in your app.
|
||||
|
||||
### 2. Add User Documentation
|
||||
|
||||
To add user documentation, add folders and pages in your `/docs/user` folder in the same way you would build a website pages in the `www` folder.
|
||||
|
||||
Some quick tips:
|
||||
|
||||
1. Add your pages as `.md` or `.html` pages
|
||||
2. Optionally add `.css` files with the same name that will be automatically served
|
||||
3. Add index by adding `{index}`
|
||||
|
||||
### 3. Linking
|
||||
|
||||
While linking make sure you add `{{ docs_base_url }}` to all your links.
|
||||
|
||||
|
||||
{% raw %}<a href="{{ docs_base_url }}/user/link/to/page.html">Link Description</a>{% endraw %}
|
||||
|
||||
|
||||
### 4. Adding Images
|
||||
|
||||
You can add images in the `/docs/assets` folder. You can add links to the images as follows:
|
||||
|
||||
{% raw %}<img src="{{ docs_base_url }}/assets/img/my-img/gif" class="screenshot">{% endraw %}
|
||||
|
||||
---
|
||||
|
||||
## Setting up output docs
|
||||
|
||||
1. Create a `/docs` folder in your bench, parallel to your `/sites` folder. e.g. `/frappe-bench/docs`
|
||||
2. Copy the repo of your app to the docs folder. e.g. `cp -R apps/myapp docs/myapp` (you can also clone it here using `git clone`).
|
||||
3. Go to your docs folder `cd docs/myapp`
|
||||
4. Checkout the gh-pages branch `git checkout --orphan gh-pages`
|
||||
5. Clean everything `git rm -rf .`
|
||||
|
||||
Note > The branch name `gh-pages` is only if you are using GitHub. If you are hosting this on any other static file server, can just skip this and just create your docs folder for your app like `docs/myapp`
|
||||
|
||||
Putting it all together:
|
||||
|
||||
mkdir docs
|
||||
cp -R apps/myapp docs/myapp
|
||||
cd docs/myapp
|
||||
git checkout --orphan gh-pages
|
||||
git rm -rf .
|
||||
|
||||
---
|
||||
|
||||
## Viewing Locally
|
||||
|
||||
To test your docs locally, add a `--local` option to the `build-docs` command.
|
||||
|
||||
bench --site [site] build-docs [appname] --local
|
||||
|
||||
Then it will build urls so that you can view these files locally. To view them locally in your browser, you can use the Python SimpleHTTPServer
|
||||
|
||||
Run this from your `docs/myapp` folder:
|
||||
|
||||
python -m SimpleHTTPServer 8080
|
||||
|
||||
---
|
||||
|
||||
## Publishing to GitHub Pages
|
||||
|
||||
To publish your docs on GitHub pages, you will have to create an empty and orphan branch in your repository called `gh-pages` and write yours there
|
||||
|
||||
Now go back to your bench folder and write these docs to this branch. For example if your path to the `gh-pages` repo is `docs/reponame`
|
||||
|
||||
bench --site [site] build-docs [appname]
|
||||
|
||||
To check your documentation online go to: https://[orgname].github.io/[reponame]
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
When you are in application design mode and you want the changes in your DocTypes, Reports etc to affect the app repository, you must be in **Developer Mode**.
|
||||
|
||||
To enable developer mode, update the `site_config.json` file of your site in the sites folder for example:
|
||||
|
||||
frappe-bench/sites/site1/site_config.json
|
||||
|
||||
Add this to the JSON object
|
||||
|
||||
"developer_mode": 1
|
||||
|
||||
After setting developer mode, clear the cache:
|
||||
|
||||
$ bench clear-cache
|
||||
|
||||
<!-- markdown -->
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
Your custom app can automatically add **Custom Fields** to DocTypes outside of your app when it is installed to a new site.
|
||||
|
||||
To do this, add the new custom fields that your app requires, using the Frappe web application.
|
||||
|
||||
In your `hooks.py` file, add `"Custom Fields"`
|
||||
|
||||
fixtures = ["Custom Field"]
|
||||
|
||||
Export fixtures before you commit your app with:
|
||||
|
||||
$ bench --site mysite export-fixtures
|
||||
|
||||
This will create a new folder called `fixtures` in your app folder and a `.csv` or `.json` file will be created with the definition of the custom fields you added.
|
||||
|
||||
This file will be automatically imported when the app is installed in a new site or updated via `bench update`.
|
||||
|
||||
Note: You can also add single DocTypes like "Website Settings" as fixtures
|
||||
|
||||
|
||||
<!-- markdown -->
|
||||
102
frappe/docs/user/en/guides/app-development/how-to-improve-a-standard-control.md
Executable file
102
frappe/docs/user/en/guides/app-development/how-to-improve-a-standard-control.md
Executable file
|
|
@ -0,0 +1,102 @@
|
|||
Frappé has a couple of elegant and useful widgets, but some times we need to edit them to add small improvements. This small article will describe how to add new resources to the standard widgets.
|
||||
|
||||
Let me explain first our goal:
|
||||
|
||||
> Add `many` alternative translations in `numerous records` and in a `lot of doctypes`
|
||||
|
||||
Look the highlighted sections in the __goal__, we have _many translations_ to add in _many records_ and in _many doctypes_, so, we heave a **many of work**, so we have a lot to do right?
|
||||
|
||||
The answer for this question is: _-Of course not! Because we know that if one element exists in many records and in many doctypes, this element is the `Control` or `Widget`_
|
||||
|
||||
So, what we need do, is improve your goal based on the `Control`, to reduce our quantity of work.
|
||||
|
||||
But, where will we find this magic element, the control? _-For now, we can look it in the JavaScript sources - let's look now at [Github](https://github.com/frappe/frappe/blob/develop/frappe/public/js/frappe/form/control.js#L13)_
|
||||
|
||||
> Don't worry if you don't understand the code for now, our goal there is simplify our work.
|
||||
|
||||
Let's go ahead with the thought!
|
||||
|
||||
We know where we need to make the changes, but how will we dismember which are the controls that are affected by our feature and which aren't ?
|
||||
|
||||
We need to keep in mind, that `Control` are instance of `DocFields` and the `DocFields` have a field that is very important for us in this case, the field that will help us to dismember which are affected by our feature and which aren't is the field `options` in the `DocField`.
|
||||
|
||||
_-Wait!, we understood that the field `options` can help us, but, how will it help us?_
|
||||
|
||||
Good question, we will define a word to put in the `options` of the `DocFields` that we need to include the feature, this world will be **`Translatable`.**
|
||||
|
||||
> If you forget how to customize the options of a field look [this article](https://kb.erpnext.com/kb/customize/creating-custom-link-field), it can refresh your knowledge.
|
||||
|
||||
Well, with the defined word in `options` of our selected `DocFields`, now is time to code:
|
||||
|
||||
_-At last, we think we would never stop talking!_
|
||||
|
||||
frappe.ui.form.ControlData = frappe.ui.form.ControlData.$extend({
|
||||
make_input: function(){
|
||||
var options = this.df.options;
|
||||
if (!options || options!=="Translatable"){
|
||||
this._super();
|
||||
return;
|
||||
}
|
||||
var me = this;
|
||||
$('<div class="link-field" style="position: relative;">\
|
||||
<input type="text" class="input-with-feedback form-control">\
|
||||
<span class="dialog-btn">\
|
||||
<a class="btn-open no-decoration" title="' + __(" open="" translation")="" +="" '"="">\
|
||||
<i class="icon-globe"></i></a>\
|
||||
</span>\
|
||||
</div>').prependTo(this.input_area);
|
||||
this.$input_area = $(this.input_area);
|
||||
this.$input = this.$input_area.find('input');
|
||||
this.$btn = this.$input_area.find('.dialog-btn');
|
||||
this.set_input_attributes();
|
||||
this.$input.on("focus", function(){
|
||||
me.$btn.toggle(true);
|
||||
});
|
||||
this.$input.on("blur", function(){
|
||||
setTimeout(function(){ me.$btn.toggle(false) }, 500);
|
||||
});
|
||||
this.input = $this.input.get(0);
|
||||
this.has_input = true;
|
||||
var me = this;
|
||||
this.setup_button();
|
||||
},
|
||||
setup_button: function(){
|
||||
var me = this;
|
||||
if (this.only_input){
|
||||
this.$btn.remove();
|
||||
return;
|
||||
}
|
||||
this.$btn.on("click", function(){
|
||||
var value = me.get_value();
|
||||
var options = me.df.options;
|
||||
if (value && options && options==="Translatable"){
|
||||
this.open_dialog();
|
||||
}
|
||||
});
|
||||
},
|
||||
open_dialog: function(){
|
||||
var doc = this.doc;
|
||||
if (!doc.__unsaved){
|
||||
new frappe.ui.form.TranslationSelector({
|
||||
doc: doc,
|
||||
df: this.doc,
|
||||
text: this.value
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
_-Other letter soup, for my gosh!_
|
||||
|
||||
In fact, it IS a soup of letters, for a newbie, but we are not a beginner.
|
||||
|
||||
Let me explain what this code does;
|
||||
|
||||
- At line 1 the code overrides the `ControlData` by one extended `Class` of itself.
|
||||
- The method `make_input` checks if the docfield is **`Translatable`** to make the new `Control` if not, it calls the *original* `make_input` using `_super()`
|
||||
- The method `setup_button` checks if the docfield is **`Translatable`** to enable it show a `dialog`
|
||||
- The method `open_dialog` invokes a new instance of the `TranslationSelector` that we will create in the code below.
|
||||
|
||||
|
||||
|
||||
<!-- markdown -->
|
||||
3
frappe/docs/user/en/guides/app-development/index.md
Executable file
3
frappe/docs/user/en/guides/app-development/index.md
Executable file
|
|
@ -0,0 +1,3 @@
|
|||
# App Development
|
||||
|
||||
{index}
|
||||
14
frappe/docs/user/en/guides/app-development/index.txt
Executable file
14
frappe/docs/user/en/guides/app-development/index.txt
Executable file
|
|
@ -0,0 +1,14 @@
|
|||
adding-module-icons-on-desktop
|
||||
custom-module-icon
|
||||
generating-docs
|
||||
how-enable-developer-mode-in-frappe
|
||||
fetch-custom-field-value-from-master-to-all-related-transactions
|
||||
executing-code-on-doctype-events
|
||||
how-to-create-custom-fields-during-app-installation
|
||||
insert-a-document-via-api
|
||||
how-to-improve-a-standard-control
|
||||
overriding-link-query-by-custom-script
|
||||
single-type-doctype
|
||||
trigger-event-on-deletion-of-grid-row
|
||||
dialogs-types
|
||||
using-html-templates-in-javascript
|
||||
53
frappe/docs/user/en/guides/app-development/insert-a-document-via-api.md
Executable file
53
frappe/docs/user/en/guides/app-development/insert-a-document-via-api.md
Executable file
|
|
@ -0,0 +1,53 @@
|
|||
You can insert documents via a script using the `frappe.get_doc` method
|
||||
|
||||
### Examples:
|
||||
|
||||
#### 1. Insert a ToDo
|
||||
|
||||
todo = frappe.get_doc({"doctype":"ToDo", "description": "test"})
|
||||
todo.insert()
|
||||
|
||||
---
|
||||
|
||||
#### 2. Insert without the user's permissions being checked:
|
||||
|
||||
todo = frappe.get_doc({"doctype":"ToDo", "description": "test"})
|
||||
todo.insert(ignore_permissions = True)
|
||||
|
||||
|
||||
---
|
||||
|
||||
#### 3. Submit after inserting
|
||||
|
||||
todo = frappe.get_doc({"doctype":"ToDo", "description": "test"})
|
||||
todo.insert(ignore_permissions=True)
|
||||
todo.submit()
|
||||
|
||||
---
|
||||
|
||||
#### 4. Insert a document on saving of another document
|
||||
|
||||
class MyType(Document):
|
||||
def on_update(self):
|
||||
todo = frappe.get_doc({"doctype":"ToDo", "description": "test"})
|
||||
todo.insert()
|
||||
|
||||
----
|
||||
|
||||
#### 5. Insert a document with child tables:
|
||||
|
||||
sales_order = frappe.get_doc({
|
||||
"doctype": "Sales Order",
|
||||
"company": "_Test Company",
|
||||
"customer": "_Test Customer",
|
||||
"delivery_date": "2013-02-23",
|
||||
"sales_order_details": [
|
||||
{
|
||||
"item_code": "_Test Item Home Desktop 100",
|
||||
"qty": 10.0,
|
||||
"rate": 100.0,
|
||||
"warehouse": "_Test Warehouse - _TC"
|
||||
}
|
||||
]
|
||||
})
|
||||
sales_order.insert()
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
You can override the standard link query by using `set_query`
|
||||
|
||||
### 1. Adding Fitlers
|
||||
|
||||
You can add filters to the query:
|
||||
|
||||
frappe.ui.form.on("Bank Reconciliation", "onload", function(frm) {
|
||||
cur_frm.set_query("bank_account", function() {
|
||||
return {
|
||||
"filters": {
|
||||
"account_type": "Bank",
|
||||
"group_or_ledger": "Ledger"
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
A more complex query:
|
||||
|
||||
frappe.ui.form.on("Bank Reconciliation", "onload", function(frm){
|
||||
cur_frm.set_query("bank_account", function(){
|
||||
return {
|
||||
"filters": [
|
||||
["Bank Account": "account_type", "=", "Bank"],
|
||||
["Bank Account": "group_or_ledger", "!=", "Group"]
|
||||
]
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
---
|
||||
|
||||
### 2. Calling a Different Method to Generate Results
|
||||
|
||||
You can also set a server side method to be called on the query:
|
||||
|
||||
frm.set_query("item_code", "items", function() {
|
||||
return {
|
||||
query: "erpnext.controllers.queries.item_query",
|
||||
filters: frm.doc.enquiry_type === "Maintenance" ?
|
||||
{"is_service_item": "Yes"} : {"is_sales_item": "Yes"}
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
|
||||
#### Custom Method
|
||||
|
||||
The custom method should return a list of items for auto select. If you want to send additional data, you can send multiple columns in the list.
|
||||
|
||||
Parameters to the custom method are:
|
||||
|
||||
`def custom_query(doctype, txt, searchfield, start, page_len, filters)`
|
||||
|
||||
**Example:**
|
||||
|
||||
# searches for leads which are not converted
|
||||
def lead_query(doctype, txt, searchfield, start, page_len, filters):
|
||||
return frappe.db.sql("""select name, lead_name, company_name from `tabLead`
|
||||
where docstatus < 2
|
||||
and ifnull(status, '') != 'Converted'
|
||||
and ({key} like %(txt)s
|
||||
or lead_name like %(txt)s
|
||||
or company_name like %(txt)s)
|
||||
{mcond}
|
||||
order by
|
||||
if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999),
|
||||
if(locate(%(_txt)s, lead_name), locate(%(_txt)s, lead_name), 99999),
|
||||
if(locate(%(_txt)s, company_name), locate(%(_txt)s, company_name), 99999),
|
||||
name, lead_name
|
||||
limit %(start)s, %(page_len)s""".format(**{
|
||||
'key': searchfield,
|
||||
'mcond':get_match_cond(doctype)
|
||||
}), {
|
||||
'txt': "%%%s%%" % txt,
|
||||
'_txt': txt.replace("%", ""),
|
||||
'start': start,
|
||||
'page_len': page_len
|
||||
})
|
||||
|
||||
|
||||
|
||||
For more examples see:
|
||||
|
||||
[https://github.com/frappe/erpnext/blob/develop/erpnext/controllers/queries.py](https://github.com/frappe/erpnext/blob/develop/erpnext/controllers/queries.py)
|
||||
|
||||
<!-- markdown -->
|
||||
9
frappe/docs/user/en/guides/app-development/single-type-doctype.md
Executable file
9
frappe/docs/user/en/guides/app-development/single-type-doctype.md
Executable file
|
|
@ -0,0 +1,9 @@
|
|||
DocTypes have a table associated with them. For example DocType **Customer** will have a table `tabCustomer` associated with it.
|
||||
|
||||
**Single** type DocTypes have no table associated and there is only one Document for it. This is similar to the Singleton pattern in Java. Single DocTypes are ideal for saving Settings (that are globally applicable) and for wizard / helper type forms that have no documents, but when the DocType is used for the Form UI.
|
||||
|
||||
The data in Single DocType is stored in `tabSingles` (`doctype`, `field`, `value`)
|
||||
|
||||
#### Examples
|
||||
|
||||
In Frappe, Single types are **System Settings** and **Customize Form**
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
To trigger an event when a row from a grid has been deleted, you need to add a handler the `fieldname_remove` event, where fieldname is the fieldname of the grid (Table)
|
||||
|
||||
<h3>Example for add</h3>
|
||||
|
||||
<p>Recalculate totals when a Journal Entry row has been added</p>
|
||||
|
||||
frappe.ui.form.on("Journal Entry Account", "accounts_add", function(frm){
|
||||
cur_frm.cscript.update_totals(frm.doc);
|
||||
});
|
||||
|
||||
<!-- markdown -->
|
||||
|
||||
<h3>Example for delete</h3>
|
||||
|
||||
<p>Recalculate totals when a Journal Entry row has been deleted</p>
|
||||
|
||||
frappe.ui.form.on("Journal Entry Account", "accounts_remove", function(frm){
|
||||
cur_frm.cscript.update_totals(frm.doc);
|
||||
});
|
||||
|
||||
<!-- markdown -->
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
Often while building javascript interfaces, there is a need to render DOM as an HTML template. Frappe Framework uses John Resig's Microtemplate script to render HTML templates in the Desk application.
|
||||
|
||||
> Note 1: In Frappe we use the Jinja-like `{%` tags to embed code rather than the standard `<%`
|
||||
|
||||
> Note 2: Never use single quotes `'` inside the HTML template.
|
||||
|
||||
To render a template,
|
||||
|
||||
1. Create a template `html` file in your app. e.g. `address_list.html`
|
||||
1. Add it to `build.json` for your app (you can include it in `frappe.min.js` or your own javascript file).
|
||||
1. To render it in your app, use `frappe.render(frappe.templates.address_list, {[context]})`
|
||||
|
||||
#### Example Template:
|
||||
|
||||
From `erpnext/public/js/templates/address_list.js`
|
||||
|
||||
|
||||
<p><button class="btn btn-sm btn-default btn-address">
|
||||
<i class="icon-plus"></i> New Address</button></p>
|
||||
{% for(var i=0, l=addr_list.length; i<l; i++) { %}
|
||||
<hr>
|
||||
<a href="#Form/Address/{%= addr_list[i].name %}" class="btn btn-sm btn-default pull-right">
|
||||
{%= __("Edit") %}</a>
|
||||
<h4>{%= addr_list[i].address_type %}</h4>
|
||||
<div style="padding-left: 15px;">
|
||||
<div>
|
||||
{% if(addr_list[i].is_primary_address) { %}<span class="label label-info">
|
||||
{%= __("Primary") %}</span>{% } %}
|
||||
{% if(addr_list[i].is_shipping_address) { %}<span class="label label-default">
|
||||
{%= __("Shipping") %}</span>{% } %}
|
||||
</div>
|
||||
<p style="margin-top: 5px;">{%= addr_list[i].display %}</p>
|
||||
</div>
|
||||
{% } %}
|
||||
{% if(!addr_list.length) { %}
|
||||
<p class="text-muted">{%= __("No address added yet.") %}</p>
|
||||
{% } %}
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- markdown -->
|
||||
109
frappe/docs/user/en/guides/basics/apps.md
Executable file
109
frappe/docs/user/en/guides/basics/apps.md
Executable file
|
|
@ -0,0 +1,109 @@
|
|||
# Frappe Apps
|
||||
|
||||
Frappe Apps are Python packages which use the Frappe platform. They can live
|
||||
anywhere on the [Python
|
||||
path](https://docs.python.org/2/tutorial/modules.html#the-module-search-path)
|
||||
and must have an entry in the `apps.txt` file.
|
||||
|
||||
|
||||
### Creating an app
|
||||
|
||||
Frappe ships with a boiler plate for a new app. The command `bench make-app
|
||||
app-name` helps you start a new app by starting an interactive shell.
|
||||
|
||||
|
||||
% bench make-app sample_app
|
||||
App Name: sample_app
|
||||
App Title: Sample App
|
||||
App Description: This is a sample app.
|
||||
App Publisher: Acme Inc.
|
||||
App Icon: icon-linux
|
||||
App Color: #6DAFC9
|
||||
App Email: info@example.com
|
||||
App URL: http://example.com
|
||||
App License: MIT
|
||||
|
||||
The above command would create an app with the following directory structure.
|
||||
|
||||
sample_app
|
||||
├── license.txt
|
||||
├── MANIFEST.in
|
||||
├── README.md
|
||||
├── sample_app
|
||||
│ ├── __init__.py
|
||||
│ ├── sample_app
|
||||
│ │ └── __init__.py
|
||||
│ ├── config
|
||||
│ │ ├── desktop.py
|
||||
│ │ └── __init__.py
|
||||
│ ├── hooks.py
|
||||
│ ├── modules.txt
|
||||
│ ├── patches.txt
|
||||
│ └── templates
|
||||
│ ├── generators
|
||||
│ │ └── __init__.py
|
||||
│ ├── __init__.py
|
||||
│ ├── pages
|
||||
│ │ └── __init__.py
|
||||
│ └── statics
|
||||
└── setup.py
|
||||
|
||||
Here, "App Icon" is a font awesome class that you can select from
|
||||
[http://fortawesome.github.io/Font-Awesome/icons/](http://fortawesome.github.io/Font-Awesome/icons/).
|
||||
|
||||
The boiler plate contains just enough files to show your app icon on the [Desk].
|
||||
|
||||
### Files in the app
|
||||
|
||||
#### `hooks.py`
|
||||
|
||||
The `hooks.py` file defines the metadata of your app and integration points
|
||||
with other parts of Frappe or Frappe apps. Examples of such parts include task
|
||||
scheduling or listening to updates to different documents in the system. For
|
||||
now, it just contains the details you entered during app creation.
|
||||
|
||||
|
||||
app_name = "sample-app"
|
||||
app_title = "Sample App"
|
||||
app_publisher = "Acme Inc."
|
||||
app_description = "This is a sample app."
|
||||
app_icon = "fa-linux"
|
||||
app_color = "black"
|
||||
app_email = "info@example.com"
|
||||
app_url = "http://example.com"
|
||||
app_version = 0.0.1
|
||||
|
||||
#### `modules.txt`
|
||||
|
||||
Modules in Frappe help you organize Documents in Frappe and they are defined in
|
||||
the `modules.txt` file in your app. It is necessary for every [DocType] to be
|
||||
attached to a module. By default a module by the name of your app is added.
|
||||
Also, each module gets an icon on the [Desk]. For example, the [ERPNext] app is
|
||||
organized in the following modules.
|
||||
|
||||
accounts
|
||||
buying
|
||||
home
|
||||
hr
|
||||
manufacturing
|
||||
projects
|
||||
selling
|
||||
setup
|
||||
stock
|
||||
support
|
||||
utilities
|
||||
contacts
|
||||
|
||||
### Adding app to a site
|
||||
|
||||
Once you have an app, whether it's the one you just created or any other you
|
||||
downloaded, you are required to do the following things.
|
||||
|
||||
Download the app via git
|
||||
|
||||
bench get-app https://github.com/org/app_name
|
||||
|
||||
Install the app to your site
|
||||
|
||||
bench --site app_name install-app app_name
|
||||
|
||||
273
frappe/docs/user/en/guides/basics/hooks.md
Executable file
273
frappe/docs/user/en/guides/basics/hooks.md
Executable file
|
|
@ -0,0 +1,273 @@
|
|||
# Hooks
|
||||
<!-- TODO: Add tables for quick reference -->
|
||||
|
||||
Hooks are the duct tape of the Frappe system. Hooks allow you to "hook" in to
|
||||
functionality and events of other parts of the Frappe system. Following are the
|
||||
official hooks from Frappe.
|
||||
|
||||
### Application Name and Details
|
||||
|
||||
1. `app_name` - slugified name with underscores e.g. "shopping\_cart"
|
||||
2. `app_title` - full title name e.g. "Frappe"
|
||||
3. `app_publisher`
|
||||
4. `app_description`
|
||||
5. `app_version`
|
||||
6. `app_icon` - font-awesome icon or image url
|
||||
7. `app_color` - hex colour background of the app icon
|
||||
|
||||
### Install Events
|
||||
|
||||
1. `before_install`
|
||||
2. `after_install`
|
||||
|
||||
The above hooks are called before and after installation of the app they are in.
|
||||
For example, [ERPNext](/apps/erpnext)'s hooks contains a line,
|
||||
|
||||
after_install = "erpnext.setup.install.after_install"
|
||||
|
||||
So, the function after\_install is imported and called after ERPNext is installed.
|
||||
|
||||
Note, the `before_install` and `after_install` hooks are called with no arguments.
|
||||
|
||||
### Boot Session
|
||||
|
||||
After a successful login, the Frappe JS Client requests for a resource called
|
||||
`bootinfo`. The `bootinfo` is available as a global in Javascript via
|
||||
`frappe.boot`. By default, the `bootinfo` contains
|
||||
|
||||
* System defaults
|
||||
* Notification status
|
||||
* Permissions
|
||||
* List of icons on desktop
|
||||
* User settings
|
||||
* Language and timezone info
|
||||
|
||||
If your app wants to modify bootinfo, it can declare a hook `boot_session`. The
|
||||
value is assumed to be a dotted path to a function and is called with one
|
||||
argument, bootinfo which it can modify and return.
|
||||
|
||||
Eg,
|
||||
|
||||
boot_session = "erpnext.startup.boot.boot_session"
|
||||
|
||||
### Notification configurations
|
||||
|
||||
The notification configuration hook is expected to return a Python dictionary.
|
||||
|
||||
{
|
||||
"for_doctype": {
|
||||
"Issue": {"status":"Open"},
|
||||
"Customer Issue": {"status":"Open"},
|
||||
},
|
||||
"for_module_doctypes": {
|
||||
"ToDo": "To Do",
|
||||
"Event": "Calendar",
|
||||
"Comment": "Messages"
|
||||
},
|
||||
"for_module": {
|
||||
"To Do": "frappe.core.notifications.get_things_todo",
|
||||
"Calendar": "frappe.core.notifications.get_todays_events",
|
||||
"Messages": "frappe.core.notifications.get_unread_messages"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
The above configuration has three parts,
|
||||
|
||||
1. `for_doctype` part of the above configuration marks any "Issue"
|
||||
or "Customer Issue" as unread if its status is Open
|
||||
2. `for_module_doctypes` maps doctypes to module's unread count.
|
||||
3. `for_module` maps modules to functions to obtain its unread count. The
|
||||
functions are called without any argument.
|
||||
|
||||
### Javascript / CSS Assets
|
||||
|
||||
The following hooks allow you to bundle built assets to your app for serving.
|
||||
There are two types of assets, app and web. The app assets are loaded in the
|
||||
Desk and web assets are loaded in the website.
|
||||
|
||||
1. `app_include_js`
|
||||
2. `app_include_css`
|
||||
3. `web_include_js`
|
||||
4. `web_include_css`
|
||||
|
||||
Eg,
|
||||
|
||||
app_include_js = "assets/js/erpnext.min.js"
|
||||
web_include_js = "assets/js/erpnext-web.min.js"
|
||||
|
||||
Note: to create an asset bundle (eg, assets/js/erpnext.min.js) the target file
|
||||
should be in build.json of your app.
|
||||
|
||||
### Configuring Reports
|
||||
|
||||
In the report view, you can force filters as per doctype using `dump_report_map`
|
||||
hook. The hook should be a dotted path to a Python function which will be called
|
||||
without any arguments. Example of output of this function is below.
|
||||
|
||||
|
||||
"Warehouse": {
|
||||
"columns": ["name"],
|
||||
"conditions": ["docstatus < 2"],
|
||||
"order_by": "name"
|
||||
}
|
||||
|
||||
Here, for a report with Warehouse doctype, would include only those records that
|
||||
are not cancelled (docstatus < 2) and will be ordered by name.
|
||||
|
||||
### Modifying Website Context
|
||||
|
||||
Context used in website pages can be modified by adding
|
||||
a `update_website_context` hook. This hook should be a dotted path to a function
|
||||
which will be called with a context (dictionary) argument.
|
||||
|
||||
### Customizing Email footer
|
||||
|
||||
By default, for every email, a footer with content, "Sent via Frappe" is sent.
|
||||
You can customize this globally by adding a `mail_footer` hook. The hook should
|
||||
be a dotted path to a variable.
|
||||
|
||||
### Session Creation Hook
|
||||
|
||||
You can attach custom logic to the event of a successful login using
|
||||
`on_session_creation` hook. The hook should be a dotted path to a Python
|
||||
function that takes login\_manager as an argument.
|
||||
|
||||
Eg,
|
||||
|
||||
def on_session_creation(login_manager):
|
||||
"""make feed"""
|
||||
if frappe.session['user'] != 'Guest':
|
||||
# log to timesheet
|
||||
pass
|
||||
|
||||
### Website Clear Cache
|
||||
|
||||
If you cache values in your views, the `website_clear_cache` allows you to hook
|
||||
methods that invalidate your caches when Frappe tries to clear cache for all
|
||||
website related pages.
|
||||
|
||||
### Document hooks
|
||||
|
||||
#### Permissions
|
||||
|
||||
#### Query Permissions
|
||||
You can customize how permissions are resolved for a DocType by hooking custom
|
||||
permission match conditions using the `permission_query_conditions` hook. This
|
||||
match condition is expected to be fragment for a where clause in an sql query.
|
||||
Structure for this hook is as follows.
|
||||
|
||||
|
||||
permission_query_conditions = {
|
||||
"{doctype}": "{dotted.path.to.function}",
|
||||
}
|
||||
|
||||
The output of the function should be a string with a match condition.
|
||||
Example of such a function,
|
||||
|
||||
|
||||
def get_permission_query_conditions():
|
||||
return "(tabevent.event_type='public' or tabevent.owner='{user}'".format(user=frappe.session.user)
|
||||
|
||||
The above function returns a fragment that permits an event to listed if it's
|
||||
public or owned by the current user.
|
||||
|
||||
#### Document permissions
|
||||
You can hook to `doc.has_permission` for any DocType and add special permission
|
||||
checking logic using the `has_permission` hook. Structure for this hook is,
|
||||
|
||||
has_permission = {
|
||||
"{doctype}": "{dotted.path.to.function}",
|
||||
}
|
||||
|
||||
The function will be passed the concerned document as an argument. It should
|
||||
True or a falsy value after running the required logic.
|
||||
|
||||
For Example,
|
||||
|
||||
def has_permission(doc):
|
||||
if doc.event_type=="Public" or doc.owner==frappe.session.user:
|
||||
return True
|
||||
|
||||
The above function permits an event if it's public or owned by the current user.
|
||||
|
||||
#### CRUD Events
|
||||
|
||||
You can hook to various CRUD events of any doctype, the syntax for such a hook
|
||||
is as follows,
|
||||
|
||||
doc_events = {
|
||||
"{doctype}": {
|
||||
"{event}": "{dotted.path.to.function}",
|
||||
}
|
||||
}
|
||||
|
||||
To hook to events of all doctypes, you can use the follwing syntax also,
|
||||
|
||||
doc_events = {
|
||||
"*": {
|
||||
"on_update": "{dotted.path.to.function}",
|
||||
}
|
||||
}
|
||||
|
||||
The hook function will be passed the doc in concern as the only argument.
|
||||
|
||||
##### List of events
|
||||
|
||||
* `validate`
|
||||
* `before_save`
|
||||
* `after_save`
|
||||
* `before_insert`
|
||||
* `after_insert`
|
||||
* `before_submit`
|
||||
* `before_cancel`
|
||||
* `before_update_after_submit`
|
||||
* `on_update`
|
||||
* `on_submit`
|
||||
* `on_cancel`
|
||||
* `on_update_after_submit`
|
||||
|
||||
|
||||
Eg,
|
||||
|
||||
doc_events = {
|
||||
"Cab Request": {
|
||||
"after_insert": topcab.schedule_cab",
|
||||
}
|
||||
}
|
||||
|
||||
### Scheduler Hooks
|
||||
|
||||
Scheduler hooks are methods that are run periodically in background. Structure for such a hook is,
|
||||
|
||||
scheduler_events = {
|
||||
"{event_name}": [
|
||||
"{dotted.path.to.function}"
|
||||
],
|
||||
}
|
||||
|
||||
#### Events
|
||||
|
||||
* `daily`
|
||||
* `daily_long`
|
||||
* `weekly`
|
||||
* `weekly_long`
|
||||
* `monthly`
|
||||
* `monthly_long`
|
||||
* `hourly`
|
||||
* `all`
|
||||
|
||||
The scheduler events require celery, celerybeat and redis (or a supported and
|
||||
configured broker) to be running. The events with suffix '\_long' are for long
|
||||
jobs. The `all` event is triggered everytime (as per the celerybeat interval).
|
||||
|
||||
Example,
|
||||
|
||||
scheduler_events = {
|
||||
"{daily}": [
|
||||
"erpnext.accounts.doctype.sales_invoice.sales_invoice.manage_recurring_invoices"
|
||||
],
|
||||
"{daily_long}": [
|
||||
"erpnext.setup.doctype.backup_manager.backup_manager.take_backups_daily"
|
||||
],
|
||||
}
|
||||
3
frappe/docs/user/en/guides/basics/index.md
Executable file
3
frappe/docs/user/en/guides/basics/index.md
Executable file
|
|
@ -0,0 +1,3 @@
|
|||
# Basics
|
||||
|
||||
{index}
|
||||
7
frappe/docs/user/en/guides/basics/index.txt
Executable file
7
frappe/docs/user/en/guides/basics/index.txt
Executable file
|
|
@ -0,0 +1,7 @@
|
|||
install
|
||||
apps
|
||||
sites
|
||||
site_config
|
||||
hooks
|
||||
translations
|
||||
writing-tests
|
||||
10
frappe/docs/user/en/guides/basics/install.md
Executable file
10
frappe/docs/user/en/guides/basics/install.md
Executable file
|
|
@ -0,0 +1,10 @@
|
|||
# Installing Frappe
|
||||
|
||||
## Frappe bench
|
||||
|
||||
The following steps help you setup an isolated environment (bench) to run and
|
||||
develop Frappe apps. A virtualenv is installed in the env directory. You can
|
||||
activate it by running `source ./env/bin/activate` or use execute using
|
||||
absolute/relative path (eg, `./env/bin/frappe`).
|
||||
|
||||
For more info, see [Frappe Bench](https://github.com/frappe/bench/)
|
||||
40
frappe/docs/user/en/guides/basics/site_config.md
Executable file
40
frappe/docs/user/en/guides/basics/site_config.md
Executable file
|
|
@ -0,0 +1,40 @@
|
|||
# Site Config
|
||||
|
||||
Settings for `sites/[site]/site_config.json`
|
||||
|
||||
`site_config.json` stores global settings for a particular site and is present in the site directory. Here is a list of properties you can set in `site_config.json`.
|
||||
|
||||
Example:
|
||||
|
||||
{
|
||||
"db_name": "test_frappe",
|
||||
"db_password": "test_frappe",
|
||||
"admin_password": "admin",
|
||||
}
|
||||
|
||||
### Mandatory Settings
|
||||
|
||||
- `db_name`: Database Name.
|
||||
- `db_password`: Database password.
|
||||
|
||||
### Optional Settings
|
||||
|
||||
- `db_host`: Database host if not `localhost`.
|
||||
- `admin_password`: Default Password for "Administrator".
|
||||
- `mute_emails`: Stops email sending if true.
|
||||
- `deny_multiple_logins`: Stop users from having more than one active session.
|
||||
- `root_password`: MariaDB root password.
|
||||
|
||||
### Defaut Outgoing Email Settings
|
||||
|
||||
- `mail_server`: SMTP server hostname.
|
||||
- `mail_port`: STMP port.
|
||||
- `use_ssl`: Connect via SSL / TLS.
|
||||
- `mail_login`: Login id for SMTP server.
|
||||
- `mail_password`: Password for SMTP server.
|
||||
|
||||
### Developer Settings
|
||||
|
||||
- `developer_mode`: If developer mode is set, DocType changes are automatically updated in files.
|
||||
- `disable_website_cache`: Don't cache website pages.
|
||||
- `logging`: writes logs if **1**, writes queries also if set to **2**.
|
||||
82
frappe/docs/user/en/guides/basics/sites.md
Executable file
82
frappe/docs/user/en/guides/basics/sites.md
Executable file
|
|
@ -0,0 +1,82 @@
|
|||
# Sites
|
||||
|
||||
## Sites Directory
|
||||
|
||||
Frappe is a multitenant platform and each tenant is called a site. Sites exist
|
||||
in a directory called `sites_dir`, assumed as the current working directory when
|
||||
running a frappe command or other services like Celery worker or a WSGI server.
|
||||
|
||||
You can set `sites_dir` with an environment variable `SITES_DIR` or pass
|
||||
`--sites_dir` option to the frappe command.
|
||||
|
||||
Apart from the sites, the `sites_dir` should contain the following.
|
||||
|
||||
#### apps.txt
|
||||
|
||||
`apps.txt` contain a list of Python packages to treat as Frappe apps. Every
|
||||
frappe app that you intend to use in you site should have an entry in this file.
|
||||
Also, they should be in the `PYTHONPATH`. For more information, refer
|
||||
[Frappe Apps](/help/apps).
|
||||
|
||||
#### common\_site\_config.json
|
||||
|
||||
`common_site_config.json` is an optional file. Configuration common to all sites
|
||||
can be put in this file.
|
||||
|
||||
#### assets
|
||||
|
||||
Assets contain files that are required to be served for the browser client.
|
||||
These generally include *.js, *.css, *.png files. This directory is auto
|
||||
generated using the `bench build` command.
|
||||
|
||||
#### languages.txt
|
||||
|
||||
`languages.txt` is an autogenerated file which maps every language to it's code.
|
||||
|
||||
## Site
|
||||
|
||||
A site is a directory in `sites_dir` which represents a tenant in Frappe Platform.
|
||||
|
||||
|
||||
### Directory Structure
|
||||
|
||||
site
|
||||
├── locks
|
||||
├── private
|
||||
│ └── backups
|
||||
├── public
|
||||
│ └── files
|
||||
│ └── testfile.txt
|
||||
└── site_config.json
|
||||
|
||||
* `locks` directory is used by the scheduler to synchronize various jobs using
|
||||
the [file locking concept](http://en.wikipedia.org/wiki/File_locking).
|
||||
|
||||
* `private` directory contains files that require authentication to access.
|
||||
Presently, it is limited only to backups.
|
||||
|
||||
* `public` directory contains files that can directly served. In the above
|
||||
example, `testfile.txt` can be accessed by the URL,
|
||||
http://site/files/testfile.txt
|
||||
|
||||
* `site_config.json` contains site specific configuration
|
||||
|
||||
### Site Config
|
||||
|
||||
[See configuration options for `site_config.json`](/docs/user-guide/site_config.md)
|
||||
|
||||
### Site Resolution
|
||||
|
||||
While responding to an HTTP request, a site is automatically selected based on,
|
||||
|
||||
* `Host` header in the HTTP request matches a site
|
||||
* `X-Frappe-Site-Name` header in the HTTP request matches a site
|
||||
|
||||
It is also possible to force the development server to serve a specific site by
|
||||
starting it with the following command.
|
||||
`bench --site SITENAME serve`
|
||||
|
||||
|
||||
### Adding a new site
|
||||
|
||||
`frappe new-site SITENAME`
|
||||
86
frappe/docs/user/en/guides/basics/translations.md
Executable file
86
frappe/docs/user/en/guides/basics/translations.md
Executable file
|
|
@ -0,0 +1,86 @@
|
|||
<!-- jinja -->
|
||||
<!-- static -->
|
||||
|
||||
This document shows how to translations are managed in ERPNext and how to add
|
||||
a new language or update translations of an existing language.
|
||||
|
||||
### 1. Source
|
||||
|
||||
Translatable text exists in 3 main sources:
|
||||
|
||||
1. Javascript Code Files (both framework and application)
|
||||
2. Python Code Files
|
||||
3. DocTypes (names, labels and select options)
|
||||
|
||||
#### Strings in Code Files
|
||||
|
||||
Strings in code files are annotated using the `_` (underscore) method
|
||||
|
||||
1. In Python it is the `frappe._` method. Example:
|
||||
|
||||
`frappe._("String {0} must be translated".format(txt))`
|
||||
|
||||
2. In Javascript it is the `__` method. Example:
|
||||
|
||||
`__("String {0} must be translated", [txt])`
|
||||
|
||||
**Note:** If you find translatable strings are not properly annotated using the `_`
|
||||
method, you can add them in the code and rebuild the translations.
|
||||
|
||||
### 2. How Translations Are Picked up During Execution
|
||||
|
||||
Whenever a translation is called via the _ method, the entire translation
|
||||
dictionaries from all apps are built and stored in memcache.
|
||||
|
||||
Based on the user preferences or request preferences, the appropriate
|
||||
translations are loaded at the time of request on the server side. Or if
|
||||
metadata (DocType) is queried, then the appropriate translations are appended
|
||||
when the DocType data is requested.
|
||||
|
||||
The underscore `_` method will replace the strings based on the available
|
||||
translations loaded at the time.
|
||||
|
||||
### 3. Adding New Translations
|
||||
|
||||
1. To find untranslated strings, run `bench get-untranslated [lang] [path]`
|
||||
1. Add the translated strings in another file in the same order
|
||||
1. run `bench update-translations [lang] [path of untranslated strings] [path of translated strings]`
|
||||
|
||||
### 4. Improving Translations:
|
||||
|
||||
For updating translations, please go to the to [the translation portal](https://frappe.io/translator).
|
||||
|
||||
If you want to do it directly via code:
|
||||
|
||||
To improve an existing translation, just edit the master translation files in
|
||||
the `translations` of each app
|
||||
|
||||
> Please contribute your translations back to ERPNext by sending us a Pull
|
||||
Request.
|
||||
|
||||
### 5. Bootstrapping a New Language
|
||||
|
||||
If you want to add a new language it is similar to adding new translations. You need to first export all the translations strings in one file, get them translated via Google Translate Tool or Bing Translate Tool and then import the translations into individual apps.
|
||||
|
||||
**Step 1: Export to a file**
|
||||
|
||||
$ bench get-untranslated [lang] [path]
|
||||
|
||||
**Step 2: Translate**
|
||||
|
||||
Create another file with updated translations (in the same order as the source file). For this you can use the [Google Translator Toolkit](https://translate.google.com/toolkit) or [Bing Translator](http://www.bing.com/translator/).
|
||||
|
||||
**Step 3: Import your translations**
|
||||
|
||||
$ bench update-translations [lang] [source path] [translated path]
|
||||
|
||||
**Step 4: Update `languages.txt`**
|
||||
|
||||
Add your language in `apps/languages.txt` and also `frappe/data/languages.txt` (fore new bench installs)
|
||||
|
||||
**Step 5: Commit each app and push**
|
||||
|
||||
A new file will be added to the `translations` folder in each app. You need to add that file and push to your repo. Then send us a pull-request.
|
||||
|
||||
---
|
||||
|
||||
109
frappe/docs/user/en/guides/basics/writing-tests.md
Executable file
109
frappe/docs/user/en/guides/basics/writing-tests.md
Executable file
|
|
@ -0,0 +1,109 @@
|
|||
# Writing Tests
|
||||
|
||||
### Introduction
|
||||
|
||||
Frappe provides some basic tooling to quickly write automated tests. There are some basic rules:
|
||||
|
||||
1. Test can be anywhere in your repository but must begin with `test_` and should be a `.py` file.
|
||||
1. Tests must run on a site that starts with `test_`. This is to prevent accidental loss of data.
|
||||
1. Test stubs are automatically generated for new DocTypes.
|
||||
1. Frappe test runner will automatically build test records for dependant DocTypes identified by the `Link` type field (Foreign Key)
|
||||
1. Tests can be executed using `bench run-tests`
|
||||
1. For non-DocType tests, you can write simple unittests and prefix your file names with `test_`.
|
||||
|
||||
### Tests for a DocType
|
||||
|
||||
#### Writing DocType Tests:
|
||||
|
||||
1. Records that are used for testing are stored in a file `test_records.json` in the doctype folder. [For example see the Event Tests](https://github.com/frappe/frappe/blob/develop/frappe/core/doctype/event/test_records.json).
|
||||
1. Test cases are in a file named `test_[doctype].py`
|
||||
1. To provide the test records (and dependencies) call `test_records = frappe.get_test_records('Event')` in your test case file.
|
||||
|
||||
#### Example (for `test_records.json`):
|
||||
|
||||
[
|
||||
{
|
||||
"doctype": "Event",
|
||||
"subject":"_Test Event 1",
|
||||
"starts_on": "2014-01-01",
|
||||
"event_type": "Public"
|
||||
},
|
||||
{
|
||||
"doctype": "Event",
|
||||
"starts_on": "2014-01-01",
|
||||
"subject":"_Test Event 2",
|
||||
"event_type": "Private"
|
||||
},
|
||||
{
|
||||
"doctype": "Event",
|
||||
"starts_on": "2014-01-01",
|
||||
"subject":"_Test Event 3",
|
||||
"event_type": "Private",
|
||||
"event_individuals": [{
|
||||
"person": "test1@example.com"
|
||||
}]
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
#### Example (for `test_event.py`):
|
||||
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# MIT License. See license.txt
|
||||
|
||||
import frappe
|
||||
import frappe.defaults
|
||||
import unittest
|
||||
|
||||
# load test records and dependencies
|
||||
test_records = frappe.get_test_records('Event')
|
||||
|
||||
class TestEvent(unittest.TestCase):
|
||||
def tearDown(self):
|
||||
frappe.set_user("Administrator")
|
||||
|
||||
def test_allowed_public(self):
|
||||
frappe.set_user("test1@example.com")
|
||||
doc = frappe.get_doc("Event", frappe.db.get_value("Event", {"subject":"_Test Event 1"}))
|
||||
self.assertTrue(frappe.has_permission("Event", doc=doc))
|
||||
|
||||
def test_not_allowed_private(self):
|
||||
frappe.set_user("test1@example.com")
|
||||
doc = frappe.get_doc("Event", frappe.db.get_value("Event", {"subject":"_Test Event 2"}))
|
||||
self.assertFalse(frappe.has_permission("Event", doc=doc))
|
||||
|
||||
def test_allowed_private_if_in_event_user(self):
|
||||
frappe.set_user("test1@example.com")
|
||||
doc = frappe.get_doc("Event", frappe.db.get_value("Event", {"subject":"_Test Event 3"}))
|
||||
self.assertTrue(frappe.has_permission("Event", doc=doc))
|
||||
|
||||
def test_event_list(self):
|
||||
frappe.set_user("test1@example.com")
|
||||
res = frappe.get_list("Event", filters=[["Event", "subject", "like", "_Test Event%"]], fields=["name", "subject"])
|
||||
self.assertEquals(len(res), 2)
|
||||
subjects = [r.subject for r in res]
|
||||
self.assertTrue("_Test Event 1" in subjects)
|
||||
self.assertTrue("_Test Event 3" in subjects)
|
||||
self.assertFalse("_Test Event 2" in subjects)
|
||||
|
||||
#### Running Tests
|
||||
|
||||
To run a test for a doctype
|
||||
|
||||
bench run-tests --doctype [doctype]
|
||||
|
||||
This function will build all the test dependencies and run your tests.
|
||||
|
||||
### Running All Tests
|
||||
|
||||
To run all tests:
|
||||
|
||||
bench run-tests
|
||||
|
||||
---
|
||||
|
||||
## Client Side Testing (Using Selenium)
|
||||
|
||||
> This feature is still under development.
|
||||
|
||||
For an example see, [https://github.com/frappe/erpnext/blob/develop/erpnext/tests/sel_tests.py](https://github.com/frappe/erpnext/blob/develop/erpnext/tests/sel_tests.py)
|
||||
23
frappe/docs/user/en/guides/data/import-large-csv-file.md
Executable file
23
frappe/docs/user/en/guides/data/import-large-csv-file.md
Executable file
|
|
@ -0,0 +1,23 @@
|
|||
To import very large CSV files, you can use the bench utility `import-csv`.
|
||||
|
||||
The benefit is that this is not subject to timeouts if you use the web interface.
|
||||
|
||||
Here is an example:
|
||||
|
||||
bench --site test.erpnext.com import-csv ~/Downloads/Activity_Type.csv
|
||||
|
||||
### Help
|
||||
|
||||
$ bench import-csv --help
|
||||
Usage: bench import-csv [OPTIONS] PATH
|
||||
|
||||
Import CSV using data import tool
|
||||
|
||||
Options:
|
||||
--only-insert Do not overwrite existing records
|
||||
--submit-after-import Submit document after importing it
|
||||
--ignore-encoding-errors Ignore encoding errors while coverting to unicode
|
||||
--help Show this message and exit.
|
||||
|
||||
|
||||
<!-- markdown -->
|
||||
3
frappe/docs/user/en/guides/data/index.md
Executable file
3
frappe/docs/user/en/guides/data/index.md
Executable file
|
|
@ -0,0 +1,3 @@
|
|||
# Data Management
|
||||
|
||||
{index}
|
||||
1
frappe/docs/user/en/guides/data/index.txt
Executable file
1
frappe/docs/user/en/guides/data/index.txt
Executable file
|
|
@ -0,0 +1 @@
|
|||
import-large-csv-file
|
||||
15
frappe/docs/user/en/guides/deployment/checking-problems-in-bench.md
Executable file
15
frappe/docs/user/en/guides/deployment/checking-problems-in-bench.md
Executable file
|
|
@ -0,0 +1,15 @@
|
|||
<!-- markdown -->
|
||||
|
||||
If you're experiencing delays in scheduled jobs or they don't seem to run, you run run the following command to diagnose the issue.
|
||||
|
||||
`bench doctor`
|
||||
|
||||
A desirable output is like below
|
||||
|
||||
|
||||
Workers online: True
|
||||
Pending tasks 0
|
||||
Timed out locks:
|
||||
|
||||
|
||||
We'll be adding more health checks soon.
|
||||
43
frappe/docs/user/en/guides/deployment/configuring-https.md
Executable file
43
frappe/docs/user/en/guides/deployment/configuring-https.md
Executable file
|
|
@ -0,0 +1,43 @@
|
|||
<!-- markdown -->
|
||||
### Get the required files
|
||||
|
||||
You can buy a SSL certificate from a trusted Certificate Authority or generate your own. For self signed certificates the browser will show a warning that the certificate is not trusted.
|
||||
|
||||
The files required are
|
||||
|
||||
* Certificate (usually with extension .crt)
|
||||
* Decrypted private key
|
||||
|
||||
If you have multiple certificates (primary and intermediate), you will have to concatenate them. For example,
|
||||
|
||||
cat your_certificate.crt CA.crt >> certificate_bundle.crt
|
||||
|
||||
Also make sure that your private key is not world readable. Generally, it is owned and readable only by root
|
||||
|
||||
chown root private.key
|
||||
chmod 600 private.key
|
||||
|
||||
### Move the two files to an appropriate location
|
||||
|
||||
mkdir /etc/nginx/conf.d/ssl
|
||||
mv private.key /etc/nginx/conf.d/ssl/private.key
|
||||
mv certificate_bundle.crt /etc/nginx/conf.d/ssl/certificate_bundle.crt
|
||||
|
||||
### Setup nginx config
|
||||
|
||||
Set the paths to the certificate and private key for your site
|
||||
|
||||
bench set-ssl-certificate site1.local /etc/nginx/ssl/certificate_bundle.crt
|
||||
bench set-ssl-key site1.local /etc/nginx/ssl/private.key
|
||||
|
||||
### Generate nginx config
|
||||
|
||||
bench setup nginx
|
||||
|
||||
### Reload nginx
|
||||
|
||||
service nginx reload
|
||||
|
||||
or
|
||||
|
||||
systemctl reload nginx # for CentOS 7
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
|
||||
<p>Frappe handles failure of jobs in the following way,</p><p>1) If a job fails, (raises exception), it's logged in Scheduler Log and <code>logs/worker.error.log</code>.<br>2) Keeps a lock file and would not run anymore if lock file is there.<br>3) Raises LockTimeoutError in case the lock file is more than 10 minutes old.</p>
|
||||
|
||||
<p>You can configure email notification for scheduler errors. By writing a file, <code>sites/common_site_config.json</code> with content<br></p>
|
||||
|
||||
<pre><code class="json hljs">{
|
||||
"<span class="hljs-attribute">celery_error_emails</span>": <span class="hljs-value">{
|
||||
"<span class="hljs-attribute">ADMINS</span>": <span class="hljs-value">[
|
||||
[
|
||||
<span class="hljs-string">"Person 1"</span>,
|
||||
<span class="hljs-string">"person1@example.com"</span>
|
||||
],
|
||||
[
|
||||
<span class="hljs-string">"Person2 "</span>,
|
||||
<span class="hljs-string">"person2@example.com"</span>
|
||||
]
|
||||
]</span>,
|
||||
"<span class="hljs-attribute">SERVER_EMAIL</span>": <span class="hljs-value"><span class="hljs-string">"exceptions@example.com"</span>
|
||||
</span>}
|
||||
</span>}</code></pre>
|
||||
|
||||
<p>One limitation is that it'll use local mailserver on port 25 to send the emails.</p>
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
While using a virtual machine, links within emails will be point to your host, e.g. localhost, like **http://localhost/set-password** etc.
|
||||
|
||||
Frappe will automatically extract the host name from the incoming request, or from the `host_name` property from `site_config`.
|
||||
|
||||
### bench set-config
|
||||
|
||||
To fix this, you can use **bench set-config** to set your public IP or domain name as the host name.
|
||||
|
||||
#### Example:
|
||||
|
||||
bench --site mysite.com set-config host_name mysite.com
|
||||
|
||||
---
|
||||
|
||||
Or edit the `frappe-bench/sites/mysite.com/site_config.json` and add a `host_name` property.
|
||||
|
||||
|
||||
<!-- markdown -->
|
||||
67
frappe/docs/user/en/guides/deployment/how-to-enable-social-logins.md
Executable file
67
frappe/docs/user/en/guides/deployment/how-to-enable-social-logins.md
Executable file
|
|
@ -0,0 +1,67 @@
|
|||
Use Facebook, Google or GitHub authentication to login to Frappe, and your users will be spared from remembering another password.
|
||||
|
||||
The system uses the **Email ID** supplied by these services to **match with an existing user** in Frappe. If no such user is found, **a new user is created** of the default type **Website User**, if Signup is not disabled in Website Settings. Any System Manager can later change the user type from **Website User** to **System User**, so that the user can access the Desktop.
|
||||
|
||||
<figure class="text-center">
|
||||
<img src="/assets/frappe_io/images/how-to/social-logins-1.png"
|
||||
alt="Login screen with Social Logins enabled">
|
||||
<figcaption>Login screen with Social Logins enabled</figcaption>
|
||||
</figure>
|
||||
|
||||
To enable these signups, you need to have **Client ID** and **Client Secret** from these authentication services for your Frappe site. The Client ID and Client Secret are to be set in Website > Setup > Social Login Keys. Here are the steps to obtain these credentials.
|
||||
|
||||
> Use **https://{{ yoursite }}** if your site is HTTPS enabled.
|
||||
|
||||
---
|
||||
|
||||
### Facebook
|
||||
|
||||
1. Go to [https://developers.facebook.com](https://developers.facebook.com)
|
||||
1. Click on Apps (topbar) > New App, fill in the form.
|
||||
1. Go to Settings > Basic, set the **Contact Email** and save the changes.
|
||||
1. Go to Settings > Advanced, find the field **Valid OAuth redirect URIs**, and enter:
|
||||
**http://{{ yoursite }}/api/method/frappe.templates.pages.login.login\_via\_facebook**
|
||||
1. Save the changes in Advance tab.
|
||||
1. Go to Status & Review and switch on "Do you want to make this app and all its live features available to the general public?"
|
||||
1. Go to Dashboard, click on the show button besides App Secret, and copy the App ID and App Secret into **Desktop > Website > Setup > Social Login Keys**
|
||||
|
||||
<div class="embed-responsive embed-responsive-16by9">
|
||||
<iframe src="https://www.youtube.com/embed/zC6Q6gIfiw8" class="embed-responsive-item" allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
### Google
|
||||
|
||||
1. Go to [https://console.developers.google.com](https://console.developers.google.com)
|
||||
1. Create a new Project and fill in the form.
|
||||
1. Click on APIs & Auth > Credentials > Create new Client ID
|
||||
1. Fill the form with:
|
||||
- Web Application
|
||||
- Authorized JavaScript origins as **http://{{ yoursite }}**
|
||||
- Authorized redirect URI as
|
||||
**http://{{ yoursite }}/api/method/frappe.templates.pages.login.login\_via\_google**
|
||||
1. Go to the section **Client ID for web application** and copy the Client ID and Client Secret into **Desktop > Website > Setup > Social Login Keys**
|
||||
|
||||
<div class="embed-responsive embed-responsive-16by9">
|
||||
<iframe src="https://www.youtube.com/embed/w_EAttrE9sw" class="embed-responsive-item" allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
### GitHub
|
||||
|
||||
1. Go to [https://github.com/settings/applications](https://github.com/settings/applications)
|
||||
1. Click on **Register new application**
|
||||
1. Fill the form with:
|
||||
- Homepage URL as **http://{{ yoursite }}**
|
||||
- Authorization callback URL as
|
||||
**http://{{ yoursite }}/api/method/frappe.templates.pages.login.login\_via\_github**
|
||||
1. Click on Register application.
|
||||
1. Copy the generated Client ID and Client Secret into **Desktop > Website > Setup > Social Login Keys**
|
||||
|
||||
<div class="embed-responsive embed-responsive-16by9">
|
||||
<iframe src="https://www.youtube.com/embed/bG71DxxkVjQ" class="embed-responsive-item" allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
<!-- markdown -->
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
#### 1. DocType / Schema Changes
|
||||
|
||||
If you are in `developer_mode`, the `.json` files for each **DocType** are automatically updated.
|
||||
|
||||
When you update in your production using `--latest` or `bench update`, these changes are updated in the site's schema too!
|
||||
|
||||
#### 2. Permissions
|
||||
|
||||
Permissions do not get updated because the user may have changed them. To update permissions, you can add a new patch in the `patches.txt` of your app.
|
||||
|
||||
execute:frappe.permissions.reset_perms("[docype]")
|
||||
|
||||
<!-- markdown -->
|
||||
5
frappe/docs/user/en/guides/deployment/index.md
Executable file
5
frappe/docs/user/en/guides/deployment/index.md
Executable file
|
|
@ -0,0 +1,5 @@
|
|||
# Deployment
|
||||
|
||||
Deploying your apps on remote servers
|
||||
|
||||
{index}
|
||||
7
frappe/docs/user/en/guides/deployment/index.txt
Executable file
7
frappe/docs/user/en/guides/deployment/index.txt
Executable file
|
|
@ -0,0 +1,7 @@
|
|||
migrations
|
||||
how-to-migrate-doctype-changes-to-production
|
||||
how-to-change-host-name-from-localhost
|
||||
configuring-https
|
||||
checking-problems-in-bench
|
||||
email-notifications-for-failed-background-jobs
|
||||
how-to-enable-social-logins
|
||||
69
frappe/docs/user/en/guides/deployment/migrations.md
Executable file
69
frappe/docs/user/en/guides/deployment/migrations.md
Executable file
|
|
@ -0,0 +1,69 @@
|
|||
# Migrations
|
||||
|
||||
A project often undergoes changes related to database schema during course of
|
||||
its life. It may also be required patch existing data. Frappe bundles tools to
|
||||
handle these schenarios.
|
||||
|
||||
When you pull updates from any Frappe app (including Frappe), you should run
|
||||
`bench migrate` to apply schema changes and data migrations if any.
|
||||
|
||||
## Schema changes
|
||||
|
||||
You can edit a DocType to add, remove or change fields. On saving a DocType,
|
||||
a JSON file containing the DocType data is added to source tree of your app.
|
||||
When you add an app to a site, the DocTypes are installed using this JSON file.
|
||||
For making schema changes, it's required to set `developer_mode` in the
|
||||
configuration.
|
||||
|
||||
On running a sync (`bench migrate`), doctypes in the system are synced to
|
||||
their latest version from the JSON files in the app.
|
||||
|
||||
Note: Fields are soft deleted ie. the columns are not removed from the database
|
||||
table and however, they will not be visible in the documents. This is done to
|
||||
avoid any potential data loss situations and to allow you write related data
|
||||
migrations which might need values from deleted fields.
|
||||
|
||||
Note: Frappe doesn't support reverse schema migrations.
|
||||
|
||||
## Data Migrations
|
||||
|
||||
On introducing data related changes, you might want to run one off scripts to
|
||||
change existing data to match expectations as per new code.
|
||||
|
||||
To add a data migration to your code, you will have to write an `execute`
|
||||
function to a python module and add it to `patches.txt` of your app.
|
||||
|
||||
It is recommended to make a file with a patch number and name in its path and
|
||||
add it to a patches package (directory) in your app. You can then add a line
|
||||
with dotted path to the patch module to `patches.txt`.
|
||||
|
||||
The directory structure followed in Frappe is as below
|
||||
|
||||
|
||||
frappe
|
||||
└── patches
|
||||
└── 4_0
|
||||
└── my_awesome_patch.py
|
||||
|
||||
The patch can be added to `patches.txt` by adding a line like
|
||||
|
||||
frappe.patches.4_0.my_awesome_patch
|
||||
|
||||
The metadata ie. DocType available in the execute function will be the latest as
|
||||
per JSON files in the apps. However, you will not be able to access metadata of
|
||||
any previous states of the system.
|
||||
|
||||
#### One off Python statements
|
||||
|
||||
You can also add one off python statements in `patches.txt` using the syntax,
|
||||
execute:{python statement}
|
||||
|
||||
For example,
|
||||
execute:frappe.get_doc("User", "Guest").save()
|
||||
|
||||
Note: All lines in patches.txt have to be unique. If you want to run a line
|
||||
twice, you can make it unique by adding a distinct comment.
|
||||
|
||||
For Example,
|
||||
|
||||
execute:frappe.installer.make_site_dirs() #2014-02-19
|
||||
7
frappe/docs/user/en/guides/index.md
Executable file
7
frappe/docs/user/en/guides/index.md
Executable file
|
|
@ -0,0 +1,7 @@
|
|||
# Guides
|
||||
|
||||
The Frappe Framework is a server side and client side framework and is built with the philosophy make it a "battries included" framework. It has libraries and API for everything from authentication to reports.
|
||||
|
||||
In this section we will try and cover the most commonly used API on client and server side that will be useful for app development.
|
||||
|
||||
{index}
|
||||
7
frappe/docs/user/en/guides/index.txt
Executable file
7
frappe/docs/user/en/guides/index.txt
Executable file
|
|
@ -0,0 +1,7 @@
|
|||
basics
|
||||
app-development
|
||||
deployment
|
||||
reports-and-printing
|
||||
portal-development
|
||||
data
|
||||
integration
|
||||
3
frappe/docs/user/en/guides/integration/index.md
Executable file
3
frappe/docs/user/en/guides/integration/index.md
Executable file
|
|
@ -0,0 +1,3 @@
|
|||
# Integrations
|
||||
|
||||
{index}
|
||||
1
frappe/docs/user/en/guides/integration/index.txt
Executable file
1
frappe/docs/user/en/guides/integration/index.txt
Executable file
|
|
@ -0,0 +1 @@
|
|||
rest_api
|
||||
283
frappe/docs/user/en/guides/integration/rest_api.md
Executable file
283
frappe/docs/user/en/guides/integration/rest_api.md
Executable file
|
|
@ -0,0 +1,283 @@
|
|||
# REST API
|
||||
|
||||
Frappe ships with an HTTP API. There are two parts of this API.
|
||||
|
||||
1. Remote Procedure Calls (RPC)
|
||||
2. REST
|
||||
|
||||
## 1. RPC
|
||||
|
||||
A request to an endpoint `/api/method/{dotted.path.to.function}` will call
|
||||
a whitelisted python function. A function can be whitelisted using the
|
||||
`frappe.whitelist` decorator.
|
||||
|
||||
For example, Add the following to sample\_app/\_\_init\_\_.py
|
||||
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def ping():
|
||||
return 'pong'
|
||||
|
||||
<span class="label label-success">GET</span> http://frappe.local:8000**/api/method/sample_app.ping**
|
||||
|
||||
_Response:_
|
||||
|
||||
{
|
||||
"message": "pong"
|
||||
}
|
||||
|
||||
|
||||
## 2. REST
|
||||
|
||||
All documents in Frappe are available via a RESTful API with prefix
|
||||
`/api/resource/`.
|
||||
|
||||
### Login
|
||||
|
||||
To login, you will have to send a POST request to the login method.
|
||||
|
||||
<span class="label label-info">POST</span> http://frappe.local:8000**/api/method/login**
|
||||
|
||||
usr=Administrator&pwd=admin
|
||||
|
||||
_Response:_
|
||||
|
||||
{
|
||||
"full_name": "Administrator",
|
||||
"message": "Logged In"
|
||||
}
|
||||
|
||||
|
||||
Try to make an authenticated request
|
||||
|
||||
<span class="label label-success">GET</span> http://frappe.local:8000**/api/method/frappe.auth.get\_logged\_user**
|
||||
|
||||
_Response:_
|
||||
|
||||
{
|
||||
"message": "Administrator"
|
||||
}
|
||||
|
||||
|
||||
### Listing Documents
|
||||
|
||||
To list documents, the URL endpoint is `/api/resource/{doctype}` and the
|
||||
expected HTTP verb is GET.
|
||||
|
||||
Response is returned as JSON Object and the listing is an array in with the key `data`.
|
||||
|
||||
<span class="label label-success">GET</span> http://frappe.local:8000**/api/resource/Person**
|
||||
|
||||
_Response:_
|
||||
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"name": "000000012"
|
||||
},
|
||||
{
|
||||
"name": "000000008"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
#### Fields
|
||||
|
||||
By default, only name field is included in the listing, to add more fields, you
|
||||
can pass the fields param to GET request. The param has to be a JSON array.
|
||||
|
||||
<span class="label label-success">GET</span> http://frappe.local:8000**/api/resource/Person/?fields=["name", "first\_name"]**
|
||||
|
||||
_Response:_
|
||||
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"first_name": "Jane",
|
||||
"name": "000000012"
|
||||
},
|
||||
{
|
||||
"first_name": "John",
|
||||
"name": "000000008"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
#### Filters
|
||||
|
||||
You can filter the listing using sql conditions by passing them as the `filters`
|
||||
GET param. Each condition is an array of the format, [{doctype}, {field},
|
||||
{operator}, {operand}].
|
||||
|
||||
Eg, to filter persons with name Jane, pass a param `filters=[["Person", "first_name", "=", "Jane"]]`
|
||||
|
||||
<span class="label label-success">GET</span> http://frappe.local:8000**/api/resource/Person/**
|
||||
|
||||
_Response:_
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"name": "000000012"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
#### Pagination
|
||||
|
||||
All listings are returned paginated by 20 items. To change the page size, you
|
||||
can pass `limit_page_length`. To request succesive pages, pass `limit_start` as
|
||||
per your `limit_page_length`.
|
||||
|
||||
For Example, to request second page, pass `limit_start` as 20.
|
||||
|
||||
<span class="label label-success">GET</span> http://frappe.local:8000**/api/resource/DocType**
|
||||
|
||||
_Response:_
|
||||
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"name": "testdoc"
|
||||
},
|
||||
{
|
||||
"name": "Person"
|
||||
},
|
||||
|
||||
......
|
||||
|
||||
{
|
||||
"name": "Website Template"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
<span class="label label-success">GET</span> http://frappe.local:8000**/api/resource/DocType?limit_start=20**
|
||||
|
||||
_Response:_
|
||||
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"name": "Website Route"
|
||||
},
|
||||
{
|
||||
"name": "Version"
|
||||
},
|
||||
{
|
||||
"name": "Blog Post"
|
||||
},
|
||||
|
||||
......
|
||||
|
||||
{
|
||||
"name": "Custom Field"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
### CRUD
|
||||
|
||||
#### Create
|
||||
|
||||
You can create a document by sending a `POST` request to the url, `/api/resource/{doctype}`.
|
||||
|
||||
<span class="label label-info">POST</span> http://frappe.local:8000**/api/resource/Person**
|
||||
|
||||
_Body_:
|
||||
|
||||
data={"first_name": "Robert"}
|
||||
|
||||
_Response:_
|
||||
|
||||
{
|
||||
"data": {
|
||||
"first_name": "Robert",
|
||||
"last_name": null,
|
||||
"modified_by": "Administrator",
|
||||
"name": "000000051",
|
||||
"parent": null,
|
||||
"creation": "2014-05-04 17:22:38.037685",
|
||||
"modified": "2014-05-04 17:22:38.037685",
|
||||
"doctype": "Person",
|
||||
"idx": null,
|
||||
"parenttype": null,
|
||||
"owner": "Administrator",
|
||||
"docstatus": 0,
|
||||
"parentfield": null
|
||||
}
|
||||
}
|
||||
|
||||
#### Read
|
||||
|
||||
You can get a document by its name using the url, `/api/resource/{doctype}/{name}`
|
||||
|
||||
For Example,
|
||||
|
||||
<span class="label label-success">GET</span> http://frappe.local:8000**/api/resource/Person/000000012**
|
||||
|
||||
_Response:_
|
||||
|
||||
{
|
||||
"data": {
|
||||
"first_name": "Jane",
|
||||
"last_name": "Doe",
|
||||
"modified_by": "Administrator",
|
||||
"name": "000000012",
|
||||
"parent": null,
|
||||
"creation": "2014-04-25 17:56:51.105372",
|
||||
"modified": "2014-04-25 17:56:51.105372",
|
||||
"doctype": "Person",
|
||||
"idx": null,
|
||||
"parenttype": null,
|
||||
"owner": "Administrator",
|
||||
"docstatus": 0,
|
||||
"parentfield": null
|
||||
}
|
||||
}
|
||||
|
||||
### Update
|
||||
|
||||
You can create a document by sending a `PUT` request to the url,
|
||||
`/api/resource/{doctype}`. This acts like a `PATCH` HTTP request in which you do
|
||||
not have to send the whole document but only the parts you want to change.
|
||||
|
||||
For Example,
|
||||
|
||||
<span class="label label-primary">PUT</span> http://frappe.local:8000**/api/resource/Person/000000008**
|
||||
|
||||
_Body:_
|
||||
|
||||
data={"last_name": "Watson"}
|
||||
|
||||
_Response:_
|
||||
|
||||
{
|
||||
"data": {
|
||||
"first_name": "John ",
|
||||
"last_name": "Watson",
|
||||
"modified_by": "Administrator",
|
||||
"name": "000000008",
|
||||
"creation": "2014-04-25 17:26:22.728327",
|
||||
"modified": "2014-05-04 18:21:45.385995",
|
||||
"doctype": "Person",
|
||||
"owner": "Administrator",
|
||||
"docstatus": 0
|
||||
}
|
||||
}
|
||||
|
||||
### Delete
|
||||
|
||||
You can delete a document by its name by sending a `DELETE` request to the url,
|
||||
`/api/resource/{doctype}/{name}`.
|
||||
|
||||
For Example,
|
||||
|
||||
<span class="label label-danger">DELETE</span> http://frappe.local:8000**/api/resource/Person/000000008**
|
||||
|
||||
_Response:_
|
||||
|
||||
{"message":"ok"}
|
||||
5
frappe/docs/user/en/guides/portal-development/.md
Executable file
5
frappe/docs/user/en/guides/portal-development/.md
Executable file
|
|
@ -0,0 +1,5 @@
|
|||
# Pages
|
||||
|
||||
You can make your website by adding pages to the `/www` folder of your website. The urls of your site will match the path of your pages within the `/www` folder.
|
||||
|
||||
Pages must be `.html` or `.md` (Markdown) files. Basic HTML template is provided in frappe in `frappe/templates/base_template.html`
|
||||
39
frappe/docs/user/en/guides/portal-development/adding-pages.md
Executable file
39
frappe/docs/user/en/guides/portal-development/adding-pages.md
Executable file
|
|
@ -0,0 +1,39 @@
|
|||
# Adding Pages
|
||||
|
||||
To add pages, just add `.html` or `.md` files in the `www` folder. The pages must only have the content, not the `<html>` and `<body>` tags.
|
||||
|
||||
You can also write markdown pages
|
||||
|
||||
### Index
|
||||
|
||||
The first file in a folder must be called `index.md` or `index.html`
|
||||
|
||||
Either file must be present for the system to make this a valid folder to build pages.
|
||||
|
||||
### Markdown
|
||||
|
||||
# This is a title
|
||||
|
||||
This is some page content
|
||||
a [link](/link/to/page)
|
||||
|
||||
### Adding Links
|
||||
|
||||
Links urls to pages can be given without the `.html` extension for example `/home/link`
|
||||
|
||||
### Title
|
||||
|
||||
The first `<h1>` block if present will be the page title if not specified in a special tag. If no `<h1>` or title is specified, the file name will be the title.
|
||||
|
||||
### Adding CSS
|
||||
|
||||
You can also add a `.css` file with the same filename (e.g. `index.css` for `index.md`) that will be rendered with the page.
|
||||
|
||||
### Special Tags
|
||||
|
||||
1. `<!-- jinja -->` will make the page render in Jinja
|
||||
2. `<!-- title: Adding Pages -->` will add a custom title
|
||||
3. `<!-- no-breadcrumbs -->` will not add breadcrumbs in the page
|
||||
4. `<!-- static -->` will enable caching (if you have used Jinja templating)
|
||||
|
||||
{next}
|
||||
15
frappe/docs/user/en/guides/portal-development/building.md
Executable file
15
frappe/docs/user/en/guides/portal-development/building.md
Executable file
|
|
@ -0,0 +1,15 @@
|
|||
# Building the site
|
||||
|
||||
To make the pages to be served on the web, they must first be synced with the database. This is done by running:
|
||||
|
||||
bench --site sitename sync-www
|
||||
|
||||
To re-build the site
|
||||
|
||||
bench --site sitename --force sync-www
|
||||
|
||||
Clearing the website cache
|
||||
|
||||
bench --site sitename clear-website-cache
|
||||
|
||||
{next}
|
||||
17
frappe/docs/user/en/guides/portal-development/contents.md
Executable file
17
frappe/docs/user/en/guides/portal-development/contents.md
Executable file
|
|
@ -0,0 +1,17 @@
|
|||
# Table of Contents
|
||||
|
||||
You can add a table of contents by adding `{index}` string on a new line.
|
||||
|
||||
You can also make Previous and Next buttons by adding `previous` or `next` in `{}`
|
||||
|
||||
### Showing contents
|
||||
|
||||
# This is a title
|
||||
|
||||
Hello paragraph
|
||||
|
||||
### Contents:
|
||||
|
||||
{index}
|
||||
|
||||
{next}
|
||||
8
frappe/docs/user/en/guides/portal-development/context.md
Executable file
8
frappe/docs/user/en/guides/portal-development/context.md
Executable file
|
|
@ -0,0 +1,8 @@
|
|||
# Adding to context
|
||||
|
||||
You can add more data for the pages by adding a `.py` file with the same filename (e.g. `index.py` for `index.md`) with a `get_context` method.
|
||||
|
||||
def get_context(context):
|
||||
context.data = frappe.db.sql("some query")
|
||||
|
||||
{next}
|
||||
7
frappe/docs/user/en/guides/portal-development/index.md
Executable file
7
frappe/docs/user/en/guides/portal-development/index.md
Executable file
|
|
@ -0,0 +1,7 @@
|
|||
# Making Portals
|
||||
|
||||
You can make your website by adding pages to the `/www` folder of your website. The urls of your site will match the path of your pages within the `/www` folder.
|
||||
|
||||
Pages must be `.html` or `.md` (Markdown) files. Basic HTML template is provided in frappe in `frappe/templates/base_template.html`
|
||||
|
||||
{index}
|
||||
5
frappe/docs/user/en/guides/portal-development/index.txt
Executable file
5
frappe/docs/user/en/guides/portal-development/index.txt
Executable file
|
|
@ -0,0 +1,5 @@
|
|||
adding-pages
|
||||
ordering
|
||||
contents
|
||||
context
|
||||
building
|
||||
13
frappe/docs/user/en/guides/portal-development/ordering.md
Executable file
13
frappe/docs/user/en/guides/portal-development/ordering.md
Executable file
|
|
@ -0,0 +1,13 @@
|
|||
# Ordering
|
||||
|
||||
You can defining the ordering of pages in index by defining the index.txt file in your folder. The index.txt file must have the names (without extensions) of the pages in that folder indicating the order.
|
||||
|
||||
For example for this folder the `index.txt` looks like:
|
||||
|
||||
adding-pages
|
||||
ordering
|
||||
contents
|
||||
context
|
||||
building
|
||||
|
||||
{next}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
In a print format, you can get data from another document. For example in if you have a fields called `sales_order` in Sales Invoice, then you can get the sales order details using `frappe.get_doc`:
|
||||
|
||||
{% raw %}
|
||||
{% set sales_order_doc = frappe.get_doc("Sales Order", sales_order) %}
|
||||
|
||||
{{ sales_order_doc.customer }}
|
||||
{% endraw %}
|
||||
56
frappe/docs/user/en/guides/reports-and-printing/how-to-make-query-report.md
Executable file
56
frappe/docs/user/en/guides/reports-and-printing/how-to-make-query-report.md
Executable file
|
|
@ -0,0 +1,56 @@
|
|||
You can create tabulated reports using complex SQL queries by creating a new Report. These reports can be created by a System Manager and are stored in the Database
|
||||
|
||||
> Note: You will need System Manager Permissions for this.
|
||||
|
||||
To create a new Query Report:
|
||||
|
||||
### 1. Create a new Report
|
||||
|
||||

|
||||
|
||||
1. Set type as "Query Report"
|
||||
1. Set the reference DocType - Users that have access to the reference DocType will have access to the report
|
||||
1. Set the module - The report will appear in the "Custom Reports" section of the module.
|
||||
1. Add your Query
|
||||
|
||||
### 2. Set the Query
|
||||
|
||||
You can define complex queries such as:
|
||||
|
||||
|
||||
SELECT
|
||||
`tabProduction Order`.name as "Production Order:Link/Production Order:200",
|
||||
`tabProduction Order`.creation as "Date:Date:120",
|
||||
`tabProduction Order`.production_item as "Item:Link/Item:150",
|
||||
`tabProduction Order`.qty as "To Produce:Int:100",
|
||||
`tabProduction Order`.produced_qty as "Produced:Int:100"
|
||||
FROM
|
||||
`tabProduction Order`
|
||||
WHERE
|
||||
`tabProduction Order`.docstatus=1
|
||||
AND ifnull(`tabProduction Order`.produced_qty,0) < `tabProduction Order`.qty
|
||||
AND EXISTS (SELECT name from `tabStock Entry` where production_order =`tabProduction Order`.name)
|
||||
|
||||
1. To format the columns, set labels for each column in the format: [Label]:[Field Type]/[Options]:[Width]
|
||||
|
||||
### 3. Check the Report
|
||||
|
||||

|
||||
|
||||
### 4. Advanced (adding filters)
|
||||
|
||||
If you are making a standard report, you can add filters in your query report just like [script reports](https://frappe.io/kb/reports/how-to-make-script-reports) by adding a `.js` file in your query report folder. To include filters in your query, use `%(filter_key)s` where your filter value will be shown.
|
||||
|
||||
For example
|
||||
|
||||
SELECT ... FROM ... WHERE item_code = %(item_code)s ORDER BY ...
|
||||
|
||||
---
|
||||
|
||||
### Note: Standard Script Report
|
||||
|
||||
If you are developing a standard report for an app, make sure to set "Is Standard" as "Yes"
|
||||
|
||||
|
||||
|
||||
<!-- markdown -->
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
# Script Report
|
||||
|
||||
You can create tabulated reports using server side scripts by creating a new Report.
|
||||
|
||||
> Note: You will need Administrator Permissions for this.
|
||||
|
||||
Since these reports give you unrestricted access via Python scripts, they can only be created by Administrators. The script part of the report becomes a part of the repository of the application. If you have not created an app, [read this](/developers/guide).
|
||||
|
||||
> Note: You must be in [Developer Mode](/developers/how-to/enable-developer-mode) to do this
|
||||
|
||||
### 1. Create a new Report
|
||||
|
||||

|
||||
|
||||
1. Set Report Type as "Script Report"
|
||||
1. Set "Is Standard" as "Yes"
|
||||
1. Select the Module in which you want to add this report
|
||||
1. In the module folder (for example if it is Accounts in ERPnext the folder will be `erpnext/accounts/report/[report-name]`) you will see that templates for the report files will be created.
|
||||
1. In the `.js` file, you can set filters for the reports
|
||||
1. In the `.py` file, you can write the script that will generate the report
|
||||
|
||||
### 2. Add Filters
|
||||
|
||||
You can add filters in the `.js`. See an example below:
|
||||
|
||||
frappe.query_reports["Accounts Receivable"] = {
|
||||
"filters": [
|
||||
{
|
||||
"fieldname":"company",
|
||||
"label": __("Company"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Company",
|
||||
"default": frappe.defaults.get_user_default("company")
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
1. These properties are the same as you would set in a DocField in a DocType
|
||||
|
||||
### 3. Add the Script
|
||||
|
||||
In the `.py` file you can add the script for generating the report.
|
||||
|
||||
1. In the `execute` method, two lists `columns` and `data` are returned
|
||||
2. Columns must be a list of labels in the same format as query report. **[Label]:[Field Type]/[Options]:[Width]**. For example `Item:Link/Item:150`
|
||||
3. You can use all server side modules to build your report.
|
||||
4. For example see existing reports. ([Balance Sheet](https://github.com/frappe/erpnext/blob/develop/erpnext/accounts/report/balance_sheet/balance_sheet.py))
|
||||
|
||||
### 4. Commit and Push the app
|
||||
|
||||
Don't forget to commit and push your app.
|
||||
1
frappe/docs/user/en/guides/reports-and-printing/index.md
Executable file
1
frappe/docs/user/en/guides/reports-and-printing/index.md
Executable file
|
|
@ -0,0 +1 @@
|
|||
# Reports and Printing
|
||||
5
frappe/docs/user/en/guides/reports-and-printing/index.txt
Executable file
5
frappe/docs/user/en/guides/reports-and-printing/index.txt
Executable file
|
|
@ -0,0 +1,5 @@
|
|||
how-to-make-script-reports
|
||||
how-to-make-query-report
|
||||
getting-information-from-another-document-in-print-format
|
||||
where-do-i-find-standard-print-formats
|
||||
print-format-for-reports
|
||||
70
frappe/docs/user/en/guides/reports-and-printing/print-format-for-reports.md
Executable file
70
frappe/docs/user/en/guides/reports-and-printing/print-format-for-reports.md
Executable file
|
|
@ -0,0 +1,70 @@
|
|||
# Report Print Formats
|
||||
|
||||
In version 4.1 we introduce Report Print Formats. These are HTML templates that you can use to format Query Report data for printing.
|
||||
|
||||
### 1. Creating New Print Formats
|
||||
|
||||
To create a new Print Format, just drop in a `.html` file in the folder of the query report. For example, for the [General Ledger](https://github.com/frappe/erpnext/tree/develop/erpnext/accounts/report/general_ledger) report in ERPNext, you can drop in a file called `general_ledger.html` along side the `.js` and `.py` files.
|
||||
|
||||
##### Tree Of `erpnext/accounts/general_ledger`
|
||||
|
||||
general_ledger/
|
||||
├── __init__.py
|
||||
├── general_ledger.html
|
||||
├── general_ledger.js
|
||||
├── general_ledger.json
|
||||
└── general_ledger.py
|
||||
|
||||
|
||||
### 2. Templating
|
||||
|
||||
For templating, we use an adapted version of [John Resig's microtemplating script](http://ejohn.org/blog/javascript-micro-templating/). If you know Javascript, it is very easy to follow this templating language.
|
||||
|
||||
##### Here are some examples (from John Resig's Blog):
|
||||
|
||||
Example: Properities:
|
||||
|
||||
<div id="<%=id%>" class="<%=(i % 2 == 1 ? " even"="" :="" "")%="">">
|
||||
<div class="grid_1 alpha right">
|
||||
<img class="righted" src="<%=profile_image_url%>">
|
||||
</div>
|
||||
<div class="grid_6 omega contents">
|
||||
<div><b><a href="/<%=from_user%>">
|
||||
<%=from_user%></a>:</b> <%=text%></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Example: Code structures, Loops
|
||||
|
||||
<% for ( var i = 0; i < users.length; i++ ) { %>
|
||||
<li><a href="<%=users[i].url%>"><%=users[i].name%></a></li>
|
||||
<% } %>
|
||||
|
||||
> **Note**: It is important to note that you should not use single quotes (') in your template as the engine cannot handle them effectively.
|
||||
|
||||
### 3. Data
|
||||
|
||||
Data is available to the template as:
|
||||
|
||||
- `data`: this is a list of records, with each record as an object with slugified properties from labels. For example "Posting Date" becomes "posting_date"
|
||||
- `filters`: filters set in the report
|
||||
- `report`: reportview object
|
||||
|
||||
### 4. Example
|
||||
|
||||
Here is how the General Ledger Report is built:
|
||||
|
||||
[General Ledger Print Format Template](https://github.com/frappe/erpnext/blob/develop/erpnext/accounts/report/general_ledger/general_ledger.html)
|
||||
|
||||
Here is what the report looks like:
|
||||
|
||||

|
||||
|
||||
##### Comments:
|
||||
|
||||
1. [Bootstrap Stylesheet](http://getbootstrap.com) is pre-loaded.
|
||||
1. You can use all global functions like `fmt_money` and dateutil.
|
||||
1. Translatable strings should be written as `__("text")`
|
||||
1. You can create modules and import using `{% include "templates/includes/formats/common_format" %}`
|
||||
|
||||
<!-- markdown -->
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
Standard Print formats are <b>auto generated</b> from the layout of the DocType. You can customize the standard format by
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<h4>1. Customizing Standard Print</h4>
|
||||
Go to <b>Setup > Customize > Customize Form View </b>and you can:
|
||||
<br>
|
||||
<ol>
|
||||
<li>Re-arranging fields by dragging and dropping</li>
|
||||
<li>Add static elements by adding <b>HTML</b> type fields and adding your HTML in <b>Options</b>
|
||||
|
||||
</li>
|
||||
<li>Hiding fields by setting the <b>Print Hide</b> property</li>
|
||||
</ol>
|
||||
<hr>
|
||||
|
||||
<h4>2. Creating new layouts based on Print Formats</h4>
|
||||
|
||||
<p>As there are not templates that are generated for standard Print Formats, you will have to create new templates from scratch using the <a href="http://jinja.pocoo.org/" target="_blank">Jinja Templating Language</a> via</p>
|
||||
<p><b>Setup > Printing and Branding > Print Format</b>
|
||||
|
||||
</p>
|
||||
<ol>
|
||||
<li><a href="https://erpnext.com/user-guide/customize-erpnext/print-format" target="_blank">See Print Format help</a>.
|
||||
<br>
|
||||
</li>
|
||||
<li>You can use the <a href="http://getbootstrap.com" target="_blank">Bootstrap CSS framework</a> to layout your print formats
|
||||
<br>
|
||||
</li>
|
||||
</ol>
|
||||
<hr>
|
||||
<p><b>Tip: You can import <a href="https://github.com/frappe/frappe/blob/develop/frappe/templates/print_formats/standard_macros.html" target="_blank">Standard Template macros</a> for building your print formats.</b>
|
||||
|
||||
</p>
|
||||
<p>Example, adding the standard header:
|
||||
<br>
|
||||
</p>
|
||||
<pre><code>{% raw %}{%- from "templates/print_formats/standard_macros.html" import add_header -%}
|
||||
{{ add_header() }}{% endraw %}
|
||||
</code></pre>
|
||||
3
frappe/docs/user/en/index.md
Executable file
3
frappe/docs/user/en/index.md
Executable file
|
|
@ -0,0 +1,3 @@
|
|||
# Develop Apps with Frappe
|
||||
|
||||
{index}
|
||||
2
frappe/docs/user/en/index.txt
Executable file
2
frappe/docs/user/en/index.txt
Executable file
|
|
@ -0,0 +1,2 @@
|
|||
tutorial
|
||||
guides
|
||||
9
frappe/docs/user/en/tutorial/app.md
Executable file
9
frappe/docs/user/en/tutorial/app.md
Executable file
|
|
@ -0,0 +1,9 @@
|
|||
# What is an Application
|
||||
|
||||
An Application in Frappe is just a standard Python application. You can structure a Frappe Application the same way you structure a standard Python Application. For deployment, Frappe uses the standard Python Setuptools, so you can easily port and install the application on any machine.
|
||||
|
||||
Frappe Framework provides a WSGI interface and for development you can use the built-in Werkzeug server. For implementing in production, we recommend using nginx and gunicorn.
|
||||
|
||||
Frappe also has a multi-tenant architecture, grounds up. This means that you can run multiple "sites" in your setup, each could be serving a different set of applications and users. The database for each site is separate.
|
||||
|
||||
{next}
|
||||
48
frappe/docs/user/en/tutorial/before.md
Executable file
48
frappe/docs/user/en/tutorial/before.md
Executable file
|
|
@ -0,0 +1,48 @@
|
|||
# Before You Start
|
||||
|
||||
<p class="lead">A list of tools, technologies that will be very helpful for building apps in Frappe.</p>
|
||||
|
||||
There are a number of good tutorials online and we found [CodeAcademy](http://www.codecademy.com/) to be the most beautiful ones out there here bunch of lessons you can learn from CodeAcademy
|
||||
|
||||
---
|
||||
|
||||
#### 1. Python
|
||||
|
||||
Server side Frappe is written in Python and its a good idea to [quickly learn Python](http://www.codecademy.com/tracks/python) before you started digging into Frappe. Another good place to learn Python is the [tutorial on docs.python.org](https://docs.python.org/2.7/tutorial/index.html). Note that Frappe uses Python 2.7
|
||||
|
||||
To write quality server side code, you must include automatic tests. You can learn the [basics of test driven development here](http://code.tutsplus.com/tutorials/beginning-test-driven-development-in-python--net-30137).
|
||||
|
||||
---
|
||||
|
||||
#### 2. Databases MariaDB / MySQL
|
||||
|
||||
You need to understand the basics of databases, like how to install, login, create new databases, and basic SQL queries. Here is a [very quick introduction to MySQL](https://www.digitalocean.com/community/tutorials/a-basic-mysql-tutorial) or head to [the MariaDB site for a more detailed understanding](https://mariadb.com/kb/en/mariadb/documentation/getting-started/)
|
||||
|
||||
---
|
||||
|
||||
#### 3. HTML / CSS
|
||||
|
||||
If you are building user interfaces, you will need to [learn basic HTML / CSS](http://www.codecademy.com/tracks/web) and the [Boostrap CSS Framework](http://getbootstrap.com)
|
||||
|
||||
---
|
||||
|
||||
#### 4. Building UI with Javascript and JQuery
|
||||
|
||||
To customize forms and create new rich user interfaces, it is best to [learn Javacsript](http://www.codecademy.com/tracks/javascript) and the [popular library JQuery](http://www.codecademy.com/tracks/jquery).
|
||||
|
||||
---
|
||||
|
||||
#### 5. Customizing Prints and Web pages with Jinja Templating
|
||||
|
||||
If you are customizing Print templates, you need to learn the [Jinja Templating language](http://jinja.pocoo.org/). It is an easy way to create dynamic web pages (HTML).
|
||||
|
||||
---
|
||||
|
||||
#### 6. Git and GitHub
|
||||
|
||||
[Learn how to contribute back to an open source project using Git and GitHub](https://guides.github.com/activities/contributing-to-open-source/), two great tools to help you manage your code and share it with others.
|
||||
|
||||
---
|
||||
|
||||
When you are ready, [try building a sample application on Frappe]({{ docs_base_url }}/user/en/tutorial/app)
|
||||
|
||||
11
frappe/docs/user/en/tutorial/bench.md
Executable file
11
frappe/docs/user/en/tutorial/bench.md
Executable file
|
|
@ -0,0 +1,11 @@
|
|||
# Installing the Frappe Bench
|
||||
|
||||
Easiest way to setup frappe on a Unix Like system is to use frappe-bench. Read the detailed instructions on how to install using Frappe Bench.
|
||||
|
||||
> [https://github.com/frappe/bench](https://github.com/frappe/bench)
|
||||
|
||||
With Frappe Bench you will be able to setup and host multiple applications and sites and it will also setup a Python Virtualenv so that you can have an isolated environment to run your applications (and will not have version conflict with other development environments).
|
||||
|
||||
The `bench` command line tool will also be installed that will help you in development and management of the installation.
|
||||
|
||||
{next}
|
||||
7
frappe/docs/user/en/tutorial/conclusion.md
Executable file
7
frappe/docs/user/en/tutorial/conclusion.md
Executable file
|
|
@ -0,0 +1,7 @@
|
|||
# Conclusion
|
||||
|
||||
|
||||
We hope this will give you an overview of how applications are developed in Frappe. The objective was to briefly touch on the various aspects of application development and give a broad overview. To get help on specific issues, look at the API.
|
||||
|
||||
For help, join the community at the [chat channel on Gitter](https://gitter.im/frappe/erpnext) or the [developer forum](https://discuss.erpnext.com)
|
||||
|
||||
59
frappe/docs/user/en/tutorial/controllers.md
Executable file
59
frappe/docs/user/en/tutorial/controllers.md
Executable file
|
|
@ -0,0 +1,59 @@
|
|||
# Controllers
|
||||
|
||||
Next step would be adding methods and event handlers to models. In the app, we should ensure that if a Library Transaction is made, the Article in question must be in stock and the member loaning the Article must have a valid membership.
|
||||
|
||||
For this, we can write a validation just before the Library Transaction object is saved. To do this, open the `library_management/doctype/library_transaction/library_transaction.py` template.
|
||||
|
||||
This file is the controller for the Library Transaction object. In this you can write methods for:
|
||||
|
||||
1. `before_insert`
|
||||
1. `validate` (before inserting or updating)
|
||||
1. `on_update` (after saving)
|
||||
1. `on_submit` (when document is set as submitted)
|
||||
1. `on_cancel`
|
||||
1. `on_trash` (before it is about to be deleted)
|
||||
|
||||
You can write methods for these events and they will be called by the framework when the document is saved etc.
|
||||
|
||||
Here is the finished controller:
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
|
||||
class LibraryTransaction(Document):
|
||||
def validate(self):
|
||||
last_transaction = frappe.get_list("Library Transaction",
|
||||
fields=["transaction_type", "transaction_date"],
|
||||
filters = {
|
||||
"article": self.article,
|
||||
"transaction_date": ("<=", self.transaction_date),
|
||||
"name": ("!=", self.name)
|
||||
})
|
||||
if self.transaction_type=="Issue":
|
||||
msg = _("Article {0} {1} has not been recorded as returned since {2}")
|
||||
if last_transaction and last_transaction[0].transaction_type=="Issue":
|
||||
frappe.throw(msg.format(self.article, self.article_name,
|
||||
last_transaction[0].transaction_date))
|
||||
else:
|
||||
if not last_transaction or last_transaction[0].transaction_type!="Issue":
|
||||
frappe.throw(_("Cannot return article not issued"))
|
||||
|
||||
In this script:
|
||||
|
||||
1. We get the last transaction before the current transaction date using the query function `frappe.get_list`
|
||||
1. If the last transaction is something we don't like we throw an exception using `frappe.throw`
|
||||
1. We use `_("text")` method to identify translatable strings.
|
||||
|
||||
Check if your validations work by creating new records
|
||||
|
||||
<img class="screenshot" alt="Transaction" src="{{docs_base_url}}/assets/img/lib_trans.png">
|
||||
|
||||
#### Debugging
|
||||
|
||||
To Debug, always keep your JS Console open. Lookout for both Javascript and server tracebacks.
|
||||
|
||||
Also check your terminal window for exceptions. Any **500 Internal Server Errors** will get printed in your terminal where on which your server is running.
|
||||
|
||||
{next}
|
||||
31
frappe/docs/user/en/tutorial/doctype-directory-structure.md
Executable file
31
frappe/docs/user/en/tutorial/doctype-directory-structure.md
Executable file
|
|
@ -0,0 +1,31 @@
|
|||
# DocType Directory Structure
|
||||
|
||||
After saving the DocTypes, check that the model `.json` and `.py` files are created in the `apps/library_management/library_management` module. The directory structure after creating the models should look like this:
|
||||
|
||||
.
|
||||
├── MANIFEST.in
|
||||
├── README.md
|
||||
├── library_management
|
||||
..
|
||||
│ ├── library_management
|
||||
│ │ ├── __init__.py
|
||||
│ │ └── doctype
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── article
|
||||
│ │ │ ├── __init__.py
|
||||
│ │ │ ├── article.json
|
||||
│ │ │ └── article.py
|
||||
│ │ ├── library_member
|
||||
│ │ │ ├── __init__.py
|
||||
│ │ │ ├── library_member.json
|
||||
│ │ │ └── library_member.py
|
||||
│ │ ├── library_membership
|
||||
│ │ │ ├── __init__.py
|
||||
│ │ │ ├── library_membership.json
|
||||
│ │ │ └── library_membership.py
|
||||
│ │ └── library_transaction
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── library_transaction.json
|
||||
│ │ └── library_transaction.py
|
||||
|
||||
{next}
|
||||
96
frappe/docs/user/en/tutorial/doctypes.md
Executable file
96
frappe/docs/user/en/tutorial/doctypes.md
Executable file
|
|
@ -0,0 +1,96 @@
|
|||
# DocType
|
||||
|
||||
After creating the Roles, let us create the **DocTypes**
|
||||
|
||||
To create a new **DocType**, go to:
|
||||
|
||||
> Developer > Documents > Doctype > New
|
||||
|
||||
<img class="screenshot" alt="New Doctype" src="{{docs_base_url}}/assets/img/doctype_new.png">
|
||||
|
||||
In the DocType, first the Module, which in our case is **Library Managment**
|
||||
|
||||
#### Adding Fields
|
||||
|
||||
In the Fields Table, you can add the fields (properties) of the DocType (Article).
|
||||
|
||||
Fields are much more than database columns, they can be:
|
||||
|
||||
1. Columns in the database
|
||||
1. Layout helpers (section / column breaks)
|
||||
1. Child tables (Table type field)
|
||||
1. HTML
|
||||
1. Actions (button)
|
||||
1. Attachments or Images
|
||||
|
||||
Let us add the fields of the Article.
|
||||
|
||||
<img class="screenshot" alt="Adding Fields" src="{{docs_base_url}}/assets/img/doctype_adding_field.png">
|
||||
|
||||
When you add fields, you need to enter the **Type**. **Label** is optional for Section Break and Column Break. **Name** (`fieldname`) is the name of the database table column and also the property of the controller. This has to be *code friendly*, i.e. it has to have small cases are _ instead of " ". If you leave the Fieldname blank, it will be automatically set when you save it.
|
||||
|
||||
You can also set other properties of the field like whether it is mandatory, read only etc.
|
||||
|
||||
We can add the following fields:
|
||||
|
||||
1. Article Name (Data)
|
||||
2. Author (Data)
|
||||
3. Description
|
||||
4. ISBN
|
||||
5. Status (Select): For Select fields, you will enter the Options. Enter **Issued** and **Available** each on a new line in the Options box. See diagram below
|
||||
6. Publisher (Data)
|
||||
7. Language (Data)
|
||||
8. Image (Attach Image)
|
||||
|
||||
|
||||
#### Add Permissions
|
||||
|
||||
After adding the fields, hit done and add a new row in the Permission Rules section. For now, let us give Read, Write, Create, Delete and Report access to **Librarian**. Frappe has a finely grained Role based permission model. You can also change permissions later using the **Role Permissions Manager** from **Setup**.
|
||||
|
||||
<img class="screenshot" alt="Adding Permissions" src="{{docs_base_url}}/assets/img/doctype_adding_permission.png">
|
||||
|
||||
#### Saving
|
||||
|
||||
Click on the **Save** button. When the button is clicked, a popup will ask you for the name. Give it the name **Article** and save the DocType.
|
||||
|
||||
Now login into mysql and check the database table created:
|
||||
|
||||
$ bench mysql
|
||||
Welcome to the MariaDB monitor. Commands end with ; or \g.
|
||||
Your MariaDB connection id is 3931
|
||||
Server version: 5.5.36-MariaDB-log Homebrew
|
||||
|
||||
Copyright (c) 2000, 2014, Oracle, Monty Program Ab and others.
|
||||
|
||||
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
|
||||
|
||||
MariaDB [library]> DESC tabArticle;
|
||||
+--------------+--------------+------+-----+---------+-------+
|
||||
| Field | Type | Null | Key | Default | Extra |
|
||||
+--------------+--------------+------+-----+---------+-------+
|
||||
| name | varchar(255) | NO | PRI | NULL | |
|
||||
| creation | datetime(6) | YES | | NULL | |
|
||||
| modified | datetime(6) | YES | | NULL | |
|
||||
| modified_by | varchar(40) | YES | | NULL | |
|
||||
| owner | varchar(60) | YES | | NULL | |
|
||||
| docstatus | int(1) | YES | | 0 | |
|
||||
| parent | varchar(255) | YES | MUL | NULL | |
|
||||
| parentfield | varchar(255) | YES | | NULL | |
|
||||
| parenttype | varchar(255) | YES | | NULL | |
|
||||
| idx | int(8) | YES | | NULL | |
|
||||
| article_name | varchar(255) | YES | | NULL | |
|
||||
| status | varchar(255) | YES | | NULL | |
|
||||
| description | text | YES | | NULL | |
|
||||
| image | varchar(255) | YES | | NULL | |
|
||||
| publisher | varchar(255) | YES | | NULL | |
|
||||
| isbn | varchar(255) | YES | | NULL | |
|
||||
| language | varchar(255) | YES | | NULL | |
|
||||
| author | varchar(255) | YES | | NULL | |
|
||||
+--------------+--------------+------+-----+---------+-------+
|
||||
18 rows in set (0.00 sec)
|
||||
|
||||
|
||||
As you can see, along with the DocFields, several standard columns have also been added to the table. Important to note here are, the primary key, `name`, `owner`(the user who has created the record), `creation` and `modified` (timestamps for creation and last modification).
|
||||
|
||||
{next}
|
||||
|
||||
37
frappe/docs/user/en/tutorial/form-client-scripting.md
Executable file
37
frappe/docs/user/en/tutorial/form-client-scripting.md
Executable file
|
|
@ -0,0 +1,37 @@
|
|||
## Scripting Forms
|
||||
|
||||
Now we have created a basic system that works out of the box without us having to write any code. Let us now write some scripts to make the application richer and add validations so that the user does not enter wrong data.
|
||||
|
||||
### Client Side Scripting
|
||||
|
||||
In the **Library Transaction** DocType, we have only field for Member Name. We have not made two fields. Now this could well be two fields (and probably should), but for the sake of example, let us consider we have to implement this. To do this we would have to write a event handler for the event when the user selects the `library_member` field and then access the member resource from the server using REST API and set the values in the form.
|
||||
|
||||
To start the script, in the `library_management/doctype/library_transaction` folder, create a new file `library_transaction.js`. This file will be automatically executed when the first Library Transaction is opened by the user. So in this file, we can bind events and write other functions.
|
||||
|
||||
#### library_transaction.js
|
||||
|
||||
frappe.ui.form.on("Library Transaction", "library_member",
|
||||
function(frm) {
|
||||
frappe.call({
|
||||
"method": "frappe.client.get",
|
||||
args: {
|
||||
doctype: "Library Member",
|
||||
name: frm.doc.library_member
|
||||
},
|
||||
callback: function (data) {
|
||||
frappe.model.set_value(frm.doctype,
|
||||
frm.docname, "member_name",
|
||||
data.message.first_name
|
||||
+ (data.message.last_name ?
|
||||
(" " + data.message.last_name) : ""))
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
1. **frappe.ui.form.on(*doctype*, *fieldname*, *handler*)** is used to bind a handler to the event when the property library_member is set.
|
||||
1. In the handler, we trigger an AJAX call to `frappe.client.get`. In response we get the requested object as JSON. [Learn more about the API](/frappe/user/en/guides/integration/rest_api).
|
||||
1. Using **frappe.model.set_value(*doctype*, *name*, *fieldname*, *value*)** we set the value in the form.
|
||||
|
||||
**Note:** To check if your script works, remember to 'reload' the page before testing your script. Client script changes are not automatically picked up when you are in developer mode.
|
||||
|
||||
{next}
|
||||
33
frappe/docs/user/en/tutorial/index.md
Executable file
33
frappe/docs/user/en/tutorial/index.md
Executable file
|
|
@ -0,0 +1,33 @@
|
|||
# Frappe Tutorial
|
||||
|
||||
In this guide we will show you how to create an application from scratch using **Frappe**. Using the example of a Library Management System, we will cover:
|
||||
|
||||
1. Installation
|
||||
1. Making a New App
|
||||
1. Making Models
|
||||
1. Creating Users and Records
|
||||
1. Creating Controllers
|
||||
1. Creating Web Views
|
||||
1. Setting Hooks and Tasks
|
||||
|
||||
## Who is This For?
|
||||
|
||||
This guide is intended for software developers who are familiar with how the web applications are built and served. Frappe Framework is built on Python and uses MariaDB database and for creating web views, HTML/CSS/Javascript is used. So it would be great if you are familiar with all these technologies. At minimum if you have never used Python before, you should take a quick tutorial before your use this Guide.
|
||||
|
||||
Frappe uses the git version control system on GitHub. It is also important that you are familiar with basic git and have an account on GitHub to manage your applications.
|
||||
|
||||
## Example
|
||||
|
||||
For this guide book, we will build a simple **Library Management** application. In this application we will have models:
|
||||
|
||||
1. Article (Book or any other item that can be loaned)
|
||||
1. Library Member
|
||||
1. Library Transaction (Issue or Return of an article)
|
||||
1. Library Membership (A period in which a member is allowed to transact)
|
||||
1. Library Management Setting (Global settings like period of loan)
|
||||
|
||||
The user interface (UI) for the librarian will be the **Frappe Desk**, a built-in browser based UI environment where forms are automatically generated from the models and roles and permissions are also applied.
|
||||
|
||||
We will also create web views for library where users can browse articles from a website.
|
||||
|
||||
{index}
|
||||
19
frappe/docs/user/en/tutorial/index.txt
Executable file
19
frappe/docs/user/en/tutorial/index.txt
Executable file
|
|
@ -0,0 +1,19 @@
|
|||
before
|
||||
app
|
||||
bench
|
||||
new-app
|
||||
setting-up-the-site
|
||||
start
|
||||
models
|
||||
roles
|
||||
doctypes
|
||||
naming-and-linking
|
||||
doctype-directory-structure
|
||||
users-and-records
|
||||
form-client-scripting
|
||||
controllers
|
||||
reports
|
||||
web-views
|
||||
single-doctypes
|
||||
task-runner
|
||||
conclusion
|
||||
19
frappe/docs/user/en/tutorial/models.md
Executable file
19
frappe/docs/user/en/tutorial/models.md
Executable file
|
|
@ -0,0 +1,19 @@
|
|||
# Making Models
|
||||
|
||||
The next step is to create the models as we discussed in the introduction. In Frappe, models are called **DocTypes**. You can create new DocTypes from the Desk UI. **DocTypes** are made of fields called **DocField** and role based permissions are integrated into the models, these are called **DocPerms**.
|
||||
|
||||
When a DocType is saved, a new table is created in the database. This table is named as `tab[doctype]`.
|
||||
|
||||
When you create a **DocType** a new folder is created in the **Module** and a model JSON file and a controller template in Python are automatically created. When you update the DocType, the JSON model file is updated and whenever `bench migrate` is executed, it is synced with the database. This makes it easy to propagate schema changes and migrate.
|
||||
|
||||
### Developer Mode
|
||||
|
||||
To create models, you must set `developer_mode` as 1 in the `site_config.json` file located in /sites/library and execute command `bench clear-cache` or use the user menu in UI and click on "Reload" for the changes to take effect. You should now see the "Developer" app on your desk
|
||||
|
||||
{
|
||||
"db_name": "bcad64afbf",
|
||||
"db_password": "v3qHDeVKvWVi7s97",
|
||||
"developer_mode": 1
|
||||
}
|
||||
|
||||
{next}
|
||||
71
frappe/docs/user/en/tutorial/naming-and-linking.md
Executable file
71
frappe/docs/user/en/tutorial/naming-and-linking.md
Executable file
|
|
@ -0,0 +1,71 @@
|
|||
# DocType Naming and Linking
|
||||
|
||||
Then let us create the other DocType and save it too:
|
||||
|
||||
1. Library Member (First Name, Last Name, Email ID, Phone, Address)
|
||||
|
||||
<img class="screenshot" alt="Doctype Saved" src="{{docs_base_url}}/assets/img/naming_doctype.png">
|
||||
|
||||
|
||||
#### Naming of DocTypes
|
||||
|
||||
DocTypes can be named in different ways:
|
||||
|
||||
1. Based on a field
|
||||
1. Based on a series
|
||||
1. By controller (code)
|
||||
1. Prompt
|
||||
|
||||
This can be set by entering the **Autoname** field. For controller, leave blank.
|
||||
|
||||
> **Search Fields**: A DocType may be named on a series but it still needs to be searched by name. In our case, the Article will be searched by the title or the author name. So this can be entered in search field.
|
||||
|
||||
<img class="screenshot" alt="Autonaming and Search Field" src="{{docs_base_url}}/assets/img/autoname_and_search_field.png">
|
||||
|
||||
#### Link and Select Fields
|
||||
|
||||
Foreign keys are specified in Frappe as **Link** type fields. The target DocType must be mentioned in the Options text area.
|
||||
|
||||
In our example, in the Library Transaction DocType, we have to link both the Library Member and the Article.
|
||||
|
||||
**Note:** Remeber that Link fields are not automatically set as Foreign Keys in the MariaDB database, because that will implicitly index the column. This may not be optimum hence the Foreign Key validation is done by the Framework.
|
||||
|
||||
<img class="screenshot" alt="Link Field" src="{{docs_base_url}}/assets/img/link_field.png">
|
||||
|
||||
For select fields, as we mentioned earlier, add the various options in the **Options** input box, each option on a new row.
|
||||
|
||||
<img class="screenshot" alt="Select Field" src="{{docs_base_url}}/assets/img/select_field.png">
|
||||
|
||||
Similary complete making the other models.
|
||||
|
||||
#### Linked Values
|
||||
|
||||
A standard pattern is when you select an ID, say **Library Member** in **Library Membership**, then the Member's first and last names should be copied into relevant fields in the Library Membership Transaction.
|
||||
|
||||
To do this, we can use Read Only fields and in options, we can set the the name of the link and the fieldname of the property we want to fetch. For this example in **Member First Name** we can set `library_member.first_name`
|
||||
|
||||
<img class="screenshot" alt="Fetch values" src="{{docs_base_url}}/assets/img/fetch.png">
|
||||
|
||||
### Complete the Models
|
||||
|
||||
In the same way, you can complete all the models so that the final fields look like this:
|
||||
|
||||
#### Article
|
||||
|
||||
<img class="screenshot" alt="Article" src="{{docs_base_url}}/assets/img/doctype_article.png">
|
||||
|
||||
#### Library Member
|
||||
|
||||
<img class="screenshot" alt="Library Member" src="{{docs_base_url}}/assets/img/doctype_lib_member.png">
|
||||
|
||||
#### Library Membership
|
||||
|
||||
<img class="screenshot" alt="Library Membership" src="{{docs_base_url}}/assets/img/doctype_lib_membership.png">
|
||||
|
||||
#### Library Transaction
|
||||
|
||||
<img class="screenshot" alt="Library Transaction" src="{{docs_base_url}}/assets/img/doctype_lib_trans.png">
|
||||
|
||||
> Make sure to give permissions to **Librarian** on each DocType
|
||||
|
||||
{next}
|
||||
54
frappe/docs/user/en/tutorial/new-app.md
Executable file
54
frappe/docs/user/en/tutorial/new-app.md
Executable file
|
|
@ -0,0 +1,54 @@
|
|||
# Make a New App
|
||||
|
||||
Once the bench is installed, you will see two main folders, `apps` and `sites`. All the applications will be installed in apps.
|
||||
|
||||
To make a new application, go to your bench folder and run, `bench new-app {app_name}` and fill in details about the application. This will create a boilerplate application for you.
|
||||
|
||||
$ bench new-app library_management
|
||||
App Title (defaut: Lib Mgt): Library Management
|
||||
App Description: App for managing Articles, Members, Memberships and Transactions for Libraries
|
||||
App Publisher: Frappe
|
||||
App Email: info@frappe.io
|
||||
App Icon (default 'octicon octicon-file-directory'): octicon octicon-book
|
||||
App Color (default 'grey'): #589494
|
||||
App License (default 'MIT'): GNU General Public License
|
||||
|
||||
### App Structure
|
||||
|
||||
The application will be created in a folder called `library_management` and will have the following structure:
|
||||
|
||||
.
|
||||
├── MANIFEST.in
|
||||
├── README.md
|
||||
├── library_management
|
||||
│ ├── __init__.py
|
||||
│ ├── config
|
||||
│ │ ├── __init__.py
|
||||
│ │ └── desktop.py
|
||||
│ ├── hooks.py
|
||||
│ ├── library_management
|
||||
│ │ └── __init__.py
|
||||
│ ├── modules.txt
|
||||
│ ├── patches.txt
|
||||
│ └── templates
|
||||
│ ├── __init__.py
|
||||
│ ├── generators
|
||||
│ │ └── __init__.py
|
||||
│ ├── pages
|
||||
│ │ └── __init__.py
|
||||
│ └── statics
|
||||
├── license.txt
|
||||
├── requirements.txt
|
||||
└── setup.py
|
||||
|
||||
1. `config` folder contains application configuration info
|
||||
1. `desktop.py` is where desktop icons can be added to the Desk
|
||||
1. `hooks.py` is where integrations with the environment and other applications is mentioned.
|
||||
1. `library_management` (inner) is a **module** that is bootstrapped. In Frappe, a **module** is where model and controller files reside.
|
||||
1. `modules.txt` contains list of **modules** in the app. When you create a new module, it is required that you update it in this file.
|
||||
1. `patches.txt` is where migration patches are written. They are python module references using the dot notation.
|
||||
1. `templates` is the folder where web view templates are maintained. Templates for **Login** and other standard pages are bootstrapped in frappe.
|
||||
1. `generators` are where templates for models are maintained, where each model instance has a separte web route, for example a **Blog Post** where each post has its unique web url. In Frappe, the templating engine used is Jinja2
|
||||
1. `pages` is where single route templates are maintained. For example for a "/blog" type of page.
|
||||
|
||||
{next}
|
||||
7
frappe/docs/user/en/tutorial/reports.md
Executable file
7
frappe/docs/user/en/tutorial/reports.md
Executable file
|
|
@ -0,0 +1,7 @@
|
|||
# Reports
|
||||
|
||||
You can also click on the Reports text on the sidebar (left) to see tabulated records
|
||||
|
||||
<img class="screenshot" alt="Report" src="{{docs_base_url}}/assets/img/report.png">
|
||||
|
||||
{next}
|
||||
14
frappe/docs/user/en/tutorial/roles.md
Executable file
14
frappe/docs/user/en/tutorial/roles.md
Executable file
|
|
@ -0,0 +1,14 @@
|
|||
# Creating Roles
|
||||
|
||||
Before creating Models, we must create Roles so that we can set permissions on the Model. There are two Roles we will create:
|
||||
|
||||
1. Librarian
|
||||
1. Library Member
|
||||
|
||||
To create a new Role, go to:
|
||||
|
||||
> Setup > Users > Role > New
|
||||
|
||||
<img class="screenshot" alt="Adding Roles" src="{{docs_base_url}}/assets/img/roles_creation.png">
|
||||
|
||||
{next}
|
||||
53
frappe/docs/user/en/tutorial/setting-up-the-site.md
Executable file
53
frappe/docs/user/en/tutorial/setting-up-the-site.md
Executable file
|
|
@ -0,0 +1,53 @@
|
|||
# Setting up the Site
|
||||
|
||||
Let us create a new site and call it `library`.
|
||||
|
||||
You can install a new site, by the command `bench new-site library`
|
||||
|
||||
This will create a new database and site folder and install `frappe` (which is also an application!) in the new site. The `frappe` application has two built-in modules **Core** and **Website**. The Core module contains the basic models for the application. Frappe is a batteries included framework and comes with a lot of built-in models. These models are called **DocTypes**. More on that later.
|
||||
|
||||
$ bench new-site library
|
||||
MySQL root password:
|
||||
Installing frappe...
|
||||
Updating frappe : [========================================]
|
||||
Updating country info : [========================================]
|
||||
Set Administrator password:
|
||||
Re-enter Administrator password:
|
||||
Installing fixtures...
|
||||
*** Scheduler is disabled ***
|
||||
|
||||
### Site Structure
|
||||
|
||||
A new folder called `library` will be created in the `sites` folder. Here is the standard folder structure for a site.
|
||||
|
||||
.
|
||||
├── locks
|
||||
├── private
|
||||
│ └── backups
|
||||
├── public
|
||||
│ └── files
|
||||
└── site_config.json
|
||||
|
||||
1. `public/files` is where user uploaded files are stored.
|
||||
1. `private/backups` is where backups are dumped
|
||||
1. `site_config.json` is where site level configurations are maintained.
|
||||
|
||||
### Setting Default Site
|
||||
|
||||
In case you have multiple sites on you bench use `bench use [site_name]` to set the default site.
|
||||
|
||||
Example:
|
||||
|
||||
$ bench use library
|
||||
|
||||
### Install App
|
||||
|
||||
Now let us install our app `library_management` in our site `library`
|
||||
|
||||
1. Install library_management in library with: `bench --site [site_name] install-app [app_name]`
|
||||
|
||||
Example:
|
||||
|
||||
$ bench --site library install-app library_management
|
||||
|
||||
{next}
|
||||
9
frappe/docs/user/en/tutorial/single-doctypes.md
Executable file
9
frappe/docs/user/en/tutorial/single-doctypes.md
Executable file
|
|
@ -0,0 +1,9 @@
|
|||
# Single DocTypes
|
||||
|
||||
A application will usually have a Settings page. In our application, we can define a page where we can set the loan period. We also need to save this property. In Frappe, this can be done using a **Single** type DocType. A Single DocType is like the Singleton pattern in Java. It is an object with only one instance. Let us call this as **Library Managment Settings**.
|
||||
|
||||
To create an new Single DocType, mark the **Is Single** property as checked.
|
||||
|
||||
<img class="screenshot" alt="Single Doctypes" src="{{docs_base_url}}/assets/img/tab_single.png">
|
||||
|
||||
{next}
|
||||
31
frappe/docs/user/en/tutorial/start.md
Executable file
31
frappe/docs/user/en/tutorial/start.md
Executable file
|
|
@ -0,0 +1,31 @@
|
|||
# Starting the Bench
|
||||
|
||||
Now we can login and check if everything works.
|
||||
|
||||
To start the development server, run `bench start`
|
||||
|
||||
$ bench start
|
||||
13:58:51 web.1 | started with pid 22135
|
||||
13:58:51 worker.1 | started with pid 22136
|
||||
13:58:51 workerbeat.1 | started with pid 22137
|
||||
13:58:52 web.1 | * Running on http://0.0.0.0:8000/
|
||||
13:58:52 web.1 | * Restarting with reloader
|
||||
13:58:52 workerbeat.1 | [2014-09-17 13:58:52,343: INFO/MainProcess] beat: Starting...
|
||||
|
||||
You can now open your browser and go to `http://localhost:8000`. You should see this login page if all goes well:
|
||||
|
||||
<img class="screenshot" alt="Login Screen" src="{{docs_base_url}}/assets/img/login.png">
|
||||
|
||||
Now login with :
|
||||
|
||||
Login ID: **Administrator**
|
||||
|
||||
Password : **Use the password that was created during installation**
|
||||
|
||||
When you login, you should see the "Desk" home page
|
||||
|
||||
<img class="screenshot" alt="Desk" src="{{docs_base_url}}/assets/img/desk.png">
|
||||
|
||||
As you can see, the Frappe basic system comes with several pre-loaded applications like To Do, File Manager etc. These apps can integrated in your app workflow as we progress.
|
||||
|
||||
{next}
|
||||
77
frappe/docs/user/en/tutorial/task-runner.md
Executable file
77
frappe/docs/user/en/tutorial/task-runner.md
Executable file
|
|
@ -0,0 +1,77 @@
|
|||
# Scheduled Tasks
|
||||
|
||||
Finally, an application also has to send email notifications and do other kind of scheduled tasks. In Frappe, if you have setup the bench, the task / scheduler is setup via Celery using Redis Queue.
|
||||
|
||||
To add a new task handler, go to `hooks.py` and add a new handler. Default handlers are `all`, `daily`, `weekly`, `monthly`. The `all` handler is called every 3 minutes by default.
|
||||
|
||||
# Scheduled Tasks
|
||||
# ---------------
|
||||
|
||||
scheduler_events = {
|
||||
"daily": [
|
||||
"library_management.tasks.daily"
|
||||
],
|
||||
}
|
||||
|
||||
Here we can point to a Python function and that function will be executed every day. Let us look what this function looks like:
|
||||
|
||||
# Copyright (c) 2013, Frappe
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.utils import datediff, nowdate, format_date, add_days
|
||||
|
||||
def daily():
|
||||
loan_period = frappe.db.get_value("Library Management Settings",
|
||||
None, "loan_period")
|
||||
|
||||
overdue = get_overdue(loan_period)
|
||||
|
||||
for member, items in overdue.iteritems():
|
||||
content = """<h2>Following Items are Overdue</h2>
|
||||
<p>Please return them as soon as possible</p><ol>"""
|
||||
|
||||
for i in items:
|
||||
content += "<li>{0} ({1}) due on {2}</li>".format(i.article_name,
|
||||
i.article,
|
||||
format_date(add_days(i.transaction_date, loan_period)))
|
||||
|
||||
content += "</ol>"
|
||||
|
||||
recipient = frappe.db.get_value("Library Member", member, "email_id")
|
||||
frappe.sendmail(recipients=[recipient],
|
||||
sender="test@example.com",
|
||||
subject="Library Articles Overdue", content=content, bulk=True)
|
||||
|
||||
def get_overdue(loan_period):
|
||||
# check for overdue articles
|
||||
today = nowdate()
|
||||
|
||||
overdue_by_member = {}
|
||||
articles_transacted = []
|
||||
|
||||
for d in frappe.db.sql("""select name, article, article_name,
|
||||
library_member, member_name
|
||||
from `tabLibrary Transaction`
|
||||
order by transaction_date desc, modified desc""", as_dict=1):
|
||||
|
||||
if d.article in articles_transacted:
|
||||
continue
|
||||
|
||||
if d.transaction_type=="Issue" and \
|
||||
datediff(today, d.transaction_date) > loan_period:
|
||||
overdue_by_member.setdefault(d.library_member, [])
|
||||
overdue_by_member[d.library_member].append(d)
|
||||
|
||||
articles_transacted.append(d.article)
|
||||
|
||||
We can place the above code code in any accessible Python module. The route is defined in `hooks.py`, so for our purposes we would place this code in `library_management/tasks.py`.
|
||||
|
||||
Note:
|
||||
|
||||
1. We get the loan period from **Library Management Settings** by using `frappe.db.get_value`.
|
||||
1. We run a query in the database with `frappe.db.sql`
|
||||
1. Email is sent via `frappe.sendmail`
|
||||
|
||||
{next}
|
||||
55
frappe/docs/user/en/tutorial/users-and-records.md
Executable file
55
frappe/docs/user/en/tutorial/users-and-records.md
Executable file
|
|
@ -0,0 +1,55 @@
|
|||
# Making Users and Records
|
||||
|
||||
Now that we have created the models, we can directly start making records using Frappe Desk UI. You do not have to create views! Views in Frappe are automatically made based on the DocType properties.
|
||||
|
||||
### 4.1 Creating User
|
||||
|
||||
To make records, we will first create a User. To create a user, go to:
|
||||
|
||||
> Setup > Users > User > New
|
||||
|
||||
Create a new User and set the name and first name and new password.
|
||||
|
||||
Also give the Librarian and Library Member Roles to this user
|
||||
|
||||
<img class="screenshot" alt="Add User Roles" src="{{docs_base_url}}/assets/img/add_user_roles.png">
|
||||
|
||||
Now logout and login using the new user id and password.
|
||||
|
||||
### 4.2 Creating Records
|
||||
|
||||
You will now see an icon for the Library Management module. Click on that icon and you will see the Module page:
|
||||
|
||||
<img class="screenshot" alt="Library Management Module" src="{{docs_base_url}}/assets/img/lib_management_module.png">
|
||||
|
||||
Here you can see the DocTypes that we have created for the application. Let us start creating a few records.
|
||||
|
||||
First let us create a new Article:
|
||||
|
||||
<img class="screenshot" alt="New Article" src="{{docs_base_url}}/assets/img/new_article_blank.png">
|
||||
|
||||
Here you will see that the the DocType you had created has been rendered as a form. The validations and other rules will also apply as designed. Let us fill out one Article.
|
||||
|
||||
<img class="screenshot" alt="New Article" src="{{docs_base_url}}/assets/img/new_article.png">
|
||||
|
||||
You can also add an image.
|
||||
|
||||
<img class="screenshot" alt="Attach Image" src="{{docs_base_url}}/assets/img/attach_image.gif">
|
||||
|
||||
Now let us create a new member:
|
||||
|
||||
<img class="screenshot" alt="New Library Member" src="{{docs_base_url}}/assets/img/new_member.png">
|
||||
|
||||
After this, let us create a new membership record for the member.
|
||||
|
||||
Here if you remember we had set the values of Member First Name and Member Last Name to be directly fetched from the Member records and as soon as you will select the member id, the names will be updated.
|
||||
|
||||
<img class="screenshot" alt="New Library Membership" src="{{docs_base_url}}/assets/img/new_lib_membership.png">
|
||||
|
||||
As you can see that the date is formatted as year-month-day which is a system format. To set / change date, time and number formats, go to
|
||||
|
||||
> Setup > Settings > System Settings
|
||||
|
||||
<img class="screenshot" alt="System Settings" src="{{docs_base_url}}/assets/img/system_settings.png">
|
||||
|
||||
{next}
|
||||
64
frappe/docs/user/en/tutorial/web-views.md
Executable file
64
frappe/docs/user/en/tutorial/web-views.md
Executable file
|
|
@ -0,0 +1,64 @@
|
|||
# Web Views
|
||||
|
||||
Frappe has two main user environments, the Desk and Web. Desk is a controlled UI environment with a rich AJAX application and the web is more traditional HTML templates served for public consumption. Web views can also be generated to create more controlled views for users who may login but still do not have access to the Desk.
|
||||
|
||||
In Frappe, Web Views are managed by templates and they are usually in the `templates` folder. There are 2 main types of templates.
|
||||
|
||||
1. Pages: These are Jinja templates where a single view exists for a single web route e.g. `/blog`.
|
||||
2. Generators: These are templates where each instance of a DocType has a separate web route `/blog/a-blog`, `blog/b-blog` etc.
|
||||
3. Lists and Views: These are standard lists and views with the route `[doctype]/[name]` and are rendered based on permission.
|
||||
|
||||
### Standard Web Views
|
||||
|
||||
> This features is still under development.
|
||||
|
||||
Let us look at the standard Web Views:
|
||||
|
||||
If you are logged in as the test user, go to `/article` and you should see the list of articles:
|
||||
|
||||

|
||||
|
||||
Click on one article and you will see the default web view
|
||||
|
||||

|
||||
|
||||
Now if you want to make a better list view for the article, drop a file called `list_item.html` in the `library_management/doctype/article` folder. Here is an example file:
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-4">
|
||||
<a href="/Article/{{ doc.name }}">
|
||||
<img src="{{ doc.image }}"
|
||||
class="img-responsive" style="max-height: 200px">
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<a href="/Article/{{ doc.name }}"><h4>{{ doc.article_name }}</h4></a>
|
||||
<p>{{ doc.author }}</p>
|
||||
<p>{{ (doc.description[:200] + "...")
|
||||
if doc.description|length > 200 else doc.description }}</p>
|
||||
<p class="text-muted">Publisher: {{ doc.publisher }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Here, you will get all the properties of the article in the `doc` object.
|
||||
|
||||
The updated list view looks like this!
|
||||
|
||||

|
||||
|
||||
#### Home Page
|
||||
|
||||
Frappe also has a built-in signup workflow which also includes 3rd party signups via Google, Facebook and GitHub. When a user signs up on the web, she does not have access to the desk interface by default.
|
||||
|
||||
> To allow user access into the Desk, open set the user from Setup > User and set the User Type as "System User"
|
||||
|
||||
Now for the non system users, we can set a home page when they login via `hooks.py` based on the role.
|
||||
|
||||
To when library members sign in, they must be redirected to the `article` page, to set this open `library_management/hooks.py` and add this:
|
||||
|
||||
role_home_page = {
|
||||
"Library Member": "article"
|
||||
}
|
||||
|
||||
{next}
|
||||
9
frappe/docs/user/en/videos/index.md
Executable file
9
frappe/docs/user/en/videos/index.md
Executable file
|
|
@ -0,0 +1,9 @@
|
|||
# Video Tutorials for Frappe Framework
|
||||
|
||||
This 10-part video tutorial will teach you how to build complex apps in Frappe
|
||||
|
||||
Pre-requisites: <a href="{{ docs_base_url }}/user/tutorial/before.html" target="_blank">You must have some understanding of Python, Javascript and MySQL before you start this tutorial.</a>
|
||||
|
||||
---
|
||||
|
||||
<iframe width="670" height="376" src="https://www.youtube.com/embed/videoseries?list=PL3lFfCEoMxvzHtsZHFJ4T3n5yMM3nGJ1W" frameborder="0" allowfullscreen></iframe>
|
||||
Loading…
Add table
Reference in a new issue