Compare commits

..

75 Commits

Author SHA1 Message Date
Nabin Hait
ec6267e82a Merge branch 'hotfix' 2016-08-23 12:10:56 +05:30
Nabin Hait
db05ac2414 bumped to version 7.0.32 2016-08-23 12:40:56 +06:00
Nabin Hait
f862505bf9 Merge pull request #6153 from rohitwaghchaure/hotfix
[POS] Fixed decimal button not working
2016-08-23 12:07:40 +05:30
Rohit Waghchaure
ea6d7e9b09 [Fix] decimal button not working 2016-08-23 11:39:44 +05:30
Nabin Hait
8f782e71af Merge pull request #6149 from nabinhait/change_log_v7
Change logs for v7
2016-08-22 15:56:32 +05:30
Nabin Hait
dac204b1e3 Merge pull request #6124 from rohitwaghchaure/hotfix
[POS] Fixed issue of paid amount, write off account
2016-08-22 15:56:20 +05:30
Nabin Hait
9c786948d5 Merge pull request #6125 from nabinhait/lcv_hotfix
[fix] Repost only distinct purchase receipts and invoices
2016-08-22 15:53:21 +05:30
Nabin Hait
6f1795cb3d Merge pull request #6146 from neilLasrado/operation
Operations related fixes
2016-08-22 15:52:57 +05:30
Nabin Hait
01b555edc7 Change logs for v7 2016-08-22 15:50:21 +05:30
Neil Trini Lasrado
20b01873ab Made operation mandatory and removed mandatory from operation desc in Production Order Operation, set operation name as desc in operation master if desc is blank 2016-08-22 15:05:50 +05:30
Nabin Hait
43accf4c07 Merge pull request #6144 from nabinhait/timesheet_patch_fix
Ignore validating mandatory fields on converting timelogs to timesheets
2016-08-22 14:39:01 +05:30
Nabin Hait
9239ed5c44 Ignore validating mandatory fields on converting timelogs to timesheets 2016-08-22 14:35:06 +05:30
Rohit Waghchaure
713e2b7b62 [POS] Fixed issue of paid amount, write off account 2016-08-19 19:27:16 +05:30
Nabin Hait
3b6dc141c6 [fix] Repost only distinct purchase receipts and invoices 2016-08-19 16:39:50 +05:30
Nabin Hait
e4fb7b1b2f Merge branch 'hotfix' 2016-08-18 16:15:49 +05:30
Nabin Hait
9a1bcac576 bumped to version 7.0.31 2016-08-18 16:45:49 +06:00
Nabin Hait
e68b089187 Query for warehouse in delivery note 2016-08-18 16:14:23 +05:30
Nabin Hait
d8a372587d [fix] Legend in support analytics chart 2016-08-18 16:14:23 +05:30
Nabin Hait
f04ce3c5a6 [fix] check expense agaist budget 2016-08-18 16:14:23 +05:30
Nabin Hait
50f8262ac7 Currency fix in reports 2016-08-18 16:14:23 +05:30
Nabin Hait
e30fadc661 Merge branch 'develop' 2016-08-18 16:13:15 +05:30
Nabin Hait
f0937bf722 bumped to version 7.0.30 2016-08-18 16:43:15 +06:00
Nabin Hait
4810831678 Merge pull request #6107 from neilLasrado/develop
[Fix] Enroll Students from Student Applicants in Program Enrollment Tool.
2016-08-18 14:21:11 +05:30
Nabin Hait
7cdc6fd789 Merge pull request #6115 from rohitwaghchaure/pos_stock_update_issue
[POS] Fixed stock update issue
2016-08-18 14:20:26 +05:30
Rushabh Mehta
03e5ea3a0d Merge pull request #6114 from hereabdulla/patch-1
Update employee_list.js
2016-08-18 14:05:58 +05:30
Rohit Waghchaure
9d5a07d101 [POS] Fixed stock update issue 2016-08-18 13:27:06 +05:30
Rushabh Mehta
b7bc6bd75d [fix] better message for cost center, fixes #6109 2016-08-18 12:50:58 +05:30
Abdulla P I
23a6d05622 Update employee_list.js 2016-08-18 12:43:19 +05:30
Rushabh Mehta
b969c2cb60 [minor] budget link in cost center, fixes #6093 2016-08-18 12:36:20 +05:30
Neil Trini Lasrado
c4e71fcc51 [Fix] Enroll Students from Student Applicants in Program Enrollment Tool. 2016-08-17 17:37:19 +05:30
Nabin Hait
b8a8fb5877 Merge branch 'develop' 2016-08-17 17:11:09 +05:30
Nabin Hait
734cf70b43 bumped to version 7.0.29 2016-08-17 17:41:09 +06:00
Nabin Hait
6fe3ac49cf Merge pull request #6039 from rohitwaghchaure/allow_to_edit_change_amount
Allow to edit change amount
2016-08-17 17:08:54 +05:30
Rohit Waghchaure
e4e69ec027 changed field name, validation for change amount account, validation for serial no qty 2016-08-17 16:20:13 +05:30
Nabin Hait
386d9e1613 Merge pull request #6106 from nabinhait/item_reload
Default material request type field restored
2016-08-17 16:16:28 +05:30
Nabin Hait
40c60b6182 Default material request type field restored 2016-08-17 16:14:24 +05:30
Nabin Hait
95c998109d Merge pull request #6043 from aruizramon/purchase-taxes-client-validation
Validate on changing from Total to Valuation/Valuation&Total when add…
2016-08-17 12:12:14 +05:30
Nabin Hait
33bcaa8a07 Merge pull request #6080 from bcornwellmott/quoteditem_picksupplier
Quoted Item Comparison: Button for setting the default_supplier
2016-08-17 11:36:55 +05:30
Nabin Hait
4da2c81641 Merge pull request #6094 from rmehta/sales-purchase-items
[revert] is_sales_item, is_purchase_item back
2016-08-17 11:30:37 +05:30
Nabin Hait
c2595aa902 Merge pull request #6099 from nabinhait/patch_fix_for_v6_to_v7_migration
Patch fixed for v6 to v7 migration
2016-08-17 11:28:29 +05:30
Nabin Hait
613ef344f3 Patch fixed for v6 to v7 migration 2016-08-16 18:31:26 +05:30
Nabin Hait
0c1be8df35 Merge pull request #6096 from rohitwaghchaure/minor_fix
[Fix] lwp salary structure
2016-08-16 18:17:14 +05:30
Nabin Hait
815ebafa7b Merge pull request #6092 from umairsy/9aug
Updated docs (please don't merge)
2016-08-16 18:16:28 +05:30
Umair Sayyed
8f7708ed5b docs updated 2016-08-16 18:13:12 +05:30
Umair Sayyed
1bd9f22add updated docsgd 2016-08-16 18:08:24 +05:30
Umair Sayyed
f369b5951e updated docs 2016-08-16 18:08:00 +05:30
Umair Sayyed
81995389ac updated docs 2016-08-16 18:08:00 +05:30
Rohit Waghchaure
fe913c9969 [Fix] lwp salary structure 2016-08-16 15:43:50 +05:30
Nabin Hait
18d6162935 Merge branch 'develop' 2016-08-16 15:25:34 +05:30
Nabin Hait
91d6544958 bumped to version 7.0.28 2016-08-16 15:55:33 +06:00
Nabin Hait
f640ad4389 Merge pull request #6095 from nabinhait/timesheet_patch
Ignore overlap validation while creating timesheet from existing time logs
2016-08-16 15:19:56 +05:30
Nabin Hait
39bc4b2a4c Ignore overlap validation while creating timesheet from existing time logs 2016-08-16 15:18:28 +05:30
Rushabh Mehta
d973c1606a [revert] is_sales_item, is_purchase_item back 2016-08-16 11:32:08 +05:30
Nabin Hait
df9cf2ef8e Merge pull request #6068 from neilLasrado/develop
Added image field to guardian, program enrollment, fixed some typos
2016-08-16 11:01:58 +05:30
Nabin Hait
528ab53b3a Merge pull request #6067 from rohitwaghchaure/pos_fixes
[POS] fixed issue of negative stock
2016-08-16 11:00:31 +05:30
Rohit Waghchaure
9cd356c7f0 [POS] Fixed print qty decimal issue 2016-08-16 10:44:21 +05:30
Rushabh Mehta
de08639d49 [minor] fixes to patches while moving from v5 2016-08-16 10:01:56 +05:30
Neil Trini Lasrado
987009bf35 Update quotation.json 2016-08-12 16:44:00 +05:30
Rushabh Mehta
c833cc8432 Merge branch 'develop' 2016-08-12 11:53:08 +05:30
Rushabh Mehta
3f22ec9536 bumped to version 7.0.27 2016-08-12 12:23:08 +06:00
Rushabh Mehta
d643f2b249 [minor] fixes #6074; 2016-08-12 10:36:59 +05:30
Ben Cornwell-Mott
b739dd24b2 Added a button to assist in setting the default_supplier 2016-08-11 19:45:55 -07:00
Neil Trini Lasrado
c917423b01 Fixed typo in quotation, added image feild in Program Enrollment 2016-08-11 18:22:45 +05:30
Neil Trini Lasrado
6a23016f90 Added image feild to guardian 2016-08-11 17:28:21 +05:30
Rushabh Mehta
730f3e7aba [minor] remove validation #4904 2016-08-11 17:17:26 +05:30
Rohit Waghchaure
033ed00c56 [POS] fixed issue of negative stock 2016-08-11 16:37:29 +05:30
Rushabh Mehta
6c0d9579d2 Merge pull request #6055 from rohitwaghchaure/bank_reconciliation_statement_report_issue
[Fix] No permission to read DocType for account user in bank reconciliation statement report
2016-08-11 10:55:10 +05:30
Rushabh Mehta
09fc241d59 Merge pull request #6054 from rohitwaghchaure/purchase_invoice_accounting_issue_for_auto_stock
[Fix] Debit and credit not equal for purchase invoice, if update stock is yes and taxes is defined
2016-08-11 10:54:40 +05:30
Rohit Waghchaure
e78ef5f8c8 [Fix] No permission to read DocType for account user in bank reconciliation statement report 2016-08-11 00:46:15 +05:30
Rohit Waghchaure
315a5e1b4d [Fix] Debit and credit not equal for purchase invoice, if update stock is yes and taxes is defined 2016-08-11 00:35:00 +05:30
aruizramon
8bd2487533 semicolon 2016-08-09 16:04:45 -04:00
Alec Ruiz-Ramon
08fb39f1ba Validate on changing from Total to Valuation/Valuation&Total when add_deduct_tax is 'Deduct' 2016-08-09 15:38:34 -04:00
Rohit Waghchaure
baef2624a2 Given provision to enter write off and change amount on POS 2016-08-10 00:50:53 +05:30
Rohit Waghchaure
c41ab8d15b Added change amount account 2016-08-08 23:19:18 +05:30
Rohit Waghchaure
7127a8f522 Allow user to edit change amount from sales invoice form for is pos 2016-08-08 23:19:18 +05:30
97 changed files with 1046 additions and 600 deletions

View File

@@ -2,7 +2,7 @@
from __future__ import unicode_literals
import frappe
__version__ = '7.0.26'
__version__ = '7.0.32'
def get_default_company(user=None):
'''Get default company for user'''

View File

@@ -8,6 +8,7 @@
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"fields": [
{
"allow_on_submit": 0,
@@ -65,24 +66,24 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "monthly_distribution",
"fieldname": "company",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Monthly Distribution",
"label": "Company",
"length": 0,
"no_copy": 0,
"options": "Monthly Distribution",
"options": "Company",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
@@ -170,24 +171,25 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "company",
"depends_on": "eval:in_list([\"Stop\", \"Warn\"], doc.action_if_accumulated_monthly_budget_exceeded)",
"fieldname": "monthly_distribution",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Company",
"label": "Monthly Distribution",
"length": 0,
"no_copy": 0,
"options": "Company",
"options": "Monthly Distribution",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
@@ -271,13 +273,14 @@
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 1,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2016-05-16 15:00:40.233685",
"modified": "2016-08-18 14:46:02.653081",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Budget",

View File

@@ -5,7 +5,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import flt, getdate, add_months, get_last_day
from frappe.utils import flt, getdate, add_months, get_last_day, fmt_money
from frappe.model.naming import make_autoname
from frappe.model.document import Document
@@ -73,25 +73,30 @@ def validate_expense_against_budget(args):
args.posting_date, args.fiscal_year, budget.budget_amount)
args["month_end_date"] = get_last_day(args.posting_date)
compare_expense_with_budget(args, budget.cost_center,
budget_amount, _("Accumulated Monthly"), monthly_action)
elif yearly_action in ["Stop", "Warn"]:
compare_expense_with_budget(args, budget.cost_center,
flt(budget.budget_amount), _("Annual"), yearly_action)
if yearly_action in ("Stop", "Warn") and monthly_action != "Stop" \
and yearly_action != monthly_action:
compare_expense_with_budget(args, budget.cost_center,
flt(budget.budget_amount), _("Annual"), yearly_action)
def compare_expense_with_budget(args, cost_center, budget_amount, action_for, action):
actual_expense = get_actual_expense(args, cost_center)
if actual_expense > budget_amount:
diff = actual_expense - budget_amount
currency = frappe.db.get_value('Company', frappe.db.get_value('Cost Center',
cost_center, 'company'), 'default_currency')
msg = _("{0} Budget for Account {1} against Cost Center {2} is {3}. It will exceed by {4}").format(_(action_for), args.account, cost_center, budget_amount, diff)
msg = _("{0} Budget for Account {1} against Cost Center {2} is {3}. It will exceed by {4}").format(_(action_for),
frappe.bold(args.account), frappe.bold(cost_center),
frappe.bold(fmt_money(budget_amount, currency=currency)), frappe.bold(fmt_money(diff, currency=currency)))
if action=="Stop":
frappe.throw(msg, BudgetError)
else:
frappe.msgprint(msg)
frappe.msgprint(msg, indicator='orange')
def get_accumulated_monthly_budget(monthly_distribution, posting_date, fiscal_year, annual_budget):
distribution = {}

View File

@@ -32,8 +32,13 @@ cur_frm.cscript.refresh = function(doc, cdt, cdn) {
cur_frm.toggle_display('sb1', doc.is_group==0)
cur_frm.set_intro(intro_txt);
cur_frm.add_custom_button(__('Chart of Cost Centers'),
function() { frappe.set_route("Tree", "Cost Center"); }, __("View"))
if(!cur_frm.doc.__islocal) {
cur_frm.add_custom_button(__('Chart of Cost Centers'),
function() { frappe.set_route("Tree", "Cost Center"); });
cur_frm.add_custom_button(__('Budget'),
function() { frappe.set_route("List", "Budget", {'cost_center': cur_frm.doc.name}); });
}
}
cur_frm.cscript.parent_cost_center = function(doc, cdt, cdn) {

View File

@@ -118,6 +118,32 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "campaign",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Campaign",
"length": 0,
"no_copy": 0,
"options": "Campaign",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@@ -690,6 +716,32 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "account_for_change_amount",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Account for Change Amount",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@@ -833,7 +885,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2016-08-06 17:05:59.990031",
"modified": "2016-08-17 15:12:56.713748",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Profile",

View File

@@ -232,7 +232,8 @@ cur_frm.fields_dict['contact_person'].get_query = function(doc, cdt, cdn) {
cur_frm.fields_dict['items'].grid.get_field("item_code").get_query = function(doc, cdt, cdn) {
return {
query: "erpnext.controllers.queries.item_query"
query: "erpnext.controllers.queries.item_query",
filters: {'is_purchase_item': 1}
}
}

View File

@@ -497,6 +497,18 @@ class PurchaseInvoice(BuyingController):
i += 1
if self.update_stock and valuation_tax:
for cost_center, amount in valuation_tax.items():
gl_entries.append(
self.get_gl_dict({
"account": self.expenses_included_in_valuation,
"cost_center": cost_center,
"against": self.supplier,
"credit": amount,
"remarks": self.remarks or "Accounting Entry for Stock"
})
)
def make_payment_gl_entries(self, gl_entries):
# Make Cash GL Entries
if cint(self.is_paid) and self.cash_bank_account and self.paid_amount:

View File

@@ -18,3 +18,13 @@ frappe.ui.form.on("Purchase Taxes and Charges", "add_deduct_tax", function(doc,
}
refresh_field('add_deduct_tax', d.name, 'taxes');
});
frappe.ui.form.on("Purchase Taxes and Charges", "category", function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
if (d.category != 'Total' && d.add_deduct_tax == 'Deduct') {
msgprint(__("Cannot deduct when category is for 'Valuation' or 'Vaulation and Total'"));
d.add_deduct_tax = '';
}
refresh_field('add_deduct_tax', d.name, 'taxes');
});

View File

@@ -13,9 +13,9 @@ from erpnext.controllers.accounts_controller import get_taxes_and_charges
@frappe.whitelist()
def get_pos_data():
doc = frappe.new_doc('Sales Invoice')
doc.update_stock = 1;
doc.is_pos = 1;
pos_profile = get_pos_profile(doc.company) or {}
doc.update_stock = pos_profile.get('update_stock')
if pos_profile.get('name'):
pos_profile = frappe.get_doc('POS Profile', pos_profile.get('name'))
@@ -35,7 +35,6 @@ def get_pos_data():
'customers': get_customers(pos_profile, doc),
'pricing_rules': get_pricing_rules(doc),
'print_template': print_template,
'write_off_account': pos_profile.get('write_off_account'),
'meta': {
'invoice': frappe.get_meta('Sales Invoice'),
'items': frappe.get_meta('Sales Invoice Item'),
@@ -45,7 +44,12 @@ def get_pos_data():
def update_pos_profile_data(doc, pos_profile):
company_data = frappe.db.get_value('Company', doc.company, '*', as_dict=1)
doc.campaign = pos_profile.get('campaign')
doc.write_off_account = pos_profile.get('write_off_account') or \
company_data.write_off_account
doc.change_amount_account = pos_profile.get('change_amount_account') or \
company_data.default_cash_account
doc.taxes_and_charges = pos_profile.get('taxes_and_charges')
if doc.taxes_and_charges:
update_tax_table(doc)
@@ -54,7 +58,8 @@ def update_pos_profile_data(doc, pos_profile):
doc.conversion_rate = 1.0
if doc.currency != company_data.default_currency:
doc.conversion_rate = get_exchange_rate(doc.currency, company_data.default_currency)
doc.selling_price_list = pos_profile.get('selling_price_list') or frappe.db.get_value('Selling Settings', None, 'selling_price_list')
doc.selling_price_list = pos_profile.get('selling_price_list') or \
frappe.db.get_value('Selling Settings', None, 'selling_price_list')
doc.naming_series = pos_profile.get('naming_series') or 'SINV-'
doc.letter_head = pos_profile.get('letter_head') or company_data.default_letter_head
doc.ignore_pricing_rule = pos_profile.get('ignore_pricing_rule') or 0
@@ -100,7 +105,7 @@ def update_tax_table(doc):
def get_items(doc, pos_profile):
item_list = []
for item in frappe.get_all("Item", fields=["*"], filters={'disabled': 0, 'has_variants': 0}):
for item in frappe.get_all("Item", fields=["*"], filters={'disabled': 0, 'has_variants': 0, 'is_sales_item': 1}):
item_doc = frappe.get_doc('Item', item.name)
if item_doc.taxes:
item.taxes = json.dumps(dict(([d.tax_type, d.tax_rate] for d in
@@ -157,10 +162,11 @@ def get_customers(pos_profile, doc):
def get_pricing_rules(doc):
pricing_rules = ""
if doc.ignore_pricing_rule == 0:
pricing_rules = frappe.db.sql(""" Select * from `tabPricing Rule` where docstatus < 2 and disable = 0
and selling = 1 and ifnull(company, '') in (%(company)s, '') and
ifnull(for_price_list, '') in (%(price_list)s, '') and %(date)s between
ifnull(valid_from, '2000-01-01') and ifnull(valid_upto, '2500-12-31') order by priority desc, name desc""",
pricing_rules = frappe.db.sql(""" Select * from `tabPricing Rule` where docstatus < 2
and ifnull(for_price_list, '') in (%(price_list)s, '') and selling = 1
and ifnull(company, '') in (%(company)s, '') and disable = 0 and %(date)s
between ifnull(valid_from, '2000-01-01') and ifnull(valid_upto, '2500-12-31')
order by priority desc, name desc""",
{'company': doc.company, 'price_list': doc.selling_price_list, 'date': nowdate()}, as_dict=1)
return pricing_rules
@@ -173,17 +179,23 @@ def make_invoice(doc_list):
for docs in doc_list:
for name, doc in docs.items():
if not frappe.db.exists('Sales Invoice', {'offline_pos_name': name}):
validate_customer(doc)
validate_item(doc)
if not frappe.db.exists('Sales Invoice',
{'offline_pos_name': name, 'docstatus': ("<", "2")}):
validate_records(doc)
si_doc = frappe.new_doc('Sales Invoice')
si_doc.offline_pos_name = name
si_doc.update(doc)
submit_invoice(si_doc, name)
name_list.append(name)
else:
name_list.append(name)
return name_list
def validate_records(doc):
validate_customer(doc)
validate_item(doc)
def validate_customer(doc):
if not frappe.db.exists('Customer', doc.get('customer')):
customer_doc = frappe.new_doc('Customer')
@@ -195,8 +207,6 @@ def validate_customer(doc):
frappe.db.commit()
doc['customer'] = customer_doc.name
return doc
def validate_item(doc):
for item in doc.get('items'):
if not frappe.db.exists('Item', item.get('item_code')):
@@ -222,6 +232,7 @@ def submit_invoice(si_doc, name):
def save_invoice(e, si_doc, name):
if not frappe.db.exists('Sales Invoice', {'offline_pos_name': name}):
si_doc.docstatus = 0
si_doc.flags.ignore_mandatory = True
si_doc.insert()
make_scheduler_log(e, si_doc.name)

View File

@@ -267,6 +267,16 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
amount: function(){
this.write_off_outstanding_amount_automatically()
},
change_amount: function(){
if(this.frm.doc.paid_amount > this.frm.doc.grand_total){
this.calculate_write_off_amount()
}else {
this.frm.set_value("change_amount", 0.0)
}
this.frm.refresh_fields();
}
});
@@ -458,7 +468,7 @@ frappe.ui.form.on('Sales Invoice', {
]
}
}
},
}
})
frappe.ui.form.on('Sales Invoice Timesheet', {

View File

@@ -2200,32 +2200,6 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "base_change_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Base Change Amount (Company Currency)",
"length": 0,
"no_copy": 1,
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@@ -2278,6 +2252,80 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "section_break_88",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "base_change_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Base Change Amount (Company Currency)",
"length": 0,
"no_copy": 1,
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "column_break_90",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@@ -2297,7 +2345,33 @@
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "account_for_change_amount",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Account for Change Amount",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@@ -3677,7 +3751,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2016-08-03 11:50:49.680278",
"modified": "2016-08-17 15:12:39.357372",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",

View File

@@ -61,6 +61,7 @@ class SalesInvoice(SellingController):
self.clear_unallocated_advances("Sales Invoice Advance", "advances")
self.add_remarks()
self.validate_write_off_account()
self.validate_account_for_change_amount()
self.validate_fixed_asset()
self.set_income_account_for_fixed_assets()
@@ -233,12 +234,22 @@ class SalesInvoice(SellingController):
from erpnext.stock.get_item_details import get_pos_profile_item_details, get_pos_profile
pos = get_pos_profile(self.company)
if not self.get('payments'):
pos_profile = frappe.get_doc('POS Profile', pos.name) if pos else None
update_multi_mode_option(self, pos_profile)
if not self.account_for_change_amount:
self.account_for_change_amount = frappe.db.get_value('Company', self.company, 'default_cash_account')
if pos:
if not for_validate and not self.customer:
self.customer = pos.customer
self.mode_of_payment = pos.mode_of_payment
# self.set_customer_defaults()
if pos.get('account_for_change_amount'):
self.account_for_change_amount = pos.get('account_for_change_amount')
for fieldname in ('territory', 'naming_series', 'currency', 'taxes_and_charges', 'letter_head', 'tc_name',
'selling_price_list', 'company', 'select_print_heading', 'cash_bank_account',
'write_off_account', 'write_off_cost_center'):
@@ -265,10 +276,6 @@ class SalesInvoice(SellingController):
if self.taxes_and_charges and not len(self.get("taxes")):
self.set_taxes()
if not self.get('payments'):
pos_profile = frappe.get_doc('POS Profile', pos.name)
update_multi_mode_option(self, pos_profile)
return pos
def get_company_abbr(self):
@@ -374,11 +381,16 @@ class SalesInvoice(SellingController):
if d.delivery_note:
msgprint(_("Stock cannot be updated against Delivery Note {0}").format(d.delivery_note), raise_exception=1)
def validate_write_off_account(self):
if flt(self.write_off_amount) and not self.write_off_account:
self.write_off_account = frappe.db.get_value('Company', self.company, 'write_off_account')
if flt(self.write_off_amount) and not self.write_off_account:
msgprint(_("Please enter Write Off Account"), raise_exception=1)
def validate_account_for_change_amount(self):
if flt(self.change_amount) and not self.account_for_change_amount:
msgprint(_("Please enter Account for Change Amount"), raise_exception=1)
def validate_c_form(self):
""" Blank C-form no if C-form applicable marked as 'No'"""
@@ -502,7 +514,7 @@ class SalesInvoice(SellingController):
gl_entries = merge_similar_entries(gl_entries)
self.make_pos_gl_entries(gl_entries)
self.make_gle_for_change(gl_entries)
self.make_gle_for_change_amount(gl_entries)
self.make_write_off_gl_entry(gl_entries)
@@ -606,16 +618,15 @@ class SalesInvoice(SellingController):
}, payment_mode_account_currency)
)
def make_gle_for_change(self, gl_entries):
def make_gle_for_change_amount(self, gl_entries):
if cint(self.is_pos) and self.change_amount:
cash_account = self.get_cash_account()
if cash_account:
if self.account_for_change_amount:
gl_entries.append(
self.get_gl_dict({
"account": self.debit_to,
"party_type": "Customer",
"party": self.customer,
"against": cash_account,
"against": self.account_for_change_amount,
"debit": flt(self.base_change_amount),
"debit_in_account_currency": flt(self.base_change_amount) \
if self.party_account_currency==self.company_currency else flt(self.change_amount),
@@ -626,22 +637,13 @@ class SalesInvoice(SellingController):
gl_entries.append(
self.get_gl_dict({
"account": cash_account,
"account": self.account_for_change_amount,
"against": self.customer,
"credit": self.base_change_amount
})
)
def get_cash_account(self):
cash_account = [d.account for d in self.payments if d.type=="Cash"]
if cash_account:
cash_account = cash_account[0]
else:
cash_account = frappe.db.get_value("Account",
filters={"company": self.company, "account_type": "Cash", "is_group": 0})
return cash_account
else:
frappe.throw(_("Select change amount account"), title="Mandatory Field")
def make_write_off_gl_entry(self, gl_entries):
# write off entries, applicable if only pos

View File

@@ -455,6 +455,25 @@ class TestSalesInvoice(unittest.TestCase):
self.pos_gl_entry(si, pos, 300)
def test_pos_change_amount(self):
set_perpetual_inventory()
self.make_pos_profile()
self._insert_purchase_receipt()
pos = copy.deepcopy(test_records[1])
pos["is_pos"] = 1
pos["update_stock"] = 1
pos["payments"] = [{'mode_of_payment': 'Bank Draft', 'account': '_Test Bank - _TC', 'amount': 300},
{'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 340}]
si = frappe.copy_doc(pos)
si.change_amount = 5.0
si.insert()
si.submit()
self.assertEquals(si.grand_total, 630.0)
self.assertEquals(si.write_off_amount, -5)
def test_make_pos_invoice(self):
from erpnext.accounts.doctype.sales_invoice.pos import make_invoice

View File

@@ -183,6 +183,14 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
if(this.frm.doc.customer){
this.party_field.$input.val(this.frm.doc.customer);
}
if(!this.frm.doc.write_off_account){
this.frm.doc.write_off_account = doc.write_off_account
}
if(!this.frm.doc.account_for_change_amount){
this.frm.doc.account_for_change_amount = doc.account_for_change_amount
}
},
get_invoice_doc: function(si_docs){
@@ -209,7 +217,6 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
window.meta = r.message.meta;
window.print_template = r.message.print_template;
me.default_customer = r.message.default_customer || null;
me.write_off_account = r.message.write_off_account;
localStorage.setItem('doc', JSON.stringify(r.message.doc));
if(callback){
callback();
@@ -485,11 +492,8 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
this.remove_item = []
$.each(this.frm.doc["items"] || [], function(i, d) {
if (d.item_code == item_code && d.serial_no
&& field == 'qty' && cint(value) != value) {
d.qty = 0.0;
me.refresh();
frappe.throw(__("Serial no item cannot be a fraction"))
if(d.serial_no){
me.validate_serial_no_qty(d, item_code, field, value)
}
if (d.item_code == item_code) {
@@ -505,7 +509,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
this.remove_zero_qty_item();
}
this.refresh();
this.update_paid_amount_status(false)
},
remove_zero_qty_item: function(){
@@ -587,7 +591,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
if (!caught)
this.add_new_item_to_grid();
this.refresh();
this.update_paid_amount_status(false)
},
add_new_item_to_grid: function() {
@@ -612,6 +616,14 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
? this.item_serial_no[this.child.item_code][0] : '');
},
update_paid_amount_status: function(update_paid_amount){
if(this.name){
update_paid_amount = update_paid_amount ? false : true;
}
this.refresh(update_paid_amount);
},
refresh: function(update_paid_amount) {
var me = this;
this.refresh_fields(update_paid_amount);
@@ -619,6 +631,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
this.update_rate();
this.set_primary_action();
},
refresh_fields: function(update_paid_amount) {
this.apply_pricing_rule();
this.discount_amount_applied = false;
@@ -694,7 +707,8 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
if (this.frm.doc.docstatus==0) {
this.page.set_primary_action(__("Pay"), function() {
me.validate()
me.validate();
me.update_paid_amount_status(true);
me.create_invoice();
me.make_payment();
}, "octicon octicon-credit-card");
@@ -723,49 +737,6 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
}, 1000)
},
write_off_amount: function(){
var me = this;
var value = 0.0;
if(this.frm.doc.outstanding_amount > 0){
dialog = new frappe.ui.Dialog({
title: 'Write Off Amount',
fields: [
{fieldtype: "Check", fieldname: "write_off_amount", label: __("Write off Outstanding Amount")},
{fieldtype: "Link", options:"Account", default:this.write_off_account, fieldname: "write_off_account",
label: __("Write off Account"), get_query: function() {
return {
filters: {'is_group': 0, 'report_type': 'Profit and Loss'}
}
}}
]
});
dialog.show();
dialog.fields_dict.write_off_amount.$input.change(function(){
write_off_amount = dialog.get_values().write_off_amount;
me.frm.doc.write_off_outstanding_amount_automatically = write_off_amount;
me.frm.doc.base_write_off_amount = (write_off_amount==1) ? flt(me.frm.doc.grand_total - me.frm.doc.paid_amount, precision("outstanding_amount")) : 0;
me.frm.doc.write_off_account = (write_off_amount==1) ? dialog.get_values().write_off_account : '';
me.frm.doc.write_off_amount = flt(me.frm.doc.base_write_off_amount * me.frm.doc.conversion_rate, precision("write_off_amount"))
me.calculate_outstanding_amount();
me.set_primary_action();
})
dialog.fields_dict.write_off_account.$input.change(function(){
me.frm.doc.write_off_account = dialog.get_values().write_off_account;
})
dialog.set_primary_action(__("Submit"), function(){
dialog.hide()
me.submit_invoice()
})
}else{
this.submit_invoice()
}
},
submit_invoice: function(){
var me = this;
frappe.confirm(__("Do you really want to submit the invoice?"), function () {
@@ -804,6 +775,8 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
this.update_invoice()
}else{
this.name = $.now();
this.frm.doc.posting_date = frappe.datetime.get_today();
this.frm.doc.posting_time = frappe.datetime.now_time();
invoice_data[this.name] = this.frm.doc
this.si_docs.push(invoice_data)
this.update_localstorage();
@@ -949,6 +922,23 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
}
},
validate_serial_no_qty: function(args, item_code, field, value){
var me = this;
if (args.item_code == item_code && args.serial_no
&& field == 'qty' && cint(value) != value) {
args.qty = 0.0;
this.refresh();
frappe.throw(__("Serial no item cannot be a fraction"))
}
if(args.serial_no && args.serial_no.split('\n').length != cint(value)){
args.qty = 0.0;
args.serial_no = ''
this.refresh();
frappe.throw(__("Total nos of serial no is not equal to quantity."))
}
},
mandatory_batch_no: function(){
var me = this;
if(this.items[0].has_batch_no && !this.item_batch_no[this.items[0].item_code]){
@@ -976,11 +966,13 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
get_pricing_rule: function(item){
var me = this;
return $.grep(this.pricing_rules, function(data){
if(data.item_code == item.item_code || in_list(['All Item Groups', item.item_group], data.item_group)) {
if(in_list(['Customer', 'Customer Group', 'Territory'], data.applicable_for)){
return me.validate_condition(data)
}else{
return true
if(item.qty >= data.min_qty && (item.qty <= (data.max_qty ? data.max_qty : item.qty)) ){
if(data.item_code == item.item_code || in_list(['All Item Groups', item.item_group], data.item_group)) {
if(in_list(['Customer', 'Customer Group', 'Territory', 'Campaign'], data.applicable_for)){
return me.validate_condition(data)
}else{
return true
}
}
}
})
@@ -999,6 +991,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
'Customer': [data.customer, [this.frm.doc.customer]],
'Customer Group': [data.customer_group, [this.frm.doc.customer_group, 'All Customer Groups']],
'Territory': [data.territory, [this.frm.doc.territory, 'All Territories']],
'Campaign': [data.campaign, [this.frm.doc.campaign]],
}
},

View File

@@ -6,9 +6,9 @@
"docstatus": 0,
"doctype": "Print Format",
"font": "Default",
"html": "<style>\n\t.print-format table, .print-format tr, \n\t.print-format td, .print-format div, .print-format p {\n\t\tfont-family: Monospace;\n\t\tline-height: 200%;\n\t\tvertical-align: middle;\n\t}\n\t@media screen {\n\t\t.print-format {\n\t\t\twidth: 4in;\n\t\t\tpadding: 0.25in;\n\t\t\tmin-height: 8in;\n\t\t}\n\t}\n</style>\n\n<p class=\"text-center\">\n\t{{ company }}<br>\n\t{{ __(\"Invoice\") }}<br>\n</p>\n<p>\n\t<b>{{ __(\"Date\") }}:</b> {{ dateutil.global_date_format(posting_date) }}<br>\n</p>\n\n<hr>\n<table class=\"table table-condensed cart no-border\">\n\t<thead>\n\t\t<tr>\n\t\t\t<th width=\"50%\">{{ __(\"Item\") }}</b></th>\n\t\t\t<th width=\"25%\" class=\"text-right\">{{ __(\"Qty\") }}</th>\n\t\t\t<th width=\"25%\" class=\"text-right\">{{ __(\"Amount\") }}</th>\n\t\t</tr>\n\t</thead>\n\t<tbody>\n\t\t{% for item in items %}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t{{ item.item_name }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">{{ item.qty }}<br>@ {{ format_currency(item.rate, currency) }}</td>\n\t\t\t<td class=\"text-right\">{{ format_currency(item.amount, currency) }}</td>\n\t\t</tr>\n\t\t{% endfor %}\n\t</tbody>\n</table>\n\n<table class=\"table table-condensed no-border\">\n\t<tbody>\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ __(\"Net Total\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(total, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{% for row in taxes %}\n\t\t{% if not row.included_in_print_rate %}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ row.description }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(row.tax_amount, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{% endif %}\n\t\t{% endfor %}\n\t\t{% if discount_amount %}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t{{ __(\"Discount\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(discount_amount, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{% endif %}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ __(\"Grand Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(grand_total, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t</tbody>\n</table>\n\n\n<hr>\n<p class=\"text-center\">{{ __(\"Thank you, please visit again.\") }}</p>",
"html": "<style>\n\t.print-format table, .print-format tr, \n\t.print-format td, .print-format div, .print-format p {\n\t\tfont-family: Monospace;\n\t\tline-height: 200%;\n\t\tvertical-align: middle;\n\t}\n\t@media screen {\n\t\t.print-format {\n\t\t\twidth: 4in;\n\t\t\tpadding: 0.25in;\n\t\t\tmin-height: 8in;\n\t\t}\n\t}\n</style>\n\n<p class=\"text-center\">\n\t{{ company }}<br>\n\t{{ __(\"Invoice\") }}<br>\n</p>\n<p>\n\t<b>{{ __(\"Date\") }}:</b> {{ dateutil.global_date_format(posting_date) }}<br>\n</p>\n\n<hr>\n<table class=\"table table-condensed cart no-border\">\n\t<thead>\n\t\t<tr>\n\t\t\t<th width=\"50%\">{{ __(\"Item\") }}</b></th>\n\t\t\t<th width=\"25%\" class=\"text-right\">{{ __(\"Qty\") }}</th>\n\t\t\t<th width=\"25%\" class=\"text-right\">{{ __(\"Amount\") }}</th>\n\t\t</tr>\n\t</thead>\n\t<tbody>\n\t\t{% for item in items %}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t{{ item.item_name }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">{{ format_number(item.qty, precision(\"difference\")) }}<br>@ {{ format_currency(item.rate, currency) }}</td>\n\t\t\t<td class=\"text-right\">{{ format_currency(item.amount, currency) }}</td>\n\t\t</tr>\n\t\t{% endfor %}\n\t</tbody>\n</table>\n\n<table class=\"table table-condensed no-border\">\n\t<tbody>\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ __(\"Net Total\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(total, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{% for row in taxes %}\n\t\t{% if not row.included_in_print_rate %}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ row.description }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(row.tax_amount, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{% endif %}\n\t\t{% endfor %}\n\t\t{% if discount_amount %}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t{{ __(\"Discount\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(discount_amount, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{% endif %}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ __(\"Grand Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(grand_total, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t</tbody>\n</table>\n\n\n<hr>\n<p class=\"text-center\">{{ __(\"Thank you, please visit again.\") }}</p>",
"idx": 0,
"modified": "2016-05-21 00:25:20.359074",
"modified": "2016-08-11 07:23:04.530676",
"modified_by": "Administrator",
"name": "Point of Sale",
"owner": "Administrator",

View File

@@ -66,7 +66,8 @@ class ReceivablePayableReport(object):
columns.append({
"fieldname": "currency",
"label": _("Currency"),
"fieldtype": "Data",
"fieldtype": "Link",
"options": "Currency",
"width": 100
})
if args.get("party_type") == "Customer":

View File

@@ -34,7 +34,8 @@ class AccountsReceivableSummary(ReceivablePayableReport):
columns.append({
"fieldname": "currency",
"label": _("Currency"),
"fieldtype": "Data",
"fieldtype": "Link",
"options": "Currency",
"width": 80
})

View File

@@ -55,14 +55,6 @@ def get_columns():
"fieldtype": "Date",
"width": 90
},
{
"fieldname": "payment_document",
"label": _("Payment Document"),
"fieldtype": "Link",
"options": "DocType",
"width": 120,
"hidden": 1
},
{
"fieldname": "payment_entry",
"label": _("Payment Entry"),

View File

@@ -79,7 +79,8 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
}
} else {
return{
query: "erpnext.controllers.queries.item_query"
query: "erpnext.controllers.queries.item_query",
filters: {'is_purchase_item': 1}
}
}
});

View File

@@ -11,5 +11,72 @@ frappe.query_reports["Quoted Item Comparison"] = {
"default": ""
}
]
],
onload: function(report) {
//Create a button for setting the default supplier
report.page.add_inner_button(__("Select Default Supplier"), function() {
var reporter = frappe.query_reports["Quoted Item Comparison"];
//Always make a new one so that the latest values get updated
reporter.make_default_supplier_dialog(report);
report.dialog.show();
setTimeout(function() { report.dialog.input.focus(); }, 1000);
}, 'Tools');
},
"make_default_supplier_dialog": function (report) {
//Get the name of the item to change
var filters = report.get_values();
var item_code = filters.item;
//Get a list of the suppliers (with a blank as well) for the user to select
var select_options = "";
for (let supplier of report.data)
{
select_options += supplier.supplier_name+ '\n'
}
//Create a dialog window for the user to pick their supplier
var d = new frappe.ui.Dialog({
title: __('Select Default Supplier'),
fields: [
{fieldname: 'supplier', fieldtype:'Select', label:'Supplier', reqd:1,options:select_options},
{fieldname: 'ok_button', fieldtype:'Button', label:'Set Default Supplier'},
]
});
//On the user clicking the ok button
d.fields_dict.ok_button.input.onclick = function() {
var btn = d.fields_dict.ok_button.input;
var v = report.dialog.get_values();
if(v) {
$(btn).set_working();
//Set the default_supplier field of the appropriate Item to the selected supplier
frappe.call({
method: "frappe.client.set_value",
args: {
doctype: "Item",
name: item_code,
fieldname: "default_supplier",
value: v.supplier,
},
callback: function (r){
$(btn).done_working();
msgprint("Successfully Set Supplier");
report.dialog.hide();
}
});
}
}
report.dialog = d;
}
}

View File

@@ -0,0 +1,58 @@
#### New POS
- Offline
- Multiple Payment Modes
- Standard documents cannot be edited in POS view
#### Payment Entry
- Dedicated form for managing Payments
- Designed for normal users who do not have accounting background
#### Request for Quotation
- Updated workflow: Material Request -> **Request for Quotation** -> Supplier Quotation -> Purchase Order
#### Fixed Asset Management
- Manage fixed asset records and their depreciation
#### Improved Navigation
- Heatmaps
- Centralized navigation from Masters like Item, Customer, Supplier, Employee etc.
#### Timesheets
- New grid
- Multiple time logs in one timesheets
- Linked to Payroll and Billing
#### Graphs in Reports
- Added graphs in some important reports like Balance Sheet, Accounts Receivable etc.
#### Sub-warehouse
- Tree view for Warehouse
#### New Portal Design
- New Homepage Design
- Sidebar in Portal View
- New Cart View
#### Collaborative Project Management
- Web View
- Customers/Suppliers can add/edit issues and view timesheets
#### Budget
- Dedicated budget form
- Budget can be assigned against Cost Center Group
#### Check Printing Format
- Ability to customize Cheque Printing Format for any bank
#### Schools application is now part of ERPNext
#### Minor
- Selling Price calculation based on Margin defined in the Pricing Rule
- Document flow-chart on Sales / Purchase Transactions
- Domain specific desktop views
- Add opening Stock and Rate while creating a new Item
- Book payments and update stock directly from Purchase Invoice
- List view for Products on Website
- Features Setup is deprecated, settings moved to individual module setup views
- Added Safety Stock to Item Master

View File

@@ -204,10 +204,10 @@ class StockController(AccountsController):
from erpnext.stock.stock_ledger import make_sl_entries
make_sl_entries(sl_entries, is_amended, allow_negative_stock, via_landed_cost_voucher)
def make_gl_entries_on_cancel(self):
def make_gl_entries_on_cancel(self, repost_future_gle=True):
if frappe.db.sql("""select name from `tabGL Entry` where voucher_type=%s
and voucher_no=%s""", (self.doctype, self.name)):
self.make_gl_entries()
self.make_gl_entries(repost_future_gle)
def get_serialized_items(self):
serialized_items = []
@@ -261,7 +261,7 @@ def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for
future_stock_vouchers = get_future_stock_vouchers(posting_date, posting_time, for_warehouses, for_items)
gle = get_voucherwise_gl_entries(future_stock_vouchers, posting_date)
for voucher_type, voucher_no in future_stock_vouchers:
existing_gle = gle.get((voucher_type, voucher_no), [])
voucher_obj = frappe.get_doc(voucher_type, voucher_no)

View File

@@ -440,6 +440,7 @@ class calculate_taxes_and_totals(object):
paid_amount = self.doc.paid_amount \
if self.doc.party_account_currency == self.doc.currency else self.doc.base_paid_amount
self.calculate_write_off_amount()
self.calculate_change_amount()
self.doc.outstanding_amount = flt(total_amount_to_pay - flt(paid_amount) +
@@ -468,6 +469,13 @@ class calculate_taxes_and_totals(object):
self.doc.base_change_amount = flt(self.doc.change_amount * self.doc.conversion_rate,
self.doc.precision("base_change_amount"))
def calculate_write_off_amount(self):
if flt(self.doc.change_amount) > 0:
self.doc.write_off_amount = flt(self.doc.grand_total - self.doc.paid_amount + self.doc.change_amount,
self.doc.precision("write_off_amount"))
self.doc.base_write_off_amount = flt(self.doc.write_off_amount * self.doc.conversion_rate,
self.doc.precision("base_write_off_amount"))
def calculate_margin(self, item):
total_margin = 0.0
if item.price_list_rate:

View File

@@ -51,7 +51,8 @@ erpnext.crm.Opportunity = frappe.ui.form.Controller.extend({
this.frm.set_query("item_code", "items", function() {
return {
query: "erpnext.controllers.queries.item_query"
query: "erpnext.controllers.queries.item_query",
filters: {'is_sales_item': 1}
};
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 547 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 566 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 231 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 KiB

View File

@@ -1,36 +0,0 @@
#Cheque Print
** Whats is Cheque Print? **
You can choose to print Cheques at the time of making payments to Creditors/ parties during Voucher Entry i.e., directly from the Payment Vouchers and Inter-bank payment or transfers through Contra Vouchers.
###Setup Cheque Print
To enable cheque printing,
1. Create cheque settings under `Accounts > Cheque Print Template`.
![Cheque Print Template]({{docs_base_url}}/assets/img/articles/cueque_print_template.png)
You can see a preview of cheque print by attaching scanned copy of cheque to avoid miss printing.
![Cheque scanned copy]({{docs_base_url}}/assets/img/articles/attach_scanned_copy.png)
![Cheque Print Preview]({{docs_base_url}}/assets/img/articles/cueque_print_preview.png)
2. After saving cheque print settings, you can Create / Update print format for settings.
To create print format, click on `Create Print Format`.
![Create Print Format]({{docs_base_url}}/assets/img/articles/create_print_format.png)
If you have already created a Print Format, you can update it by clicking on `Update Print Format`.
3. You will see newly created / updated print format under Journal Entry.
![Print from Journal Entry]({{docs_base_url}}/assets/img/articles/journal_entry_cheque_print.png)
###Cheque Print
![Print from Journal Entry]({{docs_base_url}}/assets/img/articles/cheque_print.gif)

View File

@@ -1,41 +0,0 @@
#Depreciation for Fixed Asset Items
Depreciation is when you write off certain value of your assets as an expense. For example, office computer will be used for five years. Hence total value of computer should be booked as expense over the period of five years.
As per perpetual inventory valuation system (set by default), you should create Stock Reconciliation for depreciating value of fixed asset items. Check below steps to learn more.
#### Step 1: Depreciation Account
Depreciation account is auto-created, under Indirect Expenses account.
<img alt="Project Default Cost Center" class="screenshot" src="{{docs_base_url}}/assets/img/articles/depreciation-1.png">
#### Step 2: Stock Reconciliation
To create new Stock Reconciliation, go to:
`Stock > Setup > Stock Reconciliation > New`
Set Posting Date and Time of Stock Reconciliation will when you wish depreciation entry to be posted in your accounts.
#### Step 3: Item
Select Fixed Asset Items in the item table. Update Warehouse of an item. For item valuation, update post-depreciation value. For example, item value was 100. Depreciation amount is 20. As per this post-depreciation valuation of an item will be 80. Hence 80 should be posted as valuation in the Stock Reconciliation.
<img alt="Project Default Cost Center" class="screenshot" src="{{docs_base_url}}/assets/img/articles/depreciation-2.png">
#### Step 4: Depreciation Account
Select Depereciation Account in which depereciation amount will be booked.
<img alt="Project Default Cost Center" class="screenshot" src="{{docs_base_url}}/assets/img/articles/depreciation-3.png">
#### Step 5: Submit
On submission of Stock Reconciliation, depreciation will booked for items asset items.
<img alt="Project Default Cost Center" class="screenshot" src="{{docs_base_url}}/assets/img/articles/depreciation-4.png">
Click [here]({{docs_base_url}}/user/manual/en/setting-up/stock-reconciliation-for-non-serialized-item.html) for steps to be followed when making Stock Reconciliation entry.
<!-- markdown -->

View File

@@ -1,28 +1,36 @@
#How To Freeze Accounting Ledger?
You can freeze any accounting ledger in ERPNext. So that frozen accounting ledger became unsearchable in accounting transaction. Follow below step to understand the process.
If you want to discontinue using specific Account, you can freeze it.
#### 1. Set Frozen Accounts Modifier
>Account can be Frozen by the User having specific Role. This Role for set in the Account Settings, in the field "Role Allowed to Set Frozen Accounts & Edit Frozen Entries".
To set frozen accounts modifier go to `Accounts > Setup > Accounts Setting`
Please check following steps to freeze an Account from the Chart of Accounts master.
Search and select Role under Frozen Accounts Modifier field and save the Account Settings form.
![Account Settings]({{docs_base_url}}/assets/img/articles/Selection_001f1e2ff.png)
####Step 1: Chart of Accounts
#### 2. Edit Accounting Ledger.
To edit an Account, go to Chart of Accounts:
To edit accounting ledger go to `Accounts > Setup > Chart of Accounts`
`Explore > Accounts > Chart of Accounts`
![Account Settings]({{docs_base_url}}/assets/img/articles/Selection_0027e4d09.png)
<img class="screenshot" alt="Freeze Account" src="{{docs_base_url}}/assets/img/articles/freeze-account-1.png">
#### 3. Set Frozen Status of Ledger.
Click on Account in which Frozen Date is to be updated.
![Account Settings]({{docs_base_url}}/assets/img/articles/Selection_003bf981b.png)
####Step 2: Set Account as Frozen
In the Account form, you will find a field called **Frozen**. Set value in this field as 'Yes'
<img class="screenshot" alt="Freeze Account" src="{{docs_base_url}}/assets/img/articles/freeze-account-2.png">
####Step 3: Save
After update Save an Account.
On saving, this Account will be frozen and will not be selectable in any accounting transaction.
<div class ="well"> Note: In future, if you want to make an accounting transaction against this Account, then you can unfreeze this account by setting values in the Frozen field as 'No'.</div>
Set Frozen field status of ledger as 'Yes' and save the ledger form. On save this ledger will be frozen and you will became unable to search this ledger in accounting transactions.
<div class ="well"> Note: If you want to make accounting transaction against this ledger in the future, then that time again set frozen field status as 'No'.</div>
<!-- markdown -->

View File

@@ -1,7 +1,5 @@
tracking-project-profitability-using-cost-center
c-form
changing-parent-account
depreciation-for-fixed-asset-items
difference-entry-button
fiscal-year-error
freeze-accounting-entries
@@ -13,4 +11,4 @@ post-dated-cheque-entry
update-stock-option-in-sales-invoice
what-is-the-differences-of-total-and-valuation-in-tax-and-charges
withdrawing-salary-from-owners-equity-account
cheque-print
c-form

View File

@@ -1,32 +1,32 @@
#Post Dated Cheque Entry
Post Dated Cheque is a cheque dated on future date. Party generally give post dated cheque, as advance payment. This cheque would be cleared only after cheque date has arrived.
Post Dated Cheque is a cheque dated on future date. Party generally give post dated cheque, as advance payment. This cheque would be cleared only when cheque date arrives.
In ERPNext, create Journal Entries for post dated cheque.
In ERPNext, create Payment Entry for post dated cheque.
####New Journal Entry
####New Payment Entry
To open new journal voucher go to
`Accounts > Documents > Journal Entry > New`
`Explore > Accounts > Payment Entry > New`
#### Set Posting Date
Assuming your Cheque Date is 31st December, 2016 (or any future date). As a result, this posting in your bank ledger will appear on Posting Date updated.
<img alt="JE Posting Date" class="screenshot" src="{{docs_base_url}}/assets/img/articles/post-dated-1.gif">
<img alt="JE Posting Date" class="screenshot" src="{{docs_base_url}}/assets/img/articles/post-dated-1.png">
Note: Journal Voucher Reference Date should equal to or less than Posting Date.
Note: Payment Entry Reference Date should equal to or less than Posting Date.
####Step 3: Save and Submit
After entering required details, Save and Submit the Journal Entry.
After entering required details, Save and Submit the Payment Entry.
####Adjusting Post Dated Cheque Entry
If Post Dated Journal Entry needs to be adjusted against any invoice, it can be accomplished via [Payment Reconciliation Tool]({{docs_base_url}}/user/manual/en/accounts/tools/payment-reconciliation.html).
You can adjust Post Dated Payment Entry against an invoice via [Payment Reconciliation Tool]({{docs_base_url}}/user/manual/en/accounts/tools/payment-reconciliation.html).
When cheque is cleared, i.e. on actual date on the cheque, you can update its Clearance Date via [Bank Reconciliation Tool]({{docs_base_url}}/user/manual/en/accounts/tools/bank-reconciliation.html).
You might find value of this Journal Entry already reflecting against bank's ledger. You should check **Bank Reconciliation Statement**, a report in the account module to know difference of bank balance as per system, and actual balance in a account.
In the Chart of Accounts, you might find value of this Payment Entry already reflecting against bank Account. You should check **Bank Reconciliation Statement**, a report in the account module to know difference of bank balance as per system, and actual balance in the bank's statement.
<!-- markdown -->

View File

@@ -1,74 +0,0 @@
<h1>Setting Up Dropbox Backups</h1>
<h1>Setting Up Dropbox Backups</h1>
<p style="font-family: 'Noto Sans', sans-serif; line-height: 23.7999992370605px;">If you wish to store your backups on a periodic basis,on Dropbox, you can do it directly through ERPNext.</p>
<blockquote style="font-family: 'Noto Sans', sans-serif; line-height: 23.7999992370605px; background-color: rgb(247, 247, 247);">
<p>Setup &gt; Manage 3rd Party Backups</p>
</blockquote>
<p style="font-family: 'Noto Sans', sans-serif; line-height: 23.7999992370605px;"><strong>Step 1:</strong>&nbsp;Click on Integrations &gt; Backup Manager
<br>
</p>
<br>
<div>
<p style="font-family: 'Noto Sans', sans-serif; line-height: 23.7999992370605px;">In the Backup Manager page, enter the email addresses of those people whom you wish to notify about the upload status. Under the topic 'Sync with Dropbox', select whether you wish to upload Daily, Weekly or Never.</p>
<p style="font-family: 'Noto Sans', sans-serif; line-height: 23.7999992370605px;"><strong>Step 2</strong> Click on&nbsp;<strong>Allow Dropbox Access</strong>.</p>
<blockquote style="font-family: 'Noto Sans', sans-serif; line-height: 23.7999992370605px; background-color: rgb(247, 247, 247);">
<p>Tip: In future, if you wish to discontinue uploading backups to dropbox, then select the Never option.</p>
</blockquote>
<img src="{{docs_base_path}}/assets/img/articles/Screen Shot 2015-09-23 at 1.02.52 pm.png">
</div>
<div>&nbsp;
<br>
</div>
<div><b>
Step 3</b>
<br>
</div>
<div>
<p style="font-family: 'Noto Sans', sans-serif; line-height: 23.7999992370605px;">You need to login to your dropbox account, with your user id and password.</p>
</div>
<div>
<img src="{{docs_base_path}}/assets/img/articles/dropbox-access.png" style="line-height: 1.42857143;">&nbsp;
<br>
</div>
<div>
<br>
<hr>
</div>
<div>
<h3 style="font-family: 'Noto Sans', Helvetica, Arial, sans-serif; color: rgb(51, 51, 51);">Open Source Users</h3>
</div>
<div>
<br>
</div>
<div><b>Step 1: </b>Go to&nbsp;<a href="https://www.dropbox.com/developers/apps" target="_blank" style="line-height: 1.42857143;">https://www.dropbox.com/developers/apps</a>
</div>
<div><b>Step 2:</b> Create a new app</div>
<div>
<img src="{{docs_base_path}}/assets/img/articles/Screen Shot 2014-11-11 at 11.22.38 pm.png">
<br>
</div>
<div><b>Step 3: </b>Fill in details for the app.</div>
<div>
<img src="{{docs_base_path}}/assets/img/articles/Screen Shot 2014-11-11 at 11.23.32 pm.png">
<br>
</div>
<div>
<br>
</div>
<div><b>Step 4: </b>After the app is created, note the app key and app secret and enter in `sites/{sitename}/site_config.json` as follows,</div>
<div>
<br>
</div>
<div><pre><code>{
"db_name": "demo",
"db_password": "DZ1Idd55xJ9qvkHvUH",
"dropbox_access_key": "ACCESSKEY",
"dropbox_secret_key": "SECRECTKEY"
} </code></pre>
<br>
</div>
<div><b>Step 5: </b>Setup dropbox backups from the backup manager as shown in previous section.</div>

View File

@@ -0,0 +1,74 @@
#Setting Up Dropbox Backups
We always recommend customers to maintain backup of their data in ERPNext. he database backup is downloaded in the form of an SQL file. If needed, this SQL file of backup can be restored in the another ERPNext account as well.
You can automate database backup download of your ERPNext account into your Dropbox account.
####Step 1: Go to Setup
`Explore > Setup > Integrations > Dropbox Backup`
####Step 2: Activate
In the Dropbox Backup, check "Send Backups to Dropbox" to active this feature. On checking this field, you will find field to set Frequency and notification Email.
####Step 3: Set Frequency
Set Frequency to download backup in your Dropbox account.
<img class="screenshot" alt="set frequency" src="{{docs_base_url}}/assets/img/setup/dropbox-1.png">
####Step 4: Allow Dropbox Access
After setting frequency and updating notification email, click on `Allow Dropbox access`. On clicking this button, the Dropbox login page will open in the new tab. This might require you to allow pop-up for your ERPNext account.
####Step 5: Login to Dropbox
Login to your Dropbox account by entering login credentials.
<img class="screenshot" alt="Login" src="{{docs_base_url}}/assets/img/setup/dropbox-2.png">
####Step 6: Allow
On successfull login, you will find a confirmation message as following. Click on "Allow" to let your ERPNext account have access to your Dropbox account.
<img class="screenshot" alt="Allow" src="{{docs_base_url}}/assets/img/setup/dropbox-3.png">
With this, a folder called "ERPNext" will be created in your Dropbox account, and database backup will start to auto-download in it.
##Open Source Users
####Step 1: Go to
<a href="https://www.dropbox.com/developers/apps" target="_blank" style="line-height: 1.42857143;">https://www.dropbox.com/developers/apps</a>
####Step 2:Create a new app
<img class="screenshot" alt="Create new" src="{{docs_base_url}}/assets/img/setup/dropbox-open-3.png">
####Step 3: Fill in details for the app
<img class="screenshot" alt="Create new" src="{{docs_base_url}}/assets/img/setup/dropbox-open-1.png">
-
<img class="screenshot" alt="Create new" src="{{docs_base_url}}/assets/img/setup/dropbox-open-2.png">
####Step 4: Settings in Site Config
After the app is created, note the app key and app secret and enter in `sites/{sitename}/site_config.json` as follows,
<div>
<pre>
<code>{
"db_name": "demo",
"db_password": "DZ1Idd55xJ9qvkHvUH",
"dropbox_access_key": "ACCESSKEY",
"dropbox_secret_key": "SECRECTKEY"
}
</code>
</pre>
</div>
####Step 5: Complete Backup
Setup dropbox backups from the backup manager as shown in previous section.

View File

@@ -1,23 +1,38 @@
# Letter Heads
#Letter Head
You can manage multiple letter heads in ERPNext. In a letter head you can:
Each company has default Letter Head for their company. This Letter Head values are generally set as Header and Footer in the documents. In ERPNext, you can capture the these details in the Letter Head master.
* Create an image with your logo, brand and other information that you want to put on your letter head.
* Attach the image in your Letter Head record by clicking on image icon to automatically generate the HTML required for this Letter Head.
* If you want to make this the default letter head, click on “Is Default”.
In the Letter Head master, you can track Header and Footer details of the company. These details will appear in the Print Format of the transactions like Sales Order, Sales Invoice, Salary Slip, Purchase Order etc.
Your letter head will now appear in all Prints and Emails of documents.
####Step 1: Go to Setup
You can create / manage Letter Heads from:
`Explore > Setup > Printing > Letter Head > New Letter Head`
> Setup > Printing > Letter Head > New Letter Head
####Step 2: Letter Head Name
### Example
In one ERPNext account, you can enter multiple Letter Head, hence name Letter Head so that you can identify it easily. For example, if your Letter Head also contains office address, then you should create separate Letter Head for each office location.
####Step 3: Enter Details
Following is how you can enter details in the Letter Head.
* Logo Image: You can insert the image in your Letter Head record by clicking on image icon. Once image is inserted, HTML for it will be generated automatically.
* Other information (like Address, tax ID etc.) that you want to put on your letter head.
<img class="screenshot" alt="Print Heading" src="{{docs_base_url}}/assets/img/setup/print/letter-head.png">
> If you want to make this the default letter head, click on “Is Default”.
This is how the letter head looks in a document print:
####Step 4: Save
After enter values in the Header and Footer section, Save Letter Head.
####Letter Head in the Print Format
This is how the letter head looks in a document's print.
<img class="screenshot" alt="Print Heading" src="{{docs_base_url}}/assets/img/setup/print/letter-head-1.png">
{next}
> Please note that Footer will be visible only when document's print is seen in the PDF. Footer will not be visible in the HTML based print preview.
{next}

View File

@@ -1,72 +1,60 @@
# User Permissions
Limit access for a User to a set of documents using User Permissions Manager
Role Base Permissions define the periphery of document types within which a user with a set of Roles can move around in. However, you can have an even finer control by defining User Permissions for a User. By setting specific documents in User Permissions list, you can limit access for that User to specific documents of a particular DocType, on the condition that "Apply User Permissions" is checked in Role Permissions Manager.
To start with, go to:
> Setup > Permissions > User Permissions Manager
<figure>
<img src="{{docs_base_url}}/assets/img/users-and-permissions/user-permissions-company.png"
class="img-responsive" alt="User Permissions Manager">
<figcaption>User Permissions Manager displaying how users can access only a specific Company.</figcaption>
</figure>
User Permissions Manager displaying how users can access only a specific Company.
#### Example
User 'aromn@example.com' has Sales User role and we want to limit the user to access records for only a specific Company 'Wind Power LLC'.
User 'tom.hagen@riosolutions.com' has Sales User role and we want to limit the user to access records for only a specific Company 'Rio Solutions'.
1. We add a User Permissions row for Company.
<figure>
<img src="{{docs_base_url}}/assets/img/users-and-permissions/user-permission-user-limited-by-company.png"
class="img-responsive" alt="User Permissions For Company">
<figcaption>Add User Permissions row for a combination of User 'aromn@example.com' and Company 'Wind Power LLC'.</figcaption>
</figure>
<img src="{{docs_base_url}}/assets/img/users-and-permissions/user-permissions-new.gif" class="screen" alt="User Permissions For Company">
Add User Permissions row for a combination of User 'tom.hagen@riosolutions.com' and Company 'Rio Solutions'.
1. Also Role "All" has only Read permission for Company, with 'Apply User Permissions' checked.
<figure>
<img src="{{docs_base_url}}/assets/img/users-and-permissions/user-permissions-company-role-all.png"
class="img-responsive" alt="Role Permissions for All on Company">
<figcaption>Read Permission with Apply User Permissions checked for DocType Company.</figcaption>
</figure>
<img src="{{docs_base_url}}/assets/img/users-and-permissions/user-permissions-company-role-all.png" class="screen" alt="Role Permissions for All on Company">
1. The combined effect of the above two rules lead to User 'aromn@example.com' having only Read access to Company 'Wind Power LLC'.
<figure>
<img src="{{docs_base_url}}/assets/img/users-and-permissions/user-permissions-company-wind-power-llc.png"
class="img-responsive" alt="Effect of Role and User Permissions on Company">
<figcaption>Access is limited to Company 'Wind Power LLC'.</figcaption>
</figure>
Read Permission with Apply User Permissions checked for DocType Company.
1. The combined effect of the above two rules lead to User 'tom.hagen@riosolutions.com' having only Read access to Company 'Rio Solutions'.
<img src="{{docs_base_url}}/assets/img/users-and-permissions/user-permission-company.png" class="screen" alt="Effect of Role and User Permissions on Company">
Access is limited to Company 'Rio Solutions'.
1. We want this User Permission on Company to get applied on other documents like Quotation, Sales Order, etc.
These forms have a **Link Field based on Company**. As a result, User Permissions on Company also get applied on these documents, which leads to User 'aromn@example.com' to acces these documents having Company 'Wind Power LLC'.
<figure>
<img src="{{docs_base_url}}/assets/img/users-and-permissions/user-permissions-quotation-sales-user.png"
class="img-responsive" alt="Sales User Role Permissions for Quotation">
<figcaption>Users with Sales User Role can Read, Write, Create, Submit and Cancel Quotations based on their User Permissions, since 'Apply User Permissions' is checked.</figcaption>
</figure>
<figure>
<img src="{{docs_base_url}}/assets/old_images/erpnext/user-permissions-quotation-list.png"
class="img-responsive" alt="Quotation List limited to results for Company 'Wind Power LLC'">
<figcaption>Quotation List is limited to results for Company 'Wind Power LLC' for User 'aromn@example.com'.</figcaption>
</figure>
These forms have a **Link Field based on Company**. As a result, User Permissions on Company also get applied on these documents, which leads to User 'tom.hagen@riosolutions' to acces these documents having Company 'Rio Solutions'.
1. User Permissions get applied automatically based on Link Fields, just like how it worked for Quotation. But, Lead Form has 4 Link fields: Territory, Company, Lead Owner and Next Contact By. Say, you want Leads to limit access to Users based only on Territory, even though you have defined User Permissions for DocTypes User, Territory and Company. You can do this by setting 'Ignore User Permissions' for Link fields: Company, Lead Owner and Next Contact By.
<figure>
<img src="{{docs_base_url}}/assets/img/users-and-permissions/user-permissions-lead-role-permissions.png"
class="img-responsive" alt="Role Permissions on Lead for Sales User Role">
<figcaption>Sales User can Read, Write and Create Leads limited by User Permissions.</figcaption>
</figure>
<figure>
<img src="{{docs_base_url}}/assets/img/users-and-permissions/user-permissions-ignore-user-permissions.png"
class="img-responsive" alt="Set Ingore User Permissions from Setup > Customize > Customize Form">
<figcaption>Check 'Ingore User Permissions' for Company, Lead Owner and Next Contact By fields using Setup > Customize > Customize Form for Lead.</figcaption>
</figure>
<figure>
<img src="{{docs_base_url}}/assets/old_images/erpnext/user-permissions-lead-based-on-territory.png"
class="img-responsive" alt="Lead List is limited to records with Territory 'United States'">
<figcaption>Due to the effect of the above combination, User 'aromn@example.com' can only access Leads with Territory 'United States'.</figcaption>
</figure>
<img class="screen" alt="Sales User Role Permissions for Quotation" src="{{docs_base_url}}/assets/img/users-and-permissions/user-permissions-quotation-sales-user.png" >
Users with Sales User Role can Read, Write, Create, Submit and Cancel Quotations based on their User Permissions, since 'Apply User Permissions' is checked.
<img src="{{docs_base_url}}/assets/img/users-and-permissions/user-permission-quotation.png" class="screenshot" alt="Quotation List limited to results for Company 'Rio Solutions'">
Quotation List is limited to results for Company 'Rio Solutions' for User 'tom.hagen@riosolutions.com'.
1. User Permissions get applied automatically based on Link Fields, just like how it worked for Quotation. But, Lead Form has 4 Link fields: Territory, Company, Lead Owner and Next Contact By. Say, you want Leads to limit access to Users based only on Territory, even though you have defined User Permissions for DocTypes User, Territory and Company. You can do this by setting 'Ignore User Permissions' for Link fields: Company, Lead Owner and Next Contact By.
<img src="{{docs_base_url}}/assets/img/users-and-permissions/user-permissions-lead-role-permissions.png" class="screen" alt="Role Permissions on Lead for Sales User Role">
Sales User can Read, Write and Create Leads limited by User Permissions.
<img src="{{docs_base_url}}/assets/img/users-and-permissions/user-permissions-ignore-user-permissions.png" class="screenshot" alt="Set Ingore User Permissions from Setup > Customize > Customize Form">
Check 'Ingore User Permissions' for Company, Lead Owner and Next Contact By fields using Setup > Customize > Customize Form for Lead.
<img src="{{docs_base_url}}/assets/img/users-and-permissions/permissions-lead-list.png" class="screenshot" alt="Lead List is limited to records with Territory 'United States'">
Due to the effect of the above combination, User 'tom.hagen@riosolutions.com' can only access Leads with Territory 'United States'.
{next}

View File

@@ -1,42 +1,38 @@
In perpetual inventory, system creates accounting entries for each stock
transactions, so that stock and account balance will always remain same. The
account balance will be posted against their respective account heads for each
Warehouse. On saving of a Warehouse, the system will automatically create an
account head with the same name as warehouse. As account balance is maintained
for each Warehouse, you should create Warehouses, based on the type of items
(Current / Fixed Assets) it stores.
As per the perpetual inventory system, accounts posting is done for every stock transaction.
At the time of items received in a particular warehouse, the balance of asset
account (linked to that warehouse) will be increased. Similarly when you
deliver some items from that warehouse, an expense will be booked and the
asset account will be reduced, based on the valuation amount of those items.
On creating new Warehouse, the system will automatically create an Account in the Chart of Accout, with the same name as Warehouse Name.
## **Activation**
On receipt of items in a particular warehouse, the balance in the Warehouse Account will increase. Similarly when items are delivered from the Warehouse, an expense will be booked, and balance in the Warehouse Account will reduce.
1. Setup the following default accounts for each Company
##Activation
1. Setup the following default accounts for each Company. These accounts are created automatically in the new ERPNext accounts.
* Stock Received But Not Billed
* Stock Adjustment Account
* Expenses Included In Valuation
* Cost Center
2. In perpetual inventory, the system will maintain separate account balance for each warehouse under separate account head. To create that account head, enter "Create Account Under" in Warehouse master.
2. Ensure each Warehouse is an Account in the Chart of Accounts master. As per the default configuration, Accounts for Warehouse are created under `Assets > Current Asset > Stock Assets > (Warehouse)`
3. Activate Perpetual Inventory
> Setup > Accounts Settings > Make Accounting Entry For Every Stock Movement
> Explore > Accounts > Accounts Settings > "Make Accounting Entry For Every Stock Movement"
<img class="screenshot" alt="Perpetual Inventory" src="{{docs_base_url}}/assets/img/accounts/perpetual-1.png">
* * *
## **Example**
##Example
Consider following Chart of Accounts and Warehouse setup for your company:
#### Chart of Accounts
####Chart of Accounts
* Assets (Dr)
* Current Assets
* Accounts Receivable
* Jane Doe
* Debtor
* Stock Assets
* Stores
* Finished Goods
@@ -44,11 +40,11 @@ Consider following Chart of Accounts and Warehouse setup for your company:
* Tax Assets
* VAT
* Fixed Assets
* Fixed Asset Warehouse
* Fixed Asset Warehouse
* Liabilities (Cr)
* Current Liabilities
* Accounts Payable
* East Wind Inc.
* Creditors
* Stock Liabilities
* Stock Received But Not Billed
* Tax Liabilities
@@ -65,18 +61,15 @@ Consider following Chart of Accounts and Warehouse setup for your company:
* Shipping Charges
* Customs Duty
#### Warehouse - Account Configuration
####Warehouse - Account Configuration
* Stores
* Work In Progress
* Finished Goods
* Fixed Asset Warehouse
### **Purchase Receipt**
###Purchase Receipt
Suppose you have purchased _10 nos_ of item "RM0001" at _$200_ and _5 nos_ of
item "Desktop" at **$100** from supplier "East Wind Inc". Following are the
details of Purchase Receipt:
Suppose you have purchased _10 nos_ of item "RM0001" at _$200_ and _5 nos_ of item "Base Plate" at **$100** from supplier "East Wind Inc". Following are the details of Purchase Receipt:
**Supplier:** East Wind Inc.
@@ -100,15 +93,7 @@ details of Purchase Receipt:
<td>10</td>
<td>200</td>
<td>2000</td>
<td>2200</td>
</tr>
<tr>
<td>Desktop</td>
<td>Fixed Asset Warehouse</td>
<td>5</td>
<td>100</td>
<td>500</td>
<td>550</td>
<td>2250</td>
</tr>
</tbody>
</table>
@@ -129,8 +114,8 @@ details of Purchase Receipt:
<td>Total and Valuation</td>
</tr>
<tr>
<td>VAT</td>
<td>120</td>
<td>VAT (10%)</td>
<td>200</td>
<td>Total</td>
</tr>
<tr>
@@ -140,25 +125,22 @@ details of Purchase Receipt:
</tr>
</tbody>
</table>
<p><strong>Stock Ledger</strong>
</p>
<img alt="Stock" class="screenshot" src="{{docs_base_url}}/assets/old_images/erpnext/accounting-for-stock-2.png">
**Stock Ledger**
<img class="screenshot" alt="Perpetual Inventory" src="{{docs_base_url}}/assets/img/accounts/perpetual-2.png">
**General Ledger**
<img alt="Leger" class="screenshot" src="{{docs_base_url}}/assets/old_images/erpnext/accounting-for-stock-3.png">
<img class="screenshot" alt="Perpetual Inventory" src="{{docs_base_url}}/assets/img/accounts/perpetual-3.png">
As stock balance increases through Purchase Receipt, "Store" and "Fixed Asset
Warehouse" accounts are debited and a temporary account "Stock Receipt But Not
Billed" account is credited, to maintain double entry accounting system. At the same time, negative expense is booked in account "Expense included in Valuation" for the amount added for valuation purpose, to avoid double expense booking.
As stock balance increases through Purchase Receipt, "Store" accounts are debited and a temporary account "Stock Receipt But Not Billed" account is credited, to maintain double entry accounting system. At the same time, negative expense is booked in account "Expense included in Valuation" for the amount added for valuation purpose, to avoid double expense booking.
* * *
### **Purchase Invoice**
###Purchase Invoice
On receiving Bill from supplier, for the above Purchase Receipt, you will make
Purchase Invoice for the same. The general ledger entries are as follows:
On receiving Bill from supplier, for the above Purchase Receipt, you will make Purchase Invoice for the same. The general ledger entries are as follows:
**General Ledger**
@@ -169,7 +151,7 @@ effect of Purchase Receipt.
* * *
### **Delivery Note**
###Delivery Note
Lets say, you have an order from "Jane Doe" to deliver 5 nos of item "RM0001"
at $300. Following are the details of Delivery Note:
@@ -246,7 +228,7 @@ valuation method (FIFO / Moving Average) or actual cost of serialized items.
* * *
### **Sales Invoice with Update Stock**
###Sales Invoice with Update Stock
Lets say, you did not make Delivery Note against the above order and instead
you have made Sales Invoice directly, with "Update Stock" options. The details
@@ -265,7 +247,7 @@ Goods Sold" accounts are also affected based on the valuation amount.
* * *
### **Stock Entry (Material Receipt)**
###Stock Entry (Material Receipt)
**Items:**
@@ -300,7 +282,7 @@ Goods Sold" accounts are also affected based on the valuation amount.
* * *
### **Stock Entry (Material Issue)**
###Stock Entry (Material Issue)
**Items:**
@@ -335,7 +317,7 @@ Goods Sold" accounts are also affected based on the valuation amount.
* * *
### **Stock Entry (Material Transfer)**
###Stock Entry (Material Transfer)
**Items:**

View File

@@ -14,14 +14,10 @@ To set up a shopping cart, go to the selling module.
![Shopping Cart]({{docs_base_url}}/assets/old_images/erpnext/shopping-cart-1.png)
#### Step 2: Enter Price List, Tax Master and Shipping Rule.
![Shopping Cart]({{docs_base_url}}/assets/old_images/erpnext/shopping-cart-2.png)
#### Shopping Cart Display
On the Website, the shopping cart image will be seen below the Item price.
@@ -31,8 +27,6 @@ to the flower sign.
![Shopping Cart]({{docs_base_url}}/assets/old_images/erpnext/shopping-cart-display-1.png)
Click on the flower sign on the right hand side to see the cart details. Click
on the cart to get the final amount details.

View File

@@ -1,5 +1,5 @@
frappe.listview_settings['Employee'] = {
add_fields: ["status", "branch", "department", "designation"],
add_fields: ["status", "branch", "department", "designation","image"],
filters: [["status","=", "Active"]],
get_indicator: function(doc) {
var indicator = [__(doc.status), frappe.utils.guess_colour(doc.status), "status,=," + doc.status];

View File

@@ -99,7 +99,7 @@ def make_salary_slip(source_name, target_doc=None):
for d in source.get(key):
target.append(key, {
'amount': d.amount,
'default_amount': d.default_amount,
'default_amount': d.amount,
'depends_on_lwp' : d.depends_on_lwp,
'salary_component' : d.salary_component
})

View File

@@ -2,13 +2,9 @@
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
class Operation(Document):
def calculate_op_cost(self):
if self.hour_rate and self.time_in_mins:
self.operating_cost = flt(self.hour_rate) * flt(self.time_in_mins) / 60.0
else :
self.operating_cost = 0
def validate(self):
if not self.description:
self.description = self.name

View File

@@ -58,7 +58,7 @@
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
@@ -85,7 +85,7 @@
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
@@ -539,7 +539,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2016-07-11 03:28:04.235889",
"modified": "2016-08-22 03:41:42.356833",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Production Order Operation",

View File

@@ -22,6 +22,7 @@ execute:frappe.reload_doc('accounts', 'doctype', 'pos_setting') # 2014-01-29
execute:frappe.reload_doc('selling', 'doctype', 'customer') # 2014-01-29
execute:frappe.reload_doc('buying', 'doctype', 'supplier') # 2014-01-29
execute:frappe.reload_doc('accounts', 'doctype', 'asset_category')
execute:frappe.reload_doc('accounts', 'doctype', 'pricing_rule')
execute:frappe.reload_doctype('Item')
erpnext.patches.v4_0.map_charge_to_taxes_and_charges
execute:frappe.reload_doc('support', 'doctype', 'newsletter') # 2014-01-31
@@ -103,7 +104,6 @@ erpnext.patches.v5_0.update_frozen_accounts_permission_role
erpnext.patches.v5_0.update_dn_against_doc_fields
execute:frappe.db.sql("update `tabMaterial Request` set material_request_type = 'Material Transfer' where material_request_type = 'Transfer'")
execute:frappe.reload_doc('stock', 'doctype', 'item')
execute:frappe.db.sql("update `tabItem` i set apply_warehouse_wise_reorder_level=1, re_order_level=0, re_order_qty=0 where exists(select name from `tabItem Reorder` where parent=i.name)")
erpnext.patches.v5_0.set_default_company_in_bom
execute:frappe.reload_doc('crm', 'doctype', 'lead')
execute:frappe.reload_doc('crm', 'doctype', 'opportunity')
@@ -235,6 +235,7 @@ execute:frappe.delete_doc_if_exists("DocType", "Shopping Cart Taxes and Charges
erpnext.patches.v6_4.set_user_in_contact
erpnext.patches.v6_4.make_image_thumbnail #2015-10-20
erpnext.patches.v6_5.show_in_website_for_template_item
erpnext.patches.v7_0.create_budget_record
erpnext.patches.v6_4.fix_expense_included_in_valuation
execute:frappe.delete_doc_if_exists("Report", "Item-wise Last Purchase Rate")
erpnext.patches.v6_6.fix_website_image
@@ -269,7 +270,6 @@ erpnext.patches.v7_0.update_party_status
erpnext.patches.v7_0.update_item_projected
erpnext.patches.v7_0.remove_features_setup
erpnext.patches.v7_0.update_home_page
erpnext.patches.v7_0.create_budget_record
execute:frappe.delete_doc_if_exists("Page", "financial-analytics")
erpnext.patches.v7_0.update_project_in_gl_entry
execute:frappe.db.sql('update tabQuotation set status="Cancelled" where docstatus=2')

View File

@@ -219,6 +219,7 @@ def execute():
frappe.reload_doc("manufacturing", "doctype", "production_order_operation")
frappe.reload_doc("manufacturing", "doctype", "workstation_working_hour")
frappe.reload_doc("stock", "doctype", "item_variant")
frappe.reload_doc("hr", "doctype", "salary_detail")
frappe.reload_doc("accounts", "doctype", "party_account")
frappe.reload_doc("accounts", "doctype", "fiscal_year_company")

View File

@@ -4,8 +4,7 @@ import frappe
def execute():
fields = ("is_stock_item", "is_asset_item", "has_batch_no", "has_serial_no",
"inspection_required", "is_sub_contracted_item")
"is_sales_item", "is_purchase_item", "inspection_required", "is_sub_contracted_item")
# convert to 1 or 0
update_str = ", ".join(["`{0}`=if(`{0}`='Yes',1,0)".format(f) for f in fields])

View File

@@ -13,4 +13,5 @@ def execute():
ts.flags.ignore_validate = True
ts.flags.ignore_mandatory = True
ts.flags.ignore_validate_update_after_submit = True
ts.flags.ignore_links = True
ts.save()

View File

@@ -1,19 +1,38 @@
import frappe
from erpnext.manufacturing.doctype.production_order.production_order import make_timesheet, add_timesheet_detail
from erpnext.manufacturing.doctype.production_order.production_order \
import make_timesheet, add_timesheet_detail
def execute():
frappe.reload_doc('projects', 'doctype', 'timesheet')
for data in frappe.get_all('Time Log', fields=["*"],
filters = [["docstatus", "<", "2"]]):
for data in frappe.get_all('Time Log', fields=["*"], filters = [["docstatus", "<", "2"]]):
if data.task:
company = frappe.db.get_value("Task", data.task, "company")
elif data.production_order:
company = frappe.db.get_value("Prodction Order", data.production_order, "company")
else:
company = frappe.db.get_single_value('Global Defaults', 'default_company')
time_sheet = make_timesheet(data.production_order)
args = get_timelog_data(data)
add_timesheet_detail(time_sheet, args)
time_sheet.docstatus = data.docstatus
time_sheet.note = data.note
time_sheet.company = frappe.db.get_single_value('Global Defaults', 'default_company')
time_sheet.company = company
time_sheet.set_status()
time_sheet.update_cost()
time_sheet.calculate_total_amounts()
time_sheet.flags.ignore_validate = True
time_sheet.save(ignore_permissions=True)
# To ignore validate_mandatory_fields function
if data.docstatus == 1:
time_sheet.db_set("docstatus", 1)
for d in time_sheet.get("time_logs"):
d.db_set("docstatus", 1)
time_sheet.update_production_order(time_sheet.name)
time_sheet.update_task_and_project()
def get_timelog_data(data):
return {

View File

@@ -2,19 +2,25 @@ from __future__ import unicode_literals
import frappe
def execute():
if frappe.db.exists("DocType", "Student") and "father_name" in frappe.db.get_table_columns("Student"):
frappe.reload_doc("schools", "doctype", "student")
frappe.reload_doc("schools", "doctype", "guardian")
frappe.reload_doc("schools", "doctype", "guardian_interest")
frappe.reload_doc("hr", "doctype", "interest")
if frappe.db.exists("DocType", "Student"):
student_table_cols = frappe.db.get_table_columns("Student")
if "father_name" in student_table_cols:
frappe.reload_doc("schools", "doctype", "student")
frappe.reload_doc("schools", "doctype", "guardian")
frappe.reload_doc("schools", "doctype", "guardian_interest")
frappe.reload_doc("hr", "doctype", "interest")
fields = ["name", "father_name", "mother_name"]
if "father_email_id" in student_table_cols:
fields += ["father_email_id", "mother_email_id"]
students = frappe.get_all("Student", fields=["name", "father_name", "father_email_id",
"mother_name", "mother_email_id"])
for stud in students:
if stud.father_name:
make_guardian(stud.father_name, stud.name, stud.father_email_id)
if stud.mother_name:
make_guardian(stud.mother_name, stud.name, stud.mother_email_id)
students = frappe.get_all("Student", fields)
for stud in students:
if stud.father_name:
make_guardian(stud.father_name, stud.name, stud.father_email_id)
if stud.mother_name:
make_guardian(stud.mother_name, stud.name, stud.mother_email_id)
def make_guardian(name, student, email=None):
frappe.get_doc({

View File

@@ -1,5 +1,6 @@
from __future__ import unicode_literals
import frappe, os
from frappe.installer import remove_from_installed_apps
def execute():
reload_doctypes_for_schools_icons()
@@ -8,20 +9,18 @@ def execute():
frappe.reload_doc('website', 'doctype', 'portal_menu_item')
frappe.reload_doc('buying', 'doctype', 'request_for_quotation')
if 'schools' in frappe.get_installed_apps():
if frappe.db.exists("Module Def", "Academics") \
and frappe.db.get_value("Module Def", "Academics", "app_name") == "schools":
frappe.db.sql("""delete from `tabDesktop Icon`""")
if not frappe.db.exists('Module Def', 'Schools'):
frappe.get_doc({
'doctype': 'Module Def',
'module_name': 'Schools',
'app_name': 'erpnext'
}).insert()
frappe.db.sql("""update `tabDocType` set module='Schools' where module='Academics'""")
from frappe.installer import remove_from_installed_apps
if not frappe.db.exists('Module Def', 'Schools') and frappe.db.exists('Module Def', 'Academics'):
frappe.rename_doc("Module Def", "Academics", "Schools")
remove_from_installed_apps("schools")
def reload_doctypes_for_schools_icons():
base_path = frappe.get_app_path('erpnext', 'schools', 'doctype')
for doctype in os.listdir(base_path):
if os.path.exists(os.path.join(base_path, doctype, doctype + '.json')):
frappe.reload_doc('schools', 'doctype', doctype)
if os.path.exists(os.path.join(base_path, doctype, doctype + '.json')) \
and doctype not in ("fee_component", "assessment", "assessment_result"):
frappe.reload_doc('schools', 'doctype', doctype)

View File

@@ -8,8 +8,11 @@ from frappe.model.utils.rename_field import rename_field
def execute():
for dt in ("Sales Invoice Advance", "Purchase Invoice Advance"):
frappe.reload_doctype(dt)
frappe.db.sql("update `tab{0}` set reference_type = 'Journal Entry'".format(dt))
rename_field(dt, "journal_entry", "reference_name")
rename_field(dt, "jv_detail_no", "reference_row")
if frappe.get_meta(dt).has_field('journal_entry'):
rename_field(dt, "journal_entry", "reference_name")
if frappe.get_meta(dt).has_field('jv_detail_no'):
rename_field(dt, "jv_detail_no", "reference_row")

View File

@@ -9,7 +9,9 @@ from frappe.model.utils.rename_field import rename_field
def execute():
if frappe.db.exists("DocType", "Examination"):
frappe.rename_doc("DocType", "Examination", "Assessment")
frappe.reload_doctype("Assessment")
frappe.rename_doc("DocType", "Examination Result", "Assessment Result")
frappe.reload_doc("schools", "doctype", "assessment")
frappe.reload_doc("schools", "doctype", "assessment_result")
rename_field("Assessment", "exam_name", "assessment_name")
rename_field("Assessment", "exam_code", "assessment_code")

View File

@@ -4,7 +4,10 @@ import frappe
def execute():
frappe.reload_doc("hr", "doctype", "expense_claim_type")
frappe.reload_doc("hr", "doctype", "expense_claim_account")
if not frappe.db.has_column('Expense Claim Type', 'default_account'):
return
for expense_claim_type in frappe.get_all("Expense Claim Type", fields=["name", "default_account"]):
if expense_claim_type.default_account:
doc = frappe.get_doc("Expense Claim Type", expense_claim_type.name)

View File

@@ -18,8 +18,10 @@ class Project(Document):
if not self.get('__unsaved') and not self.get("tasks"):
self.load_tasks()
self.set_onload('activity_summary', frappe.db.sql('''select activity_type, sum(hours) as total_hours
from `tabTimesheet Detail` where project=%s group by activity_type order by total_hours desc''', self.name, as_dict=True))
self.set_onload('activity_summary', frappe.db.sql('''select activity_type,
sum(hours) as total_hours
from `tabTimesheet Detail` where project=%s and docstatus < 2 group by activity_type
order by total_hours desc''', self.name, as_dict=True))
def __setup__(self):
self.onload()
@@ -187,12 +189,12 @@ def get_list_context(context=None):
"row_template": "templates/includes/projects/project_row.html"
}
def get_users_for_project(doctype, txt, searchfield, start, page_len, filters):
def get_users_for_project(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql("""select name, concat_ws(' ', first_name, middle_name, last_name)
from `tabUser`
where enabled=1
from `tabUser`
where enabled=1
and name not in ("Guest", "Administrator")
order by
order by
name asc""")
@frappe.whitelist()

View File

@@ -159,8 +159,8 @@ class Timesheet(Document):
existing = self.get_overlap_for(fieldname, args, value)
if existing:
frappe.throw(_("Row {0}: From Time and To Time overlap with existing from and to time").format(args.idx),
OverlapError)
frappe.throw(_("Row {0}: From Time and To Time of {1} is overlapping with {2}")
.format(args.idx, self.name, existing.name), OverlapError)
def get_overlap_for(self, fieldname, args, value):
cond = "ts.`{0}`".format(fieldname)

View File

@@ -138,12 +138,14 @@
font-size: 15px;
}
.pos-payment-row .col-xs-6 {
padding: 10px;
padding: 15px;
}
.pos-payment-row {
border-bottom: 1px solid #d1d8dd;
margin: 2px 0px 5px 0px;
height: 60px;
margin-top: 0px;
margin-bottom: 0px;
}
.pos-payment-row:hover,
.pos-keyboard-key:hover {
@@ -203,3 +205,8 @@ body[data-route="pos"] .modal-dialog {
.pos-invoice-list {
padding: 15px 10px;
}
.write_off_amount,
.change_amount {
margin: 15px;
width: 130px;
}

View File

@@ -615,4 +615,18 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
this.frm.doc.base_change_amount = flt(this.frm.doc.change_amount * this.frm.doc.conversion_rate,
precision("base_change_amount"));
},
calculate_write_off_amount: function(){
if(this.frm.doc.paid_amount > this.frm.doc.grand_total){
this.frm.doc.write_off_amount = flt(this.frm.doc.grand_total - this.frm.doc.paid_amount + this.frm.doc.change_amount,
precision("write_off_amount"))
this.frm.doc.base_write_off_amount = flt(this.frm.doc.write_off_amount * this.frm.doc.conversion_rate,
precision("base_write_off_amount"));
}else{
this.frm.doc.paid_amount = 0.0
}
this.calculate_outstanding_amount(false)
}
})

View File

@@ -1,5 +1,5 @@
<div class="row pos-payment-row" type="{{type}}" idx={{idx}}>
<div class="col-xs-6">{{mode_of_payment}}</div>
<div class="col-xs-6" style="padding:20px">{{mode_of_payment}}</div>
<div class="col-xs-6">
<div class="input-group">
<input disabled class="form-control text-right amount" idx="{{idx}}" type="text" value="{{format_number(amount, 2)}}">

View File

@@ -13,6 +13,14 @@ erpnext.payments = erpnext.stock.StockController.extend({
this.$body = this.dialog.body;
this.set_payment_primary_action();
this.make_keyboard();
this.select_text()
},
select_text: function(){
var me = this;
$(this.$body).find('.form-control').click(function(){
$(this).select();
})
},
set_payment_primary_action: function(){
@@ -20,7 +28,7 @@ erpnext.payments = erpnext.stock.StockController.extend({
this.dialog.set_primary_action(__("Submit"), function() {
me.dialog.hide()
me.write_off_amount()
me.submit_invoice()
})
},
@@ -78,7 +86,7 @@ erpnext.payments = erpnext.stock.StockController.extend({
//When user first time click on row
this.payment_val = flt(this.frm.doc.outstanding_amount)
this.selected_mode.val(format_number(this.payment_val, 2));
this.update_paid_amount()
this.update_payment_amount()
}else if(flt(this.selected_mode.val()) > 0){
//If user click on existing row which has value
this.payment_val = flt(this.selected_mode.val());
@@ -90,17 +98,29 @@ erpnext.payments = erpnext.stock.StockController.extend({
bind_keyboard_event: function(){
var me = this;
this.payment_val = '';
this.bind_payment_mode_keys_event();
this.bind_keyboard_keys_event();
this.bind_form_control_event();
this.bind_numeric_keys_event();
},
bind_payment_mode_keys_event: function(){
bind_form_control_event: function(){
var me = this;
$(this.$body).find('.pos-payment-row').click(function(){
if(me.frm.doc.outstanding_amount > 0){
me.idx = $(this).attr("idx");
me.set_outstanding_amount()
}
me.idx = $(this).attr("idx");
me.set_outstanding_amount()
})
$(this.$body).find('.form-control').click(function(){
me.idx = $(this).attr("idx");
me.set_outstanding_amount();
me.update_paid_amount(true);
})
$(this.$body).find('.write_off_amount').change(function(){
me.write_off_amount(flt($(this).val()), precision("write_off_amount"));
})
$(this.$body).find('.change_amount').change(function(){
me.change_amount(flt($(this).val()), precision("change_amount"));
})
},
@@ -113,7 +133,7 @@ erpnext.payments = erpnext.stock.StockController.extend({
this.selected_mode.attr('disabled', false);
},
bind_keyboard_keys_event: function(){
bind_numeric_keys_event: function(){
var me = this;
$(this.$body).find('.pos-keyboard-key').click(function(){
me.payment_val += $(this).text();
@@ -137,15 +157,11 @@ erpnext.payments = erpnext.stock.StockController.extend({
me.payment_val = flt($(this).val()) || 0.0;
me.selected_mode.val(format_number(me.payment_val, 2))
me.idx = me.selected_mode.attr("idx")
me.update_paid_amount()
})
this.selected_mode.click(function(){
me.selected_mode.select();
me.update_payment_amount()
})
},
clear_amount: function(){
clear_amount: function() {
var me = this;
$(this.$body).find('.clr').click(function(e){
e.stopPropagation();
@@ -154,25 +170,63 @@ erpnext.payments = erpnext.stock.StockController.extend({
me.payment_val = 0.0;
me.selected_mode.val(0.0);
me.highlight_selected_row();
me.update_paid_amount();
me.update_payment_amount();
})
},
update_paid_amount: function(){
write_off_amount: function(write_off_amount) {
var me = this;
this.frm.doc.write_off_amount = flt(write_off_amount, precision("write_off_amount"));
this.frm.doc.base_write_off_amount = flt(this.frm.doc.write_off_amount * this.frm.doc.conversion_rate,
precision("base_write_off_amount"));
this.calculate_outstanding_amount(false)
this.show_amounts()
},
change_amount: function(change_amount) {
var me = this;
this.frm.doc.change_amount = flt(change_amount, precision("change_amount"));
this.calculate_write_off_amount()
this.show_amounts()
},
update_paid_amount: function(update_write_off) {
var me = this;
if(in_list(['change_amount', 'write_off_amount'], this.idx)){
value = me.selected_mode.val();
if(me.idx == 'change_amount'){
me.change_amount(value)
} else{
if(value == 0 && update_write_off) {
value = me.frm.doc.outstanding_amount;
}
me.write_off_amount(value)
}
}else{
this.update_payment_amount()
}
},
update_payment_amount: function(){
var me = this;
$.each(this.frm.doc.payments, function(index, data){
if(cint(me.idx) == cint(data.idx)){
data.amount = flt(me.selected_mode.val(), 2)
}
})
this.calculate_outstanding_amount(false);
this.show_amounts();
},
show_amounts: function(){
var me = this;
$(this.$body).find(".write_off_amount").val(format_number(this.frm.doc.write_off_amount, precision("write_off_amount")));
$(this.$body).find('.paid_amount').text(format_currency(this.frm.doc.paid_amount, this.frm.doc.currency));
$(this.$body).find('.change_amount').text(format_currency(this.frm.doc.change_amount, this.frm.doc.currency))
$(this.$body).find('.change_amount').val(format_number(this.frm.doc.change_amount, precision("change_amount")))
$(this.$body).find('.outstanding_amount').text(format_currency(this.frm.doc.outstanding_amount, this.frm.doc.currency))
this.update_invoice();
}

View File

@@ -1,8 +1,8 @@
<div class="pos_payment row">
<div class="row" style="padding: 0px 30px;">
<h3>Total Amount: <span class="label label-default" style="font-size:20px;padding:5px">{%= format_currency(grand_total, currency) %}</span></h3>
</div>
<div class="row amount-row">
<div class="col-xs-6 col-sm-3 text-center">
<p class="amount-label"> Total <h3>{%= format_currency(grand_total, currency) %} </h3></p>
</div>
<div class="col-xs-6 col-sm-3 text-center">
<p class="amount-label"> Paid <h3 class="paid_amount">{%= format_currency(paid_amount, currency) %}</h3></p>
</div>
@@ -10,13 +10,19 @@
<p class="amount-label"> Outstanding <h3 class="outstanding_amount">{%= format_currency(outstanding_amount, currency) %} </h3></p>
</div>
<div class="col-xs-6 col-sm-3 text-center">
<p class="amount-label"> Change <h3 class="change_amount">{%= format_currency(change_amount, currency) %}</h3>
<p class="amount-label"> Change <input class="form-control text-right change_amount bold" type="text" idx="change_amount" value="{{format_number(change_amount, 2)}}">
</p>
</div>
<div class="col-xs-6 col-sm-3 text-center">
<p class="amount-label"> Write off <input class="form-control text-right write_off_amount bold" type="text" idx="write_off_amount" value="{{format_number(write_off_amount, 2)}}">
</p>
</div>
</div>
<hr>
<div class="row">
<div class="col-sm-6 multimode-payments">
<div class="col-sm-6 ">
<div class ="row multimode-payments">
</div>
</div>
<div class="col-sm-6 payment-toolbar">
{% for(var i=0; i<3; i++) { %}

View File

@@ -176,13 +176,15 @@
}
.pos-payment-row .col-xs-6 {
padding :10px;
padding :15px;
}
.pos-payment-row {
border-bottom:1px solid #d1d8dd;
margin: 2px 0px 5px 0px;
height: 60px;
margin-top: 0px;
margin-bottom: 0px;
}
.pos-payment-row:hover, .pos-keyboard-key:hover{
@@ -248,3 +250,8 @@ body[data-route="pos"] .modal-dialog {
.pos-invoice-list {
padding: 15px 10px;
}
.write_off_amount, .change_amount {
margin: 15px;
width: 130px;
}

View File

@@ -91,14 +91,14 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "mobile_nuber",
"fieldname": "mobile_number",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Mobile Nuber",
"label": "Mobile Number",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -116,8 +116,8 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "section_break_5",
"fieldtype": "Section Break",
"fieldname": "column_break_3",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -136,6 +136,31 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "image",
"fieldtype": "Attach Image",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Image",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@@ -166,6 +191,7 @@
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_field": "image",
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
@@ -173,7 +199,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2016-07-25 07:20:11.458757",
"modified": "2016-08-11 07:57:21.708354",
"modified_by": "Administrator",
"module": "Schools",
"name": "Guardian",

View File

@@ -9,6 +9,7 @@
"docstatus": 0,
"doctype": "DocType",
"document_type": "Document",
"editable_grid": 0,
"fields": [
{
"allow_on_submit": 0,
@@ -239,11 +240,38 @@
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "image",
"fieldtype": "Attach Image",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Image",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_field": "image",
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 1,
@@ -251,7 +279,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2016-07-18 10:30:50.243271",
"modified": "2016-08-11 08:50:24.317353",
"modified_by": "Administrator",
"module": "Schools",
"name": "Program Enrollment",

View File

@@ -191,6 +191,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"depends_on": "eval:doc.get_students_from==\"Program Enrollments\"",
"fieldname": "new_program",
"fieldtype": "Link",
"hidden": 0,
@@ -217,6 +218,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"depends_on": "eval:doc.get_students_from==\"Program Enrollments\"",
"fieldname": "new_academic_year",
"fieldtype": "Link",
"hidden": 0,
@@ -275,7 +277,7 @@
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"modified": "2016-07-25 01:24:05.632746",
"modified": "2016-08-17 07:50:40.399492",
"modified_by": "Administrator",
"module": "Schools",
"name": "Program Enrollment Tool",

View File

@@ -6,6 +6,7 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.model.document import Document
from erpnext.schools.api import enroll_student
class ProgramEnrollmentTool(Document):
def get_students(self):
@@ -29,11 +30,16 @@ class ProgramEnrollmentTool(Document):
def enroll_students(self):
for stud in self.students:
prog_enrollment = frappe.new_doc("Program Enrollment")
prog_enrollment.student = stud.student
prog_enrollment.student_name = stud.student_name
prog_enrollment.program = self.new_program
prog_enrollment.academic_year = self.new_academic_year
prog_enrollment.save()
if stud.student:
prog_enrollment = frappe.new_doc("Program Enrollment")
prog_enrollment.student = stud.student
prog_enrollment.student_name = stud.student_name
prog_enrollment.program = self.new_program
prog_enrollment.academic_year = self.new_academic_year
prog_enrollment.save()
elif stud.student_applicant:
prog_enrollment = enroll_student(stud.student_applicant)
prog_enrollment.academic_year = self.academic_year
prog_enrollment.save()
frappe.msgprint("Students have been enrolled.")

View File

@@ -5,10 +5,11 @@
"autoname": "naming_series:",
"beta": 0,
"creation": "2013-05-24 19:29:08",
"custom": 0,
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "Document",
"editable_grid": 1,
"fields": [
{
"allow_on_submit": 0,
@@ -35,30 +36,6 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "column_break0",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"width": "50%"
},
{
"allow_on_submit": 1,
"bold": 0,
@@ -207,7 +184,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Custome Name",
"label": "Customer Name",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -2133,7 +2110,7 @@
"istable": 0,
"max_attachments": 1,
"menu_index": 0,
"modified": "2016-07-05 16:44:01.301063",
"modified": "2016-08-11 08:52:09.666306",
"modified_by": "Administrator",
"module": "Selling",
"name": "Quotation",
@@ -2313,4 +2290,4 @@
"timeline_field": "customer",
"title_field": "title",
"track_seen": 0
}
}

View File

@@ -66,7 +66,8 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
if(this.frm.fields_dict["items"].grid.get_field('item_code')) {
this.frm.set_query("item_code", "items", function() {
return {
query: "erpnext.controllers.queries.item_query"
query: "erpnext.controllers.queries.item_query",
filters: {'is_sales_item': 1}
}
});
}
@@ -79,7 +80,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
} else {
filters = {
'item_code': item.item_code,
'posting_date': me.frm.doc.posting_date || nowdate(),
'posting_date': me.frm.doc.posting_date || frappe.datetime.nowdate(),
}
if(item.warehouse) filters["warehouse"] = item.warehouse

View File

@@ -11,7 +11,7 @@ import random
def make_sample_data():
"""Create a few opportunities, quotes, material requests, issues, todos, projects
to help the user get started"""
items = frappe.get_all("Item")
items = frappe.get_all("Item", {'is_sales_item': 1})
customers = frappe.get_all("Customer")
warehouses = frappe.get_all("Warehouse")
@@ -25,7 +25,7 @@ def make_sample_data():
make_projects()
if items and warehouses:
make_material_request(items)
make_material_request(frappe.get_all("Item"))
frappe.db.commit()

View File

@@ -318,6 +318,8 @@ def create_items(args):
"item_name": item,
"description": item,
"show_in_website": 1,
"is_sales_item": is_sales_item,
"is_purchase_item": is_purchase_item,
"is_stock_item": is_stock_item and 1 or 0,
"item_group": item_group,
"stock_uom": args.get("item_uom_" + str(i)),

View File

@@ -12,6 +12,9 @@ frappe.ui.form.on('Delivery Note', 'onload', function(frm) {
return (doc.docstatus==1 || doc.qty<=doc.actual_qty) ? "green" : "orange"
})
erpnext.queries.setup_queries(frm, "Warehouse", function() {
return erpnext.queries.warehouse(frm.doc);
});
})
erpnext.stock.DeliveryNoteController = erpnext.selling.SellingController.extend({

View File

@@ -1054,6 +1054,32 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"default": "1",
"fieldname": "is_purchase_item",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Is Purchase Item",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@@ -1483,6 +1509,32 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"default": "1",
"fieldname": "is_sales_item",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Is Sales Item",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@@ -2335,7 +2387,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 1,
"modified": "2016-08-03 17:30:51.323382",
"modified": "2016-08-17 17:30:51.323382",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item",

View File

@@ -84,7 +84,7 @@ class LandedCostVoucher(Document):
self.update_landed_cost()
def update_landed_cost(self):
for d in self.get("items"):
for d in self.get("purchase_receipts"):
doc = frappe.get_doc(d.receipt_document_type, d.receipt_document)
# set landed cost voucher amount in pr item
@@ -103,7 +103,7 @@ class LandedCostVoucher(Document):
# update stock & gl entries for cancelled state of PR
doc.docstatus = 2
doc.update_stock_ledger(allow_negative_stock=True, via_landed_cost_voucher=True)
doc.make_gl_entries_on_cancel()
doc.make_gl_entries_on_cancel(repost_future_gle=False)
# update stock & gl entries for submit state of PR

View File

@@ -78,10 +78,6 @@ class StockReconciliation(StockController):
default_currency = frappe.db.get_default("currency")
# validate no of rows
if len(self.items) > 100:
frappe.throw(_("""Max 100 rows for Stock Reconciliation."""))
for row_num, row in enumerate(self.items):
# find duplicates
if [row.item_code, row.warehouse] in item_warehouse_combinations:

View File

@@ -44,7 +44,7 @@ erpnext.SupportAnalytics = frappe.views.GridReportWithPlot.extend({
var std_columns = [
{id: "_check", name: __("Plot"), field: "_check", width: 30,
formatter: this.check_formatter},
{id: "status", name: __("Status"), field: "status", width: 100},
{id: "name", name: __("Status"), field: "name", width: 100},
];
this.make_date_range_columns();
this.columns = std_columns.concat(this.columns);
@@ -54,14 +54,14 @@ erpnext.SupportAnalytics = frappe.views.GridReportWithPlot.extend({
// add Opening, Closing, Totals rows
// if filtered by account and / or voucher
var me = this;
var total_tickets = {status:"All Tickets", "id": "all-tickets",
var total_tickets = {name:"All Tickets", "id": "all-tickets",
checked:true};
var days_to_close = {status:"Days to Close", "id":"days-to-close",
var days_to_close = {name:"Days to Close", "id":"days-to-close",
checked:false};
var total_closed = {};
var hours_to_close = {status:"Hours to Close", "id":"hours-to-close",
var hours_to_close = {name:"Hours to Close", "id":"hours-to-close",
checked:false};
var hours_to_respond = {status:"Hours to Respond", "id":"hours-to-respond",
var hours_to_respond = {name:"Hours to Respond", "id":"hours-to-respond",
checked:false};
var total_responded = {};