mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-02 04:58:29 +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):
|
||||
docs_for_closing = []
|
||||
doctypes = ["Sales Invoice", "Purchase Invoice", "Journal Entry", "Payroll Entry", "Bank Reconciliation",
|
||||
"Asset", "Purchase Order", "Sales Order", "Leave Application", "Leave Allocation", "Stock Entry"]
|
||||
doctypes = ["Sales Invoice", "Purchase Invoice", "Journal Entry", "Payroll Entry", \
|
||||
"Bank Reconciliation", "Asset", "Stock Entry"]
|
||||
closed_doctypes = [{"document_type": doctype, "closed": 1} for doctype in doctypes]
|
||||
for closed_doctype in closed_doctypes:
|
||||
docs_for_closing.append(closed_doctype)
|
||||
|
||||
@@ -29,7 +29,6 @@ class GLEntry(Document):
|
||||
self.validate_and_set_fiscal_year()
|
||||
self.pl_must_have_cost_center()
|
||||
self.validate_cost_center()
|
||||
self.validate_dimensions_for_pl_and_bs()
|
||||
|
||||
if not self.flags.from_repost:
|
||||
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):
|
||||
if not from_repost:
|
||||
self.validate_account_details(adv_adj)
|
||||
self.validate_dimensions_for_pl_and_bs()
|
||||
check_freezing_date(self.posting_date, 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") {
|
||||
return {
|
||||
filters: {
|
||||
'status': ['=', 'Unpaid'],
|
||||
'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.party import get_party_account
|
||||
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 six import string_types, iteritems
|
||||
@@ -606,8 +605,8 @@ class JournalEntry(AccountsController):
|
||||
for d in self.accounts:
|
||||
if d.reference_type=="Loan" and flt(d.debit) > 0:
|
||||
doc = frappe.get_doc("Loan", d.reference_name)
|
||||
update_disbursement_status(doc)
|
||||
update_total_amount_paid(doc)
|
||||
doc.update_total_amount_paid()
|
||||
doc.set_status()
|
||||
|
||||
def validate_expense_claim(self):
|
||||
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
|
||||
# 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)
|
||||
else:
|
||||
exchange_rate = 1
|
||||
|
||||
@@ -652,14 +652,16 @@ frappe.ui.form.on('Payment Entry', {
|
||||
(frm.doc.payment_type=="Receive" && frm.doc.party_type=="Student")
|
||||
) {
|
||||
if(total_positive_outstanding > total_negative_outstanding)
|
||||
frm.set_value("paid_amount",
|
||||
total_positive_outstanding - total_negative_outstanding);
|
||||
if (!frm.doc.paid_amount)
|
||||
frm.set_value("paid_amount",
|
||||
total_positive_outstanding - total_negative_outstanding);
|
||||
} else if (
|
||||
total_negative_outstanding &&
|
||||
total_positive_outstanding < total_negative_outstanding
|
||||
) {
|
||||
frm.set_value("received_amount",
|
||||
total_negative_outstanding - total_positive_outstanding);
|
||||
if (!frm.doc.received_amount)
|
||||
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:
|
||||
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
|
||||
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"]:
|
||||
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)
|
||||
|
||||
|
||||
@@ -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", "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){
|
||||
if (frm.doc.reference_doctype) {
|
||||
frappe.call({
|
||||
|
||||
@@ -34,6 +34,9 @@ class PricingRule(Document):
|
||||
|
||||
def validate_duplicate_apply_on(self):
|
||||
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)]
|
||||
|
||||
if len(values) != len(set(values)):
|
||||
@@ -419,4 +422,4 @@ def get_item_uoms(doctype, txt, searchfield, start, page_len, filters):
|
||||
|
||||
return frappe.get_all('UOM Conversion Detail',
|
||||
filters = {'parent': ('in', items), 'uom': ("like", "{0}%".format(txt))},
|
||||
fields = ["distinct uom"], as_list=1)
|
||||
fields = ["distinct uom"], as_list=1)
|
||||
|
||||
@@ -495,7 +495,7 @@ def get_pricing_rule_items(pr_doc):
|
||||
|
||||
if 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))
|
||||
|
||||
|
||||
@@ -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) {
|
||||
// filter on Account
|
||||
if (doc.supplier) {
|
||||
return {
|
||||
filters: {
|
||||
'account_type': 'Payable',
|
||||
'is_group': 0,
|
||||
'company': doc.company
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
filters: {
|
||||
'report_type': 'Balance Sheet',
|
||||
'is_group': 0,
|
||||
'company': doc.company
|
||||
}
|
||||
return {
|
||||
filters: {
|
||||
'account_type': 'Payable',
|
||||
'is_group': 0,
|
||||
'company': doc.company
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_import": 1,
|
||||
"autoname": "naming_series:",
|
||||
"creation": "2013-05-21 16:16:39",
|
||||
@@ -417,6 +418,7 @@
|
||||
"fieldname": "contact_email",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Contact Email",
|
||||
"options": "Email",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
@@ -705,7 +707,7 @@
|
||||
},
|
||||
{
|
||||
"fieldname": "other_charges_calculation",
|
||||
"fieldtype": "Text",
|
||||
"fieldtype": "Long Text",
|
||||
"label": "Taxes and Charges Calculation",
|
||||
"no_copy": 1,
|
||||
"oldfieldtype": "HTML",
|
||||
@@ -1287,7 +1289,8 @@
|
||||
"icon": "fa fa-file-text",
|
||||
"idx": 204,
|
||||
"is_submittable": 1,
|
||||
"modified": "2019-09-17 22:31:42.666601",
|
||||
"links": [],
|
||||
"modified": "2019-12-30 19:13:49.610538",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Invoice",
|
||||
|
||||
@@ -556,22 +556,11 @@ cur_frm.cscript.cost_center = function(doc, cdt, cdn) {
|
||||
}
|
||||
|
||||
cur_frm.set_query("debit_to", function(doc) {
|
||||
// filter on Account
|
||||
if (doc.customer) {
|
||||
return {
|
||||
filters: {
|
||||
'account_type': 'Receivable',
|
||||
'is_group': 0,
|
||||
'company': doc.company
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
filters: {
|
||||
'report_type': 'Balance Sheet',
|
||||
'is_group': 0,
|
||||
'company': doc.company
|
||||
}
|
||||
return {
|
||||
filters: {
|
||||
'account_type': 'Receivable',
|
||||
'is_group': 0,
|
||||
'company': doc.company
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_import": 1,
|
||||
"autoname": "naming_series:",
|
||||
"creation": "2013-05-24 19:29:05",
|
||||
@@ -774,7 +775,7 @@
|
||||
},
|
||||
{
|
||||
"fieldname": "other_charges_calculation",
|
||||
"fieldtype": "Text",
|
||||
"fieldtype": "Long Text",
|
||||
"label": "Taxes and Charges Calculation",
|
||||
"no_copy": 1,
|
||||
"oldfieldtype": "HTML",
|
||||
@@ -1567,7 +1568,8 @@
|
||||
"icon": "fa fa-file-text",
|
||||
"idx": 181,
|
||||
"is_submittable": 1,
|
||||
"modified": "2019-10-05 21:39:49.235990",
|
||||
"links": [],
|
||||
"modified": "2019-12-30 19:15:59.580414",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice",
|
||||
|
||||
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
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 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
|
||||
@@ -1847,6 +1847,26 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
self.assertEqual(data['billLists'][0]['vehicleNo'], 'KA12KA1234')
|
||||
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):
|
||||
si = frappe.new_doc("Sales Invoice")
|
||||
|
||||
@@ -188,7 +188,7 @@
|
||||
}
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"modified": "2019-11-07 13:31:17.999744",
|
||||
"modified": "2019-12-20 14:48:01.990600",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Share Transfer",
|
||||
@@ -196,6 +196,7 @@
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 1,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
@@ -221,6 +222,7 @@
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
@@ -230,6 +232,7 @@
|
||||
"report": 1,
|
||||
"role": "Accounts Manager",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
|
||||
@@ -338,6 +338,16 @@ class Subscription(Document):
|
||||
|
||||
# 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()
|
||||
|
||||
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):
|
||||
"""
|
||||
@@ -348,7 +358,7 @@ class Subscription(Document):
|
||||
2. Change the `Subscription` status to 'Past Due Date'
|
||||
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()
|
||||
if self.current_invoice_is_past_due():
|
||||
self.status = 'Past Due Date'
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<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>
|
||||
<td class="top-bottom" colspan="5"><strong>Credit</strong></td>
|
||||
@@ -69,7 +69,7 @@
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<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>
|
||||
</table>
|
||||
<div>
|
||||
|
||||
@@ -171,7 +171,7 @@ class ReceivablePayableReport(object):
|
||||
row.outstanding = flt(row.invoiced - row.paid - row.credit_note, self.currency_precision)
|
||||
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
|
||||
|
||||
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):
|
||||
# customer / supplier name
|
||||
party_details = self.get_party_details(row.party)
|
||||
party_details = self.get_party_details(row.party) or {}
|
||||
row.update(party_details)
|
||||
if self.filters.get(scrub(self.filters.party_type)):
|
||||
row.currency = row.account_currency
|
||||
|
||||
@@ -46,13 +46,24 @@ frappe.query_reports["Budget Variance Report"] = {
|
||||
fieldtype: "Select",
|
||||
options: ["Cost Center", "Project"],
|
||||
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",
|
||||
label: __("Cost Center"),
|
||||
fieldtype: "Link",
|
||||
options: "Cost Center"
|
||||
fieldname:"budget_against_filter",
|
||||
label: __('Dimension Filter'),
|
||||
fieldtype: "MultiSelectList",
|
||||
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",
|
||||
|
||||
@@ -12,22 +12,22 @@ from six import iteritems
|
||||
from pprint import pprint
|
||||
def execute(filters=None):
|
||||
if not filters: filters = {}
|
||||
validate_filters(filters)
|
||||
|
||||
columns = get_columns(filters)
|
||||
if filters.get("cost_center"):
|
||||
cost_centers = [filters.get("cost_center")]
|
||||
if filters.get("budget_against_filter"):
|
||||
dimensions = filters.get("budget_against_filter")
|
||||
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"])
|
||||
cam_map = get_cost_center_account_month_map(filters)
|
||||
cam_map = get_dimension_account_month_map(filters)
|
||||
|
||||
data = []
|
||||
for cost_center in cost_centers:
|
||||
cost_center_items = cam_map.get(cost_center)
|
||||
if cost_center_items:
|
||||
for account, monthwise_data in iteritems(cost_center_items):
|
||||
row = [cost_center, account]
|
||||
for dimension in dimensions:
|
||||
dimension_items = cam_map.get(dimension)
|
||||
if dimension_items:
|
||||
for account, monthwise_data in iteritems(dimension_items):
|
||||
row = [dimension, account]
|
||||
totals = [0, 0, 0]
|
||||
for year in get_fiscal_years(filters):
|
||||
last_total = 0
|
||||
@@ -55,10 +55,6 @@ def execute(filters=None):
|
||||
|
||||
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):
|
||||
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:
|
||||
return frappe.db.sql_list("""select name from `tab{tab}`""".format(tab=filters.get("budget_against"))) #nosec
|
||||
|
||||
#Get cost center & target details
|
||||
def get_cost_center_target_details(filters):
|
||||
#Get dimension & target details
|
||||
def get_dimension_target_details(filters):
|
||||
cond = ""
|
||||
if filters.get("cost_center"):
|
||||
cond += " and b.cost_center=%s" % frappe.db.escape(filters.get("cost_center"))
|
||||
if filters.get("budget_against_filter"):
|
||||
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("""
|
||||
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
|
||||
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),
|
||||
(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
|
||||
@@ -153,14 +150,14 @@ def get_actual_details(name, filters):
|
||||
|
||||
return cc_actual_details
|
||||
|
||||
def get_cost_center_account_month_map(filters):
|
||||
def get_dimension_account_month_map(filters):
|
||||
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)
|
||||
|
||||
cam_map = {}
|
||||
|
||||
for ccd in cost_center_target_details:
|
||||
for ccd in dimension_target_details:
|
||||
actual_details = get_actual_details(ccd.budget_against, filters)
|
||||
|
||||
for month_id in range(1, 13):
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for(var i=0, l=data.length-1; i<l; i++) { %}
|
||||
{% for(var i=0, l=data.length; i<l; i++) { %}
|
||||
<tr>
|
||||
{% if(data[i].posting_date) { %}
|
||||
<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", [])))
|
||||
warehouse = list(set(invoice_cc_wh_map.get(inv.name, {}).get("warehouse", [])))
|
||||
|
||||
row = [
|
||||
inv.name, inv.posting_date, inv.customer, inv.customer_name
|
||||
]
|
||||
row = {
|
||||
'invoice': inv.name,
|
||||
'posting_date': inv.posting_date,
|
||||
'customer': inv.customer,
|
||||
'customer_name': inv.customer_name
|
||||
}
|
||||
|
||||
if 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
|
||||
base_net_total = 0
|
||||
for income_acc in income_accounts:
|
||||
income_amount = flt(invoice_income_map.get(inv.name, {}).get(income_acc))
|
||||
base_net_total += income_amount
|
||||
row.append(income_amount)
|
||||
row.update({
|
||||
frappe.scrub(income_acc): income_amount
|
||||
})
|
||||
|
||||
# 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
|
||||
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 = flt(invoice_tax_map.get(inv.name, {}).get(tax_acc), tax_amount_precision)
|
||||
total_tax += tax_amount
|
||||
row.append(tax_amount)
|
||||
row.update({
|
||||
frappe.scrub(tax_acc): tax_amount
|
||||
})
|
||||
|
||||
# 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)
|
||||
|
||||
@@ -84,19 +106,118 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No
|
||||
def get_columns(invoice_list, additional_table_columns):
|
||||
"""return columns based on filters"""
|
||||
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:
|
||||
columns += additional_table_columns
|
||||
|
||||
columns +=[
|
||||
_("Customer Group") + ":Link/Customer Group:120", _("Territory") + ":Link/Territory:80",
|
||||
_("Tax Id") + "::80", _("Receivable Account") + ":Link/Account:120", _("Mode of Payment") + "::120",
|
||||
_("Project") +":Link/Project:80", _("Owner") + "::150", _("Remarks") + "::150",
|
||||
_("Sales Order") + ":Link/Sales Order:100", _("Delivery Note") + ":Link/Delivery Note:100",
|
||||
_("Cost Center") + ":Link/Cost Center:100", _("Warehouse") + ":Link/Warehouse:100",
|
||||
{
|
||||
'label': _("Custmer Group"),
|
||||
'fieldname': 'customer_group',
|
||||
'fieldtype': 'Link',
|
||||
'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",
|
||||
"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:
|
||||
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""" %
|
||||
', '.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:
|
||||
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 + \
|
||||
[_("Total Tax") + ":Currency/currency:120", _("Grand Total") + ":Currency/currency:120",
|
||||
_("Rounded Total") + ":Currency/currency:120", _("Outstanding Amount") + ":Currency/currency:120"]
|
||||
net_total_column = [{
|
||||
"label": _("Net Total"),
|
||||
"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
|
||||
|
||||
|
||||
@@ -65,6 +65,21 @@ frappe.query_reports["Trial Balance for Party"] = {
|
||||
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",
|
||||
"label": __("Show zero values"),
|
||||
|
||||
@@ -20,7 +20,7 @@ def execute(filters=None):
|
||||
def get_data(filters, show_party_name):
|
||||
if filters.get('party_type') in ('Customer', 'Supplier', 'Employee', 'Member'):
|
||||
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'
|
||||
elif filters.get('party_type') == 'Shareholder':
|
||||
party_name_field = 'title'
|
||||
@@ -96,13 +96,19 @@ def get_data(filters, show_party_name):
|
||||
return data
|
||||
|
||||
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("""
|
||||
select party, sum(debit) as opening_debit, sum(credit) as opening_credit
|
||||
from `tabGL Entry`
|
||||
where company=%(company)s
|
||||
and ifnull(party_type, '') = %(party_type)s and ifnull(party, '') != ''
|
||||
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,
|
||||
"from_date": filters.from_date,
|
||||
"party_type": filters.party_type
|
||||
@@ -116,6 +122,11 @@ def get_opening_balances(filters):
|
||||
return opening
|
||||
|
||||
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("""
|
||||
select party, sum(debit) as debit, sum(credit) as credit
|
||||
from `tabGL Entry`
|
||||
@@ -123,7 +134,8 @@ def get_balances_within_period(filters):
|
||||
and ifnull(party_type, '') = %(party_type)s and ifnull(party, '') != ''
|
||||
and posting_date >= %(from_date)s and posting_date <= %(to_date)s
|
||||
and ifnull(is_opening, 'No') = 'No'
|
||||
group by party""", {
|
||||
{account_filter}
|
||||
group by party""".format(account_filter=account_filter), {
|
||||
"company": filters.company,
|
||||
"from_date": filters.from_date,
|
||||
"to_date": filters.to_date,
|
||||
|
||||
@@ -891,3 +891,9 @@ def get_allow_cost_center_in_entry_of_bs_account():
|
||||
def generator():
|
||||
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)
|
||||
|
||||
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
|
||||
asm.transaction_date asc
|
||||
""", (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 \
|
||||
auto generated for Asset {1}').format(self.name, d.asset))
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ def get_data(filters):
|
||||
filters=conditions,
|
||||
fields=["name", "asset_name", "department", "cost_center", "purchase_receipt",
|
||||
"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:
|
||||
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(flt(doc.per_received, 2) < 100 && allow_receipt) {
|
||||
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'),
|
||||
function() { me.make_stock_entry(); }, __("Transfer"));
|
||||
}
|
||||
@@ -191,6 +191,10 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
||||
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() {
|
||||
var items = $.map(cur_frm.doc.items, function(d) { return d.bom ? d.item_code : false; });
|
||||
var me = this;
|
||||
@@ -267,7 +271,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
||||
|
||||
if (me.frm.doc['supplied_items']) {
|
||||
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 ({
|
||||
'name':item.name,
|
||||
'item_code': item.main_item_code,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_import": 1,
|
||||
"autoname": "naming_series:",
|
||||
"creation": "2013-05-21 16:16:39",
|
||||
@@ -47,6 +48,7 @@
|
||||
"ignore_pricing_rule",
|
||||
"sec_warehouse",
|
||||
"set_warehouse",
|
||||
"set_reserve_warehouse",
|
||||
"col_break_warehouse",
|
||||
"is_subcontracted",
|
||||
"supplier_warehouse",
|
||||
@@ -340,6 +342,7 @@
|
||||
"fieldname": "contact_email",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Contact Email",
|
||||
"options": "Email",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
@@ -607,7 +610,7 @@
|
||||
},
|
||||
{
|
||||
"fieldname": "other_charges_calculation",
|
||||
"fieldtype": "Text",
|
||||
"fieldtype": "Long Text",
|
||||
"label": "Taxes and Charges Calculation",
|
||||
"no_copy": 1,
|
||||
"oldfieldtype": "HTML",
|
||||
@@ -1039,12 +1042,20 @@
|
||||
"fieldtype": "Link",
|
||||
"label": "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",
|
||||
"idx": 105,
|
||||
"is_submittable": 1,
|
||||
"modified": "2019-07-11 18:25:49.509343",
|
||||
"links": [],
|
||||
"modified": "2019-12-30 19:11:54.122264",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Purchase Order",
|
||||
|
||||
@@ -116,6 +116,73 @@ class TestPurchaseOrder(unittest.TestCase):
|
||||
self.assertEqual(po.get("items")[0].amount, 1400)
|
||||
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):
|
||||
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
|
||||
if make_all_scorecards(sc.name) > 0:
|
||||
# Save the scorecard to update the score and standings
|
||||
sc.save()
|
||||
frappe.get_doc('Supplier Scorecard', sc.name).save()
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
|
||||
@@ -336,6 +336,24 @@ def get_data():
|
||||
"is_query_report": True,
|
||||
"name": "Item Variant Details",
|
||||
"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
|
||||
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()
|
||||
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']
|
||||
parent = frappe.get_doc(parent_doctype, parent_doctype_name)
|
||||
|
||||
check_and_delete_children(parent, data)
|
||||
|
||||
for d in data:
|
||||
new_child_flag = False
|
||||
if not d.get("docname"):
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
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 erpnext.stock.get_item_details import _get_item_tax_template
|
||||
|
||||
# searches for active employees
|
||||
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.warehouse = %(warehouse)s
|
||||
and (sle.batch_no like %(txt)s
|
||||
or batch.expiry_date like %(txt)s
|
||||
or batch.manufacturing_date like %(txt)s)
|
||||
and batch.docstatus < 2
|
||||
{cond}
|
||||
@@ -329,6 +330,7 @@ def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
|
||||
where batch.disabled = 0
|
||||
and item = %(item_code)s
|
||||
and (name like %(txt)s
|
||||
or expiry_date like %(txt)s
|
||||
or manufacturing_date like %(txt)s)
|
||||
and docstatus < 2
|
||||
{0}
|
||||
@@ -484,7 +486,7 @@ def item_manufacturer_query(doctype, txt, searchfield, start, page_len, filters)
|
||||
@frappe.whitelist()
|
||||
def get_purchase_receipts(doctype, txt, searchfield, start, page_len, filters):
|
||||
query = """
|
||||
select pr.name
|
||||
select pr.name
|
||||
from `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pritem
|
||||
where pr.docstatus = 1 and pritem.parent = pr.name
|
||||
and pr.name like {txt}""".format(txt = frappe.db.escape('%{0}%'.format(txt)))
|
||||
@@ -497,7 +499,7 @@ def get_purchase_receipts(doctype, txt, searchfield, start, page_len, filters):
|
||||
@frappe.whitelist()
|
||||
def get_purchase_invoices(doctype, txt, searchfield, start, page_len, filters):
|
||||
query = """
|
||||
select pi.name
|
||||
select pi.name
|
||||
from `tabPurchase Invoice` pi, `tabPurchase Invoice Item` piitem
|
||||
where pi.docstatus = 1 and piitem.parent = pi.name
|
||||
and pi.name like {txt}""".format(txt = frappe.db.escape('%{0}%'.format(txt)))
|
||||
@@ -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')))
|
||||
|
||||
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):
|
||||
super(StockController, self).validate()
|
||||
self.validate_inspection()
|
||||
self.validate_serialized_batch()
|
||||
|
||||
def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False):
|
||||
if self.docstatus == 2:
|
||||
@@ -42,6 +43,18 @@ class StockController(AccountsController):
|
||||
gl_entries = self.get_asset_gl_entry(gl_entries)
|
||||
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,
|
||||
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 erpnext.controllers.accounts_controller import validate_conversion_rate, \
|
||||
validate_taxes_and_charges, validate_inclusive_tax
|
||||
from erpnext.stock.get_item_details import _get_item_tax_template
|
||||
|
||||
class calculate_taxes_and_totals(object):
|
||||
def __init__(self, doc):
|
||||
@@ -34,6 +35,7 @@ class calculate_taxes_and_totals(object):
|
||||
def _calculate(self):
|
||||
self.validate_conversion_rate()
|
||||
self.calculate_item_values()
|
||||
self.validate_item_tax_template()
|
||||
self.initialize_taxes()
|
||||
self.determine_exclusive_rate()
|
||||
self.calculate_net_total()
|
||||
@@ -43,6 +45,38 @@ class calculate_taxes_and_totals(object):
|
||||
self._cleanup()
|
||||
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):
|
||||
# validate conversion rate
|
||||
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]
|
||||
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])
|
||||
|
||||
diff = self.doc.total + non_inclusive_tax_amount \
|
||||
- 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")):
|
||||
self.doc.rounding_adjustment = flt(flt(self.doc.rounding_adjustment) +
|
||||
flt(diff), self.doc.precision("rounding_adjustment"))
|
||||
self.doc.rounding_adjustment = diff
|
||||
|
||||
def calculate_totals(self):
|
||||
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
|
||||
from frappe import _
|
||||
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
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ class Appointment(Document):
|
||||
if self._assign:
|
||||
return
|
||||
available_agents = _get_agents_sorted_by_asc_workload(
|
||||
self.scheduled_time.date())
|
||||
getdate(self.scheduled_time))
|
||||
for agent in available_agents:
|
||||
if(_check_agent_availability(agent, self.scheduled_time)):
|
||||
agent = agent[0]
|
||||
@@ -189,7 +189,7 @@ def _get_agents_sorted_by_asc_workload(date):
|
||||
assigned_to = frappe.parse_json(appointment._assign)
|
||||
if not assigned_to:
|
||||
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
|
||||
sorted_agent_list = appointment_counter.most_common()
|
||||
sorted_agent_list.reverse()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2018-10-25 10:02:48.656165",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
@@ -23,48 +24,41 @@
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.enabled==1",
|
||||
"depends_on": "enabled",
|
||||
"fieldname": "automatic_sync",
|
||||
"fieldtype": "Check",
|
||||
"label": "Synchronize all accounts every hour"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.enabled==1",
|
||||
"fieldname": "plaid_client_id",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Plaid Client ID",
|
||||
"reqd": 1
|
||||
"label": "Plaid Client ID"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.enabled==1",
|
||||
"fieldname": "plaid_secret",
|
||||
"fieldtype": "Password",
|
||||
"in_list_view": 1,
|
||||
"label": "Plaid Secret",
|
||||
"reqd": 1
|
||||
"label": "Plaid Secret"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.enabled==1",
|
||||
"fieldname": "plaid_public_key",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Plaid Public Key",
|
||||
"reqd": 1
|
||||
"label": "Plaid Public Key"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.enabled==1",
|
||||
"fieldname": "plaid_env",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Plaid Environment",
|
||||
"reqd": 1
|
||||
"label": "Plaid Environment"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_2",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"depends_on": "enabled",
|
||||
"fieldname": "section_break_4",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
@@ -74,7 +68,8 @@
|
||||
}
|
||||
],
|
||||
"issingle": 1,
|
||||
"modified": "2019-08-13 17:00:06.939422",
|
||||
"links": [],
|
||||
"modified": "2020-01-05 10:00:22.137832",
|
||||
"modified_by": "Administrator",
|
||||
"module": "ERPNext Integrations",
|
||||
"name": "Plaid Settings",
|
||||
|
||||
@@ -34,7 +34,7 @@ frappe.ui.form.on('Employee Advance', {
|
||||
}
|
||||
else if (
|
||||
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")
|
||||
) {
|
||||
frm.add_custom_button(
|
||||
@@ -45,6 +45,15 @@ frappe.ui.form.on('Employee Advance', {
|
||||
__('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) {
|
||||
@@ -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) {
|
||||
if (frm.doc.employee) {
|
||||
return frappe.call({
|
||||
|
||||
@@ -1,737 +1,213 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 0,
|
||||
"autoname": "naming_series:",
|
||||
"beta": 0,
|
||||
"creation": "2017-10-09 14:26:29.612365",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"actions": [],
|
||||
"allow_import": 1,
|
||||
"autoname": "naming_series:",
|
||||
"creation": "2017-10-09 14:26:29.612365",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"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": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "",
|
||||
"fieldname": "naming_series",
|
||||
"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",
|
||||
"length": 0,
|
||||
"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
|
||||
},
|
||||
"fieldname": "naming_series",
|
||||
"fieldtype": "Select",
|
||||
"label": "Series",
|
||||
"options": "HR-EAD-.YYYY.-"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "employee",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Employee",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"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,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "employee",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Employee",
|
||||
"options": "Employee",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_from": "employee.employee_name",
|
||||
"fieldname": "employee_name",
|
||||
"fieldtype": "Read Only",
|
||||
"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",
|
||||
"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
|
||||
},
|
||||
"fetch_from": "employee.employee_name",
|
||||
"fieldname": "employee_name",
|
||||
"fieldtype": "Read Only",
|
||||
"label": "Employee Name"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Today",
|
||||
"fieldname": "posting_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Posting Date",
|
||||
"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": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"default": "Today",
|
||||
"fieldname": "posting_date",
|
||||
"fieldtype": "Date",
|
||||
"in_list_view": 1,
|
||||
"label": "Posting Date",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_from": "employee.department",
|
||||
"fieldname": "department",
|
||||
"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",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Department",
|
||||
"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
|
||||
},
|
||||
"fetch_from": "employee.department",
|
||||
"fieldname": "department",
|
||||
"fieldtype": "Link",
|
||||
"label": "Department",
|
||||
"options": "Department",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_8",
|
||||
"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
|
||||
},
|
||||
"fieldname": "section_break_8",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "purpose",
|
||||
"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_standard_filter": 0,
|
||||
"label": "Purpose",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "purpose",
|
||||
"fieldtype": "Small Text",
|
||||
"in_list_view": 1,
|
||||
"label": "Purpose",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_11",
|
||||
"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
|
||||
},
|
||||
"fieldname": "column_break_11",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "advance_amount",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Advance Amount",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company:company:default_currency",
|
||||
"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
|
||||
},
|
||||
"fieldname": "advance_amount",
|
||||
"fieldtype": "Currency",
|
||||
"in_list_view": 1,
|
||||
"label": "Advance Amount",
|
||||
"options": "Company:company:default_currency",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "paid_amount",
|
||||
"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",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Company:company:default_currency",
|
||||
"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
|
||||
},
|
||||
"fieldname": "paid_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Paid Amount",
|
||||
"no_copy": 1,
|
||||
"options": "Company:company:default_currency",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"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",
|
||||
"fieldname": "due_advance_amount",
|
||||
"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",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company:company:default_currency",
|
||||
"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
|
||||
},
|
||||
"depends_on": "eval:cur_frm.doc.employee",
|
||||
"fieldname": "due_advance_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Due Advance Amount",
|
||||
"options": "Company:company:default_currency",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "claimed_amount",
|
||||
"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",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Company:company:default_currency",
|
||||
"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
|
||||
},
|
||||
"fieldname": "claimed_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Claimed Amount",
|
||||
"no_copy": 1,
|
||||
"options": "Company:company:default_currency",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_7",
|
||||
"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
|
||||
},
|
||||
"fieldname": "section_break_7",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "status",
|
||||
"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",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Draft\nPaid\nUnpaid\nClaimed\nCancelled",
|
||||
"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
|
||||
},
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"label": "Status",
|
||||
"no_copy": 1,
|
||||
"options": "Draft\nPaid\nUnpaid\nClaimed\nCancelled",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "company",
|
||||
"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",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company",
|
||||
"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
|
||||
},
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"label": "Company",
|
||||
"options": "Company",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Amended From",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Employee Advance",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
"label": "Amended From",
|
||||
"no_copy": 1,
|
||||
"options": "Employee Advance",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_18",
|
||||
"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
|
||||
},
|
||||
"fieldname": "column_break_18",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "advance_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"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",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Account",
|
||||
"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
|
||||
},
|
||||
"fieldname": "advance_account",
|
||||
"fieldtype": "Link",
|
||||
"ignore_user_permissions": 1,
|
||||
"label": "Advance Account",
|
||||
"options": "Account",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "mode_of_payment",
|
||||
"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",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Mode of Payment",
|
||||
"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
|
||||
"fieldname": "mode_of_payment",
|
||||
"fieldtype": "Link",
|
||||
"label": "Mode of Payment",
|
||||
"options": "Mode of Payment"
|
||||
},
|
||||
{
|
||||
"fieldname": "return_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Returned Amount",
|
||||
"options": "Company:company:default_currency",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 1,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2019-01-30 11:28:15.529649",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Employee Advance",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2019-12-15 19:04:07.044505",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Employee Advance",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Employee",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"create": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Employee",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"amend": 1,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Expense Approver",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"amend": 1,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Expense Approver",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"search_fields": "employee,employee_name",
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
}
|
||||
],
|
||||
"search_fields": "employee,employee_name",
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import frappe, erpnext
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import flt, nowdate
|
||||
from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account
|
||||
|
||||
class EmployeeAdvanceOverPayment(frappe.ValidationError):
|
||||
pass
|
||||
@@ -53,11 +54,25 @@ class EmployeeAdvance(Document):
|
||||
and party = %s
|
||||
""", (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:
|
||||
frappe.throw(_("Row {0}# Paid Amount cannot be greater than requested advance amount"),
|
||||
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("return_amount", return_amount)
|
||||
self.set_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()
|
||||
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)
|
||||
payment_account = get_default_bank_cash_account(doc.company, account_type="Cash",
|
||||
mode_of_payment=doc.mode_of_payment)
|
||||
@@ -118,3 +131,33 @@ def make_bank_entry(dt, dn):
|
||||
})
|
||||
|
||||
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", "designation", "designation");
|
||||
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) {
|
||||
|
||||
@@ -321,7 +321,7 @@ def get_expense_claim_account(expense_claim_type, company):
|
||||
@frappe.whitelist()
|
||||
def get_advances(employee, advance_id=None):
|
||||
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:
|
||||
condition = 'name={0}'.format(frappe.db.escape(advance_id))
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2013-08-02 13:45:23",
|
||||
"doctype": "DocType",
|
||||
"document_type": "Other",
|
||||
@@ -13,6 +14,7 @@
|
||||
"expense_approver_mandatory_in_expense_claim",
|
||||
"payroll_settings",
|
||||
"include_holidays_in_total_working_days",
|
||||
"disable_rounded_total",
|
||||
"max_working_hours_against_timesheet",
|
||||
"column_break_11",
|
||||
"email_salary_slip_to_employee",
|
||||
@@ -160,12 +162,20 @@
|
||||
"fieldname": "auto_leave_encashment",
|
||||
"fieldtype": "Check",
|
||||
"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",
|
||||
"idx": 1,
|
||||
"issingle": 1,
|
||||
"modified": "2019-08-05 13:07:17.993968",
|
||||
"links": [],
|
||||
"modified": "2019-12-31 14:28:32.004121",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "HR Settings",
|
||||
|
||||
@@ -7,6 +7,8 @@ from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
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):
|
||||
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 not self.password_policy:
|
||||
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
|
||||
|
||||
def create_leave_ledger_entry(self, submit=True):
|
||||
if self.status != 'Approved':
|
||||
if self.status != 'Approved' and submit:
|
||||
return
|
||||
|
||||
expiry_date = get_allocation_expiry(self.employee, self.leave_type,
|
||||
|
||||
@@ -235,8 +235,8 @@ class TestLeaveApplication(unittest.TestCase):
|
||||
frappe.get_doc(dict(
|
||||
doctype = 'Holiday List',
|
||||
holiday_list_name = holiday_list,
|
||||
from_date = date(date.today().year, 1, 1),
|
||||
to_date = date(date.today().year, 12, 31),
|
||||
from_date = add_months(today, -6),
|
||||
to_date = add_months(today, 6),
|
||||
holidays = [
|
||||
dict(holiday_date = today, description = 'Test')
|
||||
]
|
||||
@@ -597,8 +597,8 @@ def get_leave_period():
|
||||
return frappe.get_doc(dict(
|
||||
name = 'Test Leave Period',
|
||||
doctype = 'Leave Period',
|
||||
from_date = "{0}-12-01".format(now_datetime().year - 1),
|
||||
to_date = "{0}-12-31".format(now_datetime().year),
|
||||
from_date = add_months(nowdate(), -6),
|
||||
to_date = add_months(nowdate(), 6),
|
||||
company = "_Test Company",
|
||||
is_active = 1
|
||||
)).insert()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,6 +16,7 @@ class Loan(AccountsController):
|
||||
self.make_repayment_schedule()
|
||||
self.set_repayment_period()
|
||||
self.calculate_totals()
|
||||
self.set_status(from_validate=True)
|
||||
|
||||
def set_missing_fields(self):
|
||||
if not self.company:
|
||||
@@ -95,43 +96,57 @@ class Loan(AccountsController):
|
||||
self.total_payment = 0
|
||||
self.total_interest_payable = 0
|
||||
self.total_amount_paid = 0
|
||||
for data in self.repayment_schedule:
|
||||
self.total_payment += data.total_payment
|
||||
self.total_interest_payable +=data.interest_amount
|
||||
if data.paid:
|
||||
self.total_amount_paid += data.total_payment
|
||||
for schedule in self.repayment_schedule:
|
||||
self.total_payment += schedule.total_payment
|
||||
self.total_interest_payable +=schedule.interest_amount
|
||||
if schedule.paid:
|
||||
self.total_amount_paid += schedule.total_payment
|
||||
|
||||
def update_total_amount_paid(doc):
|
||||
total_amount_paid = 0
|
||||
for data in doc.repayment_schedule:
|
||||
if data.paid:
|
||||
total_amount_paid += data.total_payment
|
||||
frappe.db.set_value("Loan", doc.name, "total_amount_paid", total_amount_paid)
|
||||
def update_total_amount_paid(self):
|
||||
total_amount_paid = 0
|
||||
for schedule in self.repayment_schedule:
|
||||
if schedule.paid:
|
||||
total_amount_paid += schedule.total_payment
|
||||
frappe.db.set_value("Loan", self.name, "total_amount_paid", total_amount_paid)
|
||||
|
||||
def update_disbursement_status(doc):
|
||||
disbursement = 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
|
||||
""", (doc.payment_account, doc.name), as_dict=1)[0]
|
||||
def set_status(self, from_validate=False):
|
||||
disbursement = self.get_disbursement_entry()
|
||||
disbursement_date = None
|
||||
|
||||
disbursement_date = None
|
||||
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))
|
||||
self.status = "Draft"
|
||||
|
||||
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.db.sql("""
|
||||
update `tabLoan`
|
||||
set status = %s, disbursement_date = %s
|
||||
where name = %s
|
||||
""", (status, disbursement_date, doc.name))
|
||||
|
||||
def validate_disbursed_amount_and_loan_amount(self, disbursed_amount):
|
||||
if disbursed_amount > self.loan_amount:
|
||||
frappe.throw(_("Disbursed Amount cannot be greater than Loan Amount {0}").format(self.loan_amount))
|
||||
|
||||
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):
|
||||
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) {
|
||||
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()
|
||||
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
|
||||
`tabSalary Slip` t1, `tabSalary Slip Loan` eld
|
||||
where
|
||||
@@ -246,6 +246,7 @@ class PayrollEntry(Document):
|
||||
accounts.append({
|
||||
"account": acc,
|
||||
"debit_in_account_currency": flt(amount, precision),
|
||||
"party_type": '',
|
||||
"cost_center": self.cost_center,
|
||||
"project": self.project
|
||||
})
|
||||
@@ -257,6 +258,7 @@ class PayrollEntry(Document):
|
||||
"account": acc,
|
||||
"credit_in_account_currency": flt(amount, precision),
|
||||
"cost_center": self.cost_center,
|
||||
"party_type": '',
|
||||
"project": self.project
|
||||
})
|
||||
|
||||
@@ -264,7 +266,9 @@ class PayrollEntry(Document):
|
||||
for data in loan_details:
|
||||
accounts.append({
|
||||
"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:
|
||||
@@ -275,14 +279,17 @@ class PayrollEntry(Document):
|
||||
"account": data.interest_income_account,
|
||||
"credit_in_account_currency": data.interest_amount,
|
||||
"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
|
||||
accounts.append({
|
||||
"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)
|
||||
@@ -322,6 +329,10 @@ class PayrollEntry(Document):
|
||||
statistical_component = frappe.db.get_value("Salary Component", sal_detail.salary_component, 'statistical_component')
|
||||
if statistical_component != 1:
|
||||
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:
|
||||
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
|
||||
if publish_progress:
|
||||
frappe.publish_progress(count*100/len(salary_slips), title = _("Submitting Salary Slips..."))
|
||||
|
||||
if submitted_ss:
|
||||
payroll_entry.make_accrual_jv_entry()
|
||||
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",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"creation": "2016-12-20 15:32:25.078334",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"payment_date",
|
||||
"principal_amount",
|
||||
"interest_amount",
|
||||
"total_payment",
|
||||
"balance_loan_amount",
|
||||
"paid"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 2,
|
||||
"fieldname": "payment_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "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_on_submit": 1,
|
||||
"columns": 2,
|
||||
"fieldname": "payment_date",
|
||||
"fieldtype": "Date",
|
||||
"in_list_view": 1,
|
||||
"label": "Payment Date"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 2,
|
||||
"fieldname": "principal_amount",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Principal Amount",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Company:company:default_currency",
|
||||
"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
|
||||
},
|
||||
"columns": 2,
|
||||
"fieldname": "principal_amount",
|
||||
"fieldtype": "Currency",
|
||||
"in_list_view": 1,
|
||||
"label": "Principal Amount",
|
||||
"no_copy": 1,
|
||||
"options": "Company:company:default_currency",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 2,
|
||||
"fieldname": "interest_amount",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Interest Amount",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Company:company:default_currency",
|
||||
"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
|
||||
},
|
||||
"columns": 2,
|
||||
"fieldname": "interest_amount",
|
||||
"fieldtype": "Currency",
|
||||
"in_list_view": 1,
|
||||
"label": "Interest Amount",
|
||||
"no_copy": 1,
|
||||
"options": "Company:company:default_currency",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 2,
|
||||
"fieldname": "total_payment",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Total Payment",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company:company:default_currency",
|
||||
"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
|
||||
},
|
||||
"columns": 2,
|
||||
"fieldname": "total_payment",
|
||||
"fieldtype": "Currency",
|
||||
"in_list_view": 1,
|
||||
"label": "Total Payment",
|
||||
"options": "Company:company:default_currency",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 2,
|
||||
"fieldname": "balance_loan_amount",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Balance Loan Amount",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Company:company:default_currency",
|
||||
"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
|
||||
},
|
||||
"columns": 2,
|
||||
"fieldname": "balance_loan_amount",
|
||||
"fieldtype": "Currency",
|
||||
"in_list_view": 1,
|
||||
"label": "Balance Loan Amount",
|
||||
"no_copy": 1,
|
||||
"options": "Company:company:default_currency",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "paid",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Paid",
|
||||
"length": 0,
|
||||
"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
|
||||
"default": "0",
|
||||
"fieldname": "paid",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"label": "Paid",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"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,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-03-30 17:37:31.834792",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Repayment Schedule",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
],
|
||||
"istable": 1,
|
||||
"modified": "2019-10-29 11:45:10.694557",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Repayment Schedule",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -50,7 +50,8 @@ class SalarySlip(TransactionBase):
|
||||
self.calculate_net_pay()
|
||||
|
||||
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"):
|
||||
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:
|
||||
frappe.throw(_("Net Pay cannot be less than 0"))
|
||||
else:
|
||||
self.update_loans()
|
||||
self.set_status()
|
||||
self.update_status(self.name)
|
||||
self.update_salary_slip_in_additional_salary()
|
||||
@@ -69,6 +71,7 @@ class SalarySlip(TransactionBase):
|
||||
self.email_salary_slip()
|
||||
|
||||
def on_cancel(self):
|
||||
self.update_loans()
|
||||
self.set_status()
|
||||
self.update_status()
|
||||
self.update_salary_slip_in_additional_salary()
|
||||
@@ -90,6 +93,9 @@ class SalarySlip(TransactionBase):
|
||||
if date_diff(self.end_date, self.start_date) < 0:
|
||||
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):
|
||||
if not self.salary_slip_based_on_timesheet:
|
||||
ret_exist = frappe.db.sql("""select name from `tabSalary Slip`
|
||||
@@ -764,7 +770,8 @@ class SalarySlip(TransactionBase):
|
||||
self.total_principal_amount += loan.principal_amount
|
||||
|
||||
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
|
||||
from
|
||||
`tabRepayment Schedule` as rps, `tabLoan` as l
|
||||
@@ -815,6 +822,17 @@ class SalarySlip(TransactionBase):
|
||||
timesheet.set_status()
|
||||
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):
|
||||
'''Get and update status'''
|
||||
if not status:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,524 +1,170 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 0,
|
||||
"autoname": "HR-SSA-.YY.-.MM.-.#####",
|
||||
"beta": 0,
|
||||
"creation": "2018-04-13 16:38:41.769237",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"actions": [],
|
||||
"allow_import": 1,
|
||||
"autoname": "HR-SSA-.YY.-.MM.-.#####",
|
||||
"creation": "2018-04-13 16:38:41.769237",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"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": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "employee",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Employee",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"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,
|
||||
"search_index": 1,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "employee",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Employee",
|
||||
"options": "Employee",
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_from": "employee.employee_name",
|
||||
"fieldname": "employee_name",
|
||||
"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",
|
||||
"length": 0,
|
||||
"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
|
||||
},
|
||||
"fetch_from": "employee.employee_name",
|
||||
"fieldname": "employee_name",
|
||||
"fieldtype": "Data",
|
||||
"label": "Employee Name",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_from": "employee.department",
|
||||
"fieldname": "department",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Department",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Department",
|
||||
"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
|
||||
},
|
||||
"fetch_from": "employee.department",
|
||||
"fieldname": "department",
|
||||
"fieldtype": "Link",
|
||||
"in_standard_filter": 1,
|
||||
"label": "Department",
|
||||
"options": "Department",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_from": "employee.designation",
|
||||
"fieldname": "designation",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Designation",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Designation",
|
||||
"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
|
||||
},
|
||||
"fetch_from": "employee.designation",
|
||||
"fieldname": "designation",
|
||||
"fieldtype": "Link",
|
||||
"in_standard_filter": 1,
|
||||
"label": "Designation",
|
||||
"options": "Designation",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_6",
|
||||
"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
|
||||
},
|
||||
"fieldname": "column_break_6",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "salary_structure",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Salary Structure",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"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,
|
||||
"search_index": 1,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "salary_structure",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Salary Structure",
|
||||
"options": "Salary Structure",
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "from_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "From Date",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "from_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "From Date",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "company",
|
||||
"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",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"label": "Company",
|
||||
"options": "Company",
|
||||
"read_only": 1,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_7",
|
||||
"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
|
||||
},
|
||||
"fieldname": "section_break_7",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "base",
|
||||
"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",
|
||||
"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
|
||||
},
|
||||
"fieldname": "base",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Base",
|
||||
"options": "Company:company:default_currency"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_9",
|
||||
"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
|
||||
},
|
||||
"fieldname": "column_break_9",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "variable",
|
||||
"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",
|
||||
"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
|
||||
},
|
||||
"fieldname": "variable",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Variable",
|
||||
"options": "Company:company:default_currency"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Amended From",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Salary Structure Assignment",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
"label": "Amended From",
|
||||
"no_copy": 1,
|
||||
"options": "Salary Structure Assignment",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 1,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-08-21 16:15:48.755450",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Salary Structure Assignment",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2019-12-31 17:05:28.637510",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Salary Structure Assignment",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"amend": 1,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"amend": 1,
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR Manager",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"create": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR User",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "employee_name",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "employee_name",
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -767,7 +767,7 @@ def add_additional_cost(stock_entry, work_order):
|
||||
|
||||
items = {}
|
||||
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',
|
||||
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', {
|
||||
'expense_account': expenses_included_in_valuation,
|
||||
'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()
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
|
||||
frappe.ui.form.on('Job Card', {
|
||||
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.for_quantity != frm.doc.transferred_qty) {
|
||||
frm.add_custom_button(__("Material Request"), () => {
|
||||
|
||||
@@ -6,6 +6,7 @@ frappe.ui.form.on("Work Order", {
|
||||
frm.custom_make_buttons = {
|
||||
'Stock Entry': 'Start',
|
||||
'Pick List': 'Create Pick List',
|
||||
'Job Card': 'Create Job Card',
|
||||
};
|
||||
|
||||
// Set query for warehouses
|
||||
@@ -136,7 +137,7 @@ frappe.ui.form.on("Work Order", {
|
||||
|
||||
if (frm.doc.docstatus === 1
|
||||
&& 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 => {
|
||||
if(d.status != 'Completed') {
|
||||
|
||||
@@ -586,6 +586,7 @@ erpnext.patches.v11_0.add_permissions_in_gst_settings
|
||||
erpnext.patches.v11_1.setup_guardian_role
|
||||
execute:frappe.delete_doc('DocType', 'Notification Control')
|
||||
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.v12_0.set_task_status
|
||||
erpnext.patches.v11_0.make_italian_localization_fields # 26-03-2019
|
||||
|
||||
@@ -60,10 +60,10 @@ def execute():
|
||||
'Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice',
|
||||
'Supplier Quotation', 'Purchase Order', 'Purchase Receipt', 'Purchase Invoice'
|
||||
]
|
||||
|
||||
|
||||
for dt in doctypes:
|
||||
for d in frappe.db.sql("""select name, parenttype, parent, item_code, item_tax_rate from `tab{0} Item`
|
||||
where ifnull(item_tax_rate, '') not in ('', '{{}}')
|
||||
where ifnull(item_tax_rate, '') not in ('', '{{}}')
|
||||
and item_tax_template is NULL""".format(dt), as_dict=1):
|
||||
item_tax_map = json.loads(d.item_tax_rate)
|
||||
item_tax_template_name = get_item_tax_template(item_tax_templates,
|
||||
@@ -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)
|
||||
parent_account = frappe.db.get_value("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 = {
|
||||
"account_name": account_name,
|
||||
"company": company,
|
||||
"account_type": "Tax",
|
||||
"parent_account": parent_account
|
||||
}
|
||||
"company": company,
|
||||
"account_type": "Tax",
|
||||
"parent_account": parent_account
|
||||
}
|
||||
tax_type = frappe.db.get_value("Account", filters)
|
||||
if not tax_type:
|
||||
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 }
|
||||
}
|
||||
});
|
||||
|
||||
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) {
|
||||
|
||||
@@ -388,9 +388,14 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
|
||||
var diff = me.frm.doc.total + non_inclusive_tax_amount
|
||||
- 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))) ) {
|
||||
this.frm.doc.rounding_adjustment = flt(flt(this.frm.doc.rounding_adjustment) + diff,
|
||||
precision("rounding_adjustment"));
|
||||
me.frm.doc.rounding_adjustment = diff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -968,7 +968,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
|
||||
qty: function(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);
|
||||
},
|
||||
|
||||
@@ -1398,7 +1398,8 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
|
||||
remove_pricing_rule: function(item) {
|
||||
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) {
|
||||
var items = [];
|
||||
@@ -1418,6 +1419,12 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
fields.forEach(f => {
|
||||
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() {
|
||||
var me = this;
|
||||
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() {
|
||||
this.autofill_warehouse("warehouse");
|
||||
},
|
||||
|
||||
autofill_warehouse : function (warehouse_field) {
|
||||
// set warehouse in all child table rows
|
||||
var me = this;
|
||||
if(this.frm.doc.set_warehouse) {
|
||||
$.each(this.frm.doc.items || [], function(i, item) {
|
||||
frappe.model.set_value(me.frm.doctype + " Item", item.name, "warehouse", me.frm.doc.set_warehouse);
|
||||
let warehouse = (warehouse_field === "warehouse") ? me.frm.doc.set_warehouse : me.frm.doc.set_reserve_warehouse;
|
||||
let child_table = (warehouse_field === "warehouse") ? me.frm.doc.items : me.frm.doc.supplied_items;
|
||||
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() {
|
||||
var me = this;
|
||||
frappe.run_serially([
|
||||
|
||||
@@ -458,7 +458,8 @@ erpnext.utils.update_child_items = function(opts) {
|
||||
fieldname:"item_code",
|
||||
options: 'Item',
|
||||
in_list_view: 1,
|
||||
read_only: 1,
|
||||
read_only: 0,
|
||||
disabled: 0,
|
||||
label: __('Item Code')
|
||||
}, {
|
||||
fieldtype:'Float',
|
||||
@@ -501,6 +502,7 @@ erpnext.utils.update_child_items = function(opts) {
|
||||
frm.doc[opts.child_docname].forEach(d => {
|
||||
dialog.fields_dict.trans_items.df.data.push({
|
||||
"docname": d.name,
|
||||
"name": d.name,
|
||||
"item_code": d.item_code,
|
||||
"qty": d.qty,
|
||||
"rate": d.rate,
|
||||
|
||||
@@ -139,7 +139,7 @@ erpnext.SerialNoBatchSelector = Class.extend({
|
||||
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 => {
|
||||
if(data.item_code == d.item_code) {
|
||||
this.dialog.fields_dict.batches.df.data.push({
|
||||
|
||||
@@ -3,6 +3,26 @@
|
||||
|
||||
frappe.ui.form.on('GST HSN Code', {
|
||||
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,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "field:hsn_code",
|
||||
"beta": 0,
|
||||
"creation": "2017-06-21 10:48:56.422086",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"actions": [],
|
||||
"autoname": "field:hsn_code",
|
||||
"creation": "2017-06-21 10:48:56.422086",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"hsn_code",
|
||||
"description",
|
||||
"taxes"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "hsn_code",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "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,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "hsn_code",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "HSN Code",
|
||||
"reqd": 1,
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "description",
|
||||
"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_standard_filter": 0,
|
||||
"label": "Description",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Small Text",
|
||||
"in_list_view": 1,
|
||||
"label": "Description"
|
||||
},
|
||||
{
|
||||
"fieldname": "taxes",
|
||||
"fieldtype": "Table",
|
||||
"label": "Taxes",
|
||||
"options": "Item Tax"
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2017-09-29 14:38:52.220743",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Regional",
|
||||
"name": "GST HSN Code",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"search_fields": "hsn_code, description",
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "hsn_code",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2019-12-29 11:32:06.849631",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Regional",
|
||||
"name": "GST HSN Code",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"search_fields": "hsn_code, description",
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "hsn_code",
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -8,3 +8,26 @@ from frappe.model.document import Document
|
||||
|
||||
class GSTHSNCode(Document):
|
||||
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
|
||||
import datetime
|
||||
import json
|
||||
import six
|
||||
from six import string_types
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
import pandas as pd
|
||||
@@ -158,7 +160,7 @@ def get_gl_entries(filters, as_dict):
|
||||
where gl.company = %(company)s
|
||||
and DATE(gl.posting_date) >= %(from_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
|
||||
|
||||
@@ -404,7 +406,8 @@ def get_datev_csv(data, filters):
|
||||
|
||||
header = ';'.join(header).encode('latin_1')
|
||||
data = result.to_csv(
|
||||
sep=b';',
|
||||
# Reason for str(';'): https://github.com/pandas-dev/pandas/issues/6035
|
||||
sep=str(';'),
|
||||
# European decimal seperator
|
||||
decimal=',',
|
||||
# Windows "ANSI" encoding
|
||||
@@ -412,13 +415,16 @@ def get_datev_csv(data, filters):
|
||||
# format date as DDMM
|
||||
date_format='%d%m',
|
||||
# Windows line terminator
|
||||
line_terminator=b'\r\n',
|
||||
line_terminator='\r\n',
|
||||
# Do not number rows
|
||||
index=False,
|
||||
# Use all columns defined above
|
||||
columns=columns
|
||||
)
|
||||
|
||||
if not six.PY2:
|
||||
data = data.encode('latin_1')
|
||||
|
||||
return header + b'\r\n' + data
|
||||
|
||||
@frappe.whitelist()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_import": 1,
|
||||
"autoname": "naming_series:",
|
||||
"creation": "2013-05-24 19:29:08",
|
||||
@@ -536,7 +537,7 @@
|
||||
},
|
||||
{
|
||||
"fieldname": "other_charges_calculation",
|
||||
"fieldtype": "Text",
|
||||
"fieldtype": "Long Text",
|
||||
"label": "Taxes and Charges Calculation",
|
||||
"no_copy": 1,
|
||||
"oldfieldtype": "HTML",
|
||||
@@ -927,8 +928,9 @@
|
||||
"icon": "fa fa-shopping-cart",
|
||||
"idx": 82,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"max_attachments": 1,
|
||||
"modified": "2019-11-12 13:19:11.895715",
|
||||
"modified": "2019-12-30 19:14:56.630270",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Quotation",
|
||||
|
||||
@@ -6,13 +6,14 @@
|
||||
frappe.ui.form.on("Sales Order", {
|
||||
setup: function(frm) {
|
||||
frm.custom_make_buttons = {
|
||||
'Delivery Note': 'Delivery',
|
||||
'Delivery Note': 'Delivery Note',
|
||||
'Pick List': 'Pick List',
|
||||
'Sales Invoice': 'Invoice',
|
||||
'Material Request': 'Material Request',
|
||||
'Purchase Order': 'Purchase Order',
|
||||
'Project': 'Project',
|
||||
'Payment Entry': "Payment"
|
||||
'Payment Entry': "Payment",
|
||||
'Work Order': "Work Order"
|
||||
}
|
||||
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 !== 'On Hold') {
|
||||
debugger;
|
||||
|
||||
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
|
||||
@@ -696,4 +698,4 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
});
|
||||
}
|
||||
});
|
||||
$.extend(cur_frm.cscript, new erpnext.selling.SalesOrderController({frm: cur_frm}));
|
||||
$.extend(cur_frm.cscript, new erpnext.selling.SalesOrderController({frm: cur_frm}));
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_import": 1,
|
||||
"autoname": "naming_series:",
|
||||
"creation": "2013-06-18 12:39:59",
|
||||
@@ -619,7 +620,7 @@
|
||||
},
|
||||
{
|
||||
"fieldname": "other_charges_calculation",
|
||||
"fieldtype": "Text",
|
||||
"fieldtype": "Long Text",
|
||||
"label": "Taxes and Charges Calculation",
|
||||
"no_copy": 1,
|
||||
"oldfieldtype": "HTML",
|
||||
@@ -1194,7 +1195,8 @@
|
||||
"icon": "fa fa-file-text",
|
||||
"idx": 105,
|
||||
"is_submittable": 1,
|
||||
"modified": "2019-10-23 14:26:42.767189",
|
||||
"links": [],
|
||||
"modified": "2019-12-30 19:15:28.605085",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Sales Order",
|
||||
|
||||
@@ -380,6 +380,9 @@ class SalesOrder(SellingController):
|
||||
def get_work_order_items(self, for_raw_material_request=0):
|
||||
'''Returns items with BOM that already do not have a linked work order'''
|
||||
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 i in table:
|
||||
bom = get_default_bom_item(i.item_code)
|
||||
@@ -391,7 +394,7 @@ class SalesOrder(SellingController):
|
||||
else:
|
||||
pending_qty = stock_qty
|
||||
|
||||
if pending_qty:
|
||||
if pending_qty and i.item_code not in product_bundle_parents:
|
||||
if bom:
|
||||
items.append(dict(
|
||||
name= i.name,
|
||||
@@ -420,7 +423,7 @@ class SalesOrder(SellingController):
|
||||
|
||||
def _get_delivery_date(ref_doc_delivery_date, red_doc_transaction_date, transaction_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:
|
||||
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)
|
||||
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)
|
||||
|
||||
so.reload()
|
||||
@@ -329,6 +334,48 @@ class TestSalesOrder(unittest.TestCase):
|
||||
self.assertEqual(so.get("items")[-1].qty, 7)
|
||||
self.assertEqual(so.get("items")[-1].amount, 1400)
|
||||
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):
|
||||
|
||||
@@ -84,6 +84,13 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
|
||||
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() {
|
||||
|
||||
@@ -76,7 +76,7 @@ class AuthorizationControl(TransactionBase):
|
||||
add_cond = ''
|
||||
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())+"')")
|
||||
else: add_cond += " and ifnull(system_user,'') = '' and ifnull(system_role,'') = ''"
|
||||
|
||||
@@ -85,7 +85,7 @@ class AuthorizationControl(TransactionBase):
|
||||
if doc_obj:
|
||||
if doc_obj.doctype == 'Sales Invoice': customer = doc_obj.customer
|
||||
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 doc_obj:
|
||||
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)))
|
||||
|
||||
def delete_communications(doctype, company_name, company_fieldname):
|
||||
frappe.db.sql("""
|
||||
DELETE FROM `tabCommunication` WHERE reference_doctype = %s AND
|
||||
EXISTS (SELECT name FROM `tab{0}` WHERE {1} = %s AND `tabCommunication`.reference_name = name)
|
||||
""".format(doctype, company_fieldname), (doctype, company_name))
|
||||
|
||||
refrence_docs = frappe.get_all(doctype, filters={company_fieldname:company_name})
|
||||
reference_doctype_names = [r.name for r in refrence_docs]
|
||||
|
||||
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)
|
||||
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):
|
||||
frappe.db.sql(""" delete from `tabMode of Payment Account`
|
||||
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)
|
||||
if has_batch_no and warehouse and qty > 0:
|
||||
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:
|
||||
batch_qty = get_batch_qty(batch_no=d.batch_no, warehouse=warehouse)
|
||||
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.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.
|
||||
: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
|
||||
batches = get_batches(item_code, warehouse, qty, throw)
|
||||
batches = get_batches(item_code, warehouse, qty, throw, serial_no)
|
||||
|
||||
for batch in batches:
|
||||
if cint(qty) <= cint(batch.qty):
|
||||
@@ -260,16 +258,31 @@ def get_batch_no(item_code, warehouse, qty=1, throw=False):
|
||||
return batch_no
|
||||
|
||||
|
||||
def get_batches(item_code, warehouse, qty=1, throw=False):
|
||||
batches = frappe.db.sql(
|
||||
'select batch_id, sum(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)'
|
||||
'group by batch_id '
|
||||
'order by `tabBatch`.expiry_date ASC, `tabBatch`.creation ASC',
|
||||
(item_code, warehouse),
|
||||
as_dict=True
|
||||
)
|
||||
def get_batches(item_code, warehouse, qty=1, throw=False, serial_no=None):
|
||||
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||
cond = ''
|
||||
if serial_no:
|
||||
batch = frappe.get_all("Serial No",
|
||||
fields = ["distinct batch_no"],
|
||||
filters= {
|
||||
"item_code": item_code,
|
||||
"warehouse": warehouse,
|
||||
"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,
|
||||
"autoname": "naming_series:",
|
||||
"creation": "2013-05-24 19:29:09",
|
||||
@@ -682,7 +683,7 @@
|
||||
},
|
||||
{
|
||||
"fieldname": "other_charges_calculation",
|
||||
"fieldtype": "Text",
|
||||
"fieldtype": "Long Text",
|
||||
"label": "Taxes and Charges Calculation",
|
||||
"no_copy": 1,
|
||||
"oldfieldtype": "HTML",
|
||||
@@ -1238,7 +1239,8 @@
|
||||
"icon": "fa fa-truck",
|
||||
"idx": 146,
|
||||
"is_submittable": 1,
|
||||
"modified": "2019-09-27 14:24:20.269682",
|
||||
"links": [],
|
||||
"modified": "2019-12-30 19:17:13.122644",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Delivery Note",
|
||||
|
||||
@@ -49,7 +49,7 @@ frappe.ui.form.on("Item", {
|
||||
if (!frm.doc.is_fixed_asset) {
|
||||
erpnext.item.make_dashboard(frm);
|
||||
}
|
||||
|
||||
|
||||
if (frm.doc.is_fixed_asset) {
|
||||
frm.trigger('is_fixed_asset');
|
||||
frm.trigger('auto_create_assets');
|
||||
@@ -136,6 +136,20 @@ frappe.ui.form.on("Item", {
|
||||
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) {
|
||||
// set serial no to false & toggles its visibility
|
||||
frm.set_value('has_serial_no', 0);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_guest_to_view": 1,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
@@ -569,6 +570,7 @@
|
||||
{
|
||||
"default": "0.00",
|
||||
"depends_on": "is_stock_item",
|
||||
"description": "Minimum quantity should be as per Stock UOM",
|
||||
"fieldname": "min_order_qty",
|
||||
"fieldtype": "Float",
|
||||
"label": "Minimum Order Qty",
|
||||
@@ -1041,8 +1043,9 @@
|
||||
"icon": "fa fa-tag",
|
||||
"idx": 2,
|
||||
"image_field": "image",
|
||||
"links": [],
|
||||
"max_attachments": 1,
|
||||
"modified": "2019-12-13 12:15:56.197246",
|
||||
"modified": "2020-01-02 19:13:59.295963",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"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))
|
||||
if duplicate:
|
||||
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
|
||||
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,
|
||||
"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",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"actions": [],
|
||||
"creation": "2013-02-22 01:28:01",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"item_tax_template",
|
||||
"tax_category",
|
||||
"valid_from"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "item_tax_template",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Item Tax Template",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "tax_type",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Item Tax Template",
|
||||
"permlevel": 0,
|
||||
"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
|
||||
},
|
||||
"fieldname": "item_tax_template",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Item Tax Template",
|
||||
"oldfieldname": "tax_type",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Item Tax Template",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_from": "",
|
||||
"fieldname": "tax_category",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Tax Category",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "tax_rate",
|
||||
"oldfieldtype": "Currency",
|
||||
"options": "Tax Category",
|
||||
"permlevel": 0,
|
||||
"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
|
||||
"fieldname": "tax_category",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Tax Category",
|
||||
"oldfieldname": "tax_rate",
|
||||
"oldfieldtype": "Currency",
|
||||
"options": "Tax Category"
|
||||
},
|
||||
{
|
||||
"fieldname": "valid_from",
|
||||
"fieldtype": "Date",
|
||||
"in_list_view": 1,
|
||||
"label": "Valid From"
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 1,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-12-21 23:52:40.798944",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Item Tax",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"track_changes": 0,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2019-12-28 21:54:40.807849",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Item Tax",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC"
|
||||
}
|
||||
@@ -230,7 +230,8 @@ frappe.ui.form.on('Material Request', {
|
||||
|
||||
make_purchase_order: function(frm) {
|
||||
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) => {
|
||||
frappe.model.open_mapped_doc({
|
||||
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 },
|
||||
run_link_triggers: true
|
||||
});
|
||||
}
|
||||
},
|
||||
__('Enter Supplier')
|
||||
)
|
||||
},
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_import": 1,
|
||||
"autoname": "naming_series:",
|
||||
"creation": "2013-05-21 16:16:39",
|
||||
@@ -305,6 +306,7 @@
|
||||
"fieldname": "contact_email",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Contact Email",
|
||||
"options": "Email",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
@@ -614,7 +616,7 @@
|
||||
},
|
||||
{
|
||||
"fieldname": "other_charges_calculation",
|
||||
"fieldtype": "Text",
|
||||
"fieldtype": "Long Text",
|
||||
"label": "Taxes and Charges Calculation",
|
||||
"no_copy": 1,
|
||||
"oldfieldtype": "HTML",
|
||||
@@ -1056,7 +1058,8 @@
|
||||
"icon": "fa fa-truck",
|
||||
"idx": 261,
|
||||
"is_submittable": 1,
|
||||
"modified": "2019-09-27 14:24:49.044505",
|
||||
"links": [],
|
||||
"modified": "2019-12-30 19:12:49.709711",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Purchase Receipt",
|
||||
|
||||
@@ -88,7 +88,7 @@ class PurchaseReceipt(BuyingController):
|
||||
|
||||
if getdate(self.posting_date) > getdate(nowdate()):
|
||||
throw(_("Posting Date cannot be future date"))
|
||||
|
||||
|
||||
def validate_cwip_accounts(self):
|
||||
for item in self.get('items'):
|
||||
if item.is_fixed_asset and is_cwip_accounting_enabled(item.asset_category):
|
||||
@@ -362,7 +362,7 @@ class PurchaseReceipt(BuyingController):
|
||||
# valuation rate is total of net rate, raw mat supp cost, tax amount, lcv amount per item
|
||||
self.update_assets(item, item.valuation_rate)
|
||||
return gl_entries
|
||||
|
||||
|
||||
def add_asset_gl_entries(self, item, gl_entries):
|
||||
arbnb_account = self.get_company_default("asset_received_but_not_billed")
|
||||
# This returns category's cwip account if not then fallback to company's default cwip account
|
||||
@@ -395,7 +395,7 @@ class PurchaseReceipt(BuyingController):
|
||||
"credit_in_account_currency": (base_asset_amount
|
||||
if asset_rbnb_currency == self.company_currency else asset_amount)
|
||||
}, item=item))
|
||||
|
||||
|
||||
def add_lcv_gl_entries(self, item, gl_entries):
|
||||
expenses_included_in_asset_valuation = self.get_company_default("expenses_included_in_asset_valuation")
|
||||
if not is_cwip_accounting_enabled(item.asset_category):
|
||||
@@ -404,7 +404,7 @@ class PurchaseReceipt(BuyingController):
|
||||
else:
|
||||
# This returns company's default cwip account
|
||||
asset_account = get_asset_account("capital_work_in_progress_account", company=self.company)
|
||||
|
||||
|
||||
gl_entries.append(self.get_gl_dict({
|
||||
"account": expenses_included_in_asset_valuation,
|
||||
"against": asset_account,
|
||||
@@ -424,7 +424,7 @@ class PurchaseReceipt(BuyingController):
|
||||
}, item=item))
|
||||
|
||||
def update_assets(self, item, valuation_rate):
|
||||
assets = frappe.db.get_all('Asset',
|
||||
assets = frappe.db.get_all('Asset',
|
||||
filters={ 'purchase_receipt': self.name, 'item_code': item.item_code }
|
||||
)
|
||||
|
||||
@@ -610,27 +610,36 @@ def make_stock_entry(source_name,target_doc=None):
|
||||
return doclist
|
||||
|
||||
def get_item_account_wise_additional_cost(purchase_document):
|
||||
landed_cost_voucher = frappe.get_value("Landed Cost Purchase Receipt",
|
||||
{"receipt_document": purchase_document, "docstatus": 1}, "parent")
|
||||
landed_cost_vouchers = frappe.get_all("Landed Cost Purchase Receipt", fields=["parent"],
|
||||
filters = {"receipt_document": purchase_document, "docstatus": 1})
|
||||
|
||||
if not landed_cost_voucher:
|
||||
if not landed_cost_vouchers:
|
||||
return
|
||||
|
||||
total_item_cost = 0
|
||||
item_account_wise_cost = {}
|
||||
landed_cost_voucher_doc = frappe.get_doc("Landed Cost Voucher", landed_cost_voucher)
|
||||
based_on_field = frappe.scrub(landed_cost_voucher_doc.distribute_charges_based_on)
|
||||
item_cost_allocated = []
|
||||
|
||||
for item in landed_cost_voucher_doc.items:
|
||||
total_item_cost += item.get(based_on_field)
|
||||
for lcv in landed_cost_vouchers:
|
||||
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
|
||||
for item in landed_cost_voucher_doc.items:
|
||||
if item.purchase_receipt_item not in item_cost_allocated:
|
||||
total_item_cost += item.get(based_on_field)
|
||||
item_cost_allocated.append(item.purchase_receipt_item)
|
||||
|
||||
for lcv in landed_cost_vouchers:
|
||||
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
|
||||
|
||||
|
||||
@@ -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("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("sample_quantity", doc.purpose=='Material Receipt');
|
||||
|
||||
|
||||
@@ -75,6 +75,7 @@ class StockEntry(StockController):
|
||||
set_batch_nos(self, 's_warehouse')
|
||||
|
||||
self.set_incoming_rate()
|
||||
self.validate_serialized_batch()
|
||||
self.set_actual_qty()
|
||||
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":
|
||||
self.validate_work_order_status()
|
||||
else:
|
||||
self.update_work_order()
|
||||
|
||||
self.update_work_order()
|
||||
self.update_stock_ledger()
|
||||
self.make_gl_entries_on_cancel()
|
||||
self.update_cost_in_project()
|
||||
@@ -372,7 +372,7 @@ class StockEntry(StockController):
|
||||
elif d.t_warehouse and not d.basic_rate:
|
||||
d.basic_rate = get_valuation_rate(d.item_code, d.t_warehouse,
|
||||
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):
|
||||
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):
|
||||
if self.purpose in ["Manufacture", "Repack"]:
|
||||
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_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):
|
||||
if self.purpose == "Material Issue":
|
||||
self.additional_costs = []
|
||||
@@ -585,12 +591,18 @@ class StockEntry(StockController):
|
||||
|
||||
def validate_finished_goods(self):
|
||||
"""validation: finished good quantity should be same as manufacturing quantity"""
|
||||
if not self.work_order: return
|
||||
|
||||
items_with_target_warehouse = []
|
||||
allowance_percentage = flt(frappe.db.get_single_value("Manufacturing Settings",
|
||||
"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'):
|
||||
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}"). \
|
||||
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)
|
||||
|
||||
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)
|
||||
if self.fg_completed_qty > allowed_qty:
|
||||
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", "material_consumption")== 1:
|
||||
self.get_unconsumed_raw_materials()
|
||||
|
||||
else:
|
||||
if not self.fg_completed_qty:
|
||||
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.t_warehouse = item_dict[d].get("to_warehouse")
|
||||
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.stock_uom = stock_uom
|
||||
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.allow_alternative_item = item_dict[d].get("allow_alternative_item", 0)
|
||||
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"):
|
||||
se_child.idx = item_dict[d].get("idx")
|
||||
for field in ["idx", "po_detail", "original_item",
|
||||
"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:
|
||||
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
|
||||
|
||||
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()
|
||||
def get_uom_details(item_code, uom, qty):
|
||||
"""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()
|
||||
|
||||
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`
|
||||
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
|
||||
import frappe
|
||||
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
|
||||
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
|
||||
@@ -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)
|
||||
|
||||
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)
|
||||
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)
|
||||
@@ -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_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:
|
||||
if cstr(tax.tax_category) == cstr(args.get("tax_category")):
|
||||
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
|
||||
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):
|
||||
"""
|
||||
@@ -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):
|
||||
item_price_data = price_list_rate
|
||||
else:
|
||||
for field in ["customer", "supplier", "min_qty"]:
|
||||
for field in ["customer", "supplier"]:
|
||||
del item_price_args[field]
|
||||
|
||||
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"):
|
||||
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"))
|
||||
|
||||
@@ -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