Merge branch 'develop' into version-13-beta-pre-release
This commit is contained in:
commit
13dc63499a
@ -25,7 +25,7 @@ class AssetValueAdjustment(Document):
|
||||
frappe.throw(_("Cancel the journal entry {0} first").format(self.journal_entry))
|
||||
|
||||
self.reschedule_depreciations(self.current_asset_value)
|
||||
|
||||
|
||||
def validate_date(self):
|
||||
asset_purchase_date = frappe.db.get_value('Asset', self.asset, 'purchase_date')
|
||||
if getdate(self.date) < getdate(asset_purchase_date):
|
||||
@ -53,6 +53,7 @@ class AssetValueAdjustment(Document):
|
||||
je.posting_date = self.date
|
||||
je.company = self.company
|
||||
je.remark = "Depreciation Entry against {0} worth {1}".format(self.asset, self.difference_amount)
|
||||
je.finance_book = self.finance_book
|
||||
|
||||
credit_entry = {
|
||||
"account": accumulated_depreciation_account,
|
||||
@ -78,7 +79,7 @@ class AssetValueAdjustment(Document):
|
||||
debit_entry.update({
|
||||
dimension['fieldname']: self.get(dimension['fieldname']) or dimension.get('default_dimension')
|
||||
})
|
||||
|
||||
|
||||
je.append("accounts", credit_entry)
|
||||
je.append("accounts", debit_entry)
|
||||
|
||||
|
@ -254,22 +254,26 @@ class StatusUpdater(Document):
|
||||
if not args.get("second_source_extra_cond"):
|
||||
args["second_source_extra_cond"] = ""
|
||||
|
||||
args['second_source_condition'] = """ + ifnull((select sum(%(second_source_field)s)
|
||||
args['second_source_condition'] = frappe.db.sql(""" select ifnull((select sum(%(second_source_field)s)
|
||||
from `tab%(second_source_dt)s`
|
||||
where `%(second_join_field)s`="%(detail_id)s"
|
||||
and (`tab%(second_source_dt)s`.docstatus=1) %(second_source_extra_cond)s FOR UPDATE), 0)""" % args
|
||||
and (`tab%(second_source_dt)s`.docstatus=1)
|
||||
%(second_source_extra_cond)s), 0) """ % args)[0][0]
|
||||
|
||||
if args['detail_id']:
|
||||
if not args.get("extra_cond"): args["extra_cond"] = ""
|
||||
|
||||
frappe.db.sql("""update `tab%(target_dt)s`
|
||||
set %(target_field)s = (
|
||||
args["source_dt_value"] = frappe.db.sql("""
|
||||
(select ifnull(sum(%(source_field)s), 0)
|
||||
from `tab%(source_dt)s` where `%(join_field)s`="%(detail_id)s"
|
||||
and (docstatus=1 %(cond)s) %(extra_cond)s)
|
||||
%(second_source_condition)s
|
||||
)
|
||||
%(update_modified)s
|
||||
""" % args)[0][0] or 0.0
|
||||
|
||||
if args['second_source_condition']:
|
||||
args["source_dt_value"] += flt(args['second_source_condition'])
|
||||
|
||||
frappe.db.sql("""update `tab%(target_dt)s`
|
||||
set %(target_field)s = %(source_dt_value)s %(update_modified)s
|
||||
where name='%(detail_id)s'""" % args)
|
||||
|
||||
def _update_percent_field_in_targets(self, args, update_modified=True):
|
||||
|
@ -260,6 +260,15 @@ def update_taxes_with_shipping_lines(taxes, shipping_lines, shopify_settings):
|
||||
"""Shipping lines represents the shipping details,
|
||||
each such shipping detail consists of a list of tax_lines"""
|
||||
for shipping_charge in shipping_lines:
|
||||
if shipping_charge.get("price"):
|
||||
taxes.append({
|
||||
"charge_type": _("Actual"),
|
||||
"account_head": get_tax_account_head(shipping_charge),
|
||||
"description": shipping_charge["title"],
|
||||
"tax_amount": shipping_charge["price"],
|
||||
"cost_center": shopify_settings.cost_center
|
||||
})
|
||||
|
||||
for tax in shipping_charge.get("tax_lines"):
|
||||
taxes.append({
|
||||
"charge_type": _("Actual"),
|
||||
|
@ -491,6 +491,39 @@ class TestWorkOrder(unittest.TestCase):
|
||||
work_order1.save()
|
||||
self.assertEqual(work_order1.operations[0].time_in_mins, 40.0)
|
||||
|
||||
def test_partial_material_consumption(self):
|
||||
frappe.db.set_value("Manufacturing Settings", None, "material_consumption", 1)
|
||||
wo_order = make_wo_order_test_record(planned_start_date=now(), qty=4)
|
||||
|
||||
ste_cancel_list = []
|
||||
ste1 = test_stock_entry.make_stock_entry(item_code="_Test Item",
|
||||
target="_Test Warehouse - _TC", qty=20, basic_rate=5000.0)
|
||||
ste2 = test_stock_entry.make_stock_entry(item_code="_Test Item Home Desktop 100",
|
||||
target="_Test Warehouse - _TC", qty=20, basic_rate=1000.0)
|
||||
|
||||
ste_cancel_list.extend([ste1, ste2])
|
||||
|
||||
s = frappe.get_doc(make_stock_entry(wo_order.name, "Material Transfer for Manufacture", 4))
|
||||
s.submit()
|
||||
ste_cancel_list.append(s)
|
||||
|
||||
ste1 = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 2))
|
||||
ste1.submit()
|
||||
ste_cancel_list.append(ste1)
|
||||
|
||||
print(wo_order.name)
|
||||
ste3 = frappe.get_doc(make_stock_entry(wo_order.name, "Material Consumption for Manufacture", 2))
|
||||
self.assertEquals(ste3.fg_completed_qty, 2)
|
||||
|
||||
expected_qty = {"_Test Item": 2, "_Test Item Home Desktop 100": 4}
|
||||
for row in ste3.items:
|
||||
self.assertEquals(row.qty, expected_qty.get(row.item_code))
|
||||
|
||||
for ste_doc in ste_cancel_list:
|
||||
ste_doc.cancel()
|
||||
|
||||
frappe.db.set_value("Manufacturing Settings", None, "material_consumption", 0)
|
||||
|
||||
def get_scrap_item_details(bom_no):
|
||||
scrap_items = {}
|
||||
for item in frappe.db.sql("""select item_code, stock_qty from `tabBOM Scrap Item`
|
||||
|
@ -545,7 +545,8 @@ erpnext.work_order = {
|
||||
var tbl = frm.doc.required_items || [];
|
||||
var tbl_lenght = tbl.length;
|
||||
for (var i = 0, len = tbl_lenght; i < len; i++) {
|
||||
if (flt(frm.doc.required_items[i].required_qty) > flt(frm.doc.required_items[i].consumed_qty)) {
|
||||
let wo_item_qty = frm.doc.required_items[i].transferred_qty || frm.doc.required_items[i].required_qty;
|
||||
if (flt(wo_item_qty) > flt(frm.doc.required_items[i].consumed_qty)) {
|
||||
counter += 1;
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ from frappe.utils import nowdate
|
||||
from erpnext.accounts.doctype.account.test_account import create_account
|
||||
from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_term_loans
|
||||
from erpnext.loan_management.doctype.loan.loan import make_repayment_entry
|
||||
from erpnext.loan_management.doctype.loan_repayment.loan_repayment import get_accrued_interest_entries
|
||||
from frappe.model.naming import make_autoname
|
||||
|
||||
def execute():
|
||||
|
||||
@ -18,15 +20,29 @@ def execute():
|
||||
frappe.reload_doc('loan_management', 'doctype', 'loan_repayment_detail')
|
||||
frappe.reload_doc('loan_management', 'doctype', 'loan_interest_accrual')
|
||||
frappe.reload_doc('accounts', 'doctype', 'gl_entry')
|
||||
frappe.reload_doc('accounts', 'doctype', 'journal_entry_account')
|
||||
|
||||
updated_loan_types = []
|
||||
loans_to_close = []
|
||||
|
||||
# Update old loan status as closed
|
||||
if frappe.db.has_column('Repayment Schedule', 'paid'):
|
||||
loans_list = frappe.db.sql("""SELECT distinct parent from `tabRepayment Schedule`
|
||||
where paid = 0 and docstatus = 1""", as_dict=1)
|
||||
|
||||
loans_to_close = [d.parent for d in loans_list]
|
||||
|
||||
if loans_to_close:
|
||||
frappe.db.sql("UPDATE `tabLoan` set status = 'Closed' where name not in (%s)" % (', '.join(['%s'] * len(loans_to_close))), tuple(loans_to_close))
|
||||
|
||||
loans = frappe.get_all('Loan', fields=['name', 'loan_type', 'company', 'status', 'mode_of_payment',
|
||||
'applicant_type', 'applicant', 'loan_account', 'payment_account', 'interest_income_account'])
|
||||
'applicant_type', 'applicant', 'loan_account', 'payment_account', 'interest_income_account'],
|
||||
filters={'docstatus': 1, 'status': ('!=', 'Closed')})
|
||||
|
||||
for loan in loans:
|
||||
# Update details in Loan Types and Loan
|
||||
loan_type_company = frappe.db.get_value('Loan Type', loan.loan_type, 'company')
|
||||
loan_type = loan.loan_type
|
||||
|
||||
group_income_account = frappe.get_value('Account', {'company': loan.company,
|
||||
'is_group': 1, 'root_type': 'Income', 'account_name': _('Indirect Income')})
|
||||
@ -38,7 +54,26 @@ def execute():
|
||||
penalty_account = create_account(company=loan.company, account_type='Income Account',
|
||||
account_name='Penalty Account', parent_account=group_income_account)
|
||||
|
||||
if not loan_type_company:
|
||||
# Same loan type used for multiple companies
|
||||
if loan_type_company and loan_type_company != loan.company:
|
||||
# get loan type for appropriate company
|
||||
loan_type_name = frappe.get_value('Loan Type', {'company': loan.company,
|
||||
'mode_of_payment': loan.mode_of_payment, 'loan_account': loan.loan_account,
|
||||
'payment_account': loan.payment_account, 'interest_income_account': loan.interest_income_account,
|
||||
'penalty_income_account': loan.penalty_income_account}, 'name')
|
||||
|
||||
if not loan_type_name:
|
||||
loan_type_name = create_loan_type(loan, loan_type_name, penalty_account)
|
||||
|
||||
# update loan type in loan
|
||||
frappe.db.sql("UPDATE `tabLoan` set loan_type = %s where name = %s", (loan_type_name,
|
||||
loan.name))
|
||||
|
||||
loan_type = loan_type_name
|
||||
if loan_type_name not in updated_loan_types:
|
||||
updated_loan_types.append(loan_type_name)
|
||||
|
||||
elif not loan_type_company:
|
||||
loan_type_doc = frappe.get_doc('Loan Type', loan.loan_type)
|
||||
loan_type_doc.is_term_loan = 1
|
||||
loan_type_doc.company = loan.company
|
||||
@ -49,8 +84,9 @@ def execute():
|
||||
loan_type_doc.penalty_income_account = penalty_account
|
||||
loan_type_doc.submit()
|
||||
updated_loan_types.append(loan.loan_type)
|
||||
loan_type = loan.loan_type
|
||||
|
||||
if loan.loan_type in updated_loan_types:
|
||||
if loan_type in updated_loan_types:
|
||||
if loan.status == 'Fully Disbursed':
|
||||
status = 'Disbursed'
|
||||
elif loan.status == 'Repaid/Closed':
|
||||
@ -64,25 +100,48 @@ def execute():
|
||||
'status': status
|
||||
})
|
||||
|
||||
process_loan_interest_accrual_for_term_loans(posting_date=nowdate(), loan_type=loan.loan_type,
|
||||
process_loan_interest_accrual_for_term_loans(posting_date=nowdate(), loan_type=loan_type,
|
||||
loan=loan.name)
|
||||
|
||||
payments = frappe.db.sql(''' SELECT j.name, a.debit, a.debit_in_account_currency, j.posting_date
|
||||
FROM `tabJournal Entry` j, `tabJournal Entry Account` a
|
||||
WHERE a.parent = j.name and a.reference_type='Loan' and a.reference_name = %s
|
||||
and account = %s
|
||||
''', (loan.name, loan.loan_account), as_dict=1)
|
||||
|
||||
for payment in payments:
|
||||
repayment_entry = make_repayment_entry(loan.name, loan.loan_applicant_type, loan.applicant,
|
||||
loan.loan_type, loan.company)
|
||||
if frappe.db.has_column('Repayment Schedule', 'paid'):
|
||||
total_principal, total_interest = frappe.db.get_value('Repayment Schedule', {'paid': 1, 'parent': loan.name},
|
||||
['sum(principal_amount) as total_principal', 'sum(interest_amount) as total_interest'])
|
||||
|
||||
repayment_entry.amount_paid = payment.debit_in_account_currency
|
||||
repayment_entry.posting_date = payment.posting_date
|
||||
repayment_entry.save()
|
||||
repayment_entry.submit()
|
||||
accrued_entries = get_accrued_interest_entries(loan.name)
|
||||
for entry in accrued_entries:
|
||||
interest_paid = 0
|
||||
principal_paid = 0
|
||||
|
||||
jv = frappe.get_doc('Journal Entry', payment.name)
|
||||
jv.flags.ignore_links = True
|
||||
jv.cancel()
|
||||
if total_interest > entry.interest_amount:
|
||||
interest_paid = entry.interest_amount
|
||||
else:
|
||||
interest_paid = total_interest
|
||||
|
||||
if total_principal > entry.payable_principal_amount:
|
||||
principal_paid = entry.payable_principal_amount
|
||||
else:
|
||||
principal_paid = total_principal
|
||||
|
||||
frappe.db.sql(""" UPDATE `tabLoan Interest Accrual`
|
||||
SET paid_principal_amount = `paid_principal_amount` + %s,
|
||||
paid_interest_amount = `paid_interest_amount` + %s
|
||||
WHERE name = %s""",
|
||||
(principal_paid, interest_paid, entry.name))
|
||||
|
||||
total_principal -= principal_paid
|
||||
total_interest -= interest_paid
|
||||
|
||||
def create_loan_type(loan, loan_type_name, penalty_account):
|
||||
loan_type_doc = frappe.new_doc('Loan Type')
|
||||
loan_type_doc.loan_name = make_autoname("Loan Type-.####")
|
||||
loan_type_doc.is_term_loan = 1
|
||||
loan_type_doc.company = loan.company
|
||||
loan_type_doc.mode_of_payment = loan.mode_of_payment
|
||||
loan_type_doc.payment_account = loan.payment_account
|
||||
loan_type_doc.loan_account = loan.loan_account
|
||||
loan_type_doc.interest_income_account = loan.interest_income_account
|
||||
loan_type_doc.penalty_income_account = penalty_account
|
||||
loan_type_doc.submit()
|
||||
|
||||
return loan_type_doc.name
|
||||
|
@ -151,6 +151,7 @@ class Gstr1Report(object):
|
||||
{select_columns}
|
||||
from `tab{doctype}`
|
||||
where docstatus = 1 {where_conditions}
|
||||
and is_opening = 'No'
|
||||
order by posting_date desc
|
||||
""".format(select_columns=self.select_columns, doctype=self.doctype,
|
||||
where_conditions=conditions), self.filters, as_dict=1)
|
||||
|
@ -841,6 +841,10 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
|
||||
}
|
||||
},
|
||||
|
||||
fg_completed_qty: function() {
|
||||
this.get_items();
|
||||
},
|
||||
|
||||
get_items: function() {
|
||||
var me = this;
|
||||
if(!this.frm.doc.fg_completed_qty || !this.frm.doc.bom_no)
|
||||
@ -850,6 +854,7 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
|
||||
// if work order / bom is mentioned, get items
|
||||
return this.frm.call({
|
||||
doc: me.frm.doc,
|
||||
freeze: true,
|
||||
method: "get_items",
|
||||
callback: function(r) {
|
||||
if(!r.exc) refresh_field("items");
|
||||
|
@ -120,6 +120,7 @@ class StockEntry(StockController):
|
||||
self.update_transferred_qty()
|
||||
self.update_quality_inspection()
|
||||
self.delete_auto_created_batches()
|
||||
self.delete_linked_stock_entry()
|
||||
|
||||
if self.purpose == 'Material Transfer' and self.add_to_transit:
|
||||
self.set_material_request_transfer_status('Not Started')
|
||||
@ -152,6 +153,12 @@ class StockEntry(StockController):
|
||||
frappe.throw(_("For job card {0}, you can only make the 'Material Transfer for Manufacture' type stock entry")
|
||||
.format(self.job_card))
|
||||
|
||||
def delete_linked_stock_entry(self):
|
||||
if self.purpose == "Send to Warehouse":
|
||||
for d in frappe.get_all("Stock Entry", filters={"docstatus": 0,
|
||||
"outgoing_stock_entry": self.name, "purpose": "Receive at Warehouse"}):
|
||||
frappe.delete_doc("Stock Entry", d.name)
|
||||
|
||||
def set_transfer_qty(self):
|
||||
for item in self.get("items"):
|
||||
if not flt(item.qty):
|
||||
@ -1033,26 +1040,22 @@ class StockEntry(StockController):
|
||||
wo = frappe.get_doc("Work Order", self.work_order)
|
||||
wo_items = frappe.get_all('Work Order Item',
|
||||
filters={'parent': self.work_order},
|
||||
fields=["item_code", "required_qty", "consumed_qty"]
|
||||
fields=["item_code", "required_qty", "consumed_qty", "transferred_qty"]
|
||||
)
|
||||
|
||||
work_order_qty = wo.material_transferred_for_manufacturing or wo.qty
|
||||
for item in wo_items:
|
||||
qty = item.required_qty
|
||||
|
||||
item_account_details = get_item_defaults(item.item_code, self.company)
|
||||
# Take into account consumption if there are any.
|
||||
if self.purpose == 'Manufacture':
|
||||
req_qty_each = flt(item.required_qty / wo.qty)
|
||||
if (flt(item.consumed_qty) != 0):
|
||||
remaining_qty = flt(item.consumed_qty) - (flt(wo.produced_qty) * req_qty_each)
|
||||
exhaust_qty = req_qty_each * wo.produced_qty
|
||||
if remaining_qty > exhaust_qty :
|
||||
if (remaining_qty/(req_qty_each * flt(self.fg_completed_qty))) >= 1:
|
||||
qty =0
|
||||
else:
|
||||
qty = (req_qty_each * flt(self.fg_completed_qty)) - remaining_qty
|
||||
else:
|
||||
qty = req_qty_each * flt(self.fg_completed_qty)
|
||||
|
||||
wo_item_qty = item.transferred_qty or item.required_qty
|
||||
|
||||
req_qty_each = (
|
||||
(flt(wo_item_qty) - flt(item.consumed_qty)) /
|
||||
(flt(work_order_qty) - flt(wo.produced_qty))
|
||||
)
|
||||
|
||||
qty = req_qty_each * flt(self.fg_completed_qty)
|
||||
|
||||
if qty > 0:
|
||||
self.add_to_stock_entry_detail({
|
||||
@ -1134,13 +1137,15 @@ class StockEntry(StockController):
|
||||
else:
|
||||
qty = req_qty_each * flt(self.fg_completed_qty)
|
||||
|
||||
|
||||
elif backflushed_materials.get(item.item_code):
|
||||
for d in backflushed_materials.get(item.item_code):
|
||||
if d.get(item.warehouse):
|
||||
if (qty > req_qty):
|
||||
qty = (qty/trans_qty) * flt(self.fg_completed_qty)
|
||||
|
||||
if consumed_qty:
|
||||
qty -= consumed_qty
|
||||
|
||||
if cint(frappe.get_cached_value('UOM', item.stock_uom, 'must_be_whole_number')):
|
||||
qty = frappe.utils.ceil(qty)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user