Compare commits
109 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
734e635ef6 | ||
|
|
6f9ef5b890 | ||
|
|
145393b12f | ||
|
|
9c6e2c3637 | ||
|
|
cfc2693b2e | ||
|
|
448d919cc1 | ||
|
|
87ec6a12ef | ||
|
|
059f99e621 | ||
|
|
4c28fa77bd | ||
|
|
394dbca0e4 | ||
|
|
33ebd9f88e | ||
|
|
4c1caa7e98 | ||
|
|
08c3b3c925 | ||
|
|
bb5812cf0f | ||
|
|
36645e4e2f | ||
|
|
b296bb1551 | ||
|
|
e7c14fcc3d | ||
|
|
31bb34bbae | ||
|
|
6436b9d089 | ||
|
|
d62fa84ed9 | ||
|
|
baa937aa52 | ||
|
|
3b128cabb2 | ||
|
|
dfc5a454b3 | ||
|
|
1c32f5ace9 | ||
|
|
283d5550e6 | ||
|
|
dda608dd00 | ||
|
|
e355f99786 | ||
|
|
27334c28a9 | ||
|
|
6c8d4678db | ||
|
|
ea50c9d1be | ||
|
|
35da7d1fb4 | ||
|
|
ced14cc789 | ||
|
|
9d27cf3c62 | ||
|
|
0e6933a1e8 | ||
|
|
51a76885b8 | ||
|
|
a919be111a | ||
|
|
9c42161061 | ||
|
|
79d6266c7b | ||
|
|
11d23f84d7 | ||
|
|
8e0f23efc7 | ||
|
|
ac9b1332d2 | ||
|
|
7b021e0fac | ||
|
|
d6dd25a666 | ||
|
|
f86100a734 | ||
|
|
96bb6099d6 | ||
|
|
e6c2ae3682 | ||
|
|
8d56f2959b | ||
|
|
d2d24554b3 | ||
|
|
c7d2bc67e8 | ||
|
|
1283f6308d | ||
|
|
d36c136fc6 | ||
|
|
3951f6971e | ||
|
|
75e65e7079 | ||
|
|
7f95d587b2 | ||
|
|
75b145fe2c | ||
|
|
bc3acdd0ba | ||
|
|
8f42f60dc9 | ||
|
|
823b3ca540 | ||
|
|
5e75e3ba03 | ||
|
|
113df55e64 | ||
|
|
3e4b2743c6 | ||
|
|
338c28e78e | ||
|
|
7e14996995 | ||
|
|
6e30f04181 | ||
|
|
4a10f18ee3 | ||
|
|
f37d43d0c1 | ||
|
|
aea60f349f | ||
|
|
90bd5681d1 | ||
|
|
30e03cc4c8 | ||
|
|
4c40a416e6 | ||
|
|
3020c8086c | ||
|
|
8b3ef1e70a | ||
|
|
c446bf6117 | ||
|
|
660de515b5 | ||
|
|
e012e24423 | ||
|
|
e2d0d0a0c1 | ||
|
|
22e82dff20 | ||
|
|
78d2f542d0 | ||
|
|
b962fc1573 | ||
|
|
1ee534889f | ||
|
|
fa04236c8d | ||
|
|
36025468a1 | ||
|
|
0e376a464b | ||
|
|
8333b5754b | ||
|
|
dab1172a18 | ||
|
|
ea4497c8d2 | ||
|
|
b994b3dcda | ||
|
|
805a41d06c | ||
|
|
e06526ffff | ||
|
|
2df7db0346 | ||
|
|
c9877c5c1e | ||
|
|
372a881d8c | ||
|
|
71b5250cbd | ||
|
|
3ceebaec3f | ||
|
|
35d0de8276 | ||
|
|
812853aa86 | ||
|
|
319c58266b | ||
|
|
dcf10ee4f6 | ||
|
|
1394a6557d | ||
|
|
00e825a8af | ||
|
|
ed89a83584 | ||
|
|
2c5b3e83f5 | ||
|
|
8e2531e2bb | ||
|
|
d5dd9f1706 | ||
|
|
393becce0b | ||
|
|
8f2e21def2 | ||
|
|
7231f29e78 | ||
|
|
690de64734 | ||
|
|
c7e3a09cfb |
@@ -53,4 +53,4 @@ script:
|
||||
- set -e
|
||||
- bench --verbose run-tests
|
||||
- sleep 5
|
||||
- bench --verbose run-tests --ui-tests
|
||||
- bench --verbose run-ui-tests --app erpnext
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
import inspect
|
||||
import frappe
|
||||
from erpnext.hooks import regional_overrides
|
||||
|
||||
__version__ = '8.4.3'
|
||||
__version__ = '8.6.3'
|
||||
|
||||
def get_default_company(user=None):
|
||||
'''Get default company for user'''
|
||||
@@ -65,3 +67,34 @@ def is_perpetual_inventory_enabled(company):
|
||||
company, "enable_perpetual_inventory") or 0
|
||||
|
||||
return frappe.local.enable_perpetual_inventory[company]
|
||||
|
||||
def get_region(company=None):
|
||||
'''Return the default country based on flag, company or global settings
|
||||
|
||||
You can also set global company flag in `frappe.flags.company`
|
||||
'''
|
||||
if company or frappe.flags.company:
|
||||
return frappe.db.get_value('Company',
|
||||
company or frappe.flags.company, 'country')
|
||||
elif frappe.flags.country:
|
||||
return frappe.flags.country
|
||||
else:
|
||||
return frappe.get_system_settings('country')
|
||||
|
||||
def allow_regional(fn):
|
||||
'''Decorator to make a function regionally overridable
|
||||
|
||||
Example:
|
||||
@erpnext.allow_regional
|
||||
def myfunction():
|
||||
pass'''
|
||||
def caller(*args, **kwargs):
|
||||
region = get_region()
|
||||
fn_name = inspect.getmodule(fn).__name__ + '.' + fn.__name__
|
||||
if region in regional_overrides and fn_name in regional_overrides[region]:
|
||||
return frappe.get_attr(regional_overrides[region][fn_name])(*args, **kwargs)
|
||||
else:
|
||||
return fn(*args, **kwargs)
|
||||
|
||||
return caller
|
||||
|
||||
|
||||
@@ -1,94 +1,94 @@
|
||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
// License: GNU General Public License v3. See license.txt
|
||||
|
||||
|
||||
cur_frm.cscript.refresh = function (doc, cdt, cdn) {
|
||||
if (doc.__islocal) {
|
||||
frappe.msgprint(__("Please create new account from Chart of Accounts."));
|
||||
throw "cannot create";
|
||||
}
|
||||
|
||||
cur_frm.toggle_display('account_name', doc.__islocal);
|
||||
|
||||
// hide fields if group
|
||||
cur_frm.toggle_display(['account_type', 'tax_rate'], cint(doc.is_group) == 0)
|
||||
|
||||
// disable fields
|
||||
cur_frm.toggle_enable(['account_name', 'is_group', 'company'], false);
|
||||
|
||||
if (cint(doc.is_group) == 0) {
|
||||
cur_frm.toggle_display('freeze_account', doc.__onload && doc.__onload.can_freeze_account);
|
||||
}
|
||||
|
||||
// read-only for root accounts
|
||||
if (!doc.parent_account) {
|
||||
cur_frm.set_read_only();
|
||||
cur_frm.set_intro(__("This is a root account and cannot be edited."));
|
||||
} else {
|
||||
// credit days and type if customer or supplier
|
||||
cur_frm.set_intro(null);
|
||||
|
||||
cur_frm.cscript.account_type(doc, cdt, cdn);
|
||||
|
||||
// show / hide convert buttons
|
||||
cur_frm.cscript.add_toolbar_buttons(doc);
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.add_fetch('parent_account', 'report_type', 'report_type');
|
||||
cur_frm.add_fetch('parent_account', 'root_type', 'root_type');
|
||||
|
||||
cur_frm.cscript.account_type = function (doc, cdt, cdn) {
|
||||
if (doc.is_group == 0) {
|
||||
cur_frm.toggle_display(['tax_rate'], doc.account_type == 'Tax');
|
||||
cur_frm.toggle_display('warehouse', doc.account_type == 'Stock');
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.cscript.add_toolbar_buttons = function (doc) {
|
||||
cur_frm.add_custom_button(__('Chart of Accounts'),
|
||||
function () { frappe.set_route("Tree", "Account"); });
|
||||
|
||||
if (doc.is_group == 1) {
|
||||
cur_frm.add_custom_button(__('Group to Non-Group'),
|
||||
function () { cur_frm.cscript.convert_to_ledger(); }, 'fa fa-retweet', 'btn-default');
|
||||
} else if (cint(doc.is_group) == 0) {
|
||||
cur_frm.add_custom_button(__('Ledger'), function () {
|
||||
frappe.route_options = {
|
||||
"account": doc.name,
|
||||
"from_date": frappe.sys_defaults.year_start_date,
|
||||
"to_date": frappe.sys_defaults.year_end_date,
|
||||
"company": doc.company
|
||||
frappe.ui.form.on('Account', {
|
||||
setup: function(frm) {
|
||||
frm.add_fetch('parent_account', 'report_type', 'report_type');
|
||||
frm.add_fetch('parent_account', 'root_type', 'root_type');
|
||||
},
|
||||
onload: function(frm) {
|
||||
frm.set_query('parent_account', function(doc) {
|
||||
return {
|
||||
filters: {
|
||||
"is_group": 1,
|
||||
"company": doc.company
|
||||
}
|
||||
};
|
||||
frappe.set_route("query-report", "General Ledger");
|
||||
});
|
||||
},
|
||||
refresh: function(frm) {
|
||||
if (frm.doc.__islocal) {
|
||||
frappe.msgprint(__("Please create new account from Chart of Accounts."));
|
||||
throw "cannot create";
|
||||
}
|
||||
|
||||
frm.toggle_display('account_name', frm.doc.__islocal);
|
||||
|
||||
// hide fields if group
|
||||
frm.toggle_display(['account_type', 'tax_rate'], cint(frm.doc.is_group) == 0);
|
||||
|
||||
// disable fields
|
||||
frm.toggle_enable(['account_name', 'is_group', 'company'], false);
|
||||
|
||||
if (cint(frm.doc.is_group) == 0) {
|
||||
frm.toggle_display('freeze_account', frm.doc.__onload
|
||||
&& frm.doc.__onload.can_freeze_account);
|
||||
}
|
||||
|
||||
// read-only for root accounts
|
||||
if (!frm.doc.parent_account) {
|
||||
frm.set_read_only();
|
||||
frm.set_intro(__("This is a root account and cannot be edited."));
|
||||
} else {
|
||||
// credit days and type if customer or supplier
|
||||
frm.set_intro(null);
|
||||
frm.trigger('account_type');
|
||||
|
||||
// show / hide convert buttons
|
||||
frm.trigger('add_toolbar_buttons');
|
||||
}
|
||||
},
|
||||
account_type: function (frm) {
|
||||
if (frm.doc.is_group == 0) {
|
||||
frm.toggle_display(['tax_rate'], frm.doc.account_type == 'Tax');
|
||||
frm.toggle_display('warehouse', frm.doc.account_type == 'Stock');
|
||||
}
|
||||
},
|
||||
add_toolbar_buttons: function(frm) {
|
||||
frm.add_custom_button(__('Chart of Accounts'),
|
||||
function () { frappe.set_route("Tree", "Account"); });
|
||||
|
||||
if (frm.doc.is_group == 1) {
|
||||
frm.add_custom_button(__('Group to Non-Group'), function () {
|
||||
return frappe.call({
|
||||
doc: frm.doc,
|
||||
method: 'convert_group_to_ledger',
|
||||
callback: function() {
|
||||
frm.refresh();
|
||||
}
|
||||
});
|
||||
});
|
||||
} else if (cint(frm.doc.is_group) == 0) {
|
||||
cur_frm.add_custom_button(__('Ledger'), function () {
|
||||
frappe.route_options = {
|
||||
"account": frm.doc.name,
|
||||
"from_date": frappe.sys_defaults.year_start_date,
|
||||
"to_date": frappe.sys_defaults.year_end_date,
|
||||
"company": frm.doc.company
|
||||
};
|
||||
frappe.set_route("query-report", "General Ledger");
|
||||
});
|
||||
|
||||
frm.add_custom_button(__('Non-Group to Group'), function () {
|
||||
return frappe.call({
|
||||
doc: frm.doc,
|
||||
method: 'convert_ledger_to_group',
|
||||
callback: function() {
|
||||
frm.refresh();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
cur_frm.add_custom_button(__('Non-Group to Group'),
|
||||
function () { cur_frm.cscript.convert_to_group(); }, 'fa fa-retweet', 'btn-default')
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.cscript.convert_to_ledger = function (doc, cdt, cdn) {
|
||||
return $c_obj(cur_frm.doc, 'convert_group_to_ledger', '', function (r, rt) {
|
||||
if (r.message == 1) {
|
||||
cur_frm.refresh();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
cur_frm.cscript.convert_to_group = function (doc, cdt, cdn) {
|
||||
return $c_obj(cur_frm.doc, 'convert_ledger_to_group', '', function (r, rt) {
|
||||
if (r.message == 1) {
|
||||
cur_frm.refresh();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
cur_frm.fields_dict['parent_account'].get_query = function (doc) {
|
||||
return {
|
||||
filters: {
|
||||
"is_group": 1,
|
||||
"company": doc.company
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
27
erpnext/accounts/doctype/account/test_account.js
Normal file
@@ -0,0 +1,27 @@
|
||||
QUnit.module('accounts');
|
||||
|
||||
QUnit.test("test account", function(assert) {
|
||||
assert.expect(4);
|
||||
let done = assert.async();
|
||||
frappe.run_serially([
|
||||
() => frappe.set_route('Tree', 'Account'),
|
||||
() => frappe.click_button('Expand All'),
|
||||
() => frappe.click_link('Debtors'),
|
||||
() => frappe.click_button('Edit'),
|
||||
() => frappe.timeout(1),
|
||||
() => {
|
||||
assert.ok(cur_frm.doc.root_type=='Asset');
|
||||
assert.ok(cur_frm.doc.report_type=='Balance Sheet');
|
||||
assert.ok(cur_frm.doc.account_type=='Receivable');
|
||||
},
|
||||
() => frappe.click_button('Ledger'),
|
||||
() => frappe.timeout(1),
|
||||
() => {
|
||||
// check if general ledger report shown
|
||||
assert.deepEqual(frappe.get_route(), ['query-report', 'General Ledger']);
|
||||
window.history.back();
|
||||
return frappe.timeout(1);
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
});
|
||||
@@ -96,7 +96,14 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
|
||||
|
||||
// expense claim
|
||||
if(jvd.reference_type==="Expense Claim") {
|
||||
return {};
|
||||
return {
|
||||
filters: {
|
||||
'approval_status': 'Approved',
|
||||
'total_sanctioned_amount': ['>', 0],
|
||||
'status': ['!=', 'Paid'],
|
||||
'docstatus': 1
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// journal entry
|
||||
@@ -122,10 +129,11 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
|
||||
|
||||
// account filter
|
||||
frappe.model.validate_missing(jvd, "account");
|
||||
|
||||
var party_account_field = jvd.reference_type==="Sales Invoice" ? "debit_to": "credit_to";
|
||||
out.filters.push([jvd.reference_type, party_account_field, "=", jvd.account]);
|
||||
} else {
|
||||
}
|
||||
|
||||
if(in_list(["Sales Order", "Purchase Order"], jvd.reference_type)) {
|
||||
// party_type and party mandatory
|
||||
frappe.model.validate_missing(jvd, "party_type");
|
||||
frappe.model.validate_missing(jvd, "party");
|
||||
|
||||
@@ -1516,6 +1516,36 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
"columns": 0,
|
||||
"fieldname": "sec_tax_breakup",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Tax Breakup",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
@@ -1523,7 +1553,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "other_charges_calculation",
|
||||
"fieldtype": "HTML",
|
||||
"fieldtype": "Text",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
@@ -1533,12 +1563,12 @@
|
||||
"in_standard_filter": 0,
|
||||
"label": "Taxes and Charges Calculation",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"no_copy": 1,
|
||||
"oldfieldtype": "HTML",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
@@ -3767,7 +3797,7 @@
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2017-06-29 10:48:09.707735",
|
||||
"modified": "2017-07-19 13:53:48.673757",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Invoice",
|
||||
|
||||
@@ -98,6 +98,26 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
this.set_default_print_format();
|
||||
},
|
||||
|
||||
on_submit: function(doc, dt, dn) {
|
||||
var me = this;
|
||||
|
||||
$.each(doc["items"], function(i, row) {
|
||||
if(row.delivery_note) frappe.model.clear_doc("Delivery Note", row.delivery_note)
|
||||
})
|
||||
|
||||
if(this.frm.doc.is_pos) {
|
||||
this.frm.msgbox = frappe.msgprint(
|
||||
`<a class="btn btn-primary" onclick="cur_frm.print_preview.printit(true)" style="margin-right: 5px;">
|
||||
${__('Print')}</a>
|
||||
<a class="btn btn-default" href="javascript:frappe.new_doc(cur_frm.doctype);">
|
||||
${__('New')}</a>`
|
||||
);
|
||||
|
||||
} else if(cint(frappe.boot.notification_settings.sales_invoice)) {
|
||||
this.frm.email_doc(frappe.boot.notification_settings.sales_invoice_message);
|
||||
}
|
||||
},
|
||||
|
||||
set_default_print_format: function() {
|
||||
// set default print format to POS type
|
||||
if(cur_frm.doc.is_pos) {
|
||||
@@ -306,7 +326,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
|
||||
this.frm.refresh_fields();
|
||||
},
|
||||
|
||||
|
||||
company_address: function() {
|
||||
var me = this;
|
||||
if(this.frm.doc.company_address) {
|
||||
@@ -343,13 +363,6 @@ cur_frm.cscript.hide_fields = function(doc) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var item_fields_stock = ['batch_no', 'actual_batch_qty', 'actual_qty', 'expense_account',
|
||||
'warehouse', 'expense_account', 'quality_inspection']
|
||||
cur_frm.fields_dict['items'].grid.set_column_disp(item_fields_stock,
|
||||
(cint(doc.update_stock)==1 || cint(doc.is_return)==1 ? true : false));
|
||||
|
||||
|
||||
// India related fields
|
||||
if (frappe.boot.sysdefaults.country == 'India') unhide_field(['c_form_applicable', 'c_form_no']);
|
||||
else hide_field(['c_form_applicable', 'c_form_no']);
|
||||
@@ -445,24 +458,6 @@ cur_frm.cscript.cost_center = function(doc, cdt, cdn) {
|
||||
erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "cost_center");
|
||||
}
|
||||
|
||||
cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
|
||||
$.each(doc["items"], function(i, row) {
|
||||
if(row.delivery_note) frappe.model.clear_doc("Delivery Note", row.delivery_note)
|
||||
})
|
||||
|
||||
if(cur_frm.doc.is_pos) {
|
||||
cur_frm.msgbox = frappe.msgprint(
|
||||
`<a class="btn btn-primary" onclick="cur_frm.print_preview.printit(true)" style="margin-right: 5px;">
|
||||
${__('Print')}</a>
|
||||
<a class="btn btn-default" href="javascript:frappe.new_doc(cur_frm.doctype);">
|
||||
${__('New')}</a>`
|
||||
);
|
||||
|
||||
} else if(cint(frappe.boot.notification_settings.sales_invoice)) {
|
||||
cur_frm.email_doc(frappe.boot.notification_settings.sales_invoice_message);
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.set_query("debit_to", function(doc) {
|
||||
// filter on Account
|
||||
if (doc.customer) {
|
||||
|
||||
@@ -18,6 +18,7 @@ from erpnext.projects.doctype.timesheet.timesheet import get_projectwise_timeshe
|
||||
from erpnext.accounts.doctype.asset.depreciation \
|
||||
import get_disposal_account_and_cost_center, get_gl_entries_on_asset_disposal
|
||||
from erpnext.stock.doctype.batch.batch import set_batch_nos
|
||||
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos, get_delivery_note_serial_no
|
||||
|
||||
form_grid_templates = {
|
||||
"items": "templates/form_grid/item_grid.html"
|
||||
@@ -83,10 +84,10 @@ class SalesInvoice(SellingController):
|
||||
|
||||
if not self.is_opening:
|
||||
self.is_opening = 'No'
|
||||
|
||||
|
||||
if self._action != 'submit' and self.update_stock and not self.is_return:
|
||||
set_batch_nos(self, 'warehouse', True)
|
||||
|
||||
|
||||
|
||||
self.set_against_income_account()
|
||||
self.validate_c_form()
|
||||
@@ -98,7 +99,7 @@ class SalesInvoice(SellingController):
|
||||
self.set_billing_hours_and_amount()
|
||||
self.update_timesheet_billing_for_project()
|
||||
self.set_status()
|
||||
|
||||
|
||||
def before_save(self):
|
||||
set_account_for_mode_of_payment(self)
|
||||
|
||||
@@ -139,6 +140,8 @@ class SalesInvoice(SellingController):
|
||||
|
||||
self.update_time_sheet(self.name)
|
||||
|
||||
frappe.enqueue('erpnext.setup.doctype.company.company.update_company_current_month_sales', company=self.company)
|
||||
|
||||
def validate_pos_paid_amount(self):
|
||||
if len(self.payments) == 0 and self.is_pos:
|
||||
frappe.throw(_("At least one mode of payment is required for POS invoice."))
|
||||
@@ -812,11 +815,18 @@ class SalesInvoice(SellingController):
|
||||
"""
|
||||
validate serial number agains Delivery Note and Sales Invoice
|
||||
"""
|
||||
self.set_serial_no_against_delivery_note()
|
||||
self.validate_serial_against_delivery_note()
|
||||
self.validate_serial_against_sales_invoice()
|
||||
|
||||
def set_serial_no_against_delivery_note(self):
|
||||
for item in self.items:
|
||||
if item.serial_no and item.delivery_note and \
|
||||
item.qty != len(get_serial_nos(item.serial_no)):
|
||||
item.serial_no = get_delivery_note_serial_no(item.item_code, item.qty, item.delivery_note)
|
||||
|
||||
def validate_serial_against_delivery_note(self):
|
||||
"""
|
||||
"""
|
||||
validate if the serial numbers in Sales Invoice Items are same as in
|
||||
Delivery Note Item
|
||||
"""
|
||||
@@ -826,14 +836,18 @@ class SalesInvoice(SellingController):
|
||||
continue
|
||||
|
||||
serial_nos = frappe.db.get_value("Delivery Note Item", item.dn_detail, "serial_no") or ""
|
||||
dn_serial_nos = set(serial_nos.split("\n"))
|
||||
dn_serial_nos = set(get_serial_nos(serial_nos))
|
||||
|
||||
serial_nos = item.serial_no or ""
|
||||
si_serial_nos = set(serial_nos.split("\n"))
|
||||
si_serial_nos = set(get_serial_nos(serial_nos))
|
||||
|
||||
if si_serial_nos - dn_serial_nos:
|
||||
frappe.throw(_("Serial Numbers in row {0} does not match with Delivery Note".format(item.idx)))
|
||||
|
||||
if item.serial_no and cint(item.qty) != len(si_serial_nos):
|
||||
frappe.throw(_("Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.".format(
|
||||
item.idx, item.qty, item.item_code, len(si_serial_nos))))
|
||||
|
||||
def validate_serial_against_sales_invoice(self):
|
||||
""" check if serial number is already used in other sales invoice """
|
||||
for item in self.items:
|
||||
@@ -918,7 +932,6 @@ def make_delivery_note(source_name, target_doc=None):
|
||||
|
||||
return doclist
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_sales_return(source_name, target_doc=None):
|
||||
from erpnext.controllers.sales_and_purchase_return import make_return_doc
|
||||
|
||||
@@ -13,6 +13,7 @@ from erpnext.exceptions import InvalidAccountCurrency, InvalidCurrency
|
||||
from erpnext.stock.doctype.serial_no.serial_no import SerialNoWarehouseError
|
||||
from frappe.model.naming import make_autoname
|
||||
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
||||
from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_data
|
||||
|
||||
class TestSalesInvoice(unittest.TestCase):
|
||||
def make(self):
|
||||
@@ -1105,10 +1106,75 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
for i, k in enumerate(expected_values["keys"]):
|
||||
self.assertEquals(d.get(k), expected_values[d.item_code][i])
|
||||
|
||||
def test_item_wise_tax_breakup(self):
|
||||
def test_item_wise_tax_breakup_india(self):
|
||||
frappe.flags.country = "India"
|
||||
|
||||
si = self.create_si_to_test_tax_breakup()
|
||||
itemised_tax, itemised_taxable_amount = get_itemised_tax_breakup_data(si)
|
||||
|
||||
expected_itemised_tax = {
|
||||
"999800": {
|
||||
"Service Tax": {
|
||||
"tax_rate": 10.0,
|
||||
"tax_amount": 1500.0
|
||||
}
|
||||
}
|
||||
}
|
||||
expected_itemised_taxable_amount = {
|
||||
"999800": 15000.0
|
||||
}
|
||||
|
||||
self.assertEqual(itemised_tax, expected_itemised_tax)
|
||||
self.assertEqual(itemised_taxable_amount, expected_itemised_taxable_amount)
|
||||
|
||||
frappe.flags.country = None
|
||||
|
||||
def test_item_wise_tax_breakup_outside_india(self):
|
||||
frappe.flags.country = "United States"
|
||||
|
||||
si = self.create_si_to_test_tax_breakup()
|
||||
|
||||
itemised_tax, itemised_taxable_amount = get_itemised_tax_breakup_data(si)
|
||||
|
||||
expected_itemised_tax = {
|
||||
"_Test Item": {
|
||||
"Service Tax": {
|
||||
"tax_rate": 10.0,
|
||||
"tax_amount": 1000.0
|
||||
}
|
||||
},
|
||||
"_Test Item 2": {
|
||||
"Service Tax": {
|
||||
"tax_rate": 10.0,
|
||||
"tax_amount": 500.0
|
||||
}
|
||||
}
|
||||
}
|
||||
expected_itemised_taxable_amount = {
|
||||
"_Test Item": 10000.0,
|
||||
"_Test Item 2": 5000.0
|
||||
}
|
||||
|
||||
self.assertEqual(itemised_tax, expected_itemised_tax)
|
||||
self.assertEqual(itemised_taxable_amount, expected_itemised_taxable_amount)
|
||||
|
||||
frappe.flags.country = None
|
||||
|
||||
def create_si_to_test_tax_breakup(self):
|
||||
si = create_sales_invoice(qty=100, rate=50, do_not_save=True)
|
||||
si.append("items", {
|
||||
"item_code": "_Test Item",
|
||||
"gst_hsn_code": "999800",
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
"qty": 100,
|
||||
"rate": 50,
|
||||
"income_account": "Sales - _TC",
|
||||
"expense_account": "Cost of Goods Sold - _TC",
|
||||
"cost_center": "_Test Cost Center - _TC"
|
||||
})
|
||||
si.append("items", {
|
||||
"item_code": "_Test Item 2",
|
||||
"gst_hsn_code": "999800",
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
"qty": 100,
|
||||
"rate": 50,
|
||||
@@ -1125,11 +1191,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
"rate": 10
|
||||
})
|
||||
si.insert()
|
||||
|
||||
tax_breakup_html = '''\n<div class="tax-break-up" style="overflow-x: auto;">\n\t<table class="table table-bordered table-hover">\n\t\t<thead><tr><th class="text-left" style="min-width: 120px;">Item Name</th><th class="text-right" style="min-width: 80px;">Taxable Amount</th><th class="text-right" style="min-width: 80px;">_Test Account Service Tax - _TC</th></tr></thead>\n\t\t<tbody><tr><td>_Test Item</td><td class="text-right">\u20b9 10,000.00</td><td class="text-right">(10.0%) \u20b9 1,000.00</td></tr></tbody>\n\t</table>\n</div>'''
|
||||
|
||||
self.assertEqual(si.other_charges_calculation, tax_breakup_html)
|
||||
|
||||
return si
|
||||
|
||||
def create_sales_invoice(**args):
|
||||
si = frappe.new_doc("Sales Invoice")
|
||||
@@ -1150,6 +1212,7 @@ def create_sales_invoice(**args):
|
||||
|
||||
si.append("items", {
|
||||
"item_code": args.item or args.item_code or "_Test Item",
|
||||
"gst_hsn_code": "999800",
|
||||
"warehouse": args.warehouse or "_Test Warehouse - _TC",
|
||||
"qty": args.qty or 1,
|
||||
"rate": args.rate or 100,
|
||||
|
||||
@@ -1424,7 +1424,7 @@
|
||||
"collapsible": 1,
|
||||
"collapsible_depends_on": "eval:doc.serial_no || doc.batch_no",
|
||||
"columns": 0,
|
||||
"depends_on": "eval: parent.update_stock",
|
||||
"depends_on": "",
|
||||
"fieldname": "warehouse_and_reference",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
@@ -2166,7 +2166,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-07-06 17:54:03.347700",
|
||||
"modified": "2017-07-17 17:54:48.246507",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice Item",
|
||||
|
||||
@@ -1398,10 +1398,6 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
return erpnext.get_currency(this.frm.doc.company);
|
||||
},
|
||||
|
||||
show_item_wise_taxes: function () {
|
||||
return null;
|
||||
},
|
||||
|
||||
show_items_in_item_cart: function () {
|
||||
var me = this;
|
||||
var $items = this.wrapper.find(".items").empty();
|
||||
|
||||
@@ -284,12 +284,14 @@ def get_credit_days(party_type, party, company):
|
||||
if not credit_days_based_on:
|
||||
if party_type == "Customer":
|
||||
credit_days_based_on, credit_days = \
|
||||
frappe.db.get_value("Customer Group", customer_group, ["credit_days_based_on", "credit_days"]) \
|
||||
or frappe.db.get_value("Company", company, ["credit_days_based_on", "credit_days"])
|
||||
frappe.db.get_value("Customer Group", customer_group, ["credit_days_based_on", "credit_days"])
|
||||
else:
|
||||
credit_days_based_on, credit_days = \
|
||||
frappe.db.get_value("Supplier Type", supplier_type, ["credit_days_based_on", "credit_days"])\
|
||||
or frappe.db.get_value("Company", company, ["credit_days_based_on", "credit_days"] )
|
||||
frappe.db.get_value("Supplier Type", supplier_type, ["credit_days_based_on", "credit_days"])
|
||||
|
||||
if not credit_days_based_on:
|
||||
credit_days_based_on, credit_days = \
|
||||
frappe.db.get_value("Company", company, ["credit_days_based_on", "credit_days"])
|
||||
|
||||
return credit_days_based_on, credit_days
|
||||
|
||||
|
||||
@@ -209,7 +209,10 @@ class GrossProfitGenerator(object):
|
||||
sle.voucher_detail_no == row.item_row:
|
||||
previous_stock_value = len(my_sle) > i+1 and \
|
||||
flt(my_sle[i+1].stock_value) or 0.0
|
||||
return previous_stock_value - flt(sle.stock_value)
|
||||
if previous_stock_value:
|
||||
return previous_stock_value - flt(sle.stock_value)
|
||||
else:
|
||||
return flt(row.qty) * self.get_average_buying_rate(row, item_code)
|
||||
else:
|
||||
return flt(row.qty) * self.get_average_buying_rate(row, item_code)
|
||||
|
||||
|
||||
@@ -1546,6 +1546,36 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
"columns": 0,
|
||||
"fieldname": "sec_tax_breakup",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Tax Breakup",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
@@ -1553,7 +1583,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "other_charges_calculation",
|
||||
"fieldtype": "HTML",
|
||||
"fieldtype": "Text",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
@@ -1568,7 +1598,7 @@
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
@@ -3305,7 +3335,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-06-13 14:29:21.066814",
|
||||
"modified": "2017-07-19 14:03:51.838328",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Purchase Order",
|
||||
|
||||
@@ -11,3 +11,6 @@ from erpnext.controllers.print_settings import print_settings_for_item_table
|
||||
class PurchaseOrderItem(Document):
|
||||
def __setup__(self):
|
||||
print_settings_for_item_table(self)
|
||||
|
||||
def on_doctype_update():
|
||||
frappe.db.add_index("Purchase Order Item", ["item_code", "warehouse"])
|
||||
@@ -1120,6 +1120,36 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
"columns": 0,
|
||||
"fieldname": "tax_breakup",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Tax Breakup",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
@@ -1127,7 +1157,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "other_charges_calculation",
|
||||
"fieldtype": "HTML",
|
||||
"fieldtype": "Text",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
@@ -1142,7 +1172,7 @@
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
@@ -2217,7 +2247,7 @@
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2017-06-13 14:28:54.466450",
|
||||
"modified": "2017-07-19 13:51:18.929697",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Supplier Quotation",
|
||||
|
||||
@@ -160,6 +160,7 @@ class AccountsController(TransactionBase):
|
||||
def set_missing_item_details(self, for_validate=False):
|
||||
"""set missing item values"""
|
||||
from erpnext.stock.get_item_details import get_item_details
|
||||
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||
|
||||
if hasattr(self, "items"):
|
||||
parent_dict = {}
|
||||
@@ -196,7 +197,7 @@ class AccountsController(TransactionBase):
|
||||
|
||||
elif fieldname == "serial_no":
|
||||
stock_qty = item.get("stock_qty") * -1 if item.get("stock_qty") < 0 else item.get("stock_qty")
|
||||
if stock_qty != len(item.get('serial_no').split('\n')):
|
||||
if stock_qty != len(get_serial_nos(item.get('serial_no'))):
|
||||
item.set(fieldname, value)
|
||||
|
||||
elif fieldname == "conversion_factor" and not item.get("conversion_factor"):
|
||||
|
||||
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
|
||||
import json
|
||||
import frappe, erpnext
|
||||
from frappe import _, scrub
|
||||
from frappe.utils import cint, flt, cstr, fmt_money, round_based_on_smallest_currency_fraction
|
||||
from frappe.utils import cint, flt, round_based_on_smallest_currency_fraction
|
||||
from erpnext.controllers.accounts_controller import validate_conversion_rate, \
|
||||
validate_taxes_and_charges, validate_inclusive_tax
|
||||
|
||||
@@ -509,108 +509,75 @@ class calculate_taxes_and_totals(object):
|
||||
return rate_with_margin
|
||||
|
||||
def set_item_wise_tax_breakup(self):
|
||||
item_tax = {}
|
||||
tax_accounts = []
|
||||
company_currency = erpnext.get_company_currency(self.doc.company)
|
||||
self.doc.other_charges_calculation = get_itemised_tax_breakup_html(self.doc)
|
||||
|
||||
item_tax, tax_accounts = self.get_item_tax(item_tax, tax_accounts, company_currency)
|
||||
|
||||
headings = get_table_column_headings(tax_accounts)
|
||||
|
||||
distinct_items, taxable_amount = self.get_distinct_items()
|
||||
|
||||
rows = get_table_rows(distinct_items, item_tax, tax_accounts, company_currency, taxable_amount)
|
||||
|
||||
if not rows:
|
||||
self.doc.other_charges_calculation = ""
|
||||
else:
|
||||
self.doc.other_charges_calculation = '''
|
||||
<div class="tax-break-up" style="overflow-x: auto;">
|
||||
<table class="table table-bordered table-hover">
|
||||
<thead><tr>{headings}</tr></thead>
|
||||
<tbody>{rows}</tbody>
|
||||
</table>
|
||||
</div>'''.format(**{
|
||||
"headings": "".join(headings),
|
||||
"rows": "".join(rows)
|
||||
})
|
||||
|
||||
def get_item_tax(self, item_tax, tax_accounts, company_currency):
|
||||
for tax in self.doc.taxes:
|
||||
tax_amount_precision = tax.precision("tax_amount")
|
||||
tax_rate_precision = tax.precision("rate");
|
||||
|
||||
item_tax_map = self._load_item_tax_rate(tax.item_wise_tax_detail)
|
||||
for item_code, tax_data in item_tax_map.items():
|
||||
if not item_tax.get(item_code):
|
||||
item_tax[item_code] = {}
|
||||
|
||||
if isinstance(tax_data, list):
|
||||
tax_rate = ""
|
||||
if tax_data[0]:
|
||||
if tax.charge_type == "Actual":
|
||||
tax_rate = fmt_money(flt(tax_data[0], tax_amount_precision),
|
||||
tax_amount_precision, company_currency)
|
||||
else:
|
||||
tax_rate = cstr(flt(tax_data[0], tax_rate_precision)) + "%"
|
||||
|
||||
tax_amount = fmt_money(flt(tax_data[1], tax_amount_precision),
|
||||
tax_amount_precision, company_currency)
|
||||
|
||||
item_tax[item_code][tax.name] = [tax_rate, tax_amount]
|
||||
else:
|
||||
item_tax[item_code][tax.name] = [cstr(flt(tax_data, tax_rate_precision)) + "%", "0.00"]
|
||||
tax_accounts.append([tax.name, tax.account_head])
|
||||
|
||||
return item_tax, tax_accounts
|
||||
|
||||
def get_itemised_tax_breakup_html(doc):
|
||||
if not doc.taxes:
|
||||
return
|
||||
frappe.flags.company = doc.company
|
||||
|
||||
def get_distinct_items(self):
|
||||
distinct_item_names = []
|
||||
distinct_items = []
|
||||
taxable_amount = {}
|
||||
for item in self.doc.items:
|
||||
item_code = item.item_code or item.item_name
|
||||
if item_code not in distinct_item_names:
|
||||
distinct_item_names.append(item_code)
|
||||
distinct_items.append(item)
|
||||
taxable_amount[item_code] = item.net_amount
|
||||
else:
|
||||
taxable_amount[item_code] = taxable_amount.get(item_code, 0) + item.net_amount
|
||||
|
||||
return distinct_items, taxable_amount
|
||||
# get headers
|
||||
tax_accounts = list(set([d.description for d in doc.taxes]))
|
||||
headers = get_itemised_tax_breakup_header(doc.doctype + " Item", tax_accounts)
|
||||
|
||||
# get tax breakup data
|
||||
itemised_tax, itemised_taxable_amount = get_itemised_tax_breakup_data(doc)
|
||||
|
||||
frappe.flags.company = None
|
||||
|
||||
return frappe.render_template(
|
||||
"templates/includes/itemised_tax_breakup.html", dict(
|
||||
headers=headers,
|
||||
itemised_tax=itemised_tax,
|
||||
itemised_taxable_amount=itemised_taxable_amount,
|
||||
tax_accounts=tax_accounts,
|
||||
company_currency=erpnext.get_company_currency(doc.company)
|
||||
)
|
||||
)
|
||||
|
||||
def get_table_column_headings(tax_accounts):
|
||||
headings_name = [_("Item Name"), _("Taxable Amount")] + [d[1] for d in tax_accounts]
|
||||
headings = []
|
||||
for head in headings_name:
|
||||
if head == _("Item Name"):
|
||||
headings.append('<th style="min-width: 120px;" class="text-left">' + (head or "") + "</th>")
|
||||
else:
|
||||
headings.append('<th style="min-width: 80px;" class="text-right">' + (head or "") + "</th>")
|
||||
@erpnext.allow_regional
|
||||
def get_itemised_tax_breakup_header(item_doctype, tax_accounts):
|
||||
return [_("Item"), _("Taxable Amount")] + tax_accounts
|
||||
|
||||
@erpnext.allow_regional
|
||||
def get_itemised_tax_breakup_data(doc):
|
||||
itemised_tax = get_itemised_tax(doc.taxes)
|
||||
|
||||
itemised_taxable_amount = get_itemised_taxable_amount(doc.items)
|
||||
|
||||
return itemised_tax, itemised_taxable_amount
|
||||
|
||||
def get_itemised_tax(taxes):
|
||||
itemised_tax = {}
|
||||
for tax in taxes:
|
||||
tax_amount_precision = tax.precision("tax_amount")
|
||||
tax_rate_precision = tax.precision("rate")
|
||||
|
||||
item_tax_map = json.loads(tax.item_wise_tax_detail) if tax.item_wise_tax_detail else {}
|
||||
|
||||
for item_code, tax_data in item_tax_map.items():
|
||||
itemised_tax.setdefault(item_code, frappe._dict())
|
||||
|
||||
return headings
|
||||
|
||||
def get_table_rows(distinct_items, item_tax, tax_accounts, company_currency, taxable_amount):
|
||||
rows = []
|
||||
for item in distinct_items:
|
||||
item_tax_record = item_tax.get(item.item_code or item.item_name)
|
||||
if not item_tax_record:
|
||||
continue
|
||||
|
||||
taxes = []
|
||||
for head in tax_accounts:
|
||||
if item_tax_record[head[0]]:
|
||||
taxes.append("<td class='text-right'>(" + item_tax_record[head[0]][0] + ") "
|
||||
+ item_tax_record[head[0]][1] + "</td>")
|
||||
if isinstance(tax_data, list) and tax_data[0]:
|
||||
precision = tax_amount_precision if tax.charge_type == "Actual" else tax_rate_precision
|
||||
|
||||
itemised_tax[item_code][tax.description] = frappe._dict(dict(
|
||||
tax_rate=flt(tax_data[0], precision),
|
||||
tax_amount=flt(tax_data[1], tax_amount_precision)
|
||||
))
|
||||
else:
|
||||
taxes.append("<td></td>")
|
||||
itemised_tax[item_code][tax.description] = frappe._dict(dict(
|
||||
tax_rate=flt(tax_data, tax_rate_precision),
|
||||
tax_amount=0.0
|
||||
))
|
||||
|
||||
return itemised_tax
|
||||
|
||||
def get_itemised_taxable_amount(items):
|
||||
itemised_taxable_amount = frappe._dict()
|
||||
for item in items:
|
||||
item_code = item.item_code or item.item_name
|
||||
rows.append("<tr><td>{item_name}</td><td class='text-right'>{taxable_amount}</td>{taxes}</tr>".format(**{
|
||||
"item_name": item.item_name,
|
||||
"taxable_amount": fmt_money(taxable_amount.get(item_code, 0), item.precision("net_amount"), company_currency),
|
||||
"taxes": "".join(taxes)
|
||||
}))
|
||||
|
||||
return rows
|
||||
itemised_taxable_amount.setdefault(item_code, 0)
|
||||
itemised_taxable_amount[item_code] += item.net_amount
|
||||
|
||||
return itemised_taxable_amount
|
||||
@@ -27,7 +27,8 @@ def test_recurring_document(obj, test_records):
|
||||
base_doc.set(date_field, today)
|
||||
|
||||
if base_doc.doctype == "Sales Order":
|
||||
base_doc.set("delivery_date", add_days(today, 15))
|
||||
for d in base_doc.get("items"):
|
||||
d.set("delivery_date", add_days(today, 15))
|
||||
|
||||
# monthly
|
||||
doc1 = frappe.copy_doc(base_doc)
|
||||
|
||||
43
erpnext/crm/doctype/lead/test_lead.js
Normal file
@@ -0,0 +1,43 @@
|
||||
QUnit.module("sales");
|
||||
|
||||
QUnit.test("test: lead", function (assert) {
|
||||
assert.expect(4);
|
||||
let done = assert.async();
|
||||
let lead_name = frappe.utils.get_random(10);
|
||||
frappe.run_serially([
|
||||
// test lead creation
|
||||
() => frappe.set_route("List", "Lead"),
|
||||
() => frappe.new_doc("Lead"),
|
||||
() => frappe.timeout(1),
|
||||
() => cur_frm.set_value("lead_name", lead_name),
|
||||
() => cur_frm.save(),
|
||||
() => frappe.timeout(1),
|
||||
() => {
|
||||
assert.ok(cur_frm.doc.lead_name.includes(lead_name),
|
||||
'name correctly set');
|
||||
frappe.lead_name = cur_frm.doc.name;
|
||||
},
|
||||
// create address and contact
|
||||
() => frappe.click_link('Address & Contact'),
|
||||
() => frappe.click_button('New Address'),
|
||||
() => frappe.timeout(1),
|
||||
() => frappe.set_control('address_line1', 'Gateway'),
|
||||
() => frappe.set_control('city', 'Mumbai'),
|
||||
() => cur_frm.save(),
|
||||
() => frappe.timeout(3),
|
||||
() => assert.equal(frappe.get_route()[1], 'Lead',
|
||||
'back to lead form'),
|
||||
() => frappe.click_link('Address & Contact'),
|
||||
() => assert.ok($('.address-box').text().includes('Mumbai'),
|
||||
'city is seen in address box'),
|
||||
|
||||
// make opportunity
|
||||
() => frappe.click_button('Make'),
|
||||
() => frappe.click_link('Opportunity'),
|
||||
() => frappe.timeout(2),
|
||||
() => assert.equal(cur_frm.doc.lead, frappe.lead_name,
|
||||
'lead name correctly mapped'),
|
||||
|
||||
() => done()
|
||||
]);
|
||||
});
|
||||
56
erpnext/crm/doctype/opportunity/test_opportunity.js
Normal file
@@ -0,0 +1,56 @@
|
||||
QUnit.test("test: opportunity", function (assert) {
|
||||
assert.expect(8);
|
||||
let done = assert.async();
|
||||
frappe.run_serially([
|
||||
() => frappe.set_route('List', 'Opportunity'),
|
||||
() => frappe.timeout(1),
|
||||
() => frappe.click_button('New'),
|
||||
() => frappe.timeout(1),
|
||||
() => cur_frm.set_value('enquiry_from', 'Customer'),
|
||||
() => cur_frm.set_value('customer', 'Test Customer 1'),
|
||||
|
||||
// check items
|
||||
() => cur_frm.set_value('with_items', 1),
|
||||
() => frappe.tests.set_grid_values(cur_frm, 'items', [
|
||||
[
|
||||
{item_code:'Test Product 1'},
|
||||
{qty: 4}
|
||||
]
|
||||
]),
|
||||
() => cur_frm.save(),
|
||||
() => frappe.timeout(1),
|
||||
() => {
|
||||
assert.notOk(cur_frm.is_new(), 'saved');
|
||||
frappe.opportunity_name = cur_frm.doc.name;
|
||||
},
|
||||
|
||||
// close and re-open
|
||||
() => frappe.click_button('Close'),
|
||||
() => frappe.timeout(1),
|
||||
() => assert.equal(cur_frm.doc.status, 'Closed',
|
||||
'closed'),
|
||||
|
||||
() => frappe.click_button('Reopen'),
|
||||
() => assert.equal(cur_frm.doc.status, 'Open',
|
||||
'reopened'),
|
||||
() => frappe.timeout(1),
|
||||
|
||||
// make quotation
|
||||
() => frappe.click_button('Make'),
|
||||
() => frappe.click_link('Quotation', 1),
|
||||
() => frappe.timeout(2),
|
||||
() => {
|
||||
assert.equal(frappe.get_route()[1], 'Quotation',
|
||||
'made quotation');
|
||||
assert.equal(cur_frm.doc.customer, 'Test Customer 1',
|
||||
'customer set in quotation');
|
||||
assert.equal(cur_frm.doc.items[0].item_code, 'Test Product 1',
|
||||
'item set in quotation');
|
||||
assert.equal(cur_frm.doc.items[0].qty, 4,
|
||||
'qty set in quotation');
|
||||
assert.equal(cur_frm.doc.items[0].prevdoc_docname, frappe.opportunity_name,
|
||||
'opportunity set in quotation');
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
});
|
||||
@@ -118,7 +118,8 @@ def make_sales_order():
|
||||
from erpnext.selling.doctype.quotation.quotation import make_sales_order
|
||||
so = frappe.get_doc(make_sales_order(q))
|
||||
so.transaction_date = frappe.flags.current_date
|
||||
so.delivery_date = frappe.utils.add_days(frappe.flags.current_date, 10)
|
||||
for d in so.get("items"):
|
||||
d.delivery_date = frappe.utils.add_days(frappe.flags.current_date, 10)
|
||||
so.insert()
|
||||
frappe.db.commit()
|
||||
so.submit()
|
||||
|
||||
|
Before Width: | Height: | Size: 185 KiB After Width: | Height: | Size: 215 KiB |
BIN
erpnext/docs/assets/img/sales_goal/sales_goal_notification.png
Normal file
|
After Width: | Height: | Size: 112 KiB |
BIN
erpnext/docs/assets/img/sales_goal/sales_history_graph.png
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
erpnext/docs/assets/img/sales_goal/setting_sales_goal.gif
Normal file
|
After Width: | Height: | Size: 7.8 MiB |
|
Before Width: | Height: | Size: 273 KiB After Width: | Height: | Size: 443 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 38 KiB |
@@ -15,5 +15,6 @@ third-party-backups
|
||||
workflows
|
||||
bar-code
|
||||
company-setup
|
||||
setting-company-sales-goal
|
||||
calculate-incentive-for-sales-team
|
||||
articles
|
||||
|
||||
@@ -31,7 +31,7 @@ Most of the information in your Sales Order is the same as the Quotation.
|
||||
There are a few amongst other things that a Sales Order will ask you to
|
||||
update.
|
||||
|
||||
* Expected date of delivery.
|
||||
* Enter delivery date agaist each item. If there are multiple items and if you enter delivery date in the first row, the date will be copied to other rows as well where it is blank.
|
||||
* Customer Purchase Order number: If your customer has sent you a Purchase Order, you can update its number for future reference (in billing).
|
||||
|
||||
### Packing List
|
||||
@@ -89,9 +89,9 @@ ERPNext will automatically create new Order and mail a notification to the Email
|
||||
Once you “Submit” your Sales Order, you can now trigger different aspects of
|
||||
your organization:
|
||||
|
||||
* To begin purchase click on “Make Purchase Request”
|
||||
* To make a shipment entry click on “Make Delivery Note”
|
||||
* To bill, make “Make Sales Invoice”
|
||||
* To begin purchase click on Make -> Purchase Request
|
||||
* To make a shipment entry click on Make -> Delivery Note. You can also make Delivery Note for selected items based on delivery date.
|
||||
* To bill, make Make -> Sales Invoice
|
||||
* To stop further process on this Sales Order, click on “Stop”
|
||||
|
||||
### Submission
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# Setting Company Sales Goal
|
||||
|
||||
Monthly sales targets can be set for a company via the Company master. By default, the Company master dashboard features past sales stats.
|
||||
|
||||
<img class="screenshot" alt="Sales Graph" src="{{docs_base_url}}/assets/img/sales_goal/sales_history_graph.png">
|
||||
|
||||
You can set the **Sales Target** field to track progress to track progress with respect to it.
|
||||
|
||||
<img class="screenshot" alt="Setting Sales Goal" src="{{docs_base_url}}/assets/img/sales_goal/setting_sales_goal.gif">
|
||||
|
||||
The target progress is also shown in notifications:
|
||||
|
||||
<img class="screenshot" alt="Sales Notification" src="{{docs_base_url}}/assets/img/sales_goal/sales_goal_notification.png">
|
||||
|
||||
{next}
|
||||
@@ -3,10 +3,10 @@ WORK IN PROGRESS
|
||||
-->
|
||||
# Manual de Usuario (Español)
|
||||
|
||||
### Contenido:
|
||||
### Contenido:
|
||||
|
||||
{index}
|
||||
|
||||
**Trabajo en progreso.**
|
||||
|
||||
[The Spanish Translation of the ERPNext manual is in progress. Click here to see the english manual]({{ docs_base_url }}/user/manual/en)
|
||||
[La traducción al Español del manual de ERPNext está en progreso. Click aquí para ver el manual en ingles]({{ docs_base_url }}/user/manual/en)
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
introduction
|
||||
accounts
|
||||
|
||||
20
erpnext/docs/user/manual/es/introduction/do-i-need-an-erp.md
Normal file
@@ -0,0 +1,20 @@
|
||||
ERPNext es una herramienta moderna que no solo abarca el módulo de contabilidad,
|
||||
sino que también, cubre todas las otras funciones de su negocio en una plataforma integrada.
|
||||
Tiene muchos beneficios sobre los sistemas tradicionales de contabilidad y otros ERP en el mercado.
|
||||
|
||||
### Beneficios sobre los sistemas de contabilidad tradicionales:
|
||||
|
||||
* Es más que solo contabilidad! Gestionar inventario, facturación, cotizaciones, clientes potenciales, nómina y mucho más.
|
||||
* Mantiene toda tu información segura y en un solo lugar. No siga buscando sus datos cuando más lo necesitas en diferente hojas de calculo y en diferentes ordenadores.
|
||||
Gestiona a todos tus empleados en el mismo lugar. Todos los usuarios obtienen información actualizada.
|
||||
* No más trabajo doble. No introduzcas la misma información desde su procesador de textos a su herramienta de contabilidad. Todo está integrado!
|
||||
* Manten un historial. Obten el historial completo de un cliente o un acuerdo en un solo lugar
|
||||
|
||||
### Beneficios sobre ERPs más grandes
|
||||
|
||||
* $$$ - Ahorra dinero.
|
||||
* **Más facíl de configurar:** Grandes ERP son extramadamente complicados para configurar y van a preguntar demasiadas preguntas amtes de que puedas hacer algo utíl.
|
||||
* **Más facíl de usar:** Una moderna y limpia interfaz web va a mantener sus usuarios contentos y en un entorno mas familiar.
|
||||
* **Código Abierto :** Este sistema es completamente gratis y puedes instalarlo/configurarlo donde desees.
|
||||
|
||||
{next}
|
||||
@@ -0,0 +1,31 @@
|
||||
Hay muchas manera de comenzar a utilizar ERPNext.
|
||||
|
||||
### 1\. Ver el Demo
|
||||
|
||||
Si deseas entrar en contacto con la interfaz de usuario de ERPNext y **sentir** la aplicación, solo tienes que ver el demo en:
|
||||
see the demo at:
|
||||
|
||||
* <https://demo.erpnext.com>
|
||||
|
||||
### 2\. Comienza con una cuenta gratis en ERPNext.com
|
||||
|
||||
|
||||
ERPNext.com es manejado por la organización (Frappe) que publicó ERPNext.
|
||||
Puedes iniciar con su propia cuenta en [registrandote en la página](https://erpnext.com).
|
||||
|
||||
También, puedes hostear tu aplicación en erpnext.com comprando un plan de alojamiento.
|
||||
De esta forma, estas aportando a la organización que desarrolla y mejora ERPNext.
|
||||
También obten soporte de uno-a-uno con los planes de alojamiento.
|
||||
|
||||
### 3\. Descarga una Maquina Virtual
|
||||
|
||||
Para evitar las molestias de instalar el sistema, ERPNext está disponible como una image virtual (un sistema operativo completo con ERPNext instalado).
|
||||
Puedes usarla en **cualquier** plataforma incluyendo Microsoft Windows.
|
||||
|
||||
[Click aquí para ver las instrucciones de como usar la imagen](https://erpnext.com/download)
|
||||
|
||||
### 4\. Instalar ERPNext en su ordenador Unix/Linux/Mac
|
||||
|
||||
En caso de estar relacionado con la instalación de aplicaciones en plataformas *nix, leer las instrucciones de como instalarlo usando [Frappe Bench](https://github.com/frappe/bench).
|
||||
|
||||
{next}
|
||||
@@ -0,0 +1,32 @@
|
||||
Antes de que empieces a manejar todas tus operaciones en ERPNext, primero
|
||||
deberías estar familiarizado con el sistema y los términos que utiliza.
|
||||
Por esa razón recomendamos que la implementación pase en dos fases.
|
||||
|
||||
* La **Fase de Prueba**, donde introduces información de prueba que representan sus transacciones del día a día y la **Fase de Producción**, donde comenzamos a introducir información real.
|
||||
|
||||
### Fase de Prueba
|
||||
|
||||
* Leer el manual
|
||||
* Crea una cuenta gratis en [https://erpnext.com](https://erpnext.com) (La forma más facíl de experimental).
|
||||
* Crea su primer Cliente, Suplidor y Producto. Agrega varios de estos para que se familiarice con ellos.
|
||||
* Crea un Grupo de Clientes, Grupo de Productos, Almacenes, Grupo de Suplidores, para que puedas clasificar sus productos.
|
||||
* Completar un ciclo estandar de ventas - Iniciativa > Oportunidad > Cotización > Orden de Venta > Nota de Entrega > Factura de Venta > Pago (Entrada de diario)
|
||||
* Completa un ciclo estandar de compra - Solicitud de Material > Orden de Compra > Recibo de Compra > Pagos (Entrada de diario).
|
||||
* Completar un ciclo de manofactura (si aplica) - BOM > Herramienta de Planificación de Producción > Orden de Producción > Problema de material
|
||||
* Replicar un escenario de su día a día dentro del sistema.
|
||||
* Crea un custom fields, formato de impresión, etc como sea requerido.
|
||||
|
||||
### Fase de Producción
|
||||
|
||||
Una vez ya estes falimiliarizado con ERPNext, inicia introduciendo la información real!
|
||||
|
||||
* Borra toda la información de prueba de la cuenta o inicia con una nueva instalación.
|
||||
* Si solo quieres borrar las transacciones y no las demás informaciones sobre Productos, Clientes, Suplidores, BOM etc, puedes dar click en Eliminar Transacciones de su compañia y inicia desde cero. Para hacerlo, abre el registro de la compañia via Setup > Masters > Company y eliminar las transacciones de su compañia clickeando en el botón **Eliminar las transacciones de la compañia** al final del formulario de la compañia.
|
||||
* También puedes configurar una nueva cuenta en [https://erpnext.com](https://erpnext.com), y usa los 30 días gratis. [Encuentra mas formas de usar ERPNext](/introduction/getting-started-with-erpnext)
|
||||
* Configura todos los módulos con Grupos de Clientes, Grupos de Productos, Almacenes, BOMs etc.
|
||||
* Importar Clientes, Suplidores, Productos, Contactos y Direcciones usando la Herramienta de Importación de Data.
|
||||
* Importar el inventario de apertura usando la Herramienta de Reconciliación de Inventario.
|
||||
* Crear la entrada de apertura de cuenta usando la Entrada de Diario y crea facturas de ventas pendientes y facturas de compra.
|
||||
* Si necesitas ayuda, [puedes pagar por soporte](https://erpnext.com/pricing) o [preguntar en el foro de la comunidad](https://discuss.erpnext.com).
|
||||
|
||||
{next}
|
||||
40
erpnext/docs/user/manual/es/introduction/index.md
Normal file
@@ -0,0 +1,40 @@
|
||||
## ¿Qué es un ERP y Por qué debería interesarme?
|
||||
|
||||
(Si ya sabes que necesitas un sistema todo-en-uno para su compañia, puedes pasar a la siguiente página)
|
||||
|
||||
Si eres dueño de una pequeña empresa que tiene varios empleados, debes entender que es difícil manejar la naturaleza dinámica de hacer negocios.
|
||||
Pequeñas empresas no son tan diferentes que las grandes empresas. Las pequeñas empresas contienen la mayoria de las complejidades que posee una empresa grande junto a otras reestricciones.
|
||||
Las pequeñas empresas tienen que comunicarse con clientes, hacer contabilidad, pagar impuestos, pagar nómina, gestionar tiempos,
|
||||
proporsionar bienes y servicios de calidad, responder preguntar, y mantener a todos contentos como lo hacen las grandes empresas.
|
||||
|
||||
Grandes empresas tienen la venraja de usar sistemas avanzados para manejar sus procesos de una forma mas eficiente.
|
||||
Pequeñas empresas, sin embargo, luchan para mantener las cosas organizadas. Normalmente usan un conjuntos de aplicaciones como hojas de calculos, sistemas de contabilidad,
|
||||
un CRM etc para administrarse. El problema es que no todos estan en la misma página. Un ERP cambia todo eso.
|
||||
|
||||
## ¿Qué es ERPNext?
|
||||
|
||||
ERPNext es una solución de negocio de extremo a extremo que te ayuda a manejar toda la información de su negocio en una sola aplicación
|
||||
y usado no solo para manejar operaciones, sino que tambien le permite tomar decisiones efectivas y bien documentadas justo en el momento que las necesites.
|
||||
Forma una columna vertebral de su negocio para agregar fuerza, transparencia y control a su compañia.
|
||||
|
||||
Junto con otras cosas, ERPNext te ayudará con todo lo siguiente:
|
||||
|
||||
* Mantener registro de todas sus facturas y pagos.
|
||||
* Saber que cantidad de cada producto hay disponible en almacen.
|
||||
* Identificar y hacer seguimiento de los indicadores de rendimientos (KPI's)
|
||||
* Identificar consultas abiertas de los clientes.
|
||||
* Gestionar Nómina.
|
||||
* Asignar tareas y hacer seguimiento de las mismas.
|
||||
* Mantener una base de datos de todos sus clientes, suplidores y sus contactos.
|
||||
* Preparar presupuestos.
|
||||
* Hacer seguimiento a su presupuesto y sus gastos.
|
||||
* Determinar el precio efectivo para ventas basado en la materia prima disponible, maquinaria y costo de esfuerzo.
|
||||
* Obtener recordatorios sobre el calendario de mantenimientos.
|
||||
* Publicar su página web.
|
||||
|
||||
Y Mucho mucho más.
|
||||
|
||||
|
||||
### Temas
|
||||
|
||||
{index}
|
||||
7
erpnext/docs/user/manual/es/introduction/index.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
do-i-need-an-erp
|
||||
open-source
|
||||
getting-started-with-erpnext
|
||||
the-champion
|
||||
implementation-strategy
|
||||
key-workflows
|
||||
concepts-and-terms
|
||||
13
erpnext/docs/user/manual/es/introduction/key-workflows.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Flujo De Transacciones En ERPNext
|
||||
|
||||
Este diagrama cubre como ERPNext hace el seguimiento de la información de su compañia a través de funciones claves.
|
||||
Este diagrama no cubre toda la funcionalidad o características de ERPNext.
|
||||
|
||||

|
||||
|
||||
|
||||
<img class="screenshot" alt="Workflow" src="{{docs_base_url}}/assets/img/setup/overview.png">
|
||||
|
||||
_Nota: No todos los pasos son obligatorios. ERPNext te permite pasar algunos pasos si deseas simplificar el proceso._
|
||||
|
||||
{next}
|
||||
34
erpnext/docs/user/manual/es/introduction/open-source.md
Normal file
@@ -0,0 +1,34 @@
|
||||
El código fuente de ERPNext es de código abierto. Está abierto para que todos
|
||||
podamos entenderlo, extenderlo o mejorarlo. Y es gratis!
|
||||
|
||||
Las ventajas de un Sistema de Código Abierto:
|
||||
|
||||
1. Puedes cambiar tu proveedor de servicios cuando quieras.
|
||||
2. Puedas hostear la aplicación donde quieras, incluyendo en tu propio servidor para tener completa propiedad y privacidad de la información.
|
||||
3. Puedes pedir ayuda a la comunidad en caso de necesitarla. No estas atado a un proveedor de servicios.
|
||||
4. Te puedes beneficiar de un producto que es criticado y usado por una gran cantidad de personas,
|
||||
quienes han reportado cientos de fallos y sugerencias para mejorarlo, y esto siempre va a continuar así.
|
||||
|
||||
|
||||
---
|
||||
|
||||
### Código Fuente de ERPNext
|
||||
|
||||
El repositorio que contiene el código fuente de ERPnext está disponible en GitHub y puede ser encontrado aquí
|
||||
|
||||
- [https://github.com/frappe/erpnext](https://github.com/frappe/erpnext)
|
||||
|
||||
|
||||
---
|
||||
|
||||
### Alternativas
|
||||
|
||||
Hay muchas soluciones ERP que puedes considerar. Los más populares son:
|
||||
|
||||
1. Odoo
|
||||
2. OpenBravo
|
||||
3. Apache OfBiz
|
||||
4. xTuple
|
||||
5. Compiere (y clones)
|
||||
|
||||
{next}
|
||||
41
erpnext/docs/user/manual/es/introduction/the-champion.md
Normal file
@@ -0,0 +1,41 @@
|
||||
<!-- no-heading -->
|
||||
|
||||
<h1 class="white">El campeón</h1>
|
||||
|
||||
<img alt="Champion" class="screenshot" src="{{docs_base_url}}/assets/img/setup/implementation-image.png">
|
||||
|
||||
Hemos visto docenas de implementaciones de sistemas ERP en los últimos años
|
||||
y nos hemos dado cuenta que una implementación exitosa es más sobre cosas intangibles y actitudes.
|
||||
|
||||
**Los ERP no son requeridos.**
|
||||
|
||||
Como el ejercicio.
|
||||
|
||||
El cuerpo humano puede que parezca que no requiere ejercicio hoy ni quizas mañana, pero con el pasar del tiempo,
|
||||
si desea mantener su cuerpo y su salud deberá comenzar a hacer ejercicio.
|
||||
|
||||
En esta misma forma, ERPs mejoran la salud de su compañia a largo plazo manteniendola ajustada y eficiente.
|
||||
Mientas más demores en poner las cosas en orden, más tiempo pierdes, y estas más cerca de una desastre mayor.
|
||||
|
||||
Por tanto, cuando comienzas a implementar un ERP, manten la visión en beneficios a largo plazo.
|
||||
Como el ejercicio, es doloroso al comienzo, pero va a hacer cosas maravillosas si te mantienes haciendolo.
|
||||
|
||||
* * *
|
||||
|
||||
## El Campeón
|
||||
|
||||
Un ERP significa un cambio en la organización y un cambio no sucede sin exfuerzo.
|
||||
Cada cambio requiere un campeón y es la responsabilidad de el campeón el
|
||||
organizar y motivar al equipo completo durante la implementación.
|
||||
El campeón necesita ser activo en caso que algo salga mal.
|
||||
|
||||
En muchas organizaciones que hemos visto, frecuentemente el campeón es el dueño o un Administrador.
|
||||
Ocasionalmente, el campeón es una persona externa quien es contratado con un propósito específico.
|
||||
|
||||
En cualquier caso, debes identificar su campeón primero.
|
||||
|
||||
Lo más seguro es que sea **usted!**
|
||||
|
||||
Comencemos!
|
||||
|
||||
{next}
|
||||
@@ -1,6 +1,5 @@
|
||||
from __future__ import unicode_literals
|
||||
from frappe import _
|
||||
from . import __version__ as app_version
|
||||
|
||||
app_name = "erpnext"
|
||||
app_title = "ERPNext"
|
||||
@@ -80,13 +79,7 @@ website_route_rules = [
|
||||
"parents": [{"title": _("Supplier Quotation"), "name": "quotations"}]
|
||||
}
|
||||
},
|
||||
{"from_route": "/quotes", "to_route": "Quotation"},
|
||||
{"from_route": "/quotes/<path:name>", "to_route": "order",
|
||||
"defaults": {
|
||||
"doctype": "Quotation",
|
||||
"parents": [{"title": _("Quotes"), "name": "quotes"}]
|
||||
}
|
||||
},
|
||||
{"from_route": "/quotation", "to_route": "Quotation"},
|
||||
{"from_route": "/shipments", "to_route": "Delivery Note"},
|
||||
{"from_route": "/shipments/<path:name>", "to_route": "order",
|
||||
"defaults": {
|
||||
@@ -117,7 +110,7 @@ standard_portal_menu_items = [
|
||||
{"title": _("Projects"), "route": "/project", "reference_doctype": "Project"},
|
||||
{"title": _("Request for Quotations"), "route": "/rfq", "reference_doctype": "Request for Quotation", "role": "Supplier"},
|
||||
{"title": _("Supplier Quotation"), "route": "/quotations", "reference_doctype": "Supplier Quotation", "role": "Supplier"},
|
||||
{"title": _("Quotes"), "route": "/quotes", "reference_doctype": "Quotation", "role":"Customer"},
|
||||
{"title": _("Quotations"), "route": "/quotation", "reference_doctype": "Quotation", "role":"Customer"},
|
||||
{"title": _("Orders"), "route": "/orders", "reference_doctype": "Sales Order", "role":"Customer"},
|
||||
{"title": _("Invoices"), "route": "/invoices", "reference_doctype": "Sales Invoice", "role":"Customer"},
|
||||
{"title": _("Shipments"), "route": "/shipments", "reference_doctype": "Delivery Note", "role":"Customer"},
|
||||
@@ -190,10 +183,13 @@ scheduler_events = {
|
||||
"erpnext.projects.doctype.task.task.set_tasks_as_overdue",
|
||||
"erpnext.accounts.doctype.asset.depreciation.post_depreciation_entries",
|
||||
"erpnext.hr.doctype.daily_work_summary_settings.daily_work_summary_settings.send_summary",
|
||||
"erpnext.stock.doctype.serial_no.serial_no.update_maintenance_status"
|
||||
"erpnext.stock.doctype.serial_no.serial_no.update_maintenance_status",
|
||||
"erpnext.setup.doctype.company.company.cache_companies_monthly_sales_history"
|
||||
]
|
||||
}
|
||||
|
||||
email_brand_image = "assets/erpnext/images/erpnext-logo.jpg"
|
||||
|
||||
default_mail_footer = """<div style="text-align: center;">
|
||||
<a href="https://erpnext.com?source=via_email_footer" target="_blank" style="color: #8d99a6;">
|
||||
Sent via ERPNext
|
||||
@@ -211,3 +207,11 @@ bot_parsers = [
|
||||
get_site_info = 'erpnext.utilities.get_site_info'
|
||||
|
||||
payment_gateway_enabled = "erpnext.accounts.utils.create_payment_gateway_account"
|
||||
|
||||
regional_overrides = {
|
||||
'India': {
|
||||
'erpnext.tests.test_regional.test_method': 'erpnext.regional.india.utils.test_method',
|
||||
'erpnext.controllers.taxes_and_totals.get_itemised_tax_breakup_header': 'erpnext.regional.india.utils.get_itemised_tax_breakup_header',
|
||||
'erpnext.controllers.taxes_and_totals.get_itemised_tax_breakup_data': 'erpnext.regional.india.utils.get_itemised_tax_breakup_data'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ from frappe.model.document import Document
|
||||
from frappe import _
|
||||
from email_reply_parser import EmailReplyParser
|
||||
from erpnext.hr.doctype.employee.employee import is_holiday
|
||||
from frappe.utils import formatdate
|
||||
from frappe.utils import global_date_format
|
||||
from markdown2 import markdown
|
||||
|
||||
class DailyWorkSummary(Document):
|
||||
@@ -24,17 +24,18 @@ class DailyWorkSummary(Document):
|
||||
|
||||
def send_summary(self):
|
||||
'''Send summary of all replies. Called at midnight'''
|
||||
message = self.get_summary_message()
|
||||
args = self.get_message_details()
|
||||
|
||||
frappe.sendmail(recipients = get_employee_emails(self.company, False),
|
||||
message = message,
|
||||
template='daily_work_summary',
|
||||
args=args,
|
||||
subject = _('Daily Work Summary for {0}').format(self.company),
|
||||
reference_doctype=self.doctype, reference_name=self.name)
|
||||
|
||||
self.db_set('status', 'Sent')
|
||||
|
||||
def get_summary_message(self):
|
||||
'''Return summary of replies as HTML'''
|
||||
def get_message_details(self):
|
||||
'''Return args for template'''
|
||||
settings = frappe.get_doc('Daily Work Summary Settings')
|
||||
|
||||
replies = frappe.get_all('Communication', fields=['content', 'text_content', 'sender'],
|
||||
@@ -45,8 +46,12 @@ class DailyWorkSummary(Document):
|
||||
did_not_reply = self.email_sent_to.split()
|
||||
|
||||
for d in replies:
|
||||
d.sender_name = frappe.db.get_value("Employee", {"user_id": d.sender},
|
||||
"employee_name") or d.sender
|
||||
emp = frappe.db.get_values("Employee", {"user_id": d.sender},
|
||||
["employee_name", "image"], as_dict=True)
|
||||
|
||||
d.sender_name = emp[0].employee_name if emp else d.sender
|
||||
d.image = emp[0].image if emp and emp[0].image else None
|
||||
|
||||
if d.sender in did_not_reply:
|
||||
did_not_reply.remove(d.sender)
|
||||
if d.text_content:
|
||||
@@ -56,30 +61,12 @@ class DailyWorkSummary(Document):
|
||||
did_not_reply = [(frappe.db.get_value("Employee", {"user_id": email}, "employee_name") or email)
|
||||
for email in did_not_reply]
|
||||
|
||||
return frappe.render_template(self.get_summary_template(),
|
||||
dict(replies=replies,
|
||||
original_message=settings.message,
|
||||
title=_('Daily Work Summary for {0}'.format(formatdate(self.creation))),
|
||||
did_not_reply= ', '.join(did_not_reply) or '',
|
||||
did_not_reply_title = _('No replies from')))
|
||||
return dict(replies=replies,
|
||||
original_message=settings.message,
|
||||
title=_('Daily Work Summary for {0}'.format(global_date_format(self.creation))),
|
||||
did_not_reply= ', '.join(did_not_reply) or '',
|
||||
did_not_reply_title = _('No replies from'))
|
||||
|
||||
def get_summary_template(self):
|
||||
return '''
|
||||
<h3>{{ title }}</h3>
|
||||
|
||||
{% for reply in replies %}
|
||||
<h4>{{ reply.sender_name }}</h4>
|
||||
<p style="padding-bottom: 20px">
|
||||
{{ reply.content }}
|
||||
</p>
|
||||
<hr>
|
||||
{% endfor %}
|
||||
|
||||
{% if did_not_reply %}
|
||||
<p>{{ did_not_reply_title }}: {{ did_not_reply }}</p>
|
||||
{% endif %}
|
||||
|
||||
'''
|
||||
|
||||
def get_employee_emails(company, only_working=True):
|
||||
'''Returns list of Employee user ids for the given company who are working today
|
||||
|
||||
@@ -46,9 +46,9 @@ class TestDailyWorkSummary(unittest.TestCase):
|
||||
daily_work_summary = frappe.get_doc('Daily Work Summary',
|
||||
frappe.get_all('Daily Work Summary')[0].name)
|
||||
|
||||
summary = daily_work_summary.get_summary_message()
|
||||
args = daily_work_summary.get_message_details()
|
||||
|
||||
self.assertTrue('I built Daily Work Summary!' in summary)
|
||||
self.assertTrue('I built Daily Work Summary!' in args.get('replies')[0].content)
|
||||
|
||||
def setup_and_prepare_test(self, hour=None):
|
||||
frappe.db.sql('delete from `tabDaily Work Summary`')
|
||||
|
||||
@@ -230,7 +230,7 @@ frappe.ui.form.on("Expense Claim",{
|
||||
frm.fields_dict["payable_account"].get_query = function() {
|
||||
return {
|
||||
filters: {
|
||||
"root_type": "Liability",
|
||||
"report_type": "Balance Sheet",
|
||||
"account_type": "Payable"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -905,7 +905,7 @@
|
||||
"label": "Status",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Draft\nPaid\nUnpaid\nSubmitted\nCancelled",
|
||||
"options": "Draft\nPaid\nUnpaid\nRejected\nSubmitted\nCancelled",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
@@ -964,7 +964,7 @@
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2017-06-13 14:29:16.914609",
|
||||
"modified": "2017-07-17 15:47:23.255142",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Expense Claim",
|
||||
|
||||
@@ -39,10 +39,13 @@ class ExpenseClaim(AccountsController):
|
||||
"2": "Cancelled"
|
||||
}[cstr(self.docstatus or 0)]
|
||||
|
||||
if self.total_sanctioned_amount == self.total_amount_reimbursed and self.docstatus == 1:
|
||||
if self.total_sanctioned_amount > 0 and self.total_sanctioned_amount == self.total_amount_reimbursed \
|
||||
and self.docstatus == 1 and self.approval_status == 'Approved':
|
||||
self.status = "Paid"
|
||||
elif self.docstatus == 1:
|
||||
elif self.total_sanctioned_amount > 0 and self.docstatus == 1 and self.approval_status == 'Approved':
|
||||
self.status = "Unpaid"
|
||||
elif self.docstatus == 1 and self.approval_status == 'Rejected':
|
||||
self.status = 'Rejected'
|
||||
|
||||
def set_payable_account(self):
|
||||
if not self.payable_account and not self.is_paid:
|
||||
@@ -157,6 +160,9 @@ class ExpenseClaim(AccountsController):
|
||||
self.total_claimed_amount = 0
|
||||
self.total_sanctioned_amount = 0
|
||||
for d in self.get('expenses'):
|
||||
if self.approval_status == 'Rejected':
|
||||
d.sanctioned_amount = 0.0
|
||||
|
||||
self.total_claimed_amount += flt(d.claim_amount)
|
||||
self.total_sanctioned_amount += flt(d.sanctioned_amount)
|
||||
|
||||
|
||||
@@ -4,8 +4,10 @@ frappe.listview_settings['Expense Claim'] = {
|
||||
get_indicator: function(doc) {
|
||||
if(doc.status == "Paid") {
|
||||
return [__("Paid"), "green", "status,=,'Paid'"];
|
||||
} else {
|
||||
}else if(doc.status == "Unpaid") {
|
||||
return [__("Unpaid"), "orange"];
|
||||
} else if(doc.status == "Rejected") {
|
||||
return [__("Rejected"), "grey"];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -113,5 +113,23 @@ class TestExpenseClaim(unittest.TestCase):
|
||||
self.assertEquals(expected_values[gle.account][1], gle.debit)
|
||||
self.assertEquals(expected_values[gle.account][2], gle.credit)
|
||||
|
||||
def test_rejected_expense_claim(self):
|
||||
payable_account = get_payable_account("Wind Power LLC")
|
||||
expense_claim = frappe.get_doc({
|
||||
"doctype": "Expense Claim",
|
||||
"employee": "_T-Employee-0001",
|
||||
"payable_account": payable_account,
|
||||
"approval_status": "Rejected",
|
||||
"expenses":
|
||||
[{ "expense_type": "Travel", "default_account": "Travel Expenses - WP", "claim_amount": 300, "sanctioned_amount": 200 }]
|
||||
})
|
||||
expense_claim.submit()
|
||||
|
||||
self.assertEquals(expense_claim.status, 'Rejected')
|
||||
self.assertEquals(expense_claim.total_sanctioned_amount, 0.0)
|
||||
|
||||
gl_entry = frappe.get_all('GL Entry', {'voucher_type': 'Expense Claim', 'voucher_no': expense_claim.name})
|
||||
self.assertEquals(len(gl_entry), 0)
|
||||
|
||||
def get_payable_account(company):
|
||||
return frappe.db.get_value('Company', company, 'default_payable_account')
|
||||
|
||||
@@ -69,27 +69,17 @@ def get_events(start, end, filters=None):
|
||||
:param end: End date-time.
|
||||
:param filters: Filters (JSON).
|
||||
"""
|
||||
condition = ''
|
||||
values = {
|
||||
"start_date": getdate(start),
|
||||
"end_date": getdate(end)
|
||||
}
|
||||
|
||||
if filters:
|
||||
if isinstance(filters, basestring):
|
||||
filters = json.loads(filters)
|
||||
filters = json.loads(filters)
|
||||
else:
|
||||
filters = []
|
||||
|
||||
if filters.get('holiday_list'):
|
||||
condition = 'and hlist.name=%(holiday_list)s'
|
||||
values['holiday_list'] = filters['holiday_list']
|
||||
if start:
|
||||
filters.append(['Holiday', 'holiday_date', '>', getdate(start)])
|
||||
if end:
|
||||
filters.append(['Holiday', 'holiday_date', '<', getdate(end)])
|
||||
|
||||
data = frappe.db.sql("""select hlist.name, h.holiday_date, h.description
|
||||
from `tabHoliday List` hlist, tabHoliday h
|
||||
where h.parent = hlist.name
|
||||
and h.holiday_date is not null
|
||||
and h.holiday_date >= %(start_date)s
|
||||
and h.holiday_date <= %(end_date)s
|
||||
{condition}""".format(condition=condition),
|
||||
values, as_dict=True, update={"allDay": 1})
|
||||
|
||||
return data
|
||||
return frappe.get_list('Holiday List',
|
||||
fields=['name', '`tabHoliday`.holiday_date', '`tabHoliday`.description'],
|
||||
filters = filters,
|
||||
update={"allDay": 1})
|
||||
|
||||
@@ -63,13 +63,13 @@ class LeaveApplication(Document):
|
||||
def validate_dates(self):
|
||||
if self.from_date and self.to_date and (getdate(self.to_date) < getdate(self.from_date)):
|
||||
frappe.throw(_("To date cannot be before from date"))
|
||||
|
||||
|
||||
if self.half_day and self.half_day_date \
|
||||
and (getdate(self.half_day_date) < getdate(self.from_date)
|
||||
and (getdate(self.half_day_date) < getdate(self.from_date)
|
||||
or getdate(self.half_day_date) > getdate(self.to_date)):
|
||||
|
||||
|
||||
frappe.throw(_("Half Day Date should be between From Date and To Date"))
|
||||
|
||||
|
||||
if not is_lwp(self.leave_type):
|
||||
self.validate_dates_acorss_allocation()
|
||||
self.validate_back_dated_application()
|
||||
@@ -158,7 +158,7 @@ class LeaveApplication(Document):
|
||||
self.name = "New Leave Application"
|
||||
|
||||
for d in frappe.db.sql("""
|
||||
select
|
||||
select
|
||||
name, leave_type, posting_date, from_date, to_date, total_leave_days, half_day_date
|
||||
from `tabLeave Application`
|
||||
where employee = %(employee)s and docstatus < 2 and status in ("Open", "Approved")
|
||||
@@ -169,12 +169,12 @@ class LeaveApplication(Document):
|
||||
"to_date": self.to_date,
|
||||
"name": self.name
|
||||
}, as_dict = 1):
|
||||
|
||||
|
||||
if cint(self.half_day)==1 and getdate(self.half_day_date) == getdate(d.half_day_date) and (
|
||||
flt(self.total_leave_days)==0.5
|
||||
or getdate(self.from_date) == getdate(d.to_date)
|
||||
flt(self.total_leave_days)==0.5
|
||||
or getdate(self.from_date) == getdate(d.to_date)
|
||||
or getdate(self.to_date) == getdate(d.from_date)):
|
||||
|
||||
|
||||
total_leaves_on_half_day = self.get_total_leaves_on_half_day()
|
||||
if total_leaves_on_half_day >= 1:
|
||||
self.throw_overlap_error(d)
|
||||
@@ -199,7 +199,7 @@ class LeaveApplication(Document):
|
||||
"half_day_date": self.half_day_date,
|
||||
"name": self.name
|
||||
})[0][0]
|
||||
|
||||
|
||||
return leave_count_on_half_day_date * 0.5
|
||||
|
||||
def validate_max_days(self):
|
||||
@@ -400,7 +400,7 @@ def is_lwp(leave_type):
|
||||
return lwp and cint(lwp[0][0]) or 0
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_events(start, end):
|
||||
def get_events(start, end, filters=None):
|
||||
events = []
|
||||
|
||||
employee = frappe.db.get_value("Employee", {"user_id": frappe.session.user}, ["name", "company"],
|
||||
@@ -411,14 +411,14 @@ def get_events(start, end):
|
||||
employee=''
|
||||
company=frappe.db.get_value("Global Defaults", None, "default_company")
|
||||
|
||||
from frappe.desk.reportview import build_match_conditions
|
||||
match_conditions = build_match_conditions("Leave Application")
|
||||
from frappe.desk.reportview import get_filters_cond
|
||||
conditions = get_filters_cond("Leave Application", filters, [])
|
||||
|
||||
# show department leaves for employee
|
||||
if "Employee" in frappe.get_roles():
|
||||
add_department_leaves(events, start, end, employee, company)
|
||||
|
||||
add_leaves(events, start, end, match_conditions)
|
||||
add_leaves(events, start, end, conditions)
|
||||
|
||||
add_block_dates(events, start, end, employee, company)
|
||||
add_holidays(events, start, end, employee, company)
|
||||
@@ -435,7 +435,7 @@ def add_department_leaves(events, start, end, employee, company):
|
||||
department_employees = frappe.db.sql_list("""select name from tabEmployee where department=%s
|
||||
and company=%s""", (department, company))
|
||||
|
||||
match_conditions = "employee in (\"%s\")" % '", "'.join(department_employees)
|
||||
match_conditions = "and employee in (\"%s\")" % '", "'.join(department_employees)
|
||||
add_leaves(events, start, end, match_conditions=match_conditions)
|
||||
|
||||
def add_leaves(events, start, end, match_conditions=None):
|
||||
@@ -446,7 +446,7 @@ def add_leaves(events, start, end, match_conditions=None):
|
||||
and docstatus < 2
|
||||
and status!="Rejected" """
|
||||
if match_conditions:
|
||||
query += " and " + match_conditions
|
||||
query += match_conditions
|
||||
|
||||
for d in frappe.db.sql(query, {"start":start, "end": end}, as_dict=True):
|
||||
e = {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
// License: GNU General Public License v3. See license.txt
|
||||
|
||||
var in_progress = false;
|
||||
|
||||
frappe.ui.form.on("Process Payroll", {
|
||||
onload: function (frm) {
|
||||
frm.doc.posting_date = frappe.datetime.nowdate();
|
||||
@@ -47,11 +49,12 @@ frappe.ui.form.on("Process Payroll", {
|
||||
},
|
||||
|
||||
start_date: function (frm) {
|
||||
frm.trigger("set_start_end_dates");
|
||||
},
|
||||
|
||||
end_date: function (frm) {
|
||||
frm.trigger("set_start_end_dates");
|
||||
if(!in_progress && frm.doc.start_date){
|
||||
frm.trigger("set_end_date");
|
||||
}else{
|
||||
// reset flag
|
||||
in_progress = false
|
||||
}
|
||||
},
|
||||
|
||||
salary_slip_based_on_timesheet: function (frm) {
|
||||
@@ -68,10 +71,11 @@ frappe.ui.form.on("Process Payroll", {
|
||||
method: 'erpnext.hr.doctype.process_payroll.process_payroll.get_start_end_dates',
|
||||
args: {
|
||||
payroll_frequency: frm.doc.payroll_frequency,
|
||||
start_date: frm.doc.start_date || frm.doc.posting_date
|
||||
start_date: frm.doc.posting_date
|
||||
},
|
||||
callback: function (r) {
|
||||
if (r.message) {
|
||||
in_progress = true;
|
||||
frm.set_value('start_date', r.message.start_date);
|
||||
frm.set_value('end_date', r.message.end_date);
|
||||
}
|
||||
@@ -79,6 +83,21 @@ frappe.ui.form.on("Process Payroll", {
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
set_end_date: function(frm){
|
||||
frappe.call({
|
||||
method: 'erpnext.hr.doctype.process_payroll.process_payroll.get_end_date',
|
||||
args: {
|
||||
frequency: frm.doc.payroll_frequency,
|
||||
start_date: frm.doc.start_date
|
||||
},
|
||||
callback: function (r) {
|
||||
if (r.message) {
|
||||
frm.set_value('end_date', r.message.end_date);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
cur_frm.cscript.display_activity_log = function (msg) {
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.utils import cint, flt, nowdate, add_days, getdate, fmt_money
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from frappe.utils import cint, nowdate, add_days, getdate, fmt_money, add_to_date, DATE_FORMAT
|
||||
from frappe import _
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
|
||||
@@ -47,7 +48,6 @@ class ProcessPayroll(Document):
|
||||
%s """% cond, {"sal_struct": sal_struct})
|
||||
return emp_list
|
||||
|
||||
|
||||
def get_filter_condition(self):
|
||||
self.check_mandatory()
|
||||
|
||||
@@ -58,7 +58,6 @@ class ProcessPayroll(Document):
|
||||
|
||||
return cond
|
||||
|
||||
|
||||
def get_joining_releiving_condition(self):
|
||||
cond = """
|
||||
and ifnull(t1.date_of_joining, '0000-00-00') <= '%(end_date)s'
|
||||
@@ -66,7 +65,6 @@ class ProcessPayroll(Document):
|
||||
""" % {"start_date": self.start_date, "end_date": self.end_date}
|
||||
return cond
|
||||
|
||||
|
||||
def check_mandatory(self):
|
||||
for fieldname in ['company', 'start_date', 'end_date']:
|
||||
if not self.get(fieldname):
|
||||
@@ -110,7 +108,6 @@ class ProcessPayroll(Document):
|
||||
ss_list.append(ss_dict)
|
||||
return self.create_log(ss_list)
|
||||
|
||||
|
||||
def create_log(self, ss_list):
|
||||
if not ss_list or len(ss_list) < 1:
|
||||
log = "<p>" + _("No employee for the above selected criteria OR salary slip already created") + "</p>"
|
||||
@@ -134,7 +131,6 @@ class ProcessPayroll(Document):
|
||||
""" % ('%s', '%s', '%s','%s', cond), (ss_status, self.start_date, self.end_date, self.salary_slip_based_on_timesheet), as_dict=as_dict)
|
||||
return ss_list
|
||||
|
||||
|
||||
def submit_salary_slips(self):
|
||||
"""
|
||||
Submit all salary slips based on selected criteria
|
||||
@@ -194,7 +190,6 @@ class ProcessPayroll(Document):
|
||||
def format_as_links(self, salary_slip):
|
||||
return ['<a href="#Form/Salary Slip/{0}">{0}</a>'.format(salary_slip)]
|
||||
|
||||
|
||||
def get_total_salary_and_loan_amounts(self):
|
||||
"""
|
||||
Get total loan principal, loan interest and salary amount from submitted salary slip based on selected criteria
|
||||
@@ -257,7 +252,6 @@ class ProcessPayroll(Document):
|
||||
|
||||
return payroll_payable_account
|
||||
|
||||
|
||||
def make_accural_jv_entry(self):
|
||||
self.check_permission('write')
|
||||
earnings = self.get_salary_component_total(component_type = "earnings") or {}
|
||||
@@ -358,7 +352,6 @@ class ProcessPayroll(Document):
|
||||
self.update(get_start_end_dates(self.payroll_frequency,
|
||||
self.start_date or self.posting_date, self.company))
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_start_end_dates(payroll_frequency, start_date=None, company=None):
|
||||
'''Returns dict of start and end dates for given payroll frequency based on start_date'''
|
||||
@@ -391,6 +384,29 @@ def get_start_end_dates(payroll_frequency, start_date=None, company=None):
|
||||
'start_date': start_date, 'end_date': end_date
|
||||
})
|
||||
|
||||
def get_frequency_kwargs(frequency_name):
|
||||
frequency_dict = {
|
||||
'monthly': {'months': 1},
|
||||
'fortnightly': {'days': 14},
|
||||
'weekly': {'days': 7},
|
||||
'daily': {'days': 1}
|
||||
}
|
||||
return frequency_dict.get(frequency_name)
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_end_date(start_date, frequency):
|
||||
start_date = getdate(start_date)
|
||||
frequency = frequency.lower() if frequency else 'monthly'
|
||||
kwargs = get_frequency_kwargs(frequency) if frequency != 'bimonthly' else get_frequency_kwargs('monthly')
|
||||
|
||||
# weekly, fortnightly and daily intervals have fixed days so no problems
|
||||
end_date = add_to_date(start_date, **kwargs) - relativedelta(days=1)
|
||||
if frequency != 'bimonthly':
|
||||
return dict(end_date=end_date.strftime(DATE_FORMAT))
|
||||
|
||||
else:
|
||||
return dict(end_date='')
|
||||
|
||||
def get_month_details(year, month):
|
||||
ysd = frappe.db.get_value("Fiscal Year", year, "year_start_date")
|
||||
if ysd:
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import unittest
|
||||
import frappe
|
||||
|
||||
import erpnext
|
||||
from frappe.utils import flt, add_months, cint, nowdate, getdate, add_days, random_string
|
||||
from frappe.utils.make_random import get_random
|
||||
import frappe
|
||||
from frappe.utils import nowdate
|
||||
from erpnext.hr.doctype.process_payroll.process_payroll import get_end_date
|
||||
|
||||
|
||||
class TestProcessPayroll(unittest.TestCase):
|
||||
def test_process_payroll(self):
|
||||
@@ -30,6 +32,16 @@ class TestProcessPayroll(unittest.TestCase):
|
||||
process_payroll.submit_salary_slips()
|
||||
if process_payroll.get_sal_slip_list(ss_status = 1):
|
||||
r = process_payroll.make_payment_entry()
|
||||
|
||||
def test_get_end_date(self):
|
||||
self.assertEqual(get_end_date('2017-01-01', 'monthly'), {'end_date': '2017-01-31'})
|
||||
self.assertEqual(get_end_date('2017-02-01', 'monthly'), {'end_date': '2017-02-28'})
|
||||
self.assertEqual(get_end_date('2017-02-01', 'fortnightly'), {'end_date': '2017-02-14'})
|
||||
self.assertEqual(get_end_date('2017-02-01', 'bimonthly'), {'end_date': ''})
|
||||
self.assertEqual(get_end_date('2017-01-01', 'bimonthly'), {'end_date': ''})
|
||||
self.assertEqual(get_end_date('2020-02-15', 'bimonthly'), {'end_date': ''})
|
||||
self.assertEqual(get_end_date('2017-02-15', 'monthly'), {'end_date': '2017-03-14'})
|
||||
self.assertEqual(get_end_date('2017-02-15', 'daily'), {'end_date': '2017-02-15'})
|
||||
|
||||
|
||||
def get_salary_component_account(sal_comp):
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
@@ -12,6 +13,7 @@
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -22,6 +24,7 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Payment Date",
|
||||
@@ -40,6 +43,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -50,11 +54,13 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Principal Amount",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
@@ -68,6 +74,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -78,11 +85,13 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Interest Amount",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
@@ -96,6 +105,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -106,11 +116,13 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Total Payment",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
@@ -124,6 +136,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -134,11 +147,13 @@
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Balance Loan Amount",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
@@ -152,17 +167,17 @@
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"in_dialog": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-01-09 12:00:10.818772",
|
||||
"modified": "2017-07-26 14:47:29.862084",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Repayment Schedule",
|
||||
@@ -172,6 +187,7 @@
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
|
||||
@@ -29,6 +29,27 @@ frappe.ui.form.on("Salary Slip", {
|
||||
})
|
||||
},
|
||||
|
||||
start_date: function(frm){
|
||||
if(frm.doc.start_date){
|
||||
frm.trigger("set_end_date");
|
||||
}
|
||||
},
|
||||
|
||||
set_end_date: function(frm){
|
||||
frappe.call({
|
||||
method: 'erpnext.hr.doctype.process_payroll.process_payroll.get_end_date',
|
||||
args: {
|
||||
frequency: frm.doc.payroll_frequency,
|
||||
start_date: frm.doc.start_date
|
||||
},
|
||||
callback: function (r) {
|
||||
if (r.message) {
|
||||
frm.set_value('end_date', r.message.end_date);
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
company: function(frm) {
|
||||
var company = locals[':Company'][frm.doc.company];
|
||||
if(!frm.doc.letter_head && company.default_letter_head) {
|
||||
@@ -45,11 +66,17 @@ frappe.ui.form.on("Salary Slip", {
|
||||
},
|
||||
|
||||
salary_slip_based_on_timesheet: function(frm) {
|
||||
frm.trigger("toggle_fields")
|
||||
frm.trigger("toggle_fields");
|
||||
frm.set_value('start_date', '');
|
||||
},
|
||||
|
||||
payroll_frequency: function(frm) {
|
||||
frm.trigger("toggle_fields")
|
||||
frm.trigger("toggle_fields");
|
||||
frm.set_value('start_date', '');
|
||||
},
|
||||
|
||||
employee: function(frm){
|
||||
frm.set_value('start_date', '');
|
||||
},
|
||||
|
||||
toggle_fields: function(frm) {
|
||||
@@ -74,18 +101,19 @@ frappe.ui.form.on('Salary Detail', {
|
||||
// Get leave details
|
||||
//---------------------------------------------------------------------
|
||||
cur_frm.cscript.start_date = function(doc, dt, dn){
|
||||
return frappe.call({
|
||||
method: 'get_emp_and_leave_details',
|
||||
doc: locals[dt][dn],
|
||||
callback: function(r, rt) {
|
||||
cur_frm.refresh();
|
||||
calculate_all(doc, dt, dn);
|
||||
}
|
||||
});
|
||||
if(!doc.start_date){
|
||||
return frappe.call({
|
||||
method: 'get_emp_and_leave_details',
|
||||
doc: locals[dt][dn],
|
||||
callback: function(r, rt) {
|
||||
cur_frm.refresh();
|
||||
calculate_all(doc, dt, dn);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.cscript.payroll_frequency = cur_frm.cscript.salary_slip_based_on_timesheet = cur_frm.cscript.start_date;
|
||||
cur_frm.cscript.end_date = cur_frm.cscript.start_date;
|
||||
|
||||
cur_frm.cscript.employee = function(doc,dt,dn){
|
||||
doc.salary_structure = ''
|
||||
|
||||
@@ -51,6 +51,7 @@ class BOM(WebsiteGenerator):
|
||||
from erpnext.utilities.transaction_base import validate_uom_is_integer
|
||||
validate_uom_is_integer(self, "stock_uom", "stock_qty", "BOM Item")
|
||||
|
||||
self.update_stock_qty()
|
||||
self.validate_materials()
|
||||
self.set_bom_material_details()
|
||||
self.validate_operations()
|
||||
|
||||
@@ -77,7 +77,6 @@ frappe.ui.form.on("Production Order", {
|
||||
if (!frm.doc.status)
|
||||
frm.doc.status = 'Draft';
|
||||
|
||||
frm.add_fetch("sales_order", "delivery_date", "expected_delivery_date");
|
||||
frm.add_fetch("sales_order", "project", "project");
|
||||
|
||||
if(frm.doc.__islocal) {
|
||||
|
||||
@@ -50,8 +50,12 @@ class ProductionOrder(Document):
|
||||
|
||||
def validate_sales_order(self):
|
||||
if self.sales_order:
|
||||
so = frappe.db.sql("""select name, delivery_date, project from `tabSales Order`
|
||||
where name=%s and docstatus = 1""", self.sales_order, as_dict=1)
|
||||
so = frappe.db.sql("""
|
||||
select so.name, so_item.delivery_date, so.project
|
||||
from `tabSales Order` so, `tabSales Order Item` so_item
|
||||
where so.name=%s and so.name=so_item.parent
|
||||
and so.docstatus = 1 and so_item.item_code=%s
|
||||
""", (self.sales_order, self.production_item), as_dict=1)
|
||||
|
||||
if len(so):
|
||||
if not self.expected_delivery_date:
|
||||
@@ -510,6 +514,12 @@ def check_if_scrap_warehouse_mandatory(bom_no):
|
||||
|
||||
return res
|
||||
|
||||
@frappe.whitelist()
|
||||
def set_production_order_ops(name):
|
||||
po = frappe.get_doc('Production Order', name)
|
||||
po.set_production_order_operations()
|
||||
po.save()
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_stock_entry(production_order_id, purpose, qty=None):
|
||||
production_order = frappe.get_doc("Production Order", production_order_id)
|
||||
|
||||
@@ -8,3 +8,6 @@ from frappe.model.document import Document
|
||||
|
||||
class ProductionOrderItem(Document):
|
||||
pass
|
||||
|
||||
def on_doctype_update():
|
||||
frappe.db.add_index("Production Order Item", ["item_code", "source_warehouse"])
|
||||
@@ -0,0 +1,23 @@
|
||||
/* eslint-disable */
|
||||
// rename this file from _test_[name] to test_[name] to activate
|
||||
// and remove above this line
|
||||
|
||||
QUnit.test("test: Workstation", function (assert) {
|
||||
let done = assert.async();
|
||||
|
||||
// number of asserts
|
||||
assert.expect(1);
|
||||
|
||||
frappe.run_serially('Workstation', [
|
||||
// insert a new Workstation
|
||||
() => frappe.tests.make([
|
||||
// values to be set
|
||||
{key: 'value'}
|
||||
]),
|
||||
() => {
|
||||
assert.equal(cur_frm.doc.key, 'value');
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
|
||||
});
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:workstation_name",
|
||||
@@ -12,11 +13,12 @@
|
||||
"editable_grid": 0,
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"collapsible": 1,
|
||||
"columns": 0,
|
||||
"fieldname": "description_and_warehouse",
|
||||
"fieldname": "description_section",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
@@ -25,7 +27,7 @@
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "",
|
||||
"label": "Description",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
@@ -41,6 +43,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -71,6 +74,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -102,65 +106,7 @@
|
||||
"width": "300px"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "",
|
||||
"fieldname": "holiday_list",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Holiday List",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Holiday List",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -190,6 +136,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -221,6 +168,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -252,6 +200,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -280,6 +229,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -311,6 +261,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -342,6 +293,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -373,6 +325,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -402,6 +355,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -430,20 +384,52 @@
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "",
|
||||
"fieldname": "holiday_list",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Holiday List",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Holiday List",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"icon": "icon-wrench",
|
||||
"idx": 1,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"in_dialog": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-02-17 17:26:57.238167",
|
||||
"modified": "2017-07-18 22:28:50.163219",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Workstation",
|
||||
@@ -470,11 +456,11 @@
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_order": "ASC",
|
||||
"track_changes": 0,
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
/* eslint-disable */
|
||||
frappe.listview_settings['Workstation'] = {
|
||||
// add_fields: ["status"],
|
||||
// filters:[["status","=", "Open"]]
|
||||
};
|
||||
@@ -416,4 +416,11 @@ erpnext.patches.v8_0.update_production_orders
|
||||
erpnext.patches.v8_1.remove_sales_invoice_from_returned_serial_no
|
||||
erpnext.patches.v8_1.allow_invoice_copy_to_edit_after_submit
|
||||
erpnext.patches.v8_1.add_hsn_sac_codes
|
||||
erpnext.patches.v8_1.update_gst_state
|
||||
erpnext.patches.v8_1.update_gst_state #17-07-2017
|
||||
erpnext.patches.v8_1.removed_report_support_hours
|
||||
erpnext.patches.v8_1.add_indexes_in_transaction_doctypes
|
||||
erpnext.patches.v8_3.set_restrict_to_domain_for_module_def
|
||||
erpnext.patches.v8_1.update_expense_claim_status
|
||||
erpnext.patches.v8_3.update_company_total_sales
|
||||
erpnext.patches.v8_1.set_delivery_date_in_so_item
|
||||
erpnext.patches.v8_5.fix_tax_breakup_for_non_invoice_docs
|
||||
@@ -11,6 +11,9 @@ def execute():
|
||||
for dt in ("assessment", "course", "fees"):
|
||||
frappe.reload_doc("schools", "doctype", dt)
|
||||
|
||||
for dt in ("domain", "has_domain", "domain_settings"):
|
||||
frappe.reload_doc("core", "doctype", dt)
|
||||
|
||||
frappe.reload_doc('website', 'doctype', 'portal_menu_item')
|
||||
|
||||
frappe.get_doc('Portal Settings').sync_menu()
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
for dt in ("Sales Order Item", "Purchase Order Item",
|
||||
"Material Request Item", "Production Order Item", "Packed Item"):
|
||||
frappe.get_doc("DocType", dt).run_module_method("on_doctype_update")
|
||||
14
erpnext/patches/v8_1/removed_report_support_hours.py
Normal file
@@ -0,0 +1,14 @@
|
||||
# Copyright (c) 2017, Frappe and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
frappe.db.sql(""" update `tabAuto Email Report` set report = %s
|
||||
where name = %s""", ('Support Hour Distribution', 'Support Hours'))
|
||||
|
||||
frappe.db.sql(""" update `tabCustom Role` set report = %s
|
||||
where report = %s""", ('Support Hour Distribution', 'Support Hours'))
|
||||
|
||||
frappe.delete_doc('Report', 'Support Hours')
|
||||
13
erpnext/patches/v8_1/set_delivery_date_in_so_item.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
frappe.reload_doctype("Sales Order")
|
||||
frappe.reload_doctype("Sales Order Item")
|
||||
|
||||
frappe.db.sql("""update `tabSales Order` set final_delivery_date = delivery_date where docstatus=1""")
|
||||
|
||||
frappe.db.sql("""
|
||||
update `tabSales Order` so, `tabSales Order Item` so_item
|
||||
set so_item.delivery_date = so.delivery_date
|
||||
where so.name = so_item.parent
|
||||
""")
|
||||
23
erpnext/patches/v8_1/update_expense_claim_status.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# Copyright (c) 2017, Frappe and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
frappe.reload_doctype('Expense Claim')
|
||||
|
||||
for data in frappe.db.sql(""" select name from `tabExpense Claim`
|
||||
where (docstatus=1 and total_sanctioned_amount=0 and status = 'Paid') or
|
||||
(docstatus = 1 and approval_status = 'Rejected' and total_sanctioned_amount > 0)""", as_dict=1):
|
||||
doc = frappe.get_doc('Expense Claim', data.name)
|
||||
if doc.approval_status == 'Rejected':
|
||||
for d in doc.expenses:
|
||||
d.db_set("sanctioned_amount", 0, update_modified = False)
|
||||
doc.db_set("total_sanctioned_amount", 0, update_modified = False)
|
||||
|
||||
frappe.db.sql(""" delete from `tabGL Entry` where voucher_type = 'Expense Claim'
|
||||
and voucher_no = %s""", (doc.name))
|
||||
|
||||
doc.set_status()
|
||||
doc.db_set("status", doc.status, update_modified = False)
|
||||
@@ -11,3 +11,4 @@ def execute():
|
||||
|
||||
frappe.db.sql("update `tabCustom Field` set options=%s where fieldname='gst_state'", '\n'.join(states))
|
||||
frappe.db.sql("update `tabAddress` set gst_state='Chhattisgarh' where gst_state='Chattisgarh'")
|
||||
frappe.db.sql("update `tabAddress` set gst_state_number='05' where gst_state='Uttarakhand'")
|
||||
|
||||
0
erpnext/patches/v8_3/__init__.py
Normal file
@@ -0,0 +1,14 @@
|
||||
# Copyright (c) 2017, Frappe and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
from erpnext.setup.setup_wizard.domainify import update_module_def_restrict_to_domain
|
||||
|
||||
def execute():
|
||||
""" set the restrict to domain in module def """
|
||||
|
||||
frappe.reload_doc("core", "doctype", "module_def")
|
||||
if frappe.db.get_single_value('System Settings', 'setup_complete'):
|
||||
update_module_def_restrict_to_domain()
|
||||
15
erpnext/patches/v8_3/update_company_total_sales.py
Normal file
@@ -0,0 +1,15 @@
|
||||
# Copyright (c) 2017, Frappe and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from erpnext.setup.doctype.company.company import update_company_current_month_sales, update_company_monthly_sales
|
||||
|
||||
def execute():
|
||||
'''Update company monthly sales history based on sales invoices'''
|
||||
frappe.reload_doctype("Company")
|
||||
companies = [d['name'] for d in frappe.get_list("Company")]
|
||||
|
||||
for company in companies:
|
||||
update_company_current_month_sales(company)
|
||||
update_company_monthly_sales(company)
|
||||
0
erpnext/patches/v8_5/__init__.py
Normal file
47
erpnext/patches/v8_5/fix_tax_breakup_for_non_invoice_docs.py
Normal file
@@ -0,0 +1,47 @@
|
||||
import frappe
|
||||
from erpnext.regional.india.setup import make_custom_fields
|
||||
from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_html
|
||||
|
||||
def execute():
|
||||
companies = [d.name for d in frappe.get_all('Company', filters = {'country': 'India'})]
|
||||
if not companies:
|
||||
return
|
||||
|
||||
make_custom_fields()
|
||||
|
||||
# update invoice copy value
|
||||
values = ["Original for Recipient", "Duplicate for Transporter",
|
||||
"Duplicate for Supplier", "Triplicate for Supplier"]
|
||||
for d in values:
|
||||
frappe.db.sql("update `tabSales Invoice` set invoice_copy=%s where invoice_copy=%s", (d, d))
|
||||
|
||||
# update tax breakup in transactions made after 1st July 2017
|
||||
doctypes = ["Quotation", "Sales Order", "Delivery Note", "Sales Invoice",
|
||||
"Supplier Quotation", "Purchase Order", "Purchase Receipt", "Purchase Invoice"]
|
||||
|
||||
for doctype in doctypes:
|
||||
frappe.reload_doctype(doctype)
|
||||
|
||||
date_field = "posting_date"
|
||||
if doctype in ["Quotation", "Sales Order", "Supplier Quotation", "Purchase Order"]:
|
||||
date_field = "transaction_date"
|
||||
|
||||
records = [d.name for d in frappe.get_all(doctype, filters={
|
||||
"docstatus": ["!=", 2],
|
||||
date_field: [">=", "2017-07-01"],
|
||||
"company": ["in", companies],
|
||||
"total_taxes_and_charges": [">", 0],
|
||||
"other_charges_calculation": ""
|
||||
})]
|
||||
if records:
|
||||
frappe.db.sql("""
|
||||
update `tab%s Item` dt_item
|
||||
set gst_hsn_code = (select gst_hsn_code from tabItem where name=dt_item.item_code)
|
||||
where parent in (%s)
|
||||
and (gst_hsn_code is null or gst_hsn_code = '')
|
||||
""" % (doctype, ', '.join(['%s']*len(records))), tuple(records))
|
||||
|
||||
for record in records:
|
||||
doc = frappe.get_doc(doctype, record)
|
||||
html = get_itemised_tax_breakup_html(doc)
|
||||
doc.db_set("other_charges_calculation", html, update_modified=False)
|
||||
@@ -3,6 +3,22 @@
|
||||
|
||||
frappe.ui.form.on("Project", {
|
||||
onload: function(frm) {
|
||||
frm.set_indicator_formatter('title',
|
||||
function(doc) {
|
||||
let indicator = 'orange';
|
||||
if (doc.status == 'Overdue') {
|
||||
indicator = 'red';
|
||||
}
|
||||
else if (doc.status == 'Cancelled') {
|
||||
indicator = 'dark grey';
|
||||
}
|
||||
else if (doc.status == 'Closed') {
|
||||
indicator = 'green';
|
||||
}
|
||||
return indicator;
|
||||
}
|
||||
);
|
||||
|
||||
var so = frappe.meta.get_docfield("Project", "sales_order");
|
||||
so.get_route_options_for_new_doc = function(field) {
|
||||
if(frm.is_new()) return;
|
||||
@@ -35,6 +51,7 @@ frappe.ui.form.on("Project", {
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
refresh: function(frm) {
|
||||
if(frm.doc.__islocal) {
|
||||
frm.web_link && frm.web_link.remove();
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -44,6 +45,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -76,6 +78,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -107,6 +110,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -138,6 +142,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -169,6 +174,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -197,6 +203,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -228,6 +235,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -258,6 +266,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 1,
|
||||
"collapsible": 0,
|
||||
@@ -269,7 +278,7 @@
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Expected End Date",
|
||||
"length": 0,
|
||||
@@ -288,6 +297,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 1,
|
||||
"collapsible": 0,
|
||||
@@ -316,6 +326,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
@@ -346,6 +357,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -377,6 +389,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -405,6 +418,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -435,6 +449,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
@@ -464,6 +479,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -495,6 +511,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -525,6 +542,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -555,6 +573,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -584,6 +603,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
@@ -614,6 +634,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -644,6 +665,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
@@ -673,6 +695,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -702,6 +725,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -731,6 +755,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -759,6 +784,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -789,6 +815,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
@@ -819,6 +846,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -850,6 +878,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -880,6 +909,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -910,6 +940,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -939,6 +970,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -968,6 +1000,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -996,6 +1029,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1026,6 +1060,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1055,6 +1090,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1084,6 +1120,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
@@ -1114,6 +1151,7 @@
|
||||
"width": "50%"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1145,6 +1183,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1173,6 +1212,7 @@
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
@@ -1215,8 +1255,8 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 4,
|
||||
"modified": "2017-04-19 13:16:32.462005",
|
||||
"modified_by": "faris@erpnext.com",
|
||||
"modified": "2017-07-19 14:36:20.857673",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Projects",
|
||||
"name": "Project",
|
||||
"owner": "Administrator",
|
||||
|
||||
24
erpnext/projects/doctype/task/test_task.js
Normal file
@@ -0,0 +1,24 @@
|
||||
/* eslint-disable */
|
||||
// rename this file from _test_[name] to test_[name] to activate
|
||||
// and remove above this line
|
||||
|
||||
QUnit.test("test: Task", function (assert) {
|
||||
let done = assert.async();
|
||||
|
||||
// number of asserts
|
||||
assert.expect(2);
|
||||
|
||||
frappe.run_serially([
|
||||
// insert a new Task
|
||||
() => frappe.tests.make('Task', [
|
||||
// values to be set
|
||||
{subject: 'new task'}
|
||||
]),
|
||||
() => {
|
||||
assert.equal(cur_frm.doc.status, 'Open');
|
||||
assert.equal(cur_frm.doc.priority, 'Low');
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
|
||||
});
|
||||
@@ -133,10 +133,15 @@ var calculate_end_time = function(frm, cdt, cdn) {
|
||||
var child = locals[cdt][cdn];
|
||||
|
||||
var d = moment(child.from_time);
|
||||
d.add(child.hours, "hours");
|
||||
frm._setting_hours = true;
|
||||
frappe.model.set_value(cdt, cdn, "to_time", d.format(moment.defaultDatetimeFormat));
|
||||
frm._setting_hours = false;
|
||||
if(child.hours) {
|
||||
d.add(child.hours, "hours");
|
||||
frm._setting_hours = true;
|
||||
frappe.model.set_value(cdt, cdn, "to_time",
|
||||
d.format(moment.defaultDatetimeFormat)).then(() => {
|
||||
frm._setting_hours = false;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if((frm.doc.__islocal || frm.doc.__onload.maintain_bill_work_hours_same) && child.hours){
|
||||
frappe.model.set_value(cdt, cdn, "billing_hours", child.hours);
|
||||
|
||||
@@ -9,9 +9,8 @@ from frappe import _
|
||||
import json
|
||||
from datetime import timedelta
|
||||
from erpnext.controllers.queries import get_match_cond
|
||||
from frappe.utils import flt, time_diff_in_hours, get_datetime, getdate, cint, get_datetime_str
|
||||
from frappe.utils import flt, time_diff_in_hours, get_datetime, getdate, cint
|
||||
from frappe.model.document import Document
|
||||
from frappe.model.mapper import get_mapped_doc
|
||||
from erpnext.manufacturing.doctype.workstation.workstation import (check_if_within_operating_hours,
|
||||
WorkstationHolidayError)
|
||||
from erpnext.manufacturing.doctype.manufacturing_settings.manufacturing_settings import get_mins_between_operations
|
||||
@@ -133,7 +132,7 @@ class Timesheet(Document):
|
||||
if data.name == timesheet.operation_id:
|
||||
summary = self.get_actual_timesheet_summary(timesheet.operation_id)
|
||||
data.time_sheet = time_sheet
|
||||
data.completed_qty = summary.completed_qty
|
||||
data.completed_qty = summary.completed_qty
|
||||
data.actual_operation_time = summary.mins
|
||||
data.actual_start_time = summary.from_time
|
||||
data.actual_end_time = summary.to_time
|
||||
@@ -148,7 +147,7 @@ class Timesheet(Document):
|
||||
"""Returns 'Actual Operating Time'. """
|
||||
return frappe.db.sql("""select
|
||||
sum(tsd.hours*60) as mins, sum(tsd.completed_qty) as completed_qty, min(tsd.from_time) as from_time,
|
||||
max(tsd.to_time) as to_time from `tabTimesheet Detail` as tsd, `tabTimesheet` as ts where
|
||||
max(tsd.to_time) as to_time from `tabTimesheet Detail` as tsd, `tabTimesheet` as ts where
|
||||
ts.production_order = %s and tsd.operation_id = %s and ts.docstatus=1 and ts.name = tsd.parent""",
|
||||
(self.production_order, operation_id), as_dict=1)[0]
|
||||
|
||||
@@ -192,7 +191,7 @@ class Timesheet(Document):
|
||||
if fieldname == 'workstation':
|
||||
cond = "tsd.`{0}`".format(fieldname)
|
||||
|
||||
existing = frappe.db.sql("""select ts.name as name, tsd.from_time as from_time, tsd.to_time as to_time from
|
||||
existing = frappe.db.sql("""select ts.name as name, tsd.from_time as from_time, tsd.to_time as to_time from
|
||||
`tabTimesheet Detail` tsd, `tabTimesheet` ts where {0}=%(val)s and tsd.parent = ts.name and
|
||||
(
|
||||
(%(from_time)s > tsd.from_time and %(from_time)s < tsd.to_time) or
|
||||
@@ -211,8 +210,8 @@ class Timesheet(Document):
|
||||
# check internal overlap
|
||||
for time_log in self.time_logs:
|
||||
if (fieldname != 'workstation' or args.get(fieldname) == time_log.get(fieldname)) and \
|
||||
args.idx != time_log.idx and ((args.from_time > time_log.from_time and args.from_time < time_log.to_time) or
|
||||
(args.to_time > time_log.from_time and args.to_time < time_log.to_time) or
|
||||
args.idx != time_log.idx and ((args.from_time > time_log.from_time and args.from_time < time_log.to_time) or
|
||||
(args.to_time > time_log.from_time and args.to_time < time_log.to_time) or
|
||||
(args.from_time <= time_log.from_time and args.to_time >= time_log.to_time)):
|
||||
return self
|
||||
|
||||
@@ -239,7 +238,7 @@ class Timesheet(Document):
|
||||
self.check_workstation_working_day(data)
|
||||
|
||||
def get_last_working_slot(self, time_sheet, workstation):
|
||||
return frappe.db.sql(""" select max(from_time) as from_time, max(to_time) as to_time
|
||||
return frappe.db.sql(""" select max(from_time) as from_time, max(to_time) as to_time
|
||||
from `tabTimesheet Detail` where workstation = %(workstation)s""",
|
||||
{'workstation': workstation}, as_dict=True)[0]
|
||||
|
||||
@@ -277,7 +276,7 @@ def get_projectwise_timesheet_data(project, parent=None):
|
||||
if parent:
|
||||
cond = "and parent = %(parent)s"
|
||||
|
||||
return frappe.db.sql("""select name, parent, billing_hours, billing_amount as billing_amt
|
||||
return frappe.db.sql("""select name, parent, billing_hours, billing_amount as billing_amt
|
||||
from `tabTimesheet Detail` where docstatus=1 and project = %(project)s {0} and billable = 1
|
||||
and sales_invoice is null""".format(cond), {'project': project, 'parent': parent}, as_dict=1)
|
||||
|
||||
@@ -290,9 +289,9 @@ def get_timesheet(doctype, txt, searchfield, start, page_len, filters):
|
||||
condition = "and tsd.project = %(project)s"
|
||||
|
||||
return frappe.db.sql("""select distinct tsd.parent from `tabTimesheet Detail` tsd,
|
||||
`tabTimesheet` ts where
|
||||
ts.status in ('Submitted', 'Payslip') and tsd.parent = ts.name and
|
||||
tsd.docstatus = 1 and ts.total_billable_amount > 0
|
||||
`tabTimesheet` ts where
|
||||
ts.status in ('Submitted', 'Payslip') and tsd.parent = ts.name and
|
||||
tsd.docstatus = 1 and ts.total_billable_amount > 0
|
||||
and tsd.parent LIKE %(txt)s {condition}
|
||||
order by tsd.parent limit %(start)s, %(page_len)s"""
|
||||
.format(condition=condition), {
|
||||
@@ -305,7 +304,7 @@ def get_timesheet_data(name, project):
|
||||
if project and project!='':
|
||||
data = get_projectwise_timesheet_data(project, name)
|
||||
else:
|
||||
data = frappe.get_all('Timesheet',
|
||||
data = frappe.get_all('Timesheet',
|
||||
fields = ["(total_billable_amount - total_billed_amount) as billing_amt", "total_billable_hours as billing_hours"], filters = {'name': name})
|
||||
|
||||
return {
|
||||
@@ -332,7 +331,7 @@ def make_sales_invoice(source_name, target=None):
|
||||
@frappe.whitelist()
|
||||
def make_salary_slip(source_name, target_doc=None):
|
||||
target = frappe.new_doc("Salary Slip")
|
||||
set_missing_values(source_name, target)
|
||||
set_missing_values(source_name, target)
|
||||
target.run_method("get_emp_and_leave_details")
|
||||
|
||||
return target
|
||||
@@ -364,32 +363,21 @@ def get_events(start, end, filters=None):
|
||||
:param filters: Filters (JSON).
|
||||
"""
|
||||
filters = json.loads(filters)
|
||||
from frappe.desk.calendar import get_event_conditions
|
||||
conditions = get_event_conditions("Timesheet", filters)
|
||||
|
||||
conditions = get_conditions(filters)
|
||||
return frappe.db.sql("""select `tabTimesheet Detail`.name as name,
|
||||
return frappe.db.sql("""select `tabTimesheet Detail`.name as name,
|
||||
`tabTimesheet Detail`.docstatus as status, `tabTimesheet Detail`.parent as parent,
|
||||
from_time as start_date, hours, activity_type,
|
||||
`tabTimesheet Detail`.project, to_time as end_date,
|
||||
CONCAT(`tabTimesheet Detail`.parent, ' (', ROUND(hours,2),' hrs)') as title
|
||||
from `tabTimesheet Detail`, `tabTimesheet`
|
||||
where `tabTimesheet Detail`.parent = `tabTimesheet`.name
|
||||
and `tabTimesheet`.docstatus < 2
|
||||
from_time as start_date, hours, activity_type,
|
||||
`tabTimesheet Detail`.project, to_time as end_date,
|
||||
CONCAT(`tabTimesheet Detail`.parent, ' (', ROUND(hours,2),' hrs)') as title
|
||||
from `tabTimesheet Detail`, `tabTimesheet`
|
||||
where `tabTimesheet Detail`.parent = `tabTimesheet`.name
|
||||
and `tabTimesheet`.docstatus < 2
|
||||
and (from_time <= %(end)s and to_time >= %(start)s) {conditions} {match_cond}
|
||||
""".format(conditions=conditions, match_cond = get_match_cond('Timesheet')),
|
||||
""".format(conditions=conditions, match_cond = get_match_cond('Timesheet')),
|
||||
{
|
||||
"start": start,
|
||||
"end": end
|
||||
}, as_dict=True, update={"allDay": 0})
|
||||
|
||||
def get_conditions(filters):
|
||||
conditions = []
|
||||
for key in filters:
|
||||
if filters.get(key):
|
||||
if frappe.get_meta("Timesheet").has_field(key):
|
||||
dt = 'tabTimesheet'
|
||||
elif frappe.get_meta("Timesheet Detail").has_field(key):
|
||||
dt = 'tabTimesheet Detail'
|
||||
|
||||
conditions.append("`%s`.%s = '%s'"%(dt, key, filters.get(key)))
|
||||
|
||||
return " and {}".format(" and ".join(conditions)) if conditions else ""
|
||||
|
||||
@@ -228,6 +228,8 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
||||
items: my_items
|
||||
},
|
||||
callback: function(r) {
|
||||
if(r.exc) return;
|
||||
|
||||
var i = 0;
|
||||
var item_length = cur_frm.doc.items.length;
|
||||
while (i < item_length) {
|
||||
@@ -244,35 +246,26 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
||||
cur_frm.doc.items[i].qty = my_qty;
|
||||
|
||||
frappe.msgprint("Assigning " + d.mr_name + " to " + d.item_code + " (row " + cur_frm.doc.items[i].idx + ")");
|
||||
if (qty > 0)
|
||||
{
|
||||
if (qty > 0) {
|
||||
frappe.msgprint("Splitting " + qty + " units of " + d.item_code);
|
||||
var newrow = frappe.model.add_child(cur_frm.doc, cur_frm.doc.items[i].doctype, "items");
|
||||
item_length++;
|
||||
|
||||
for (var key in cur_frm.doc.items[i])
|
||||
{
|
||||
for (var key in cur_frm.doc.items[i]) {
|
||||
newrow[key] = cur_frm.doc.items[i][key];
|
||||
}
|
||||
|
||||
newrow.idx = item_length;
|
||||
newrow["stock_qty"] = newrow.conversion_factor*qty;
|
||||
newrow["qty"] = qty;
|
||||
|
||||
newrow["material_request"] = "";
|
||||
newrow["material_request_item"] = "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
i++;
|
||||
}
|
||||
refresh_field("items");
|
||||
//cur_frm.save();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -40,8 +40,10 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
|
||||
},
|
||||
|
||||
calculate_discount_amount: function(){
|
||||
if (frappe.meta.get_docfield(this.frm.doc.doctype, "discount_amount"))
|
||||
if (frappe.meta.get_docfield(this.frm.doc.doctype, "discount_amount")) {
|
||||
this.set_discount_amount();
|
||||
this.apply_discount_amount();
|
||||
}
|
||||
},
|
||||
|
||||
_calculate_taxes_and_totals: function() {
|
||||
@@ -54,7 +56,6 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
|
||||
this.manipulate_grand_total_for_inclusive_tax();
|
||||
this.calculate_totals();
|
||||
this._cleanup();
|
||||
this.show_item_wise_taxes();
|
||||
},
|
||||
|
||||
validate_conversion_rate: function() {
|
||||
@@ -452,6 +453,13 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
|
||||
}
|
||||
},
|
||||
|
||||
set_discount_amount: function() {
|
||||
if(this.frm.doc.additional_discount_percentage) {
|
||||
this.frm.doc.discount_amount = flt(flt(this.frm.doc[frappe.scrub(this.frm.doc.apply_discount_on)])
|
||||
* this.frm.doc.additional_discount_percentage / 100, precision("discount_amount"));
|
||||
}
|
||||
},
|
||||
|
||||
apply_discount_amount: function() {
|
||||
var me = this;
|
||||
var distributed_amount = 0.0;
|
||||
@@ -634,99 +642,5 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
|
||||
}
|
||||
|
||||
this.calculate_outstanding_amount(false)
|
||||
},
|
||||
|
||||
show_item_wise_taxes: function() {
|
||||
if(this.frm.fields_dict.other_charges_calculation) {
|
||||
this.frm.toggle_display("other_charges_calculation", this.frm.doc.other_charges_calculation);
|
||||
}
|
||||
},
|
||||
|
||||
set_item_wise_tax_breakup: function() {
|
||||
if(this.frm.fields_dict.other_charges_calculation) {
|
||||
var html = this.get_item_wise_taxes_html();
|
||||
// console.log(html);
|
||||
this.frm.set_value("other_charges_calculation", html);
|
||||
this.show_item_wise_taxes();
|
||||
}
|
||||
},
|
||||
|
||||
get_item_wise_taxes_html: function() {
|
||||
var item_tax = {};
|
||||
var tax_accounts = [];
|
||||
var company_currency = this.get_company_currency();
|
||||
|
||||
$.each(this.frm.doc["taxes"] || [], function(i, tax) {
|
||||
var tax_amount_precision = precision("tax_amount", tax);
|
||||
var tax_rate_precision = precision("rate", tax);
|
||||
$.each(JSON.parse(tax.item_wise_tax_detail || '{}'),
|
||||
function(item_code, tax_data) {
|
||||
if(!item_tax[item_code]) item_tax[item_code] = {};
|
||||
if($.isArray(tax_data)) {
|
||||
var tax_rate = "";
|
||||
if(tax_data[0] != null) {
|
||||
tax_rate = (tax.charge_type === "Actual") ?
|
||||
format_currency(flt(tax_data[0], tax_amount_precision),
|
||||
company_currency, tax_amount_precision) :
|
||||
(flt(tax_data[0], tax_rate_precision) + "%");
|
||||
}
|
||||
var tax_amount = format_currency(flt(tax_data[1], tax_amount_precision),
|
||||
company_currency, tax_amount_precision);
|
||||
|
||||
item_tax[item_code][tax.name] = [tax_rate, tax_amount];
|
||||
} else {
|
||||
item_tax[item_code][tax.name] = [flt(tax_data, tax_rate_precision) + "%", "0.00"];
|
||||
}
|
||||
});
|
||||
tax_accounts.push([tax.name, tax.account_head]);
|
||||
});
|
||||
|
||||
var headings = $.map([__("Item Name"), __("Taxable Amount")].concat($.map(tax_accounts,
|
||||
function(head) { return head[1]; })), function(head) {
|
||||
if(head==__("Item Name")) {
|
||||
return '<th style="min-width: 100px;" class="text-left">' + (head || "") + "</th>";
|
||||
} else {
|
||||
return '<th style="min-width: 80px;" class="text-right">' + (head || "") + "</th>";
|
||||
}
|
||||
}
|
||||
).join("");
|
||||
|
||||
var distinct_item_names = [];
|
||||
var distinct_items = [];
|
||||
var taxable_amount = {};
|
||||
$.each(this.frm.doc["items"] || [], function(i, item) {
|
||||
var item_code = item.item_code || item.item_name;
|
||||
if(distinct_item_names.indexOf(item_code)===-1) {
|
||||
distinct_item_names.push(item_code);
|
||||
distinct_items.push(item);
|
||||
taxable_amount[item_code] = item.net_amount;
|
||||
} else {
|
||||
taxable_amount[item_code] = taxable_amount[item_code] + item.net_amount;
|
||||
}
|
||||
});
|
||||
|
||||
var rows = $.map(distinct_items, function(item) {
|
||||
var item_code = item.item_code || item.item_name;
|
||||
var item_tax_record = item_tax[item_code];
|
||||
if(!item_tax_record) { return null; }
|
||||
|
||||
return repl("<tr><td>%(item_name)s</td><td class='text-right'>%(taxable_amount)s</td>%(taxes)s</tr>", {
|
||||
item_name: item.item_name,
|
||||
taxable_amount: format_currency(taxable_amount[item_code],
|
||||
company_currency, precision("net_amount", item)),
|
||||
taxes: $.map(tax_accounts, function(head) {
|
||||
return item_tax_record[head[0]] ?
|
||||
"<td class='text-right'>(" + item_tax_record[head[0]][0] + ") " + item_tax_record[head[0]][1] + "</td>" :
|
||||
"<td></td>";
|
||||
}).join("")
|
||||
});
|
||||
}).join("");
|
||||
|
||||
if(!rows) return "";
|
||||
return '<div class="tax-break-up" style="overflow-x: auto;">\
|
||||
<table class="table table-bordered table-hover">\
|
||||
<thead><tr>' + headings + '</tr></thead> \
|
||||
<tbody>' + rows + '</tbody> \
|
||||
</table></div>';
|
||||
}
|
||||
})
|
||||
|
||||
@@ -210,7 +210,6 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
refresh: function() {
|
||||
erpnext.toggle_naming_series();
|
||||
erpnext.hide_company();
|
||||
this.show_item_wise_taxes();
|
||||
this.set_dynamic_labels();
|
||||
this.setup_sms();
|
||||
},
|
||||
@@ -367,7 +366,6 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
|
||||
validate: function() {
|
||||
this.calculate_taxes_and_totals(false);
|
||||
this.set_item_wise_tax_breakup();
|
||||
},
|
||||
|
||||
company: function() {
|
||||
|
||||
@@ -104,7 +104,7 @@ var erpnext_slides = [
|
||||
options: "", fieldtype: 'Select'
|
||||
},
|
||||
|
||||
{ fieldtype: "Section Break", label: "Financial Year" },
|
||||
{ fieldtype: "Section Break", label: __('Financial Year') },
|
||||
{ fieldname: 'fy_start_date', label: __('Start Date'), fieldtype: 'Date', reqd: 1 },
|
||||
{ fieldtype: "Column Break" },
|
||||
{ fieldname: 'fy_end_date', label: __('End Date'), fieldtype: 'Date', reqd: 1 },
|
||||
@@ -216,6 +216,17 @@ var erpnext_slides = [
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
// Sales Target
|
||||
name: 'Goals',
|
||||
domains: ['manufacturing', 'services', 'retail', 'distribution'],
|
||||
title: __("Set your Target"),
|
||||
help: __("Set a sales target you'd like to achieve."),
|
||||
fields: [
|
||||
{fieldtype:"Currency", fieldname:"sales_target", label:__("Monthly Sales Target")},
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
// Taxes
|
||||
name: 'taxes',
|
||||
@@ -225,7 +236,7 @@ var erpnext_slides = [
|
||||
help: __("List your tax heads (e.g. VAT, Customs etc; they should have unique names) and their standard rates. This will create a standard template, which you can edit and add more later."),
|
||||
add_more: 1,
|
||||
max_count: 3,
|
||||
mandatory_entry: 1,
|
||||
mandatory_entry: 0,
|
||||
fields: [
|
||||
{fieldtype:"Section Break"},
|
||||
{fieldtype:"Data", fieldname:"tax", label:__("Tax"),
|
||||
@@ -297,8 +308,10 @@ var erpnext_slides = [
|
||||
options:[__("Unit"), __("Nos"), __("Box"), __("Pair"), __("Kg"), __("Set"),
|
||||
__("Hour"), __("Minute"), __("Litre"), __("Meter"), __("Gram")],
|
||||
"default": __("Unit"), static: 1},
|
||||
{fieldtype: "Check", fieldname: "is_sales_item", label:__("We sell this Item"), default: 1, static: 1},
|
||||
{fieldtype: "Check", fieldname: "is_purchase_item", label:__("We buy this Item"), static: 1},
|
||||
{fieldtype: "Check", fieldname: "is_sales_item",
|
||||
label:__("We sell this Item"), default: 1, static: 1},
|
||||
{fieldtype: "Check", fieldname: "is_purchase_item",
|
||||
label:__("We buy this Item"), default: 1, static: 1},
|
||||
{fieldtype:"Column Break"},
|
||||
{fieldtype:"Currency", fieldname:"item_price", label:__("Rate"), static: 1},
|
||||
{fieldtype:"Attach Image", fieldname:"item_img", label:__("Attach Image"), is_private: 0, static: 1},
|
||||
|
||||
@@ -42,11 +42,15 @@ erpnext.utils.get_party_details = function(frm, method, args, callback) {
|
||||
callback: function(r) {
|
||||
if(r.message) {
|
||||
frm.updating_party_details = true;
|
||||
frm.set_value(r.message);
|
||||
frm.updating_party_details = false;
|
||||
if(callback) callback();
|
||||
frm.refresh();
|
||||
erpnext.utils.add_item(frm);
|
||||
frappe.run_serially([
|
||||
() => frm.set_value(r.message),
|
||||
() => {
|
||||
frm.updating_party_details = false;
|
||||
if(callback) callback();
|
||||
frm.refresh();
|
||||
erpnext.utils.add_item(frm);
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -66,7 +66,7 @@ erpnext.SerialNoBatchSelector = Class.extend({
|
||||
fieldtype:'Float',
|
||||
read_only: 1,
|
||||
label: __(me.has_batch ? 'Total Qty' : 'Qty'),
|
||||
default: me.qty
|
||||
default: 0
|
||||
},
|
||||
];
|
||||
|
||||
@@ -155,14 +155,10 @@ erpnext.SerialNoBatchSelector = Class.extend({
|
||||
},
|
||||
|
||||
bind_qty: function() {
|
||||
let serial_no_link = this.dialog.fields_dict.serial_no_select;
|
||||
let serial_no_list_field = this.dialog.fields_dict.serial_no;
|
||||
let batches_field = this.dialog.fields_dict.batches;
|
||||
|
||||
let qty_field = this.dialog.fields_dict.qty;
|
||||
|
||||
let update_quantity = (batch) => {
|
||||
if(batch) {
|
||||
if(batches_field) {
|
||||
batches_field.grid.wrapper.on('change', function() {
|
||||
let total_qty = 0;
|
||||
batches_field.grid.wrapper.find(
|
||||
'input[data-fieldname="selected_qty"]').each(function() {
|
||||
@@ -170,48 +166,6 @@ erpnext.SerialNoBatchSelector = Class.extend({
|
||||
total_qty += Number($(this).val());
|
||||
});
|
||||
qty_field.set_input(total_qty);
|
||||
} else {
|
||||
let serial_numbers = serial_no_list_field.get_value()
|
||||
.replace(/\n/g, ' ').match(/\S+/g) || [];
|
||||
qty_field.set_input(serial_numbers.length);
|
||||
}
|
||||
};
|
||||
|
||||
if(serial_no_link) {
|
||||
let serial_list = [];
|
||||
serial_no_link.$input.on('awesomplete-selectcomplete', function() {
|
||||
if(serial_no_link.get_value().length > 0) {
|
||||
let new_no = serial_no_link.get_value();
|
||||
let list_value = serial_no_list_field.get_value();
|
||||
let new_line = '\n';
|
||||
if(!serial_no_list_field.get_value()) {
|
||||
new_line = '';
|
||||
} else {
|
||||
serial_list = list_value.replace(/\s+/g, ' ').split(' ');
|
||||
}
|
||||
if(!serial_list.includes(new_no)) {
|
||||
serial_no_link.set_new_description('');
|
||||
serial_no_list_field.set_value(list_value + new_line + new_no);
|
||||
update_quantity(0);
|
||||
} else {
|
||||
serial_no_link.set_new_description(new_no + ' is already selected.');
|
||||
}
|
||||
}
|
||||
|
||||
// Should, but doesn't work
|
||||
serial_no_link.set_input('');
|
||||
serial_no_link.$input.blur();
|
||||
});
|
||||
|
||||
serial_no_list_field.$input.on('input', function() {
|
||||
serial_list = serial_no_list_field.get_value().replace(/\s+/g, ' ').split(' ');
|
||||
update_quantity(0);
|
||||
});
|
||||
}
|
||||
|
||||
if(batches_field) {
|
||||
batches_field.grid.wrapper.on('change', function() {
|
||||
update_quantity(1);
|
||||
});
|
||||
}
|
||||
},
|
||||
@@ -319,6 +273,7 @@ erpnext.SerialNoBatchSelector = Class.extend({
|
||||
|
||||
get_serial_no_fields: function() {
|
||||
var me = this;
|
||||
this.serial_list = [];
|
||||
return [
|
||||
{fieldtype: 'Section Break', label: __('Serial No')},
|
||||
{
|
||||
@@ -326,10 +281,46 @@ erpnext.SerialNoBatchSelector = Class.extend({
|
||||
label: __('Select'),
|
||||
get_query: function() {
|
||||
return { filters: {item_code: me.item_code}};
|
||||
},
|
||||
onchange: function(e) {
|
||||
if(this.in_local_change) return;
|
||||
this.in_local_change = 1;
|
||||
|
||||
let serial_no_list_field = this.layout.fields_dict.serial_no;
|
||||
let qty_field = this.layout.fields_dict.qty;
|
||||
|
||||
let new_number = this.get_value();
|
||||
let list_value = serial_no_list_field.get_value();
|
||||
let new_line = '\n';
|
||||
if(!list_value) {
|
||||
new_line = '';
|
||||
} else {
|
||||
me.serial_list = list_value.replace(/\n/g, ' ').match(/\S+/g) || [];
|
||||
}
|
||||
|
||||
if(!me.serial_list.includes(new_number)) {
|
||||
this.set_new_description('');
|
||||
serial_no_list_field.set_value(me.serial_list.join('\n') + new_line + new_number);
|
||||
me.serial_list = serial_no_list_field.get_value().replace(/\n/g, ' ').match(/\S+/g) || [];
|
||||
} else {
|
||||
this.set_new_description(new_number + ' is already selected.');
|
||||
}
|
||||
|
||||
qty_field.set_input(me.serial_list.length);
|
||||
this.$input.val("");
|
||||
this.in_local_change = 0;
|
||||
}
|
||||
},
|
||||
{fieldtype: 'Column Break'},
|
||||
{fieldname: 'serial_no', fieldtype: 'Small Text'}
|
||||
{
|
||||
fieldname: 'serial_no',
|
||||
fieldtype: 'Small Text',
|
||||
onchange: function() {
|
||||
me.serial_list = this.get_value()
|
||||
.replace(/\n/g, ' ').match(/\S+/g) || [];
|
||||
this.layout.fields_dict.qty.set_input(me.serial_list.length);
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
});
|
||||
@@ -10,7 +10,7 @@
|
||||
"state_name": "Uttar Pradesh"
|
||||
},
|
||||
{
|
||||
"state_number": "36",
|
||||
"state_number": "05",
|
||||
"state_code": "UT",
|
||||
"state_name": "Uttarakhand"
|
||||
},
|
||||
|
||||
@@ -80,7 +80,7 @@ def add_print_formats():
|
||||
|
||||
def make_custom_fields():
|
||||
hsn_sac_field = dict(fieldname='gst_hsn_code', label='HSN/SAC',
|
||||
fieldtype='Data', options='item_code.gst_hsn_code', insert_after='description')
|
||||
fieldtype='Data', options='item_code.gst_hsn_code', insert_after='description', print_hide=1)
|
||||
|
||||
custom_fields = {
|
||||
'Address': [
|
||||
@@ -107,13 +107,15 @@ def make_custom_fields():
|
||||
fieldtype='Data', insert_after='company_address',
|
||||
options='company_address.gstin', print_hide=1),
|
||||
dict(fieldname='invoice_copy', label='Invoice Copy',
|
||||
fieldtype='Select', insert_after='project', print_hide=1, allow_on_submit=1,
|
||||
options='ORIGINAL FOR RECIPIENT\nDUPLICATE FOR TRANSPORTER\nDUPLICATE FOR SUPPLIER\nTRIPLICATE FOR SUPPLIER')
|
||||
fieldtype='Select', insert_after='select_print_heading', print_hide=1, allow_on_submit=1,
|
||||
options='Original for Recipient\nDuplicate for Transporter\nDuplicate for Supplier\nTriplicate for Supplier')
|
||||
],
|
||||
'Item': [
|
||||
dict(fieldname='gst_hsn_code', label='HSN/SAC',
|
||||
fieldtype='Link', options='GST HSN Code', insert_after='item_group'),
|
||||
],
|
||||
'Quotation Item': [hsn_sac_field],
|
||||
'Supplier Quotation Item': [hsn_sac_field],
|
||||
'Sales Order Item': [hsn_sac_field],
|
||||
'Delivery Note Item': [hsn_sac_field],
|
||||
'Sales Invoice Item': [hsn_sac_field],
|
||||
@@ -131,7 +133,7 @@ def make_custom_fields():
|
||||
custom_field = frappe.get_doc("Custom Field", field)
|
||||
custom_field.update(df)
|
||||
custom_field.save()
|
||||
|
||||
|
||||
def make_fixtures():
|
||||
docs = [
|
||||
{'doctype': 'Salary Component', 'salary_component': 'Professional Tax', 'description': 'Professional Tax', 'type': 'Deduction'},
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import frappe, re
|
||||
from frappe import _
|
||||
from erpnext.regional.india import states, state_numbers
|
||||
from erpnext.controllers.taxes_and_totals import get_itemised_tax, get_itemised_taxable_amount
|
||||
|
||||
def validate_gstin_for_india(doc, method):
|
||||
if not hasattr(doc, 'gstin'):
|
||||
@@ -22,3 +23,44 @@ def validate_gstin_for_india(doc, method):
|
||||
if doc.gstin != "NA" and doc.gst_state_number != doc.gstin[:2]:
|
||||
frappe.throw(_("First 2 digits of GSTIN should match with State number {0}")
|
||||
.format(doc.gst_state_number))
|
||||
|
||||
def get_itemised_tax_breakup_header(item_doctype, tax_accounts):
|
||||
if frappe.get_meta(item_doctype).has_field('gst_hsn_code'):
|
||||
return [_("HSN/SAC"), _("Taxable Amount")] + tax_accounts
|
||||
else:
|
||||
return [_("Item"), _("Taxable Amount")] + tax_accounts
|
||||
|
||||
def get_itemised_tax_breakup_data(doc):
|
||||
itemised_tax = get_itemised_tax(doc.taxes)
|
||||
|
||||
itemised_taxable_amount = get_itemised_taxable_amount(doc.items)
|
||||
|
||||
if not frappe.get_meta(doc.doctype + " Item").has_field('gst_hsn_code'):
|
||||
return itemised_tax, itemised_taxable_amount
|
||||
|
||||
item_hsn_map = frappe._dict()
|
||||
for d in doc.items:
|
||||
item_hsn_map.setdefault(d.item_code or d.item_name, d.get("gst_hsn_code"))
|
||||
|
||||
hsn_tax = {}
|
||||
for item, taxes in itemised_tax.items():
|
||||
hsn_code = item_hsn_map.get(item)
|
||||
hsn_tax.setdefault(hsn_code, frappe._dict())
|
||||
for tax_account, tax_detail in taxes.items():
|
||||
hsn_tax[hsn_code].setdefault(tax_account, {"tax_rate": 0, "tax_amount": 0})
|
||||
hsn_tax[hsn_code][tax_account]["tax_rate"] = tax_detail.get("tax_rate")
|
||||
hsn_tax[hsn_code][tax_account]["tax_amount"] += tax_detail.get("tax_amount")
|
||||
|
||||
# set taxable amount
|
||||
hsn_taxable_amount = frappe._dict()
|
||||
for item, taxable_amount in itemised_taxable_amount.items():
|
||||
hsn_code = item_hsn_map.get(item)
|
||||
hsn_taxable_amount.setdefault(hsn_code, 0)
|
||||
hsn_taxable_amount[hsn_code] += itemised_taxable_amount.get(item)
|
||||
|
||||
return hsn_tax, hsn_taxable_amount
|
||||
|
||||
# don't remove this function it is used in tests
|
||||
def test_method():
|
||||
'''test function'''
|
||||
return 'overridden'
|
||||
@@ -25,7 +25,7 @@
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Academic Year",
|
||||
"length": 0,
|
||||
@@ -148,7 +148,7 @@
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Program",
|
||||
"length": 0,
|
||||
@@ -269,7 +269,7 @@
|
||||
"issingle": 1,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-05-15 12:43:32.317942",
|
||||
"modified": "2017-07-17 21:57:35.602091",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Schools",
|
||||
"name": "Student Group Creation Tool",
|
||||
@@ -300,6 +300,7 @@
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"restrict_to_domain": "Education",
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
|
||||
@@ -1,346 +1,357 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "SLA.######",
|
||||
"beta": 0,
|
||||
"creation": "2016-11-28 15:38:54.793854",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "SLA.######",
|
||||
"beta": 0,
|
||||
"creation": "2016-11-28 15:38:54.793854",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "student",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Student",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Student",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "student",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Student",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Student",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "student_name",
|
||||
"fieldtype": "Read Only",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Student Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "student.title",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "student_name",
|
||||
"fieldtype": "Read Only",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Student Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "student.title",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "from_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "From Date",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "from_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "From Date",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "to_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "To Date",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "to_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "To Date",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Will show the student as Present in Student Monthly Attendance Report",
|
||||
"fieldname": "mark_as_present",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Mark as Present",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Will show the student as Present in Student Monthly Attendance Report",
|
||||
"fieldname": "mark_as_present",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Mark as Present",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_5",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_5",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "reason",
|
||||
"fieldtype": "Text",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Reason",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "reason",
|
||||
"fieldtype": "Text",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Reason",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Amended From",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Student Leave Application",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Amended From",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Student Leave Application",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"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": "2017-02-20 13:21:08.828872",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Schools",
|
||||
"name": "Student Leave Application",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 1,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-07-17 21:57:57.804413",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Schools",
|
||||
"name": "Student Leave Application",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 1,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Instructor",
|
||||
"set_user_permissions": 0,
|
||||
"share": 0,
|
||||
"submit": 1,
|
||||
"amend": 1,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Instructor",
|
||||
"set_user_permissions": 0,
|
||||
"share": 0,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"amend": 1,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Academics User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"amend": 1,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Academics User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "student_name",
|
||||
"track_changes": 0,
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"restrict_to_domain": "Education",
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "student_name",
|
||||
"track_changes": 0,
|
||||
"track_seen": 0
|
||||
}
|
||||
@@ -1,399 +1,400 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "SLog.####",
|
||||
"beta": 0,
|
||||
"creation": "2016-07-29 03:27:22.451772",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "SLog.####",
|
||||
"beta": 0,
|
||||
"creation": "2016-07-29 03:27:22.451772",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "student",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Student",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Student",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "student",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Student",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Student",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "student_name",
|
||||
"fieldtype": "Read Only",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Student Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "student.title",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "student_name",
|
||||
"fieldtype": "Read Only",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Student Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "student.title",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "type",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Type",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "General\nAcademic\nMedical\nAchievement",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "type",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Type",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "General\nAcademic\nMedical\nAchievement",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Date",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Date",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "academic_year",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Academic Year",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Academic Year",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "academic_year",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Academic Year",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Academic Year",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "academic_term",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Academic Term",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Academic Term",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "academic_term",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Academic Term",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Academic Term",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "program",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Program",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Program",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "program",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Program",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Program",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "student_batch",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Student Batch",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Student Batch Name",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "student_batch",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Student Batch",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Student Batch Name",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_5",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_5",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "log",
|
||||
"fieldtype": "Text Editor",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Log",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "log",
|
||||
"fieldtype": "Text Editor",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Log",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-07-06 12:42:05.777673",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Schools",
|
||||
"name": "Student Log",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-07-17 21:57:11.024049",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Schools",
|
||||
"name": "Student Log",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Academics User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Academics User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "student_name",
|
||||
"track_changes": 0,
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"restrict_to_domain": "Education",
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "student_name",
|
||||
"track_changes": 0,
|
||||
"track_seen": 1
|
||||
}
|
||||
@@ -105,6 +105,10 @@ erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({
|
||||
|
||||
lead: function() {
|
||||
var me = this;
|
||||
if(!this.frm.doc.lead) {
|
||||
return;
|
||||
}
|
||||
|
||||
frappe.call({
|
||||
method: "erpnext.crm.doctype.lead.lead.get_lead_details",
|
||||
args: {
|
||||
|
||||
@@ -1440,6 +1440,36 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
"columns": 0,
|
||||
"fieldname": "sec_tax_breakup",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Tax Breakup",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
@@ -1447,7 +1477,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "other_charges_calculation",
|
||||
"fieldtype": "HTML",
|
||||
"fieldtype": "Text",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
@@ -1457,12 +1487,12 @@
|
||||
"in_standard_filter": 0,
|
||||
"label": "Taxes and Charges Calculation",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"no_copy": 1,
|
||||
"oldfieldtype": "HTML",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
@@ -2542,7 +2572,7 @@
|
||||
"istable": 0,
|
||||
"max_attachments": 1,
|
||||
"menu_index": 0,
|
||||
"modified": "2017-06-13 14:29:18.553722",
|
||||
"modified": "2017-07-19 13:49:33.388736",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Quotation",
|
||||
|
||||
@@ -93,7 +93,7 @@ def get_list_context(context=None):
|
||||
'show_sidebar': True,
|
||||
'show_search': True,
|
||||
'no_breadcrumbs': True,
|
||||
'title': _('Quotes'),
|
||||
'title': _('Quotations'),
|
||||
})
|
||||
|
||||
return list_context
|
||||
|
||||
53
erpnext/selling/doctype/quotation/test_quotation.js
Normal file
@@ -0,0 +1,53 @@
|
||||
QUnit.test("test: quotation", function (assert) {
|
||||
assert.expect(10);
|
||||
let done = assert.async();
|
||||
frappe.run_serially([
|
||||
() => {
|
||||
return frappe.tests.make("Quotation", [
|
||||
{customer: "Test Customer 1"},
|
||||
{items: [
|
||||
[
|
||||
{"item_code": "Test Product 1"},
|
||||
{"qty": 5}
|
||||
]]
|
||||
}
|
||||
]);
|
||||
},
|
||||
() => {
|
||||
// get_item_details
|
||||
assert.ok(cur_frm.doc.items[0].item_name == "Test Product 1", "Added Test Product 1");
|
||||
|
||||
// calculate_taxes_and_totals
|
||||
assert.ok(cur_frm.doc.grand_total === 500, "Total Amount is correct");
|
||||
},
|
||||
() => cur_frm.set_value("customer_address", "Test1-Billing"),
|
||||
() => cur_frm.set_value("shipping_address_name", "Test1-Warehouse"),
|
||||
() => cur_frm.set_value("contact_person", "Contact 1-Test Customer 1"),
|
||||
() => cur_frm.set_value("currency", "USD"),
|
||||
() => frappe.timeout(0.3),
|
||||
() => cur_frm.set_value("selling_price_list", "Test-Selling-USD"),
|
||||
() => frappe.timeout(0.5),
|
||||
() => cur_frm.doc.items[0].rate = 200,
|
||||
() => frappe.timeout(0.3),
|
||||
() => cur_frm.set_value("tc_name", "Test Term 1"),
|
||||
() => frappe.timeout(0.3),
|
||||
() => cur_frm.save(),
|
||||
() => {
|
||||
// Check Address and Contact Info
|
||||
assert.ok(cur_frm.doc.address_display.includes("Billing Street 1"), "Address Changed");
|
||||
assert.ok(cur_frm.doc.shipping_address.includes("Warehouse Street 1"), "Address Changed");
|
||||
assert.ok(cur_frm.doc.contact_display == "Contact 1", "Contact info changed");
|
||||
|
||||
// Check Currency
|
||||
assert.ok(cur_frm.doc_currency == "USD", "Currency Changed");
|
||||
assert.ok(cur_frm.doc.selling_price_list == "Test-Selling-USD", "Price List Changed");
|
||||
assert.ok(cur_frm.doc.items[0].rate == 200, "Price Changed Manually");
|
||||
assert.equal(cur_frm.doc.total, 1000, "New Total Calculated");
|
||||
|
||||
// Check Terms and Condtions
|
||||
assert.ok(cur_frm.doc.tc_name == "Test Term 1", "Terms and Conditions Checked");
|
||||
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
});
|
||||
@@ -27,7 +27,8 @@ class TestQuotation(unittest.TestCase):
|
||||
self.assertEquals(sales_order.get("items")[0].prevdoc_docname, quotation.name)
|
||||
self.assertEquals(sales_order.customer, "_Test Customer")
|
||||
|
||||
sales_order.delivery_date = "2014-01-01"
|
||||
for d in sales_order.get("items"):
|
||||
d.delivery_date = "2014-01-01"
|
||||
sales_order.naming_series = "_T-Quotation-"
|
||||
sales_order.transaction_date = "2013-05-12"
|
||||
sales_order.insert()
|
||||
@@ -51,9 +52,11 @@ class TestQuotation(unittest.TestCase):
|
||||
quotation.submit()
|
||||
|
||||
sales_order = make_sales_order(quotation.name)
|
||||
sales_order.delivery_date = "2016-01-02"
|
||||
sales_order.naming_series = "_T-Quotation-"
|
||||
sales_order.transaction_date = "2016-01-01"
|
||||
for d in sales_order.get("items"):
|
||||
d.delivery_date = "2016-01-02"
|
||||
|
||||
sales_order.insert()
|
||||
|
||||
self.assertEquals(quotation.get("items")[0].rate, rate_with_margin)
|
||||
@@ -86,4 +89,4 @@ def get_quotation_dict(customer=None, item_code=None):
|
||||
'rate': 100
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,13 @@ frappe.ui.form.on("Sales Order", {
|
||||
function(doc) { return (doc.stock_qty<=doc.delivered_qty) ? "green" : "orange" })
|
||||
|
||||
erpnext.queries.setup_warehouse_query(frm);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
frappe.ui.form.on("Sales Order Item", {
|
||||
delivery_date: function(frm, cdt, cdn) {
|
||||
erpnext.utils.copy_value_in_all_row(frm.doc, cdt, cdn, "items", "delivery_date");
|
||||
}
|
||||
});
|
||||
|
||||
erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend({
|
||||
@@ -77,7 +83,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
// delivery note
|
||||
if(flt(doc.per_delivered, 2) < 100 && ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1 && allow_delivery) {
|
||||
this.frm.add_custom_button(__('Delivery'),
|
||||
function() { me.make_delivery_note() }, __("Make"));
|
||||
function() { me.make_delivery_note_based_on_delivery_note(); }, __("Make"));
|
||||
this.frm.add_custom_button(__('Production Order'),
|
||||
function() { me.make_production_order() }, __("Make"));
|
||||
|
||||
@@ -235,7 +241,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
},
|
||||
|
||||
order_type: function() {
|
||||
this.frm.toggle_reqd("delivery_date", this.frm.doc.order_type == "Sales");
|
||||
this.frm.fields_dict.items.grid.toggle_reqd("delivery_date", this.frm.doc.order_type == "Sales");
|
||||
},
|
||||
|
||||
tc_name: function() {
|
||||
@@ -249,10 +255,72 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
})
|
||||
},
|
||||
|
||||
make_delivery_note_based_on_delivery_note: function() {
|
||||
var me = this;
|
||||
|
||||
var delivery_dates = [];
|
||||
$.each(this.frm.doc.items || [], function(i, d) {
|
||||
if(!delivery_dates.includes(d.delivery_date)) {
|
||||
delivery_dates.push(d.delivery_date);
|
||||
}
|
||||
});
|
||||
|
||||
var item_grid = this.frm.fields_dict["items"].grid;
|
||||
if(!item_grid.get_selected().length && delivery_dates.length > 1) {
|
||||
var dialog = new frappe.ui.Dialog({
|
||||
title: __("Select Items based on Delivery Date"),
|
||||
fields: [{fieldtype: "HTML", fieldname: "dates_html"}]
|
||||
});
|
||||
|
||||
var html = $(`
|
||||
<div style="border: 1px solid #d1d8dd">
|
||||
<div class="list-item list-item--head">
|
||||
<div class="list-item__content list-item__content--flex-2">
|
||||
${__('Delivery Date')}
|
||||
</div>
|
||||
</div>
|
||||
${delivery_dates.map(date => `
|
||||
<div class="list-item">
|
||||
<div class="list-item__content list-item__content--flex-2">
|
||||
<label>
|
||||
<input type="checkbox" data-date="${date}" checked="checked"/>
|
||||
${frappe.datetime.str_to_user(date)}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
`).join("")}
|
||||
</div>
|
||||
`);
|
||||
|
||||
var wrapper = dialog.fields_dict.dates_html.$wrapper;
|
||||
wrapper.html(html);
|
||||
|
||||
dialog.set_primary_action(__("Select"), function() {
|
||||
var dates = wrapper.find('input[type=checkbox]:checked')
|
||||
.map((i, el) => $(el).attr('data-date')).toArray();
|
||||
|
||||
if(!dates) return;
|
||||
|
||||
$.each(dates, function(i, d) {
|
||||
$.each(item_grid.grid_rows || [], function(j, row) {
|
||||
if(row.doc.delivery_date == d) {
|
||||
row.doc.__checked = 1;
|
||||
}
|
||||
});
|
||||
})
|
||||
me.make_delivery_note();
|
||||
dialog.hide();
|
||||
});
|
||||
dialog.show();
|
||||
} else {
|
||||
this.make_delivery_note();
|
||||
}
|
||||
},
|
||||
|
||||
make_delivery_note: function() {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "erpnext.selling.doctype.sales_order.sales_order.make_delivery_note",
|
||||
frm: this.frm
|
||||
frm: me.frm
|
||||
})
|
||||
},
|
||||
|
||||
@@ -344,6 +412,11 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
if(cint(frappe.boot.notification_settings.sales_order)) {
|
||||
this.frm.email_doc(frappe.boot.notification_settings.sales_order_message);
|
||||
}
|
||||
},
|
||||
|
||||
items_add: function(doc, cdt, cdn) {
|
||||
var row = frappe.get_doc(cdt, cdn);
|
||||
this.frm.script_manager.copy_from_first_row("items", row, ["delivery_date"]);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||