Merge branch 'develop' of https://github.com/frappe/erpnext into custom_append_to

This commit is contained in:
Himanshu Warekar
2020-01-19 11:45:24 +05:30
37 changed files with 820 additions and 2004 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -373,6 +373,7 @@ def get_existing_payment_request_amount(ref_dt, ref_dn):
reference_doctype = %s reference_doctype = %s
and reference_name = %s and reference_name = %s
and docstatus = 1 and docstatus = 1
and status != 'Paid'
""", (ref_dt, ref_dn)) """, (ref_dt, ref_dn))
return flt(existing_payment_request_amount[0][0]) if existing_payment_request_amount else 0 return flt(existing_payment_request_amount[0][0]) if existing_payment_request_amount else 0

View File

@@ -167,8 +167,15 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
make_comment_dialog_and_block_invoice: function(){ make_comment_dialog_and_block_invoice: function(){
const me = this; const me = this;
const title = __('Add Comment'); const title = __('Block Invoice');
const fields = [ const fields = [
{
fieldname: 'release_date',
read_only: 0,
fieldtype:'Date',
label: __('Release Date'),
default: me.frm.doc.release_date
},
{ {
fieldname: 'hold_comment', fieldname: 'hold_comment',
read_only: 0, read_only: 0,
@@ -187,7 +194,11 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
const dialog_data = me.dialog.get_values(); const dialog_data = me.dialog.get_values();
frappe.call({ frappe.call({
'method': 'erpnext.accounts.doctype.purchase_invoice.purchase_invoice.block_invoice', 'method': 'erpnext.accounts.doctype.purchase_invoice.purchase_invoice.block_invoice',
'args': {'name': me.frm.doc.name, 'hold_comment': dialog_data.hold_comment}, 'args': {
'name': me.frm.doc.name,
'hold_comment': dialog_data.hold_comment,
'release_date': dialog_data.release_date
},
'callback': (r) => me.frm.reload_doc() 'callback': (r) => me.frm.reload_doc()
}); });
me.dialog.hide(); me.dialog.hide();

View File

@@ -927,9 +927,10 @@ class PurchaseInvoice(BuyingController):
def on_recurring(self, reference_doc, auto_repeat_doc): def on_recurring(self, reference_doc, auto_repeat_doc):
self.due_date = None self.due_date = None
def block_invoice(self, hold_comment=None): def block_invoice(self, hold_comment=None, release_date=None):
self.db_set('on_hold', 1) self.db_set('on_hold', 1)
self.db_set('hold_comment', cstr(hold_comment)) self.db_set('hold_comment', cstr(hold_comment))
self.db_set('release_date', release_date)
def unblock_invoice(self): def unblock_invoice(self):
self.db_set('on_hold', 0) self.db_set('on_hold', 0)
@@ -1013,10 +1014,10 @@ def unblock_invoice(name):
@frappe.whitelist() @frappe.whitelist()
def block_invoice(name, hold_comment): def block_invoice(name, hold_comment, release_date):
if frappe.db.exists('Purchase Invoice', name): if frappe.db.exists('Purchase Invoice', name):
pi = frappe.get_doc('Purchase Invoice', name) pi = frappe.get_doc('Purchase Invoice', name)
pi.block_invoice(hold_comment) pi.block_invoice(hold_comment, release_date)
@frappe.whitelist() @frappe.whitelist()
def make_inter_company_sales_invoice(source_name, target_doc=None): def make_inter_company_sales_invoice(source_name, target_doc=None):

View File

@@ -1,134 +1,134 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_events_in_timeline": 0, "allow_events_in_timeline": 0,
"allow_guest_to_view": 0, "allow_guest_to_view": 0,
"allow_import": 0, "allow_import": 0,
"allow_rename": 0, "allow_rename": 0,
"autoname": "field:title", "autoname": "field:title",
"beta": 0, "beta": 0,
"creation": "2018-11-22 23:38:39.668804", "creation": "2018-11-22 23:38:39.668804",
"custom": 0, "custom": 0,
"docstatus": 0, "docstatus": 0,
"doctype": "DocType", "doctype": "DocType",
"document_type": "", "document_type": "",
"editable_grid": 1, "editable_grid": 1,
"engine": "InnoDB", "engine": "InnoDB",
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fieldname": "title", "fieldname": "title",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Title", "label": "Title",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0, "remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0, "translatable": 0,
"unique": 1 "unique": 1
} }
], ],
"has_web_view": 0, "has_web_view": 0,
"hide_heading": 0, "hide_heading": 0,
"hide_toolbar": 0, "hide_toolbar": 0,
"idx": 0, "idx": 0,
"image_view": 0, "image_view": 0,
"in_create": 0, "in_create": 0,
"is_submittable": 0, "is_submittable": 0,
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-11-22 23:38:39.668804", "modified": "2020-01-15 17:14:28.951793",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Tax Category", "name": "Tax Category",
"name_case": "", "name_case": "",
"owner": "Administrator", "owner": "Administrator",
"permissions": [ "permissions": [
{ {
"amend": 0, "amend": 0,
"cancel": 0, "cancel": 0,
"create": 1, "create": 1,
"delete": 1, "delete": 1,
"email": 1, "email": 1,
"export": 1, "export": 1,
"if_owner": 0, "if_owner": 0,
"import": 0, "import": 0,
"permlevel": 0, "permlevel": 0,
"print": 1, "print": 1,
"read": 1, "read": 1,
"report": 1, "report": 1,
"role": "System Manager", "role": "System Manager",
"set_user_permissions": 0, "set_user_permissions": 0,
"share": 1, "share": 1,
"submit": 0, "submit": 0,
"write": 1 "write": 1
}, },
{ {
"amend": 0, "amend": 0,
"cancel": 0, "cancel": 0,
"create": 1, "create": 1,
"delete": 1, "delete": 1,
"email": 1, "email": 1,
"export": 1, "export": 1,
"if_owner": 0, "if_owner": 0,
"import": 0, "import": 0,
"permlevel": 0, "permlevel": 0,
"print": 1, "print": 1,
"read": 1, "read": 1,
"report": 1, "report": 1,
"role": "Accounts Manager", "role": "Accounts Manager",
"set_user_permissions": 0, "set_user_permissions": 0,
"share": 1, "share": 1,
"submit": 0, "submit": 0,
"write": 1 "write": 1
}, },
{ {
"amend": 0, "amend": 0,
"cancel": 0, "cancel": 0,
"create": 0, "create": 0,
"delete": 0, "delete": 0,
"email": 1, "email": 1,
"export": 1, "export": 1,
"if_owner": 0, "if_owner": 0,
"import": 0, "import": 0,
"permlevel": 0, "permlevel": 0,
"print": 1, "print": 1,
"read": 1, "read": 1,
"report": 1, "report": 1,
"role": "Accounts User", "role": "Accounts User",
"set_user_permissions": 0, "set_user_permissions": 0,
"share": 1, "share": 1,
"submit": 0, "submit": 0,
"write": 0 "write": 0
} }
], ],
"quick_entry": 1, "quick_entry": 1,
"read_only": 0, "read_only": 0,
"read_only_onload": 0, "read_only_onload": 0,
"show_name_in_global_search": 0, "show_name_in_global_search": 0,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"track_changes": 1, "track_changes": 1,
"track_seen": 0, "track_seen": 0,
"track_views": 0 "track_views": 0
} }

View File

@@ -338,25 +338,12 @@ frappe.ui.form.on('Asset', {
}) })
}, },
purchase_receipt: function(frm) { purchase_receipt: (frm) => {
frm.trigger('toggle_reference_doc'); frm.trigger('toggle_reference_doc');
if (frm.doc.purchase_receipt) { if (frm.doc.purchase_receipt) {
if (frm.doc.item_code) { if (frm.doc.item_code) {
frappe.db.get_doc('Purchase Receipt', frm.doc.purchase_receipt).then(pr_doc => { frappe.db.get_doc('Purchase Receipt', frm.doc.purchase_receipt).then(pr_doc => {
frm.set_value('company', pr_doc.company); frm.events.set_values_from_purchase_doc(frm, 'Purchase Receipt', pr_doc)
frm.set_value('purchase_date', pr_doc.posting_date);
const item = pr_doc.items.find(item => item.item_code === frm.doc.item_code);
if (!item) {
frm.set_value('purchase_receipt', '');
frappe.msgprint({
title: __('Invalid Purchase Receipt'),
message: __("The selected Purchase Receipt doesn't contains selected Asset Item."),
indicator: 'red'
});
}
frm.set_value('gross_purchase_amount', item.base_net_rate);
frm.set_value('location', item.asset_location);
}); });
} else { } else {
frm.set_value('purchase_receipt', ''); frm.set_value('purchase_receipt', '');
@@ -368,24 +355,12 @@ frappe.ui.form.on('Asset', {
} }
}, },
purchase_invoice: function(frm) { purchase_invoice: (frm) => {
frm.trigger('toggle_reference_doc'); frm.trigger('toggle_reference_doc');
if (frm.doc.purchase_invoice) { if (frm.doc.purchase_invoice) {
if (frm.doc.item_code) { if (frm.doc.item_code) {
frappe.db.get_doc('Purchase Invoice', frm.doc.purchase_invoice).then(pi_doc => { frappe.db.get_doc('Purchase Invoice', frm.doc.purchase_invoice).then(pi_doc => {
frm.set_value('company', pi_doc.company); frm.events.set_values_from_purchase_doc(frm, 'Purchase Invoice', pi_doc)
frm.set_value('purchase_date', pi_doc.posting_date);
const item = pi_doc.items.find(item => item.item_code === frm.doc.item_code);
if (!item) {
frm.set_value('purchase_invoice', '');
frappe.msgprint({
title: __('Invalid Purchase Invoice'),
message: __("The selected Purchase Invoice doesn't contains selected Asset Item."),
indicator: 'red'
});
}
frm.set_value('gross_purchase_amount', item.base_net_rate);
frm.set_value('location', item.asset_location);
}); });
} else { } else {
frm.set_value('purchase_invoice', ''); frm.set_value('purchase_invoice', '');
@@ -397,6 +372,24 @@ frappe.ui.form.on('Asset', {
} }
}, },
set_values_from_purchase_doc: function(frm, doctype, purchase_doc) {
frm.set_value('company', purchase_doc.company);
frm.set_value('purchase_date', purchase_doc.posting_date);
const item = purchase_doc.items.find(item => item.item_code === frm.doc.item_code);
if (!item) {
doctype_field = frappe.scrub(doctype)
frm.set_value(doctype_field, '');
frappe.msgprint({
title: __(`Invalid ${doctype}`),
message: __(`The selected ${doctype} doesn't contains selected Asset Item.`),
indicator: 'red'
});
}
frm.set_value('gross_purchase_amount', item.base_net_rate + item.item_tax_amount);
frm.set_value('purchase_receipt_amount', item.base_net_rate + item.item_tax_amount);
frm.set_value('location', item.asset_location);
},
set_depreciation_rate: function(frm, row) { set_depreciation_rate: function(frm, row) {
if (row.total_number_of_depreciations && row.frequency_of_depreciation if (row.total_number_of_depreciations && row.frequency_of_depreciation
&& row.expected_value_after_useful_life) { && row.expected_value_after_useful_life) {

View File

@@ -22,7 +22,7 @@ def post_depreciation_entries(date=None):
def get_depreciable_assets(date): def get_depreciable_assets(date):
return frappe.db.sql_list("""select a.name return frappe.db.sql_list("""select a.name
from tabAsset a, `tabDepreciation Schedule` ds from tabAsset a, `tabDepreciation Schedule` ds
where a.name = ds.parent and a.docstatus=1 and ds.schedule_date<=%s where a.name = ds.parent and a.docstatus=1 and ds.schedule_date<=%s and a.calculate_depreciation = 1
and a.status in ('Submitted', 'Partially Depreciated') and a.status in ('Submitted', 'Partially Depreciated')
and ifnull(ds.journal_entry, '')=''""", date) and ifnull(ds.journal_entry, '')=''""", date)

View File

@@ -1,5 +1,4 @@
{ {
"actions": [],
"allow_import": 1, "allow_import": 1,
"autoname": "naming_series:", "autoname": "naming_series:",
"creation": "2013-05-21 16:16:39", "creation": "2013-05-21 16:16:39",
@@ -48,7 +47,6 @@
"ignore_pricing_rule", "ignore_pricing_rule",
"sec_warehouse", "sec_warehouse",
"set_warehouse", "set_warehouse",
"set_reserve_warehouse",
"col_break_warehouse", "col_break_warehouse",
"is_subcontracted", "is_subcontracted",
"supplier_warehouse", "supplier_warehouse",
@@ -58,6 +56,7 @@
"section_break_48", "section_break_48",
"pricing_rules", "pricing_rules",
"raw_material_details", "raw_material_details",
"set_reserve_warehouse",
"supplied_items", "supplied_items",
"sb_last_purchase", "sb_last_purchase",
"total_qty", "total_qty",
@@ -1054,8 +1053,7 @@
"icon": "fa fa-file-text", "icon": "fa fa-file-text",
"idx": 105, "idx": 105,
"is_submittable": 1, "is_submittable": 1,
"links": [], "modified": "2020-01-14 18:54:39.694448",
"modified": "2019-12-30 19:11:54.122264",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Purchase Order", "name": "Purchase Order",

View File

@@ -182,7 +182,7 @@ class StatusUpdater(Document):
if args.get('no_allowance'): if args.get('no_allowance'):
item['reduce_by'] = item[args['target_field']] - item[args['target_ref_field']] item['reduce_by'] = item[args['target_field']] - item[args['target_ref_field']]
if item['reduce_by'] > .01: if item['reduce_by'] > .01:
self.limits_crossed_error(args, item) self.limits_crossed_error(args, item, "qty")
elif item[args['target_ref_field']]: elif item[args['target_ref_field']]:
self.check_overflow_with_allowance(item, args) self.check_overflow_with_allowance(item, args)

View File

@@ -66,6 +66,7 @@ class StockController(AccountsController):
gl_list = [] gl_list = []
warehouse_with_no_account = [] warehouse_with_no_account = []
precision = frappe.get_precision("GL Entry", "debit_in_account_currency")
for item_row in voucher_details: for item_row in voucher_details:
sle_list = sle_map.get(item_row.name) sle_list = sle_map.get(item_row.name)
if sle_list: if sle_list:
@@ -91,7 +92,7 @@ class StockController(AccountsController):
"against": item_row.expense_account, "against": item_row.expense_account,
"cost_center": item_row.cost_center, "cost_center": item_row.cost_center,
"remarks": self.get("remarks") or "Accounting Entry for Stock", "remarks": self.get("remarks") or "Accounting Entry for Stock",
"debit": flt(sle.stock_value_difference, 2), "debit": flt(sle.stock_value_difference, precision),
"is_opening": item_row.get("is_opening") or self.get("is_opening") or "No", "is_opening": item_row.get("is_opening") or self.get("is_opening") or "No",
}, warehouse_account[sle.warehouse]["account_currency"], item=item_row)) }, warehouse_account[sle.warehouse]["account_currency"], item=item_row))
@@ -101,7 +102,7 @@ class StockController(AccountsController):
"against": warehouse_account[sle.warehouse]["account"], "against": warehouse_account[sle.warehouse]["account"],
"cost_center": item_row.cost_center, "cost_center": item_row.cost_center,
"remarks": self.get("remarks") or "Accounting Entry for Stock", "remarks": self.get("remarks") or "Accounting Entry for Stock",
"credit": flt(sle.stock_value_difference, 2), "credit": flt(sle.stock_value_difference, precision),
"project": item_row.get("project") or self.get("project"), "project": item_row.get("project") or self.get("project"),
"is_opening": item_row.get("is_opening") or self.get("is_opening") or "No" "is_opening": item_row.get("is_opening") or self.get("is_opening") or "No"
}, item=item_row)) }, item=item_row))

View File

@@ -304,7 +304,7 @@ def set_multiple_status(names, status):
def auto_close_opportunity(): def auto_close_opportunity():
""" auto close the `Replied` Opportunities after 7 days """ """ auto close the `Replied` Opportunities after 7 days """
auto_close_after_days = frappe.db.get_value("Support Settings", "Support Settings", "close_opportunity_after_days") or 15 auto_close_after_days = frappe.db.get_single_value("Selling Settings", "close_opportunity_after_days") or 15
opportunities = frappe.db.sql(""" select name from tabOpportunity where status='Replied' and opportunities = frappe.db.sql(""" select name from tabOpportunity where status='Replied' and
modified<DATE_SUB(CURDATE(), INTERVAL %s DAY) """, (auto_close_after_days), as_dict=True) modified<DATE_SUB(CURDATE(), INTERVAL %s DAY) """, (auto_close_after_days), as_dict=True)

View File

@@ -53,7 +53,11 @@ def add_institution(token, response):
@frappe.whitelist() @frappe.whitelist()
def add_bank_accounts(response, bank, company): def add_bank_accounts(response, bank, company):
response = json.loads(response) if not "accounts" in response else response try:
response = json.loads(response)
except TypeError:
pass
bank = json.loads(bank) bank = json.loads(bank)
result = [] result = []

View File

@@ -264,6 +264,13 @@ doc_events = {
} }
} }
# On cancel event Payment Entry will be exempted and all linked submittable doctype will get cancelled.
# to maintain data integrity we exempted payment entry. it will un-link when sales invoice get cancelled.
# if payment entry not in auto cancel exempted doctypes it will cancel payment entry.
auto_cancel_exempted_doctypes= [
"Payment Entry"
]
scheduler_events = { scheduler_events = {
"all": [ "all": [
"erpnext.projects.doctype.project.project.project_status_update_reminder" "erpnext.projects.doctype.project.project.project_status_update_reminder"

View File

@@ -265,7 +265,7 @@
"bold": 1, "bold": 1,
"fieldname": "person_to_be_contacted", "fieldname": "person_to_be_contacted",
"fieldtype": "Data", "fieldtype": "Data",
"label": "Emergency Contact" "label": "Emergency Contact Name"
}, },
{ {
"fieldname": "relation", "fieldname": "relation",
@@ -787,7 +787,7 @@
"idx": 24, "idx": 24,
"image_field": "image", "image_field": "image",
"links": [], "links": [],
"modified": "2019-12-11 13:22:18.323622", "modified": "2020-01-09 04:23:55.611366",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "HR", "module": "HR",
"name": "Employee", "name": "Employee",

View File

@@ -47,7 +47,7 @@ frappe.ui.form.on('Employee Advance', {
} }
if (frm.doc.docstatus === 1 if (frm.doc.docstatus === 1
&& (flt(frm.doc.claimed_amount) < flt(frm.doc.paid_amount)) && (flt(frm.doc.claimed_amount) + flt(frm.doc.return_amount) < flt(frm.doc.paid_amount))
&& frappe.model.can_create("Journal Entry")) { && frappe.model.can_create("Journal Entry")) {
frm.add_custom_button(__("Return"), function() { frm.add_custom_button(__("Return"), function() {
@@ -96,12 +96,12 @@ frappe.ui.form.on('Employee Advance', {
frappe.call({ frappe.call({
method: 'erpnext.hr.doctype.employee_advance.employee_advance.make_return_entry', method: 'erpnext.hr.doctype.employee_advance.employee_advance.make_return_entry',
args: { args: {
'employee_name': frm.doc.employee, 'employee': frm.doc.employee,
'company': frm.doc.company, 'company': frm.doc.company,
'employee_advance_name': frm.doc.name, 'employee_advance_name': frm.doc.name,
'return_amount': flt(frm.doc.paid_amount - frm.doc.claimed_amount), 'return_amount': flt(frm.doc.paid_amount - frm.doc.claimed_amount),
'mode_of_payment': frm.doc.mode_of_payment, 'advance_account': frm.doc.advance_account,
'advance_account': frm.doc.advance_account 'mode_of_payment': frm.doc.mode_of_payment
}, },
callback: function(r) { callback: function(r) {
const doclist = frappe.model.sync(r.message); const doclist = frappe.model.sync(r.message);

View File

@@ -133,7 +133,8 @@ def make_bank_entry(dt, dn):
return je.as_dict() return je.as_dict()
@frappe.whitelist() @frappe.whitelist()
def make_return_entry(employee_name, company, employee_advance_name, return_amount, mode_of_payment, advance_account): def make_return_entry(employee, company, employee_advance_name,
return_amount, advance_account, mode_of_payment=None):
return_account = get_default_bank_cash_account(company, account_type='Cash', mode_of_payment = mode_of_payment) return_account = get_default_bank_cash_account(company, account_type='Cash', mode_of_payment = mode_of_payment)
je = frappe.new_doc('Journal Entry') je = frappe.new_doc('Journal Entry')
je.posting_date = nowdate() je.posting_date = nowdate()
@@ -147,7 +148,7 @@ def make_return_entry(employee_name, company, employee_advance_name, return_amou
'reference_type': 'Employee Advance', 'reference_type': 'Employee Advance',
'reference_name': employee_advance_name, 'reference_name': employee_advance_name,
'party_type': 'Employee', 'party_type': 'Employee',
'party': employee_name, 'party': employee,
'is_advance': 'Yes' 'is_advance': 'Yes'
}) })
@@ -159,5 +160,5 @@ def make_return_entry(employee_name, company, employee_advance_name, return_amou
}) })
return je.as_dict() return je.as_dict()

View File

@@ -242,13 +242,14 @@ frappe.ui.form.on("Expense Claim", {
}, },
update_employee_advance_claimed_amount: function(frm) { update_employee_advance_claimed_amount: function(frm) {
console.log("update_employee_advance_claimed_amount")
let amount_to_be_allocated = frm.doc.grand_total; let amount_to_be_allocated = frm.doc.grand_total;
$.each(frm.doc.advances || [], function(i, advance) { $.each(frm.doc.advances || [], function(i, advance){
if (amount_to_be_allocated >= advance.unclaimed_amount) { if (amount_to_be_allocated >= advance.unclaimed_amount){
frm.doc.advances[i].allocated_amount = frm.doc.advances[i].unclaimed_amount; advance.allocated_amount = frm.doc.advances[i].unclaimed_amount;
amount_to_be_allocated -= advance.allocated_amount; amount_to_be_allocated -= advance.allocated_amount;
} else { } else {
frm.doc.advances[i].allocated_amount = amount_to_be_allocated; advance.allocated_amount = amount_to_be_allocated;
amount_to_be_allocated = 0; amount_to_be_allocated = 0;
} }
frm.refresh_field("advances"); frm.refresh_field("advances");
@@ -300,6 +301,7 @@ frappe.ui.form.on("Expense Claim", {
doc: frm.doc, doc: frm.doc,
callback: () => { callback: () => {
refresh_field("taxes"); refresh_field("taxes");
frm.trigger("update_employee_advance_claimed_amount");
} }
}); });
} }
@@ -340,16 +342,12 @@ frappe.ui.form.on("Expense Claim Detail", {
}, },
amount: function(frm, cdt, cdn) { amount: function(frm, cdt, cdn) {
var child = locals[cdt][cdn]; var child = locals[cdt][cdn];
var doc = frm.doc;
frappe.model.set_value(cdt, cdn, 'sanctioned_amount', child.amount); frappe.model.set_value(cdt, cdn, 'sanctioned_amount', child.amount);
cur_frm.cscript.calculate_total(doc,cdt,cdn);
}, },
sanctioned_amount: function(frm, cdt, cdn) { sanctioned_amount: function(frm, cdt, cdn) {
var doc = frm.doc; cur_frm.cscript.calculate_total(frm.doc, cdt, cdn);
cur_frm.cscript.calculate_total(doc,cdt,cdn);
frm.trigger("get_taxes"); frm.trigger("get_taxes");
frm.trigger("calculate_grand_total");
}, },
cost_center: function(frm, cdt, cdn) { cost_center: function(frm, cdt, cdn) {
erpnext.utils.copy_value_in_all_rows(frm.doc, cdt, cdn, "expenses", "cost_center"); erpnext.utils.copy_value_in_all_rows(frm.doc, cdt, cdn, "expenses", "cost_center");

View File

@@ -244,6 +244,7 @@ class ExpenseClaim(AccountsController):
precision = self.precision("total_advance_amount") precision = self.precision("total_advance_amount")
if flt(self.total_advance_amount, precision) > flt(self.total_claimed_amount, precision): if flt(self.total_advance_amount, precision) > flt(self.total_claimed_amount, precision):
frappe.throw(_("Total advance amount cannot be greater than total claimed amount")) frappe.throw(_("Total advance amount cannot be greater than total claimed amount"))
if self.total_sanctioned_amount \ if self.total_sanctioned_amount \
and flt(self.total_advance_amount, precision) > flt(self.total_sanctioned_amount, precision): and flt(self.total_advance_amount, precision) > flt(self.total_sanctioned_amount, precision):
frappe.throw(_("Total advance amount cannot be greater than total sanctioned amount")) frappe.throw(_("Total advance amount cannot be greater than total sanctioned amount"))

View File

@@ -1,5 +1,4 @@
{ {
"actions": [],
"creation": "2017-10-09 16:53:26.410762", "creation": "2017-10-09 16:53:26.410762",
"doctype": "DocType", "doctype": "DocType",
"document_type": "Document", "document_type": "Document",
@@ -43,7 +42,7 @@
"fieldtype": "Currency", "fieldtype": "Currency",
"in_list_view": 1, "in_list_view": 1,
"label": "Advance Paid", "label": "Advance Paid",
"options": "Company:company.default_currency", "options": "Company:company:default_currency",
"read_only": 1 "read_only": 1
}, },
{ {
@@ -55,7 +54,7 @@
"no_copy": 1, "no_copy": 1,
"oldfieldname": "advance_amount", "oldfieldname": "advance_amount",
"oldfieldtype": "Currency", "oldfieldtype": "Currency",
"options": "Company:company.default_currency", "options": "Company:company:default_currency",
"print_width": "120px", "print_width": "120px",
"read_only": 1, "read_only": 1,
"reqd": 1, "reqd": 1,
@@ -70,7 +69,7 @@
"no_copy": 1, "no_copy": 1,
"oldfieldname": "allocated_amount", "oldfieldname": "allocated_amount",
"oldfieldtype": "Currency", "oldfieldtype": "Currency",
"options": "Company:company.default_currency", "options": "Company:company:default_currency",
"print_width": "120px", "print_width": "120px",
"width": "120px" "width": "120px"
}, },
@@ -88,7 +87,7 @@
], ],
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2019-12-11 13:53:22.111766", "modified": "2019-12-17 13:53:22.111766",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "HR", "module": "HR",
"name": "Expense Claim Advance", "name": "Expense Claim Advance",

View File

@@ -75,6 +75,7 @@ frappe.ui.form.on('Salary Structure', {
title: __("Assign to Employees"), title: __("Assign to Employees"),
fields: [ fields: [
{fieldname: "sec_break", fieldtype: "Section Break", label: __("Filter Employees By (Optional)")}, {fieldname: "sec_break", fieldtype: "Section Break", label: __("Filter Employees By (Optional)")},
{fieldname: "company", fieldtype: "Link", options: "Company", label: __("Company"), default: frm.doc.company, read_only:1},
{fieldname: "grade", fieldtype: "Link", options: "Employee Grade", label: __("Employee Grade")}, {fieldname: "grade", fieldtype: "Link", options: "Employee Grade", label: __("Employee Grade")},
{fieldname:'department', fieldtype:'Link', options: 'Department', label: __('Department')}, {fieldname:'department', fieldtype:'Link', options: 'Department', label: __('Department')},
{fieldname:'designation', fieldtype:'Link', options: 'Designation', label: __('Designation')}, {fieldname:'designation', fieldtype:'Link', options: 'Designation', label: __('Designation')},
@@ -87,7 +88,6 @@ frappe.ui.form.on('Salary Structure', {
], ],
primary_action: function() { primary_action: function() {
var data = d.get_values(); var data = d.get_values();
frappe.call({ frappe.call({
doc: frm.doc, doc: frm.doc,
method: "assign_salary_structure", method: "assign_salary_structure",

View File

@@ -81,24 +81,24 @@ class SalaryStructure(Document):
return employees return employees
@frappe.whitelist() @frappe.whitelist()
def assign_salary_structure(self, grade=None, department=None, designation=None,employee=None, def assign_salary_structure(self, company=None, grade=None, department=None, designation=None,employee=None,
from_date=None, base=None,variable=None): from_date=None, base=None,variable=None):
employees = self.get_employees(grade= grade,department= department,designation= designation,name=employee) employees = self.get_employees(company= company, grade= grade,department= department,designation= designation,name=employee)
if employees: if employees:
if len(employees) > 20: if len(employees) > 20:
frappe.enqueue(assign_salary_structure_for_employees, timeout=600, frappe.enqueue(assign_salary_structure_for_employees, timeout=600,
employees=employees, salary_structure=self,from_date=from_date, base=base,variable=variable) employees=employees, salary_structure=self,from_date=from_date, base=base,variable=variable)
else: else:
assign_salary_structure_for_employees(employees, self,from_date=from_date, base=base,variable=variable) assign_salary_structure_for_employees(employees, self, from_date=from_date, base=base,variable=variable)
else: else:
frappe.msgprint(_("No Employee Found")) frappe.msgprint(_("No Employee Found"))
def assign_salary_structure_for_employees(employees, salary_structure,from_date=None, base=None,variable=None): def assign_salary_structure_for_employees(employees, salary_structure, from_date=None, base=None,variable=None):
salary_structures_assignments = [] salary_structures_assignments = []
existing_assignments_for = get_existing_assignments(employees, salary_structure.name,from_date) existing_assignments_for = get_existing_assignments(employees, salary_structure, from_date)
count=0 count=0
for employee in employees: for employee in employees:
if employee in existing_assignments_for: if employee in existing_assignments_for:
@@ -117,6 +117,7 @@ def create_salary_structures_assignment(employee, salary_structure, from_date, b
assignment = frappe.new_doc("Salary Structure Assignment") assignment = frappe.new_doc("Salary Structure Assignment")
assignment.employee = employee assignment.employee = employee
assignment.salary_structure = salary_structure.name assignment.salary_structure = salary_structure.name
assignment.company = salary_structure.company
assignment.from_date = from_date assignment.from_date = from_date
assignment.base = base assignment.base = base
assignment.variable = variable assignment.variable = variable
@@ -125,12 +126,12 @@ def create_salary_structures_assignment(employee, salary_structure, from_date, b
return assignment.name return assignment.name
def get_existing_assignments(employees, salary_structure,from_date): def get_existing_assignments(employees, salary_structure, from_date):
salary_structures_assignments = frappe.db.sql_list(""" salary_structures_assignments = frappe.db.sql_list("""
select distinct employee from `tabSalary Structure Assignment` select distinct employee from `tabSalary Structure Assignment`
where salary_structure=%s and employee in (%s) where salary_structure=%s and employee in (%s)
and from_date=%s and docstatus=1 and from_date=%s and company= %s and docstatus=1
""" % ('%s', ', '.join(['%s']*len(employees)),'%s'), [salary_structure] + employees+[from_date]) """ % ('%s', ', '.join(['%s']*len(employees)),'%s', '%s'), [salary_structure.name] + employees+[from_date]+[salary_structure.company])
if salary_structures_assignments: if salary_structures_assignments:
frappe.msgprint(_("Skipping Salary Structure Assignment for the following employees, as Salary Structure Assignment records already exists against them. {0}") frappe.msgprint(_("Skipping Salary Structure Assignment for the following employees, as Salary Structure Assignment records already exists against them. {0}")
.format("\n".join(salary_structures_assignments))) .format("\n".join(salary_structures_assignments)))
@@ -170,7 +171,7 @@ def make_salary_slip(source_name, target_doc = None, employee = None, as_print =
def get_employees(salary_structure): def get_employees(salary_structure):
employees = frappe.get_list('Salary Structure Assignment', employees = frappe.get_list('Salary Structure Assignment',
filters={'salary_structure': salary_structure, 'docstatus': 1}, fields=['employee']) filters={'salary_structure': salary_structure, 'docstatus': 1}, fields=['employee'])
if not employees: if not employees:
frappe.throw(_("There's no Employee with Salary Structure: {0}. \ frappe.throw(_("There's no Employee with Salary Structure: {0}. \
Assign {1} to an Employee to preview Salary Slip").format(salary_structure, salary_structure)) Assign {1} to an Employee to preview Salary Slip").format(salary_structure, salary_structure))

View File

@@ -588,7 +588,7 @@ class BOM(WebsiteGenerator):
for d in self.operations: for d in self.operations:
if not d.description: if not d.description:
d.description = frappe.db.get_value('Operation', d.operation, 'description') d.description = frappe.db.get_value('Operation', d.operation, 'description')
if not d.batch_size > 0: if not d.batch_size or d.batch_size <= 0:
d.batch_size = 1 d.batch_size = 1
def get_list_context(context): def get_list_context(context):
@@ -634,7 +634,7 @@ def get_bom_items_as_dict(bom, company, qty=1, fetch_exploded=1, fetch_scrap_ite
is_stock_item=is_stock_item, is_stock_item=is_stock_item,
qty_field="stock_qty", qty_field="stock_qty",
select_columns = """, bom_item.source_warehouse, bom_item.operation, select_columns = """, bom_item.source_warehouse, bom_item.operation,
bom_item.include_item_in_manufacturing, bom_item.description, bom_item.include_item_in_manufacturing, bom_item.description, bom_item.rate,
(Select idx from `tabBOM Item` where item_code = bom_item.item_code and parent = %(parent)s limit 1) as idx""") (Select idx from `tabBOM Item` where item_code = bom_item.item_code and parent = %(parent)s limit 1) as idx""")
items = frappe.db.sql(query, { "parent": bom, "qty": qty, "bom": bom, "company": company }, as_dict=True) items = frappe.db.sql(query, { "parent": bom, "qty": qty, "bom": bom, "company": company }, as_dict=True)
@@ -648,7 +648,7 @@ def get_bom_items_as_dict(bom, company, qty=1, fetch_exploded=1, fetch_scrap_ite
qty_field="stock_qty" if fetch_qty_in_stock_uom else "qty", qty_field="stock_qty" if fetch_qty_in_stock_uom else "qty",
select_columns = """, bom_item.uom, bom_item.conversion_factor, bom_item.source_warehouse, select_columns = """, bom_item.uom, bom_item.conversion_factor, bom_item.source_warehouse,
bom_item.idx, bom_item.operation, bom_item.include_item_in_manufacturing, bom_item.idx, bom_item.operation, bom_item.include_item_in_manufacturing,
bom_item.description """) bom_item.description, bom_item.base_rate as rate """)
items = frappe.db.sql(query, { "qty": qty, "bom": bom, "company": company }, as_dict=True) items = frappe.db.sql(query, { "qty": qty, "bom": bom, "company": company }, as_dict=True)
for item in items: for item in items:
@@ -761,11 +761,17 @@ def get_boms_in_bottom_up_order(bom_no=None):
def add_additional_cost(stock_entry, work_order): def add_additional_cost(stock_entry, work_order):
# Add non stock items cost in the additional cost # Add non stock items cost in the additional cost
bom = frappe.get_doc('BOM', work_order.bom_no) stock_entry.additional_costs = []
table = 'exploded_items' if work_order.get('use_multi_level_bom') else 'items'
expenses_included_in_valuation = frappe.get_cached_value("Company", work_order.company, expenses_included_in_valuation = frappe.get_cached_value("Company", work_order.company,
"expenses_included_in_valuation") "expenses_included_in_valuation")
add_non_stock_items_cost(stock_entry, work_order, expenses_included_in_valuation)
add_operations_cost(stock_entry, work_order, expenses_included_in_valuation)
def add_non_stock_items_cost(stock_entry, work_order, expense_account):
bom = frappe.get_doc('BOM', work_order.bom_no)
table = 'exploded_items' if work_order.get('use_multi_level_bom') else 'items'
items = {} items = {}
for d in bom.get(table): for d in bom.get(table):
items.setdefault(d.item_code, d.amount) items.setdefault(d.item_code, d.amount)
@@ -773,11 +779,35 @@ def add_additional_cost(stock_entry, work_order):
non_stock_items = frappe.get_all('Item', non_stock_items = frappe.get_all('Item',
fields="name", filters={'name': ('in', list(items.keys())), 'ifnull(is_stock_item, 0)': 0}, as_list=1) fields="name", filters={'name': ('in', list(items.keys())), 'ifnull(is_stock_item, 0)': 0}, as_list=1)
non_stock_items_cost = 0.0
for name in non_stock_items: for name in non_stock_items:
non_stock_items_cost += flt(items.get(name[0])) * flt(stock_entry.fg_completed_qty) / flt(bom.quantity)
stock_entry.append('additional_costs', {
'expense_account': expense_account,
'description': _("Non stock items"),
'amount': non_stock_items_cost
})
def add_operations_cost(stock_entry, work_order=None, expense_account=None):
from erpnext.stock.doctype.stock_entry.stock_entry import get_operating_cost_per_unit
operating_cost_per_unit = get_operating_cost_per_unit(work_order, stock_entry.bom_no)
if operating_cost_per_unit:
stock_entry.append('additional_costs', { stock_entry.append('additional_costs', {
'expense_account': expenses_included_in_valuation, "expense_account": expense_account,
'description': name[0], "description": _("Operating Cost as per Work Order / BOM"),
'amount': flt(items.get(name[0])) * flt(stock_entry.fg_completed_qty) / flt(bom.quantity) "amount": operating_cost_per_unit * flt(stock_entry.fg_completed_qty)
})
if work_order and work_order.additional_operating_cost and work_order.qty:
additional_operating_cost_per_unit = \
flt(work_order.additional_operating_cost) / flt(work_order.qty)
stock_entry.append('additional_costs', {
"expense_account": expense_account,
"description": "Additional Operating Cost",
"amount": additional_operating_cost_per_unit * flt(stock_entry.fg_completed_qty)
}) })
@frappe.whitelist() @frappe.whitelist()

View File

@@ -12,8 +12,7 @@ from erpnext.manufacturing.doctype.bom.bom import validate_bom_no, get_bom_items
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from erpnext.stock.doctype.item.item import validate_end_of_life from erpnext.stock.doctype.item.item import validate_end_of_life
from erpnext.manufacturing.doctype.workstation.workstation import WorkstationHolidayError from erpnext.manufacturing.doctype.workstation.workstation import WorkstationHolidayError
from erpnext.manufacturing.doctype.job_card.job_card import OverlapError from erpnext.projects.doctype.timesheet.timesheet import OverlapError
from erpnext.stock.doctype.stock_entry.stock_entry import get_additional_costs
from erpnext.manufacturing.doctype.manufacturing_settings.manufacturing_settings import get_mins_between_operations from erpnext.manufacturing.doctype.manufacturing_settings.manufacturing_settings import get_mins_between_operations
from erpnext.stock.stock_balance import get_planned_qty, update_bin_qty from erpnext.stock.stock_balance import get_planned_qty, update_bin_qty
from frappe.utils.csvutils import getlink from frappe.utils.csvutils import getlink
@@ -278,10 +277,11 @@ class WorkOrder(Document):
enable_capacity_planning=enable_capacity_planning, auto_create=True) enable_capacity_planning=enable_capacity_planning, auto_create=True)
if enable_capacity_planning and job_card_doc: if enable_capacity_planning and job_card_doc:
row.planned_start_time = job_card_doc.time_logs[0].from_time row.planned_start_time = job_card_doc.time_logs[-1].from_time
row.planned_end_time = job_card_doc.time_logs[-1].to_time row.planned_end_time = job_card_doc.time_logs[-1].to_time
if date_diff(row.planned_start_time, original_start_time) > plan_days: if date_diff(row.planned_start_time, original_start_time) > plan_days:
frappe.message_log.pop()
frappe.throw(_("Unable to find the time slot in the next {0} days for the operation {1}.") frappe.throw(_("Unable to find the time slot in the next {0} days for the operation {1}.")
.format(plan_days, row.operation), CapacityError) .format(plan_days, row.operation), CapacityError)
@@ -708,10 +708,6 @@ def make_stock_entry(work_order_id, purpose, qty=None):
stock_entry.from_warehouse = wip_warehouse stock_entry.from_warehouse = wip_warehouse
stock_entry.to_warehouse = work_order.fg_warehouse stock_entry.to_warehouse = work_order.fg_warehouse
stock_entry.project = work_order.project stock_entry.project = work_order.project
if purpose=="Manufacture":
additional_costs = get_additional_costs(work_order, fg_qty=stock_entry.fg_completed_qty,
company=work_order.company)
stock_entry.set("additional_costs", additional_costs)
stock_entry.set_stock_entry_type() stock_entry.set_stock_entry_type()
stock_entry.get_items() stock_entry.get_items()

View File

@@ -13,6 +13,7 @@ erpnext.patches.v4_0.apply_user_permissions
erpnext.patches.v4_0.move_warehouse_user_to_restrictions erpnext.patches.v4_0.move_warehouse_user_to_restrictions
erpnext.patches.v4_0.global_defaults_to_system_settings erpnext.patches.v4_0.global_defaults_to_system_settings
erpnext.patches.v4_0.update_incharge_name_to_sales_person_in_maintenance_schedule erpnext.patches.v4_0.update_incharge_name_to_sales_person_in_maintenance_schedule
execute:frappe.reload_doc("HR", "doctype", "HR Settings") #2020-01-16
execute:frappe.reload_doc('stock', 'doctype', 'warehouse') # 2017-04-24 execute:frappe.reload_doc('stock', 'doctype', 'warehouse') # 2017-04-24
execute:frappe.reload_doc('accounts', 'doctype', 'sales_invoice') # 2016-08-31 execute:frappe.reload_doc('accounts', 'doctype', 'sales_invoice') # 2016-08-31
execute:frappe.reload_doc('selling', 'doctype', 'sales_order') # 2014-01-29 execute:frappe.reload_doc('selling', 'doctype', 'sales_order') # 2014-01-29
@@ -513,7 +514,6 @@ erpnext.patches.v11_0.rename_employee_loan_to_loan
erpnext.patches.v11_0.move_leave_approvers_from_employee #13-06-2018 erpnext.patches.v11_0.move_leave_approvers_from_employee #13-06-2018
erpnext.patches.v11_0.update_department_lft_rgt erpnext.patches.v11_0.update_department_lft_rgt
erpnext.patches.v11_0.add_default_email_template_for_leave erpnext.patches.v11_0.add_default_email_template_for_leave
execute:frappe.reload_doc("HR", "doctype", "HR Settings")
erpnext.patches.v11_0.set_default_email_template_in_hr #08-06-2018 erpnext.patches.v11_0.set_default_email_template_in_hr #08-06-2018
erpnext.patches.v11_0.uom_conversion_data #30-06-2018 erpnext.patches.v11_0.uom_conversion_data #30-06-2018
erpnext.patches.v10_0.taxes_issue_with_pos erpnext.patches.v10_0.taxes_issue_with_pos

View File

@@ -49,12 +49,13 @@ def execute():
item_tax_template_name = get_item_tax_template(item_tax_templates, item_tax_map, item_code) item_tax_template_name = get_item_tax_template(item_tax_templates, item_tax_map, item_code)
# update the item tax table # update the item tax table
item = frappe.get_doc("Item", item_code)
item.set("taxes", [])
item.append("taxes", {"item_tax_template": item_tax_template_name, "tax_category": ""})
frappe.db.sql("delete from `tabItem Tax` where parent=%s and parenttype='Item'", item_code) frappe.db.sql("delete from `tabItem Tax` where parent=%s and parenttype='Item'", item_code)
for d in item.taxes: if item_tax_template_name:
d.db_insert() item = frappe.get_doc("Item", item_code)
item.set("taxes", [])
item.append("taxes", {"item_tax_template": item_tax_template_name, "tax_category": ""})
for d in item.taxes:
d.db_insert()
doctypes = [ doctypes = [
'Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice', 'Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice',
@@ -95,30 +96,35 @@ def get_item_tax_template(item_tax_templates, item_tax_map, item_code, parenttyp
else: else:
parts = tax_type.strip().split(" - ") parts = tax_type.strip().split(" - ")
account_name = " - ".join(parts[:-1]) account_name = " - ".join(parts[:-1])
company = get_company(parts[-1], parenttype, parent) if not account_name:
parent_account = frappe.db.get_value("Account", tax_type = None
filters={"account_type": "Tax", "root_type": "Liability", "is_group": 0, "company": company}, fieldname="parent_account") else:
if not parent_account: company = get_company(parts[-1], parenttype, parent)
parent_account = frappe.db.get_value("Account", parent_account = frappe.db.get_value("Account",
filters={"account_type": "Tax", "root_type": "Liability", "is_group": 1, "company": company}) filters={"account_type": "Tax", "root_type": "Liability", "is_group": 0, "company": company}, fieldname="parent_account")
filters = { if not parent_account:
"account_name": account_name, parent_account = frappe.db.get_value("Account",
"company": company, filters={"account_type": "Tax", "root_type": "Liability", "is_group": 1, "company": company})
"account_type": "Tax", filters = {
"parent_account": parent_account "account_name": account_name,
} "company": company,
tax_type = frappe.db.get_value("Account", filters) "account_type": "Tax",
if not tax_type: "parent_account": parent_account
account = frappe.new_doc("Account") }
account.update(filters) tax_type = frappe.db.get_value("Account", filters)
account.insert() if not tax_type:
tax_type = account.name account = frappe.new_doc("Account")
account.update(filters)
account.insert()
tax_type = account.name
item_tax_template.append("taxes", {"tax_type": tax_type, "tax_rate": tax_rate}) if tax_type:
item_tax_templates.setdefault(item_tax_template.title, {}) item_tax_template.append("taxes", {"tax_type": tax_type, "tax_rate": tax_rate})
item_tax_templates[item_tax_template.title][tax_type] = tax_rate item_tax_templates.setdefault(item_tax_template.title, {})
item_tax_template.save() item_tax_templates[item_tax_template.title][tax_type] = tax_rate
return item_tax_template.name if item_tax_template.get("taxes"):
item_tax_template.save()
return item_tax_template.name
def get_company(company_abbr, parenttype=None, parent=None): def get_company(company_abbr, parenttype=None, parent=None):
if parenttype and parent: if parenttype and parent:

View File

@@ -13,6 +13,8 @@ def execute():
frappe.reload_doc('hr', 'doctype', 'employee_tax_exemption_declaration_category') frappe.reload_doc('hr', 'doctype', 'employee_tax_exemption_declaration_category')
frappe.reload_doc('hr', 'doctype', 'employee_tax_exemption_proof_submission_detail') frappe.reload_doc('hr', 'doctype', 'employee_tax_exemption_proof_submission_detail')
frappe.reload_doc('accounts', 'doctype', 'tax_category')
for doctype in ["Sales Invoice", "Delivery Note", "Purchase Invoice"]: for doctype in ["Sales Invoice", "Delivery Note", "Purchase Invoice"]:
frappe.db.sql("""delete from `tabCustom Field` where dt = %s frappe.db.sql("""delete from `tabCustom Field` where dt = %s
and fieldname in ('port_code', 'shipping_bill_number', 'shipping_bill_date')""", doctype) and fieldname in ('port_code', 'shipping_bill_number', 'shipping_bill_date')""", doctype)
@@ -29,4 +31,4 @@ def execute():
update tabAddress update tabAddress
set gst_state_number=concat("0", gst_state_number) set gst_state_number=concat("0", gst_state_number)
where ifnull(gst_state_number, '') != '' and gst_state_number<10 where ifnull(gst_state_number, '') != '' and gst_state_number<10
""") """)

View File

@@ -240,7 +240,7 @@ def create_supplier(supplier_group, args):
if not frappe.get_list("Contact", filters): if not frappe.get_list("Contact", filters):
new_contact = frappe.new_doc("Contact") new_contact = frappe.new_doc("Contact")
new_contact.first_name = args.supplier new_contact.first_name = args.supplier[:30]
new_contact.append('links', { new_contact.append('links', {
"link_doctype": "Supplier", "link_doctype": "Supplier",
"link_name": existing_supplier_name "link_name": existing_supplier_name
@@ -251,7 +251,7 @@ def create_supplier(supplier_group, args):
else: else:
new_supplier = frappe.new_doc("Supplier") new_supplier = frappe.new_doc("Supplier")
new_supplier.supplier_name = args.supplier new_supplier.supplier_name = re.sub('&amp', '&', args.supplier)
new_supplier.supplier_group = supplier_group new_supplier.supplier_group = supplier_group
new_supplier.tax_id = args.tax_id new_supplier.tax_id = args.tax_id
new_supplier.fiscal_code = args.fiscal_code new_supplier.fiscal_code = args.fiscal_code
@@ -259,7 +259,7 @@ def create_supplier(supplier_group, args):
new_supplier.save() new_supplier.save()
new_contact = frappe.new_doc("Contact") new_contact = frappe.new_doc("Contact")
new_contact.first_name = args.supplier new_contact.first_name = args.supplier[:30]
new_contact.append('links', { new_contact.append('links', {
"link_doctype": "Supplier", "link_doctype": "Supplier",
"link_name": new_supplier.name "link_name": new_supplier.name

View File

@@ -103,7 +103,7 @@ frappe.ui.form.on("Customer", {
} }
frappe.dynamic_link = {doc: frm.doc, fieldname: 'name', doctype: 'Customer'} frappe.dynamic_link = {doc: frm.doc, fieldname: 'name', doctype: 'Customer'}
frm.toggle_display(['address_html','contact_html','primary_address_and_contact_detail'], !frm.doc.__islocal); frm.toggle_display(['address_html','contact_html'], !frm.doc.__islocal);
if(!frm.doc.__islocal) { if(!frm.doc.__islocal) {
frappe.contacts.render_address_and_contact(frm); frappe.contacts.render_address_and_contact(frm);

View File

@@ -1,4 +1,5 @@
{ {
"actions": [],
"autoname": "hash", "autoname": "hash",
"creation": "2013-03-07 11:42:58", "creation": "2013-03-07 11:42:58",
"doctype": "DocType", "doctype": "DocType",
@@ -151,6 +152,7 @@
"width": "300px" "width": "300px"
}, },
{ {
"allow_on_submit": 1,
"columns": 2, "columns": 2,
"depends_on": "eval: !parent.skip_delivery_note", "depends_on": "eval: !parent.skip_delivery_note",
"fieldname": "delivery_date", "fieldname": "delivery_date",
@@ -767,7 +769,8 @@
], ],
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"modified": "2019-12-12 18:06:26.238169", "links": [],
"modified": "2020-01-13 12:29:03.103797",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Selling", "module": "Selling",
"name": "Sales Order Item", "name": "Sales Order Item",

View File

@@ -76,7 +76,7 @@ class AuthorizationControl(TransactionBase):
add_cond = '' add_cond = ''
auth_value = av_dis auth_value = av_dis
if val == 1: add_cond += " and system_user = '"+ frappe.db.escape(session['user'])+"'" if val == 1: add_cond += " and system_user = {}".format(frappe.db.escape(session['user']))
elif val == 2: add_cond += " and system_role IN %s" % ("('"+"','".join(frappe.get_roles())+"')") elif val == 2: add_cond += " and system_role IN %s" % ("('"+"','".join(frappe.get_roles())+"')")
else: add_cond += " and ifnull(system_user,'') = '' and ifnull(system_role,'') = ''" else: add_cond += " and ifnull(system_user,'') = '' and ifnull(system_role,'') = ''"
@@ -85,7 +85,7 @@ class AuthorizationControl(TransactionBase):
if doc_obj: if doc_obj:
if doc_obj.doctype == 'Sales Invoice': customer = doc_obj.customer if doc_obj.doctype == 'Sales Invoice': customer = doc_obj.customer
else: customer = doc_obj.customer_name else: customer = doc_obj.customer_name
add_cond = " and master_name = '"+ frappe.db.escape(customer) +"'" add_cond = " and master_name = {}".format(frappe.db.escape(customer))
if based_on == 'Itemwise Discount': if based_on == 'Itemwise Discount':
if doc_obj: if doc_obj:
for t in doc_obj.get("items"): for t in doc_obj.get("items"):

View File

@@ -436,7 +436,7 @@ def make_sales_invoice(source_name, target_doc=None):
def update_item(source_doc, target_doc, source_parent): def update_item(source_doc, target_doc, source_parent):
target_doc.qty = to_make_invoice_qty_map[source_doc.name] target_doc.qty = to_make_invoice_qty_map[source_doc.name]
if source_doc.serial_no and source_parent.per_billed > 0: if source_doc.serial_no and source_parent.per_billed > 0 and not source_parent.is_return:
target_doc.serial_no = get_delivery_note_serial_no(source_doc.item_code, target_doc.serial_no = get_delivery_note_serial_no(source_doc.item_code,
target_doc.qty, source_parent.name) target_doc.qty, source_parent.name)

View File

@@ -230,8 +230,19 @@ frappe.ui.form.on('Material Request', {
make_purchase_order: function(frm) { make_purchase_order: function(frm) {
frappe.prompt( frappe.prompt(
{fieldname:'default_supplier', label: __('For Default Supplier (optional)'), description: __('Selected Supplier\ {
must be the Default Supplier of one of the items below.'), fieldtype: 'Link', options: 'Supplier'}, label: __('For Default Supplier (Optional)'),
fieldname:'default_supplier',
fieldtype: 'Link',
options: 'Supplier',
description: __('Select a Supplier from the Default Supplier List of the items below.'),
get_query: () => {
return{
query: "erpnext.stock.doctype.material_request.material_request.get_default_supplier_query",
filters: {'doc': frm.doc.name}
}
}
},
(values) => { (values) => {
frappe.model.open_mapped_doc({ frappe.model.open_mapped_doc({
method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order", method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order",

View File

@@ -386,6 +386,18 @@ def get_material_requests_based_on_supplier(supplier):
return material_requests, supplier_items return material_requests, supplier_items
def get_default_supplier_query(doctype, txt, searchfield, start, page_len, filters):
doc = frappe.get_doc("Material Request", filters.get("doc"))
item_list = []
for d in doc.items:
item_list.append(d.item_code)
return frappe.db.sql("""select default_supplier
from `tabItem Default`
where parent in ({0}) and
default_supplier IS NOT NULL
""".format(', '.join(['%s']*len(item_list))),tuple(item_list))
@frappe.whitelist() @frappe.whitelist()
def make_supplier_quotation(source_name, target_doc=None): def make_supplier_quotation(source_name, target_doc=None):
def postprocess(source, target_doc): def postprocess(source, target_doc):

View File

@@ -478,15 +478,17 @@ class StockEntry(StockController):
def set_basic_rate_for_finished_goods(self, raw_material_cost, scrap_material_cost): def set_basic_rate_for_finished_goods(self, raw_material_cost, scrap_material_cost):
if self.purpose in ["Manufacture", "Repack"]: if self.purpose in ["Manufacture", "Repack"]:
for d in self.get("items"): for d in self.get("items"):
if (d.transfer_qty and (d.bom_no or d.t_warehouse) and raw_material_cost if (d.transfer_qty and (d.bom_no or d.t_warehouse)
and (getattr(self, "pro_doc", frappe._dict()).scrap_warehouse != d.t_warehouse)): and (getattr(self, "pro_doc", frappe._dict()).scrap_warehouse != d.t_warehouse)):
d.basic_rate = flt((raw_material_cost - scrap_material_cost) / flt(d.transfer_qty), d.precision("basic_rate"))
d.basic_amount = flt((raw_material_cost - scrap_material_cost), d.precision("basic_amount"))
if (not d.basic_rate and self.work_order and if self.work_order \
frappe.db.get_single_value("Manufacturing Settings", "material_consumption")): and frappe.db.get_single_value("Manufacturing Settings", "material_consumption"):
d.basic_rate = get_valuation_rate_for_finished_good_entry(self.work_order) or 0 bom_items = self.get_bom_raw_materials(d.transfer_qty)
d.basic_amount = d.basic_rate * d.qty raw_material_cost = sum([flt(d.qty)*flt(d.rate) for d in bom_items.values()])
if raw_material_cost:
d.basic_rate = flt((raw_material_cost - scrap_material_cost) / flt(d.transfer_qty), d.precision("basic_rate"))
d.basic_amount = flt((raw_material_cost - scrap_material_cost), d.precision("basic_amount"))
def distribute_additional_costs(self): def distribute_additional_costs(self):
if self.purpose == "Material Issue": if self.purpose == "Material Issue":
@@ -1403,30 +1405,6 @@ def get_work_order_details(work_order, company):
"additional_costs": get_additional_costs(work_order, fg_qty=pending_qty_to_produce, company=company) "additional_costs": get_additional_costs(work_order, fg_qty=pending_qty_to_produce, company=company)
} }
def get_additional_costs(work_order=None, bom_no=None, fg_qty=None, company=None):
additional_costs = []
operating_cost_per_unit = get_operating_cost_per_unit(work_order, bom_no)
expenses_included_in_valuation = frappe.get_cached_value("Company", company, "expenses_included_in_valuation")
if operating_cost_per_unit:
additional_costs.append({
"expense_account": expenses_included_in_valuation,
"description": "Operating Cost as per Work Order / BOM",
"amount": operating_cost_per_unit * flt(fg_qty)
})
if work_order and work_order.additional_operating_cost and work_order.qty:
additional_operating_cost_per_unit = \
flt(work_order.additional_operating_cost) / flt(work_order.qty)
additional_costs.append({
"expense_account": expenses_included_in_valuation,
"description": "Additional Operating Cost",
"amount": additional_operating_cost_per_unit * flt(fg_qty)
})
return additional_costs
def get_operating_cost_per_unit(work_order=None, bom_no=None): def get_operating_cost_per_unit(work_order=None, bom_no=None):
operating_cost_per_unit = 0 operating_cost_per_unit = 0
if work_order: if work_order:

View File

@@ -610,7 +610,7 @@ def get_item_price(args, item_code, ignore_party=False):
return frappe.db.sql(""" select name, price_list_rate, uom return frappe.db.sql(""" select name, price_list_rate, uom
from `tabItem Price` {conditions} from `tabItem Price` {conditions}
order by uom desc, min_qty desc, valid_from desc """.format(conditions=conditions), args) order by valid_from desc, min_qty desc, uom desc """.format(conditions=conditions), args)
def get_price_list_rate_for(args, item_code): def get_price_list_rate_for(args, item_code):
""" """
@@ -632,7 +632,8 @@ def get_price_list_rate_for(args, item_code):
"customer": args.get('customer'), "customer": args.get('customer'),
"supplier": args.get('supplier'), "supplier": args.get('supplier'),
"uom": args.get('uom'), "uom": args.get('uom'),
"min_qty": args.get('qty'), "min_qty": args.get('qty') if args.get('price_list_uom_dependant')\
else flt(args.get('qty')) * flt(args.get("conversion_factor", 1)),
"transaction_date": args.get('transaction_date'), "transaction_date": args.get('transaction_date'),
} }
@@ -646,8 +647,8 @@ def get_price_list_rate_for(args, item_code):
for field in ["customer", "supplier"]: for field in ["customer", "supplier"]:
del item_price_args[field] del item_price_args[field]
general_price_list_rate = get_item_price(item_price_args, item_code, ignore_party=args.get("ignore_party")) general_price_list_rate = get_item_price(item_price_args, item_code,
ignore_party=args.get("ignore_party"))
if not general_price_list_rate: if not general_price_list_rate:
del item_price_args["min_qty"] del item_price_args["min_qty"]
general_price_list_rate = get_item_price(item_price_args, item_code, ignore_party=args.get("ignore_party")) general_price_list_rate = get_item_price(item_price_args, item_code, ignore_party=args.get("ignore_party"))

View File

@@ -43,7 +43,7 @@ def get_data(report_filters):
def get_stock_ledger_data(report_filters, filters): def get_stock_ledger_data(report_filters, filters):
if report_filters.account: if report_filters.account:
warehouses = get_warehouses_based_on_account(report_filters.account, warehouses = get_warehouses_based_on_account(report_filters.account,
report_filters.warehouse) report_filters.company)
filters["warehouse"] = ("in", warehouses) filters["warehouse"] = ("in", warehouses)

View File

@@ -3432,7 +3432,7 @@ apps/erpnext/erpnext/accounts/doctype/bank_transaction/bank_transaction.py,The t
DocType: Landed Cost Voucher,Distribute Charges Based On,Kosten auf folgender Grundlage verteilen DocType: Landed Cost Voucher,Distribute Charges Based On,Kosten auf folgender Grundlage verteilen
DocType: Projects Settings,Timesheets,Zeiterfassungen DocType: Projects Settings,Timesheets,Zeiterfassungen
DocType: HR Settings,HR Settings,Einstellungen zum Modul Personalwesen DocType: HR Settings,HR Settings,Einstellungen zum Modul Personalwesen
apps/erpnext/erpnext/config/accounting.py,Accounting Masters,Accounting Masters apps/erpnext/erpnext/config/accounting.py,Accounting Masters,Buchhaltungsstammdaten
DocType: Salary Slip,net pay info,Netto-Zahlung Info DocType: Salary Slip,net pay info,Netto-Zahlung Info
apps/erpnext/erpnext/regional/report/eway_bill/eway_bill.py,CESS Amount,CESS-Betrag apps/erpnext/erpnext/regional/report/eway_bill/eway_bill.py,CESS Amount,CESS-Betrag
DocType: Woocommerce Settings,Enable Sync,Aktivieren Sie die Synchronisierung DocType: Woocommerce Settings,Enable Sync,Aktivieren Sie die Synchronisierung
Can't render this file because it is too large.