mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-03 04:09:11 +00:00
Merge branch 'version-12-hotfix' into v12-pre-release
This commit is contained in:
@@ -41,8 +41,8 @@ class AccountingPeriod(Document):
|
|||||||
|
|
||||||
def get_doctypes_for_closing(self):
|
def get_doctypes_for_closing(self):
|
||||||
docs_for_closing = []
|
docs_for_closing = []
|
||||||
doctypes = ["Sales Invoice", "Purchase Invoice", "Journal Entry", "Payroll Entry", "Bank Reconciliation",
|
doctypes = ["Sales Invoice", "Purchase Invoice", "Journal Entry", "Payroll Entry", \
|
||||||
"Asset", "Purchase Order", "Sales Order", "Leave Application", "Leave Allocation", "Stock Entry"]
|
"Bank Reconciliation", "Asset", "Stock Entry"]
|
||||||
closed_doctypes = [{"document_type": doctype, "closed": 1} for doctype in doctypes]
|
closed_doctypes = [{"document_type": doctype, "closed": 1} for doctype in doctypes]
|
||||||
for closed_doctype in closed_doctypes:
|
for closed_doctype in closed_doctypes:
|
||||||
docs_for_closing.append(closed_doctype)
|
docs_for_closing.append(closed_doctype)
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ class GLEntry(Document):
|
|||||||
self.validate_and_set_fiscal_year()
|
self.validate_and_set_fiscal_year()
|
||||||
self.pl_must_have_cost_center()
|
self.pl_must_have_cost_center()
|
||||||
self.validate_cost_center()
|
self.validate_cost_center()
|
||||||
self.validate_dimensions_for_pl_and_bs()
|
|
||||||
|
|
||||||
if not self.flags.from_repost:
|
if not self.flags.from_repost:
|
||||||
self.check_pl_account()
|
self.check_pl_account()
|
||||||
@@ -39,6 +38,7 @@ class GLEntry(Document):
|
|||||||
def on_update_with_args(self, adv_adj, update_outstanding = 'Yes', from_repost=False):
|
def on_update_with_args(self, adv_adj, update_outstanding = 'Yes', from_repost=False):
|
||||||
if not from_repost:
|
if not from_repost:
|
||||||
self.validate_account_details(adv_adj)
|
self.validate_account_details(adv_adj)
|
||||||
|
self.validate_dimensions_for_pl_and_bs()
|
||||||
check_freezing_date(self.posting_date, adv_adj)
|
check_freezing_date(self.posting_date, adv_adj)
|
||||||
|
|
||||||
validate_frozen_account(self.account, adv_adj)
|
validate_frozen_account(self.account, adv_adj)
|
||||||
|
|||||||
@@ -190,7 +190,6 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
|
|||||||
if(jvd.reference_type==="Employee Advance") {
|
if(jvd.reference_type==="Employee Advance") {
|
||||||
return {
|
return {
|
||||||
filters: {
|
filters: {
|
||||||
'status': ['=', 'Unpaid'],
|
|
||||||
'docstatus': 1
|
'docstatus': 1
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ from erpnext.controllers.accounts_controller import AccountsController
|
|||||||
from erpnext.accounts.utils import get_balance_on, get_account_currency
|
from erpnext.accounts.utils import get_balance_on, get_account_currency
|
||||||
from erpnext.accounts.party import get_party_account
|
from erpnext.accounts.party import get_party_account
|
||||||
from erpnext.hr.doctype.expense_claim.expense_claim import update_reimbursed_amount
|
from erpnext.hr.doctype.expense_claim.expense_claim import update_reimbursed_amount
|
||||||
from erpnext.hr.doctype.loan.loan import update_disbursement_status, update_total_amount_paid
|
|
||||||
from erpnext.accounts.doctype.invoice_discounting.invoice_discounting import get_party_account_based_on_invoice_discounting
|
from erpnext.accounts.doctype.invoice_discounting.invoice_discounting import get_party_account_based_on_invoice_discounting
|
||||||
|
|
||||||
from six import string_types, iteritems
|
from six import string_types, iteritems
|
||||||
@@ -606,8 +605,8 @@ class JournalEntry(AccountsController):
|
|||||||
for d in self.accounts:
|
for d in self.accounts:
|
||||||
if d.reference_type=="Loan" and flt(d.debit) > 0:
|
if d.reference_type=="Loan" and flt(d.debit) > 0:
|
||||||
doc = frappe.get_doc("Loan", d.reference_name)
|
doc = frappe.get_doc("Loan", d.reference_name)
|
||||||
update_disbursement_status(doc)
|
doc.update_total_amount_paid()
|
||||||
update_total_amount_paid(doc)
|
doc.set_status()
|
||||||
|
|
||||||
def validate_expense_claim(self):
|
def validate_expense_claim(self):
|
||||||
for d in self.accounts:
|
for d in self.accounts:
|
||||||
@@ -968,7 +967,7 @@ def get_exchange_rate(posting_date, account=None, account_currency=None, company
|
|||||||
|
|
||||||
# The date used to retreive the exchange rate here is the date passed
|
# The date used to retreive the exchange rate here is the date passed
|
||||||
# in as an argument to this function.
|
# in as an argument to this function.
|
||||||
elif (not exchange_rate or exchange_rate==1) and account_currency and posting_date:
|
elif (not exchange_rate or flt(exchange_rate)==1) and account_currency and posting_date:
|
||||||
exchange_rate = get_exchange_rate(account_currency, company_currency, posting_date)
|
exchange_rate = get_exchange_rate(account_currency, company_currency, posting_date)
|
||||||
else:
|
else:
|
||||||
exchange_rate = 1
|
exchange_rate = 1
|
||||||
|
|||||||
@@ -652,14 +652,16 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
(frm.doc.payment_type=="Receive" && frm.doc.party_type=="Student")
|
(frm.doc.payment_type=="Receive" && frm.doc.party_type=="Student")
|
||||||
) {
|
) {
|
||||||
if(total_positive_outstanding > total_negative_outstanding)
|
if(total_positive_outstanding > total_negative_outstanding)
|
||||||
frm.set_value("paid_amount",
|
if (!frm.doc.paid_amount)
|
||||||
total_positive_outstanding - total_negative_outstanding);
|
frm.set_value("paid_amount",
|
||||||
|
total_positive_outstanding - total_negative_outstanding);
|
||||||
} else if (
|
} else if (
|
||||||
total_negative_outstanding &&
|
total_negative_outstanding &&
|
||||||
total_positive_outstanding < total_negative_outstanding
|
total_positive_outstanding < total_negative_outstanding
|
||||||
) {
|
) {
|
||||||
frm.set_value("received_amount",
|
if (!frm.doc.received_amount)
|
||||||
total_negative_outstanding - total_positive_outstanding);
|
frm.set_value("received_amount",
|
||||||
|
total_negative_outstanding - total_positive_outstanding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -911,7 +911,10 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
|
|||||||
else:
|
else:
|
||||||
party_account = get_party_account(party_type, doc.get(party_type.lower()), doc.company)
|
party_account = get_party_account(party_type, doc.get(party_type.lower()), doc.company)
|
||||||
|
|
||||||
party_account_currency = doc.get("party_account_currency") or get_account_currency(party_account)
|
if dt not in ("Sales Invoice", "Purchase Invoice"):
|
||||||
|
party_account_currency = get_account_currency(party_account)
|
||||||
|
else:
|
||||||
|
party_account_currency = doc.get("party_account_currency") or get_account_currency(party_account)
|
||||||
|
|
||||||
# payment type
|
# payment type
|
||||||
if (dt == "Sales Order" or (dt in ("Sales Invoice", "Fees") and doc.outstanding_amount > 0)) \
|
if (dt == "Sales Order" or (dt in ("Sales Invoice", "Fees") and doc.outstanding_amount > 0)) \
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ class PaymentReconciliation(Document):
|
|||||||
|
|
||||||
if self.party_type in ["Customer", "Supplier"]:
|
if self.party_type in ["Customer", "Supplier"]:
|
||||||
dr_or_cr_notes = self.get_dr_or_cr_notes()
|
dr_or_cr_notes = self.get_dr_or_cr_notes()
|
||||||
|
else:
|
||||||
|
dr_or_cr_notes = []
|
||||||
|
|
||||||
self.add_payment_entries(payment_entries + journal_entries + dr_or_cr_notes)
|
self.add_payment_entries(payment_entries + journal_entries + dr_or_cr_notes)
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,16 @@ cur_frm.add_fetch("payment_gateway_account", "payment_account", "payment_account
|
|||||||
cur_frm.add_fetch("payment_gateway_account", "payment_gateway", "payment_gateway")
|
cur_frm.add_fetch("payment_gateway_account", "payment_gateway", "payment_gateway")
|
||||||
cur_frm.add_fetch("payment_gateway_account", "message", "message")
|
cur_frm.add_fetch("payment_gateway_account", "message", "message")
|
||||||
|
|
||||||
|
frappe.ui.form.on("Payment Request", {
|
||||||
|
setup: function(frm) {
|
||||||
|
frm.set_query("party_type", function() {
|
||||||
|
return {
|
||||||
|
query: "erpnext.setup.doctype.party_type.party_type.get_party_type",
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
frappe.ui.form.on("Payment Request", "onload", function(frm, dt, dn){
|
frappe.ui.form.on("Payment Request", "onload", function(frm, dt, dn){
|
||||||
if (frm.doc.reference_doctype) {
|
if (frm.doc.reference_doctype) {
|
||||||
frappe.call({
|
frappe.call({
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ class PricingRule(Document):
|
|||||||
|
|
||||||
def validate_duplicate_apply_on(self):
|
def validate_duplicate_apply_on(self):
|
||||||
field = apply_on_dict.get(self.apply_on)
|
field = apply_on_dict.get(self.apply_on)
|
||||||
|
if not field:
|
||||||
|
return False
|
||||||
|
|
||||||
values = [d.get(frappe.scrub(self.apply_on)) for d in self.get(field)]
|
values = [d.get(frappe.scrub(self.apply_on)) for d in self.get(field)]
|
||||||
|
|
||||||
if len(values) != len(set(values)):
|
if len(values) != len(set(values)):
|
||||||
|
|||||||
@@ -495,7 +495,7 @@ def get_pricing_rule_items(pr_doc):
|
|||||||
|
|
||||||
if pr_doc.apply_rule_on_other:
|
if pr_doc.apply_rule_on_other:
|
||||||
apply_on = frappe.scrub(pr_doc.apply_rule_on_other)
|
apply_on = frappe.scrub(pr_doc.apply_rule_on_other)
|
||||||
apply_on_data.append(pr_doc.get(apply_on))
|
apply_on_data.append(pr_doc.get("other_" + apply_on))
|
||||||
|
|
||||||
return list(set(apply_on_data))
|
return list(set(apply_on_data))
|
||||||
|
|
||||||
|
|||||||
@@ -382,21 +382,11 @@ cur_frm.fields_dict['items'].grid.get_field("item_code").get_query = function(do
|
|||||||
|
|
||||||
cur_frm.fields_dict['credit_to'].get_query = function(doc) {
|
cur_frm.fields_dict['credit_to'].get_query = function(doc) {
|
||||||
// filter on Account
|
// filter on Account
|
||||||
if (doc.supplier) {
|
return {
|
||||||
return {
|
filters: {
|
||||||
filters: {
|
'account_type': 'Payable',
|
||||||
'account_type': 'Payable',
|
'is_group': 0,
|
||||||
'is_group': 0,
|
'company': doc.company
|
||||||
'company': doc.company
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
filters: {
|
|
||||||
'report_type': 'Balance Sheet',
|
|
||||||
'is_group': 0,
|
|
||||||
'company': doc.company
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"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",
|
||||||
@@ -417,6 +418,7 @@
|
|||||||
"fieldname": "contact_email",
|
"fieldname": "contact_email",
|
||||||
"fieldtype": "Small Text",
|
"fieldtype": "Small Text",
|
||||||
"label": "Contact Email",
|
"label": "Contact Email",
|
||||||
|
"options": "Email",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
@@ -705,7 +707,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "other_charges_calculation",
|
"fieldname": "other_charges_calculation",
|
||||||
"fieldtype": "Text",
|
"fieldtype": "Long Text",
|
||||||
"label": "Taxes and Charges Calculation",
|
"label": "Taxes and Charges Calculation",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldtype": "HTML",
|
"oldfieldtype": "HTML",
|
||||||
@@ -1287,7 +1289,8 @@
|
|||||||
"icon": "fa fa-file-text",
|
"icon": "fa fa-file-text",
|
||||||
"idx": 204,
|
"idx": 204,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"modified": "2019-09-17 22:31:42.666601",
|
"links": [],
|
||||||
|
"modified": "2019-12-30 19:13:49.610538",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Purchase Invoice",
|
"name": "Purchase Invoice",
|
||||||
|
|||||||
@@ -556,22 +556,11 @@ cur_frm.cscript.cost_center = function(doc, cdt, cdn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cur_frm.set_query("debit_to", function(doc) {
|
cur_frm.set_query("debit_to", function(doc) {
|
||||||
// filter on Account
|
return {
|
||||||
if (doc.customer) {
|
filters: {
|
||||||
return {
|
'account_type': 'Receivable',
|
||||||
filters: {
|
'is_group': 0,
|
||||||
'account_type': 'Receivable',
|
'company': doc.company
|
||||||
'is_group': 0,
|
|
||||||
'company': doc.company
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
filters: {
|
|
||||||
'report_type': 'Balance Sheet',
|
|
||||||
'is_group': 0,
|
|
||||||
'company': doc.company
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"autoname": "naming_series:",
|
"autoname": "naming_series:",
|
||||||
"creation": "2013-05-24 19:29:05",
|
"creation": "2013-05-24 19:29:05",
|
||||||
@@ -774,7 +775,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "other_charges_calculation",
|
"fieldname": "other_charges_calculation",
|
||||||
"fieldtype": "Text",
|
"fieldtype": "Long Text",
|
||||||
"label": "Taxes and Charges Calculation",
|
"label": "Taxes and Charges Calculation",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldtype": "HTML",
|
"oldfieldtype": "HTML",
|
||||||
@@ -1567,7 +1568,8 @@
|
|||||||
"icon": "fa fa-file-text",
|
"icon": "fa fa-file-text",
|
||||||
"idx": 181,
|
"idx": 181,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"modified": "2019-10-05 21:39:49.235990",
|
"links": [],
|
||||||
|
"modified": "2019-12-30 19:15:59.580414",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Sales Invoice",
|
"name": "Sales Invoice",
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
|
|
||||||
import unittest, copy, time
|
import unittest, copy, time
|
||||||
from frappe.utils import nowdate, flt, getdate, cint
|
from frappe.utils import nowdate, flt, getdate, cint, add_days
|
||||||
from frappe.model.dynamic_links import get_dynamic_link_map
|
from frappe.model.dynamic_links import get_dynamic_link_map
|
||||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry, get_qty_after_transaction
|
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry, get_qty_after_transaction
|
||||||
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import unlink_payment_on_cancel_of_invoice
|
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import unlink_payment_on_cancel_of_invoice
|
||||||
@@ -1847,6 +1847,26 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
self.assertEqual(data['billLists'][0]['vehicleNo'], 'KA12KA1234')
|
self.assertEqual(data['billLists'][0]['vehicleNo'], 'KA12KA1234')
|
||||||
self.assertEqual(data['billLists'][0]['itemList'][0]['taxableAmount'], 60000)
|
self.assertEqual(data['billLists'][0]['itemList'][0]['taxableAmount'], 60000)
|
||||||
|
|
||||||
|
def test_item_tax_validity(self):
|
||||||
|
item = frappe.get_doc("Item", "_Test Item 2")
|
||||||
|
|
||||||
|
if item.taxes:
|
||||||
|
item.taxes = []
|
||||||
|
item.save()
|
||||||
|
|
||||||
|
item.append("taxes", {
|
||||||
|
"item_tax_template": "_Test Item Tax Template 1",
|
||||||
|
"valid_from": add_days(nowdate(), 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
item.save()
|
||||||
|
|
||||||
|
sales_invoice = create_sales_invoice(item = "_Test Item 2", do_not_save=1)
|
||||||
|
sales_invoice.items[0].item_tax_template = "_Test Item Tax Template 1"
|
||||||
|
self.assertRaises(frappe.ValidationError, sales_invoice.save)
|
||||||
|
|
||||||
|
item.taxes = []
|
||||||
|
item.save()
|
||||||
|
|
||||||
def create_sales_invoice(**args):
|
def create_sales_invoice(**args):
|
||||||
si = frappe.new_doc("Sales Invoice")
|
si = frappe.new_doc("Sales Invoice")
|
||||||
|
|||||||
@@ -188,7 +188,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"modified": "2019-11-07 13:31:17.999744",
|
"modified": "2019-12-20 14:48:01.990600",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Share Transfer",
|
"name": "Share Transfer",
|
||||||
@@ -196,6 +196,7 @@
|
|||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
"amend": 1,
|
"amend": 1,
|
||||||
|
"cancel": 1,
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
@@ -221,6 +222,7 @@
|
|||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"cancel": 1,
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
@@ -230,6 +232,7 @@
|
|||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "Accounts Manager",
|
"role": "Accounts Manager",
|
||||||
"share": 1,
|
"share": 1,
|
||||||
|
"submit": 1,
|
||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -339,6 +339,16 @@ class Subscription(Document):
|
|||||||
# Check invoice dates and make sure it doesn't have outstanding invoices
|
# Check invoice dates and make sure it doesn't have outstanding invoices
|
||||||
return getdate(nowdate()) >= getdate(self.current_invoice_start) and not self.has_outstanding_invoice()
|
return getdate(nowdate()) >= getdate(self.current_invoice_start) and not self.has_outstanding_invoice()
|
||||||
|
|
||||||
|
def is_current_invoice_paid(self):
|
||||||
|
if self.is_new_subscription():
|
||||||
|
return False
|
||||||
|
|
||||||
|
last_invoice = frappe.get_doc('Sales Invoice', self.invoices[-1].invoice)
|
||||||
|
if getdate(last_invoice.posting_date) == getdate(self.current_invoice_start) and last_invoice.status == 'Paid':
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
def process_for_active(self):
|
def process_for_active(self):
|
||||||
"""
|
"""
|
||||||
Called by `process` if the status of the `Subscription` is 'Active'.
|
Called by `process` if the status of the `Subscription` is 'Active'.
|
||||||
@@ -348,7 +358,7 @@ class Subscription(Document):
|
|||||||
2. Change the `Subscription` status to 'Past Due Date'
|
2. Change the `Subscription` status to 'Past Due Date'
|
||||||
3. Change the `Subscription` status to 'Cancelled'
|
3. Change the `Subscription` status to 'Cancelled'
|
||||||
"""
|
"""
|
||||||
if self.is_postpaid_to_invoice() or self.is_prepaid_to_invoice():
|
if not self.is_current_invoice_paid() and (self.is_postpaid_to_invoice() or self.is_prepaid_to_invoice()):
|
||||||
self.generate_invoice()
|
self.generate_invoice()
|
||||||
if self.current_invoice_is_past_due():
|
if self.current_invoice_is_past_due():
|
||||||
self.status = 'Past Due Date'
|
self.status = 'Past Due Date'
|
||||||
|
|||||||
@@ -49,7 +49,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="right" colspan="3" ><strong>Total (debit) </strong></td>
|
<td class="right" colspan="3" ><strong>Total (debit) </strong></td>
|
||||||
<td class="left" >{{ gl | sum(attribute='debit') }}</td>
|
<td class="left" >{{ frappe.format((gl | sum(attribute="debit")), {fieldtype: "Currency"}) }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="top-bottom" colspan="5"><strong>Credit</strong></td>
|
<td class="top-bottom" colspan="5"><strong>Credit</strong></td>
|
||||||
@@ -69,7 +69,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="right" colspan="3"><strong>Total (credit) </strong></td>
|
<td class="right" colspan="3"><strong>Total (credit) </strong></td>
|
||||||
<td class="left" >{{ gl | sum(attribute='credit') }}</td>
|
<td class="left" >{{ frappe.format((gl | sum(attribute="credit")), {fieldtype: "Currency"}) }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ class ReceivablePayableReport(object):
|
|||||||
row.outstanding = flt(row.invoiced - row.paid - row.credit_note, self.currency_precision)
|
row.outstanding = flt(row.invoiced - row.paid - row.credit_note, self.currency_precision)
|
||||||
row.invoice_grand_total = row.invoiced
|
row.invoice_grand_total = row.invoiced
|
||||||
|
|
||||||
if abs(row.outstanding) > 0.1/10 ** self.currency_precision:
|
if abs(row.outstanding) > 1.0/10 ** self.currency_precision:
|
||||||
# non-zero oustanding, we must consider this row
|
# non-zero oustanding, we must consider this row
|
||||||
|
|
||||||
if self.is_invoice(row) and self.filters.based_on_payment_terms:
|
if self.is_invoice(row) and self.filters.based_on_payment_terms:
|
||||||
@@ -285,7 +285,7 @@ class ReceivablePayableReport(object):
|
|||||||
|
|
||||||
def set_party_details(self, row):
|
def set_party_details(self, row):
|
||||||
# customer / supplier name
|
# customer / supplier name
|
||||||
party_details = self.get_party_details(row.party)
|
party_details = self.get_party_details(row.party) or {}
|
||||||
row.update(party_details)
|
row.update(party_details)
|
||||||
if self.filters.get(scrub(self.filters.party_type)):
|
if self.filters.get(scrub(self.filters.party_type)):
|
||||||
row.currency = row.account_currency
|
row.currency = row.account_currency
|
||||||
|
|||||||
@@ -46,13 +46,24 @@ frappe.query_reports["Budget Variance Report"] = {
|
|||||||
fieldtype: "Select",
|
fieldtype: "Select",
|
||||||
options: ["Cost Center", "Project"],
|
options: ["Cost Center", "Project"],
|
||||||
default: "Cost Center",
|
default: "Cost Center",
|
||||||
reqd: 1
|
reqd: 1,
|
||||||
|
on_change: function() {
|
||||||
|
frappe.query_report.set_filter_value("budget_against_filter", []);
|
||||||
|
frappe.query_report.refresh();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: "cost_center",
|
fieldname:"budget_against_filter",
|
||||||
label: __("Cost Center"),
|
label: __('Dimension Filter'),
|
||||||
fieldtype: "Link",
|
fieldtype: "MultiSelectList",
|
||||||
options: "Cost Center"
|
get_data: function(txt) {
|
||||||
|
if (!frappe.query_report.filters) return;
|
||||||
|
|
||||||
|
let budget_against = frappe.query_report.get_filter_value('budget_against');
|
||||||
|
if (!budget_against) return;
|
||||||
|
|
||||||
|
return frappe.db.get_link_options(budget_against, txt);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname:"show_cumulative",
|
fieldname:"show_cumulative",
|
||||||
|
|||||||
@@ -12,22 +12,22 @@ from six import iteritems
|
|||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
if not filters: filters = {}
|
if not filters: filters = {}
|
||||||
validate_filters(filters)
|
|
||||||
columns = get_columns(filters)
|
columns = get_columns(filters)
|
||||||
if filters.get("cost_center"):
|
if filters.get("budget_against_filter"):
|
||||||
cost_centers = [filters.get("cost_center")]
|
dimensions = filters.get("budget_against_filter")
|
||||||
else:
|
else:
|
||||||
cost_centers = get_cost_centers(filters)
|
dimensions = get_cost_centers(filters)
|
||||||
|
|
||||||
period_month_ranges = get_period_month_ranges(filters["period"], filters["from_fiscal_year"])
|
period_month_ranges = get_period_month_ranges(filters["period"], filters["from_fiscal_year"])
|
||||||
cam_map = get_cost_center_account_month_map(filters)
|
cam_map = get_dimension_account_month_map(filters)
|
||||||
|
|
||||||
data = []
|
data = []
|
||||||
for cost_center in cost_centers:
|
for dimension in dimensions:
|
||||||
cost_center_items = cam_map.get(cost_center)
|
dimension_items = cam_map.get(dimension)
|
||||||
if cost_center_items:
|
if dimension_items:
|
||||||
for account, monthwise_data in iteritems(cost_center_items):
|
for account, monthwise_data in iteritems(dimension_items):
|
||||||
row = [cost_center, account]
|
row = [dimension, account]
|
||||||
totals = [0, 0, 0]
|
totals = [0, 0, 0]
|
||||||
for year in get_fiscal_years(filters):
|
for year in get_fiscal_years(filters):
|
||||||
last_total = 0
|
last_total = 0
|
||||||
@@ -55,10 +55,6 @@ def execute(filters=None):
|
|||||||
|
|
||||||
return columns, data
|
return columns, data
|
||||||
|
|
||||||
def validate_filters(filters):
|
|
||||||
if filters.get("budget_against") != "Cost Center" and filters.get("cost_center"):
|
|
||||||
frappe.throw(_("Filter based on Cost Center is only applicable if Budget Against is selected as Cost Center"))
|
|
||||||
|
|
||||||
def get_columns(filters):
|
def get_columns(filters):
|
||||||
columns = [_(filters.get("budget_against")) + ":Link/%s:150"%(filters.get("budget_against")), _("Account") + ":Link/Account:150"]
|
columns = [_(filters.get("budget_against")) + ":Link/%s:150"%(filters.get("budget_against")), _("Account") + ":Link/Account:150"]
|
||||||
|
|
||||||
@@ -98,11 +94,12 @@ def get_cost_centers(filters):
|
|||||||
else:
|
else:
|
||||||
return frappe.db.sql_list("""select name from `tab{tab}`""".format(tab=filters.get("budget_against"))) #nosec
|
return frappe.db.sql_list("""select name from `tab{tab}`""".format(tab=filters.get("budget_against"))) #nosec
|
||||||
|
|
||||||
#Get cost center & target details
|
#Get dimension & target details
|
||||||
def get_cost_center_target_details(filters):
|
def get_dimension_target_details(filters):
|
||||||
cond = ""
|
cond = ""
|
||||||
if filters.get("cost_center"):
|
if filters.get("budget_against_filter"):
|
||||||
cond += " and b.cost_center=%s" % frappe.db.escape(filters.get("cost_center"))
|
cond += " and b.{budget_against} in (%s)".format(budget_against = \
|
||||||
|
frappe.scrub(filters.get('budget_against'))) % ', '.join(['%s']* len(filters.get('budget_against_filter')))
|
||||||
|
|
||||||
return frappe.db.sql("""
|
return frappe.db.sql("""
|
||||||
select b.{budget_against} as budget_against, b.monthly_distribution, ba.account, ba.budget_amount,b.fiscal_year
|
select b.{budget_against} as budget_against, b.monthly_distribution, ba.account, ba.budget_amount,b.fiscal_year
|
||||||
@@ -110,8 +107,8 @@ def get_cost_center_target_details(filters):
|
|||||||
where b.name=ba.parent and b.docstatus = 1 and b.fiscal_year between %s and %s
|
where b.name=ba.parent and b.docstatus = 1 and b.fiscal_year between %s and %s
|
||||||
and b.budget_against = %s and b.company=%s {cond} order by b.fiscal_year
|
and b.budget_against = %s and b.company=%s {cond} order by b.fiscal_year
|
||||||
""".format(budget_against=filters.get("budget_against").replace(" ", "_").lower(), cond=cond),
|
""".format(budget_against=filters.get("budget_against").replace(" ", "_").lower(), cond=cond),
|
||||||
(filters.from_fiscal_year,filters.to_fiscal_year,filters.budget_against, filters.company), as_dict=True)
|
tuple([filters.from_fiscal_year,filters.to_fiscal_year,filters.budget_against, filters.company] + filters.get('budget_against_filter')),
|
||||||
|
as_dict=True)
|
||||||
|
|
||||||
|
|
||||||
#Get target distribution details of accounts of cost center
|
#Get target distribution details of accounts of cost center
|
||||||
@@ -153,14 +150,14 @@ def get_actual_details(name, filters):
|
|||||||
|
|
||||||
return cc_actual_details
|
return cc_actual_details
|
||||||
|
|
||||||
def get_cost_center_account_month_map(filters):
|
def get_dimension_account_month_map(filters):
|
||||||
import datetime
|
import datetime
|
||||||
cost_center_target_details = get_cost_center_target_details(filters)
|
dimension_target_details = get_dimension_target_details(filters)
|
||||||
tdd = get_target_distribution_details(filters)
|
tdd = get_target_distribution_details(filters)
|
||||||
|
|
||||||
cam_map = {}
|
cam_map = {}
|
||||||
|
|
||||||
for ccd in cost_center_target_details:
|
for ccd in dimension_target_details:
|
||||||
actual_details = get_actual_details(ccd.budget_against, filters)
|
actual_details = get_actual_details(ccd.budget_against, filters)
|
||||||
|
|
||||||
for month_id in range(1, 13):
|
for month_id in range(1, 13):
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for(var i=0, l=data.length-1; i<l; i++) { %}
|
{% for(var i=0, l=data.length; i<l; i++) { %}
|
||||||
<tr>
|
<tr>
|
||||||
{% if(data[i].posting_date) { %}
|
{% if(data[i].posting_date) { %}
|
||||||
<td>{%= frappe.datetime.str_to_user(data[i].posting_date) %}</td>
|
<td>{%= frappe.datetime.str_to_user(data[i].posting_date) %}</td>
|
||||||
|
|||||||
@@ -38,32 +38,46 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No
|
|||||||
cost_center = list(set(invoice_cc_wh_map.get(inv.name, {}).get("cost_center", [])))
|
cost_center = list(set(invoice_cc_wh_map.get(inv.name, {}).get("cost_center", [])))
|
||||||
warehouse = list(set(invoice_cc_wh_map.get(inv.name, {}).get("warehouse", [])))
|
warehouse = list(set(invoice_cc_wh_map.get(inv.name, {}).get("warehouse", [])))
|
||||||
|
|
||||||
row = [
|
row = {
|
||||||
inv.name, inv.posting_date, inv.customer, inv.customer_name
|
'invoice': inv.name,
|
||||||
]
|
'posting_date': inv.posting_date,
|
||||||
|
'customer': inv.customer,
|
||||||
|
'customer_name': inv.customer_name
|
||||||
|
}
|
||||||
|
|
||||||
if additional_query_columns:
|
if additional_query_columns:
|
||||||
for col in additional_query_columns:
|
for col in additional_query_columns:
|
||||||
row.append(inv.get(col))
|
row.update({
|
||||||
|
col: inv.get(col)
|
||||||
|
})
|
||||||
|
|
||||||
|
row.update({
|
||||||
|
'customer_group': inv.get("customer_group"),
|
||||||
|
'territory': inv.get("territory"),
|
||||||
|
'tax_id': inv.get("tax_id"),
|
||||||
|
'receivable_account': inv.debit_to,
|
||||||
|
'mode_of_payment': ", ".join(mode_of_payments.get(inv.name, [])),
|
||||||
|
'project': inv.project,
|
||||||
|
'owner': inv.owner,
|
||||||
|
'remarks': inv.remarks,
|
||||||
|
'sales_order': ", ".join(sales_order),
|
||||||
|
'delivery_note': ", ".join(delivery_note),
|
||||||
|
'cost_center': ", ".join(cost_center),
|
||||||
|
'warehouse': ", ".join(warehouse),
|
||||||
|
'currency': company_currency
|
||||||
|
})
|
||||||
|
|
||||||
row +=[
|
|
||||||
inv.get("customer_group"),
|
|
||||||
inv.get("territory"),
|
|
||||||
inv.get("tax_id"),
|
|
||||||
inv.debit_to, ", ".join(mode_of_payments.get(inv.name, [])),
|
|
||||||
inv.project, inv.owner, inv.remarks,
|
|
||||||
", ".join(sales_order), ", ".join(delivery_note),", ".join(cost_center),
|
|
||||||
", ".join(warehouse), company_currency
|
|
||||||
]
|
|
||||||
# map income values
|
# map income values
|
||||||
base_net_total = 0
|
base_net_total = 0
|
||||||
for income_acc in income_accounts:
|
for income_acc in income_accounts:
|
||||||
income_amount = flt(invoice_income_map.get(inv.name, {}).get(income_acc))
|
income_amount = flt(invoice_income_map.get(inv.name, {}).get(income_acc))
|
||||||
base_net_total += income_amount
|
base_net_total += income_amount
|
||||||
row.append(income_amount)
|
row.update({
|
||||||
|
frappe.scrub(income_acc): income_amount
|
||||||
|
})
|
||||||
|
|
||||||
# net total
|
# net total
|
||||||
row.append(base_net_total or inv.base_net_total)
|
row.update({'net_total': base_net_total or inv.base_net_total})
|
||||||
|
|
||||||
# tax account
|
# tax account
|
||||||
total_tax = 0
|
total_tax = 0
|
||||||
@@ -72,10 +86,18 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No
|
|||||||
tax_amount_precision = get_field_precision(frappe.get_meta("Sales Taxes and Charges").get_field("tax_amount"), currency=company_currency) or 2
|
tax_amount_precision = get_field_precision(frappe.get_meta("Sales Taxes and Charges").get_field("tax_amount"), currency=company_currency) or 2
|
||||||
tax_amount = flt(invoice_tax_map.get(inv.name, {}).get(tax_acc), tax_amount_precision)
|
tax_amount = flt(invoice_tax_map.get(inv.name, {}).get(tax_acc), tax_amount_precision)
|
||||||
total_tax += tax_amount
|
total_tax += tax_amount
|
||||||
row.append(tax_amount)
|
row.update({
|
||||||
|
frappe.scrub(tax_acc): tax_amount
|
||||||
|
})
|
||||||
|
|
||||||
# total tax, grand total, outstanding amount & rounded total
|
# total tax, grand total, outstanding amount & rounded total
|
||||||
row += [total_tax, inv.base_grand_total, inv.base_rounded_total, inv.outstanding_amount]
|
|
||||||
|
row.update({
|
||||||
|
'tax_total': total_tax,
|
||||||
|
'grand_total': inv.base_grand_total,
|
||||||
|
'rounded_total': inv.base_rounded_total,
|
||||||
|
'outstanding_amount': inv.outstanding_amount
|
||||||
|
})
|
||||||
|
|
||||||
data.append(row)
|
data.append(row)
|
||||||
|
|
||||||
@@ -84,19 +106,118 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No
|
|||||||
def get_columns(invoice_list, additional_table_columns):
|
def get_columns(invoice_list, additional_table_columns):
|
||||||
"""return columns based on filters"""
|
"""return columns based on filters"""
|
||||||
columns = [
|
columns = [
|
||||||
_("Invoice") + ":Link/Sales Invoice:120", _("Posting Date") + ":Date:80",
|
{
|
||||||
_("Customer") + ":Link/Customer:120", _("Customer Name") + "::120"
|
'label': _("Invoice"),
|
||||||
|
'fieldname': 'invoice',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Sales Invoice',
|
||||||
|
'width': 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Posting Date"),
|
||||||
|
'fieldname': 'posting_date',
|
||||||
|
'fieldtype': 'Date',
|
||||||
|
'width': 80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Customer"),
|
||||||
|
'fieldname': 'customer',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Customer',
|
||||||
|
'width': 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Customer Name"),
|
||||||
|
'fieldname': 'customer_name',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'width': 120
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
if additional_table_columns:
|
if additional_table_columns:
|
||||||
columns += additional_table_columns
|
columns += additional_table_columns
|
||||||
|
|
||||||
columns +=[
|
columns +=[
|
||||||
_("Customer Group") + ":Link/Customer Group:120", _("Territory") + ":Link/Territory:80",
|
{
|
||||||
_("Tax Id") + "::80", _("Receivable Account") + ":Link/Account:120", _("Mode of Payment") + "::120",
|
'label': _("Custmer Group"),
|
||||||
_("Project") +":Link/Project:80", _("Owner") + "::150", _("Remarks") + "::150",
|
'fieldname': 'customer_group',
|
||||||
_("Sales Order") + ":Link/Sales Order:100", _("Delivery Note") + ":Link/Delivery Note:100",
|
'fieldtype': 'Link',
|
||||||
_("Cost Center") + ":Link/Cost Center:100", _("Warehouse") + ":Link/Warehouse:100",
|
'options': 'Customer Group',
|
||||||
|
'width': 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Territory"),
|
||||||
|
'fieldname': 'territory',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Territory',
|
||||||
|
'width': 80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Tax Id"),
|
||||||
|
'fieldname': 'tax_id',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'width': 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Receivable Account"),
|
||||||
|
'fieldname': 'receivable_account',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Account',
|
||||||
|
'width': 80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Mode Of Payment"),
|
||||||
|
'fieldname': 'mode_of_payment',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'width': 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Project"),
|
||||||
|
'fieldname': 'project',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'project',
|
||||||
|
'width': 80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Owner"),
|
||||||
|
'fieldname': 'owner',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'width': 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Remarks"),
|
||||||
|
'fieldname': 'remarks',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'width': 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Sales Order"),
|
||||||
|
'fieldname': 'sales_order',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Sales Order',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Delivery Note"),
|
||||||
|
'fieldname': 'delivery_note',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Delivery Note',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Cost Center"),
|
||||||
|
'fieldname': 'cost_center',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Cost Center',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Warehouse"),
|
||||||
|
'fieldname': 'warehouse',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Warehouse',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "currency",
|
"fieldname": "currency",
|
||||||
"label": _("Currency"),
|
"label": _("Currency"),
|
||||||
@@ -105,7 +226,10 @@ def get_columns(invoice_list, additional_table_columns):
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
income_accounts = tax_accounts = income_columns = tax_columns = []
|
income_accounts = []
|
||||||
|
tax_accounts = []
|
||||||
|
income_columns = []
|
||||||
|
tax_columns = []
|
||||||
|
|
||||||
if invoice_list:
|
if invoice_list:
|
||||||
income_accounts = frappe.db.sql_list("""select distinct income_account
|
income_accounts = frappe.db.sql_list("""select distinct income_account
|
||||||
@@ -119,14 +243,65 @@ def get_columns(invoice_list, additional_table_columns):
|
|||||||
and parent in (%s) order by account_head""" %
|
and parent in (%s) order by account_head""" %
|
||||||
', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]))
|
', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]))
|
||||||
|
|
||||||
income_columns = [(account + ":Currency/currency:120") for account in income_accounts]
|
for account in income_accounts:
|
||||||
|
income_columns.append({
|
||||||
|
"label": account,
|
||||||
|
"fieldname": frappe.scrub(account),
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"options": 'currency',
|
||||||
|
"width": 120
|
||||||
|
})
|
||||||
|
|
||||||
for account in tax_accounts:
|
for account in tax_accounts:
|
||||||
if account not in income_accounts:
|
if account not in income_accounts:
|
||||||
tax_columns.append(account + ":Currency/currency:120")
|
tax_columns.append({
|
||||||
|
"label": account,
|
||||||
|
"fieldname": frappe.scrub(account),
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"options": 'currency',
|
||||||
|
"width": 120
|
||||||
|
})
|
||||||
|
|
||||||
columns = columns + income_columns + [_("Net Total") + ":Currency/currency:120"] + tax_columns + \
|
net_total_column = [{
|
||||||
[_("Total Tax") + ":Currency/currency:120", _("Grand Total") + ":Currency/currency:120",
|
"label": _("Net Total"),
|
||||||
_("Rounded Total") + ":Currency/currency:120", _("Outstanding Amount") + ":Currency/currency:120"]
|
"fieldname": "net_total",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"options": 'currency',
|
||||||
|
"width": 120
|
||||||
|
}]
|
||||||
|
|
||||||
|
total_columns = [
|
||||||
|
{
|
||||||
|
"label": _("Tax Total"),
|
||||||
|
"fieldname": "tax_total",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"options": 'currency',
|
||||||
|
"width": 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Grand Total"),
|
||||||
|
"fieldname": "grand_total",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"options": 'currency',
|
||||||
|
"width": 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Rounded Total"),
|
||||||
|
"fieldname": "rounded_total",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"options": 'currency',
|
||||||
|
"width": 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Outstanding Amount"),
|
||||||
|
"fieldname": "outstanding_amount",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"options": 'currency',
|
||||||
|
"width": 120
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
columns = columns + income_columns + net_total_column + tax_columns + total_columns
|
||||||
|
|
||||||
return columns, income_accounts, tax_accounts
|
return columns, income_accounts, tax_accounts
|
||||||
|
|
||||||
|
|||||||
@@ -65,6 +65,21 @@ frappe.query_reports["Trial Balance for Party"] = {
|
|||||||
return party_type;
|
return party_type;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "account",
|
||||||
|
"label": __("Account"),
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Account",
|
||||||
|
"get_query": function() {
|
||||||
|
var company = frappe.query_report.get_filter_value('company');
|
||||||
|
return {
|
||||||
|
"doctype": "Account",
|
||||||
|
"filters": {
|
||||||
|
"company": company,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "show_zero_values",
|
"fieldname": "show_zero_values",
|
||||||
"label": __("Show zero values"),
|
"label": __("Show zero values"),
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ def execute(filters=None):
|
|||||||
def get_data(filters, show_party_name):
|
def get_data(filters, show_party_name):
|
||||||
if filters.get('party_type') in ('Customer', 'Supplier', 'Employee', 'Member'):
|
if filters.get('party_type') in ('Customer', 'Supplier', 'Employee', 'Member'):
|
||||||
party_name_field = "{0}_name".format(frappe.scrub(filters.get('party_type')))
|
party_name_field = "{0}_name".format(frappe.scrub(filters.get('party_type')))
|
||||||
if filters.get('party_type') == 'Student':
|
elif filters.get('party_type') == 'Student':
|
||||||
party_name_field = 'first_name'
|
party_name_field = 'first_name'
|
||||||
elif filters.get('party_type') == 'Shareholder':
|
elif filters.get('party_type') == 'Shareholder':
|
||||||
party_name_field = 'title'
|
party_name_field = 'title'
|
||||||
@@ -96,13 +96,19 @@ def get_data(filters, show_party_name):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
def get_opening_balances(filters):
|
def get_opening_balances(filters):
|
||||||
|
|
||||||
|
account_filter = ''
|
||||||
|
if filters.get('account'):
|
||||||
|
account_filter = "and account = %s" % (frappe.db.escape(filters.get('account')))
|
||||||
|
|
||||||
gle = frappe.db.sql("""
|
gle = frappe.db.sql("""
|
||||||
select party, sum(debit) as opening_debit, sum(credit) as opening_credit
|
select party, sum(debit) as opening_debit, sum(credit) as opening_credit
|
||||||
from `tabGL Entry`
|
from `tabGL Entry`
|
||||||
where company=%(company)s
|
where company=%(company)s
|
||||||
and ifnull(party_type, '') = %(party_type)s and ifnull(party, '') != ''
|
and ifnull(party_type, '') = %(party_type)s and ifnull(party, '') != ''
|
||||||
and (posting_date < %(from_date)s or ifnull(is_opening, 'No') = 'Yes')
|
and (posting_date < %(from_date)s or ifnull(is_opening, 'No') = 'Yes')
|
||||||
group by party""", {
|
{account_filter}
|
||||||
|
group by party""".format(account_filter=account_filter), {
|
||||||
"company": filters.company,
|
"company": filters.company,
|
||||||
"from_date": filters.from_date,
|
"from_date": filters.from_date,
|
||||||
"party_type": filters.party_type
|
"party_type": filters.party_type
|
||||||
@@ -116,6 +122,11 @@ def get_opening_balances(filters):
|
|||||||
return opening
|
return opening
|
||||||
|
|
||||||
def get_balances_within_period(filters):
|
def get_balances_within_period(filters):
|
||||||
|
|
||||||
|
account_filter = ''
|
||||||
|
if filters.get('account'):
|
||||||
|
account_filter = "and account = %s" % (frappe.db.escape(filters.get('account')))
|
||||||
|
|
||||||
gle = frappe.db.sql("""
|
gle = frappe.db.sql("""
|
||||||
select party, sum(debit) as debit, sum(credit) as credit
|
select party, sum(debit) as debit, sum(credit) as credit
|
||||||
from `tabGL Entry`
|
from `tabGL Entry`
|
||||||
@@ -123,7 +134,8 @@ def get_balances_within_period(filters):
|
|||||||
and ifnull(party_type, '') = %(party_type)s and ifnull(party, '') != ''
|
and ifnull(party_type, '') = %(party_type)s and ifnull(party, '') != ''
|
||||||
and posting_date >= %(from_date)s and posting_date <= %(to_date)s
|
and posting_date >= %(from_date)s and posting_date <= %(to_date)s
|
||||||
and ifnull(is_opening, 'No') = 'No'
|
and ifnull(is_opening, 'No') = 'No'
|
||||||
group by party""", {
|
{account_filter}
|
||||||
|
group by party""".format(account_filter=account_filter), {
|
||||||
"company": filters.company,
|
"company": filters.company,
|
||||||
"from_date": filters.from_date,
|
"from_date": filters.from_date,
|
||||||
"to_date": filters.to_date,
|
"to_date": filters.to_date,
|
||||||
|
|||||||
@@ -891,3 +891,9 @@ def get_allow_cost_center_in_entry_of_bs_account():
|
|||||||
def generator():
|
def generator():
|
||||||
return cint(frappe.db.get_value('Accounts Settings', None, 'allow_cost_center_in_entry_of_bs_account'))
|
return cint(frappe.db.get_value('Accounts Settings', None, 'allow_cost_center_in_entry_of_bs_account'))
|
||||||
return frappe.local_cache("get_allow_cost_center_in_entry_of_bs_account", (), generator, regenerate_if_none=True)
|
return frappe.local_cache("get_allow_cost_center_in_entry_of_bs_account", (), generator, regenerate_if_none=True)
|
||||||
|
|
||||||
|
def get_stock_accounts(company):
|
||||||
|
return frappe.get_all("Account", filters = {
|
||||||
|
"account_type": "Stock",
|
||||||
|
"company": company
|
||||||
|
})
|
||||||
@@ -110,7 +110,7 @@ class AssetMovement(Document):
|
|||||||
ORDER BY
|
ORDER BY
|
||||||
asm.transaction_date asc
|
asm.transaction_date asc
|
||||||
""", (d.asset, self.company, 'Receipt'), as_dict=1)
|
""", (d.asset, self.company, 'Receipt'), as_dict=1)
|
||||||
if auto_gen_movement_entry[0].get('name') == self.name:
|
if auto_gen_movement_entry and auto_gen_movement_entry[0].get('name') == self.name:
|
||||||
frappe.throw(_('{0} will be cancelled automatically on asset cancellation as it was \
|
frappe.throw(_('{0} will be cancelled automatically on asset cancellation as it was \
|
||||||
auto generated for Asset {1}').format(self.name, d.asset))
|
auto generated for Asset {1}').format(self.name, d.asset))
|
||||||
|
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ def get_data(filters):
|
|||||||
filters=conditions,
|
filters=conditions,
|
||||||
fields=["name", "asset_name", "department", "cost_center", "purchase_receipt",
|
fields=["name", "asset_name", "department", "cost_center", "purchase_receipt",
|
||||||
"asset_category", "purchase_date", "gross_purchase_amount", "location",
|
"asset_category", "purchase_date", "gross_purchase_amount", "location",
|
||||||
"available_for_use_date", "status", "purchase_invoice"])
|
"available_for_use_date", "status", "purchase_invoice", "opening_accumulated_depreciation"])
|
||||||
|
|
||||||
for asset in assets_record:
|
for asset in assets_record:
|
||||||
asset_value = asset.gross_purchase_amount - flt(asset.opening_accumulated_depreciation) \
|
asset_value = asset.gross_purchase_amount - flt(asset.opening_accumulated_depreciation) \
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
|||||||
if (doc.status != "On Hold") {
|
if (doc.status != "On Hold") {
|
||||||
if(flt(doc.per_received, 2) < 100 && allow_receipt) {
|
if(flt(doc.per_received, 2) < 100 && allow_receipt) {
|
||||||
cur_frm.add_custom_button(__('Receipt'), this.make_purchase_receipt, __('Create'));
|
cur_frm.add_custom_button(__('Receipt'), this.make_purchase_receipt, __('Create'));
|
||||||
if(doc.is_subcontracted==="Yes") {
|
if(doc.is_subcontracted==="Yes" && me.has_unsupplied_items()) {
|
||||||
cur_frm.add_custom_button(__('Material to Supplier'),
|
cur_frm.add_custom_button(__('Material to Supplier'),
|
||||||
function() { me.make_stock_entry(); }, __("Transfer"));
|
function() { me.make_stock_entry(); }, __("Transfer"));
|
||||||
}
|
}
|
||||||
@@ -191,6 +191,10 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
|||||||
set_schedule_date(this.frm);
|
set_schedule_date(this.frm);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
has_unsupplied_items: function() {
|
||||||
|
return this.frm.doc['supplied_items'].some(item => item.required_qty != item.supplied_qty)
|
||||||
|
},
|
||||||
|
|
||||||
make_stock_entry: function() {
|
make_stock_entry: function() {
|
||||||
var items = $.map(cur_frm.doc.items, function(d) { return d.bom ? d.item_code : false; });
|
var items = $.map(cur_frm.doc.items, function(d) { return d.bom ? d.item_code : false; });
|
||||||
var me = this;
|
var me = this;
|
||||||
@@ -267,7 +271,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
|||||||
|
|
||||||
if (me.frm.doc['supplied_items']) {
|
if (me.frm.doc['supplied_items']) {
|
||||||
me.frm.doc['supplied_items'].forEach((item, index) => {
|
me.frm.doc['supplied_items'].forEach((item, index) => {
|
||||||
if (item.rm_item_code && item.main_item_code) {
|
if (item.rm_item_code && item.main_item_code && item.required_qty - item.supplied_qty != 0) {
|
||||||
me.raw_material_data.push ({
|
me.raw_material_data.push ({
|
||||||
'name':item.name,
|
'name':item.name,
|
||||||
'item_code': item.main_item_code,
|
'item_code': item.main_item_code,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"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",
|
||||||
@@ -47,6 +48,7 @@
|
|||||||
"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",
|
||||||
@@ -340,6 +342,7 @@
|
|||||||
"fieldname": "contact_email",
|
"fieldname": "contact_email",
|
||||||
"fieldtype": "Small Text",
|
"fieldtype": "Small Text",
|
||||||
"label": "Contact Email",
|
"label": "Contact Email",
|
||||||
|
"options": "Email",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
@@ -607,7 +610,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "other_charges_calculation",
|
"fieldname": "other_charges_calculation",
|
||||||
"fieldtype": "Text",
|
"fieldtype": "Long Text",
|
||||||
"label": "Taxes and Charges Calculation",
|
"label": "Taxes and Charges Calculation",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldtype": "HTML",
|
"oldfieldtype": "HTML",
|
||||||
@@ -1039,12 +1042,20 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Tax Category",
|
"label": "Tax Category",
|
||||||
"options": "Tax Category"
|
"options": "Tax Category"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "supplied_items",
|
||||||
|
"fieldname": "set_reserve_warehouse",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Set Reserve Warehouse",
|
||||||
|
"options": "Warehouse"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-file-text",
|
"icon": "fa fa-file-text",
|
||||||
"idx": 105,
|
"idx": 105,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"modified": "2019-07-11 18:25:49.509343",
|
"links": [],
|
||||||
|
"modified": "2019-12-30 19:11:54.122264",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Purchase Order",
|
"name": "Purchase Order",
|
||||||
|
|||||||
@@ -116,6 +116,73 @@ class TestPurchaseOrder(unittest.TestCase):
|
|||||||
self.assertEqual(po.get("items")[0].amount, 1400)
|
self.assertEqual(po.get("items")[0].amount, 1400)
|
||||||
self.assertEqual(get_ordered_qty(), existing_ordered_qty + 3)
|
self.assertEqual(get_ordered_qty(), existing_ordered_qty + 3)
|
||||||
|
|
||||||
|
|
||||||
|
def test_add_new_item_in_update_child_qty_rate(self):
|
||||||
|
po = create_purchase_order(do_not_save=1)
|
||||||
|
po.items[0].qty = 4
|
||||||
|
po.save()
|
||||||
|
po.submit()
|
||||||
|
pr = make_pr_against_po(po.name, 2)
|
||||||
|
|
||||||
|
po.load_from_db()
|
||||||
|
first_item_of_po = po.get("items")[0]
|
||||||
|
|
||||||
|
trans_item = json.dumps([
|
||||||
|
{
|
||||||
|
'item_code': first_item_of_po.item_code,
|
||||||
|
'rate': first_item_of_po.rate,
|
||||||
|
'qty': first_item_of_po.qty,
|
||||||
|
'docname': first_item_of_po.name
|
||||||
|
},
|
||||||
|
{'item_code' : '_Test Item', 'rate' : 200, 'qty' : 7}
|
||||||
|
])
|
||||||
|
update_child_qty_rate('Purchase Order', trans_item, po.name)
|
||||||
|
|
||||||
|
po.reload()
|
||||||
|
self.assertEquals(len(po.get('items')), 2)
|
||||||
|
self.assertEqual(po.status, 'To Receive and Bill')
|
||||||
|
|
||||||
|
|
||||||
|
def test_remove_item_in_update_child_qty_rate(self):
|
||||||
|
po = create_purchase_order(do_not_save=1)
|
||||||
|
po.items[0].qty = 4
|
||||||
|
po.save()
|
||||||
|
po.submit()
|
||||||
|
pr = make_pr_against_po(po.name, 2)
|
||||||
|
|
||||||
|
po.reload()
|
||||||
|
first_item_of_po = po.get("items")[0]
|
||||||
|
# add an item
|
||||||
|
trans_item = json.dumps([
|
||||||
|
{
|
||||||
|
'item_code': first_item_of_po.item_code,
|
||||||
|
'rate': first_item_of_po.rate,
|
||||||
|
'qty': first_item_of_po.qty,
|
||||||
|
'docname': first_item_of_po.name
|
||||||
|
},
|
||||||
|
{'item_code' : '_Test Item', 'rate' : 200, 'qty' : 7}])
|
||||||
|
update_child_qty_rate('Purchase Order', trans_item, po.name)
|
||||||
|
|
||||||
|
po.reload()
|
||||||
|
# check if can remove received item
|
||||||
|
trans_item = json.dumps([{'item_code' : '_Test Item', 'rate' : 200, 'qty' : 7, 'docname': po.get("items")[1].name}])
|
||||||
|
self.assertRaises(frappe.ValidationError, update_child_qty_rate, 'Purchase Order', trans_item, po.name)
|
||||||
|
|
||||||
|
first_item_of_po = po.get("items")[0]
|
||||||
|
trans_item = json.dumps([
|
||||||
|
{
|
||||||
|
'item_code': first_item_of_po.item_code,
|
||||||
|
'rate': first_item_of_po.rate,
|
||||||
|
'qty': first_item_of_po.qty,
|
||||||
|
'docname': first_item_of_po.name
|
||||||
|
}
|
||||||
|
])
|
||||||
|
update_child_qty_rate('Purchase Order', trans_item, po.name)
|
||||||
|
|
||||||
|
po.reload()
|
||||||
|
self.assertEquals(len(po.get('items')), 1)
|
||||||
|
self.assertEqual(po.status, 'To Receive and Bill')
|
||||||
|
|
||||||
def test_update_qty(self):
|
def test_update_qty(self):
|
||||||
po = create_purchase_order()
|
po = create_purchase_order()
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -138,7 +138,7 @@ def refresh_scorecards():
|
|||||||
# Check to see if any new scorecard periods are created
|
# Check to see if any new scorecard periods are created
|
||||||
if make_all_scorecards(sc.name) > 0:
|
if make_all_scorecards(sc.name) > 0:
|
||||||
# Save the scorecard to update the score and standings
|
# Save the scorecard to update the score and standings
|
||||||
sc.save()
|
frappe.get_doc('Supplier Scorecard', sc.name).save()
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
|
|||||||
@@ -336,6 +336,24 @@ def get_data():
|
|||||||
"is_query_report": True,
|
"is_query_report": True,
|
||||||
"name": "Item Variant Details",
|
"name": "Item Variant Details",
|
||||||
"doctype": "Item"
|
"doctype": "Item"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "report",
|
||||||
|
"is_query_report": True,
|
||||||
|
"name": "Subcontracted Raw Materials To Be Transferred",
|
||||||
|
"doctype": "Purchase Order"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "report",
|
||||||
|
"is_query_report": True,
|
||||||
|
"name": "Subcontracted Item To Be Received",
|
||||||
|
"doctype": "Purchase Order"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "report",
|
||||||
|
"is_query_report": True,
|
||||||
|
"name": "Stock and Account Value Comparison",
|
||||||
|
"doctype": "Stock Ledger Entry"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1155,6 +1155,30 @@ def set_purchase_order_defaults(parent_doctype, parent_doctype_name, child_docna
|
|||||||
child_item.base_amount = 1 # Initiallize value will update in parent validation
|
child_item.base_amount = 1 # Initiallize value will update in parent validation
|
||||||
return child_item
|
return child_item
|
||||||
|
|
||||||
|
def check_and_delete_children(parent, data):
|
||||||
|
deleted_children = []
|
||||||
|
updated_item_names = [d.get("docname") for d in data]
|
||||||
|
for item in parent.items:
|
||||||
|
if item.name not in updated_item_names:
|
||||||
|
deleted_children.append(item)
|
||||||
|
|
||||||
|
for d in deleted_children:
|
||||||
|
if parent.doctype == "Sales Order":
|
||||||
|
if flt(d.delivered_qty):
|
||||||
|
frappe.throw(_("Row #{0}: Cannot delete item {1} which has already been delivered").format(d.idx, d.item_code))
|
||||||
|
if flt(d.work_order_qty):
|
||||||
|
frappe.throw(_("Row #{0}: Cannot delete item {1} which has work order assigned to it.").format(d.idx, d.item_code))
|
||||||
|
if flt(d.ordered_qty):
|
||||||
|
frappe.throw(_("Row #{0}: Cannot delete item {1} which is assigned to customer's purchase order.").format(d.idx, d.item_code))
|
||||||
|
|
||||||
|
if parent.doctype == "Purchase Order" and flt(d.received_qty):
|
||||||
|
frappe.throw(_("Row #{0}: Cannot delete item {1} which has already been received").format(d.idx, d.item_code))
|
||||||
|
|
||||||
|
if flt(d.billed_amt):
|
||||||
|
frappe.throw(_("Row #{0}: Cannot delete item {1} which has already been billed.").format(d.idx, d.item_code))
|
||||||
|
|
||||||
|
d.cancel()
|
||||||
|
d.delete()
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, child_docname="items"):
|
def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, child_docname="items"):
|
||||||
@@ -1163,6 +1187,8 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
|
|||||||
sales_doctypes = ['Sales Order', 'Sales Invoice', 'Delivery Note', 'Quotation']
|
sales_doctypes = ['Sales Order', 'Sales Invoice', 'Delivery Note', 'Quotation']
|
||||||
parent = frappe.get_doc(parent_doctype, parent_doctype_name)
|
parent = frappe.get_doc(parent_doctype, parent_doctype_name)
|
||||||
|
|
||||||
|
check_and_delete_children(parent, data)
|
||||||
|
|
||||||
for d in data:
|
for d in data:
|
||||||
new_child_flag = False
|
new_child_flag = False
|
||||||
if not d.get("docname"):
|
if not d.get("docname"):
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.desk.reportview import get_match_cond, get_filters_cond
|
from frappe.desk.reportview import get_match_cond, get_filters_cond
|
||||||
from frappe.utils import nowdate
|
from frappe.utils import nowdate, getdate
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
from erpnext.stock.get_item_details import _get_item_tax_template
|
||||||
|
|
||||||
# searches for active employees
|
# searches for active employees
|
||||||
def employee_query(doctype, txt, searchfield, start, page_len, filters):
|
def employee_query(doctype, txt, searchfield, start, page_len, filters):
|
||||||
@@ -311,6 +311,7 @@ def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
and sle.item_code = %(item_code)s
|
and sle.item_code = %(item_code)s
|
||||||
and sle.warehouse = %(warehouse)s
|
and sle.warehouse = %(warehouse)s
|
||||||
and (sle.batch_no like %(txt)s
|
and (sle.batch_no like %(txt)s
|
||||||
|
or batch.expiry_date like %(txt)s
|
||||||
or batch.manufacturing_date like %(txt)s)
|
or batch.manufacturing_date like %(txt)s)
|
||||||
and batch.docstatus < 2
|
and batch.docstatus < 2
|
||||||
{cond}
|
{cond}
|
||||||
@@ -329,6 +330,7 @@ def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
where batch.disabled = 0
|
where batch.disabled = 0
|
||||||
and item = %(item_code)s
|
and item = %(item_code)s
|
||||||
and (name like %(txt)s
|
and (name like %(txt)s
|
||||||
|
or expiry_date like %(txt)s
|
||||||
or manufacturing_date like %(txt)s)
|
or manufacturing_date like %(txt)s)
|
||||||
and docstatus < 2
|
and docstatus < 2
|
||||||
{0}
|
{0}
|
||||||
@@ -506,3 +508,27 @@ def get_purchase_invoices(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
query += " and piitem.item_code = {item_code}".format(item_code = frappe.db.escape(filters.get('item_code')))
|
query += " and piitem.item_code = {item_code}".format(item_code = frappe.db.escape(filters.get('item_code')))
|
||||||
|
|
||||||
return frappe.db.sql(query, filters)
|
return frappe.db.sql(query, filters)
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def get_tax_template(doctype, txt, searchfield, start, page_len, filters):
|
||||||
|
|
||||||
|
item_doc = frappe.get_cached_doc('Item', filters.get('item_code'))
|
||||||
|
item_group = filters.get('item_group')
|
||||||
|
taxes = item_doc.taxes or []
|
||||||
|
|
||||||
|
while item_group:
|
||||||
|
item_group_doc = frappe.get_cached_doc('Item Group', item_group)
|
||||||
|
taxes += item_group_doc.taxes or []
|
||||||
|
item_group = item_group_doc.parent_item_group
|
||||||
|
|
||||||
|
if not taxes:
|
||||||
|
return frappe.db.sql(""" SELECT name FROM `tabItem Tax Template` """)
|
||||||
|
else:
|
||||||
|
args = {
|
||||||
|
'item_code': filters.get('item_code'),
|
||||||
|
'posting_date': filters.get('valid_from'),
|
||||||
|
'tax_category': filters.get('tax_category')
|
||||||
|
}
|
||||||
|
|
||||||
|
taxes = _get_item_tax_template(args, taxes, for_validate=True)
|
||||||
|
return [(d,) for d in set(taxes)]
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ class StockController(AccountsController):
|
|||||||
def validate(self):
|
def validate(self):
|
||||||
super(StockController, self).validate()
|
super(StockController, self).validate()
|
||||||
self.validate_inspection()
|
self.validate_inspection()
|
||||||
|
self.validate_serialized_batch()
|
||||||
|
|
||||||
def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False):
|
def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False):
|
||||||
if self.docstatus == 2:
|
if self.docstatus == 2:
|
||||||
@@ -42,6 +43,18 @@ class StockController(AccountsController):
|
|||||||
gl_entries = self.get_asset_gl_entry(gl_entries)
|
gl_entries = self.get_asset_gl_entry(gl_entries)
|
||||||
make_gl_entries(gl_entries, from_repost=from_repost)
|
make_gl_entries(gl_entries, from_repost=from_repost)
|
||||||
|
|
||||||
|
def validate_serialized_batch(self):
|
||||||
|
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||||
|
for d in self.get("items"):
|
||||||
|
if not (hasattr(d, 'serial_no') and d.serial_no and d.batch_no): continue
|
||||||
|
|
||||||
|
serial_nos = get_serial_nos(d.serial_no)
|
||||||
|
for serial_no_data in frappe.get_all("Serial No",
|
||||||
|
filters={"name": ("in", serial_nos)}, fields=["batch_no", "name"]):
|
||||||
|
if serial_no_data.batch_no != d.batch_no:
|
||||||
|
frappe.throw(_("Row #{0}: Serial No {1} does not belong to Batch {2}")
|
||||||
|
.format(d.idx, serial_no_data.name, d.batch_no))
|
||||||
|
|
||||||
def get_gl_entries(self, warehouse_account=None, default_expense_account=None,
|
def get_gl_entries(self, warehouse_account=None, default_expense_account=None,
|
||||||
default_cost_center=None):
|
default_cost_center=None):
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ from frappe import _, scrub
|
|||||||
from frappe.utils import cint, flt, round_based_on_smallest_currency_fraction
|
from frappe.utils import cint, flt, round_based_on_smallest_currency_fraction
|
||||||
from erpnext.controllers.accounts_controller import validate_conversion_rate, \
|
from erpnext.controllers.accounts_controller import validate_conversion_rate, \
|
||||||
validate_taxes_and_charges, validate_inclusive_tax
|
validate_taxes_and_charges, validate_inclusive_tax
|
||||||
|
from erpnext.stock.get_item_details import _get_item_tax_template
|
||||||
|
|
||||||
class calculate_taxes_and_totals(object):
|
class calculate_taxes_and_totals(object):
|
||||||
def __init__(self, doc):
|
def __init__(self, doc):
|
||||||
@@ -34,6 +35,7 @@ class calculate_taxes_and_totals(object):
|
|||||||
def _calculate(self):
|
def _calculate(self):
|
||||||
self.validate_conversion_rate()
|
self.validate_conversion_rate()
|
||||||
self.calculate_item_values()
|
self.calculate_item_values()
|
||||||
|
self.validate_item_tax_template()
|
||||||
self.initialize_taxes()
|
self.initialize_taxes()
|
||||||
self.determine_exclusive_rate()
|
self.determine_exclusive_rate()
|
||||||
self.calculate_net_total()
|
self.calculate_net_total()
|
||||||
@@ -43,6 +45,38 @@ class calculate_taxes_and_totals(object):
|
|||||||
self._cleanup()
|
self._cleanup()
|
||||||
self.calculate_total_net_weight()
|
self.calculate_total_net_weight()
|
||||||
|
|
||||||
|
def validate_item_tax_template(self):
|
||||||
|
for item in self.doc.get('items'):
|
||||||
|
if item.item_code and item.get('item_tax_template'):
|
||||||
|
item_doc = frappe.get_cached_doc("Item", item.item_code)
|
||||||
|
args = {
|
||||||
|
'tax_category': self.doc.get('tax_category'),
|
||||||
|
'posting_date': self.doc.get('posting_date'),
|
||||||
|
'bill_date': self.doc.get('bill_date'),
|
||||||
|
'transaction_date': self.doc.get('transaction_date')
|
||||||
|
}
|
||||||
|
|
||||||
|
item_group = item_doc.item_group
|
||||||
|
item_group_taxes = []
|
||||||
|
|
||||||
|
while item_group:
|
||||||
|
item_group_doc = frappe.get_cached_doc('Item Group', item_group)
|
||||||
|
item_group_taxes += item_group_doc.taxes or []
|
||||||
|
item_group = item_group_doc.parent_item_group
|
||||||
|
|
||||||
|
item_taxes = item_doc.taxes or []
|
||||||
|
|
||||||
|
if not item_group_taxes and (not item_taxes):
|
||||||
|
# No validation if no taxes in item or item group
|
||||||
|
continue
|
||||||
|
|
||||||
|
taxes = _get_item_tax_template(args, item_taxes + item_group_taxes, for_validate=True)
|
||||||
|
|
||||||
|
if item.item_tax_template not in taxes:
|
||||||
|
frappe.throw(_("Row {0}: Invalid Item Tax Template for item {1}").format(
|
||||||
|
item.idx, frappe.bold(item.item_code)
|
||||||
|
))
|
||||||
|
|
||||||
def validate_conversion_rate(self):
|
def validate_conversion_rate(self):
|
||||||
# validate conversion rate
|
# validate conversion rate
|
||||||
company_currency = erpnext.get_company_currency(self.doc.company)
|
company_currency = erpnext.get_company_currency(self.doc.company)
|
||||||
@@ -312,11 +346,19 @@ class calculate_taxes_and_totals(object):
|
|||||||
last_tax = self.doc.get("taxes")[-1]
|
last_tax = self.doc.get("taxes")[-1]
|
||||||
non_inclusive_tax_amount = sum([flt(d.tax_amount_after_discount_amount)
|
non_inclusive_tax_amount = sum([flt(d.tax_amount_after_discount_amount)
|
||||||
for d in self.doc.get("taxes") if not d.included_in_print_rate])
|
for d in self.doc.get("taxes") if not d.included_in_print_rate])
|
||||||
|
|
||||||
diff = self.doc.total + non_inclusive_tax_amount \
|
diff = self.doc.total + non_inclusive_tax_amount \
|
||||||
- flt(last_tax.total, last_tax.precision("total"))
|
- flt(last_tax.total, last_tax.precision("total"))
|
||||||
|
|
||||||
|
# If discount amount applied, deduct the discount amount
|
||||||
|
# because self.doc.total is always without discount, but last_tax.total is after discount
|
||||||
|
if self.discount_amount_applied and self.doc.discount_amount:
|
||||||
|
diff -= flt(self.doc.discount_amount)
|
||||||
|
|
||||||
|
diff = flt(diff, self.doc.precision("rounding_adjustment"))
|
||||||
|
|
||||||
if diff and abs(diff) <= (5.0 / 10**last_tax.precision("tax_amount")):
|
if diff and abs(diff) <= (5.0 / 10**last_tax.precision("tax_amount")):
|
||||||
self.doc.rounding_adjustment = flt(flt(self.doc.rounding_adjustment) +
|
self.doc.rounding_adjustment = diff
|
||||||
flt(diff), self.doc.precision("rounding_adjustment"))
|
|
||||||
|
|
||||||
def calculate_totals(self):
|
def calculate_totals(self):
|
||||||
self.doc.grand_total = flt(self.doc.get("taxes")[-1].total) + flt(self.doc.rounding_adjustment) \
|
self.doc.grand_total = flt(self.doc.get("taxes")[-1].total) + flt(self.doc.rounding_adjustment) \
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from datetime import timedelta
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import get_url
|
from frappe.utils import get_url, getdate
|
||||||
from frappe.utils.verified_command import verify_request, get_signed_params
|
from frappe.utils.verified_command import verify_request, get_signed_params
|
||||||
|
|
||||||
|
|
||||||
@@ -117,7 +117,7 @@ class Appointment(Document):
|
|||||||
if self._assign:
|
if self._assign:
|
||||||
return
|
return
|
||||||
available_agents = _get_agents_sorted_by_asc_workload(
|
available_agents = _get_agents_sorted_by_asc_workload(
|
||||||
self.scheduled_time.date())
|
getdate(self.scheduled_time))
|
||||||
for agent in available_agents:
|
for agent in available_agents:
|
||||||
if(_check_agent_availability(agent, self.scheduled_time)):
|
if(_check_agent_availability(agent, self.scheduled_time)):
|
||||||
agent = agent[0]
|
agent = agent[0]
|
||||||
@@ -189,7 +189,7 @@ def _get_agents_sorted_by_asc_workload(date):
|
|||||||
assigned_to = frappe.parse_json(appointment._assign)
|
assigned_to = frappe.parse_json(appointment._assign)
|
||||||
if not assigned_to:
|
if not assigned_to:
|
||||||
continue
|
continue
|
||||||
if (assigned_to[0] in agent_list) and appointment.scheduled_time.date() == date:
|
if (assigned_to[0] in agent_list) and getdate(appointment.scheduled_time) == date:
|
||||||
appointment_counter[assigned_to[0]] += 1
|
appointment_counter[assigned_to[0]] += 1
|
||||||
sorted_agent_list = appointment_counter.most_common()
|
sorted_agent_list = appointment_counter.most_common()
|
||||||
sorted_agent_list.reverse()
|
sorted_agent_list.reverse()
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"creation": "2018-10-25 10:02:48.656165",
|
"creation": "2018-10-25 10:02:48.656165",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
@@ -23,48 +24,41 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"depends_on": "eval:doc.enabled==1",
|
"depends_on": "enabled",
|
||||||
"fieldname": "automatic_sync",
|
"fieldname": "automatic_sync",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Synchronize all accounts every hour"
|
"label": "Synchronize all accounts every hour"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:doc.enabled==1",
|
|
||||||
"fieldname": "plaid_client_id",
|
"fieldname": "plaid_client_id",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Plaid Client ID",
|
"label": "Plaid Client ID"
|
||||||
"reqd": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:doc.enabled==1",
|
|
||||||
"fieldname": "plaid_secret",
|
"fieldname": "plaid_secret",
|
||||||
"fieldtype": "Password",
|
"fieldtype": "Password",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Plaid Secret",
|
"label": "Plaid Secret"
|
||||||
"reqd": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:doc.enabled==1",
|
|
||||||
"fieldname": "plaid_public_key",
|
"fieldname": "plaid_public_key",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Plaid Public Key",
|
"label": "Plaid Public Key"
|
||||||
"reqd": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:doc.enabled==1",
|
|
||||||
"fieldname": "plaid_env",
|
"fieldname": "plaid_env",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Plaid Environment",
|
"label": "Plaid Environment"
|
||||||
"reqd": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "column_break_2",
|
"fieldname": "column_break_2",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"depends_on": "enabled",
|
||||||
"fieldname": "section_break_4",
|
"fieldname": "section_break_4",
|
||||||
"fieldtype": "Section Break"
|
"fieldtype": "Section Break"
|
||||||
},
|
},
|
||||||
@@ -74,7 +68,8 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"modified": "2019-08-13 17:00:06.939422",
|
"links": [],
|
||||||
|
"modified": "2020-01-05 10:00:22.137832",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "ERPNext Integrations",
|
"module": "ERPNext Integrations",
|
||||||
"name": "Plaid Settings",
|
"name": "Plaid Settings",
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ frappe.ui.form.on('Employee Advance', {
|
|||||||
}
|
}
|
||||||
else if (
|
else if (
|
||||||
frm.doc.docstatus === 1
|
frm.doc.docstatus === 1
|
||||||
&& flt(frm.doc.claimed_amount) < flt(frm.doc.paid_amount)
|
&& flt(frm.doc.claimed_amount) < flt(frm.doc.paid_amount) - flt(frm.doc.return_amount)
|
||||||
&& frappe.model.can_create("Expense Claim")
|
&& frappe.model.can_create("Expense Claim")
|
||||||
) {
|
) {
|
||||||
frm.add_custom_button(
|
frm.add_custom_button(
|
||||||
@@ -45,6 +45,15 @@ frappe.ui.form.on('Employee Advance', {
|
|||||||
__('Create')
|
__('Create')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (frm.doc.docstatus === 1
|
||||||
|
&& (flt(frm.doc.claimed_amount) < flt(frm.doc.paid_amount))
|
||||||
|
&& frappe.model.can_create("Journal Entry")) {
|
||||||
|
|
||||||
|
frm.add_custom_button(__("Return"), function() {
|
||||||
|
frm.trigger('make_return_entry');
|
||||||
|
}, __('Create'));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
make_payment_entry: function(frm) {
|
make_payment_entry: function(frm) {
|
||||||
@@ -83,6 +92,24 @@ frappe.ui.form.on('Employee Advance', {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
make_return_entry: function(frm) {
|
||||||
|
frappe.call({
|
||||||
|
method: 'erpnext.hr.doctype.employee_advance.employee_advance.make_return_entry',
|
||||||
|
args: {
|
||||||
|
'employee_name': frm.doc.employee,
|
||||||
|
'company': frm.doc.company,
|
||||||
|
'employee_advance_name': frm.doc.name,
|
||||||
|
'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
|
||||||
|
},
|
||||||
|
callback: function(r) {
|
||||||
|
const doclist = frappe.model.sync(r.message);
|
||||||
|
frappe.set_route('Form', doclist[0].doctype, doclist[0].name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
employee: function (frm) {
|
employee: function (frm) {
|
||||||
if (frm.doc.employee) {
|
if (frm.doc.employee) {
|
||||||
return frappe.call({
|
return frappe.call({
|
||||||
|
|||||||
@@ -1,707 +1,193 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"actions": [],
|
||||||
"allow_events_in_timeline": 0,
|
|
||||||
"allow_guest_to_view": 0,
|
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"allow_rename": 0,
|
|
||||||
"autoname": "naming_series:",
|
"autoname": "naming_series:",
|
||||||
"beta": 0,
|
|
||||||
"creation": "2017-10-09 14:26:29.612365",
|
"creation": "2017-10-09 14:26:29.612365",
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "",
|
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"naming_series",
|
||||||
|
"employee",
|
||||||
|
"employee_name",
|
||||||
|
"column_break_4",
|
||||||
|
"posting_date",
|
||||||
|
"department",
|
||||||
|
"section_break_8",
|
||||||
|
"purpose",
|
||||||
|
"column_break_11",
|
||||||
|
"advance_amount",
|
||||||
|
"paid_amount",
|
||||||
|
"due_advance_amount",
|
||||||
|
"claimed_amount",
|
||||||
|
"return_amount",
|
||||||
|
"section_break_7",
|
||||||
|
"status",
|
||||||
|
"company",
|
||||||
|
"amended_from",
|
||||||
|
"column_break_18",
|
||||||
|
"advance_account",
|
||||||
|
"mode_of_payment"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"default": "",
|
|
||||||
"fieldname": "naming_series",
|
"fieldname": "naming_series",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Series",
|
"label": "Series",
|
||||||
"length": 0,
|
"options": "HR-EAD-.YYYY.-"
|
||||||
"no_copy": 0,
|
|
||||||
"options": "HR-EAD-.YYYY.-",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "employee",
|
"fieldname": "employee",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Employee",
|
"label": "Employee",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Employee",
|
"options": "Employee",
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "employee.employee_name",
|
"fetch_from": "employee.employee_name",
|
||||||
"fieldname": "employee_name",
|
"fieldname": "employee_name",
|
||||||
"fieldtype": "Read Only",
|
"fieldtype": "Read Only",
|
||||||
"hidden": 0,
|
"label": "Employee Name"
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Employee Name",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_4",
|
"fieldname": "column_break_4",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"default": "Today",
|
"default": "Today",
|
||||||
"fieldname": "posting_date",
|
"fieldname": "posting_date",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Posting Date",
|
"label": "Posting Date",
|
||||||
"length": 0,
|
"reqd": 1
|
||||||
"no_copy": 0,
|
|
||||||
"options": "",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "employee.department",
|
"fetch_from": "employee.department",
|
||||||
"fieldname": "department",
|
"fieldname": "department",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Department",
|
"label": "Department",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Department",
|
"options": "Department",
|
||||||
"permlevel": 0,
|
"read_only": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "section_break_8",
|
"fieldname": "section_break_8",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "purpose",
|
"fieldname": "purpose",
|
||||||
"fieldtype": "Small Text",
|
"fieldtype": "Small Text",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Purpose",
|
"label": "Purpose",
|
||||||
"length": 0,
|
"reqd": 1
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_11",
|
"fieldname": "column_break_11",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "advance_amount",
|
"fieldname": "advance_amount",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Advance Amount",
|
"label": "Advance Amount",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Company:company:default_currency",
|
"options": "Company:company:default_currency",
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "paid_amount",
|
"fieldname": "paid_amount",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Paid Amount",
|
"label": "Paid Amount",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Company:company:default_currency",
|
"options": "Company:company:default_currency",
|
||||||
"permlevel": 0,
|
"read_only": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"depends_on": "eval:cur_frm.doc.employee",
|
"depends_on": "eval:cur_frm.doc.employee",
|
||||||
"fieldname": "due_advance_amount",
|
"fieldname": "due_advance_amount",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Due Advance Amount",
|
"label": "Due Advance Amount",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Company:company:default_currency",
|
"options": "Company:company:default_currency",
|
||||||
"permlevel": 0,
|
"read_only": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "claimed_amount",
|
"fieldname": "claimed_amount",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Claimed Amount",
|
"label": "Claimed Amount",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Company:company:default_currency",
|
"options": "Company:company:default_currency",
|
||||||
"permlevel": 0,
|
"read_only": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "section_break_7",
|
"fieldname": "section_break_7",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "status",
|
"fieldname": "status",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Status",
|
"label": "Status",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Draft\nPaid\nUnpaid\nClaimed\nCancelled",
|
"options": "Draft\nPaid\nUnpaid\nClaimed\nCancelled",
|
||||||
"permlevel": 0,
|
"read_only": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "company",
|
"fieldname": "company",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Company",
|
"label": "Company",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Company",
|
"options": "Company",
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "amended_from",
|
"fieldname": "amended_from",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Amended From",
|
"label": "Amended From",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Employee Advance",
|
"options": "Employee Advance",
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"print_hide_if_no_value": 0,
|
"read_only": 1
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_18",
|
"fieldname": "column_break_18",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "advance_account",
|
"fieldname": "advance_account",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 1,
|
"ignore_user_permissions": 1,
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Advance Account",
|
"label": "Advance Account",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Account",
|
"options": "Account",
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "mode_of_payment",
|
"fieldname": "mode_of_payment",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Mode of Payment",
|
"label": "Mode of Payment",
|
||||||
"length": 0,
|
"options": "Mode of Payment"
|
||||||
"no_copy": 0,
|
},
|
||||||
"options": "Mode of Payment",
|
{
|
||||||
"permlevel": 0,
|
"fieldname": "return_amount",
|
||||||
"precision": "",
|
"fieldtype": "Currency",
|
||||||
"print_hide": 0,
|
"label": "Returned Amount",
|
||||||
"print_hide_if_no_value": 0,
|
"options": "Company:company:default_currency",
|
||||||
"read_only": 0,
|
"read_only": 1
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
|
||||||
"idx": 0,
|
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"issingle": 0,
|
"links": [],
|
||||||
"istable": 0,
|
"modified": "2019-12-15 19:04:07.044505",
|
||||||
"max_attachments": 0,
|
|
||||||
"modified": "2019-01-30 11:28:15.529649",
|
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Employee Advance",
|
"name": "Employee Advance",
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 0,
|
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "Employee",
|
"role": "Employee",
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -711,27 +197,17 @@
|
|||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "Expense Approver",
|
"role": "Expense Approver",
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 1,
|
"submit": 1,
|
||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 0,
|
|
||||||
"search_fields": "employee,employee_name",
|
"search_fields": "employee,employee_name",
|
||||||
"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_views": 0
|
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,7 @@ import frappe, erpnext
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import flt, nowdate
|
from frappe.utils import flt, nowdate
|
||||||
|
from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account
|
||||||
|
|
||||||
class EmployeeAdvanceOverPayment(frappe.ValidationError):
|
class EmployeeAdvanceOverPayment(frappe.ValidationError):
|
||||||
pass
|
pass
|
||||||
@@ -53,11 +54,25 @@ class EmployeeAdvance(Document):
|
|||||||
and party = %s
|
and party = %s
|
||||||
""", (self.name, self.employee), as_dict=1)[0].paid_amount
|
""", (self.name, self.employee), as_dict=1)[0].paid_amount
|
||||||
|
|
||||||
|
return_amount = frappe.db.sql("""
|
||||||
|
select name, ifnull(sum(credit_in_account_currency), 0) as return_amount
|
||||||
|
from `tabGL Entry`
|
||||||
|
where against_voucher_type = 'Employee Advance'
|
||||||
|
and voucher_type != 'Expense Claim'
|
||||||
|
and against_voucher = %s
|
||||||
|
and party_type = 'Employee'
|
||||||
|
and party = %s
|
||||||
|
""", (self.name, self.employee), as_dict=1)[0].return_amount
|
||||||
|
|
||||||
if flt(paid_amount) > self.advance_amount:
|
if flt(paid_amount) > self.advance_amount:
|
||||||
frappe.throw(_("Row {0}# Paid Amount cannot be greater than requested advance amount"),
|
frappe.throw(_("Row {0}# Paid Amount cannot be greater than requested advance amount"),
|
||||||
EmployeeAdvanceOverPayment)
|
EmployeeAdvanceOverPayment)
|
||||||
|
|
||||||
|
if flt(return_amount) > self.paid_amount - self.claimed_amount:
|
||||||
|
frappe.throw(_("Return amount cannot be greater unclaimed amount"))
|
||||||
|
|
||||||
self.db_set("paid_amount", paid_amount)
|
self.db_set("paid_amount", paid_amount)
|
||||||
|
self.db_set("return_amount", return_amount)
|
||||||
self.set_status()
|
self.set_status()
|
||||||
frappe.db.set_value("Employee Advance", self.name , "status", self.status)
|
frappe.db.set_value("Employee Advance", self.name , "status", self.status)
|
||||||
|
|
||||||
@@ -88,8 +103,6 @@ def get_due_advance_amount(employee, posting_date):
|
|||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def make_bank_entry(dt, dn):
|
def make_bank_entry(dt, dn):
|
||||||
from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account
|
|
||||||
|
|
||||||
doc = frappe.get_doc(dt, dn)
|
doc = frappe.get_doc(dt, dn)
|
||||||
payment_account = get_default_bank_cash_account(doc.company, account_type="Cash",
|
payment_account = get_default_bank_cash_account(doc.company, account_type="Cash",
|
||||||
mode_of_payment=doc.mode_of_payment)
|
mode_of_payment=doc.mode_of_payment)
|
||||||
@@ -118,3 +131,33 @@ def make_bank_entry(dt, dn):
|
|||||||
})
|
})
|
||||||
|
|
||||||
return je.as_dict()
|
return je.as_dict()
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def make_return_entry(employee_name, company, employee_advance_name, return_amount, mode_of_payment, advance_account):
|
||||||
|
return_account = get_default_bank_cash_account(company, account_type='Cash', mode_of_payment = mode_of_payment)
|
||||||
|
je = frappe.new_doc('Journal Entry')
|
||||||
|
je.posting_date = nowdate()
|
||||||
|
je.voucher_type = 'Bank Entry'
|
||||||
|
je.company = company
|
||||||
|
je.remark = 'Return against Employee Advance: ' + employee_advance_name
|
||||||
|
|
||||||
|
je.append('accounts', {
|
||||||
|
'account': advance_account,
|
||||||
|
'credit_in_account_currency': return_amount,
|
||||||
|
'reference_type': 'Employee Advance',
|
||||||
|
'reference_name': employee_advance_name,
|
||||||
|
'party_type': 'Employee',
|
||||||
|
'party': employee_name,
|
||||||
|
'is_advance': 'Yes'
|
||||||
|
})
|
||||||
|
|
||||||
|
je.append("accounts", {
|
||||||
|
"account": return_account.account,
|
||||||
|
"debit_in_account_currency": return_amount,
|
||||||
|
"account_currency": return_account.account_currency,
|
||||||
|
"account_type": return_account.account_type
|
||||||
|
})
|
||||||
|
|
||||||
|
return je.as_dict()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
from frappe import _
|
||||||
|
|
||||||
|
def get_data():
|
||||||
|
return {
|
||||||
|
'fieldname': 'employee_advance',
|
||||||
|
'non_standard_fieldnames': {
|
||||||
|
'Payment Entry': 'reference_name',
|
||||||
|
'Journal Entry': 'reference_name'
|
||||||
|
},
|
||||||
|
'transactions': [
|
||||||
|
{
|
||||||
|
'items': ['Expense Claim']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'items': ['Payment Entry', 'Journal Entry']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -7,6 +7,14 @@ frappe.ui.form.on('Employee Onboarding', {
|
|||||||
frm.add_fetch("employee_onboarding_template", "department", "department");
|
frm.add_fetch("employee_onboarding_template", "department", "department");
|
||||||
frm.add_fetch("employee_onboarding_template", "designation", "designation");
|
frm.add_fetch("employee_onboarding_template", "designation", "designation");
|
||||||
frm.add_fetch("employee_onboarding_template", "employee_grade", "employee_grade");
|
frm.add_fetch("employee_onboarding_template", "employee_grade", "employee_grade");
|
||||||
|
|
||||||
|
frm.set_query('job_offer', function () {
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
'job_applicant': frm.doc.job_applicant
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
|
|||||||
@@ -321,7 +321,7 @@ def get_expense_claim_account(expense_claim_type, company):
|
|||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_advances(employee, advance_id=None):
|
def get_advances(employee, advance_id=None):
|
||||||
if not advance_id:
|
if not advance_id:
|
||||||
condition = 'docstatus=1 and employee={0} and paid_amount > 0 and paid_amount > claimed_amount'.format(frappe.db.escape(employee))
|
condition = 'docstatus=1 and employee={0} and paid_amount > 0 and paid_amount > claimed_amount + return_amount'.format(frappe.db.escape(employee))
|
||||||
else:
|
else:
|
||||||
condition = 'name={0}'.format(frappe.db.escape(advance_id))
|
condition = 'name={0}'.format(frappe.db.escape(advance_id))
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"creation": "2013-08-02 13:45:23",
|
"creation": "2013-08-02 13:45:23",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Other",
|
"document_type": "Other",
|
||||||
@@ -13,6 +14,7 @@
|
|||||||
"expense_approver_mandatory_in_expense_claim",
|
"expense_approver_mandatory_in_expense_claim",
|
||||||
"payroll_settings",
|
"payroll_settings",
|
||||||
"include_holidays_in_total_working_days",
|
"include_holidays_in_total_working_days",
|
||||||
|
"disable_rounded_total",
|
||||||
"max_working_hours_against_timesheet",
|
"max_working_hours_against_timesheet",
|
||||||
"column_break_11",
|
"column_break_11",
|
||||||
"email_salary_slip_to_employee",
|
"email_salary_slip_to_employee",
|
||||||
@@ -160,12 +162,20 @@
|
|||||||
"fieldname": "auto_leave_encashment",
|
"fieldname": "auto_leave_encashment",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Auto Leave Encashment"
|
"label": "Auto Leave Encashment"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"description": "If checked, hides and disables Rounded Total field in Salary Slips",
|
||||||
|
"fieldname": "disable_rounded_total",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Disable Rounded Total"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-cog",
|
"icon": "fa fa-cog",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"modified": "2019-08-05 13:07:17.993968",
|
"links": [],
|
||||||
|
"modified": "2019-12-31 14:28:32.004121",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "HR Settings",
|
"name": "HR Settings",
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
from frappe.utils import cint
|
||||||
|
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
|
||||||
|
|
||||||
class HRSettings(Document):
|
class HRSettings(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
@@ -22,3 +24,12 @@ class HRSettings(Document):
|
|||||||
if self.email_salary_slip_to_employee and self.encrypt_salary_slips_in_emails:
|
if self.email_salary_slip_to_employee and self.encrypt_salary_slips_in_emails:
|
||||||
if not self.password_policy:
|
if not self.password_policy:
|
||||||
frappe.throw(_("Password policy for Salary Slips is not set"))
|
frappe.throw(_("Password policy for Salary Slips is not set"))
|
||||||
|
|
||||||
|
def on_update(self):
|
||||||
|
self.toggle_rounded_total()
|
||||||
|
frappe.clear_cache()
|
||||||
|
|
||||||
|
def toggle_rounded_total(self):
|
||||||
|
self.disable_rounded_total = cint(self.disable_rounded_total)
|
||||||
|
make_property_setter("Salary Slip", "rounded_total", "hidden", self.disable_rounded_total, "Check")
|
||||||
|
make_property_setter("Salary Slip", "rounded_total", "print_hide", self.disable_rounded_total, "Check")
|
||||||
|
|||||||
@@ -351,7 +351,7 @@ class LeaveApplication(Document):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def create_leave_ledger_entry(self, submit=True):
|
def create_leave_ledger_entry(self, submit=True):
|
||||||
if self.status != 'Approved':
|
if self.status != 'Approved' and submit:
|
||||||
return
|
return
|
||||||
|
|
||||||
expiry_date = get_allocation_expiry(self.employee, self.leave_type,
|
expiry_date = get_allocation_expiry(self.employee, self.leave_type,
|
||||||
|
|||||||
@@ -235,8 +235,8 @@ class TestLeaveApplication(unittest.TestCase):
|
|||||||
frappe.get_doc(dict(
|
frappe.get_doc(dict(
|
||||||
doctype = 'Holiday List',
|
doctype = 'Holiday List',
|
||||||
holiday_list_name = holiday_list,
|
holiday_list_name = holiday_list,
|
||||||
from_date = date(date.today().year, 1, 1),
|
from_date = add_months(today, -6),
|
||||||
to_date = date(date.today().year, 12, 31),
|
to_date = add_months(today, 6),
|
||||||
holidays = [
|
holidays = [
|
||||||
dict(holiday_date = today, description = 'Test')
|
dict(holiday_date = today, description = 'Test')
|
||||||
]
|
]
|
||||||
@@ -597,8 +597,8 @@ def get_leave_period():
|
|||||||
return frappe.get_doc(dict(
|
return frappe.get_doc(dict(
|
||||||
name = 'Test Leave Period',
|
name = 'Test Leave Period',
|
||||||
doctype = 'Leave Period',
|
doctype = 'Leave Period',
|
||||||
from_date = "{0}-12-01".format(now_datetime().year - 1),
|
from_date = add_months(nowdate(), -6),
|
||||||
to_date = "{0}-12-31".format(now_datetime().year),
|
to_date = add_months(nowdate(), 6),
|
||||||
company = "_Test Company",
|
company = "_Test Company",
|
||||||
is_active = 1
|
is_active = 1
|
||||||
)).insert()
|
)).insert()
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -16,6 +16,7 @@ class Loan(AccountsController):
|
|||||||
self.make_repayment_schedule()
|
self.make_repayment_schedule()
|
||||||
self.set_repayment_period()
|
self.set_repayment_period()
|
||||||
self.calculate_totals()
|
self.calculate_totals()
|
||||||
|
self.set_status(from_validate=True)
|
||||||
|
|
||||||
def set_missing_fields(self):
|
def set_missing_fields(self):
|
||||||
if not self.company:
|
if not self.company:
|
||||||
@@ -95,43 +96,57 @@ class Loan(AccountsController):
|
|||||||
self.total_payment = 0
|
self.total_payment = 0
|
||||||
self.total_interest_payable = 0
|
self.total_interest_payable = 0
|
||||||
self.total_amount_paid = 0
|
self.total_amount_paid = 0
|
||||||
for data in self.repayment_schedule:
|
for schedule in self.repayment_schedule:
|
||||||
self.total_payment += data.total_payment
|
self.total_payment += schedule.total_payment
|
||||||
self.total_interest_payable +=data.interest_amount
|
self.total_interest_payable +=schedule.interest_amount
|
||||||
if data.paid:
|
if schedule.paid:
|
||||||
self.total_amount_paid += data.total_payment
|
self.total_amount_paid += schedule.total_payment
|
||||||
|
|
||||||
def update_total_amount_paid(doc):
|
def update_total_amount_paid(self):
|
||||||
total_amount_paid = 0
|
total_amount_paid = 0
|
||||||
for data in doc.repayment_schedule:
|
for schedule in self.repayment_schedule:
|
||||||
if data.paid:
|
if schedule.paid:
|
||||||
total_amount_paid += data.total_payment
|
total_amount_paid += schedule.total_payment
|
||||||
frappe.db.set_value("Loan", doc.name, "total_amount_paid", total_amount_paid)
|
frappe.db.set_value("Loan", self.name, "total_amount_paid", total_amount_paid)
|
||||||
|
|
||||||
def update_disbursement_status(doc):
|
def set_status(self, from_validate=False):
|
||||||
disbursement = frappe.db.sql("""
|
disbursement = self.get_disbursement_entry()
|
||||||
select posting_date, ifnull(sum(credit_in_account_currency), 0) as disbursed_amount
|
disbursement_date = None
|
||||||
from `tabGL Entry`
|
|
||||||
where account = %s and against_voucher_type = 'Loan' and against_voucher = %s
|
|
||||||
""", (doc.payment_account, doc.name), as_dict=1)[0]
|
|
||||||
|
|
||||||
disbursement_date = None
|
self.status = "Draft"
|
||||||
if not disbursement or disbursement.disbursed_amount == 0:
|
|
||||||
status = "Sanctioned"
|
|
||||||
elif disbursement.disbursed_amount == doc.loan_amount:
|
|
||||||
disbursement_date = disbursement.posting_date
|
|
||||||
status = "Disbursed"
|
|
||||||
elif disbursement.disbursed_amount > doc.loan_amount:
|
|
||||||
frappe.throw(_("Disbursed Amount cannot be greater than Loan Amount {0}").format(doc.loan_amount))
|
|
||||||
|
|
||||||
if status == 'Disbursed' and getdate(disbursement_date) > getdate(frappe.db.get_value("Loan", doc.name, "repayment_start_date")):
|
if (not disbursement or disbursement.disbursed_amount == 0) and self.docstatus == 1:
|
||||||
|
self.status = "Sanctioned"
|
||||||
|
if disbursement:
|
||||||
|
self.validate_disbursed_amount_and_loan_amount(disbursement.disbursed_amount)
|
||||||
|
if disbursement.disbursed_amount == self.loan_amount and disbursement.disbursed_amount != 0:
|
||||||
|
self.status = "Disbursed"
|
||||||
|
disbursement_date = disbursement.posting_date
|
||||||
|
self.validate_disbursement_date(disbursement_date, self.status)
|
||||||
|
|
||||||
|
if self.total_amount_paid == self.total_payment:
|
||||||
|
self.status = "Repaid/Closed"
|
||||||
|
|
||||||
|
if not from_validate:
|
||||||
|
frappe.db.set_value("Loan", self.name, "status", self.status)
|
||||||
|
if disbursement_date:
|
||||||
|
frappe.db.set_value("Loan", self.name, "disbursement_date", disbursement_date)
|
||||||
|
|
||||||
|
def validate_disbursement_date(self, disbursement_date, loan_status):
|
||||||
|
if loan_status == 'Disbursed' and getdate(disbursement_date) > getdate(frappe.db.get_value("Loan", self.name, "repayment_start_date")):
|
||||||
frappe.throw(_("Disbursement Date cannot be after Loan Repayment Start Date"))
|
frappe.throw(_("Disbursement Date cannot be after Loan Repayment Start Date"))
|
||||||
|
|
||||||
frappe.db.sql("""
|
|
||||||
update `tabLoan`
|
def validate_disbursed_amount_and_loan_amount(self, disbursed_amount):
|
||||||
set status = %s, disbursement_date = %s
|
if disbursed_amount > self.loan_amount:
|
||||||
where name = %s
|
frappe.throw(_("Disbursed Amount cannot be greater than Loan Amount {0}").format(self.loan_amount))
|
||||||
""", (status, disbursement_date, doc.name))
|
|
||||||
|
def get_disbursement_entry(self):
|
||||||
|
return frappe.db.sql("""
|
||||||
|
select posting_date, ifnull(sum(credit_in_account_currency), 0) as disbursed_amount
|
||||||
|
from `tabGL Entry`
|
||||||
|
where account = %s and against_voucher_type = 'Loan' and against_voucher = %s
|
||||||
|
""", (self.payment_account, self.name), as_dict=1)[0]
|
||||||
|
|
||||||
def validate_repayment_method(repayment_method, loan_amount, monthly_repayment_amount, repayment_periods):
|
def validate_repayment_method(repayment_method, loan_amount, monthly_repayment_amount, repayment_periods):
|
||||||
if repayment_method == "Repay Over Number of Periods" and not repayment_periods:
|
if repayment_method == "Repay Over Number of Periods" and not repayment_periods:
|
||||||
|
|||||||
@@ -31,7 +31,11 @@ frappe.ui.form.on('Payroll Entry', {
|
|||||||
}
|
}
|
||||||
if ((frm.doc.employees || []).length) {
|
if ((frm.doc.employees || []).length) {
|
||||||
frm.page.set_primary_action(__('Create Salary Slips'), () => {
|
frm.page.set_primary_action(__('Create Salary Slips'), () => {
|
||||||
frm.save('Submit');
|
frm.save('Submit').then(()=>{
|
||||||
|
frm.page.clear_primary_action();
|
||||||
|
frm.refresh();
|
||||||
|
frm.events.refresh(frm);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ class PayrollEntry(Document):
|
|||||||
"""
|
"""
|
||||||
cond = self.get_filter_condition()
|
cond = self.get_filter_condition()
|
||||||
return frappe.db.sql(""" select eld.loan_account, eld.loan,
|
return frappe.db.sql(""" select eld.loan_account, eld.loan,
|
||||||
eld.interest_income_account, eld.principal_amount, eld.interest_amount, eld.total_payment
|
eld.interest_income_account, eld.principal_amount, eld.interest_amount, eld.total_payment,t1.employee
|
||||||
from
|
from
|
||||||
`tabSalary Slip` t1, `tabSalary Slip Loan` eld
|
`tabSalary Slip` t1, `tabSalary Slip Loan` eld
|
||||||
where
|
where
|
||||||
@@ -246,6 +246,7 @@ class PayrollEntry(Document):
|
|||||||
accounts.append({
|
accounts.append({
|
||||||
"account": acc,
|
"account": acc,
|
||||||
"debit_in_account_currency": flt(amount, precision),
|
"debit_in_account_currency": flt(amount, precision),
|
||||||
|
"party_type": '',
|
||||||
"cost_center": self.cost_center,
|
"cost_center": self.cost_center,
|
||||||
"project": self.project
|
"project": self.project
|
||||||
})
|
})
|
||||||
@@ -257,6 +258,7 @@ class PayrollEntry(Document):
|
|||||||
"account": acc,
|
"account": acc,
|
||||||
"credit_in_account_currency": flt(amount, precision),
|
"credit_in_account_currency": flt(amount, precision),
|
||||||
"cost_center": self.cost_center,
|
"cost_center": self.cost_center,
|
||||||
|
"party_type": '',
|
||||||
"project": self.project
|
"project": self.project
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -264,7 +266,9 @@ class PayrollEntry(Document):
|
|||||||
for data in loan_details:
|
for data in loan_details:
|
||||||
accounts.append({
|
accounts.append({
|
||||||
"account": data.loan_account,
|
"account": data.loan_account,
|
||||||
"credit_in_account_currency": data.principal_amount
|
"credit_in_account_currency": data.principal_amount,
|
||||||
|
"party_type": "Employee",
|
||||||
|
"party": data.employee
|
||||||
})
|
})
|
||||||
|
|
||||||
if data.interest_amount and not data.interest_income_account:
|
if data.interest_amount and not data.interest_income_account:
|
||||||
@@ -275,14 +279,17 @@ class PayrollEntry(Document):
|
|||||||
"account": data.interest_income_account,
|
"account": data.interest_income_account,
|
||||||
"credit_in_account_currency": data.interest_amount,
|
"credit_in_account_currency": data.interest_amount,
|
||||||
"cost_center": self.cost_center,
|
"cost_center": self.cost_center,
|
||||||
"project": self.project
|
"project": self.project,
|
||||||
|
"party_type": "Employee",
|
||||||
|
"party": data.employee
|
||||||
})
|
})
|
||||||
payable_amount -= flt(data.total_payment, precision)
|
payable_amount -= flt(data.total_payment, precision)
|
||||||
|
|
||||||
# Payable amount
|
# Payable amount
|
||||||
accounts.append({
|
accounts.append({
|
||||||
"account": default_payroll_payable_account,
|
"account": default_payroll_payable_account,
|
||||||
"credit_in_account_currency": flt(payable_amount, precision)
|
"credit_in_account_currency": flt(payable_amount, precision),
|
||||||
|
"party_type": '',
|
||||||
})
|
})
|
||||||
|
|
||||||
journal_entry.set("accounts", accounts)
|
journal_entry.set("accounts", accounts)
|
||||||
@@ -322,6 +329,10 @@ class PayrollEntry(Document):
|
|||||||
statistical_component = frappe.db.get_value("Salary Component", sal_detail.salary_component, 'statistical_component')
|
statistical_component = frappe.db.get_value("Salary Component", sal_detail.salary_component, 'statistical_component')
|
||||||
if statistical_component != 1:
|
if statistical_component != 1:
|
||||||
salary_slip_total -= sal_detail.amount
|
salary_slip_total -= sal_detail.amount
|
||||||
|
|
||||||
|
#loan deduction from bank entry during payroll
|
||||||
|
salary_slip_total -= salary_slip.total_loan_repayment
|
||||||
|
|
||||||
if salary_slip_total > 0:
|
if salary_slip_total > 0:
|
||||||
self.create_journal_entry(salary_slip_total, "salary")
|
self.create_journal_entry(salary_slip_total, "salary")
|
||||||
|
|
||||||
@@ -546,7 +557,6 @@ def submit_salary_slips_for_employees(payroll_entry, salary_slips, publish_progr
|
|||||||
count += 1
|
count += 1
|
||||||
if publish_progress:
|
if publish_progress:
|
||||||
frappe.publish_progress(count*100/len(salary_slips), title = _("Submitting Salary Slips..."))
|
frappe.publish_progress(count*100/len(salary_slips), title = _("Submitting Salary Slips..."))
|
||||||
|
|
||||||
if submitted_ss:
|
if submitted_ss:
|
||||||
payroll_entry.make_accrual_jv_entry()
|
payroll_entry.make_accrual_jv_entry()
|
||||||
frappe.msgprint(_("Salary Slip submitted for period from {0} to {1}")
|
frappe.msgprint(_("Salary Slip submitted for period from {0} to {1}")
|
||||||
|
|||||||
@@ -1,231 +1,82 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
|
||||||
"allow_guest_to_view": 0,
|
|
||||||
"allow_import": 0,
|
|
||||||
"allow_rename": 0,
|
|
||||||
"beta": 0,
|
|
||||||
"creation": "2016-12-20 15:32:25.078334",
|
"creation": "2016-12-20 15:32:25.078334",
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "",
|
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"payment_date",
|
||||||
|
"principal_amount",
|
||||||
|
"interest_amount",
|
||||||
|
"total_payment",
|
||||||
|
"balance_loan_amount",
|
||||||
|
"paid"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"allow_on_submit": 1,
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 2,
|
"columns": 2,
|
||||||
"fieldname": "payment_date",
|
"fieldname": "payment_date",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
"label": "Payment Date"
|
||||||
"label": "Payment Date",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 2,
|
"columns": 2,
|
||||||
"fieldname": "principal_amount",
|
"fieldname": "principal_amount",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Principal Amount",
|
"label": "Principal Amount",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Company:company:default_currency",
|
"options": "Company:company:default_currency",
|
||||||
"permlevel": 0,
|
"read_only": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 2,
|
"columns": 2,
|
||||||
"fieldname": "interest_amount",
|
"fieldname": "interest_amount",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Interest Amount",
|
"label": "Interest Amount",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Company:company:default_currency",
|
"options": "Company:company:default_currency",
|
||||||
"permlevel": 0,
|
"read_only": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 2,
|
"columns": 2,
|
||||||
"fieldname": "total_payment",
|
"fieldname": "total_payment",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Total Payment",
|
"label": "Total Payment",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Company:company:default_currency",
|
"options": "Company:company:default_currency",
|
||||||
"permlevel": 0,
|
"read_only": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 2,
|
"columns": 2,
|
||||||
"fieldname": "balance_loan_amount",
|
"fieldname": "balance_loan_amount",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Balance Loan Amount",
|
"label": "Balance Loan Amount",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Company:company:default_currency",
|
"options": "Company:company:default_currency",
|
||||||
"permlevel": 0,
|
"read_only": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"default": "0",
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "paid",
|
"fieldname": "paid",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Paid",
|
"label": "Paid",
|
||||||
"length": 0,
|
"read_only": 1
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
|
||||||
"idx": 0,
|
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
|
||||||
"is_submittable": 0,
|
|
||||||
"issingle": 0,
|
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"max_attachments": 0,
|
"modified": "2019-10-29 11:45:10.694557",
|
||||||
"modified": "2018-03-30 17:37:31.834792",
|
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Repayment Schedule",
|
"name": "Repayment Schedule",
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [],
|
"permissions": [],
|
||||||
"quick_entry": 1,
|
"quick_entry": 1,
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 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
|
|
||||||
}
|
}
|
||||||
@@ -50,7 +50,8 @@ class SalarySlip(TransactionBase):
|
|||||||
self.calculate_net_pay()
|
self.calculate_net_pay()
|
||||||
|
|
||||||
company_currency = erpnext.get_company_currency(self.company)
|
company_currency = erpnext.get_company_currency(self.company)
|
||||||
self.total_in_words = money_in_words(self.rounded_total, company_currency)
|
total = self.net_pay if self.is_rounding_total_disabled() else self.rounded_total
|
||||||
|
self.total_in_words = money_in_words(total, company_currency)
|
||||||
|
|
||||||
if frappe.db.get_single_value("HR Settings", "max_working_hours_against_timesheet"):
|
if frappe.db.get_single_value("HR Settings", "max_working_hours_against_timesheet"):
|
||||||
max_working_hours = frappe.db.get_single_value("HR Settings", "max_working_hours_against_timesheet")
|
max_working_hours = frappe.db.get_single_value("HR Settings", "max_working_hours_against_timesheet")
|
||||||
@@ -62,6 +63,7 @@ class SalarySlip(TransactionBase):
|
|||||||
if self.net_pay < 0:
|
if self.net_pay < 0:
|
||||||
frappe.throw(_("Net Pay cannot be less than 0"))
|
frappe.throw(_("Net Pay cannot be less than 0"))
|
||||||
else:
|
else:
|
||||||
|
self.update_loans()
|
||||||
self.set_status()
|
self.set_status()
|
||||||
self.update_status(self.name)
|
self.update_status(self.name)
|
||||||
self.update_salary_slip_in_additional_salary()
|
self.update_salary_slip_in_additional_salary()
|
||||||
@@ -69,6 +71,7 @@ class SalarySlip(TransactionBase):
|
|||||||
self.email_salary_slip()
|
self.email_salary_slip()
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
|
self.update_loans()
|
||||||
self.set_status()
|
self.set_status()
|
||||||
self.update_status()
|
self.update_status()
|
||||||
self.update_salary_slip_in_additional_salary()
|
self.update_salary_slip_in_additional_salary()
|
||||||
@@ -90,6 +93,9 @@ class SalarySlip(TransactionBase):
|
|||||||
if date_diff(self.end_date, self.start_date) < 0:
|
if date_diff(self.end_date, self.start_date) < 0:
|
||||||
frappe.throw(_("To date cannot be before From date"))
|
frappe.throw(_("To date cannot be before From date"))
|
||||||
|
|
||||||
|
def is_rounding_total_disabled(self):
|
||||||
|
return cint(frappe.db.get_single_value("HR Settings", "disable_rounded_total"))
|
||||||
|
|
||||||
def check_existing(self):
|
def check_existing(self):
|
||||||
if not self.salary_slip_based_on_timesheet:
|
if not self.salary_slip_based_on_timesheet:
|
||||||
ret_exist = frappe.db.sql("""select name from `tabSalary Slip`
|
ret_exist = frappe.db.sql("""select name from `tabSalary Slip`
|
||||||
@@ -764,7 +770,8 @@ class SalarySlip(TransactionBase):
|
|||||||
self.total_principal_amount += loan.principal_amount
|
self.total_principal_amount += loan.principal_amount
|
||||||
|
|
||||||
def get_loan_details(self):
|
def get_loan_details(self):
|
||||||
return frappe.db.sql("""select rps.principal_amount, rps.interest_amount, l.name,
|
return frappe.db.sql("""select rps.principal_amount,
|
||||||
|
rps.name as repayment_name, rps.interest_amount, l.name,
|
||||||
rps.total_payment, l.loan_account, l.interest_income_account
|
rps.total_payment, l.loan_account, l.interest_income_account
|
||||||
from
|
from
|
||||||
`tabRepayment Schedule` as rps, `tabLoan` as l
|
`tabRepayment Schedule` as rps, `tabLoan` as l
|
||||||
@@ -815,6 +822,17 @@ class SalarySlip(TransactionBase):
|
|||||||
timesheet.set_status()
|
timesheet.set_status()
|
||||||
timesheet.save()
|
timesheet.save()
|
||||||
|
|
||||||
|
def update_loans(self):
|
||||||
|
for loan in self.get_loan_details():
|
||||||
|
doc = frappe.get_doc("Loan", loan.name)
|
||||||
|
|
||||||
|
#setting repayment schedule and updating total amount to pay
|
||||||
|
repayment_status = 1 if doc.docstatus == 1 else 0
|
||||||
|
frappe.db.set_value("Repayment Schedule", loan.repayment_name, "paid", repayment_status)
|
||||||
|
doc.reload()
|
||||||
|
doc.update_total_amount_paid()
|
||||||
|
doc.set_status()
|
||||||
|
|
||||||
def set_status(self, status=None):
|
def set_status(self, status=None):
|
||||||
'''Get and update status'''
|
'''Get and update status'''
|
||||||
if not status:
|
if not status:
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,475 +1,138 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"actions": [],
|
||||||
"allow_guest_to_view": 0,
|
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"allow_rename": 0,
|
|
||||||
"autoname": "HR-SSA-.YY.-.MM.-.#####",
|
"autoname": "HR-SSA-.YY.-.MM.-.#####",
|
||||||
"beta": 0,
|
|
||||||
"creation": "2018-04-13 16:38:41.769237",
|
"creation": "2018-04-13 16:38:41.769237",
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "",
|
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"employee",
|
||||||
|
"employee_name",
|
||||||
|
"department",
|
||||||
|
"designation",
|
||||||
|
"column_break_6",
|
||||||
|
"salary_structure",
|
||||||
|
"from_date",
|
||||||
|
"company",
|
||||||
|
"section_break_7",
|
||||||
|
"base",
|
||||||
|
"column_break_9",
|
||||||
|
"variable",
|
||||||
|
"amended_from"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "employee",
|
"fieldname": "employee",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 1,
|
"in_standard_filter": 1,
|
||||||
"label": "Employee",
|
"label": "Employee",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Employee",
|
"options": "Employee",
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 1,
|
"search_index": 1
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "employee.employee_name",
|
"fetch_from": "employee.employee_name",
|
||||||
"fieldname": "employee_name",
|
"fieldname": "employee_name",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Employee Name",
|
"label": "Employee Name",
|
||||||
"length": 0,
|
"read_only": 1
|
||||||
"no_copy": 0,
|
|
||||||
"options": "",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "employee.department",
|
"fetch_from": "employee.department",
|
||||||
"fieldname": "department",
|
"fieldname": "department",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 1,
|
"in_standard_filter": 1,
|
||||||
"label": "Department",
|
"label": "Department",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Department",
|
"options": "Department",
|
||||||
"permlevel": 0,
|
"read_only": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "employee.designation",
|
"fetch_from": "employee.designation",
|
||||||
"fieldname": "designation",
|
"fieldname": "designation",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 1,
|
"in_standard_filter": 1,
|
||||||
"label": "Designation",
|
"label": "Designation",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Designation",
|
"options": "Designation",
|
||||||
"permlevel": 0,
|
"read_only": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_6",
|
"fieldname": "column_break_6",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "salary_structure",
|
"fieldname": "salary_structure",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 1,
|
"in_standard_filter": 1,
|
||||||
"label": "Salary Structure",
|
"label": "Salary Structure",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Salary Structure",
|
"options": "Salary Structure",
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 1,
|
"search_index": 1
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "from_date",
|
"fieldname": "from_date",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "From Date",
|
"label": "From Date",
|
||||||
"length": 0,
|
"reqd": 1
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "company",
|
"fieldname": "company",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Company",
|
"label": "Company",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Company",
|
"options": "Company",
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
"read_only": 1,
|
||||||
"remember_last_selected_value": 0,
|
"reqd": 1
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "section_break_7",
|
"fieldname": "section_break_7",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "base",
|
"fieldname": "base",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Base",
|
"label": "Base",
|
||||||
"length": 0,
|
"options": "Company:company:default_currency"
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_9",
|
"fieldname": "column_break_9",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "variable",
|
"fieldname": "variable",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Variable",
|
"label": "Variable",
|
||||||
"length": 0,
|
"options": "Company:company:default_currency"
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "amended_from",
|
"fieldname": "amended_from",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Amended From",
|
"label": "Amended From",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Salary Structure Assignment",
|
"options": "Salary Structure Assignment",
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"print_hide_if_no_value": 0,
|
"read_only": 1
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
|
||||||
"idx": 0,
|
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"issingle": 0,
|
"links": [],
|
||||||
"istable": 0,
|
"modified": "2019-12-31 17:05:28.637510",
|
||||||
"max_attachments": 0,
|
|
||||||
"modified": "2018-08-21 16:15:48.755450",
|
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Salary Structure Assignment",
|
"name": "Salary Structure Assignment",
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
|
||||||
"import": 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,
|
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -479,46 +142,29 @@
|
|||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "HR Manager",
|
"role": "HR Manager",
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 1,
|
"submit": 1,
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 0,
|
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "HR User",
|
"role": "HR User",
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 1,
|
"submit": 1,
|
||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 0,
|
|
||||||
"show_name_in_global_search": 0,
|
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"title_field": "employee_name",
|
"title_field": "employee_name",
|
||||||
"track_changes": 1,
|
"track_changes": 1
|
||||||
"track_seen": 0,
|
|
||||||
"track_views": 0
|
|
||||||
}
|
}
|
||||||
@@ -767,7 +767,7 @@ def add_additional_cost(stock_entry, work_order):
|
|||||||
|
|
||||||
items = {}
|
items = {}
|
||||||
for d in bom.get(table):
|
for d in bom.get(table):
|
||||||
items.setdefault(d.item_code, d.rate)
|
items.setdefault(d.item_code, d.amount)
|
||||||
|
|
||||||
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)
|
||||||
@@ -776,7 +776,7 @@ def add_additional_cost(stock_entry, work_order):
|
|||||||
stock_entry.append('additional_costs', {
|
stock_entry.append('additional_costs', {
|
||||||
'expense_account': expenses_included_in_valuation,
|
'expense_account': expenses_included_in_valuation,
|
||||||
'description': name[0],
|
'description': name[0],
|
||||||
'amount': items.get(name[0])
|
'amount': flt(items.get(name[0])) * flt(stock_entry.fg_completed_qty) / flt(bom.quantity)
|
||||||
})
|
})
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
|
|||||||
@@ -3,6 +3,11 @@
|
|||||||
|
|
||||||
frappe.ui.form.on('Job Card', {
|
frappe.ui.form.on('Job Card', {
|
||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
|
|
||||||
|
if(frm.doc.docstatus == 0) {
|
||||||
|
frm.set_df_property("operation", "read_only", frm.doc.operation_id ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
if(!frm.doc.__islocal && frm.doc.items && frm.doc.items.length) {
|
if(!frm.doc.__islocal && frm.doc.items && frm.doc.items.length) {
|
||||||
if (frm.doc.for_quantity != frm.doc.transferred_qty) {
|
if (frm.doc.for_quantity != frm.doc.transferred_qty) {
|
||||||
frm.add_custom_button(__("Material Request"), () => {
|
frm.add_custom_button(__("Material Request"), () => {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ frappe.ui.form.on("Work Order", {
|
|||||||
frm.custom_make_buttons = {
|
frm.custom_make_buttons = {
|
||||||
'Stock Entry': 'Start',
|
'Stock Entry': 'Start',
|
||||||
'Pick List': 'Create Pick List',
|
'Pick List': 'Create Pick List',
|
||||||
|
'Job Card': 'Create Job Card',
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set query for warehouses
|
// Set query for warehouses
|
||||||
@@ -136,7 +137,7 @@ frappe.ui.form.on("Work Order", {
|
|||||||
|
|
||||||
if (frm.doc.docstatus === 1
|
if (frm.doc.docstatus === 1
|
||||||
&& frm.doc.operations && frm.doc.operations.length
|
&& frm.doc.operations && frm.doc.operations.length
|
||||||
&& frm.doc.qty != frm.doc.material_transferred_for_manufacturing) {
|
&& frm.doc.qty != frm.doc.produced_qty) {
|
||||||
|
|
||||||
const not_completed = frm.doc.operations.filter(d => {
|
const not_completed = frm.doc.operations.filter(d => {
|
||||||
if(d.status != 'Completed') {
|
if(d.status != 'Completed') {
|
||||||
|
|||||||
@@ -586,6 +586,7 @@ erpnext.patches.v11_0.add_permissions_in_gst_settings
|
|||||||
erpnext.patches.v11_1.setup_guardian_role
|
erpnext.patches.v11_1.setup_guardian_role
|
||||||
execute:frappe.delete_doc('DocType', 'Notification Control')
|
execute:frappe.delete_doc('DocType', 'Notification Control')
|
||||||
erpnext.patches.v12_0.set_gst_category
|
erpnext.patches.v12_0.set_gst_category
|
||||||
|
erpnext.patches.v12_0.update_gst_category
|
||||||
erpnext.patches.v11_0.remove_barcodes_field_from_copy_fields_to_variants
|
erpnext.patches.v11_0.remove_barcodes_field_from_copy_fields_to_variants
|
||||||
erpnext.patches.v12_0.set_task_status
|
erpnext.patches.v12_0.set_task_status
|
||||||
erpnext.patches.v11_0.make_italian_localization_fields # 26-03-2019
|
erpnext.patches.v11_0.make_italian_localization_fields # 26-03-2019
|
||||||
|
|||||||
@@ -98,12 +98,15 @@ def get_item_tax_template(item_tax_templates, item_tax_map, item_code, parenttyp
|
|||||||
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")
|
||||||
|
if not parent_account:
|
||||||
|
parent_account = frappe.db.get_value("Account",
|
||||||
|
filters={"account_type": "Tax", "root_type": "Liability", "is_group": 1, "company": company})
|
||||||
filters = {
|
filters = {
|
||||||
"account_name": account_name,
|
"account_name": account_name,
|
||||||
"company": company,
|
"company": company,
|
||||||
"account_type": "Tax",
|
"account_type": "Tax",
|
||||||
"parent_account": parent_account
|
"parent_account": parent_account
|
||||||
}
|
}
|
||||||
tax_type = frappe.db.get_value("Account", filters)
|
tax_type = frappe.db.get_value("Account", filters)
|
||||||
if not tax_type:
|
if not tax_type:
|
||||||
account = frappe.new_doc("Account")
|
account = frappe.new_doc("Account")
|
||||||
|
|||||||
19
erpnext/patches/v12_0/update_gst_category.py
Normal file
19
erpnext/patches/v12_0/update_gst_category.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
|
||||||
|
company = frappe.get_all('Company', filters = {'country': 'India'})
|
||||||
|
if not company:
|
||||||
|
return
|
||||||
|
|
||||||
|
frappe.db.sql(""" UPDATE `tabSales Invoice` set gst_category = 'Unregistered'
|
||||||
|
where gst_category = 'Registered Regular'
|
||||||
|
and ifnull(customer_gstin, '')=''
|
||||||
|
and ifnull(billing_address_gstin,'')=''
|
||||||
|
""")
|
||||||
|
|
||||||
|
frappe.db.sql(""" UPDATE `tabPurchase Invoice` set gst_category = 'Unregistered'
|
||||||
|
where gst_category = 'Registered Regular'
|
||||||
|
and ifnull(supplier_gstin, '')=''
|
||||||
|
""")
|
||||||
@@ -107,6 +107,12 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
|||||||
filters:{ 'item_code': row.item_code }
|
filters:{ 'item_code': row.item_code }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if(this.frm.fields_dict["items"].grid.get_field('item_code')) {
|
||||||
|
this.frm.set_query("item_tax_template", "items", function(doc, cdt, cdn) {
|
||||||
|
return me.set_query_for_item_tax_template(doc, cdt, cdn)
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
refresh: function(doc) {
|
refresh: function(doc) {
|
||||||
|
|||||||
@@ -388,9 +388,14 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
|
|||||||
var diff = me.frm.doc.total + non_inclusive_tax_amount
|
var diff = me.frm.doc.total + non_inclusive_tax_amount
|
||||||
- flt(last_tax.total, precision("grand_total"));
|
- flt(last_tax.total, precision("grand_total"));
|
||||||
|
|
||||||
|
if(me.discount_amount_applied && me.frm.doc.discount_amount) {
|
||||||
|
diff -= flt(me.frm.doc.discount_amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff = flt(diff, precision("rounding_adjustment"));
|
||||||
|
|
||||||
if ( diff && Math.abs(diff) <= (5.0 / Math.pow(10, precision("tax_amount", last_tax))) ) {
|
if ( diff && Math.abs(diff) <= (5.0 / Math.pow(10, precision("tax_amount", last_tax))) ) {
|
||||||
this.frm.doc.rounding_adjustment = flt(flt(this.frm.doc.rounding_adjustment) + diff,
|
me.frm.doc.rounding_adjustment = diff;
|
||||||
precision("rounding_adjustment"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -968,7 +968,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
|
|
||||||
qty: function(doc, cdt, cdn) {
|
qty: function(doc, cdt, cdn) {
|
||||||
let item = frappe.get_doc(cdt, cdn);
|
let item = frappe.get_doc(cdt, cdn);
|
||||||
this.conversion_factor(doc, cdt, cdn, true);
|
this.conversion_factor(doc, cdt, cdn, false);
|
||||||
this.apply_pricing_rule(item, true);
|
this.apply_pricing_rule(item, true);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1398,7 +1398,8 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
|
|
||||||
remove_pricing_rule: function(item) {
|
remove_pricing_rule: function(item) {
|
||||||
let me = this;
|
let me = this;
|
||||||
const fields = ["discount_percentage", "discount_amount", "pricing_rules"];
|
const fields = ["discount_percentage",
|
||||||
|
"discount_amount", "margin_rate_or_amount", "rate_with_margin"];
|
||||||
|
|
||||||
if(item.remove_free_item) {
|
if(item.remove_free_item) {
|
||||||
var items = [];
|
var items = [];
|
||||||
@@ -1418,6 +1419,12 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
fields.forEach(f => {
|
fields.forEach(f => {
|
||||||
row[f] = 0;
|
row[f] = 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
["pricing_rules", "margin_type"].forEach(field => {
|
||||||
|
if (row[field]) {
|
||||||
|
row[field] = '';
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1693,6 +1700,29 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
set_query_for_item_tax_template: function(doc, cdt, cdn) {
|
||||||
|
|
||||||
|
var item = frappe.get_doc(cdt, cdn);
|
||||||
|
if(!item.item_code) {
|
||||||
|
frappe.throw(__("Please enter Item Code to get item taxes"));
|
||||||
|
} else {
|
||||||
|
|
||||||
|
let filters = {
|
||||||
|
'item_code': item.item_code,
|
||||||
|
'valid_from': doc.transaction_date || doc.bill_date || doc.posting_date,
|
||||||
|
'item_group': item.item_group,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doc.tax_category)
|
||||||
|
filters['tax_category'] = doc.tax_category;
|
||||||
|
|
||||||
|
return {
|
||||||
|
query: "erpnext.controllers.queries.get_tax_template",
|
||||||
|
filters: filters
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
payment_terms_template: function() {
|
payment_terms_template: function() {
|
||||||
var me = this;
|
var me = this;
|
||||||
const doc = this.frm.doc;
|
const doc = this.frm.doc;
|
||||||
@@ -1767,14 +1797,28 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
set_reserve_warehouse: function() {
|
||||||
|
this.autofill_warehouse("reserve_warehouse");
|
||||||
|
},
|
||||||
|
|
||||||
set_warehouse: function() {
|
set_warehouse: function() {
|
||||||
|
this.autofill_warehouse("warehouse");
|
||||||
|
},
|
||||||
|
|
||||||
|
autofill_warehouse : function (warehouse_field) {
|
||||||
|
// set warehouse in all child table rows
|
||||||
var me = this;
|
var me = this;
|
||||||
if(this.frm.doc.set_warehouse) {
|
let warehouse = (warehouse_field === "warehouse") ? me.frm.doc.set_warehouse : me.frm.doc.set_reserve_warehouse;
|
||||||
$.each(this.frm.doc.items || [], function(i, item) {
|
let child_table = (warehouse_field === "warehouse") ? me.frm.doc.items : me.frm.doc.supplied_items;
|
||||||
frappe.model.set_value(me.frm.doctype + " Item", item.name, "warehouse", me.frm.doc.set_warehouse);
|
let doctype = (warehouse_field === "warehouse") ? (me.frm.doctype + " Item") : (me.frm.doctype + " Item Supplied");
|
||||||
|
|
||||||
|
if(warehouse) {
|
||||||
|
$.each(child_table || [], function(i, item) {
|
||||||
|
frappe.model.set_value(doctype, item.name, warehouse_field, warehouse);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
coupon_code: function() {
|
coupon_code: function() {
|
||||||
var me = this;
|
var me = this;
|
||||||
frappe.run_serially([
|
frappe.run_serially([
|
||||||
|
|||||||
@@ -458,7 +458,8 @@ erpnext.utils.update_child_items = function(opts) {
|
|||||||
fieldname:"item_code",
|
fieldname:"item_code",
|
||||||
options: 'Item',
|
options: 'Item',
|
||||||
in_list_view: 1,
|
in_list_view: 1,
|
||||||
read_only: 1,
|
read_only: 0,
|
||||||
|
disabled: 0,
|
||||||
label: __('Item Code')
|
label: __('Item Code')
|
||||||
}, {
|
}, {
|
||||||
fieldtype:'Float',
|
fieldtype:'Float',
|
||||||
@@ -501,6 +502,7 @@ erpnext.utils.update_child_items = function(opts) {
|
|||||||
frm.doc[opts.child_docname].forEach(d => {
|
frm.doc[opts.child_docname].forEach(d => {
|
||||||
dialog.fields_dict.trans_items.df.data.push({
|
dialog.fields_dict.trans_items.df.data.push({
|
||||||
"docname": d.name,
|
"docname": d.name,
|
||||||
|
"name": d.name,
|
||||||
"item_code": d.item_code,
|
"item_code": d.item_code,
|
||||||
"qty": d.qty,
|
"qty": d.qty,
|
||||||
"rate": d.rate,
|
"rate": d.rate,
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ erpnext.SerialNoBatchSelector = Class.extend({
|
|||||||
this.dialog.set_value('serial_no', d.serial_no);
|
this.dialog.set_value('serial_no', d.serial_no);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (d.batch_no) {
|
if (d.has_batch_no && d.batch_no) {
|
||||||
this.frm.doc.items.forEach(data => {
|
this.frm.doc.items.forEach(data => {
|
||||||
if(data.item_code == d.item_code) {
|
if(data.item_code == d.item_code) {
|
||||||
this.dialog.fields_dict.batches.df.data.push({
|
this.dialog.fields_dict.batches.df.data.push({
|
||||||
|
|||||||
@@ -3,6 +3,26 @@
|
|||||||
|
|
||||||
frappe.ui.form.on('GST HSN Code', {
|
frappe.ui.form.on('GST HSN Code', {
|
||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
|
if(! frm.doc.__islocal && frm.doc.taxes.length){
|
||||||
|
frm.add_custom_button(__('Update Taxes for Items'), function(){
|
||||||
|
frappe.confirm(
|
||||||
|
'Are you sure? It will overwrite taxes for all items with HSN Code <b>'+frm.doc.name+'</b>.',
|
||||||
|
function(){
|
||||||
|
frappe.call({
|
||||||
|
args:{
|
||||||
|
taxes: frm.doc.taxes,
|
||||||
|
hsn_code: frm.doc.name
|
||||||
|
},
|
||||||
|
method: 'erpnext.regional.doctype.gst_hsn_code.gst_hsn_code.update_taxes_in_item_master',
|
||||||
|
callback: function(r) {
|
||||||
|
if(r.message){
|
||||||
|
frappe.show_alert(__('Item taxes updated'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,104 +1,48 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"actions": [],
|
||||||
"allow_guest_to_view": 0,
|
|
||||||
"allow_import": 0,
|
|
||||||
"allow_rename": 0,
|
|
||||||
"autoname": "field:hsn_code",
|
"autoname": "field:hsn_code",
|
||||||
"beta": 0,
|
|
||||||
"creation": "2017-06-21 10:48:56.422086",
|
"creation": "2017-06-21 10:48:56.422086",
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "",
|
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"hsn_code",
|
||||||
|
"description",
|
||||||
|
"taxes"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "hsn_code",
|
"fieldname": "hsn_code",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "HSN Code",
|
"label": "HSN Code",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 0,
|
"unique": 1
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "description",
|
"fieldname": "description",
|
||||||
"fieldtype": "Small Text",
|
"fieldtype": "Small Text",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
"label": "Description"
|
||||||
"label": "Description",
|
},
|
||||||
"length": 0,
|
{
|
||||||
"no_copy": 0,
|
"fieldname": "taxes",
|
||||||
"permlevel": 0,
|
"fieldtype": "Table",
|
||||||
"precision": "",
|
"label": "Taxes",
|
||||||
"print_hide": 0,
|
"options": "Item Tax"
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
"links": [],
|
||||||
"hide_heading": 0,
|
"modified": "2019-12-29 11:32:06.849631",
|
||||||
"hide_toolbar": 0,
|
|
||||||
"idx": 0,
|
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
|
||||||
"is_submittable": 0,
|
|
||||||
"issingle": 0,
|
|
||||||
"istable": 0,
|
|
||||||
"max_attachments": 0,
|
|
||||||
"modified": "2017-09-29 14:38:52.220743",
|
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Regional",
|
"module": "Regional",
|
||||||
"name": "GST HSN Code",
|
"name": "GST HSN Code",
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [],
|
"permissions": [],
|
||||||
"quick_entry": 1,
|
"quick_entry": 1,
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 0,
|
|
||||||
"search_fields": "hsn_code, description",
|
"search_fields": "hsn_code, description",
|
||||||
"show_name_in_global_search": 0,
|
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"title_field": "hsn_code",
|
"title_field": "hsn_code",
|
||||||
"track_changes": 1,
|
"track_changes": 1
|
||||||
"track_seen": 0
|
|
||||||
}
|
}
|
||||||
@@ -8,3 +8,26 @@ from frappe.model.document import Document
|
|||||||
|
|
||||||
class GSTHSNCode(Document):
|
class GSTHSNCode(Document):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def update_taxes_in_item_master(taxes, hsn_code):
|
||||||
|
items = frappe.get_list("Item", filters={
|
||||||
|
'gst_hsn_code': hsn_code
|
||||||
|
})
|
||||||
|
|
||||||
|
taxes = frappe.parse_json(taxes)
|
||||||
|
frappe.enqueue(update_item_document, items=items, taxes=taxes)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def update_item_document(items, taxes):
|
||||||
|
for item in items:
|
||||||
|
item_to_be_updated=frappe.get_doc("Item", item.name)
|
||||||
|
item_to_be_updated.taxes = []
|
||||||
|
for tax in taxes:
|
||||||
|
tax = frappe._dict(tax)
|
||||||
|
item_to_be_updated.append("taxes", {
|
||||||
|
'item_tax_template': tax.item_tax_template,
|
||||||
|
'tax_category': tax.tax_category,
|
||||||
|
'valid_from': tax.valid_from
|
||||||
|
})
|
||||||
|
item_to_be_updated.save()
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ Provide a report and downloadable CSV according to the German DATEV format.
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import datetime
|
import datetime
|
||||||
import json
|
import json
|
||||||
|
import six
|
||||||
from six import string_types
|
from six import string_types
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
@@ -158,7 +160,7 @@ def get_gl_entries(filters, as_dict):
|
|||||||
where gl.company = %(company)s
|
where gl.company = %(company)s
|
||||||
and DATE(gl.posting_date) >= %(from_date)s
|
and DATE(gl.posting_date) >= %(from_date)s
|
||||||
and DATE(gl.posting_date) <= %(to_date)s
|
and DATE(gl.posting_date) <= %(to_date)s
|
||||||
order by 'Belegdatum', gl.voucher_no""", filters, as_dict=as_dict)
|
order by 'Belegdatum', gl.voucher_no""", filters, as_dict=as_dict, as_utf8=1)
|
||||||
|
|
||||||
return gl_entries
|
return gl_entries
|
||||||
|
|
||||||
@@ -404,7 +406,8 @@ def get_datev_csv(data, filters):
|
|||||||
|
|
||||||
header = ';'.join(header).encode('latin_1')
|
header = ';'.join(header).encode('latin_1')
|
||||||
data = result.to_csv(
|
data = result.to_csv(
|
||||||
sep=b';',
|
# Reason for str(';'): https://github.com/pandas-dev/pandas/issues/6035
|
||||||
|
sep=str(';'),
|
||||||
# European decimal seperator
|
# European decimal seperator
|
||||||
decimal=',',
|
decimal=',',
|
||||||
# Windows "ANSI" encoding
|
# Windows "ANSI" encoding
|
||||||
@@ -412,13 +415,16 @@ def get_datev_csv(data, filters):
|
|||||||
# format date as DDMM
|
# format date as DDMM
|
||||||
date_format='%d%m',
|
date_format='%d%m',
|
||||||
# Windows line terminator
|
# Windows line terminator
|
||||||
line_terminator=b'\r\n',
|
line_terminator='\r\n',
|
||||||
# Do not number rows
|
# Do not number rows
|
||||||
index=False,
|
index=False,
|
||||||
# Use all columns defined above
|
# Use all columns defined above
|
||||||
columns=columns
|
columns=columns
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if not six.PY2:
|
||||||
|
data = data.encode('latin_1')
|
||||||
|
|
||||||
return header + b'\r\n' + data
|
return header + b'\r\n' + data
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"autoname": "naming_series:",
|
"autoname": "naming_series:",
|
||||||
"creation": "2013-05-24 19:29:08",
|
"creation": "2013-05-24 19:29:08",
|
||||||
@@ -536,7 +537,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "other_charges_calculation",
|
"fieldname": "other_charges_calculation",
|
||||||
"fieldtype": "Text",
|
"fieldtype": "Long Text",
|
||||||
"label": "Taxes and Charges Calculation",
|
"label": "Taxes and Charges Calculation",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldtype": "HTML",
|
"oldfieldtype": "HTML",
|
||||||
@@ -927,8 +928,9 @@
|
|||||||
"icon": "fa fa-shopping-cart",
|
"icon": "fa fa-shopping-cart",
|
||||||
"idx": 82,
|
"idx": 82,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
|
"links": [],
|
||||||
"max_attachments": 1,
|
"max_attachments": 1,
|
||||||
"modified": "2019-11-12 13:19:11.895715",
|
"modified": "2019-12-30 19:14:56.630270",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Selling",
|
"module": "Selling",
|
||||||
"name": "Quotation",
|
"name": "Quotation",
|
||||||
|
|||||||
@@ -6,13 +6,14 @@
|
|||||||
frappe.ui.form.on("Sales Order", {
|
frappe.ui.form.on("Sales Order", {
|
||||||
setup: function(frm) {
|
setup: function(frm) {
|
||||||
frm.custom_make_buttons = {
|
frm.custom_make_buttons = {
|
||||||
'Delivery Note': 'Delivery',
|
'Delivery Note': 'Delivery Note',
|
||||||
'Pick List': 'Pick List',
|
'Pick List': 'Pick List',
|
||||||
'Sales Invoice': 'Invoice',
|
'Sales Invoice': 'Invoice',
|
||||||
'Material Request': 'Material Request',
|
'Material Request': 'Material Request',
|
||||||
'Purchase Order': 'Purchase Order',
|
'Purchase Order': 'Purchase Order',
|
||||||
'Project': 'Project',
|
'Project': 'Project',
|
||||||
'Payment Entry': "Payment"
|
'Payment Entry': "Payment",
|
||||||
|
'Work Order': "Work Order"
|
||||||
}
|
}
|
||||||
frm.add_fetch('customer', 'tax_id', 'tax_id');
|
frm.add_fetch('customer', 'tax_id', 'tax_id');
|
||||||
|
|
||||||
@@ -134,6 +135,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
|||||||
}
|
}
|
||||||
if(doc.status !== 'Closed') {
|
if(doc.status !== 'Closed') {
|
||||||
if(doc.status !== 'On Hold') {
|
if(doc.status !== 'On Hold') {
|
||||||
|
debugger;
|
||||||
|
|
||||||
allow_delivery = this.frm.doc.items.some(item => item.delivered_by_supplier === 0 && item.qty > flt(item.delivered_qty))
|
allow_delivery = this.frm.doc.items.some(item => item.delivered_by_supplier === 0 && item.qty > flt(item.delivered_qty))
|
||||||
&& !this.frm.doc.skip_delivery_note
|
&& !this.frm.doc.skip_delivery_note
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"autoname": "naming_series:",
|
"autoname": "naming_series:",
|
||||||
"creation": "2013-06-18 12:39:59",
|
"creation": "2013-06-18 12:39:59",
|
||||||
@@ -619,7 +620,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "other_charges_calculation",
|
"fieldname": "other_charges_calculation",
|
||||||
"fieldtype": "Text",
|
"fieldtype": "Long Text",
|
||||||
"label": "Taxes and Charges Calculation",
|
"label": "Taxes and Charges Calculation",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldtype": "HTML",
|
"oldfieldtype": "HTML",
|
||||||
@@ -1194,7 +1195,8 @@
|
|||||||
"icon": "fa fa-file-text",
|
"icon": "fa fa-file-text",
|
||||||
"idx": 105,
|
"idx": 105,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"modified": "2019-10-23 14:26:42.767189",
|
"links": [],
|
||||||
|
"modified": "2019-12-30 19:15:28.605085",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Selling",
|
"module": "Selling",
|
||||||
"name": "Sales Order",
|
"name": "Sales Order",
|
||||||
|
|||||||
@@ -380,6 +380,9 @@ class SalesOrder(SellingController):
|
|||||||
def get_work_order_items(self, for_raw_material_request=0):
|
def get_work_order_items(self, for_raw_material_request=0):
|
||||||
'''Returns items with BOM that already do not have a linked work order'''
|
'''Returns items with BOM that already do not have a linked work order'''
|
||||||
items = []
|
items = []
|
||||||
|
item_codes = [i.item_code for i in self.items]
|
||||||
|
product_bundle_parents = [pb.new_item_code for pb in frappe.get_all("Product Bundle", {"new_item_code": ["in", item_codes]}, ["new_item_code"])]
|
||||||
|
|
||||||
for table in [self.items, self.packed_items]:
|
for table in [self.items, self.packed_items]:
|
||||||
for i in table:
|
for i in table:
|
||||||
bom = get_default_bom_item(i.item_code)
|
bom = get_default_bom_item(i.item_code)
|
||||||
@@ -391,7 +394,7 @@ class SalesOrder(SellingController):
|
|||||||
else:
|
else:
|
||||||
pending_qty = stock_qty
|
pending_qty = stock_qty
|
||||||
|
|
||||||
if pending_qty:
|
if pending_qty and i.item_code not in product_bundle_parents:
|
||||||
if bom:
|
if bom:
|
||||||
items.append(dict(
|
items.append(dict(
|
||||||
name= i.name,
|
name= i.name,
|
||||||
@@ -420,7 +423,7 @@ class SalesOrder(SellingController):
|
|||||||
|
|
||||||
def _get_delivery_date(ref_doc_delivery_date, red_doc_transaction_date, transaction_date):
|
def _get_delivery_date(ref_doc_delivery_date, red_doc_transaction_date, transaction_date):
|
||||||
delivery_date = get_next_schedule_date(ref_doc_delivery_date,
|
delivery_date = get_next_schedule_date(ref_doc_delivery_date,
|
||||||
auto_repeat_doc.frequency, cint(auto_repeat_doc.repeat_on_day))
|
auto_repeat_doc.frequency, auto_repeat_doc.start_date, cint(auto_repeat_doc.repeat_on_day))
|
||||||
|
|
||||||
if delivery_date <= transaction_date:
|
if delivery_date <= transaction_date:
|
||||||
delivery_date_diff = frappe.utils.date_diff(ref_doc_delivery_date, red_doc_transaction_date)
|
delivery_date_diff = frappe.utils.date_diff(ref_doc_delivery_date, red_doc_transaction_date)
|
||||||
|
|||||||
@@ -320,7 +320,12 @@ class TestSalesOrder(unittest.TestCase):
|
|||||||
create_dn_against_so(so.name, 4)
|
create_dn_against_so(so.name, 4)
|
||||||
make_sales_invoice(so.name)
|
make_sales_invoice(so.name)
|
||||||
|
|
||||||
trans_item = json.dumps([{'item_code' : '_Test Item 2', 'rate' : 200, 'qty' : 7}])
|
first_item_of_so = so.get("items")[0]
|
||||||
|
trans_item = json.dumps([
|
||||||
|
{'item_code' : first_item_of_so.item_code, 'rate' : first_item_of_so.rate, \
|
||||||
|
'qty' : first_item_of_so.qty, 'docname': first_item_of_so.name},
|
||||||
|
{'item_code' : '_Test Item 2', 'rate' : 200, 'qty' : 7}
|
||||||
|
])
|
||||||
update_child_qty_rate('Sales Order', trans_item, so.name)
|
update_child_qty_rate('Sales Order', trans_item, so.name)
|
||||||
|
|
||||||
so.reload()
|
so.reload()
|
||||||
@@ -330,6 +335,48 @@ class TestSalesOrder(unittest.TestCase):
|
|||||||
self.assertEqual(so.get("items")[-1].amount, 1400)
|
self.assertEqual(so.get("items")[-1].amount, 1400)
|
||||||
self.assertEqual(so.status, 'To Deliver and Bill')
|
self.assertEqual(so.status, 'To Deliver and Bill')
|
||||||
|
|
||||||
|
def test_remove_item_in_update_child_qty_rate(self):
|
||||||
|
so = make_sales_order(**{
|
||||||
|
"item_list": [{
|
||||||
|
"item_code": '_Test Item',
|
||||||
|
"qty": 5,
|
||||||
|
"rate":1000
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
create_dn_against_so(so.name, 2)
|
||||||
|
make_sales_invoice(so.name)
|
||||||
|
|
||||||
|
# add an item so as to try removing items
|
||||||
|
trans_item = json.dumps([
|
||||||
|
{"item_code": '_Test Item', "qty": 5, "rate":1000, "docname": so.get("items")[0].name},
|
||||||
|
{"item_code": '_Test Item 2', "qty": 2, "rate":500}
|
||||||
|
])
|
||||||
|
update_child_qty_rate('Sales Order', trans_item, so.name)
|
||||||
|
so.reload()
|
||||||
|
self.assertEqual(len(so.get("items")), 2)
|
||||||
|
|
||||||
|
# check if delivered items can be removed
|
||||||
|
trans_item = json.dumps([{
|
||||||
|
"item_code": '_Test Item 2',
|
||||||
|
"qty": 2,
|
||||||
|
"rate":500,
|
||||||
|
"docname": so.get("items")[1].name
|
||||||
|
}])
|
||||||
|
self.assertRaises(frappe.ValidationError, update_child_qty_rate, 'Sales Order', trans_item, so.name)
|
||||||
|
|
||||||
|
#remove last added item
|
||||||
|
trans_item = json.dumps([{
|
||||||
|
"item_code": '_Test Item',
|
||||||
|
"qty": 5,
|
||||||
|
"rate":1000,
|
||||||
|
"docname": so.get("items")[0].name
|
||||||
|
}])
|
||||||
|
update_child_qty_rate('Sales Order', trans_item, so.name)
|
||||||
|
|
||||||
|
so.reload()
|
||||||
|
self.assertEqual(len(so.get("items")), 1)
|
||||||
|
self.assertEqual(so.status, 'To Deliver and Bill')
|
||||||
|
|
||||||
|
|
||||||
def test_update_child_qty_rate(self):
|
def test_update_child_qty_rate(self):
|
||||||
so = make_sales_order(item_code= "_Test Item", qty=4)
|
so = make_sales_order(item_code= "_Test Item", qty=4)
|
||||||
|
|||||||
@@ -84,6 +84,13 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
|
|||||||
return me.set_query_for_batch(doc, cdt, cdn)
|
return me.set_query_for_batch(doc, cdt, cdn)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(this.frm.fields_dict["items"].grid.get_field('item_code')) {
|
||||||
|
this.frm.set_query("item_tax_template", "items", function(doc, cdt, cdn) {
|
||||||
|
return me.set_query_for_item_tax_template(doc, cdt, cdn)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
refresh: function() {
|
refresh: function() {
|
||||||
|
|||||||
@@ -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 = '"+session['user'].replace("'", "\\'")+"'"
|
if val == 1: add_cond += " and system_user = '"+ 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 = '"+cstr(customer).replace("'", "\\'")+"'"
|
add_cond = " and master_name = '"+ 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"):
|
||||||
|
|||||||
@@ -106,7 +106,11 @@ def delete_lead_addresses(company_name):
|
|||||||
frappe.db.sql("""update tabCustomer set lead_name=NULL where lead_name in ({leads})""".format(leads=",".join(leads)))
|
frappe.db.sql("""update tabCustomer set lead_name=NULL where lead_name in ({leads})""".format(leads=",".join(leads)))
|
||||||
|
|
||||||
def delete_communications(doctype, company_name, company_fieldname):
|
def delete_communications(doctype, company_name, company_fieldname):
|
||||||
frappe.db.sql("""
|
|
||||||
DELETE FROM `tabCommunication` WHERE reference_doctype = %s AND
|
refrence_docs = frappe.get_all(doctype, filters={company_fieldname:company_name})
|
||||||
EXISTS (SELECT name FROM `tab{0}` WHERE {1} = %s AND `tabCommunication`.reference_name = name)
|
reference_doctype_names = [r.name for r in refrence_docs]
|
||||||
""".format(doctype, company_fieldname), (doctype, company_name))
|
|
||||||
|
communications = frappe.get_all("Communication", filters={"reference_doctype":doctype,"reference_name":["in",reference_doctype_names]})
|
||||||
|
communication_names = [c.name for c in communications]
|
||||||
|
|
||||||
|
frappe.delete_doc("Communication",communication_names)
|
||||||
|
|||||||
@@ -88,6 +88,56 @@ class TestCompany(unittest.TestCase):
|
|||||||
self.delete_mode_of_payment(template)
|
self.delete_mode_of_payment(template)
|
||||||
frappe.delete_doc("Company", template)
|
frappe.delete_doc("Company", template)
|
||||||
|
|
||||||
|
def test_delete_communication(self):
|
||||||
|
from erpnext.setup.doctype.company.delete_company_transactions import delete_communications
|
||||||
|
company = create_child_company()
|
||||||
|
lead = create_test_lead_in_company(company)
|
||||||
|
communication = create_company_communication("Lead", lead)
|
||||||
|
delete_communications("Lead", "Test Company", "company")
|
||||||
|
self.assertFalse(frappe.db.exists("Communcation", communication))
|
||||||
|
self.assertFalse(frappe.db.exists({"doctype":"Comunication Link", "link_name": communication}))
|
||||||
|
|
||||||
def delete_mode_of_payment(self, company):
|
def delete_mode_of_payment(self, company):
|
||||||
frappe.db.sql(""" delete from `tabMode of Payment Account`
|
frappe.db.sql(""" delete from `tabMode of Payment Account`
|
||||||
where company =%s """, (company))
|
where company =%s """, (company))
|
||||||
|
|
||||||
|
def create_company_communication(doctype, docname):
|
||||||
|
comm = frappe.get_doc({
|
||||||
|
"doctype": "Communication",
|
||||||
|
"communication_type": "Communication",
|
||||||
|
"content": "Deduplication of Links",
|
||||||
|
"communication_medium": "Email",
|
||||||
|
"reference_doctype":doctype,
|
||||||
|
"reference_name":docname
|
||||||
|
})
|
||||||
|
comm.insert()
|
||||||
|
|
||||||
|
def create_child_company():
|
||||||
|
child_company = frappe.db.exists("Company", "Test Company")
|
||||||
|
if not child_company:
|
||||||
|
child_company = frappe.get_doc({
|
||||||
|
"doctype":"Company",
|
||||||
|
"company_name":"Test Company",
|
||||||
|
"abbr":"test_company",
|
||||||
|
"default_currency":"INR"
|
||||||
|
})
|
||||||
|
child_company.insert()
|
||||||
|
else:
|
||||||
|
child_company = frappe.get_doc("Company", child_company)
|
||||||
|
|
||||||
|
return child_company.name
|
||||||
|
|
||||||
|
def create_test_lead_in_company(company):
|
||||||
|
lead = frappe.db.exists("Lead", "Test Lead in new company")
|
||||||
|
if not lead:
|
||||||
|
lead = frappe.get_doc({
|
||||||
|
"doctype": "Lead",
|
||||||
|
"lead_name": "Test Lead in new company",
|
||||||
|
"scompany": company
|
||||||
|
})
|
||||||
|
lead.insert()
|
||||||
|
else:
|
||||||
|
lead = frappe.get_doc("Lead", lead)
|
||||||
|
lead.company = company
|
||||||
|
lead.save()
|
||||||
|
return lead.name
|
||||||
|
|||||||
@@ -226,16 +226,14 @@ def set_batch_nos(doc, warehouse_field, throw=False):
|
|||||||
warehouse = d.get(warehouse_field, None)
|
warehouse = d.get(warehouse_field, None)
|
||||||
if has_batch_no and warehouse and qty > 0:
|
if has_batch_no and warehouse and qty > 0:
|
||||||
if not d.batch_no:
|
if not d.batch_no:
|
||||||
d.batch_no = get_batch_no(d.item_code, warehouse, qty, throw)
|
d.batch_no = get_batch_no(d.item_code, warehouse, qty, throw, d.serial_no)
|
||||||
else:
|
else:
|
||||||
batch_qty = get_batch_qty(batch_no=d.batch_no, warehouse=warehouse)
|
batch_qty = get_batch_qty(batch_no=d.batch_no, warehouse=warehouse)
|
||||||
if flt(batch_qty, d.precision("qty")) < flt(qty, d.precision("qty")):
|
if flt(batch_qty, d.precision("qty")) < flt(qty, d.precision("qty")):
|
||||||
frappe.throw(_("Row #{0}: The batch {1} has only {2} qty. Please select another batch which has {3} qty available or split the row into multiple rows, to deliver/issue from multiple batches").format(d.idx, d.batch_no, batch_qty, qty))
|
frappe.throw(_("Row #{0}: The batch {1} has only {2} qty. Please select another batch which has {3} qty available or split the row into multiple rows, to deliver/issue from multiple batches").format(d.idx, d.batch_no, batch_qty, qty))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_batch_no(item_code, warehouse, qty=1, throw=False):
|
def get_batch_no(item_code, warehouse, qty=1, throw=False, serial_no=None):
|
||||||
"""
|
"""
|
||||||
Get batch number using First Expiring First Out method.
|
Get batch number using First Expiring First Out method.
|
||||||
:param item_code: `item_code` of Item Document
|
:param item_code: `item_code` of Item Document
|
||||||
@@ -245,7 +243,7 @@ def get_batch_no(item_code, warehouse, qty=1, throw=False):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
batch_no = None
|
batch_no = None
|
||||||
batches = get_batches(item_code, warehouse, qty, throw)
|
batches = get_batches(item_code, warehouse, qty, throw, serial_no)
|
||||||
|
|
||||||
for batch in batches:
|
for batch in batches:
|
||||||
if cint(qty) <= cint(batch.qty):
|
if cint(qty) <= cint(batch.qty):
|
||||||
@@ -260,16 +258,31 @@ def get_batch_no(item_code, warehouse, qty=1, throw=False):
|
|||||||
return batch_no
|
return batch_no
|
||||||
|
|
||||||
|
|
||||||
def get_batches(item_code, warehouse, qty=1, throw=False):
|
def get_batches(item_code, warehouse, qty=1, throw=False, serial_no=None):
|
||||||
batches = frappe.db.sql(
|
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||||
'select batch_id, sum(actual_qty) as qty from `tabBatch` join `tabStock Ledger Entry` ignore index (item_code, warehouse) '
|
cond = ''
|
||||||
'on (`tabBatch`.batch_id = `tabStock Ledger Entry`.batch_no )'
|
if serial_no:
|
||||||
'where `tabStock Ledger Entry`.item_code = %s and `tabStock Ledger Entry`.warehouse = %s '
|
batch = frappe.get_all("Serial No",
|
||||||
'and (`tabBatch`.expiry_date >= CURDATE() or `tabBatch`.expiry_date IS NULL)'
|
fields = ["distinct batch_no"],
|
||||||
'group by batch_id '
|
filters= {
|
||||||
'order by `tabBatch`.expiry_date ASC, `tabBatch`.creation ASC',
|
"item_code": item_code,
|
||||||
(item_code, warehouse),
|
"warehouse": warehouse,
|
||||||
as_dict=True
|
"name": ("in", get_serial_nos(serial_no))
|
||||||
)
|
}
|
||||||
|
)
|
||||||
|
|
||||||
return batches
|
if batch and len(batch) > 1:
|
||||||
|
return []
|
||||||
|
|
||||||
|
cond = " and `tabBatch`.name = %s" %(frappe.db.escape(batch[0].batch_no))
|
||||||
|
|
||||||
|
return frappe.db.sql("""
|
||||||
|
select batch_id, sum(`tabStock Ledger Entry`.actual_qty) as qty
|
||||||
|
from `tabBatch`
|
||||||
|
join `tabStock Ledger Entry` ignore index (item_code, warehouse)
|
||||||
|
on (`tabBatch`.batch_id = `tabStock Ledger Entry`.batch_no )
|
||||||
|
where `tabStock Ledger Entry`.item_code = %s and `tabStock Ledger Entry`.warehouse = %s
|
||||||
|
and (`tabBatch`.expiry_date >= CURDATE() or `tabBatch`.expiry_date IS NULL) {0}
|
||||||
|
group by batch_id
|
||||||
|
order by `tabBatch`.expiry_date ASC, `tabBatch`.creation ASC
|
||||||
|
""".format(cond), (item_code, warehouse), as_dict=True)
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"autoname": "naming_series:",
|
"autoname": "naming_series:",
|
||||||
"creation": "2013-05-24 19:29:09",
|
"creation": "2013-05-24 19:29:09",
|
||||||
@@ -682,7 +683,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "other_charges_calculation",
|
"fieldname": "other_charges_calculation",
|
||||||
"fieldtype": "Text",
|
"fieldtype": "Long Text",
|
||||||
"label": "Taxes and Charges Calculation",
|
"label": "Taxes and Charges Calculation",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldtype": "HTML",
|
"oldfieldtype": "HTML",
|
||||||
@@ -1238,7 +1239,8 @@
|
|||||||
"icon": "fa fa-truck",
|
"icon": "fa fa-truck",
|
||||||
"idx": 146,
|
"idx": 146,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"modified": "2019-09-27 14:24:20.269682",
|
"links": [],
|
||||||
|
"modified": "2019-12-30 19:17:13.122644",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Delivery Note",
|
"name": "Delivery Note",
|
||||||
|
|||||||
@@ -136,6 +136,20 @@ frappe.ui.form.on("Item", {
|
|||||||
frm.toggle_reqd('customer', frm.doc.is_customer_provided_item ? 1:0);
|
frm.toggle_reqd('customer', frm.doc.is_customer_provided_item ? 1:0);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
gst_hsn_code: function(frm){
|
||||||
|
if(!frm.doc.taxes.length) {
|
||||||
|
frappe.db.get_doc("GST HSN Code", frm.doc.gst_hsn_code).then(hsn_doc => {
|
||||||
|
$.each(hsn_doc.taxes || [], function(i, tax) {
|
||||||
|
let a = frappe.model.add_child(frm.doc, 'Item Tax', 'taxes');
|
||||||
|
a.item_tax_template = tax.item_tax_template;
|
||||||
|
a.tax_category = tax.tax_category;
|
||||||
|
a.valid_from = tax.valid_from;
|
||||||
|
frm.refresh_field('taxes');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
is_fixed_asset: function(frm) {
|
is_fixed_asset: function(frm) {
|
||||||
// set serial no to false & toggles its visibility
|
// set serial no to false & toggles its visibility
|
||||||
frm.set_value('has_serial_no', 0);
|
frm.set_value('has_serial_no', 0);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"allow_guest_to_view": 1,
|
"allow_guest_to_view": 1,
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"allow_rename": 1,
|
"allow_rename": 1,
|
||||||
@@ -569,6 +570,7 @@
|
|||||||
{
|
{
|
||||||
"default": "0.00",
|
"default": "0.00",
|
||||||
"depends_on": "is_stock_item",
|
"depends_on": "is_stock_item",
|
||||||
|
"description": "Minimum quantity should be as per Stock UOM",
|
||||||
"fieldname": "min_order_qty",
|
"fieldname": "min_order_qty",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"label": "Minimum Order Qty",
|
"label": "Minimum Order Qty",
|
||||||
@@ -1041,8 +1043,9 @@
|
|||||||
"icon": "fa fa-tag",
|
"icon": "fa fa-tag",
|
||||||
"idx": 2,
|
"idx": 2,
|
||||||
"image_field": "image",
|
"image_field": "image",
|
||||||
|
"links": [],
|
||||||
"max_attachments": 1,
|
"max_attachments": 1,
|
||||||
"modified": "2019-12-13 12:15:56.197246",
|
"modified": "2020-01-02 19:13:59.295963",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Item",
|
"name": "Item",
|
||||||
|
|||||||
@@ -551,7 +551,7 @@ class Item(WebsiteGenerator):
|
|||||||
"""select parent from `tabItem Barcode` where barcode = %s and parent != %s""", (item_barcode.barcode, self.name))
|
"""select parent from `tabItem Barcode` where barcode = %s and parent != %s""", (item_barcode.barcode, self.name))
|
||||||
if duplicate:
|
if duplicate:
|
||||||
frappe.throw(_("Barcode {0} already used in Item {1}").format(
|
frappe.throw(_("Barcode {0} already used in Item {1}").format(
|
||||||
item_barcode.barcode, duplicate[0][0]), frappe.DuplicateEntryError)
|
item_barcode.barcode, duplicate[0][0]))
|
||||||
|
|
||||||
item_barcode.barcode_type = "" if item_barcode.barcode_type not in options else item_barcode.barcode_type
|
item_barcode.barcode_type = "" if item_barcode.barcode_type not in options else item_barcode.barcode_type
|
||||||
if item_barcode.barcode_type and item_barcode.barcode_type.upper() in ('EAN', 'UPC-A', 'EAN-13', 'EAN-8'):
|
if item_barcode.barcode_type and item_barcode.barcode_type.upper() in ('EAN', 'UPC-A', 'EAN-13', 'EAN-8'):
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,107 +1,50 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"actions": [],
|
||||||
"allow_events_in_timeline": 0,
|
|
||||||
"allow_guest_to_view": 0,
|
|
||||||
"allow_import": 0,
|
|
||||||
"allow_rename": 0,
|
|
||||||
"beta": 0,
|
|
||||||
"creation": "2013-02-22 01:28:01",
|
"creation": "2013-02-22 01:28:01",
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"item_tax_template",
|
||||||
|
"tax_category",
|
||||||
|
"valid_from"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "item_tax_template",
|
"fieldname": "item_tax_template",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Item Tax Template",
|
"label": "Item Tax Template",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"oldfieldname": "tax_type",
|
"oldfieldname": "tax_type",
|
||||||
"oldfieldtype": "Link",
|
"oldfieldtype": "Link",
|
||||||
"options": "Item Tax Template",
|
"options": "Item Tax Template",
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "",
|
|
||||||
"fieldname": "tax_category",
|
"fieldname": "tax_category",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Tax Category",
|
"label": "Tax Category",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"oldfieldname": "tax_rate",
|
"oldfieldname": "tax_rate",
|
||||||
"oldfieldtype": "Currency",
|
"oldfieldtype": "Currency",
|
||||||
"options": "Tax Category",
|
"options": "Tax Category"
|
||||||
"permlevel": 0,
|
},
|
||||||
"print_hide": 0,
|
{
|
||||||
"print_hide_if_no_value": 0,
|
"fieldname": "valid_from",
|
||||||
"read_only": 0,
|
"fieldtype": "Date",
|
||||||
"remember_last_selected_value": 0,
|
"in_list_view": 1,
|
||||||
"report_hide": 0,
|
"label": "Valid From"
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
|
||||||
"is_submittable": 0,
|
|
||||||
"issingle": 0,
|
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"max_attachments": 0,
|
"links": [],
|
||||||
"modified": "2018-12-21 23:52:40.798944",
|
"modified": "2019-12-28 21:54:40.807849",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Item Tax",
|
"name": "Item Tax",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [],
|
"permissions": [],
|
||||||
"quick_entry": 0,
|
"sort_field": "modified",
|
||||||
"read_only": 0,
|
"sort_order": "DESC"
|
||||||
"read_only_onload": 0,
|
|
||||||
"show_name_in_global_search": 0,
|
|
||||||
"track_changes": 0,
|
|
||||||
"track_seen": 0,
|
|
||||||
"track_views": 0
|
|
||||||
}
|
}
|
||||||
@@ -230,7 +230,8 @@ 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)'), fieldtype: 'Link', options: 'Supplier'},
|
{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'},
|
||||||
(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",
|
||||||
@@ -238,7 +239,8 @@ frappe.ui.form.on('Material Request', {
|
|||||||
args: { default_supplier: values.default_supplier },
|
args: { default_supplier: values.default_supplier },
|
||||||
run_link_triggers: true
|
run_link_triggers: true
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
__('Enter Supplier')
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"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",
|
||||||
@@ -305,6 +306,7 @@
|
|||||||
"fieldname": "contact_email",
|
"fieldname": "contact_email",
|
||||||
"fieldtype": "Small Text",
|
"fieldtype": "Small Text",
|
||||||
"label": "Contact Email",
|
"label": "Contact Email",
|
||||||
|
"options": "Email",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
@@ -614,7 +616,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "other_charges_calculation",
|
"fieldname": "other_charges_calculation",
|
||||||
"fieldtype": "Text",
|
"fieldtype": "Long Text",
|
||||||
"label": "Taxes and Charges Calculation",
|
"label": "Taxes and Charges Calculation",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldtype": "HTML",
|
"oldfieldtype": "HTML",
|
||||||
@@ -1056,7 +1058,8 @@
|
|||||||
"icon": "fa fa-truck",
|
"icon": "fa fa-truck",
|
||||||
"idx": 261,
|
"idx": 261,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"modified": "2019-09-27 14:24:49.044505",
|
"links": [],
|
||||||
|
"modified": "2019-12-30 19:12:49.709711",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Purchase Receipt",
|
"name": "Purchase Receipt",
|
||||||
|
|||||||
@@ -610,27 +610,36 @@ def make_stock_entry(source_name,target_doc=None):
|
|||||||
return doclist
|
return doclist
|
||||||
|
|
||||||
def get_item_account_wise_additional_cost(purchase_document):
|
def get_item_account_wise_additional_cost(purchase_document):
|
||||||
landed_cost_voucher = frappe.get_value("Landed Cost Purchase Receipt",
|
landed_cost_vouchers = frappe.get_all("Landed Cost Purchase Receipt", fields=["parent"],
|
||||||
{"receipt_document": purchase_document, "docstatus": 1}, "parent")
|
filters = {"receipt_document": purchase_document, "docstatus": 1})
|
||||||
|
|
||||||
if not landed_cost_voucher:
|
if not landed_cost_vouchers:
|
||||||
return
|
return
|
||||||
|
|
||||||
total_item_cost = 0
|
total_item_cost = 0
|
||||||
item_account_wise_cost = {}
|
item_account_wise_cost = {}
|
||||||
landed_cost_voucher_doc = frappe.get_doc("Landed Cost Voucher", landed_cost_voucher)
|
item_cost_allocated = []
|
||||||
based_on_field = frappe.scrub(landed_cost_voucher_doc.distribute_charges_based_on)
|
|
||||||
|
|
||||||
for item in landed_cost_voucher_doc.items:
|
for lcv in landed_cost_vouchers:
|
||||||
total_item_cost += item.get(based_on_field)
|
landed_cost_voucher_doc = frappe.get_cached_doc("Landed Cost Voucher", lcv.parent)
|
||||||
|
based_on_field = frappe.scrub(landed_cost_voucher_doc.distribute_charges_based_on)
|
||||||
|
|
||||||
for item in landed_cost_voucher_doc.items:
|
for item in landed_cost_voucher_doc.items:
|
||||||
if item.receipt_document == purchase_document:
|
if item.purchase_receipt_item not in item_cost_allocated:
|
||||||
for account in landed_cost_voucher_doc.taxes:
|
total_item_cost += item.get(based_on_field)
|
||||||
item_account_wise_cost.setdefault((item.item_code, item.purchase_receipt_item), {})
|
item_cost_allocated.append(item.purchase_receipt_item)
|
||||||
item_account_wise_cost[(item.item_code, item.purchase_receipt_item)].setdefault(account.expense_account, 0.0)
|
|
||||||
item_account_wise_cost[(item.item_code, item.purchase_receipt_item)][account.expense_account] += \
|
for lcv in landed_cost_vouchers:
|
||||||
account.amount * item.get(based_on_field) / total_item_cost
|
landed_cost_voucher_doc = frappe.get_cached_doc("Landed Cost Voucher", lcv.parent)
|
||||||
|
based_on_field = frappe.scrub(landed_cost_voucher_doc.distribute_charges_based_on)
|
||||||
|
|
||||||
|
for item in landed_cost_voucher_doc.items:
|
||||||
|
if item.receipt_document == purchase_document:
|
||||||
|
for account in landed_cost_voucher_doc.taxes:
|
||||||
|
item_account_wise_cost.setdefault((item.item_code, item.purchase_receipt_item), {})
|
||||||
|
item_account_wise_cost[(item.item_code, item.purchase_receipt_item)].setdefault(account.expense_account, 0.0)
|
||||||
|
item_account_wise_cost[(item.item_code, item.purchase_receipt_item)][account.expense_account] += \
|
||||||
|
account.amount * item.get(based_on_field) / total_item_cost
|
||||||
|
|
||||||
return item_account_wise_cost
|
return item_account_wise_cost
|
||||||
|
|
||||||
|
|||||||
@@ -836,8 +836,6 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
|
|||||||
this.frm.toggle_enable("from_warehouse", doc.purpose!='Material Receipt');
|
this.frm.toggle_enable("from_warehouse", doc.purpose!='Material Receipt');
|
||||||
this.frm.toggle_enable("to_warehouse", doc.purpose!='Material Issue');
|
this.frm.toggle_enable("to_warehouse", doc.purpose!='Material Issue');
|
||||||
|
|
||||||
this.frm.fields_dict["items"].grid.set_column_disp("s_warehouse", doc.purpose!='Material Receipt');
|
|
||||||
this.frm.fields_dict["items"].grid.set_column_disp("t_warehouse", doc.purpose!='Material Issue');
|
|
||||||
this.frm.fields_dict["items"].grid.set_column_disp("retain_sample", doc.purpose=='Material Receipt');
|
this.frm.fields_dict["items"].grid.set_column_disp("retain_sample", doc.purpose=='Material Receipt');
|
||||||
this.frm.fields_dict["items"].grid.set_column_disp("sample_quantity", doc.purpose=='Material Receipt');
|
this.frm.fields_dict["items"].grid.set_column_disp("sample_quantity", doc.purpose=='Material Receipt');
|
||||||
|
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ class StockEntry(StockController):
|
|||||||
set_batch_nos(self, 's_warehouse')
|
set_batch_nos(self, 's_warehouse')
|
||||||
|
|
||||||
self.set_incoming_rate()
|
self.set_incoming_rate()
|
||||||
|
self.validate_serialized_batch()
|
||||||
self.set_actual_qty()
|
self.set_actual_qty()
|
||||||
self.calculate_rate_and_amount(update_finished_item_rate=False)
|
self.calculate_rate_and_amount(update_finished_item_rate=False)
|
||||||
|
|
||||||
@@ -102,9 +103,8 @@ class StockEntry(StockController):
|
|||||||
|
|
||||||
if self.work_order and self.purpose == "Material Consumption for Manufacture":
|
if self.work_order and self.purpose == "Material Consumption for Manufacture":
|
||||||
self.validate_work_order_status()
|
self.validate_work_order_status()
|
||||||
else:
|
|
||||||
self.update_work_order()
|
|
||||||
|
|
||||||
|
self.update_work_order()
|
||||||
self.update_stock_ledger()
|
self.update_stock_ledger()
|
||||||
self.make_gl_entries_on_cancel()
|
self.make_gl_entries_on_cancel()
|
||||||
self.update_cost_in_project()
|
self.update_cost_in_project()
|
||||||
@@ -372,7 +372,7 @@ class StockEntry(StockController):
|
|||||||
elif d.t_warehouse and not d.basic_rate:
|
elif d.t_warehouse and not d.basic_rate:
|
||||||
d.basic_rate = get_valuation_rate(d.item_code, d.t_warehouse,
|
d.basic_rate = get_valuation_rate(d.item_code, d.t_warehouse,
|
||||||
self.doctype, self.name, d.allow_zero_valuation_rate,
|
self.doctype, self.name, d.allow_zero_valuation_rate,
|
||||||
currency=erpnext.get_company_currency(self.company))
|
currency=erpnext.get_company_currency(self.company), company=self.company)
|
||||||
|
|
||||||
def set_actual_qty(self):
|
def set_actual_qty(self):
|
||||||
allow_negative_stock = cint(frappe.db.get_value("Stock Settings", None, "allow_negative_stock"))
|
allow_negative_stock = cint(frappe.db.get_value("Stock Settings", None, "allow_negative_stock"))
|
||||||
@@ -478,10 +478,16 @@ 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 (getattr(self, "pro_doc", frappe._dict()).scrap_warehouse != d.t_warehouse):
|
if (d.transfer_qty and (d.bom_no or d.t_warehouse) and raw_material_cost
|
||||||
|
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_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 = []
|
||||||
@@ -585,12 +591,18 @@ class StockEntry(StockController):
|
|||||||
|
|
||||||
def validate_finished_goods(self):
|
def validate_finished_goods(self):
|
||||||
"""validation: finished good quantity should be same as manufacturing quantity"""
|
"""validation: finished good quantity should be same as manufacturing quantity"""
|
||||||
|
if not self.work_order: return
|
||||||
|
|
||||||
items_with_target_warehouse = []
|
items_with_target_warehouse = []
|
||||||
allowance_percentage = flt(frappe.db.get_single_value("Manufacturing Settings",
|
allowance_percentage = flt(frappe.db.get_single_value("Manufacturing Settings",
|
||||||
"overproduction_percentage_for_work_order"))
|
"overproduction_percentage_for_work_order"))
|
||||||
|
|
||||||
|
production_item, wo_qty = frappe.db.get_value("Work Order",
|
||||||
|
self.work_order, ["production_item", "qty"])
|
||||||
|
|
||||||
for d in self.get('items'):
|
for d in self.get('items'):
|
||||||
if self.purpose != "Send to Subcontractor" and d.bom_no and flt(d.transfer_qty) > flt(self.fg_completed_qty) and (d.t_warehouse != getattr(self, "pro_doc", frappe._dict()).scrap_warehouse):
|
if (self.purpose != "Send to Subcontractor" and d.bom_no
|
||||||
|
and flt(d.transfer_qty) > flt(self.fg_completed_qty) and d.item_code == production_item):
|
||||||
frappe.throw(_("Quantity in row {0} ({1}) must be same as manufactured quantity {2}"). \
|
frappe.throw(_("Quantity in row {0} ({1}) must be same as manufactured quantity {2}"). \
|
||||||
format(d.idx, d.transfer_qty, self.fg_completed_qty))
|
format(d.idx, d.transfer_qty, self.fg_completed_qty))
|
||||||
|
|
||||||
@@ -598,9 +610,6 @@ class StockEntry(StockController):
|
|||||||
items_with_target_warehouse.append(d.item_code)
|
items_with_target_warehouse.append(d.item_code)
|
||||||
|
|
||||||
if self.work_order and self.purpose == "Manufacture":
|
if self.work_order and self.purpose == "Manufacture":
|
||||||
production_item, wo_qty = frappe.db.get_value("Work Order",
|
|
||||||
self.work_order, ["production_item", "qty"])
|
|
||||||
|
|
||||||
allowed_qty = wo_qty + (allowance_percentage/100 * wo_qty)
|
allowed_qty = wo_qty + (allowance_percentage/100 * wo_qty)
|
||||||
if self.fg_completed_qty > allowed_qty:
|
if self.fg_completed_qty > allowed_qty:
|
||||||
frappe.throw(_("For quantity {0} should not be grater than work order quantity {1}")
|
frappe.throw(_("For quantity {0} should not be grater than work order quantity {1}")
|
||||||
@@ -827,7 +836,6 @@ class StockEntry(StockController):
|
|||||||
frappe.db.get_single_value("Manufacturing Settings", "backflush_raw_materials_based_on")== "BOM" and \
|
frappe.db.get_single_value("Manufacturing Settings", "backflush_raw_materials_based_on")== "BOM" and \
|
||||||
frappe.db.get_single_value("Manufacturing Settings", "material_consumption")== 1:
|
frappe.db.get_single_value("Manufacturing Settings", "material_consumption")== 1:
|
||||||
self.get_unconsumed_raw_materials()
|
self.get_unconsumed_raw_materials()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if not self.fg_completed_qty:
|
if not self.fg_completed_qty:
|
||||||
frappe.throw(_("Manufacturing Quantity is mandatory"))
|
frappe.throw(_("Manufacturing Quantity is mandatory"))
|
||||||
@@ -1147,20 +1155,17 @@ class StockEntry(StockController):
|
|||||||
se_child.s_warehouse = item_dict[d].get("from_warehouse")
|
se_child.s_warehouse = item_dict[d].get("from_warehouse")
|
||||||
se_child.t_warehouse = item_dict[d].get("to_warehouse")
|
se_child.t_warehouse = item_dict[d].get("to_warehouse")
|
||||||
se_child.item_code = item_dict[d].get('item_code') or cstr(d)
|
se_child.item_code = item_dict[d].get('item_code') or cstr(d)
|
||||||
se_child.item_name = item_dict[d]["item_name"]
|
|
||||||
se_child.description = item_dict[d]["description"]
|
|
||||||
se_child.uom = item_dict[d]["uom"] if item_dict[d].get("uom") else stock_uom
|
se_child.uom = item_dict[d]["uom"] if item_dict[d].get("uom") else stock_uom
|
||||||
se_child.stock_uom = stock_uom
|
se_child.stock_uom = stock_uom
|
||||||
se_child.qty = flt(item_dict[d]["qty"], se_child.precision("qty"))
|
se_child.qty = flt(item_dict[d]["qty"], se_child.precision("qty"))
|
||||||
se_child.expense_account = item_dict[d].get("expense_account")
|
|
||||||
se_child.cost_center = item_dict[d].get("cost_center") or cost_center
|
se_child.cost_center = item_dict[d].get("cost_center") or cost_center
|
||||||
se_child.allow_alternative_item = item_dict[d].get("allow_alternative_item", 0)
|
se_child.allow_alternative_item = item_dict[d].get("allow_alternative_item", 0)
|
||||||
se_child.subcontracted_item = item_dict[d].get("main_item_code")
|
se_child.subcontracted_item = item_dict[d].get("main_item_code")
|
||||||
se_child.original_item = item_dict[d].get("original_item")
|
|
||||||
se_child.po_detail = item_dict[d].get("po_detail")
|
|
||||||
|
|
||||||
if item_dict[d].get("idx"):
|
for field in ["idx", "po_detail", "original_item",
|
||||||
se_child.idx = item_dict[d].get("idx")
|
"expense_account", "description", "item_name"]:
|
||||||
|
if item_dict[d].get(field):
|
||||||
|
se_child.set(field, item_dict[d].get(field))
|
||||||
|
|
||||||
if se_child.s_warehouse==None:
|
if se_child.s_warehouse==None:
|
||||||
se_child.s_warehouse = self.from_warehouse
|
se_child.s_warehouse = self.from_warehouse
|
||||||
@@ -1465,6 +1470,24 @@ def get_used_alternative_items(purchase_order=None, work_order=None):
|
|||||||
|
|
||||||
return used_alternative_items
|
return used_alternative_items
|
||||||
|
|
||||||
|
def get_valuation_rate_for_finished_good_entry(work_order):
|
||||||
|
work_order_qty = flt(frappe.get_cached_value("Work Order",
|
||||||
|
work_order, 'material_transferred_for_manufacturing'))
|
||||||
|
|
||||||
|
field = "(SUM(total_outgoing_value) / %s) as valuation_rate" % (work_order_qty)
|
||||||
|
|
||||||
|
stock_data = frappe.get_all("Stock Entry",
|
||||||
|
fields = field,
|
||||||
|
filters = {
|
||||||
|
"docstatus": 1,
|
||||||
|
"purpose": "Material Transfer for Manufacture",
|
||||||
|
"work_order": work_order
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if stock_data:
|
||||||
|
return stock_data[0].valuation_rate
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_uom_details(item_code, uom, qty):
|
def get_uom_details(item_code, uom, qty):
|
||||||
"""Returns dict `{"conversion_factor": [value], "transfer_qty": qty * [value]}`
|
"""Returns dict `{"conversion_factor": [value], "transfer_qty": qty * [value]}`
|
||||||
|
|||||||
@@ -177,7 +177,26 @@ def convert_to_group_or_ledger():
|
|||||||
return frappe.get_doc("Warehouse", args.docname).convert_to_group_or_ledger()
|
return frappe.get_doc("Warehouse", args.docname).convert_to_group_or_ledger()
|
||||||
|
|
||||||
def get_child_warehouses(warehouse):
|
def get_child_warehouses(warehouse):
|
||||||
p_warehouse = frappe.get_doc("Warehouse", warehouse)
|
lft, rgt = frappe.get_cached_value("Warehouse", warehouse, [lft, rgt])
|
||||||
|
|
||||||
return frappe.db.sql_list("""select name from `tabWarehouse`
|
return frappe.db.sql_list("""select name from `tabWarehouse`
|
||||||
where lft >= %s and rgt =< %s""", (p_warehouse.lft, p_warehouse.rgt))
|
where lft >= %s and rgt =< %s""", (lft, rgt))
|
||||||
|
|
||||||
|
def get_warehouses_based_on_account(account, company=None):
|
||||||
|
warehouses = []
|
||||||
|
for d in frappe.get_all("Warehouse", fields = ["name", "is_group"],
|
||||||
|
filters = {"account": account}):
|
||||||
|
if d.is_group:
|
||||||
|
warehouses.extend(get_child_warehouses(d.name))
|
||||||
|
else:
|
||||||
|
warehouses.append(d.name)
|
||||||
|
|
||||||
|
if (not warehouses and company and
|
||||||
|
frappe.get_cached_value("Company", company, "default_inventory_account") == account):
|
||||||
|
warehouses = [d.name for d in frappe.get_all("Warehouse", filters={'is_group': 0})]
|
||||||
|
|
||||||
|
if not warehouses:
|
||||||
|
frappe.throw(_("Warehouse not found against the account {0}")
|
||||||
|
.format(account))
|
||||||
|
|
||||||
|
return warehouses
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _, throw
|
from frappe import _, throw
|
||||||
from frappe.utils import flt, cint, add_days, cstr, add_months
|
from frappe.utils import flt, cint, add_days, cstr, add_months, getdate
|
||||||
import json, copy
|
import json, copy
|
||||||
from erpnext.accounts.doctype.pricing_rule.pricing_rule import get_pricing_rule_for_item, set_transaction_type
|
from erpnext.accounts.doctype.pricing_rule.pricing_rule import get_pricing_rule_for_item, set_transaction_type
|
||||||
from erpnext.setup.utils import get_exchange_rate
|
from erpnext.setup.utils import get_exchange_rate
|
||||||
@@ -52,6 +52,16 @@ def get_item_details(args, doc=None, for_validate=False, overwrite_warehouse=Tru
|
|||||||
|
|
||||||
out = get_basic_details(args, item, overwrite_warehouse)
|
out = get_basic_details(args, item, overwrite_warehouse)
|
||||||
|
|
||||||
|
if isinstance(doc, string_types):
|
||||||
|
doc = json.loads(doc)
|
||||||
|
|
||||||
|
if doc and doc.get('doctype') == 'Purchase Invoice':
|
||||||
|
args['bill_date'] = doc.get('bill_date')
|
||||||
|
|
||||||
|
if doc:
|
||||||
|
args['posting_date'] = doc.get('posting_date')
|
||||||
|
args['transaction_date'] = doc.get('transaction_date')
|
||||||
|
|
||||||
get_item_tax_template(args, item, out)
|
get_item_tax_template(args, item, out)
|
||||||
out["item_tax_rate"] = get_item_tax_map(args.company, args.get("item_tax_template") if out.get("item_tax_template") is None \
|
out["item_tax_rate"] = get_item_tax_map(args.company, args.get("item_tax_template") if out.get("item_tax_template") is None \
|
||||||
else out.get("item_tax_template"), as_json=True)
|
else out.get("item_tax_template"), as_json=True)
|
||||||
@@ -393,7 +403,34 @@ def get_item_tax_template(args, item, out):
|
|||||||
item_tax_template = _get_item_tax_template(args, item_group_doc.taxes, out)
|
item_tax_template = _get_item_tax_template(args, item_group_doc.taxes, out)
|
||||||
item_group = item_group_doc.parent_item_group
|
item_group = item_group_doc.parent_item_group
|
||||||
|
|
||||||
def _get_item_tax_template(args, taxes, out):
|
def _get_item_tax_template(args, taxes, out={}, for_validate=False):
|
||||||
|
taxes_with_validity = []
|
||||||
|
taxes_with_no_validity = []
|
||||||
|
|
||||||
|
for tax in taxes:
|
||||||
|
if tax.valid_from:
|
||||||
|
# In purchase Invoice first preference will be given to supplier invoice date
|
||||||
|
# if supplier date is not present then posting date
|
||||||
|
validation_date = args.get('transaction_date') or args.get('bill_date') or args.get('posting_date')
|
||||||
|
|
||||||
|
if getdate(tax.valid_from) <= getdate(validation_date):
|
||||||
|
taxes_with_validity.append(tax)
|
||||||
|
else:
|
||||||
|
taxes_with_no_validity.append(tax)
|
||||||
|
|
||||||
|
if taxes_with_validity:
|
||||||
|
taxes = sorted(taxes_with_validity, key = lambda i: i.valid_from, reverse=True)
|
||||||
|
else:
|
||||||
|
taxes = taxes_with_no_validity
|
||||||
|
|
||||||
|
if for_validate:
|
||||||
|
return [tax.item_tax_template for tax in taxes if (cstr(tax.tax_category) == cstr(args.get('tax_category')) \
|
||||||
|
and (tax.item_tax_template not in taxes))]
|
||||||
|
|
||||||
|
# all templates have validity and no template is valid
|
||||||
|
if not taxes_with_validity and (not taxes_with_no_validity):
|
||||||
|
return None
|
||||||
|
|
||||||
for tax in taxes:
|
for tax in taxes:
|
||||||
if cstr(tax.tax_category) == cstr(args.get("tax_category")):
|
if cstr(tax.tax_category) == cstr(args.get("tax_category")):
|
||||||
out["item_tax_template"] = tax.item_tax_template
|
out["item_tax_template"] = tax.item_tax_template
|
||||||
@@ -571,7 +608,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 """.format(conditions=conditions), args)
|
order by uom desc, min_qty desc, valid_from desc """.format(conditions=conditions), args)
|
||||||
|
|
||||||
def get_price_list_rate_for(args, item_code):
|
def get_price_list_rate_for(args, item_code):
|
||||||
"""
|
"""
|
||||||
@@ -604,10 +641,15 @@ def get_price_list_rate_for(args, item_code):
|
|||||||
if desired_qty and check_packing_list(price_list_rate[0][0], desired_qty, item_code):
|
if desired_qty and check_packing_list(price_list_rate[0][0], desired_qty, item_code):
|
||||||
item_price_data = price_list_rate
|
item_price_data = price_list_rate
|
||||||
else:
|
else:
|
||||||
for field in ["customer", "supplier", "min_qty"]:
|
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")
|
||||||
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"))
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
frappe.query_reports["Stock and Account Value Comparison"] = {
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"label": __("Company"),
|
||||||
|
"fieldname": "company",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Company",
|
||||||
|
"reqd": 1,
|
||||||
|
"default": frappe.defaults.get_user_default("Company")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": __("Account"),
|
||||||
|
"fieldname": "account",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Account",
|
||||||
|
get_query: function() {
|
||||||
|
var company = frappe.query_report.get_filter_value('company');
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
"account_type": "Stock",
|
||||||
|
"company": company
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": __("As On Date"),
|
||||||
|
"fieldname": "as_on_date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"default": frappe.datetime.get_today(),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
};
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"add_total_row": 1,
|
||||||
|
"creation": "2020-01-09 14:42:45.254751",
|
||||||
|
"disable_prepared_report": 0,
|
||||||
|
"disabled": 0,
|
||||||
|
"docstatus": 0,
|
||||||
|
"doctype": "Report",
|
||||||
|
"idx": 0,
|
||||||
|
"is_standard": "Yes",
|
||||||
|
"letter_head": "",
|
||||||
|
"modified": "2020-01-09 14:42:45.254751",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Stock",
|
||||||
|
"name": "Stock and Account Value Comparison",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"prepared_report": 0,
|
||||||
|
"ref_doctype": "Stock Ledger Entry",
|
||||||
|
"report_name": "Stock and Account Value Comparison",
|
||||||
|
"report_type": "Script Report",
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"role": "Stock User"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "Accounts Manager"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe, erpnext
|
||||||
|
from frappe import _
|
||||||
|
from erpnext.accounts.utils import get_stock_accounts
|
||||||
|
from erpnext.accounts.utils import get_currency_precision
|
||||||
|
from erpnext.stock.doctype.warehouse.warehouse import get_warehouses_based_on_account
|
||||||
|
|
||||||
|
def execute(filters=None):
|
||||||
|
if not erpnext.is_perpetual_inventory_enabled(filters.company):
|
||||||
|
frappe.throw(_("Perpetual inventory required for the company {0} to view this report.")
|
||||||
|
.format(filters.company))
|
||||||
|
|
||||||
|
data = get_data(filters)
|
||||||
|
columns = get_columns(filters)
|
||||||
|
|
||||||
|
return columns, data
|
||||||
|
|
||||||
|
def get_data(report_filters):
|
||||||
|
data = []
|
||||||
|
|
||||||
|
filters = {
|
||||||
|
"company": report_filters.company,
|
||||||
|
"posting_date": ("<=", report_filters.as_on_date)
|
||||||
|
}
|
||||||
|
|
||||||
|
currency_precision = get_currency_precision() or 2
|
||||||
|
stock_ledger_entries = get_stock_ledger_data(report_filters, filters)
|
||||||
|
voucher_wise_gl_data = get_gl_data(report_filters, filters)
|
||||||
|
|
||||||
|
for d in stock_ledger_entries:
|
||||||
|
key = (d.voucher_type, d.voucher_no)
|
||||||
|
gl_data = voucher_wise_gl_data.get(key) or {}
|
||||||
|
d.account_value = gl_data.get("account_value", 0)
|
||||||
|
d.difference_value = (d.stock_value - d.account_value)
|
||||||
|
if abs(d.difference_value) > 1.0/10 ** currency_precision:
|
||||||
|
data.append(d)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
def get_stock_ledger_data(report_filters, filters):
|
||||||
|
if report_filters.account:
|
||||||
|
warehouses = get_warehouses_based_on_account(report_filters.account,
|
||||||
|
report_filters.warehouse)
|
||||||
|
|
||||||
|
filters["warehouse"] = ("in", warehouses)
|
||||||
|
|
||||||
|
return frappe.get_all("Stock Ledger Entry", filters=filters,
|
||||||
|
fields = ["name", "voucher_type", "voucher_no",
|
||||||
|
"sum(stock_value_difference) as stock_value", "posting_date", "posting_time"],
|
||||||
|
group_by = "voucher_type, voucher_no",
|
||||||
|
order_by = "posting_date ASC, posting_time ASC")
|
||||||
|
|
||||||
|
def get_gl_data(report_filters, filters):
|
||||||
|
if report_filters.account:
|
||||||
|
stock_accounts = [report_filters.account]
|
||||||
|
else:
|
||||||
|
stock_accounts = [k.name
|
||||||
|
for k in get_stock_accounts(report_filters.company)]
|
||||||
|
|
||||||
|
filters.update({
|
||||||
|
"account": ("in", stock_accounts)
|
||||||
|
})
|
||||||
|
|
||||||
|
if filters.get("warehouse"):
|
||||||
|
del filters["warehouse"]
|
||||||
|
|
||||||
|
gl_entries = frappe.get_all("GL Entry", filters=filters,
|
||||||
|
fields = ["name", "voucher_type", "voucher_no",
|
||||||
|
"sum(debit_in_account_currency) - sum(credit_in_account_currency) as account_value"],
|
||||||
|
group_by = "voucher_type, voucher_no")
|
||||||
|
|
||||||
|
voucher_wise_gl_data = {}
|
||||||
|
for d in gl_entries:
|
||||||
|
key = (d.voucher_type, d.voucher_no)
|
||||||
|
voucher_wise_gl_data[key] = d
|
||||||
|
|
||||||
|
return voucher_wise_gl_data
|
||||||
|
|
||||||
|
def get_columns(filters):
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"label": _("Stock Ledger ID"),
|
||||||
|
"fieldname": "name",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Stock Ledger Entry",
|
||||||
|
"width": "80"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Posting Date"),
|
||||||
|
"fieldname": "posting_date",
|
||||||
|
"fieldtype": "Date"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Posting Time"),
|
||||||
|
"fieldname": "posting_time",
|
||||||
|
"fieldtype": "Time"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Voucher Type"),
|
||||||
|
"fieldname": "voucher_type",
|
||||||
|
"width": "110"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Voucher No"),
|
||||||
|
"fieldname": "voucher_no",
|
||||||
|
"fieldtype": "Dynamic Link",
|
||||||
|
"options": "voucher_type",
|
||||||
|
"width": "110"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Stock Value"),
|
||||||
|
"fieldname": "stock_value",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"width": "120"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Account Value"),
|
||||||
|
"fieldname": "account_value",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"width": "120"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Difference Value"),
|
||||||
|
"fieldname": "difference_value",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"width": "120"
|
||||||
|
}
|
||||||
|
]
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user