Merge branch 'develop' into fix-remaining-leave-balance-calculation

This commit is contained in:
Anurag Mishra 2020-01-20 19:41:33 +05:30 committed by GitHub
commit 85e5ba9698
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 806 additions and 2007 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

@ -57,7 +57,7 @@
"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",

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

@ -307,7 +307,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'
}) })

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,9 +81,9 @@ 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:
@ -98,7 +98,7 @@ class SalaryStructure(Document):
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
@ -129,8 +130,8 @@ 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)))

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,37 @@ 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)
if non_stock_items_cost:
stock_entry.append('additional_costs', { stock_entry.append('additional_costs', {
'expense_account': expenses_included_in_valuation, 'expense_account': expense_account,
'description': name[0], 'description': _("Non stock items"),
'amount': flt(items.get(name[0])) * flt(stock_entry.fg_completed_qty) / flt(bom.quantity) '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', {
"expense_account": expense_account,
"description": _("Operating Cost as per Work Order / BOM"),
"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)
if additional_operating_cost_per_unit:
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,10 +49,11 @@ 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
frappe.db.sql("delete from `tabItem Tax` where parent=%s and parenttype='Item'", item_code)
if item_tax_template_name:
item = frappe.get_doc("Item", item_code) item = frappe.get_doc("Item", item_code)
item.set("taxes", []) item.set("taxes", [])
item.append("taxes", {"item_tax_template": item_tax_template_name, "tax_category": ""}) 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)
for d in item.taxes: for d in item.taxes:
d.db_insert() d.db_insert()
@ -95,6 +96,9 @@ 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])
if not account_name:
tax_type = None
else:
company = get_company(parts[-1], parenttype, parent) 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": 0, "company": company}, fieldname="parent_account") filters={"account_type": "Tax", "root_type": "Liability", "is_group": 0, "company": company}, fieldname="parent_account")
@ -114,9 +118,11 @@ def get_item_tax_template(item_tax_templates, item_tax_map, item_code, parenttyp
account.insert() account.insert()
tax_type = account.name tax_type = account.name
if tax_type:
item_tax_template.append("taxes", {"tax_type": tax_type, "tax_rate": tax_rate}) item_tax_template.append("taxes", {"tax_type": tax_type, "tax_rate": tax_rate})
item_tax_templates.setdefault(item_tax_template.title, {}) item_tax_templates.setdefault(item_tax_template.title, {})
item_tax_templates[item_tax_template.title][tax_type] = tax_rate item_tax_templates[item_tax_template.title][tax_type] = tax_rate
if item_tax_template.get("taxes"):
item_tax_template.save() item_tax_template.save()
return item_tax_template.name return item_tax_template.name

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)

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

@ -51,7 +51,7 @@ class ItemPrice(Document):
def check_duplicates(self): def check_duplicates(self):
conditions = "where item_code=%(item_code)s and price_list=%(price_list)s and name != %(name)s" conditions = "where item_code=%(item_code)s and price_list=%(price_list)s and name != %(name)s"
for field in ['uom', 'min_qty', 'valid_from', for field in ['uom', 'valid_from',
'valid_upto', 'packing_unit', 'customer', 'supplier']: 'valid_upto', 'packing_unit', 'customer', 'supplier']:
if self.get(field): if self.get(field):
conditions += " and {0} = %({1})s".format(field, field) conditions += " and {0} = %({1})s".format(field, field)

View File

@ -21,7 +21,7 @@ class TestItemPrice(unittest.TestCase):
def test_addition_of_new_fields(self): def test_addition_of_new_fields(self):
# Based on https://github.com/frappe/erpnext/issues/8456 # Based on https://github.com/frappe/erpnext/issues/8456
test_fields_existance = [ test_fields_existance = [
'supplier', 'customer', 'uom', 'min_qty', 'lead_time_days', 'supplier', 'customer', 'uom', 'lead_time_days',
'packing_unit', 'valid_from', 'valid_upto', 'note' 'packing_unit', 'valid_from', 'valid_upto', 'note'
] ]
doc_fields = frappe.copy_doc(test_records[1]).__dict__.keys() doc_fields = frappe.copy_doc(test_records[1]).__dict__.keys()
@ -43,7 +43,6 @@ class TestItemPrice(unittest.TestCase):
args = { args = {
"price_list": doc.price_list, "price_list": doc.price_list,
"min_qty": doc.min_qty,
"customer": doc.customer, "customer": doc.customer,
"uom": "_Test UOM", "uom": "_Test UOM",
"transaction_date": '2017-04-18', "transaction_date": '2017-04-18',
@ -58,7 +57,6 @@ class TestItemPrice(unittest.TestCase):
doc = frappe.copy_doc(test_records[2]) doc = frappe.copy_doc(test_records[2])
args = { args = {
"price_list": doc.price_list, "price_list": doc.price_list,
"min_qty": 30,
"customer": doc.customer, "customer": doc.customer,
"uom": "_Test UOM", "uom": "_Test UOM",
"transaction_date": '2017-04-18', "transaction_date": '2017-04-18',
@ -74,7 +72,6 @@ class TestItemPrice(unittest.TestCase):
args = { args = {
"price_list": doc.price_list, "price_list": doc.price_list,
"min_qty": doc.min_qty,
"customer": "_Test Customer", "customer": "_Test Customer",
"uom": "_Test UOM", "uom": "_Test UOM",
"transaction_date": '2017-04-18', "transaction_date": '2017-04-18',
@ -90,7 +87,6 @@ class TestItemPrice(unittest.TestCase):
args = { args = {
"price_list": doc.price_list, "price_list": doc.price_list,
"min_qty": doc.min_qty,
"qty": 7, "qty": 7,
"uom": "_Test UOM", "uom": "_Test UOM",
"transaction_date": "01-15-2019" "transaction_date": "01-15-2019"
@ -105,7 +101,6 @@ class TestItemPrice(unittest.TestCase):
args = { args = {
"price_list": doc.price_list, "price_list": doc.price_list,
"min_qty": doc.min_qty,
"customer": "_Test Customer", "customer": "_Test Customer",
"uom": "_Test UOM", "uom": "_Test UOM",
"transaction_date": "2017-04-25", "transaction_date": "2017-04-25",
@ -121,7 +116,6 @@ class TestItemPrice(unittest.TestCase):
args = { args = {
"price_list": doc.price_list, "price_list": doc.price_list,
"min_qty": doc.min_qty,
"uom": "_Test UOM", "uom": "_Test UOM",
"qty": 7, "qty": 7,
} }

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

@ -840,18 +840,10 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
if (me.frm.doc.purpose == "Manufacture" || me.frm.doc.purpose == "Material Consumption for Manufacture" ) { if (me.frm.doc.purpose == "Manufacture" || me.frm.doc.purpose == "Material Consumption for Manufacture" ) {
if (me.frm.doc.purpose == "Manufacture") { if (me.frm.doc.purpose == "Manufacture") {
if (!me.frm.doc.to_warehouse) me.frm.set_value("to_warehouse", r.message["fg_warehouse"]); if (!me.frm.doc.to_warehouse) me.frm.set_value("to_warehouse", r.message["fg_warehouse"]);
if (r.message["additional_costs"].length) {
me.frm.clear_table("additional_costs");
$.each(r.message["additional_costs"], function(i, row) {
me.frm.add_child("additional_costs", row);
})
refresh_field("additional_costs");
}
} }
if (!me.frm.doc.from_warehouse) me.frm.set_value("from_warehouse", r.message["wip_warehouse"]); if (!me.frm.doc.from_warehouse) me.frm.set_value("from_warehouse", r.message["wip_warehouse"]);
} }
me.get_items() me.get_items();
} }
} }
}); });

View File

@ -478,16 +478,18 @@ 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)):
if self.work_order \
and frappe.db.get_single_value("Manufacturing Settings", "material_consumption"):
bom_items = self.get_bom_raw_materials(d.transfer_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_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")) d.basic_amount = flt((raw_material_cost - scrap_material_cost), d.precision("basic_amount"))
if (not d.basic_rate and self.work_order 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
d.basic_amount = d.basic_rate * d.qty
def distribute_additional_costs(self): def distribute_additional_costs(self):
if self.purpose == "Material Issue": if self.purpose == "Material Issue":
self.additional_costs = [] self.additional_costs = []
@ -680,6 +682,8 @@ class StockEntry(StockController):
if item_account_wise_additional_cost: if item_account_wise_additional_cost:
for d in self.get("items"): for d in self.get("items"):
for account, amount in iteritems(item_account_wise_additional_cost.get((d.item_code, d.name), {})): for account, amount in iteritems(item_account_wise_additional_cost.get((d.item_code, d.name), {})):
if not amount: continue
gl_entries.append(self.get_gl_dict({ gl_entries.append(self.get_gl_dict({
"account": account, "account": account,
"against": d.expense_account, "against": d.expense_account,
@ -1399,34 +1403,9 @@ def get_work_order_details(work_order, company):
"use_multi_level_bom": work_order.use_multi_level_bom, "use_multi_level_bom": work_order.use_multi_level_bom,
"wip_warehouse": work_order.wip_warehouse, "wip_warehouse": work_order.wip_warehouse,
"fg_warehouse": work_order.fg_warehouse, "fg_warehouse": work_order.fg_warehouse,
"fg_completed_qty": pending_qty_to_produce, "fg_completed_qty": pending_qty_to_produce
"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

@ -583,7 +583,7 @@ def get_item_price(args, item_code, ignore_party=False):
Get name, price_list_rate from Item Price based on conditions Get name, price_list_rate from Item Price based on conditions
Check if the desired qty is within the increment of the packing list. Check if the desired qty is within the increment of the packing list.
:param args: dict (or frappe._dict) with mandatory fields price_list, uom :param args: dict (or frappe._dict) with mandatory fields price_list, uom
optional fields min_qty, transaction_date, customer, supplier optional fields transaction_date, customer, supplier
:param item_code: str, Item Doctype field item_code :param item_code: str, Item Doctype field item_code
""" """
@ -601,24 +601,16 @@ def get_item_price(args, item_code, ignore_party=False):
else: else:
conditions += " and (customer is null or customer = '') and (supplier is null or supplier = '')" conditions += " and (customer is null or customer = '') and (supplier is null or supplier = '')"
if args.get('min_qty'):
conditions += " and ifnull(min_qty, 0) <= %(min_qty)s"
if args.get('transaction_date'): if args.get('transaction_date'):
conditions += """ and %(transaction_date)s between conditions += """ and %(transaction_date)s between
ifnull(valid_from, '2000-01-01') and ifnull(valid_upto, '2500-12-31')""" ifnull(valid_from, '2000-01-01') and ifnull(valid_upto, '2500-12-31')"""
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, uom desc """.format(conditions=conditions), args)
def get_price_list_rate_for(args, item_code): def get_price_list_rate_for(args, item_code):
""" """
Return Price Rate based on min_qty of each Item Price Rate.\
For example, desired qty is 10 and Item Price Rates exists
for min_qty 9 and min_qty 20. It returns Item Price Rate for qty 9 as
the best fit in the range of avaliable min_qtyies
:param customer: link to Customer DocType :param customer: link to Customer DocType
:param supplier: link to Supplier DocType :param supplier: link to Supplier DocType
:param price_list: str (Standard Buying or Standard Selling) :param price_list: str (Standard Buying or Standard Selling)
@ -632,7 +624,6 @@ 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'),
"transaction_date": args.get('transaction_date'), "transaction_date": args.get('transaction_date'),
} }
@ -646,11 +637,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:
del item_price_args["min_qty"]
general_price_list_rate = get_item_price(item_price_args, item_code, ignore_party=args.get("ignore_party"))
if not general_price_list_rate and args.get("uom") != args.get("stock_uom"): if not general_price_list_rate and args.get("uom") != args.get("stock_uom"):
item_price_args["uom"] = args.get("stock_uom") item_price_args["uom"] = args.get("stock_uom")

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.