fix: merge conflict
This commit is contained in:
commit
11eb30d082
@ -5,7 +5,7 @@ import frappe
|
|||||||
from erpnext.hooks import regional_overrides
|
from erpnext.hooks import regional_overrides
|
||||||
from frappe.utils import getdate
|
from frappe.utils import getdate
|
||||||
|
|
||||||
__version__ = '13.0.0-beta.13'
|
__version__ = '13.0.0-beta.14'
|
||||||
|
|
||||||
def get_default_company(user=None):
|
def get_default_company(user=None):
|
||||||
'''Get default company for user'''
|
'''Get default company for user'''
|
||||||
|
|||||||
@ -605,12 +605,22 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
{fieldtype:"Column Break"},
|
{fieldtype:"Column Break"},
|
||||||
{fieldtype:"Float", label: __("Less Than Amount"), fieldname:"outstanding_amt_less_than"},
|
{fieldtype:"Float", label: __("Less Than Amount"), fieldname:"outstanding_amt_less_than"},
|
||||||
{fieldtype:"Section Break"},
|
{fieldtype:"Section Break"},
|
||||||
|
{fieldtype:"Link", label:__("Cost Center"), fieldname:"cost_center", options:"Cost Center",
|
||||||
|
"get_query": function() {
|
||||||
|
return {
|
||||||
|
"filters": {"company": frm.doc.company}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{fieldtype:"Column Break"},
|
||||||
|
{fieldtype:"Section Break"},
|
||||||
{fieldtype:"Check", label: __("Allocate Payment Amount"), fieldname:"allocate_payment_amount", default:1},
|
{fieldtype:"Check", label: __("Allocate Payment Amount"), fieldname:"allocate_payment_amount", default:1},
|
||||||
];
|
];
|
||||||
|
|
||||||
frappe.prompt(fields, function(filters){
|
frappe.prompt(fields, function(filters){
|
||||||
frappe.flags.allocate_payment_amount = true;
|
frappe.flags.allocate_payment_amount = true;
|
||||||
frm.events.validate_filters_data(frm, filters);
|
frm.events.validate_filters_data(frm, filters);
|
||||||
|
frm.doc.cost_center = filters.cost_center;
|
||||||
frm.events.get_outstanding_documents(frm, filters);
|
frm.events.get_outstanding_documents(frm, filters);
|
||||||
}, __("Filters"), __("Get Outstanding Documents"));
|
}, __("Filters"), __("Get Outstanding Documents"));
|
||||||
},
|
},
|
||||||
@ -627,13 +637,13 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
let to_field = fields[key][1];
|
let to_field = fields[key][1];
|
||||||
|
|
||||||
if (filters[from_field] && !filters[to_field]) {
|
if (filters[from_field] && !filters[to_field]) {
|
||||||
frappe.throw(__("Error: {0} is mandatory field",
|
frappe.throw(
|
||||||
[to_field.replace(/_/g, " ")]
|
__("Error: {0} is mandatory field", [to_field.replace(/_/g, " ")])
|
||||||
));
|
);
|
||||||
} else if (filters[from_field] && filters[from_field] > filters[to_field]) {
|
} else if (filters[from_field] && filters[from_field] > filters[to_field]) {
|
||||||
frappe.throw(__("{0}: {1} must be less than {2}",
|
frappe.throw(
|
||||||
[key, from_field.replace(/_/g, " "), to_field.replace(/_/g, " ")]
|
__("{0}: {1} must be less than {2}", [key, from_field.replace(/_/g, " "), to_field.replace(/_/g, " ")])
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -682,6 +692,8 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
c.total_amount = d.invoice_amount;
|
c.total_amount = d.invoice_amount;
|
||||||
c.outstanding_amount = d.outstanding_amount;
|
c.outstanding_amount = d.outstanding_amount;
|
||||||
c.bill_no = d.bill_no;
|
c.bill_no = d.bill_no;
|
||||||
|
c.payment_term = d.payment_term;
|
||||||
|
c.allocated_amount = d.allocated_amount;
|
||||||
|
|
||||||
if(!in_list(["Sales Order", "Purchase Order", "Expense Claim", "Fees"], d.voucher_type)) {
|
if(!in_list(["Sales Order", "Purchase Order", "Expense Claim", "Fees"], d.voucher_type)) {
|
||||||
if(flt(d.outstanding_amount) > 0)
|
if(flt(d.outstanding_amount) > 0)
|
||||||
@ -764,12 +776,15 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
} else if (in_list(["Customer", "Supplier"], frm.doc.party_type)) {
|
} else if (in_list(["Customer", "Supplier"], frm.doc.party_type)) {
|
||||||
if(paid_amount > total_negative_outstanding) {
|
if(paid_amount > total_negative_outstanding) {
|
||||||
if(total_negative_outstanding == 0) {
|
if(total_negative_outstanding == 0) {
|
||||||
frappe.msgprint(__("Cannot {0} {1} {2} without any negative outstanding invoice",
|
frappe.msgprint(
|
||||||
[frm.doc.payment_type,
|
__("Cannot {0} {1} {2} without any negative outstanding invoice", [frm.doc.payment_type,
|
||||||
(frm.doc.party_type=="Customer" ? "to" : "from"), frm.doc.party_type]));
|
(frm.doc.party_type=="Customer" ? "to" : "from"), frm.doc.party_type])
|
||||||
|
);
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
frappe.msgprint(__("Paid Amount cannot be greater than total negative outstanding amount {0}", [total_negative_outstanding]));
|
frappe.msgprint(
|
||||||
|
__("Paid Amount cannot be greater than total negative outstanding amount {0}", [total_negative_outstanding])
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -781,10 +796,13 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$.each(frm.doc.references || [], function(i, row) {
|
$.each(frm.doc.references || [], function(i, row) {
|
||||||
row.allocated_amount = 0 //If allocate payment amount checkbox is unchecked, set zero to allocate amount
|
if (frappe.flags.allocate_payment_amount == 0) {
|
||||||
if(frappe.flags.allocate_payment_amount != 0){
|
//If allocate payment amount checkbox is unchecked, set zero to allocate amount
|
||||||
if(row.outstanding_amount > 0 && allocated_positive_outstanding > 0) {
|
row.allocated_amount = 0;
|
||||||
if(row.outstanding_amount >= allocated_positive_outstanding) {
|
|
||||||
|
} else if (frappe.flags.allocate_payment_amount != 0 && !row.allocated_amount) {
|
||||||
|
if (row.outstanding_amount > 0 && allocated_positive_outstanding > 0) {
|
||||||
|
if (row.outstanding_amount >= allocated_positive_outstanding) {
|
||||||
row.allocated_amount = allocated_positive_outstanding;
|
row.allocated_amount = allocated_positive_outstanding;
|
||||||
} else {
|
} else {
|
||||||
row.allocated_amount = row.outstanding_amount;
|
row.allocated_amount = row.outstanding_amount;
|
||||||
@ -792,9 +810,11 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
|
|
||||||
allocated_positive_outstanding -= flt(row.allocated_amount);
|
allocated_positive_outstanding -= flt(row.allocated_amount);
|
||||||
} else if (row.outstanding_amount < 0 && allocated_negative_outstanding) {
|
} else if (row.outstanding_amount < 0 && allocated_negative_outstanding) {
|
||||||
if(Math.abs(row.outstanding_amount) >= allocated_negative_outstanding)
|
if (Math.abs(row.outstanding_amount) >= allocated_negative_outstanding) {
|
||||||
row.allocated_amount = -1*allocated_negative_outstanding;
|
row.allocated_amount = -1*allocated_negative_outstanding;
|
||||||
else row.allocated_amount = row.outstanding_amount;
|
} else {
|
||||||
|
row.allocated_amount = row.outstanding_amount;
|
||||||
|
};
|
||||||
|
|
||||||
allocated_negative_outstanding -= Math.abs(flt(row.allocated_amount));
|
allocated_negative_outstanding -= Math.abs(flt(row.allocated_amount));
|
||||||
}
|
}
|
||||||
@ -1066,11 +1086,6 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
frm.set_value("paid_from_account_balance", r.message.paid_from_account_balance);
|
frm.set_value("paid_from_account_balance", r.message.paid_from_account_balance);
|
||||||
frm.set_value("paid_to_account_balance", r.message.paid_to_account_balance);
|
frm.set_value("paid_to_account_balance", r.message.paid_to_account_balance);
|
||||||
frm.set_value("party_balance", r.message.party_balance);
|
frm.set_value("party_balance", r.message.party_balance);
|
||||||
},
|
|
||||||
() => {
|
|
||||||
if(frm.doc.payment_type != "Internal") {
|
|
||||||
frm.clear_table("references");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@ -333,33 +333,50 @@ class PaymentEntry(AccountsController):
|
|||||||
invoice_payment_amount_map = {}
|
invoice_payment_amount_map = {}
|
||||||
invoice_paid_amount_map = {}
|
invoice_paid_amount_map = {}
|
||||||
|
|
||||||
for reference in self.get('references'):
|
for ref in self.get('references'):
|
||||||
if reference.payment_term and reference.reference_name:
|
if ref.payment_term and ref.reference_name:
|
||||||
key = (reference.payment_term, reference.reference_name)
|
key = (ref.payment_term, ref.reference_name)
|
||||||
invoice_payment_amount_map.setdefault(key, 0.0)
|
invoice_payment_amount_map.setdefault(key, 0.0)
|
||||||
invoice_payment_amount_map[key] += reference.allocated_amount
|
invoice_payment_amount_map[key] += ref.allocated_amount
|
||||||
|
|
||||||
if not invoice_paid_amount_map.get(key):
|
if not invoice_paid_amount_map.get(key):
|
||||||
payment_schedule = frappe.get_all('Payment Schedule', filters={'parent': reference.reference_name},
|
payment_schedule = frappe.get_all(
|
||||||
fields=['paid_amount', 'payment_amount', 'payment_term'])
|
'Payment Schedule',
|
||||||
|
filters={'parent': ref.reference_name},
|
||||||
|
fields=['paid_amount', 'payment_amount', 'payment_term', 'discount', 'outstanding']
|
||||||
|
)
|
||||||
for term in payment_schedule:
|
for term in payment_schedule:
|
||||||
invoice_key = (term.payment_term, reference.reference_name)
|
invoice_key = (term.payment_term, ref.reference_name)
|
||||||
invoice_paid_amount_map.setdefault(invoice_key, {})
|
invoice_paid_amount_map.setdefault(invoice_key, {})
|
||||||
invoice_paid_amount_map[invoice_key]['outstanding'] = term.payment_amount - term.paid_amount
|
invoice_paid_amount_map[invoice_key]['outstanding'] = term.outstanding
|
||||||
|
invoice_paid_amount_map[invoice_key]['discounted_amt'] = ref.total_amount * (term.discount / 100)
|
||||||
|
|
||||||
|
for key, allocated_amount in iteritems(invoice_payment_amount_map):
|
||||||
|
outstanding = flt(invoice_paid_amount_map.get(key, {}).get('outstanding'))
|
||||||
|
discounted_amt = flt(invoice_paid_amount_map.get(key, {}).get('discounted_amt'))
|
||||||
|
|
||||||
for key, amount in iteritems(invoice_payment_amount_map):
|
|
||||||
if cancel:
|
if cancel:
|
||||||
frappe.db.sql(""" UPDATE `tabPayment Schedule` SET paid_amount = `paid_amount` - %s
|
frappe.db.sql("""
|
||||||
WHERE parent = %s and payment_term = %s""", (amount, key[1], key[0]))
|
UPDATE `tabPayment Schedule`
|
||||||
|
SET
|
||||||
|
paid_amount = `paid_amount` - %s,
|
||||||
|
discounted_amount = `discounted_amount` - %s,
|
||||||
|
outstanding = `outstanding` + %s
|
||||||
|
WHERE parent = %s and payment_term = %s""",
|
||||||
|
(allocated_amount - discounted_amt, discounted_amt, allocated_amount, key[1], key[0]))
|
||||||
else:
|
else:
|
||||||
outstanding = flt(invoice_paid_amount_map.get(key, {}).get('outstanding'))
|
if allocated_amount > outstanding:
|
||||||
|
|
||||||
if amount > outstanding:
|
|
||||||
frappe.throw(_('Cannot allocate more than {0} against payment term {1}').format(outstanding, key[0]))
|
frappe.throw(_('Cannot allocate more than {0} against payment term {1}').format(outstanding, key[0]))
|
||||||
|
|
||||||
if amount and outstanding:
|
if allocated_amount and outstanding:
|
||||||
frappe.db.sql(""" UPDATE `tabPayment Schedule` SET paid_amount = `paid_amount` + %s
|
frappe.db.sql("""
|
||||||
WHERE parent = %s and payment_term = %s""", (amount, key[1], key[0]))
|
UPDATE `tabPayment Schedule`
|
||||||
|
SET
|
||||||
|
paid_amount = `paid_amount` + %s,
|
||||||
|
discounted_amount = `discounted_amount` + %s,
|
||||||
|
outstanding = `outstanding` - %s
|
||||||
|
WHERE parent = %s and payment_term = %s""",
|
||||||
|
(allocated_amount - discounted_amt, discounted_amt, allocated_amount, key[1], key[0]))
|
||||||
|
|
||||||
def set_status(self):
|
def set_status(self):
|
||||||
if self.docstatus == 2:
|
if self.docstatus == 2:
|
||||||
@ -708,6 +725,8 @@ def get_outstanding_reference_documents(args):
|
|||||||
outstanding_invoices = get_outstanding_invoices(args.get("party_type"), args.get("party"),
|
outstanding_invoices = get_outstanding_invoices(args.get("party_type"), args.get("party"),
|
||||||
args.get("party_account"), filters=args, condition=condition)
|
args.get("party_account"), filters=args, condition=condition)
|
||||||
|
|
||||||
|
outstanding_invoices = split_invoices_based_on_payment_terms(outstanding_invoices)
|
||||||
|
|
||||||
for d in outstanding_invoices:
|
for d in outstanding_invoices:
|
||||||
d["exchange_rate"] = 1
|
d["exchange_rate"] = 1
|
||||||
if party_account_currency != company_currency:
|
if party_account_currency != company_currency:
|
||||||
@ -735,6 +754,46 @@ def get_outstanding_reference_documents(args):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def split_invoices_based_on_payment_terms(outstanding_invoices):
|
||||||
|
invoice_ref_based_on_payment_terms = {}
|
||||||
|
for idx, d in enumerate(outstanding_invoices):
|
||||||
|
if d.voucher_type in ['Sales Invoice', 'Purchase Invoice']:
|
||||||
|
payment_term_template = frappe.db.get_value(d.voucher_type, d.voucher_no, 'payment_terms_template')
|
||||||
|
if payment_term_template:
|
||||||
|
allocate_payment_based_on_payment_terms = frappe.db.get_value(
|
||||||
|
'Payment Terms Template', payment_term_template, 'allocate_payment_based_on_payment_terms')
|
||||||
|
if allocate_payment_based_on_payment_terms:
|
||||||
|
payment_schedule = frappe.get_all('Payment Schedule', filters={'parent': d.voucher_no}, fields=["*"])
|
||||||
|
|
||||||
|
for payment_term in payment_schedule:
|
||||||
|
if payment_term.outstanding > 0.1:
|
||||||
|
invoice_ref_based_on_payment_terms.setdefault(idx, [])
|
||||||
|
invoice_ref_based_on_payment_terms[idx].append(frappe._dict({
|
||||||
|
'due_date': d.due_date,
|
||||||
|
'currency': d.currency,
|
||||||
|
'voucher_no': d.voucher_no,
|
||||||
|
'voucher_type': d.voucher_type,
|
||||||
|
'posting_date': d.posting_date,
|
||||||
|
'invoice_amount': flt(d.invoice_amount),
|
||||||
|
'outstanding_amount': flt(d.outstanding_amount),
|
||||||
|
'payment_amount': payment_term.payment_amount,
|
||||||
|
'payment_term': payment_term.payment_term,
|
||||||
|
'allocated_amount': payment_term.outstanding
|
||||||
|
}))
|
||||||
|
|
||||||
|
if invoice_ref_based_on_payment_terms:
|
||||||
|
for idx, ref in invoice_ref_based_on_payment_terms.items():
|
||||||
|
voucher_no = outstanding_invoices[idx]['voucher_no']
|
||||||
|
voucher_type = outstanding_invoices[idx]['voucher_type']
|
||||||
|
|
||||||
|
frappe.msgprint(_("Spliting {} {} into {} rows as per payment terms").format(
|
||||||
|
voucher_type, voucher_no, len(ref)), alert=True)
|
||||||
|
|
||||||
|
outstanding_invoices.pop(idx - 1)
|
||||||
|
outstanding_invoices += invoice_ref_based_on_payment_terms[idx]
|
||||||
|
|
||||||
|
return outstanding_invoices
|
||||||
|
|
||||||
def get_orders_to_be_billed(posting_date, party_type, party,
|
def get_orders_to_be_billed(posting_date, party_type, party,
|
||||||
company, party_account_currency, company_currency, cost_center=None, filters=None):
|
company, party_account_currency, company_currency, cost_center=None, filters=None):
|
||||||
if party_type == "Customer":
|
if party_type == "Customer":
|
||||||
@ -1091,6 +1150,8 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
|
|||||||
paid_amount, received_amount = set_paid_amount_and_received_amount(
|
paid_amount, received_amount = set_paid_amount_and_received_amount(
|
||||||
dt, party_account_currency, bank, outstanding_amount, payment_type, bank_amount, doc)
|
dt, party_account_currency, bank, outstanding_amount, payment_type, bank_amount, doc)
|
||||||
|
|
||||||
|
paid_amount, received_amount, discount_amount = apply_early_payment_discount(paid_amount, received_amount, doc)
|
||||||
|
|
||||||
pe = frappe.new_doc("Payment Entry")
|
pe = frappe.new_doc("Payment Entry")
|
||||||
pe.payment_type = payment_type
|
pe.payment_type = payment_type
|
||||||
pe.company = doc.company
|
pe.company = doc.company
|
||||||
@ -1160,11 +1221,20 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
|
|||||||
|
|
||||||
pe.setup_party_account_field()
|
pe.setup_party_account_field()
|
||||||
pe.set_missing_values()
|
pe.set_missing_values()
|
||||||
|
|
||||||
if party_account and bank:
|
if party_account and bank:
|
||||||
if dt == "Employee Advance":
|
if dt == "Employee Advance":
|
||||||
reference_doc = doc
|
reference_doc = doc
|
||||||
pe.set_exchange_rate(ref_doc=reference_doc)
|
pe.set_exchange_rate(ref_doc=reference_doc)
|
||||||
pe.set_amounts()
|
pe.set_amounts()
|
||||||
|
if discount_amount:
|
||||||
|
pe.set_gain_or_loss(account_details={
|
||||||
|
'account': frappe.get_cached_value('Company', pe.company, "default_discount_account"),
|
||||||
|
'cost_center': pe.cost_center or frappe.get_cached_value('Company', pe.company, "cost_center"),
|
||||||
|
'amount': discount_amount * (-1 if payment_type == "Pay" else 1)
|
||||||
|
})
|
||||||
|
pe.set_difference_amount()
|
||||||
|
|
||||||
return pe
|
return pe
|
||||||
|
|
||||||
def get_bank_cash_account(doc, bank_account):
|
def get_bank_cash_account(doc, bank_account):
|
||||||
@ -1285,6 +1355,33 @@ def set_paid_amount_and_received_amount(dt, party_account_currency, bank, outsta
|
|||||||
paid_amount = received_amount * doc.get('exchange_rate', 1)
|
paid_amount = received_amount * doc.get('exchange_rate', 1)
|
||||||
return paid_amount, received_amount
|
return paid_amount, received_amount
|
||||||
|
|
||||||
|
def apply_early_payment_discount(paid_amount, received_amount, doc):
|
||||||
|
total_discount = 0
|
||||||
|
if doc.doctype in ['Sales Invoice', 'Purchase Invoice'] and doc.payment_schedule:
|
||||||
|
for term in doc.payment_schedule:
|
||||||
|
if not term.discounted_amount and term.discount and getdate(nowdate()) <= term.discount_date:
|
||||||
|
if term.discount_type == 'Percentage':
|
||||||
|
discount_amount = flt(doc.get('grand_total')) * (term.discount / 100)
|
||||||
|
else:
|
||||||
|
discount_amount = term.discount
|
||||||
|
|
||||||
|
discount_amount_in_foreign_currency = discount_amount * doc.get('conversion_rate', 1)
|
||||||
|
|
||||||
|
if doc.doctype == 'Sales Invoice':
|
||||||
|
paid_amount -= discount_amount
|
||||||
|
received_amount -= discount_amount_in_foreign_currency
|
||||||
|
else:
|
||||||
|
received_amount -= discount_amount
|
||||||
|
paid_amount -= discount_amount_in_foreign_currency
|
||||||
|
|
||||||
|
total_discount += discount_amount
|
||||||
|
|
||||||
|
if total_discount:
|
||||||
|
money = frappe.utils.fmt_money(total_discount, currency=doc.get('currency'))
|
||||||
|
frappe.msgprint(_("Discount of {} applied as per Payment Term").format(money), alert=1)
|
||||||
|
|
||||||
|
return paid_amount, received_amount, total_discount
|
||||||
|
|
||||||
def get_reference_as_per_payment_terms(payment_schedule, dt, dn, doc, grand_total, outstanding_amount):
|
def get_reference_as_per_payment_terms(payment_schedule, dt, dn, doc, grand_total, outstanding_amount):
|
||||||
references = []
|
references = []
|
||||||
for payment_term in payment_schedule:
|
for payment_term in payment_schedule:
|
||||||
|
|||||||
@ -193,6 +193,34 @@ class TestPaymentEntry(unittest.TestCase):
|
|||||||
self.assertEqual(si.payment_schedule[0].paid_amount, 200.0)
|
self.assertEqual(si.payment_schedule[0].paid_amount, 200.0)
|
||||||
self.assertEqual(si.payment_schedule[1].paid_amount, 36.0)
|
self.assertEqual(si.payment_schedule[1].paid_amount, 36.0)
|
||||||
|
|
||||||
|
def test_payment_entry_against_payment_terms_with_discount(self):
|
||||||
|
si = create_sales_invoice(do_not_save=1, qty=1, rate=200)
|
||||||
|
create_payment_terms_template_with_discount()
|
||||||
|
si.payment_terms_template = 'Test Discount Template'
|
||||||
|
|
||||||
|
frappe.db.set_value('Company', si.company, 'default_discount_account', 'Write Off - _TC')
|
||||||
|
|
||||||
|
si.append('taxes', {
|
||||||
|
"charge_type": "On Net Total",
|
||||||
|
"account_head": "_Test Account Service Tax - _TC",
|
||||||
|
"cost_center": "_Test Cost Center - _TC",
|
||||||
|
"description": "Service Tax",
|
||||||
|
"rate": 18
|
||||||
|
})
|
||||||
|
si.save()
|
||||||
|
|
||||||
|
si.submit()
|
||||||
|
|
||||||
|
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Cash - _TC")
|
||||||
|
pe.submit()
|
||||||
|
si.load_from_db()
|
||||||
|
|
||||||
|
self.assertEqual(pe.references[0].payment_term, '30 Credit Days with 10% Discount')
|
||||||
|
self.assertEqual(si.payment_schedule[0].payment_amount, 236.0)
|
||||||
|
self.assertEqual(si.payment_schedule[0].paid_amount, 212.40)
|
||||||
|
self.assertEqual(si.payment_schedule[0].outstanding, 0)
|
||||||
|
self.assertEqual(si.payment_schedule[0].discounted_amount, 23.6)
|
||||||
|
|
||||||
|
|
||||||
def test_payment_against_purchase_invoice_to_check_status(self):
|
def test_payment_against_purchase_invoice_to_check_status(self):
|
||||||
pi = make_purchase_invoice(supplier="_Test Supplier USD", debit_to="_Test Payable USD - _TC",
|
pi = make_purchase_invoice(supplier="_Test Supplier USD", debit_to="_Test Payable USD - _TC",
|
||||||
@ -591,6 +619,26 @@ def create_payment_terms_template():
|
|||||||
}]
|
}]
|
||||||
}).insert()
|
}).insert()
|
||||||
|
|
||||||
|
def create_payment_terms_template_with_discount():
|
||||||
|
|
||||||
|
create_payment_term('30 Credit Days with 10% Discount')
|
||||||
|
|
||||||
|
if not frappe.db.exists('Payment Terms Template', 'Test Discount Template'):
|
||||||
|
payment_term_template = frappe.get_doc({
|
||||||
|
'doctype': 'Payment Terms Template',
|
||||||
|
'template_name': 'Test Discount Template',
|
||||||
|
'allocate_payment_based_on_payment_terms': 1,
|
||||||
|
'terms': [{
|
||||||
|
'doctype': 'Payment Terms Template Detail',
|
||||||
|
'payment_term': '30 Credit Days with 10% Discount',
|
||||||
|
'invoice_portion': 100,
|
||||||
|
'credit_days_based_on': 'Day(s) after invoice date',
|
||||||
|
'credit_days': 2,
|
||||||
|
'discount': 10,
|
||||||
|
'discount_validity_based_on': 'Day(s) after invoice date',
|
||||||
|
'discount_validity': 1
|
||||||
|
}]
|
||||||
|
}).insert()
|
||||||
|
|
||||||
def create_payment_term(name):
|
def create_payment_term(name):
|
||||||
if not frappe.db.exists('Payment Term', name):
|
if not frappe.db.exists('Payment Term', name):
|
||||||
|
|||||||
@ -58,7 +58,7 @@
|
|||||||
"fieldname": "total_amount",
|
"fieldname": "total_amount",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Total Amount",
|
"label": "Grand Total",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
@ -92,9 +92,10 @@
|
|||||||
"options": "Payment Term"
|
"options": "Payment Term"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-03-13 12:07:19.362539",
|
"modified": "2021-02-10 11:25:47.144392",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Payment Entry Reference",
|
"name": "Payment Entry Reference",
|
||||||
|
|||||||
@ -6,11 +6,23 @@
|
|||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
"field_order": [
|
"field_order": [
|
||||||
"payment_term",
|
"payment_term",
|
||||||
|
"section_break_15",
|
||||||
"description",
|
"description",
|
||||||
|
"section_break_4",
|
||||||
"due_date",
|
"due_date",
|
||||||
"invoice_portion",
|
|
||||||
"payment_amount",
|
|
||||||
"mode_of_payment",
|
"mode_of_payment",
|
||||||
|
"column_break_5",
|
||||||
|
"invoice_portion",
|
||||||
|
"section_break_6",
|
||||||
|
"discount_type",
|
||||||
|
"discount_date",
|
||||||
|
"column_break_9",
|
||||||
|
"discount",
|
||||||
|
"section_break_9",
|
||||||
|
"payment_amount",
|
||||||
|
"discounted_amount",
|
||||||
|
"column_break_3",
|
||||||
|
"outstanding",
|
||||||
"paid_amount"
|
"paid_amount"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
@ -25,6 +37,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"columns": 2,
|
"columns": 2,
|
||||||
|
"fetch_from": "payment_term.description",
|
||||||
"fieldname": "description",
|
"fieldname": "description",
|
||||||
"fieldtype": "Small Text",
|
"fieldtype": "Small Text",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
@ -62,14 +75,82 @@
|
|||||||
"options": "Mode of Payment"
|
"options": "Mode of Payment"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"depends_on": "paid_amount",
|
||||||
"fieldname": "paid_amount",
|
"fieldname": "paid_amount",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"label": "Paid Amount"
|
"label": "Paid Amount"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_3",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"depends_on": "discounted_amount",
|
||||||
|
"fieldname": "discounted_amount",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"label": "Discounted Amount",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fetch_from": "payment_amount",
|
||||||
|
"fieldname": "outstanding",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"label": "Outstanding",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_5",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "discount",
|
||||||
|
"fieldname": "discount_date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"label": "Discount Date",
|
||||||
|
"mandatory_depends_on": "discount"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "Percentage",
|
||||||
|
"fetch_from": "payment_term.discount_type",
|
||||||
|
"fieldname": "discount_type",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"label": "Discount Type",
|
||||||
|
"options": "Percentage\nAmount"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fetch_from": "payment_term.discount",
|
||||||
|
"fieldname": "discount",
|
||||||
|
"fieldtype": "Float",
|
||||||
|
"label": "Discount"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_9",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collapsible": 1,
|
||||||
|
"fieldname": "section_break_15",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Description"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_6",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_9",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_4",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-03-13 17:58:24.729526",
|
"modified": "2021-02-15 21:03:12.540546",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Payment Schedule",
|
"name": "Payment Schedule",
|
||||||
|
|||||||
@ -1,2 +1,22 @@
|
|||||||
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
// For license information, please see license.txt
|
// For license information, please see license.txt
|
||||||
|
frappe.ui.form.on('Payment Term', {
|
||||||
|
onload(frm) {
|
||||||
|
frm.trigger('set_dynamic_description');
|
||||||
|
},
|
||||||
|
discount(frm) {
|
||||||
|
frm.trigger('set_dynamic_description');
|
||||||
|
},
|
||||||
|
discount_type(frm) {
|
||||||
|
frm.trigger('set_dynamic_description');
|
||||||
|
},
|
||||||
|
set_dynamic_description(frm) {
|
||||||
|
if (frm.doc.discount) {
|
||||||
|
let description = __("{0}% of total invoice value will be given as discount.", [frm.doc.discount]);
|
||||||
|
if (frm.doc.discount_type == 'Amount') {
|
||||||
|
description = __("{0} will be given as discount.", [fmt_money(frm.doc.discount)]);
|
||||||
|
}
|
||||||
|
frm.set_df_property("discount", "description", description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
@ -1,386 +1,166 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"actions": [],
|
||||||
"allow_guest_to_view": 0,
|
"allow_import": 1,
|
||||||
"allow_import": 1,
|
"allow_rename": 1,
|
||||||
"allow_rename": 1,
|
"autoname": "field:payment_term_name",
|
||||||
"autoname": "field:payment_term_name",
|
"creation": "2017-08-10 15:24:54.876365",
|
||||||
"beta": 0,
|
"doctype": "DocType",
|
||||||
"creation": "2017-08-10 15:24:54.876365",
|
"editable_grid": 1,
|
||||||
"custom": 0,
|
"engine": "InnoDB",
|
||||||
"docstatus": 0,
|
"field_order": [
|
||||||
"doctype": "DocType",
|
"payment_term_name",
|
||||||
"document_type": "",
|
"invoice_portion",
|
||||||
"editable_grid": 1,
|
"mode_of_payment",
|
||||||
"engine": "InnoDB",
|
"column_break_3",
|
||||||
|
"due_date_based_on",
|
||||||
|
"credit_days",
|
||||||
|
"credit_months",
|
||||||
|
"section_break_8",
|
||||||
|
"discount_type",
|
||||||
|
"discount",
|
||||||
|
"column_break_11",
|
||||||
|
"discount_validity_based_on",
|
||||||
|
"discount_validity",
|
||||||
|
"section_break_6",
|
||||||
|
"description"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"bold": 1,
|
||||||
"allow_on_submit": 0,
|
"fieldname": "payment_term_name",
|
||||||
"bold": 1,
|
"fieldtype": "Data",
|
||||||
"collapsible": 0,
|
"label": "Payment Term Name",
|
||||||
"columns": 0,
|
"unique": 1
|
||||||
"fieldname": "payment_term_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": "Payment Term Name",
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"description": "Provide the invoice portion in percent",
|
"bold": 1,
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "invoice_portion",
|
||||||
"allow_on_submit": 0,
|
"fieldtype": "Float",
|
||||||
"bold": 1,
|
"label": "Invoice Portion (%)"
|
||||||
"collapsible": 0,
|
},
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "invoice_portion",
|
|
||||||
"fieldtype": "Float",
|
|
||||||
"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": "Invoice Portion",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "mode_of_payment",
|
||||||
"allow_on_submit": 0,
|
"fieldtype": "Link",
|
||||||
"bold": 0,
|
"label": "Mode of Payment",
|
||||||
"collapsible": 0,
|
"options": "Mode of Payment"
|
||||||
"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
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "column_break_3",
|
||||||
"allow_on_submit": 0,
|
"fieldtype": "Column Break"
|
||||||
"bold": 0,
|
},
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_3",
|
|
||||||
"fieldtype": "Column Break",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"bold": 1,
|
||||||
"allow_on_submit": 0,
|
"fieldname": "due_date_based_on",
|
||||||
"bold": 1,
|
"fieldtype": "Select",
|
||||||
"collapsible": 0,
|
"label": "Due Date Based On",
|
||||||
"columns": 0,
|
"options": "Day(s) after invoice date\nDay(s) after the end of the invoice month\nMonth(s) after the end of the invoice month"
|
||||||
"fieldname": "due_date_based_on",
|
},
|
||||||
"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": "Due Date Based On",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Day(s) after invoice date\nDay(s) after the end of the invoice month\nMonth(s) after the end of the invoice month",
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"description": "Give number of days according to prior selection",
|
"bold": 1,
|
||||||
"allow_bulk_edit": 0,
|
"depends_on": "eval:in_list(['Day(s) after invoice date', 'Day(s) after the end of the invoice month'], doc.due_date_based_on)",
|
||||||
"allow_on_submit": 0,
|
"fieldname": "credit_days",
|
||||||
"bold": 1,
|
"fieldtype": "Int",
|
||||||
"collapsible": 0,
|
"label": "Credit Days"
|
||||||
"columns": 0,
|
},
|
||||||
"depends_on": "eval:in_list(['Day(s) after invoice date', 'Day(s) after the end of the invoice month'], doc.due_date_based_on)",
|
|
||||||
"fieldname": "credit_days",
|
|
||||||
"fieldtype": "Int",
|
|
||||||
"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": "Credit Days",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"depends_on": "eval:doc.due_date_based_on=='Month(s) after the end of the invoice month'",
|
||||||
"allow_on_submit": 0,
|
"fieldname": "credit_months",
|
||||||
"bold": 0,
|
"fieldtype": "Int",
|
||||||
"collapsible": 0,
|
"label": "Credit Months"
|
||||||
"columns": 0,
|
},
|
||||||
"depends_on": "eval:doc.due_date_based_on=='Month(s) after the end of the invoice month'",
|
|
||||||
"fieldname": "credit_months",
|
|
||||||
"fieldtype": "Int",
|
|
||||||
"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": "Credit Months",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "section_break_6",
|
||||||
"allow_on_submit": 0,
|
"fieldtype": "Section Break"
|
||||||
"bold": 0,
|
},
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "section_break_6",
|
|
||||||
"fieldtype": "Section Break",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"bold": 1,
|
||||||
"allow_on_submit": 0,
|
"fieldname": "description",
|
||||||
"bold": 1,
|
"fieldtype": "Small Text",
|
||||||
"collapsible": 0,
|
"label": "Description"
|
||||||
"columns": 0,
|
},
|
||||||
"fieldname": "description",
|
{
|
||||||
"fieldtype": "Small Text",
|
"fieldname": "section_break_8",
|
||||||
"hidden": 0,
|
"fieldtype": "Section Break",
|
||||||
"ignore_user_permissions": 0,
|
"label": "Discount Settings"
|
||||||
"ignore_xss_filter": 0,
|
},
|
||||||
"in_filter": 0,
|
{
|
||||||
"in_global_search": 0,
|
"default": "Percentage",
|
||||||
"in_list_view": 0,
|
"fieldname": "discount_type",
|
||||||
"in_standard_filter": 0,
|
"fieldtype": "Select",
|
||||||
"label": "Description",
|
"label": "Discount Type",
|
||||||
"length": 0,
|
"options": "Percentage\nAmount"
|
||||||
"no_copy": 0,
|
},
|
||||||
"permlevel": 0,
|
{
|
||||||
"precision": "",
|
"fieldname": "discount",
|
||||||
"print_hide": 0,
|
"fieldtype": "Float",
|
||||||
"print_hide_if_no_value": 0,
|
"label": "Discount"
|
||||||
"read_only": 0,
|
},
|
||||||
"remember_last_selected_value": 0,
|
{
|
||||||
"report_hide": 0,
|
"default": "Day(s) after invoice date",
|
||||||
"reqd": 0,
|
"depends_on": "discount",
|
||||||
"search_index": 0,
|
"fieldname": "discount_validity_based_on",
|
||||||
"set_only_once": 0,
|
"fieldtype": "Select",
|
||||||
"translatable": 0,
|
"label": "Discount Validity Based On",
|
||||||
"unique": 0
|
"options": "Day(s) after invoice date\nDay(s) after the end of the invoice month\nMonth(s) after the end of the invoice month"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "discount",
|
||||||
|
"fieldname": "discount_validity",
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"label": "Discount Validity",
|
||||||
|
"mandatory_depends_on": "discount"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_11",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
"links": [],
|
||||||
"hide_heading": 0,
|
"modified": "2021-02-15 20:30:56.256403",
|
||||||
"hide_toolbar": 0,
|
"modified_by": "Administrator",
|
||||||
"idx": 0,
|
"module": "Accounts",
|
||||||
"image_view": 0,
|
"name": "Payment Term",
|
||||||
"in_create": 0,
|
"owner": "Administrator",
|
||||||
"is_submittable": 0,
|
|
||||||
"issingle": 0,
|
|
||||||
"istable": 0,
|
|
||||||
"max_attachments": 0,
|
|
||||||
"modified": "2020-10-14 10:47:32.830478",
|
|
||||||
"modified_by": "Administrator",
|
|
||||||
"module": "Accounts",
|
|
||||||
"name": "Payment Term",
|
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
"amend": 0,
|
"create": 1,
|
||||||
"apply_user_permissions": 0,
|
"delete": 1,
|
||||||
"cancel": 0,
|
"email": 1,
|
||||||
"create": 1,
|
"export": 1,
|
||||||
"delete": 1,
|
"print": 1,
|
||||||
"email": 1,
|
"read": 1,
|
||||||
"export": 1,
|
"report": 1,
|
||||||
"if_owner": 0,
|
"role": "System Manager",
|
||||||
"import": 0,
|
"share": 1,
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
|
||||||
"read": 1,
|
|
||||||
"report": 1,
|
|
||||||
"role": "System Manager",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
"create": 1,
|
||||||
"apply_user_permissions": 0,
|
"delete": 1,
|
||||||
"cancel": 0,
|
"email": 1,
|
||||||
"create": 1,
|
"export": 1,
|
||||||
"delete": 1,
|
"print": 1,
|
||||||
"email": 1,
|
"read": 1,
|
||||||
"export": 1,
|
"report": 1,
|
||||||
"if_owner": 0,
|
"role": "Accounts Manager",
|
||||||
"import": 0,
|
"share": 1,
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
|
||||||
"read": 1,
|
|
||||||
"report": 1,
|
|
||||||
"role": "Accounts Manager",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
"create": 1,
|
||||||
"apply_user_permissions": 0,
|
"delete": 1,
|
||||||
"cancel": 0,
|
"email": 1,
|
||||||
"create": 1,
|
"export": 1,
|
||||||
"delete": 1,
|
"print": 1,
|
||||||
"email": 1,
|
"read": 1,
|
||||||
"export": 1,
|
"report": 1,
|
||||||
"if_owner": 0,
|
"role": "Accounts User",
|
||||||
"import": 0,
|
"share": 1,
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
|
||||||
"read": 1,
|
|
||||||
"report": 1,
|
|
||||||
"role": "Accounts User",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 1,
|
"quick_entry": 1,
|
||||||
"read_only": 0,
|
"sort_field": "modified",
|
||||||
"read_only_onload": 0,
|
"sort_order": "DESC",
|
||||||
"show_name_in_global_search": 0,
|
"track_changes": 1
|
||||||
"sort_field": "modified",
|
}
|
||||||
"sort_order": "DESC",
|
|
||||||
"track_changes": 1,
|
|
||||||
"track_seen": 0
|
|
||||||
}
|
|
||||||
@ -3,11 +3,6 @@
|
|||||||
|
|
||||||
frappe.ui.form.on('Payment Terms Template', {
|
frappe.ui.form.on('Payment Terms Template', {
|
||||||
setup: function(frm) {
|
setup: function(frm) {
|
||||||
frm.add_fetch("payment_term", "description", "description");
|
|
||||||
frm.add_fetch("payment_term", "invoice_portion", "invoice_portion");
|
|
||||||
frm.add_fetch("payment_term", "due_date_based_on", "due_date_based_on");
|
|
||||||
frm.add_fetch("payment_term", "credit_days", "credit_days");
|
|
||||||
frm.add_fetch("payment_term", "credit_months", "credit_months");
|
|
||||||
frm.add_fetch("payment_term", "mode_of_payment", "mode_of_payment");
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -13,7 +13,6 @@ from frappe import _
|
|||||||
class PaymentTermsTemplate(Document):
|
class PaymentTermsTemplate(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.validate_invoice_portion()
|
self.validate_invoice_portion()
|
||||||
self.validate_credit_days()
|
|
||||||
self.check_duplicate_terms()
|
self.check_duplicate_terms()
|
||||||
|
|
||||||
def validate_invoice_portion(self):
|
def validate_invoice_portion(self):
|
||||||
@ -24,11 +23,6 @@ class PaymentTermsTemplate(Document):
|
|||||||
if flt(total_portion, 2) != 100.00:
|
if flt(total_portion, 2) != 100.00:
|
||||||
frappe.msgprint(_('Combined invoice portion must equal 100%'), raise_exception=1, indicator='red')
|
frappe.msgprint(_('Combined invoice portion must equal 100%'), raise_exception=1, indicator='red')
|
||||||
|
|
||||||
def validate_credit_days(self):
|
|
||||||
for term in self.terms:
|
|
||||||
if cint(term.credit_days) < 0:
|
|
||||||
frappe.msgprint(_('Credit Days cannot be a negative number'), raise_exception=1, indicator='red')
|
|
||||||
|
|
||||||
def check_duplicate_terms(self):
|
def check_duplicate_terms(self):
|
||||||
terms = []
|
terms = []
|
||||||
for term in self.terms:
|
for term in self.terms:
|
||||||
|
|||||||
@ -1,278 +1,164 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"actions": [],
|
||||||
"allow_guest_to_view": 0,
|
"creation": "2017-08-10 15:34:09.409562",
|
||||||
"allow_import": 0,
|
"doctype": "DocType",
|
||||||
"allow_rename": 0,
|
"editable_grid": 1,
|
||||||
"autoname": "",
|
"engine": "InnoDB",
|
||||||
"beta": 0,
|
"field_order": [
|
||||||
"creation": "2017-08-10 15:34:09.409562",
|
"payment_term",
|
||||||
"custom": 0,
|
"section_break_13",
|
||||||
"docstatus": 0,
|
"description",
|
||||||
"doctype": "DocType",
|
"section_break_4",
|
||||||
"document_type": "",
|
"invoice_portion",
|
||||||
"editable_grid": 1,
|
"mode_of_payment",
|
||||||
"engine": "InnoDB",
|
"column_break_3",
|
||||||
|
"due_date_based_on",
|
||||||
|
"credit_days",
|
||||||
|
"credit_months",
|
||||||
|
"section_break_8",
|
||||||
|
"discount_type",
|
||||||
|
"discount",
|
||||||
|
"column_break_11",
|
||||||
|
"discount_validity_based_on",
|
||||||
|
"discount_validity"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"columns": 2,
|
||||||
"allow_in_quick_entry": 0,
|
"fieldname": "payment_term",
|
||||||
"allow_on_submit": 0,
|
"fieldtype": "Link",
|
||||||
"bold": 0,
|
"in_list_view": 1,
|
||||||
"collapsible": 0,
|
"label": "Payment Term",
|
||||||
"columns": 2,
|
"options": "Payment Term"
|
||||||
"fieldname": "payment_term",
|
},
|
||||||
"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": "Payment Term",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Payment Term",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"columns": 2,
|
||||||
"allow_in_quick_entry": 0,
|
"fetch_from": "payment_term.description",
|
||||||
"allow_on_submit": 0,
|
"fieldname": "description",
|
||||||
"bold": 0,
|
"fieldtype": "Small Text",
|
||||||
"collapsible": 0,
|
"in_list_view": 1,
|
||||||
"columns": 2,
|
"label": "Description"
|
||||||
"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,
|
|
||||||
"options": "",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"columns": 2,
|
||||||
"allow_in_quick_entry": 0,
|
"fetch_from": "payment_term.invoice_portion",
|
||||||
"allow_on_submit": 0,
|
"fetch_if_empty": 1,
|
||||||
"bold": 0,
|
"fieldname": "invoice_portion",
|
||||||
"collapsible": 0,
|
"fieldtype": "Float",
|
||||||
"columns": 2,
|
"in_list_view": 1,
|
||||||
"default": "0",
|
"label": "Invoice Portion (%)",
|
||||||
"fieldname": "invoice_portion",
|
"reqd": 1
|
||||||
"fieldtype": "Percent",
|
},
|
||||||
"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": "Invoice Portion",
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"columns": 2,
|
||||||
"allow_in_quick_entry": 0,
|
"fetch_from": "payment_term.due_date_based_on",
|
||||||
"allow_on_submit": 0,
|
"fetch_if_empty": 1,
|
||||||
"bold": 0,
|
"fieldname": "due_date_based_on",
|
||||||
"collapsible": 0,
|
"fieldtype": "Select",
|
||||||
"columns": 2,
|
"in_list_view": 1,
|
||||||
"fieldname": "due_date_based_on",
|
"label": "Due Date Based On",
|
||||||
"fieldtype": "Select",
|
"options": "Day(s) after invoice date\nDay(s) after the end of the invoice month\nMonth(s) after the end of the invoice month",
|
||||||
"hidden": 0,
|
"reqd": 1
|
||||||
"ignore_user_permissions": 0,
|
},
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Due Date Based On",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Day(s) after invoice date\nDay(s) after the end of the invoice month\nMonth(s) after the end of the invoice month",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"columns": 2,
|
||||||
"allow_in_quick_entry": 0,
|
"default": "0",
|
||||||
"allow_on_submit": 0,
|
"depends_on": "eval:in_list(['Day(s) after invoice date', 'Day(s) after the end of the invoice month'], doc.due_date_based_on)",
|
||||||
"bold": 0,
|
"fetch_from": "payment_term.credit_days",
|
||||||
"collapsible": 0,
|
"fetch_if_empty": 1,
|
||||||
"columns": 2,
|
"fieldname": "credit_days",
|
||||||
"default": "0",
|
"fieldtype": "Int",
|
||||||
"depends_on": "eval:in_list(['Day(s) after invoice date', 'Day(s) after the end of the invoice month'], doc.due_date_based_on)",
|
"in_list_view": 1,
|
||||||
"fieldname": "credit_days",
|
"label": "Credit Days",
|
||||||
"fieldtype": "Int",
|
"non_negative": 1
|
||||||
"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": "Credit Days",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"default": "0",
|
||||||
"allow_in_quick_entry": 0,
|
"depends_on": "eval:doc.due_date_based_on=='Month(s) after the end of the invoice month'",
|
||||||
"allow_on_submit": 0,
|
"fetch_from": "payment_term.credit_months",
|
||||||
"bold": 0,
|
"fetch_if_empty": 1,
|
||||||
"collapsible": 0,
|
"fieldname": "credit_months",
|
||||||
"columns": 0,
|
"fieldtype": "Int",
|
||||||
"default": "0",
|
"label": "Credit Months",
|
||||||
"depends_on": "eval:doc.due_date_based_on=='Month(s) after the end of the invoice month'",
|
"non_negative": 1
|
||||||
"fieldname": "credit_months",
|
},
|
||||||
"fieldtype": "Int",
|
|
||||||
"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": "Credit Months",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fetch_from": "payment_term.mode_of_payment",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldname": "mode_of_payment",
|
||||||
"allow_on_submit": 0,
|
"fieldtype": "Link",
|
||||||
"bold": 0,
|
"label": "Mode of Payment",
|
||||||
"collapsible": 0,
|
"options": "Mode of Payment"
|
||||||
"columns": 0,
|
},
|
||||||
"fieldname": "mode_of_payment",
|
{
|
||||||
"fieldtype": "Link",
|
"fieldname": "column_break_3",
|
||||||
"hidden": 0,
|
"fieldtype": "Column Break"
|
||||||
"ignore_user_permissions": 0,
|
},
|
||||||
"ignore_xss_filter": 0,
|
{
|
||||||
"in_filter": 0,
|
"fieldname": "section_break_8",
|
||||||
"in_global_search": 0,
|
"fieldtype": "Section Break",
|
||||||
"in_list_view": 0,
|
"label": "Discount Settings"
|
||||||
"in_standard_filter": 0,
|
},
|
||||||
"label": "Mode of Payment",
|
{
|
||||||
"length": 0,
|
"default": "Percentage",
|
||||||
"no_copy": 0,
|
"fetch_from": "payment_term.discount_type",
|
||||||
"options": "Mode of Payment",
|
"fetch_if_empty": 1,
|
||||||
"permlevel": 0,
|
"fieldname": "discount_type",
|
||||||
"precision": "",
|
"fieldtype": "Select",
|
||||||
"print_hide": 0,
|
"label": "Discount Type",
|
||||||
"print_hide_if_no_value": 0,
|
"options": "Percentage\nAmount"
|
||||||
"read_only": 0,
|
},
|
||||||
"remember_last_selected_value": 0,
|
{
|
||||||
"report_hide": 0,
|
"fetch_from": "payment_term.discount",
|
||||||
"reqd": 0,
|
"fetch_if_empty": 1,
|
||||||
"search_index": 0,
|
"fieldname": "discount",
|
||||||
"set_only_once": 0,
|
"fieldtype": "Float",
|
||||||
"translatable": 0,
|
"label": "Discount"
|
||||||
"unique": 0
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_11",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "Day(s) after invoice date",
|
||||||
|
"depends_on": "discount",
|
||||||
|
"fetch_from": "payment_term.discount_validity_based_on",
|
||||||
|
"fetch_if_empty": 1,
|
||||||
|
"fieldname": "discount_validity_based_on",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"label": "Discount Validity Based On",
|
||||||
|
"options": "Day(s) after invoice date\nDay(s) after the end of the invoice month\nMonth(s) after the end of the invoice month"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collapsible": 1,
|
||||||
|
"fieldname": "section_break_13",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Description"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "discount",
|
||||||
|
"fetch_from": "payment_term.discount_validity",
|
||||||
|
"fetch_if_empty": 1,
|
||||||
|
"fieldname": "discount_validity",
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"label": "Discount Validity",
|
||||||
|
"mandatory_depends_on": "discount"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_4",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
"index_web_pages_for_search": 1,
|
||||||
"hide_heading": 0,
|
"istable": 1,
|
||||||
"hide_toolbar": 0,
|
"links": [],
|
||||||
"idx": 0,
|
"modified": "2021-02-24 11:56:12.410807",
|
||||||
"image_view": 0,
|
"modified_by": "Administrator",
|
||||||
"in_create": 0,
|
"module": "Accounts",
|
||||||
"is_submittable": 0,
|
"name": "Payment Terms Template Detail",
|
||||||
"issingle": 0,
|
"owner": "Administrator",
|
||||||
"istable": 1,
|
"permissions": [],
|
||||||
"max_attachments": 0,
|
"quick_entry": 1,
|
||||||
"modified": "2018-08-21 16:15:55.143025",
|
"sort_field": "modified",
|
||||||
"modified_by": "Administrator",
|
"sort_order": "DESC",
|
||||||
"module": "Accounts",
|
"track_changes": 1
|
||||||
"name": "Payment Terms Template Detail",
|
|
||||||
"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,
|
|
||||||
"track_views": 0
|
|
||||||
}
|
}
|
||||||
@ -20,15 +20,16 @@ class POSOpeningEntry(StatusUpdater):
|
|||||||
|
|
||||||
if not cint(frappe.db.get_value("User", self.user, "enabled")):
|
if not cint(frappe.db.get_value("User", self.user, "enabled")):
|
||||||
frappe.throw(_("User {} is disabled. Please select valid user/cashier").format(self.user))
|
frappe.throw(_("User {} is disabled. Please select valid user/cashier").format(self.user))
|
||||||
|
|
||||||
def validate_payment_method_account(self):
|
def validate_payment_method_account(self):
|
||||||
invalid_modes = []
|
invalid_modes = []
|
||||||
for d in self.balance_details:
|
for d in self.balance_details:
|
||||||
account = frappe.db.get_value("Mode of Payment Account",
|
if d.mode_of_payment:
|
||||||
{"parent": d.mode_of_payment, "company": self.company}, "default_account")
|
account = frappe.db.get_value("Mode of Payment Account",
|
||||||
if not account:
|
{"parent": d.mode_of_payment, "company": self.company}, "default_account")
|
||||||
invalid_modes.append(get_link_to_form("Mode of Payment", d.mode_of_payment))
|
if not account:
|
||||||
|
invalid_modes.append(get_link_to_form("Mode of Payment", d.mode_of_payment))
|
||||||
|
|
||||||
if invalid_modes:
|
if invalid_modes:
|
||||||
if invalid_modes == 1:
|
if invalid_modes == 1:
|
||||||
msg = _("Please set default Cash or Bank account in Mode of Payment {}")
|
msg = _("Please set default Cash or Bank account in Mode of Payment {}")
|
||||||
|
|||||||
@ -44,6 +44,14 @@
|
|||||||
"column_break_21",
|
"column_break_21",
|
||||||
"min_amt",
|
"min_amt",
|
||||||
"max_amt",
|
"max_amt",
|
||||||
|
"product_discount_scheme_section",
|
||||||
|
"same_item",
|
||||||
|
"free_item",
|
||||||
|
"free_qty",
|
||||||
|
"free_item_rate",
|
||||||
|
"column_break_42",
|
||||||
|
"free_item_uom",
|
||||||
|
"is_recursive",
|
||||||
"section_break_23",
|
"section_break_23",
|
||||||
"valid_from",
|
"valid_from",
|
||||||
"valid_upto",
|
"valid_upto",
|
||||||
@ -62,13 +70,6 @@
|
|||||||
"discount_amount",
|
"discount_amount",
|
||||||
"discount_percentage",
|
"discount_percentage",
|
||||||
"for_price_list",
|
"for_price_list",
|
||||||
"product_discount_scheme_section",
|
|
||||||
"same_item",
|
|
||||||
"free_item",
|
|
||||||
"free_qty",
|
|
||||||
"column_break_51",
|
|
||||||
"free_item_uom",
|
|
||||||
"free_item_rate",
|
|
||||||
"section_break_13",
|
"section_break_13",
|
||||||
"threshold_percentage",
|
"threshold_percentage",
|
||||||
"priority",
|
"priority",
|
||||||
@ -458,10 +459,6 @@
|
|||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"label": "Qty"
|
"label": "Qty"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "column_break_51",
|
|
||||||
"fieldtype": "Column Break"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"fieldname": "free_item_uom",
|
"fieldname": "free_item_uom",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
@ -552,19 +549,33 @@
|
|||||||
"fieldname": "promotional_scheme",
|
"fieldname": "promotional_scheme",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Promotional Scheme",
|
"label": "Promotional Scheme",
|
||||||
"options": "Promotional Scheme"
|
"no_copy": 1,
|
||||||
|
"options": "Promotional Scheme",
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Simple Python Expression, Example: territory != 'All Territories'",
|
"description": "Simple Python Expression, Example: territory != 'All Territories'",
|
||||||
"fieldname": "condition",
|
"fieldname": "condition",
|
||||||
"fieldtype": "Code",
|
"fieldtype": "Code",
|
||||||
"label": "Condition"
|
"label": "Condition"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_42",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"description": "Discounts to be applied in sequential ranges like buy 1 get 1, buy 2 get 2, buy 3 get 3 and so on",
|
||||||
|
"fieldname": "is_recursive",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Is Recursive"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-gift",
|
"icon": "fa fa-gift",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-03-01 23:18:38.717613",
|
"modified": "2021-03-06 22:01:24.840422",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Pricing Rule",
|
"name": "Pricing Rule",
|
||||||
|
|||||||
@ -237,6 +237,7 @@ def get_pricing_rule_for_item(args, price_list_rate=0, doc=None, for_validate=Fa
|
|||||||
"doctype": args.doctype,
|
"doctype": args.doctype,
|
||||||
"has_margin": False,
|
"has_margin": False,
|
||||||
"name": args.name,
|
"name": args.name,
|
||||||
|
"free_item_data": [],
|
||||||
"parent": args.parent,
|
"parent": args.parent,
|
||||||
"parenttype": args.parenttype,
|
"parenttype": args.parenttype,
|
||||||
"child_docname": args.get('child_docname')
|
"child_docname": args.get('child_docname')
|
||||||
|
|||||||
@ -328,6 +328,21 @@ class TestPricingRule(unittest.TestCase):
|
|||||||
self.assertEquals(item.discount_amount, 110)
|
self.assertEquals(item.discount_amount, 110)
|
||||||
self.assertEquals(item.rate, 990)
|
self.assertEquals(item.rate, 990)
|
||||||
|
|
||||||
|
def test_pricing_rule_with_margin_and_discount_amount(self):
|
||||||
|
frappe.delete_doc_if_exists('Pricing Rule', '_Test Pricing Rule')
|
||||||
|
make_pricing_rule(selling=1, margin_type="Percentage", margin_rate_or_amount=10,
|
||||||
|
rate_or_discount="Discount Amount", discount_amount=110)
|
||||||
|
si = create_sales_invoice(do_not_save=True)
|
||||||
|
si.items[0].price_list_rate = 1000
|
||||||
|
si.payment_schedule = []
|
||||||
|
si.insert(ignore_permissions=True)
|
||||||
|
|
||||||
|
item = si.items[0]
|
||||||
|
self.assertEquals(item.margin_rate_or_amount, 10)
|
||||||
|
self.assertEquals(item.rate_with_margin, 1100)
|
||||||
|
self.assertEquals(item.discount_amount, 110)
|
||||||
|
self.assertEquals(item.rate, 990)
|
||||||
|
|
||||||
def test_pricing_rule_for_product_discount_on_same_item(self):
|
def test_pricing_rule_for_product_discount_on_same_item(self):
|
||||||
frappe.delete_doc_if_exists('Pricing Rule', '_Test Pricing Rule')
|
frappe.delete_doc_if_exists('Pricing Rule', '_Test Pricing Rule')
|
||||||
test_record = {
|
test_record = {
|
||||||
@ -560,6 +575,7 @@ def make_pricing_rule(**args):
|
|||||||
"margin_rate_or_amount": args.margin_rate_or_amount or 0.0,
|
"margin_rate_or_amount": args.margin_rate_or_amount or 0.0,
|
||||||
"condition": args.condition or '',
|
"condition": args.condition or '',
|
||||||
"priority": 1,
|
"priority": 1,
|
||||||
|
"discount_amount": args.discount_amount or 0.0,
|
||||||
"apply_multiple_pricing_rules": args.apply_multiple_pricing_rules or 0
|
"apply_multiple_pricing_rules": args.apply_multiple_pricing_rules or 0
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -367,7 +367,7 @@ def get_qty_and_rate_for_mixed_conditions(doc, pr_doc, args):
|
|||||||
|
|
||||||
if items and doc.get("items"):
|
if items and doc.get("items"):
|
||||||
for row in doc.get('items'):
|
for row in doc.get('items'):
|
||||||
if row.get(apply_on) not in items: continue
|
if (row.get(apply_on) or args.get(apply_on)) not in items: continue
|
||||||
|
|
||||||
if pr_doc.mixed_conditions:
|
if pr_doc.mixed_conditions:
|
||||||
amt = args.get('qty') * args.get("price_list_rate")
|
amt = args.get('qty') * args.get("price_list_rate")
|
||||||
@ -479,7 +479,7 @@ def apply_pricing_rule_on_transaction(doc):
|
|||||||
|
|
||||||
doc.calculate_taxes_and_totals()
|
doc.calculate_taxes_and_totals()
|
||||||
elif d.price_or_product_discount == 'Product':
|
elif d.price_or_product_discount == 'Product':
|
||||||
item_details = frappe._dict({'parenttype': doc.doctype})
|
item_details = frappe._dict({'parenttype': doc.doctype, 'free_item_data': []})
|
||||||
get_product_discount_rule(d, item_details, doc=doc)
|
get_product_discount_rule(d, item_details, doc=doc)
|
||||||
apply_pricing_rule_for_free_items(doc, item_details.free_item_data)
|
apply_pricing_rule_for_free_items(doc, item_details.free_item_data)
|
||||||
doc.set_missing_values()
|
doc.set_missing_values()
|
||||||
@ -508,9 +508,16 @@ def get_product_discount_rule(pricing_rule, item_details, args=None, doc=None):
|
|||||||
frappe.throw(_("Free item not set in the pricing rule {0}")
|
frappe.throw(_("Free item not set in the pricing rule {0}")
|
||||||
.format(get_link_to_form("Pricing Rule", pricing_rule.name)))
|
.format(get_link_to_form("Pricing Rule", pricing_rule.name)))
|
||||||
|
|
||||||
item_details.free_item_data = {
|
qty = pricing_rule.free_qty or 1
|
||||||
|
if pricing_rule.is_recursive:
|
||||||
|
transaction_qty = args.get('qty') if args else doc.total_qty
|
||||||
|
if transaction_qty:
|
||||||
|
qty = flt(transaction_qty) * qty
|
||||||
|
|
||||||
|
free_item_data_args = {
|
||||||
'item_code': free_item,
|
'item_code': free_item,
|
||||||
'qty': pricing_rule.free_qty or 1,
|
'qty': qty,
|
||||||
|
'pricing_rules': pricing_rule.name,
|
||||||
'rate': pricing_rule.free_item_rate or 0,
|
'rate': pricing_rule.free_item_rate or 0,
|
||||||
'price_list_rate': pricing_rule.free_item_rate or 0,
|
'price_list_rate': pricing_rule.free_item_rate or 0,
|
||||||
'is_free_item': 1
|
'is_free_item': 1
|
||||||
@ -519,24 +526,26 @@ def get_product_discount_rule(pricing_rule, item_details, args=None, doc=None):
|
|||||||
item_data = frappe.get_cached_value('Item', free_item, ['item_name',
|
item_data = frappe.get_cached_value('Item', free_item, ['item_name',
|
||||||
'description', 'stock_uom'], as_dict=1)
|
'description', 'stock_uom'], as_dict=1)
|
||||||
|
|
||||||
item_details.free_item_data.update(item_data)
|
free_item_data_args.update(item_data)
|
||||||
item_details.free_item_data['uom'] = pricing_rule.free_item_uom or item_data.stock_uom
|
free_item_data_args['uom'] = pricing_rule.free_item_uom or item_data.stock_uom
|
||||||
item_details.free_item_data['conversion_factor'] = get_conversion_factor(free_item,
|
free_item_data_args['conversion_factor'] = get_conversion_factor(free_item,
|
||||||
item_details.free_item_data['uom']).get("conversion_factor", 1)
|
free_item_data_args['uom']).get("conversion_factor", 1)
|
||||||
|
|
||||||
if item_details.get("parenttype") == 'Purchase Order':
|
if item_details.get("parenttype") == 'Purchase Order':
|
||||||
item_details.free_item_data['schedule_date'] = doc.schedule_date if doc else today()
|
free_item_data_args['schedule_date'] = doc.schedule_date if doc else today()
|
||||||
|
|
||||||
if item_details.get("parenttype") == 'Sales Order':
|
if item_details.get("parenttype") == 'Sales Order':
|
||||||
item_details.free_item_data['delivery_date'] = doc.delivery_date if doc else today()
|
free_item_data_args['delivery_date'] = doc.delivery_date if doc else today()
|
||||||
|
|
||||||
|
item_details.free_item_data.append(free_item_data_args)
|
||||||
|
|
||||||
def apply_pricing_rule_for_free_items(doc, pricing_rule_args, set_missing_values=False):
|
def apply_pricing_rule_for_free_items(doc, pricing_rule_args, set_missing_values=False):
|
||||||
if pricing_rule_args.get('item_code'):
|
if pricing_rule_args:
|
||||||
items = [d.item_code for d in doc.items
|
items = tuple([(d.item_code, d.pricing_rules) for d in doc.items if d.is_free_item])
|
||||||
if d.item_code == (pricing_rule_args.get("item_code")) and d.is_free_item]
|
|
||||||
|
|
||||||
if not items:
|
for args in pricing_rule_args:
|
||||||
doc.append('items', pricing_rule_args)
|
if not items or (args.get('item_code'), args.get('pricing_rules')) not in items:
|
||||||
|
doc.append('items', args)
|
||||||
|
|
||||||
def get_pricing_rule_items(pr_doc):
|
def get_pricing_rule_items(pr_doc):
|
||||||
apply_on_data = []
|
apply_on_data = []
|
||||||
|
|||||||
@ -12,16 +12,16 @@ from frappe.model.document import Document
|
|||||||
pricing_rule_fields = ['apply_on', 'mixed_conditions', 'is_cumulative', 'other_item_code', 'other_item_group'
|
pricing_rule_fields = ['apply_on', 'mixed_conditions', 'is_cumulative', 'other_item_code', 'other_item_group'
|
||||||
'apply_rule_on_other', 'other_brand', 'selling', 'buying', 'applicable_for', 'valid_from',
|
'apply_rule_on_other', 'other_brand', 'selling', 'buying', 'applicable_for', 'valid_from',
|
||||||
'valid_upto', 'customer', 'customer_group', 'territory', 'sales_partner', 'campaign', 'supplier',
|
'valid_upto', 'customer', 'customer_group', 'territory', 'sales_partner', 'campaign', 'supplier',
|
||||||
'supplier_group', 'company', 'currency']
|
'supplier_group', 'company', 'currency', 'apply_multiple_pricing_rules']
|
||||||
|
|
||||||
other_fields = ['min_qty', 'max_qty', 'min_amt',
|
other_fields = ['min_qty', 'max_qty', 'min_amt',
|
||||||
'max_amt', 'priority','warehouse', 'threshold_percentage', 'rule_description']
|
'max_amt', 'priority','warehouse', 'threshold_percentage', 'rule_description']
|
||||||
|
|
||||||
price_discount_fields = ['rate_or_discount', 'apply_discount_on', 'apply_discount_on_rate',
|
price_discount_fields = ['rate_or_discount', 'apply_discount_on', 'apply_discount_on_rate',
|
||||||
'rate', 'discount_amount', 'discount_percentage', 'validate_applied_rule']
|
'rate', 'discount_amount', 'discount_percentage', 'validate_applied_rule', 'apply_multiple_pricing_rules']
|
||||||
|
|
||||||
product_discount_fields = ['free_item', 'free_qty', 'free_item_uom',
|
product_discount_fields = ['free_item', 'free_qty', 'free_item_uom',
|
||||||
'free_item_rate', 'same_item']
|
'free_item_rate', 'same_item', 'is_recursive', 'apply_multiple_pricing_rules']
|
||||||
|
|
||||||
class PromotionalScheme(Document):
|
class PromotionalScheme(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
|||||||
@ -1,792 +1,181 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"actions": [],
|
||||||
"allow_events_in_timeline": 0,
|
|
||||||
"allow_guest_to_view": 0,
|
|
||||||
"allow_import": 0,
|
|
||||||
"allow_rename": 0,
|
|
||||||
"beta": 0,
|
|
||||||
"creation": "2019-03-24 14:48:59.649168",
|
"creation": "2019-03-24 14:48:59.649168",
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "",
|
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"disable",
|
||||||
|
"apply_multiple_pricing_rules",
|
||||||
|
"column_break_2",
|
||||||
|
"rule_description",
|
||||||
|
"section_break_2",
|
||||||
|
"min_qty",
|
||||||
|
"max_qty",
|
||||||
|
"column_break_3",
|
||||||
|
"min_amount",
|
||||||
|
"max_amount",
|
||||||
|
"section_break_6",
|
||||||
|
"rate_or_discount",
|
||||||
|
"column_break_10",
|
||||||
|
"rate",
|
||||||
|
"discount_amount",
|
||||||
|
"discount_percentage",
|
||||||
|
"section_break_11",
|
||||||
|
"warehouse",
|
||||||
|
"threshold_percentage",
|
||||||
|
"validate_applied_rule",
|
||||||
|
"column_break_14",
|
||||||
|
"priority",
|
||||||
|
"apply_discount_on_rate"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"default": "0",
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "disable",
|
"fieldname": "disable",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"label": "Disable"
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Disable",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_2",
|
"fieldname": "column_break_2",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "rule_description",
|
"fieldname": "rule_description",
|
||||||
"fieldtype": "Small Text",
|
"fieldtype": "Small Text",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Rule Description",
|
"label": "Rule Description",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "section_break_2",
|
"fieldname": "section_break_2",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 1,
|
"columns": 1,
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"fieldname": "min_qty",
|
"fieldname": "min_qty",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
"label": "Min Qty"
|
||||||
"label": "Min Qty",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 1,
|
"columns": 1,
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"fieldname": "max_qty",
|
"fieldname": "max_qty",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
"label": "Max Qty"
|
||||||
"label": "Max Qty",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_3",
|
"fieldname": "column_break_3",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"fieldname": "min_amount",
|
"fieldname": "min_amount",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
"label": "Min Amount"
|
||||||
"label": "Min Amount",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"depends_on": "",
|
|
||||||
"fieldname": "max_amount",
|
"fieldname": "max_amount",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
"label": "Max Amount"
|
||||||
"label": "Max Amount",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"depends_on": "",
|
|
||||||
"fieldname": "section_break_6",
|
"fieldname": "section_break_6",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"default": "Discount Percentage",
|
"default": "Discount Percentage",
|
||||||
"depends_on": "",
|
|
||||||
"fieldname": "rate_or_discount",
|
"fieldname": "rate_or_discount",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Discount Type",
|
"label": "Discount Type",
|
||||||
"length": 0,
|
"options": "\nRate\nDiscount Percentage\nDiscount Amount"
|
||||||
"no_copy": 0,
|
|
||||||
"options": "\nRate\nDiscount Percentage\nDiscount Amount",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"depends_on": "",
|
|
||||||
"fieldname": "column_break_10",
|
"fieldname": "column_break_10",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 2,
|
"columns": 2,
|
||||||
"depends_on": "eval:doc.rate_or_discount==\"Rate\"",
|
"depends_on": "eval:doc.rate_or_discount==\"Rate\"",
|
||||||
"fieldname": "rate",
|
"fieldname": "rate",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
"label": "Rate"
|
||||||
"label": "Rate",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"depends_on": "eval:doc.rate_or_discount==\"Discount Amount\"",
|
"depends_on": "eval:doc.rate_or_discount==\"Discount Amount\"",
|
||||||
"fieldname": "discount_amount",
|
"fieldname": "discount_amount",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"hidden": 0,
|
"label": "Discount Amount"
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Discount Amount",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"depends_on": "eval:doc.rate_or_discount==\"Discount Percentage\"",
|
"depends_on": "eval:doc.rate_or_discount==\"Discount Percentage\"",
|
||||||
"fieldname": "discount_percentage",
|
"fieldname": "discount_percentage",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"hidden": 0,
|
"label": "Discount Percentage"
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Discount Percentage",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "section_break_11",
|
"fieldname": "section_break_11",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "warehouse",
|
"fieldname": "warehouse",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Warehouse",
|
"label": "Warehouse",
|
||||||
"length": 0,
|
"options": "Warehouse"
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Warehouse",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "threshold_percentage",
|
"fieldname": "threshold_percentage",
|
||||||
"fieldtype": "Percent",
|
"fieldtype": "Percent",
|
||||||
"hidden": 0,
|
"label": "Threshold for Suggestion"
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Threshold for Suggestion",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"default": "1",
|
"default": "1",
|
||||||
"fieldname": "validate_applied_rule",
|
"fieldname": "validate_applied_rule",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"label": "Validate Applied Rule"
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Validate Applied Rule",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_14",
|
"fieldname": "column_break_14",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "priority",
|
"fieldname": "priority",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Priority",
|
"label": "Priority",
|
||||||
"length": 0,
|
"options": "\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20"
|
||||||
"no_copy": 0,
|
|
||||||
"options": "\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"default": "0",
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"depends_on": "priority",
|
"depends_on": "priority",
|
||||||
"fieldname": "apply_multiple_pricing_rules",
|
"fieldname": "apply_multiple_pricing_rules",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"label": "Apply Multiple Pricing Rules"
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Apply Multiple Pricing Rules",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"depends_on": "eval:in_list(['Discount Percentage', 'Discount Amount'], doc.rate_or_discount) && doc.apply_multiple_pricing_rules",
|
"depends_on": "eval:in_list(['Discount Percentage', 'Discount Amount'], doc.rate_or_discount) && doc.apply_multiple_pricing_rules",
|
||||||
"fieldname": "apply_discount_on_rate",
|
"fieldname": "apply_discount_on_rate",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"label": "Apply Discount on Rate"
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Apply Discount on Rate",
|
|
||||||
"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
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
"index_web_pages_for_search": 1,
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
|
||||||
"idx": 0,
|
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
|
||||||
"is_submittable": 0,
|
|
||||||
"issingle": 0,
|
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"max_attachments": 0,
|
"links": [],
|
||||||
"modified": "2019-03-24 14:48:59.649168",
|
"modified": "2021-03-07 11:56:23.424137",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Promotional Scheme Price Discount",
|
"name": "Promotional Scheme Price Discount",
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [],
|
"permissions": [],
|
||||||
"quick_entry": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 0,
|
|
||||||
"show_name_in_global_search": 0,
|
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC"
|
||||||
"track_changes": 0,
|
|
||||||
"track_seen": 0,
|
|
||||||
"track_views": 0
|
|
||||||
}
|
}
|
||||||
@ -1,10 +1,12 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"creation": "2019-03-24 14:48:59.649168",
|
"creation": "2019-03-24 14:48:59.649168",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
"field_order": [
|
"field_order": [
|
||||||
"disable",
|
"disable",
|
||||||
|
"apply_multiple_pricing_rules",
|
||||||
"column_break_2",
|
"column_break_2",
|
||||||
"rule_description",
|
"rule_description",
|
||||||
"section_break_1",
|
"section_break_1",
|
||||||
@ -25,7 +27,7 @@
|
|||||||
"threshold_percentage",
|
"threshold_percentage",
|
||||||
"column_break_15",
|
"column_break_15",
|
||||||
"priority",
|
"priority",
|
||||||
"apply_multiple_pricing_rules"
|
"is_recursive"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@ -152,10 +154,19 @@
|
|||||||
"fieldname": "apply_multiple_pricing_rules",
|
"fieldname": "apply_multiple_pricing_rules",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Apply Multiple Pricing Rules"
|
"label": "Apply Multiple Pricing Rules"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"description": "Discounts to be applied in sequential ranges like buy 1 get 1, buy 2 get 2, buy 3 get 3 and so on",
|
||||||
|
"fieldname": "is_recursive",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Is Recursive"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2019-07-21 00:00:56.674284",
|
"links": [],
|
||||||
|
"modified": "2021-03-06 21:58:18.162346",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Promotional Scheme Product Discount",
|
"name": "Promotional Scheme Product Discount",
|
||||||
|
|||||||
@ -524,7 +524,7 @@ frappe.ui.form.on("Purchase Invoice", {
|
|||||||
},
|
},
|
||||||
|
|
||||||
onload: function(frm) {
|
onload: function(frm) {
|
||||||
if(frm.doc.__onload) {
|
if(frm.doc.__onload && frm.is_new()) {
|
||||||
if(frm.doc.supplier) {
|
if(frm.doc.supplier) {
|
||||||
frm.doc.apply_tds = frm.doc.__onload.supplier_tds ? 1 : 0;
|
frm.doc.apply_tds = frm.doc.__onload.supplier_tds ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,6 +24,7 @@ from erpnext.accounts.deferred_revenue import validate_service_stop_date
|
|||||||
from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import get_party_tax_withholding_details
|
from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import get_party_tax_withholding_details
|
||||||
from frappe.model.utils import get_fetch_values
|
from frappe.model.utils import get_fetch_values
|
||||||
from frappe.contacts.doctype.address.address import get_address_display
|
from frappe.contacts.doctype.address.address import get_address_display
|
||||||
|
from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import get_party_tax_withholding_details
|
||||||
|
|
||||||
from erpnext.healthcare.utils import manage_invoice_submit_cancel
|
from erpnext.healthcare.utils import manage_invoice_submit_cancel
|
||||||
|
|
||||||
|
|||||||
@ -1166,10 +1166,12 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
|
|
||||||
def test_create_so_with_margin(self):
|
def test_create_so_with_margin(self):
|
||||||
si = create_sales_invoice(item_code="_Test Item", qty=1, do_not_submit=True)
|
si = create_sales_invoice(item_code="_Test Item", qty=1, do_not_submit=True)
|
||||||
price_list_rate = 100
|
price_list_rate = flt(100) * flt(si.plc_conversion_rate)
|
||||||
si.items[0].price_list_rate = price_list_rate
|
si.items[0].price_list_rate = price_list_rate
|
||||||
si.items[0].margin_type = 'Percentage'
|
si.items[0].margin_type = 'Percentage'
|
||||||
si.items[0].margin_rate_or_amount = 25
|
si.items[0].margin_rate_or_amount = 25
|
||||||
|
si.items[0].discount_amount = 0.0
|
||||||
|
si.items[0].discount_percentage = 0.0
|
||||||
si.save()
|
si.save()
|
||||||
self.assertEqual(si.get("items")[0].rate, flt((price_list_rate*25)/100 + price_list_rate))
|
self.assertEqual(si.get("items")[0].rate, flt((price_list_rate*25)/100 + price_list_rate))
|
||||||
|
|
||||||
|
|||||||
@ -364,7 +364,7 @@ class ReceivablePayableReport(object):
|
|||||||
payment_terms_details = frappe.db.sql("""
|
payment_terms_details = frappe.db.sql("""
|
||||||
select
|
select
|
||||||
si.name, si.party_account_currency, si.currency, si.conversion_rate,
|
si.name, si.party_account_currency, si.currency, si.conversion_rate,
|
||||||
ps.due_date, ps.payment_amount, ps.description, ps.paid_amount
|
ps.due_date, ps.payment_amount, ps.description, ps.paid_amount, ps.discounted_amount
|
||||||
from `tab{0}` si, `tabPayment Schedule` ps
|
from `tab{0}` si, `tabPayment Schedule` ps
|
||||||
where
|
where
|
||||||
si.name = ps.parent and
|
si.name = ps.parent and
|
||||||
@ -395,13 +395,13 @@ class ReceivablePayableReport(object):
|
|||||||
"invoiced": invoiced,
|
"invoiced": invoiced,
|
||||||
"invoice_grand_total": row.invoiced,
|
"invoice_grand_total": row.invoiced,
|
||||||
"payment_term": d.description,
|
"payment_term": d.description,
|
||||||
"paid": d.paid_amount,
|
"paid": d.paid_amount + d.discounted_amount,
|
||||||
"credit_note": 0.0,
|
"credit_note": 0.0,
|
||||||
"outstanding": invoiced - d.paid_amount
|
"outstanding": invoiced - d.paid_amount - d.discounted_amount
|
||||||
}))
|
}))
|
||||||
|
|
||||||
if d.paid_amount:
|
if d.paid_amount:
|
||||||
row['paid'] -= d.paid_amount
|
row['paid'] -= d.paid_amount + d.discounted_amount
|
||||||
|
|
||||||
def allocate_closing_to_term(self, row, term, key):
|
def allocate_closing_to_term(self, row, term, key):
|
||||||
if row[key]:
|
if row[key]:
|
||||||
|
|||||||
@ -51,7 +51,11 @@ def get_period_list(from_fiscal_year, to_fiscal_year, period_start_date, period_
|
|||||||
"from_date": start_date
|
"from_date": start_date
|
||||||
})
|
})
|
||||||
|
|
||||||
to_date = add_months(start_date, months_to_add)
|
if i==0 and filter_based_on == 'Date Range':
|
||||||
|
to_date = add_months(get_first_day(start_date), months_to_add)
|
||||||
|
else:
|
||||||
|
to_date = add_months(start_date, months_to_add)
|
||||||
|
|
||||||
start_date = to_date
|
start_date = to_date
|
||||||
|
|
||||||
# Subtract one day from to_date, as it may be first day in next fiscal year or month
|
# Subtract one day from to_date, as it may be first day in next fiscal year or month
|
||||||
|
|||||||
25
erpnext/change_log/v13/v13_0_0-beta_14.md
Normal file
25
erpnext/change_log/v13/v13_0_0-beta_14.md
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
## Version 13.0.0 Beta 14 Release Notes
|
||||||
|
### Fixes and Enhancements
|
||||||
|
|
||||||
|
- Repost incompleted backdated transactions ([#24991](https://github.com/frappe/erpnext/pull/24991))
|
||||||
|
- Revert stock balance value calculation ([#24957](https://github.com/frappe/erpnext/pull/24957))
|
||||||
|
- Allow user to update exchange rate in Multi-currency LCV ([#24947](https://github.com/frappe/erpnext/pull/24947))
|
||||||
|
- Added correct path in hooks ([#24865](https://github.com/frappe/erpnext/pull/24865))
|
||||||
|
- Unequal debit and credit issue on RCM Invoice ([#24838](https://github.com/frappe/erpnext/pull/24838))
|
||||||
|
- Period list for exponential smoothing forecasting report ([#24983](https://github.com/frappe/erpnext/pull/24983))
|
||||||
|
- POS Opening Entry with empty balance detail rows ([#24891](https://github.com/frappe/erpnext/pull/24891))
|
||||||
|
- Use account_name only in consolidated report ([#24840](https://github.com/frappe/erpnext/pull/24840))
|
||||||
|
- Validation of job card in stock entry ([#24882](https://github.com/frappe/erpnext/pull/24882))
|
||||||
|
- Added supplier warehouse field back again ([#24827](https://github.com/frappe/erpnext/pull/24827))
|
||||||
|
- Don't throw exception on invoice lines when there is no item_cod… ([#24864](https://github.com/frappe/erpnext/pull/24864))
|
||||||
|
- Incorrect Nil Exempt and Non GST amount in GSTR3B report ([#24918](https://github.com/frappe/erpnext/pull/24918))
|
||||||
|
- Payment References on adding Cost Center in PE and Report Issue Summary fix for V13 beta pre-release ([#24951](https://github.com/frappe/erpnext/pull/24951))
|
||||||
|
- TDS check getting checked after reload ([#24973](https://github.com/frappe/erpnext/pull/24973))
|
||||||
|
- Membership and Donation API fixes ([#24900](https://github.com/frappe/erpnext/pull/24900))
|
||||||
|
- Serial no trim issue ([#24981](https://github.com/frappe/erpnext/pull/24981))
|
||||||
|
- Add method for regional round off account back ([#24894](https://github.com/frappe/erpnext/pull/24894))
|
||||||
|
- Allow zero valuation in stock reconciliation ([#24985](https://github.com/frappe/erpnext/pull/24985))
|
||||||
|
- Simplified logic for additional salary ([#24907](https://github.com/frappe/erpnext/pull/24907))
|
||||||
|
- Allow to select item code in batch naming ([#24825](https://github.com/frappe/erpnext/pull/24825))
|
||||||
|
- 80G Certificates and Donations ([#24848](https://github.com/frappe/erpnext/pull/24848))
|
||||||
|
- Membership renewal validation (#24963) ([#24964](https://github.com/frappe/erpnext/pull/24964))
|
||||||
@ -26,7 +26,8 @@ from erpnext.controllers.print_settings import set_print_templates_for_item_tabl
|
|||||||
|
|
||||||
class AccountMissingError(frappe.ValidationError): pass
|
class AccountMissingError(frappe.ValidationError): pass
|
||||||
|
|
||||||
force_item_fields = ("item_group", "brand", "stock_uom", "is_fixed_asset", "item_tax_rate", "pricing_rules")
|
force_item_fields = ("item_group", "brand", "stock_uom", "is_fixed_asset", "item_tax_rate",
|
||||||
|
"pricing_rules", "weight_per_unit", "weight_uom", "total_weight")
|
||||||
|
|
||||||
class AccountsController(TransactionBase):
|
class AccountsController(TransactionBase):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@ -920,7 +921,8 @@ class AccountsController(TransactionBase):
|
|||||||
else:
|
else:
|
||||||
for d in self.get("payment_schedule"):
|
for d in self.get("payment_schedule"):
|
||||||
if d.invoice_portion:
|
if d.invoice_portion:
|
||||||
d.payment_amount = flt(grand_total * flt(d.invoice_portion) / 100, d.precision('payment_amount'))
|
d.payment_amount = flt(grand_total * flt(d.invoice_portion / 100), d.precision('payment_amount'))
|
||||||
|
d.outstanding = d.payment_amount
|
||||||
|
|
||||||
def set_due_date(self):
|
def set_due_date(self):
|
||||||
due_dates = [d.due_date for d in self.get("payment_schedule") if d.due_date]
|
due_dates = [d.due_date for d in self.get("payment_schedule") if d.due_date]
|
||||||
@ -1235,18 +1237,24 @@ def get_payment_term_details(term, posting_date=None, grand_total=None, bill_dat
|
|||||||
term_details.description = term.description
|
term_details.description = term.description
|
||||||
term_details.invoice_portion = term.invoice_portion
|
term_details.invoice_portion = term.invoice_portion
|
||||||
term_details.payment_amount = flt(term.invoice_portion) * flt(grand_total) / 100
|
term_details.payment_amount = flt(term.invoice_portion) * flt(grand_total) / 100
|
||||||
|
term_details.discount_type = term.discount_type
|
||||||
|
term_details.discount = term.discount
|
||||||
|
# term_details.discounted_amount = flt(grand_total) * (term.discount / 100) if term.discount_type == 'Percentage' else discount
|
||||||
|
term_details.outstanding = term_details.payment_amount
|
||||||
|
term_details.mode_of_payment = term.mode_of_payment
|
||||||
|
|
||||||
if bill_date:
|
if bill_date:
|
||||||
term_details.due_date = get_due_date(term, bill_date)
|
term_details.due_date = get_due_date(term, bill_date)
|
||||||
|
term_details.discount_date = get_discount_date(term, bill_date)
|
||||||
elif posting_date:
|
elif posting_date:
|
||||||
term_details.due_date = get_due_date(term, posting_date)
|
term_details.due_date = get_due_date(term, posting_date)
|
||||||
|
term_details.discount_date = get_discount_date(term, posting_date)
|
||||||
|
|
||||||
if getdate(term_details.due_date) < getdate(posting_date):
|
if getdate(term_details.due_date) < getdate(posting_date):
|
||||||
term_details.due_date = posting_date
|
term_details.due_date = posting_date
|
||||||
term_details.mode_of_payment = term.mode_of_payment
|
|
||||||
|
|
||||||
return term_details
|
return term_details
|
||||||
|
|
||||||
|
|
||||||
def get_due_date(term, posting_date=None, bill_date=None):
|
def get_due_date(term, posting_date=None, bill_date=None):
|
||||||
due_date = None
|
due_date = None
|
||||||
date = bill_date or posting_date
|
date = bill_date or posting_date
|
||||||
@ -1258,6 +1266,16 @@ def get_due_date(term, posting_date=None, bill_date=None):
|
|||||||
due_date = add_months(get_last_day(date), term.credit_months)
|
due_date = add_months(get_last_day(date), term.credit_months)
|
||||||
return due_date
|
return due_date
|
||||||
|
|
||||||
|
def get_discount_date(term, posting_date=None, bill_date=None):
|
||||||
|
discount_validity = None
|
||||||
|
date = bill_date or posting_date
|
||||||
|
if term.discount_validity_based_on == "Day(s) after invoice date":
|
||||||
|
discount_validity = add_days(date, term.discount_validity)
|
||||||
|
elif term.discount_validity_based_on == "Day(s) after the end of the invoice month":
|
||||||
|
discount_validity = add_days(get_last_day(date), term.discount_validity)
|
||||||
|
elif term.discount_validity_based_on == "Month(s) after the end of the invoice month":
|
||||||
|
discount_validity = add_months(get_last_day(date), term.discount_validity)
|
||||||
|
return discount_validity
|
||||||
|
|
||||||
def get_supplier_block_status(party_name):
|
def get_supplier_block_status(party_name):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -406,8 +406,7 @@ class StockController(AccountsController):
|
|||||||
def set_rate_of_stock_uom(self):
|
def set_rate_of_stock_uom(self):
|
||||||
if self.doctype in ["Purchase Receipt", "Purchase Invoice", "Purchase Order", "Sales Invoice", "Sales Order", "Delivery Note", "Quotation"]:
|
if self.doctype in ["Purchase Receipt", "Purchase Invoice", "Purchase Order", "Sales Invoice", "Sales Order", "Delivery Note", "Quotation"]:
|
||||||
for d in self.get("items"):
|
for d in self.get("items"):
|
||||||
if d.conversion_factor:
|
d.stock_uom_rate = d.rate / (d.conversion_factor or 1)
|
||||||
d.stock_uom_rate = d.rate / d.conversion_factor
|
|
||||||
|
|
||||||
def validate_internal_transfer(self):
|
def validate_internal_transfer(self):
|
||||||
if self.doctype in ('Sales Invoice', 'Delivery Note', 'Purchase Invoice', 'Purchase Receipt') \
|
if self.doctype in ('Sales Invoice', 'Delivery Note', 'Purchase Invoice', 'Purchase Receipt') \
|
||||||
|
|||||||
@ -113,7 +113,12 @@ class calculate_taxes_and_totals(object):
|
|||||||
item.rate_with_margin, item.base_rate_with_margin = self.calculate_margin(item)
|
item.rate_with_margin, item.base_rate_with_margin = self.calculate_margin(item)
|
||||||
if flt(item.rate_with_margin) > 0:
|
if flt(item.rate_with_margin) > 0:
|
||||||
item.rate = flt(item.rate_with_margin * (1.0 - (item.discount_percentage / 100.0)), item.precision("rate"))
|
item.rate = flt(item.rate_with_margin * (1.0 - (item.discount_percentage / 100.0)), item.precision("rate"))
|
||||||
item.discount_amount = item.rate_with_margin - item.rate
|
|
||||||
|
if item.discount_amount and not item.discount_percentage:
|
||||||
|
item.rate = item.rate_with_margin - item.discount_amount
|
||||||
|
else:
|
||||||
|
item.discount_amount = item.rate_with_margin - item.rate
|
||||||
|
|
||||||
elif flt(item.price_list_rate) > 0:
|
elif flt(item.price_list_rate) > 0:
|
||||||
item.discount_amount = item.price_list_rate - item.rate
|
item.discount_amount = item.price_list_rate - item.rate
|
||||||
elif flt(item.price_list_rate) > 0 and not item.discount_amount:
|
elif flt(item.price_list_rate) > 0 and not item.discount_amount:
|
||||||
@ -795,7 +800,7 @@ class init_landed_taxes_and_totals(object):
|
|||||||
for d in self.doc.get(self.tax_field):
|
for d in self.doc.get(self.tax_field):
|
||||||
if d.account_currency == company_currency:
|
if d.account_currency == company_currency:
|
||||||
d.exchange_rate = 1
|
d.exchange_rate = 1
|
||||||
elif not d.exchange_rate or d.exchange_rate == 1 or self.doc.posting_date:
|
elif not d.exchange_rate:
|
||||||
d.exchange_rate = get_exchange_rate(self.doc.posting_date, account=d.expense_account,
|
d.exchange_rate = get_exchange_rate(self.doc.posting_date, account=d.expense_account,
|
||||||
account_currency=d.account_currency, company=self.doc.company)
|
account_currency=d.account_currency, company=self.doc.company)
|
||||||
|
|
||||||
|
|||||||
@ -324,6 +324,7 @@ scheduler_events = {
|
|||||||
"erpnext.hr.doctype.shift_type.shift_type.process_auto_attendance_for_all_shifts",
|
"erpnext.hr.doctype.shift_type.shift_type.process_auto_attendance_for_all_shifts",
|
||||||
"erpnext.support.doctype.issue.issue.set_service_level_agreement_variance",
|
"erpnext.support.doctype.issue.issue.set_service_level_agreement_variance",
|
||||||
"erpnext.erpnext_integrations.connectors.shopify_connection.sync_old_orders",
|
"erpnext.erpnext_integrations.connectors.shopify_connection.sync_old_orders",
|
||||||
|
"erpnext.stock.doctype.repost_item_valuation.repost_item_valuation.repost_entries"
|
||||||
],
|
],
|
||||||
"daily": [
|
"daily": [
|
||||||
"erpnext.stock.reorder_item.reorder_item",
|
"erpnext.stock.reorder_item.reorder_item",
|
||||||
@ -361,13 +362,13 @@ scheduler_events = {
|
|||||||
"erpnext.hr.utils.generate_leave_encashment",
|
"erpnext.hr.utils.generate_leave_encashment",
|
||||||
"erpnext.hr.utils.allocate_earned_leaves",
|
"erpnext.hr.utils.allocate_earned_leaves",
|
||||||
"erpnext.hr.utils.grant_leaves_automatically",
|
"erpnext.hr.utils.grant_leaves_automatically",
|
||||||
"erpnext.loan_management.doctype.loan_security_shortfall.loan_security_shortfall.create_process_loan_security_shortfall",
|
"erpnext.loan_management.doctype.process_loan_security_shortfall.process_loan_security_shortfall.create_process_loan_security_shortfall",
|
||||||
"erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual.process_loan_interest_accrual_for_term_loans",
|
"erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual.process_loan_interest_accrual_for_term_loans",
|
||||||
"erpnext.crm.doctype.lead.lead.daily_open_lead"
|
"erpnext.crm.doctype.lead.lead.daily_open_lead"
|
||||||
],
|
],
|
||||||
"monthly_long": [
|
"monthly_long": [
|
||||||
"erpnext.accounts.deferred_revenue.process_deferred_accounting",
|
"erpnext.accounts.deferred_revenue.process_deferred_accounting",
|
||||||
"erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual.process_loan_interest_accrual_for_demand_loans"
|
"erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual.process_loan_interest_accrual_for_demand_loans"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -181,7 +181,6 @@
|
|||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "Company:company:default_currency",
|
|
||||||
"depends_on": "eval:(doc.docstatus==1 || doc.employee)",
|
"depends_on": "eval:(doc.docstatus==1 || doc.employee)",
|
||||||
"fieldname": "currency",
|
"fieldname": "currency",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
@ -201,7 +200,7 @@
|
|||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-11-25 12:01:55.980721",
|
"modified": "2021-03-31 21:31:53.746659",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Employee Advance",
|
"name": "Employee Advance",
|
||||||
|
|||||||
@ -130,7 +130,6 @@
|
|||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "Company:company:default_currency",
|
|
||||||
"depends_on": "eval:(doc.docstatus==1 || doc.employee)",
|
"depends_on": "eval:(doc.docstatus==1 || doc.employee)",
|
||||||
"fieldname": "currency",
|
"fieldname": "currency",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
@ -155,7 +154,7 @@
|
|||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-11-25 11:56:06.777241",
|
"modified": "2021-03-31 21:32:55.492327",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Leave Encashment",
|
"name": "Leave Encashment",
|
||||||
|
|||||||
@ -31,7 +31,7 @@ def get_columns():
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"fieldname": "job_opening",
|
"fieldname": "job_opening",
|
||||||
"options": "Job Opening",
|
"options": "Job Opening",
|
||||||
"width": 100
|
"width": 105
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": _("Job Applicant"),
|
"label": _("Job Applicant"),
|
||||||
@ -44,13 +44,13 @@ def get_columns():
|
|||||||
"label": _("Applicant name"),
|
"label": _("Applicant name"),
|
||||||
"fieldtype": "data",
|
"fieldtype": "data",
|
||||||
"fieldname": "applicant_name",
|
"fieldname": "applicant_name",
|
||||||
"width": 120
|
"width": 130
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": _("Application Status"),
|
"label": _("Application Status"),
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"fieldname": "application_status",
|
"fieldname": "application_status",
|
||||||
"width": 100
|
"width": 150
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": _("Job Offer"),
|
"label": _("Job Offer"),
|
||||||
@ -187,4 +187,4 @@ def get_job_offer(ja_list):
|
|||||||
else:
|
else:
|
||||||
ja_joff_map[offer.job_applicant].append(offer)
|
ja_joff_map[offer.job_applicant].append(offer)
|
||||||
|
|
||||||
return ja_joff_map
|
return ja_joff_map
|
||||||
|
|||||||
@ -255,6 +255,9 @@ class JobCard(Document):
|
|||||||
data.actual_operation_time = time_in_mins
|
data.actual_operation_time = time_in_mins
|
||||||
data.actual_start_time = time_data[0].start_time if time_data else None
|
data.actual_start_time = time_data[0].start_time if time_data else None
|
||||||
data.actual_end_time = time_data[0].end_time if time_data else None
|
data.actual_end_time = time_data[0].end_time if time_data else None
|
||||||
|
if data.get("workstation") != self.workstation:
|
||||||
|
# workstations can change in a job card
|
||||||
|
data.workstation = self.workstation
|
||||||
|
|
||||||
wo.flags.ignore_validate_update_after_submit = True
|
wo.flags.ignore_validate_update_after_submit = True
|
||||||
wo.update_operation_status()
|
wo.update_operation_status()
|
||||||
@ -427,6 +430,7 @@ def make_material_request(source_name, target_doc=None):
|
|||||||
def make_stock_entry(source_name, target_doc=None):
|
def make_stock_entry(source_name, target_doc=None):
|
||||||
def update_item(obj, target, source_parent):
|
def update_item(obj, target, source_parent):
|
||||||
target.t_warehouse = source_parent.wip_warehouse
|
target.t_warehouse = source_parent.wip_warehouse
|
||||||
|
target.conversion_factor = 1
|
||||||
|
|
||||||
def set_missing_values(source, target):
|
def set_missing_values(source, target):
|
||||||
target.purpose = "Material Transfer for Manufacture"
|
target.purpose = "Material Transfer for Manufacture"
|
||||||
|
|||||||
@ -11,10 +11,14 @@
|
|||||||
"from_warehouse",
|
"from_warehouse",
|
||||||
"warehouse",
|
"warehouse",
|
||||||
"column_break_4",
|
"column_break_4",
|
||||||
|
"required_bom_qty",
|
||||||
"quantity",
|
"quantity",
|
||||||
"uom",
|
"uom",
|
||||||
"projected_qty",
|
"projected_qty",
|
||||||
"actual_qty",
|
"actual_qty",
|
||||||
|
"ordered_qty",
|
||||||
|
"reserved_qty_for_production",
|
||||||
|
"safety_stock",
|
||||||
"item_details",
|
"item_details",
|
||||||
"description",
|
"description",
|
||||||
"min_order_qty",
|
"min_order_qty",
|
||||||
@ -129,11 +133,40 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "From Warehouse",
|
"label": "From Warehouse",
|
||||||
"options": "Warehouse"
|
"options": "Warehouse"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fetch_from": "item_code.safety_stock",
|
||||||
|
"fieldname": "safety_stock",
|
||||||
|
"fieldtype": "Float",
|
||||||
|
"label": "Safety Stock",
|
||||||
|
"no_copy": 1,
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "ordered_qty",
|
||||||
|
"fieldtype": "Float",
|
||||||
|
"label": "Ordered Qty",
|
||||||
|
"no_copy": 1,
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "reserved_qty_for_production",
|
||||||
|
"fieldtype": "Float",
|
||||||
|
"label": "Reserved Qty for Production",
|
||||||
|
"no_copy": 1,
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "required_bom_qty",
|
||||||
|
"fieldtype": "Float",
|
||||||
|
"label": "Required Qty as per BOM",
|
||||||
|
"no_copy": 1,
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-02-03 12:22:29.913302",
|
"modified": "2021-03-26 12:41:13.013149",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Manufacturing",
|
"module": "Manufacturing",
|
||||||
"name": "Material Request Plan Item",
|
"name": "Material Request Plan Item",
|
||||||
|
|||||||
@ -251,7 +251,8 @@ frappe.ui.form.on('Production Plan', {
|
|||||||
|
|
||||||
get_items_for_material_requests: function(frm, warehouses) {
|
get_items_for_material_requests: function(frm, warehouses) {
|
||||||
const set_fields = ['actual_qty', 'item_code','item_name', 'description', 'uom', 'from_warehouse',
|
const set_fields = ['actual_qty', 'item_code','item_name', 'description', 'uom', 'from_warehouse',
|
||||||
'min_order_qty', 'quantity', 'sales_order', 'warehouse', 'projected_qty', 'material_request_type'];
|
'min_order_qty', 'required_bom_qty', 'quantity', 'sales_order', 'warehouse', 'projected_qty', 'ordered_qty',
|
||||||
|
'reserved_qty_for_production', 'material_request_type'];
|
||||||
|
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: "erpnext.manufacturing.doctype.production_plan.production_plan.get_items_for_material_requests",
|
method: "erpnext.manufacturing.doctype.production_plan.production_plan.get_items_for_material_requests",
|
||||||
|
|||||||
@ -32,6 +32,7 @@
|
|||||||
"material_request_planning",
|
"material_request_planning",
|
||||||
"include_non_stock_items",
|
"include_non_stock_items",
|
||||||
"include_subcontracted_items",
|
"include_subcontracted_items",
|
||||||
|
"include_safety_stock",
|
||||||
"ignore_existing_ordered_qty",
|
"ignore_existing_ordered_qty",
|
||||||
"column_break_25",
|
"column_break_25",
|
||||||
"for_warehouse",
|
"for_warehouse",
|
||||||
@ -309,13 +310,19 @@
|
|||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"label": "Sales Order Status",
|
"label": "Sales Order Status",
|
||||||
"options": "\nTo Deliver and Bill\nTo Bill\nTo Deliver"
|
"options": "\nTo Deliver and Bill\nTo Bill\nTo Deliver"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fieldname": "include_safety_stock",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Include Safety Stock in Required Qty Calculation"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-calendar",
|
"icon": "fa fa-calendar",
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-11-10 18:01:54.991970",
|
"modified": "2021-03-08 11:17:25.470147",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Manufacturing",
|
"module": "Manufacturing",
|
||||||
"name": "Production Plan",
|
"name": "Production Plan",
|
||||||
|
|||||||
@ -434,12 +434,14 @@ def download_raw_materials(doc):
|
|||||||
if isinstance(doc, string_types):
|
if isinstance(doc, string_types):
|
||||||
doc = frappe._dict(json.loads(doc))
|
doc = frappe._dict(json.loads(doc))
|
||||||
|
|
||||||
item_list = [['Item Code', 'Description', 'Stock UOM', 'Required Qty', 'Warehouse',
|
item_list = [['Item Code', 'Description', 'Stock UOM', 'Warehouse', 'Required Qty as per BOM',
|
||||||
'projected Qty', 'Actual Qty']]
|
'Projected Qty', 'Actual Qty', 'Ordered Qty', 'Reserved Qty for Production',
|
||||||
|
'Safety Stock', 'Required Qty']]
|
||||||
|
|
||||||
for d in get_items_for_material_requests(doc):
|
for d in get_items_for_material_requests(doc):
|
||||||
item_list.append([d.get('item_code'), d.get('description'), d.get('stock_uom'), d.get('quantity'),
|
item_list.append([d.get('item_code'), d.get('description'), d.get('stock_uom'), d.get('warehouse'),
|
||||||
d.get('warehouse'), d.get('projected_qty'), d.get('actual_qty')])
|
d.get('required_bom_qty'), d.get('projected_qty'), d.get('actual_qty'), d.get('ordered_qty'),
|
||||||
|
d.get('reserved_qty_for_production'), d.get('safety_stock'), d.get('quantity')])
|
||||||
|
|
||||||
if not doc.get('for_warehouse'):
|
if not doc.get('for_warehouse'):
|
||||||
row = {'item_code': d.get('item_code')}
|
row = {'item_code': d.get('item_code')}
|
||||||
@ -447,8 +449,9 @@ def download_raw_materials(doc):
|
|||||||
if d.get("warehouse") == bin_dict.get('warehouse'):
|
if d.get("warehouse") == bin_dict.get('warehouse'):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
item_list.append(['', '', '', '', bin_dict.get('warehouse'),
|
item_list.append(['', '', '', bin_dict.get('warehouse'), '',
|
||||||
bin_dict.get('projected_qty', 0), bin_dict.get('actual_qty', 0)])
|
bin_dict.get('projected_qty', 0), bin_dict.get('actual_qty', 0),
|
||||||
|
bin_dict.get('ordered_qty', 0), bin_dict.get('reserved_qty_for_production', 0)])
|
||||||
|
|
||||||
build_csv_response(item_list, doc.name)
|
build_csv_response(item_list, doc.name)
|
||||||
|
|
||||||
@ -482,7 +485,7 @@ def get_subitems(doc, data, item_details, bom_no, company, include_non_stock_ite
|
|||||||
ifnull(%(parent_qty)s * sum(bom_item.stock_qty/ifnull(bom.quantity, 1)) * %(planned_qty)s, 0) as qty,
|
ifnull(%(parent_qty)s * sum(bom_item.stock_qty/ifnull(bom.quantity, 1)) * %(planned_qty)s, 0) as qty,
|
||||||
item.is_sub_contracted_item as is_sub_contracted, bom_item.source_warehouse,
|
item.is_sub_contracted_item as is_sub_contracted, bom_item.source_warehouse,
|
||||||
item.default_bom as default_bom, bom_item.description as description,
|
item.default_bom as default_bom, bom_item.description as description,
|
||||||
bom_item.stock_uom as stock_uom, item.min_order_qty as min_order_qty,
|
bom_item.stock_uom as stock_uom, item.min_order_qty as min_order_qty, item.safety_stock as safety_stock,
|
||||||
item_default.default_warehouse, item.purchase_uom, item_uom.conversion_factor
|
item_default.default_warehouse, item.purchase_uom, item_uom.conversion_factor
|
||||||
FROM
|
FROM
|
||||||
`tabBOM Item` bom_item
|
`tabBOM Item` bom_item
|
||||||
@ -518,8 +521,8 @@ def get_subitems(doc, data, item_details, bom_no, company, include_non_stock_ite
|
|||||||
include_non_stock_items, include_subcontracted_items, d.qty)
|
include_non_stock_items, include_subcontracted_items, d.qty)
|
||||||
return item_details
|
return item_details
|
||||||
|
|
||||||
def get_material_request_items(row, sales_order,
|
def get_material_request_items(row, sales_order, company,
|
||||||
company, ignore_existing_ordered_qty, warehouse, bin_dict):
|
ignore_existing_ordered_qty, include_safety_stock, warehouse, bin_dict):
|
||||||
total_qty = row['qty']
|
total_qty = row['qty']
|
||||||
|
|
||||||
required_qty = 0
|
required_qty = 0
|
||||||
@ -543,17 +546,24 @@ def get_material_request_items(row, sales_order,
|
|||||||
if frappe.db.get_value("UOM", row['purchase_uom'], "must_be_whole_number"):
|
if frappe.db.get_value("UOM", row['purchase_uom'], "must_be_whole_number"):
|
||||||
required_qty = ceil(required_qty)
|
required_qty = ceil(required_qty)
|
||||||
|
|
||||||
|
if include_safety_stock:
|
||||||
|
required_qty += flt(row['safety_stock'])
|
||||||
|
|
||||||
if required_qty > 0:
|
if required_qty > 0:
|
||||||
return {
|
return {
|
||||||
'item_code': row.item_code,
|
'item_code': row.item_code,
|
||||||
'item_name': row.item_name,
|
'item_name': row.item_name,
|
||||||
'quantity': required_qty,
|
'quantity': required_qty,
|
||||||
|
'required_bom_qty': total_qty,
|
||||||
'description': row.description,
|
'description': row.description,
|
||||||
'stock_uom': row.get("stock_uom"),
|
'stock_uom': row.get("stock_uom"),
|
||||||
'warehouse': warehouse or row.get('source_warehouse') \
|
'warehouse': warehouse or row.get('source_warehouse') \
|
||||||
or row.get('default_warehouse') or item_group_defaults.get("default_warehouse"),
|
or row.get('default_warehouse') or item_group_defaults.get("default_warehouse"),
|
||||||
|
'safety_stock': row.safety_stock,
|
||||||
'actual_qty': bin_dict.get("actual_qty", 0),
|
'actual_qty': bin_dict.get("actual_qty", 0),
|
||||||
'projected_qty': bin_dict.get("projected_qty", 0),
|
'projected_qty': bin_dict.get("projected_qty", 0),
|
||||||
|
'ordered_qty': bin_dict.get("ordered_qty", 0),
|
||||||
|
'reserved_qty_for_production': bin_dict.get("reserved_qty_for_production", 0),
|
||||||
'min_order_qty': row['min_order_qty'],
|
'min_order_qty': row['min_order_qty'],
|
||||||
'material_request_type': row.get("default_material_request_type"),
|
'material_request_type': row.get("default_material_request_type"),
|
||||||
'sales_order': sales_order,
|
'sales_order': sales_order,
|
||||||
@ -620,7 +630,8 @@ def get_bin_details(row, company, for_warehouse=None, all_warehouse=False):
|
|||||||
""".format(lft, rgt, company)
|
""".format(lft, rgt, company)
|
||||||
|
|
||||||
return frappe.db.sql(""" select ifnull(sum(projected_qty),0) as projected_qty,
|
return frappe.db.sql(""" select ifnull(sum(projected_qty),0) as projected_qty,
|
||||||
ifnull(sum(actual_qty),0) as actual_qty, warehouse from `tabBin`
|
ifnull(sum(actual_qty),0) as actual_qty, ifnull(sum(ordered_qty),0) as ordered_qty,
|
||||||
|
ifnull(sum(reserved_qty_for_production),0) as reserved_qty_for_production, warehouse from `tabBin`
|
||||||
where item_code = %(item_code)s {conditions}
|
where item_code = %(item_code)s {conditions}
|
||||||
group by item_code, warehouse
|
group by item_code, warehouse
|
||||||
""".format(conditions=conditions), { "item_code": row['item_code'] }, as_dict=1)
|
""".format(conditions=conditions), { "item_code": row['item_code'] }, as_dict=1)
|
||||||
@ -660,6 +671,7 @@ def get_items_for_material_requests(doc, warehouses=None):
|
|||||||
|
|
||||||
company = doc.get('company')
|
company = doc.get('company')
|
||||||
ignore_existing_ordered_qty = doc.get('ignore_existing_ordered_qty')
|
ignore_existing_ordered_qty = doc.get('ignore_existing_ordered_qty')
|
||||||
|
include_safety_stock = doc.get('include_safety_stock')
|
||||||
|
|
||||||
so_item_details = frappe._dict()
|
so_item_details = frappe._dict()
|
||||||
for data in po_items:
|
for data in po_items:
|
||||||
@ -711,6 +723,7 @@ def get_items_for_material_requests(doc, warehouses=None):
|
|||||||
'description' : item_master.description,
|
'description' : item_master.description,
|
||||||
'stock_uom' : item_master.stock_uom,
|
'stock_uom' : item_master.stock_uom,
|
||||||
'conversion_factor' : conversion_factor,
|
'conversion_factor' : conversion_factor,
|
||||||
|
'safety_stock': item_master.safety_stock
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -732,7 +745,7 @@ def get_items_for_material_requests(doc, warehouses=None):
|
|||||||
|
|
||||||
if details.qty > 0:
|
if details.qty > 0:
|
||||||
items = get_material_request_items(details, sales_order, company,
|
items = get_material_request_items(details, sales_order, company,
|
||||||
ignore_existing_ordered_qty, warehouse, bin_dict)
|
ignore_existing_ordered_qty, include_safety_stock, warehouse, bin_dict)
|
||||||
if items:
|
if items:
|
||||||
mr_items.append(items)
|
mr_items.append(items)
|
||||||
|
|
||||||
|
|||||||
@ -333,8 +333,7 @@
|
|||||||
"fieldname": "operations",
|
"fieldname": "operations",
|
||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"label": "Operations",
|
"label": "Operations",
|
||||||
"options": "Work Order Operation",
|
"options": "Work Order Operation"
|
||||||
"read_only": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "operations",
|
"depends_on": "operations",
|
||||||
@ -496,7 +495,7 @@
|
|||||||
"image_field": "image",
|
"image_field": "image",
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-05-05 19:32:43.323054",
|
"modified": "2021-03-16 13:27:51.116484",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Manufacturing",
|
"module": "Manufacturing",
|
||||||
"name": "Work Order",
|
"name": "Work Order",
|
||||||
|
|||||||
@ -61,7 +61,7 @@ class ForecastingReport(ExponentialSmoothingForecast):
|
|||||||
|
|
||||||
from_date = add_years(self.filters.from_date, cint(self.filters.no_of_years) * -1)
|
from_date = add_years(self.filters.from_date, cint(self.filters.no_of_years) * -1)
|
||||||
self.period_list = get_period_list(from_date, self.filters.to_date,
|
self.period_list = get_period_list(from_date, self.filters.to_date,
|
||||||
from_date, self.filters.to_date, None, self.filters.periodicity, ignore_fiscal_year=True)
|
from_date, self.filters.to_date, "Date Range", self.filters.periodicity, ignore_fiscal_year=True)
|
||||||
|
|
||||||
order_data = self.get_data_for_forecast() or []
|
order_data = self.get_data_for_forecast() or []
|
||||||
|
|
||||||
|
|||||||
@ -752,6 +752,7 @@ erpnext.patches.v13_0.set_company_in_leave_ledger_entry
|
|||||||
erpnext.patches.v13_0.convert_qi_parameter_to_link_field
|
erpnext.patches.v13_0.convert_qi_parameter_to_link_field
|
||||||
erpnext.patches.v13_0.setup_patient_history_settings_for_standard_doctypes
|
erpnext.patches.v13_0.setup_patient_history_settings_for_standard_doctypes
|
||||||
erpnext.patches.v13_0.add_naming_series_to_old_projects # 1-02-2021
|
erpnext.patches.v13_0.add_naming_series_to_old_projects # 1-02-2021
|
||||||
|
erpnext.patches.v13_0.update_payment_terms_outstanding
|
||||||
erpnext.patches.v12_0.add_state_code_for_ladakh
|
erpnext.patches.v12_0.add_state_code_for_ladakh
|
||||||
erpnext.patches.v13_0.item_reposting_for_incorrect_sl_and_gl
|
erpnext.patches.v13_0.item_reposting_for_incorrect_sl_and_gl
|
||||||
erpnext.patches.v13_0.delete_old_bank_reconciliation_doctypes
|
erpnext.patches.v13_0.delete_old_bank_reconciliation_doctypes
|
||||||
|
|||||||
@ -20,9 +20,11 @@ def execute():
|
|||||||
frappe.clear_cache()
|
frappe.clear_cache()
|
||||||
frappe.flags.warehouse_account_map = {}
|
frappe.flags.warehouse_account_map = {}
|
||||||
|
|
||||||
|
company_list = []
|
||||||
|
|
||||||
data = frappe.db.sql('''
|
data = frappe.db.sql('''
|
||||||
SELECT
|
SELECT
|
||||||
name, item_code, warehouse, voucher_type, voucher_no, posting_date, posting_time
|
name, item_code, warehouse, voucher_type, voucher_no, posting_date, posting_time, company
|
||||||
FROM
|
FROM
|
||||||
`tabStock Ledger Entry`
|
`tabStock Ledger Entry`
|
||||||
WHERE
|
WHERE
|
||||||
@ -36,6 +38,9 @@ def execute():
|
|||||||
total_sle = len(data)
|
total_sle = len(data)
|
||||||
i = 0
|
i = 0
|
||||||
for d in data:
|
for d in data:
|
||||||
|
if d.company not in company_list:
|
||||||
|
company_list.append(d.company)
|
||||||
|
|
||||||
update_entries_after({
|
update_entries_after({
|
||||||
"item_code": d.item_code,
|
"item_code": d.item_code,
|
||||||
"warehouse": d.warehouse,
|
"warehouse": d.warehouse,
|
||||||
@ -53,8 +58,10 @@ def execute():
|
|||||||
|
|
||||||
print("Reposting General Ledger Entries...")
|
print("Reposting General Ledger Entries...")
|
||||||
|
|
||||||
for row in frappe.get_all('Company', filters= {'enable_perpetual_inventory': 1}):
|
if data:
|
||||||
update_gl_entries_after(posting_date, posting_time, company=row.name)
|
for row in frappe.get_all('Company', filters= {'enable_perpetual_inventory': 1}):
|
||||||
|
if row.name in company_list:
|
||||||
|
update_gl_entries_after(posting_date, posting_time, company=row.name)
|
||||||
|
|
||||||
frappe.db.auto_commit_on_many_writes = 0
|
frappe.db.auto_commit_on_many_writes = 0
|
||||||
|
|
||||||
|
|||||||
15
erpnext/patches/v13_0/update_payment_terms_outstanding.py
Normal file
15
erpnext/patches/v13_0/update_payment_terms_outstanding.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
|
# MIT License. See license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
frappe.reload_doc("accounts", "doctype", "Payment Schedule")
|
||||||
|
if frappe.db.count('Payment Schedule'):
|
||||||
|
frappe.db.sql('''
|
||||||
|
UPDATE
|
||||||
|
`tabPayment Schedule` ps
|
||||||
|
SET
|
||||||
|
ps.outstanding = (ps.payment_amount - ps.paid_amount)
|
||||||
|
''')
|
||||||
@ -163,7 +163,6 @@
|
|||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "Company:company:default_currency",
|
|
||||||
"depends_on": "eval:(doc.docstatus==1 || doc.employee)",
|
"depends_on": "eval:(doc.docstatus==1 || doc.employee)",
|
||||||
"fieldname": "currency",
|
"fieldname": "currency",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
@ -176,7 +175,7 @@
|
|||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-10-20 17:51:13.419716",
|
"modified": "2021-03-31 21:33:59.098532",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Payroll",
|
"module": "Payroll",
|
||||||
"name": "Additional Salary",
|
"name": "Additional Salary",
|
||||||
|
|||||||
@ -89,10 +89,11 @@ class AdditionalSalary(Document):
|
|||||||
no_of_days = date_diff(getdate(end_date), getdate(start_date)) + 1
|
no_of_days = date_diff(getdate(end_date), getdate(start_date)) + 1
|
||||||
return amount_per_day * no_of_days
|
return amount_per_day * no_of_days
|
||||||
|
|
||||||
@frappe.whitelist()
|
def get_additional_salaries(employee, start_date, end_date, component_type):
|
||||||
def get_additional_salary_component(employee, start_date, end_date, component_type):
|
additional_salary_list = frappe.db.sql("""
|
||||||
additional_salaries = frappe.db.sql("""
|
select name, salary_component as component, type, amount,
|
||||||
select name, salary_component, type, amount, overwrite_salary_structure_amount, deduct_full_tax_on_selected_payroll_date
|
overwrite_salary_structure_amount as overwrite,
|
||||||
|
deduct_full_tax_on_selected_payroll_date
|
||||||
from `tabAdditional Salary`
|
from `tabAdditional Salary`
|
||||||
where employee=%(employee)s
|
where employee=%(employee)s
|
||||||
and docstatus = 1
|
and docstatus = 1
|
||||||
@ -102,7 +103,7 @@ def get_additional_salary_component(employee, start_date, end_date, component_ty
|
|||||||
from_date <= %(to_date)s and to_date >= %(to_date)s
|
from_date <= %(to_date)s and to_date >= %(to_date)s
|
||||||
)
|
)
|
||||||
and type = %(component_type)s
|
and type = %(component_type)s
|
||||||
order by salary_component, overwrite_salary_structure_amount DESC
|
order by salary_component, overwrite ASC
|
||||||
""", {
|
""", {
|
||||||
'employee': employee,
|
'employee': employee,
|
||||||
'from_date': start_date,
|
'from_date': start_date,
|
||||||
@ -110,38 +111,18 @@ def get_additional_salary_component(employee, start_date, end_date, component_ty
|
|||||||
'component_type': "Earning" if component_type == "earnings" else "Deduction"
|
'component_type': "Earning" if component_type == "earnings" else "Deduction"
|
||||||
}, as_dict=1)
|
}, as_dict=1)
|
||||||
|
|
||||||
existing_salary_components= []
|
additional_salaries = []
|
||||||
salary_components_details = {}
|
components_to_overwrite = []
|
||||||
additional_salary_details = []
|
|
||||||
|
|
||||||
overwrites_components = [ele.salary_component for ele in additional_salaries if ele.overwrite_salary_structure_amount == 1]
|
for d in additional_salary_list:
|
||||||
|
if d.overwrite:
|
||||||
|
if d.component in components_to_overwrite:
|
||||||
|
frappe.throw(_("Multiple Additional Salaries with overwrite "
|
||||||
|
"property exist for Salary Component {0} between {1} and {2}.").format(
|
||||||
|
frappe.bold(d.component), start_date, end_date), title=_("Error"))
|
||||||
|
|
||||||
component_fields = ["depends_on_payment_days", "salary_component_abbr", "is_tax_applicable", "variable_based_on_taxable_salary", 'type']
|
components_to_overwrite.append(d.component)
|
||||||
for d in additional_salaries:
|
|
||||||
|
|
||||||
if d.salary_component not in existing_salary_components:
|
additional_salaries.append(d)
|
||||||
component = frappe.get_all("Salary Component", filters={'name': d.salary_component}, fields=component_fields)
|
|
||||||
struct_row = frappe._dict({'salary_component': d.salary_component})
|
|
||||||
if component:
|
|
||||||
struct_row.update(component[0])
|
|
||||||
|
|
||||||
struct_row['deduct_full_tax_on_selected_payroll_date'] = d.deduct_full_tax_on_selected_payroll_date
|
return additional_salaries
|
||||||
struct_row['is_additional_component'] = 1
|
|
||||||
|
|
||||||
salary_components_details[d.salary_component] = struct_row
|
|
||||||
|
|
||||||
|
|
||||||
if overwrites_components.count(d.salary_component) > 1:
|
|
||||||
frappe.throw(_("Multiple Additional Salaries with overwrite property exist for Salary Component: {0} between {1} and {2}.".format(d.salary_component, start_date, end_date)), title=_("Error"))
|
|
||||||
else:
|
|
||||||
additional_salary_details.append({
|
|
||||||
'name': d.name,
|
|
||||||
'component': d.salary_component,
|
|
||||||
'amount': d.amount,
|
|
||||||
'type': d.type,
|
|
||||||
'overwrite': d.overwrite_salary_structure_amount,
|
|
||||||
})
|
|
||||||
|
|
||||||
existing_salary_components.append(d.salary_component)
|
|
||||||
|
|
||||||
return salary_components_details, additional_salary_details
|
|
||||||
|
|||||||
@ -124,7 +124,6 @@
|
|||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "Company:company:default_currency",
|
|
||||||
"depends_on": "eval:(doc.docstatus==1 || doc.employee)",
|
"depends_on": "eval:(doc.docstatus==1 || doc.employee)",
|
||||||
"fieldname": "currency",
|
"fieldname": "currency",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
@ -148,7 +147,7 @@
|
|||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-12-14 15:52:08.566418",
|
"modified": "2021-03-31 21:35:08.940087",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Payroll",
|
"module": "Payroll",
|
||||||
"name": "Employee Benefit Application",
|
"name": "Employee Benefit Application",
|
||||||
|
|||||||
@ -21,7 +21,6 @@ frappe.ui.form.on('Employee Benefit Claim', {
|
|||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
if (r.message) {
|
if (r.message) {
|
||||||
frm.set_value('currency', r.message);
|
frm.set_value('currency', r.message);
|
||||||
frm.set_df_property('currency', 'hidden', 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -125,10 +125,9 @@
|
|||||||
"label": "Attachments"
|
"label": "Attachments"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "Company:company:default_currency",
|
"depends_on": "eval: doc.employee",
|
||||||
"fieldname": "currency",
|
"fieldname": "currency",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 1,
|
|
||||||
"label": "Currency",
|
"label": "Currency",
|
||||||
"options": "Currency",
|
"options": "Currency",
|
||||||
"read_only": 1,
|
"read_only": 1,
|
||||||
@ -145,7 +144,7 @@
|
|||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-11-25 11:49:56.097352",
|
"modified": "2021-03-31 21:37:21.024625",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Payroll",
|
"module": "Payroll",
|
||||||
"name": "Employee Benefit Claim",
|
"name": "Employee Benefit Claim",
|
||||||
|
|||||||
@ -75,7 +75,6 @@
|
|||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "Company:company:default_currency",
|
|
||||||
"depends_on": "eval:(doc.docstatus==1 || doc.employee)",
|
"depends_on": "eval:(doc.docstatus==1 || doc.employee)",
|
||||||
"fieldname": "currency",
|
"fieldname": "currency",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
@ -95,7 +94,7 @@
|
|||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-10-20 17:22:16.468042",
|
"modified": "2021-03-31 21:38:20.332316",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Payroll",
|
"module": "Payroll",
|
||||||
"name": "Employee Incentive",
|
"name": "Employee Incentive",
|
||||||
|
|||||||
@ -47,5 +47,26 @@ frappe.ui.form.on('Employee Tax Exemption Declaration', {
|
|||||||
});
|
});
|
||||||
}).addClass("btn-primary");
|
}).addClass("btn-primary");
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
employee: function(frm) {
|
||||||
|
if (frm.doc.employee) {
|
||||||
|
frm.trigger('get_employee_currency');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
get_employee_currency: function(frm) {
|
||||||
|
frappe.call({
|
||||||
|
method: "erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment.get_employee_currency",
|
||||||
|
args: {
|
||||||
|
employee: frm.doc.employee,
|
||||||
|
},
|
||||||
|
callback: function(r) {
|
||||||
|
if (r.message) {
|
||||||
|
frm.set_value('currency', r.message);
|
||||||
|
frm.refresh_fields();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -108,7 +108,7 @@
|
|||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "Company:company:default_currency",
|
"depends_on": "eval: doc.employee",
|
||||||
"fieldname": "currency",
|
"fieldname": "currency",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Currency",
|
"label": "Currency",
|
||||||
@ -119,7 +119,7 @@
|
|||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-10-20 16:42:24.493761",
|
"modified": "2021-03-31 21:39:59.237361",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Payroll",
|
"module": "Payroll",
|
||||||
"name": "Employee Tax Exemption Declaration",
|
"name": "Employee Tax Exemption Declaration",
|
||||||
|
|||||||
@ -58,5 +58,26 @@ frappe.ui.form.on('Employee Tax Exemption Proof Submission', {
|
|||||||
|
|
||||||
currency: function(frm) {
|
currency: function(frm) {
|
||||||
frm.refresh_fields();
|
frm.refresh_fields();
|
||||||
}
|
},
|
||||||
|
|
||||||
|
employee: function(frm) {
|
||||||
|
if (frm.doc.employee) {
|
||||||
|
frm.trigger('get_employee_currency');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
get_employee_currency: function(frm) {
|
||||||
|
frappe.call({
|
||||||
|
method: "erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment.get_employee_currency",
|
||||||
|
args: {
|
||||||
|
employee: frm.doc.employee,
|
||||||
|
},
|
||||||
|
callback: function(r) {
|
||||||
|
if (r.message) {
|
||||||
|
frm.set_value('currency', r.message);
|
||||||
|
frm.refresh_fields();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@ -131,7 +131,7 @@
|
|||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "Company:company:default_currency",
|
"depends_on": "eval: doc.employee",
|
||||||
"fieldname": "currency",
|
"fieldname": "currency",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Currency",
|
"label": "Currency",
|
||||||
@ -142,7 +142,7 @@
|
|||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-10-20 16:47:03.410020",
|
"modified": "2021-03-31 21:41:13.723339",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Payroll",
|
"module": "Payroll",
|
||||||
"name": "Employee Tax Exemption Proof Submission",
|
"name": "Employee Tax Exemption Proof Submission",
|
||||||
|
|||||||
@ -93,7 +93,7 @@
|
|||||||
"options": "Income Tax Slab Other Charges"
|
"options": "Income Tax Slab Other Charges"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "Company:company:default_currency",
|
"fetch_from": "company.default_currency",
|
||||||
"fieldname": "currency",
|
"fieldname": "currency",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Currency",
|
"label": "Currency",
|
||||||
@ -104,7 +104,7 @@
|
|||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-10-19 13:54:24.728075",
|
"modified": "2021-03-31 21:42:08.139520",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Payroll",
|
"module": "Payroll",
|
||||||
"name": "Income Tax Slab",
|
"name": "Income Tax Slab",
|
||||||
|
|||||||
@ -93,7 +93,6 @@
|
|||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "Company:company:default_currency",
|
|
||||||
"depends_on": "eval:(doc.docstatus==1 || doc.employee)",
|
"depends_on": "eval:(doc.docstatus==1 || doc.employee)",
|
||||||
"fieldname": "currency",
|
"fieldname": "currency",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
@ -106,7 +105,7 @@
|
|||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-10-20 17:27:47.003134",
|
"modified": "2021-03-31 21:43:28.363644",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Payroll",
|
"module": "Payroll",
|
||||||
"name": "Retention Bonus",
|
"name": "Retention Bonus",
|
||||||
|
|||||||
@ -500,7 +500,6 @@
|
|||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "Company:company:default_currency",
|
|
||||||
"depends_on": "eval:(doc.docstatus==1 || doc.salary_structure)",
|
"depends_on": "eval:(doc.docstatus==1 || doc.salary_structure)",
|
||||||
"fetch_from": "salary_structure.currency",
|
"fetch_from": "salary_structure.currency",
|
||||||
"fieldname": "currency",
|
"fieldname": "currency",
|
||||||
@ -632,7 +631,7 @@
|
|||||||
"idx": 9,
|
"idx": 9,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-02-19 11:48:05.383945",
|
"modified": "2021-03-31 21:44:09.772331",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Payroll",
|
"module": "Payroll",
|
||||||
"name": "Salary Slip",
|
"name": "Salary Slip",
|
||||||
|
|||||||
@ -13,7 +13,7 @@ from erpnext.payroll.doctype.payroll_entry.payroll_entry import get_start_end_da
|
|||||||
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
|
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
|
||||||
from erpnext.utilities.transaction_base import TransactionBase
|
from erpnext.utilities.transaction_base import TransactionBase
|
||||||
from frappe.utils.background_jobs import enqueue
|
from frappe.utils.background_jobs import enqueue
|
||||||
from erpnext.payroll.doctype.additional_salary.additional_salary import get_additional_salary_component
|
from erpnext.payroll.doctype.additional_salary.additional_salary import get_additional_salaries
|
||||||
from erpnext.payroll.doctype.payroll_period.payroll_period import get_period_factor, get_payroll_period
|
from erpnext.payroll.doctype.payroll_period.payroll_period import get_period_factor, get_payroll_period
|
||||||
from erpnext.payroll.doctype.employee_benefit_application.employee_benefit_application import get_benefit_component_amount
|
from erpnext.payroll.doctype.employee_benefit_application.employee_benefit_application import get_benefit_component_amount
|
||||||
from erpnext.payroll.doctype.employee_benefit_claim.employee_benefit_claim import get_benefit_claim_amount, get_last_payroll_period_benefits
|
from erpnext.payroll.doctype.employee_benefit_claim.employee_benefit_claim import get_benefit_claim_amount, get_last_payroll_period_benefits
|
||||||
@ -558,15 +558,16 @@ class SalarySlip(TransactionBase):
|
|||||||
self.update_component_row(frappe._dict(last_benefit.struct_row), amount, "earnings")
|
self.update_component_row(frappe._dict(last_benefit.struct_row), amount, "earnings")
|
||||||
|
|
||||||
def add_additional_salary_components(self, component_type):
|
def add_additional_salary_components(self, component_type):
|
||||||
salary_components_details, additional_salary_details = get_additional_salary_component(self.employee,
|
additional_salaries = get_additional_salaries(self.employee,
|
||||||
self.start_date, self.end_date, component_type)
|
self.start_date, self.end_date, component_type)
|
||||||
if salary_components_details and additional_salary_details:
|
|
||||||
for additional_salary in additional_salary_details:
|
for additional_salary in additional_salaries:
|
||||||
additional_salary =frappe._dict(additional_salary)
|
self.update_component_row(
|
||||||
amount = additional_salary.amount
|
get_salary_component_data(additional_salary.component),
|
||||||
overwrite = additional_salary.overwrite
|
additional_salary.amount,
|
||||||
self.update_component_row(frappe._dict(salary_components_details[additional_salary.component]), amount,
|
component_type,
|
||||||
component_type, overwrite=overwrite, additional_salary=additional_salary.name)
|
additional_salary
|
||||||
|
)
|
||||||
|
|
||||||
def add_tax_components(self, payroll_period):
|
def add_tax_components(self, payroll_period):
|
||||||
# Calculate variable_based_on_taxable_salary after all components updated in salary slip
|
# Calculate variable_based_on_taxable_salary after all components updated in salary slip
|
||||||
@ -583,47 +584,59 @@ class SalarySlip(TransactionBase):
|
|||||||
|
|
||||||
for d in tax_components:
|
for d in tax_components:
|
||||||
tax_amount = self.calculate_variable_based_on_taxable_salary(d, payroll_period)
|
tax_amount = self.calculate_variable_based_on_taxable_salary(d, payroll_period)
|
||||||
tax_row = self.get_salary_slip_row(d)
|
tax_row = get_salary_component_data(d)
|
||||||
self.update_component_row(tax_row, tax_amount, "deductions")
|
self.update_component_row(tax_row, tax_amount, "deductions")
|
||||||
|
|
||||||
def update_component_row(self, struct_row, amount, key, overwrite=1, additional_salary = ''):
|
def update_component_row(self, component_data, amount, component_type, additional_salary=None):
|
||||||
component_row = None
|
component_row = None
|
||||||
for d in self.get(key):
|
for d in self.get(component_type):
|
||||||
if d.salary_component == struct_row.salary_component:
|
if d.salary_component != component_data.salary_component:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if (
|
||||||
|
(not d.additional_salary
|
||||||
|
and (not additional_salary or additional_salary.overwrite))
|
||||||
|
or (additional_salary
|
||||||
|
and additional_salary.name == d.additional_salary)
|
||||||
|
):
|
||||||
component_row = d
|
component_row = d
|
||||||
|
break
|
||||||
|
|
||||||
if not component_row or (struct_row.get("is_additional_component") and not overwrite):
|
if additional_salary and additional_salary.overwrite:
|
||||||
if amount:
|
# Additional Salary with overwrite checked, remove default rows of same component
|
||||||
self.append(key, {
|
self.set(component_type, [
|
||||||
'amount': amount,
|
d for d in self.get(component_type)
|
||||||
'default_amount': amount if not struct_row.get("is_additional_component") else 0,
|
if d.salary_component != component_data.salary_component
|
||||||
'depends_on_payment_days' : struct_row.depends_on_payment_days,
|
or (d.additional_salary and additional_salary.name != d.additional_salary)
|
||||||
'salary_component' : struct_row.salary_component,
|
or d == component_row
|
||||||
'abbr' : struct_row.abbr or struct_row.get("salary_component_abbr"),
|
])
|
||||||
'additional_salary': additional_salary,
|
|
||||||
'do_not_include_in_total' : struct_row.do_not_include_in_total,
|
if not component_row:
|
||||||
'is_tax_applicable': struct_row.is_tax_applicable,
|
if not amount:
|
||||||
'is_flexible_benefit': struct_row.is_flexible_benefit,
|
return
|
||||||
'variable_based_on_taxable_salary': struct_row.variable_based_on_taxable_salary,
|
|
||||||
'deduct_full_tax_on_selected_payroll_date': struct_row.deduct_full_tax_on_selected_payroll_date,
|
component_row = self.append(component_type)
|
||||||
'additional_amount': amount if struct_row.get("is_additional_component") else 0,
|
for attr in (
|
||||||
'exempted_from_income_tax': struct_row.exempted_from_income_tax
|
'depends_on_payment_days', 'salary_component', 'abbr'
|
||||||
})
|
'do_not_include_in_total', 'is_tax_applicable',
|
||||||
|
'is_flexible_benefit', 'variable_based_on_taxable_salary',
|
||||||
|
'exempted_from_income_tax'
|
||||||
|
):
|
||||||
|
component_row.set(attr, component_data.get(attr))
|
||||||
|
|
||||||
|
if additional_salary:
|
||||||
|
component_row.default_amount = 0
|
||||||
|
component_row.additional_amount = amount
|
||||||
|
component_row.additional_salary = additional_salary.name
|
||||||
|
component_row.deduct_full_tax_on_selected_payroll_date = \
|
||||||
|
additional_salary.deduct_full_tax_on_selected_payroll_date
|
||||||
else:
|
else:
|
||||||
if struct_row.get("is_additional_component"):
|
component_row.default_amount = amount
|
||||||
if overwrite:
|
component_row.additional_amount = 0
|
||||||
component_row.additional_amount = amount - component_row.get("default_amount", 0)
|
component_row.deduct_full_tax_on_selected_payroll_date = \
|
||||||
component_row.additional_salary = additional_salary
|
component_data.deduct_full_tax_on_selected_payroll_date
|
||||||
else:
|
|
||||||
component_row.additional_amount = amount
|
|
||||||
|
|
||||||
if not overwrite and component_row.default_amount:
|
component_row.amount = amount
|
||||||
amount += component_row.default_amount
|
|
||||||
else:
|
|
||||||
component_row.default_amount = amount
|
|
||||||
|
|
||||||
component_row.amount = amount
|
|
||||||
component_row.deduct_full_tax_on_selected_payroll_date = struct_row.deduct_full_tax_on_selected_payroll_date
|
|
||||||
|
|
||||||
def calculate_variable_based_on_taxable_salary(self, tax_component, payroll_period):
|
def calculate_variable_based_on_taxable_salary(self, tax_component, payroll_period):
|
||||||
if not payroll_period:
|
if not payroll_period:
|
||||||
@ -957,19 +970,6 @@ class SalarySlip(TransactionBase):
|
|||||||
frappe.throw(_("Error in formula or condition: {0}").format(e))
|
frappe.throw(_("Error in formula or condition: {0}").format(e))
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def get_salary_slip_row(self, salary_component):
|
|
||||||
component = frappe.get_doc("Salary Component", salary_component)
|
|
||||||
# Data for update_component_row
|
|
||||||
struct_row = frappe._dict()
|
|
||||||
struct_row['depends_on_payment_days'] = component.depends_on_payment_days
|
|
||||||
struct_row['salary_component'] = component.name
|
|
||||||
struct_row['abbr'] = component.salary_component_abbr
|
|
||||||
struct_row['do_not_include_in_total'] = component.do_not_include_in_total
|
|
||||||
struct_row['is_tax_applicable'] = component.is_tax_applicable
|
|
||||||
struct_row['is_flexible_benefit'] = component.is_flexible_benefit
|
|
||||||
struct_row['variable_based_on_taxable_salary'] = component.variable_based_on_taxable_salary
|
|
||||||
return struct_row
|
|
||||||
|
|
||||||
def get_component_totals(self, component_type, depends_on_payment_days=0):
|
def get_component_totals(self, component_type, depends_on_payment_days=0):
|
||||||
joining_date, relieving_date = frappe.get_cached_value("Employee", self.employee,
|
joining_date, relieving_date = frappe.get_cached_value("Employee", self.employee,
|
||||||
["date_of_joining", "relieving_date"])
|
["date_of_joining", "relieving_date"])
|
||||||
@ -1032,7 +1032,6 @@ class SalarySlip(TransactionBase):
|
|||||||
self.total_loan_repayment += payment.total_payment
|
self.total_loan_repayment += payment.total_payment
|
||||||
|
|
||||||
def get_loan_details(self):
|
def get_loan_details(self):
|
||||||
|
|
||||||
return frappe.get_all("Loan",
|
return frappe.get_all("Loan",
|
||||||
fields=["name", "interest_income_account", "loan_account", "loan_type"],
|
fields=["name", "interest_income_account", "loan_account", "loan_type"],
|
||||||
filters = {
|
filters = {
|
||||||
@ -1263,3 +1262,19 @@ def unlink_ref_doc_from_salary_slip(ref_no):
|
|||||||
def generate_password_for_pdf(policy_template, employee):
|
def generate_password_for_pdf(policy_template, employee):
|
||||||
employee = frappe.get_doc("Employee", employee)
|
employee = frappe.get_doc("Employee", employee)
|
||||||
return policy_template.format(**employee.as_dict())
|
return policy_template.format(**employee.as_dict())
|
||||||
|
|
||||||
|
def get_salary_component_data(component):
|
||||||
|
return frappe.get_value(
|
||||||
|
"Salary Component",
|
||||||
|
component,
|
||||||
|
[
|
||||||
|
"name as salary_component",
|
||||||
|
"depends_on_payment_days",
|
||||||
|
"salary_component_abbr as abbr",
|
||||||
|
"do_not_include_in_total",
|
||||||
|
"is_tax_applicable",
|
||||||
|
"is_flexible_benefit",
|
||||||
|
"variable_based_on_taxable_salary",
|
||||||
|
],
|
||||||
|
as_dict=1,
|
||||||
|
)
|
||||||
|
|||||||
@ -246,7 +246,7 @@ class TestSalarySlip(unittest.TestCase):
|
|||||||
make_salary_structure("Test Loan Repayment Salary Structure", "Monthly", employee=applicant, currency='INR',
|
make_salary_structure("Test Loan Repayment Salary Structure", "Monthly", employee=applicant, currency='INR',
|
||||||
payroll_period=payroll_period)
|
payroll_period=payroll_period)
|
||||||
|
|
||||||
frappe.db.sql("""delete from `tabLoan""")
|
frappe.db.sql("delete from tabLoan")
|
||||||
loan = create_loan(applicant, "Car Loan", 11000, "Repay Over Number of Periods", 20, posting_date=add_months(nowdate(), -1))
|
loan = create_loan(applicant, "Car Loan", 11000, "Repay Over Number of Periods", 20, posting_date=add_months(nowdate(), -1))
|
||||||
loan.repay_from_salary = 1
|
loan.repay_from_salary = 1
|
||||||
loan.submit()
|
loan.submit()
|
||||||
|
|||||||
@ -125,7 +125,6 @@
|
|||||||
"options": "Income Tax Slab"
|
"options": "Income Tax Slab"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "Company:company:default_currency",
|
|
||||||
"depends_on": "eval:(doc.docstatus==1 || doc.salary_structure)",
|
"depends_on": "eval:(doc.docstatus==1 || doc.salary_structure)",
|
||||||
"fetch_from": "salary_structure.currency",
|
"fetch_from": "salary_structure.currency",
|
||||||
"fieldname": "currency",
|
"fieldname": "currency",
|
||||||
@ -146,7 +145,7 @@
|
|||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-11-30 18:07:48.251311",
|
"modified": "2021-03-31 21:44:46.267974",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Payroll",
|
"module": "Payroll",
|
||||||
"name": "Salary Structure Assignment",
|
"name": "Salary Structure Assignment",
|
||||||
|
|||||||
@ -577,7 +577,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
var d = locals[cdt][cdn];
|
var d = locals[cdt][cdn];
|
||||||
me.add_taxes_from_item_tax_template(d.item_tax_rate);
|
me.add_taxes_from_item_tax_template(d.item_tax_rate);
|
||||||
if (d.free_item_data) {
|
if (d.free_item_data) {
|
||||||
me.apply_product_discount(d.free_item_data);
|
me.apply_product_discount(d);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
@ -738,21 +738,15 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var valid_serial_nos = [];
|
var valid_serial_nos = [];
|
||||||
|
var serialnos = [];
|
||||||
// Replacing all occurences of comma with carriage return
|
// Replacing all occurences of comma with carriage return
|
||||||
var serial_nos = item.serial_no.trim().replace(/,/g, '\n');
|
item.serial_no = item.serial_no.replace(/,/g, '\n');
|
||||||
|
serialnos = item.serial_no.split("\n");
|
||||||
serial_nos = serial_nos.trim().split('\n');
|
for (var i = 0; i < serialnos.length; i++) {
|
||||||
|
if (serialnos[i] != "") {
|
||||||
// Trim each string and push unique string to new list
|
valid_serial_nos.push(serialnos[i]);
|
||||||
for (var x=0; x<=serial_nos.length - 1; x++) {
|
|
||||||
if (serial_nos[x].trim() != "" && valid_serial_nos.indexOf(serial_nos[x].trim()) == -1) {
|
|
||||||
valid_serial_nos.push(serial_nos[x].trim());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the new list to the serial no. field in grid with each in new line
|
|
||||||
item.serial_no = valid_serial_nos.join('\n');
|
|
||||||
item.conversion_factor = item.conversion_factor || 1;
|
item.conversion_factor = item.conversion_factor || 1;
|
||||||
|
|
||||||
refresh_field("serial_no", item.name, item.parentfield);
|
refresh_field("serial_no", item.name, item.parentfield);
|
||||||
@ -1209,7 +1203,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
|
|
||||||
calculate_stock_uom_rate: function(doc, cdt, cdn) {
|
calculate_stock_uom_rate: function(doc, cdt, cdn) {
|
||||||
let item = frappe.get_doc(cdt, cdn);
|
let item = frappe.get_doc(cdt, cdn);
|
||||||
item.stock_uom_rate = flt(item.rate)/flt(item.conversion_factor);
|
item.stock_uom_rate = flt(item.rate)/flt(item.conversion_factor);
|
||||||
refresh_field("stock_uom_rate", item.name, item.parentfield);
|
refresh_field("stock_uom_rate", item.name, item.parentfield);
|
||||||
},
|
},
|
||||||
service_stop_date: function(frm, cdt, cdn) {
|
service_stop_date: function(frm, cdt, cdn) {
|
||||||
@ -1538,7 +1532,10 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
if(k=="price_list_rate") {
|
if(k=="price_list_rate") {
|
||||||
if(flt(v) != flt(d.price_list_rate)) price_list_rate_changed = true;
|
if(flt(v) != flt(d.price_list_rate)) price_list_rate_changed = true;
|
||||||
}
|
}
|
||||||
frappe.model.set_value(d.doctype, d.name, k, v);
|
|
||||||
|
if (k !== 'free_item_data') {
|
||||||
|
frappe.model.set_value(d.doctype, d.name, k, v);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1550,7 +1547,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (d.free_item_data) {
|
if (d.free_item_data) {
|
||||||
me.apply_product_discount(d.free_item_data);
|
me.apply_product_discount(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (d.apply_rule_on_other_items) {
|
if (d.apply_rule_on_other_items) {
|
||||||
@ -1584,20 +1581,31 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
apply_product_discount: function(free_item_data) {
|
apply_product_discount: function(args) {
|
||||||
const items = this.frm.doc.items.filter(d => (d.item_code == free_item_data.item_code
|
const items = this.frm.doc.items.filter(d => (d.is_free_item)) || [];
|
||||||
&& d.is_free_item)) || [];
|
|
||||||
|
|
||||||
if (!items.length) {
|
const exist_items = items.map(row => (row.item_code, row.pricing_rules));
|
||||||
let row_to_modify = frappe.model.add_child(this.frm.doc,
|
|
||||||
this.frm.doc.doctype + ' Item', 'items');
|
|
||||||
|
|
||||||
for (let key in free_item_data) {
|
args.free_item_data.forEach(pr_row => {
|
||||||
row_to_modify[key] = free_item_data[key];
|
let row_to_modify = {};
|
||||||
|
if (!items || !in_list(exist_items, (pr_row.item_code, pr_row.pricing_rules))) {
|
||||||
|
|
||||||
|
row_to_modify = frappe.model.add_child(this.frm.doc,
|
||||||
|
this.frm.doc.doctype + ' Item', 'items');
|
||||||
|
|
||||||
|
} else if(items) {
|
||||||
|
row_to_modify = items.filter(d => (d.item_code === pr_row.item_code
|
||||||
|
&& d.pricing_rules === pr_row.pricing_rules))[0];
|
||||||
}
|
}
|
||||||
} if (items && items.length && free_item_data) {
|
|
||||||
items[0].qty = free_item_data.qty
|
for (let key in pr_row) {
|
||||||
}
|
row_to_modify[key] = pr_row[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// free_item_data is a temporary variable
|
||||||
|
args.free_item_data = '';
|
||||||
|
refresh_field('items');
|
||||||
},
|
},
|
||||||
|
|
||||||
apply_price_list: function(item, reset_plc_conversion) {
|
apply_price_list: function(item, reset_plc_conversion) {
|
||||||
|
|||||||
@ -109,7 +109,7 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{__("Suppliies made to Composition Taxable Persons")}}</td>
|
<td>{{__("Supplies made to Composition Taxable Persons")}}</td>
|
||||||
<td class="right">
|
<td class="right">
|
||||||
{% for row in data.inter_sup.comp_details %}
|
{% for row in data.inter_sup.comp_details %}
|
||||||
{% if row %}
|
{% if row %}
|
||||||
|
|||||||
@ -172,7 +172,6 @@ class GSTR3BReport(Document):
|
|||||||
self.json_output = frappe.as_json(self.report_dict)
|
self.json_output = frappe.as_json(self.report_dict)
|
||||||
|
|
||||||
def set_inward_nil_exempt(self, inward_nil_exempt):
|
def set_inward_nil_exempt(self, inward_nil_exempt):
|
||||||
|
|
||||||
self.report_dict["inward_sup"]["isup_details"][0]["inter"] = flt(inward_nil_exempt.get("gst").get("inter"), 2)
|
self.report_dict["inward_sup"]["isup_details"][0]["inter"] = flt(inward_nil_exempt.get("gst").get("inter"), 2)
|
||||||
self.report_dict["inward_sup"]["isup_details"][0]["intra"] = flt(inward_nil_exempt.get("gst").get("intra"), 2)
|
self.report_dict["inward_sup"]["isup_details"][0]["intra"] = flt(inward_nil_exempt.get("gst").get("intra"), 2)
|
||||||
self.report_dict["inward_sup"]["isup_details"][1]["inter"] = flt(inward_nil_exempt.get("non_gst").get("inter"), 2)
|
self.report_dict["inward_sup"]["isup_details"][1]["inter"] = flt(inward_nil_exempt.get("non_gst").get("inter"), 2)
|
||||||
@ -238,7 +237,6 @@ class GSTR3BReport(Document):
|
|||||||
self.report_dict[supply_type][supply_category]["txval"] += flt(txval, 2)
|
self.report_dict[supply_type][supply_category]["txval"] += flt(txval, 2)
|
||||||
|
|
||||||
def set_inter_state_supply(self, inter_state_supply):
|
def set_inter_state_supply(self, inter_state_supply):
|
||||||
|
|
||||||
osup_det = self.report_dict["sup_details"]["osup_det"]
|
osup_det = self.report_dict["sup_details"]["osup_det"]
|
||||||
|
|
||||||
for key, value in iteritems(inter_state_supply):
|
for key, value in iteritems(inter_state_supply):
|
||||||
@ -349,13 +347,20 @@ class GSTR3BReport(Document):
|
|||||||
return inter_state_supply_details
|
return inter_state_supply_details
|
||||||
|
|
||||||
def get_inward_nil_exempt(self, state):
|
def get_inward_nil_exempt(self, state):
|
||||||
|
|
||||||
inward_nil_exempt = frappe.db.sql(""" select p.place_of_supply, sum(i.base_amount) as base_amount,
|
inward_nil_exempt = frappe.db.sql(""" select p.place_of_supply, sum(i.base_amount) as base_amount,
|
||||||
i.is_nil_exempt, i.is_non_gst from `tabPurchase Invoice` p , `tabPurchase Invoice Item` i
|
i.is_nil_exempt, i.is_non_gst from `tabPurchase Invoice` p , `tabPurchase Invoice Item` i
|
||||||
where p.docstatus = 1 and p.name = i.parent
|
where p.docstatus = 1 and p.name = i.parent
|
||||||
and i.is_nil_exempt = 1 or i.is_non_gst = 1 and
|
and p.gst_category != 'Registered Composition'
|
||||||
|
and (i.is_nil_exempt = 1 or i.is_non_gst = 1) and
|
||||||
month(p.posting_date) = %s and year(p.posting_date) = %s and p.company = %s and p.company_gstin = %s
|
month(p.posting_date) = %s and year(p.posting_date) = %s and p.company = %s and p.company_gstin = %s
|
||||||
group by p.place_of_supply """, (self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)
|
group by p.place_of_supply, i.is_nil_exempt, i.is_non_gst""", (self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)
|
||||||
|
|
||||||
|
inward_nil_exempt += frappe.db.sql("""SELECT sum(base_net_total) as base_amount, gst_category, place_of_supply
|
||||||
|
FROM `tabPurchase Invoice`
|
||||||
|
WHERE docstatus = 1 and gst_category = 'Registered Composition'
|
||||||
|
and month(posting_date) = %s and year(posting_date) = %s
|
||||||
|
and company = %s and company_gstin = %s
|
||||||
|
group by place_of_supply""", (self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)
|
||||||
|
|
||||||
inward_nil_exempt_details = {
|
inward_nil_exempt_details = {
|
||||||
"gst": {
|
"gst": {
|
||||||
@ -370,9 +375,11 @@ class GSTR3BReport(Document):
|
|||||||
|
|
||||||
for d in inward_nil_exempt:
|
for d in inward_nil_exempt:
|
||||||
if d.place_of_supply:
|
if d.place_of_supply:
|
||||||
if d.is_nil_exempt == 1 and state == d.place_of_supply.split("-")[1]:
|
if (d.is_nil_exempt == 1 or d.get('gst_category') == 'Registered Composition') \
|
||||||
|
and state == d.place_of_supply.split("-")[1]:
|
||||||
inward_nil_exempt_details["gst"]["intra"] += d.base_amount
|
inward_nil_exempt_details["gst"]["intra"] += d.base_amount
|
||||||
elif d.is_nil_exempt == 1 and state != d.place_of_supply.split("-")[1]:
|
elif (d.is_nil_exempt == 1 or d.get('gst_category') == 'Registered Composition') \
|
||||||
|
and state != d.place_of_supply.split("-")[1]:
|
||||||
inward_nil_exempt_details["gst"]["inter"] += d.base_amount
|
inward_nil_exempt_details["gst"]["inter"] += d.base_amount
|
||||||
elif d.is_non_gst == 1 and state == d.place_of_supply.split("-")[1]:
|
elif d.is_non_gst == 1 and state == d.place_of_supply.split("-")[1]:
|
||||||
inward_nil_exempt_details["non_gst"]["intra"] += d.base_amount
|
inward_nil_exempt_details["non_gst"]["intra"] += d.base_amount
|
||||||
|
|||||||
@ -64,7 +64,7 @@ class TestGSTR3BReport(unittest.TestCase):
|
|||||||
self.assertEqual(output["sup_details"]["osup_zero"]["iamt"], 18),
|
self.assertEqual(output["sup_details"]["osup_zero"]["iamt"], 18),
|
||||||
self.assertEqual(output["inter_sup"]["unreg_details"][0]["iamt"], 18),
|
self.assertEqual(output["inter_sup"]["unreg_details"][0]["iamt"], 18),
|
||||||
self.assertEqual(output["sup_details"]["osup_nil_exmp"]["txval"], 100),
|
self.assertEqual(output["sup_details"]["osup_nil_exmp"]["txval"], 100),
|
||||||
self.assertEqual(output["inward_sup"]["isup_details"][0]["inter"], 250)
|
self.assertEqual(output["inward_sup"]["isup_details"][0]["intra"], 250)
|
||||||
self.assertEqual(output["itc_elg"]["itc_avl"][4]["samt"], 22.50)
|
self.assertEqual(output["itc_elg"]["itc_avl"][4]["samt"], 22.50)
|
||||||
self.assertEqual(output["itc_elg"]["itc_avl"][4]["camt"], 22.50)
|
self.assertEqual(output["itc_elg"]["itc_avl"][4]["camt"], 22.50)
|
||||||
|
|
||||||
@ -228,6 +228,19 @@ def create_purchase_invoices():
|
|||||||
|
|
||||||
pi1.submit()
|
pi1.submit()
|
||||||
|
|
||||||
|
pi2 = make_purchase_invoice(company="_Test Company GST",
|
||||||
|
customer = '_Test Registered Supplier',
|
||||||
|
currency = 'INR',
|
||||||
|
item = 'Milk',
|
||||||
|
warehouse = 'Finished Goods - _GST',
|
||||||
|
expense_account = 'Cost of Goods Sold - _GST',
|
||||||
|
cost_center = 'Main - _GST',
|
||||||
|
rate=250,
|
||||||
|
qty=1,
|
||||||
|
do_not_save=1
|
||||||
|
)
|
||||||
|
pi2.submit()
|
||||||
|
|
||||||
def make_suppliers():
|
def make_suppliers():
|
||||||
if not frappe.db.exists("Supplier", "_Test Registered Supplier"):
|
if not frappe.db.exists("Supplier", "_Test Registered Supplier"):
|
||||||
frappe.get_doc({
|
frappe.get_doc({
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
erpnext.setup_einvoice_actions = (doctype) => {
|
erpnext.setup_einvoice_actions = (doctype) => {
|
||||||
frappe.ui.form.on(doctype, {
|
frappe.ui.form.on(doctype, {
|
||||||
async refresh(frm) {
|
async refresh(frm) {
|
||||||
const einvoicing_enabled = await frappe.db.get_single_value("E Invoice Settings", "enable");
|
const { message } = await frappe.db.get_value("E Invoice Settings", "E Invoice Settings", "enable");
|
||||||
|
const einvoicing_enabled = cint(message.enable);
|
||||||
const supply_type = frm.doc.gst_category;
|
const supply_type = frm.doc.gst_category;
|
||||||
const valid_supply_type = ['Registered Regular', 'SEZ', 'Overseas', 'Deemed Export'].includes(supply_type);
|
const valid_supply_type = ['Registered Regular', 'SEZ', 'Overseas', 'Deemed Export'].includes(supply_type);
|
||||||
const company_transaction = frm.doc.billing_address_gstin == frm.doc.company_gstin;
|
const company_transaction = frm.doc.billing_address_gstin == frm.doc.company_gstin;
|
||||||
|
|||||||
@ -719,25 +719,12 @@ def update_grand_total_for_rcm(doc, method):
|
|||||||
if country != 'India':
|
if country != 'India':
|
||||||
return
|
return
|
||||||
|
|
||||||
if not doc.total_taxes_and_charges:
|
gst_tax, base_gst_tax = get_gst_tax_amount(doc)
|
||||||
|
|
||||||
|
if not base_gst_tax:
|
||||||
return
|
return
|
||||||
|
|
||||||
if doc.reverse_charge == 'Y':
|
if doc.reverse_charge == 'Y':
|
||||||
gst_accounts = get_gst_accounts(doc.company)
|
|
||||||
gst_account_list = gst_accounts.get('cgst_account') + gst_accounts.get('sgst_account') \
|
|
||||||
+ gst_accounts.get('igst_account')
|
|
||||||
|
|
||||||
base_gst_tax = 0
|
|
||||||
gst_tax = 0
|
|
||||||
|
|
||||||
for tax in doc.get('taxes'):
|
|
||||||
if tax.category not in ("Total", "Valuation and Total"):
|
|
||||||
continue
|
|
||||||
|
|
||||||
if flt(tax.base_tax_amount_after_discount_amount) and tax.account_head in gst_account_list:
|
|
||||||
base_gst_tax += tax.base_tax_amount_after_discount_amount
|
|
||||||
gst_tax += tax.tax_amount_after_discount_amount
|
|
||||||
|
|
||||||
doc.taxes_and_charges_added -= gst_tax
|
doc.taxes_and_charges_added -= gst_tax
|
||||||
doc.total_taxes_and_charges -= gst_tax
|
doc.total_taxes_and_charges -= gst_tax
|
||||||
doc.base_taxes_and_charges_added -= base_gst_tax
|
doc.base_taxes_and_charges_added -= base_gst_tax
|
||||||
@ -771,7 +758,9 @@ def make_regional_gl_entries(gl_entries, doc):
|
|||||||
if country != 'India':
|
if country != 'India':
|
||||||
return gl_entries
|
return gl_entries
|
||||||
|
|
||||||
if not doc.total_taxes_and_charges:
|
gst_tax, base_gst_tax = get_gst_tax_amount(doc)
|
||||||
|
|
||||||
|
if not base_gst_tax:
|
||||||
return gl_entries
|
return gl_entries
|
||||||
|
|
||||||
if doc.reverse_charge == 'Y':
|
if doc.reverse_charge == 'Y':
|
||||||
@ -802,6 +791,24 @@ def make_regional_gl_entries(gl_entries, doc):
|
|||||||
|
|
||||||
return gl_entries
|
return gl_entries
|
||||||
|
|
||||||
|
def get_gst_tax_amount(doc):
|
||||||
|
gst_accounts = get_gst_accounts(doc.company)
|
||||||
|
gst_account_list = gst_accounts.get('cgst_account', []) + gst_accounts.get('sgst_account', []) \
|
||||||
|
+ gst_accounts.get('igst_account', [])
|
||||||
|
|
||||||
|
base_gst_tax = 0
|
||||||
|
gst_tax = 0
|
||||||
|
|
||||||
|
for tax in doc.get('taxes'):
|
||||||
|
if tax.category not in ("Total", "Valuation and Total"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if flt(tax.base_tax_amount_after_discount_amount) and tax.account_head in gst_account_list:
|
||||||
|
base_gst_tax += tax.base_tax_amount_after_discount_amount
|
||||||
|
gst_tax += tax.tax_amount_after_discount_amount
|
||||||
|
|
||||||
|
return gst_tax, base_gst_tax
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_regional_round_off_accounts(company, account_list):
|
def get_regional_round_off_accounts(company, account_list):
|
||||||
country = frappe.get_cached_value('Company', company, 'country')
|
country = frappe.get_cached_value('Company', company, 'country')
|
||||||
|
|||||||
@ -44,7 +44,7 @@ class Gstr2Report(Gstr1Report):
|
|||||||
for inv, items_based_on_rate in self.items_based_on_tax_rate.items():
|
for inv, items_based_on_rate in self.items_based_on_tax_rate.items():
|
||||||
invoice_details = self.invoices.get(inv)
|
invoice_details = self.invoices.get(inv)
|
||||||
for rate, items in items_based_on_rate.items():
|
for rate, items in items_based_on_rate.items():
|
||||||
if rate:
|
if rate or invoice_details.get('gst_category') == 'Registered Composition':
|
||||||
if inv not in self.igst_invoices:
|
if inv not in self.igst_invoices:
|
||||||
rate = rate / 2
|
rate = rate / 2
|
||||||
row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, items)
|
row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, items)
|
||||||
@ -86,7 +86,7 @@ class Gstr2Report(Gstr1Report):
|
|||||||
conditions += opts[1]
|
conditions += opts[1]
|
||||||
|
|
||||||
if self.filters.get("type_of_business") == "B2B":
|
if self.filters.get("type_of_business") == "B2B":
|
||||||
conditions += "and ifnull(gst_category, '') in ('Registered Regular', 'Deemed Export', 'SEZ') and is_return != 1 "
|
conditions += "and ifnull(gst_category, '') in ('Registered Regular', 'Deemed Export', 'SEZ', 'Registered Composition') and is_return != 1 "
|
||||||
|
|
||||||
elif self.filters.get("type_of_business") == "CDNR":
|
elif self.filters.get("type_of_business") == "CDNR":
|
||||||
conditions += """ and is_return = 1 """
|
conditions += """ and is_return = 1 """
|
||||||
|
|||||||
@ -212,7 +212,8 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"ignore_user_permissions": 1,
|
"ignore_user_permissions": 1,
|
||||||
"label": "Represents Company",
|
"label": "Represents Company",
|
||||||
"options": "Company"
|
"options": "Company",
|
||||||
|
"unique": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "represents_company",
|
"depends_on": "represents_company",
|
||||||
|
|||||||
@ -93,6 +93,10 @@ erpnext.PointOfSale.Controller = class {
|
|||||||
})
|
})
|
||||||
return frappe.utils.play_sound("error");
|
return frappe.utils.play_sound("error");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// filter balance details for empty rows
|
||||||
|
balance_details = balance_details.filter(d => d.mode_of_payment);
|
||||||
|
|
||||||
const method = "erpnext.selling.page.point_of_sale.point_of_sale.create_opening_voucher";
|
const method = "erpnext.selling.page.point_of_sale.point_of_sale.create_opening_voucher";
|
||||||
const res = await frappe.call({ method, args: { pos_profile, company, balance_details }, freeze:true });
|
const res = await frappe.call({ method, args: { pos_profile, company, balance_details }, freeze:true });
|
||||||
!res.exc && me.prepare_app_defaults(res.message);
|
!res.exc && me.prepare_app_defaults(res.message);
|
||||||
|
|||||||
@ -259,6 +259,7 @@ erpnext.company.setup_queries = function(frm) {
|
|||||||
["default_payroll_payable_account", {"root_type": "Liability"}],
|
["default_payroll_payable_account", {"root_type": "Liability"}],
|
||||||
["round_off_account", {"root_type": "Expense"}],
|
["round_off_account", {"root_type": "Expense"}],
|
||||||
["write_off_account", {"root_type": "Expense"}],
|
["write_off_account", {"root_type": "Expense"}],
|
||||||
|
["default_discount_account", {}],
|
||||||
["discount_allowed_account", {"root_type": "Expense"}],
|
["discount_allowed_account", {"root_type": "Expense"}],
|
||||||
["discount_received_account", {"root_type": "Income"}],
|
["discount_received_account", {"root_type": "Income"}],
|
||||||
["exchange_gain_loss_account", {"root_type": "Expense"}],
|
["exchange_gain_loss_account", {"root_type": "Expense"}],
|
||||||
@ -275,7 +276,7 @@ erpnext.company.setup_queries = function(frm) {
|
|||||||
["expenses_included_in_asset_valuation", {"account_type": "Expenses Included In Asset Valuation"}],
|
["expenses_included_in_asset_valuation", {"account_type": "Expenses Included In Asset Valuation"}],
|
||||||
["capital_work_in_progress_account", {"account_type": "Capital Work in Progress"}],
|
["capital_work_in_progress_account", {"account_type": "Capital Work in Progress"}],
|
||||||
["asset_received_but_not_billed", {"account_type": "Asset Received But Not Billed"}],
|
["asset_received_but_not_billed", {"account_type": "Asset Received But Not Billed"}],
|
||||||
["unrealized_profit_loss_account", {"root_type": "Liability"}]
|
["unrealized_profit_loss_account", {"root_type": "Liability"},]
|
||||||
], function(i, v) {
|
], function(i, v) {
|
||||||
erpnext.company.set_custom_query(frm, v);
|
erpnext.company.set_custom_query(frm, v);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -59,6 +59,7 @@
|
|||||||
"default_deferred_expense_account",
|
"default_deferred_expense_account",
|
||||||
"default_payroll_payable_account",
|
"default_payroll_payable_account",
|
||||||
"default_expense_claim_payable_account",
|
"default_expense_claim_payable_account",
|
||||||
|
"default_discount_account",
|
||||||
"section_break_22",
|
"section_break_22",
|
||||||
"cost_center",
|
"cost_center",
|
||||||
"column_break_26",
|
"column_break_26",
|
||||||
@ -733,6 +734,12 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Unrealized Profit / Loss Account",
|
"label": "Unrealized Profit / Loss Account",
|
||||||
"options": "Account"
|
"options": "Account"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "default_discount_account",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Default Payment Discount Account",
|
||||||
|
"options": "Account"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-building",
|
"icon": "fa fa-building",
|
||||||
|
|||||||
@ -10,6 +10,7 @@ from frappe import msgprint, throw, _
|
|||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.model.naming import parse_naming_series
|
from frappe.model.naming import parse_naming_series
|
||||||
from frappe.permissions import get_doctypes_with_read
|
from frappe.permissions import get_doctypes_with_read
|
||||||
|
from frappe.core.doctype.doctype.doctype import validate_series
|
||||||
|
|
||||||
class NamingSeriesNotSetError(frappe.ValidationError): pass
|
class NamingSeriesNotSetError(frappe.ValidationError): pass
|
||||||
|
|
||||||
@ -126,7 +127,7 @@ class NamingSeries(Document):
|
|||||||
dt = frappe.get_doc("DocType", self.select_doc_for_series)
|
dt = frappe.get_doc("DocType", self.select_doc_for_series)
|
||||||
options = self.scrub_options_list(self.set_options.split("\n"))
|
options = self.scrub_options_list(self.set_options.split("\n"))
|
||||||
for series in options:
|
for series in options:
|
||||||
dt.validate_series(series)
|
validate_series(dt, series)
|
||||||
for i in sr:
|
for i in sr:
|
||||||
if i[0]:
|
if i[0]:
|
||||||
existing_series = [d.split('.')[0] for d in i[0].split("\n")]
|
existing_series = [d.split('.')[0] for d in i[0].split("\n")]
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe, erpnext
|
import frappe, erpnext
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import cint, get_link_to_form
|
from frappe.utils import cint, get_link_to_form, add_to_date, today
|
||||||
from erpnext.stock.stock_ledger import repost_future_sle
|
from erpnext.stock.stock_ledger import repost_future_sle
|
||||||
from erpnext.accounts.utils import update_gl_entries_after, check_if_stock_and_account_balance_synced
|
from erpnext.accounts.utils import update_gl_entries_after, check_if_stock_and_account_balance_synced
|
||||||
from frappe.utils.user import get_users_with_role
|
from frappe.utils.user import get_users_with_role
|
||||||
@ -29,7 +29,7 @@ class RepostItemValuation(Document):
|
|||||||
self.company = frappe.get_cached_value(self.voucher_type, self.voucher_no, "company")
|
self.company = frappe.get_cached_value(self.voucher_type, self.voucher_no, "company")
|
||||||
elif self.warehouse:
|
elif self.warehouse:
|
||||||
self.company = frappe.get_cached_value("Warehouse", self.warehouse, "company")
|
self.company = frappe.get_cached_value("Warehouse", self.warehouse, "company")
|
||||||
|
|
||||||
def set_status(self, status=None):
|
def set_status(self, status=None):
|
||||||
if not status:
|
if not status:
|
||||||
status = 'Queued'
|
status = 'Queued'
|
||||||
@ -54,7 +54,6 @@ def repost(doc):
|
|||||||
|
|
||||||
repost_sl_entries(doc)
|
repost_sl_entries(doc)
|
||||||
repost_gl_entries(doc)
|
repost_gl_entries(doc)
|
||||||
check_if_stock_and_account_balance_synced(doc.posting_date, doc.company)
|
|
||||||
|
|
||||||
doc.set_status('Completed')
|
doc.set_status('Completed')
|
||||||
except Exception:
|
except Exception:
|
||||||
@ -103,7 +102,7 @@ def notify_error_to_stock_managers(doc, traceback):
|
|||||||
recipients = get_users_with_role("Stock Manager")
|
recipients = get_users_with_role("Stock Manager")
|
||||||
if not recipients:
|
if not recipients:
|
||||||
get_users_with_role("System Manager")
|
get_users_with_role("System Manager")
|
||||||
|
|
||||||
subject = _("Error while reposting item valuation")
|
subject = _("Error while reposting item valuation")
|
||||||
message = (_("Hi,") + "<br>"
|
message = (_("Hi,") + "<br>"
|
||||||
+ _("An error has been appeared while reposting item valuation via {0}")
|
+ _("An error has been appeared while reposting item valuation via {0}")
|
||||||
@ -112,4 +111,24 @@ def notify_error_to_stock_managers(doc, traceback):
|
|||||||
)
|
)
|
||||||
frappe.sendmail(recipients=recipients, subject=subject, message=message)
|
frappe.sendmail(recipients=recipients, subject=subject, message=message)
|
||||||
|
|
||||||
|
def repost_entries():
|
||||||
|
riv_entries = get_repost_item_valuation_entries()
|
||||||
|
|
||||||
|
for row in riv_entries:
|
||||||
|
doc = frappe.get_cached_doc('Repost Item Valuation', row.name)
|
||||||
|
repost(doc)
|
||||||
|
|
||||||
|
riv_entries = get_repost_item_valuation_entries()
|
||||||
|
if riv_entries:
|
||||||
|
return
|
||||||
|
|
||||||
|
for d in frappe.get_all('Company', filters= {'enable_perpetual_inventory': 1}):
|
||||||
|
check_if_stock_and_account_balance_synced(today(), d.name)
|
||||||
|
|
||||||
|
def get_repost_item_valuation_entries():
|
||||||
|
date = add_to_date(today(), hours=-12)
|
||||||
|
|
||||||
|
return frappe.db.sql(""" SELECT name from `tabRepost Item Valuation`
|
||||||
|
WHERE status != 'Completed' and creation <= %s and docstatus = 1
|
||||||
|
ORDER BY timestamp(posting_date, posting_time) asc, creation asc
|
||||||
|
""", date, as_dict=1)
|
||||||
@ -29,6 +29,8 @@ class StockReconciliation(StockController):
|
|||||||
self.remove_items_with_no_change()
|
self.remove_items_with_no_change()
|
||||||
self.validate_data()
|
self.validate_data()
|
||||||
self.validate_expense_account()
|
self.validate_expense_account()
|
||||||
|
self.validate_customer_provided_item()
|
||||||
|
self.set_zero_value_for_customer_provided_items()
|
||||||
self.set_total_qty_and_amount()
|
self.set_total_qty_and_amount()
|
||||||
self.validate_putaway_capacity()
|
self.validate_putaway_capacity()
|
||||||
|
|
||||||
@ -217,7 +219,7 @@ class StockReconciliation(StockController):
|
|||||||
if row.valuation_rate in ("", None):
|
if row.valuation_rate in ("", None):
|
||||||
row.valuation_rate = previous_sle.get("valuation_rate", 0)
|
row.valuation_rate = previous_sle.get("valuation_rate", 0)
|
||||||
|
|
||||||
if row.qty and not row.valuation_rate:
|
if row.qty and not row.valuation_rate and not row.allow_zero_valuation_rate:
|
||||||
frappe.throw(_("Valuation Rate required for Item {0} at row {1}").format(row.item_code, row.idx))
|
frappe.throw(_("Valuation Rate required for Item {0} at row {1}").format(row.item_code, row.idx))
|
||||||
|
|
||||||
if ((previous_sle and row.qty == previous_sle.get("qty_after_transaction")
|
if ((previous_sle and row.qty == previous_sle.get("qty_after_transaction")
|
||||||
@ -436,6 +438,20 @@ class StockReconciliation(StockController):
|
|||||||
if frappe.db.get_value("Account", self.expense_account, "report_type") == "Profit and Loss":
|
if frappe.db.get_value("Account", self.expense_account, "report_type") == "Profit and Loss":
|
||||||
frappe.throw(_("Difference Account must be a Asset/Liability type account, since this Stock Reconciliation is an Opening Entry"), OpeningEntryAccountError)
|
frappe.throw(_("Difference Account must be a Asset/Liability type account, since this Stock Reconciliation is an Opening Entry"), OpeningEntryAccountError)
|
||||||
|
|
||||||
|
def set_zero_value_for_customer_provided_items(self):
|
||||||
|
changed_any_values = False
|
||||||
|
|
||||||
|
for d in self.get('items'):
|
||||||
|
is_customer_item = frappe.db.get_value('Item', d.item_code, 'is_customer_provided_item')
|
||||||
|
if is_customer_item and d.valuation_rate:
|
||||||
|
d.valuation_rate = 0.0
|
||||||
|
changed_any_values = True
|
||||||
|
|
||||||
|
if changed_any_values:
|
||||||
|
msgprint(_("Valuation rate for customer provided items has been set to zero."),
|
||||||
|
title=_("Note"), indicator="blue")
|
||||||
|
|
||||||
|
|
||||||
def set_total_qty_and_amount(self):
|
def set_total_qty_and_amount(self):
|
||||||
for d in self.get("items"):
|
for d in self.get("items"):
|
||||||
d.amount = flt(d.qty, d.precision("qty")) * flt(d.valuation_rate, d.precision("valuation_rate"))
|
d.amount = flt(d.qty, d.precision("qty")) * flt(d.valuation_rate, d.precision("valuation_rate"))
|
||||||
@ -531,4 +547,4 @@ def get_difference_account(purpose, company):
|
|||||||
account = frappe.db.get_value('Account', {'is_group': 0,
|
account = frappe.db.get_value('Account', {'is_group': 0,
|
||||||
'company': company, 'account_type': 'Temporary'}, 'name')
|
'company': company, 'account_type': 'Temporary'}, 'name')
|
||||||
|
|
||||||
return account
|
return account
|
||||||
|
|||||||
@ -193,6 +193,16 @@ class TestStockReconciliation(unittest.TestCase):
|
|||||||
stock_doc = frappe.get_doc("Stock Reconciliation", d)
|
stock_doc = frappe.get_doc("Stock Reconciliation", d)
|
||||||
stock_doc.cancel()
|
stock_doc.cancel()
|
||||||
|
|
||||||
|
def test_customer_provided_items(self):
|
||||||
|
item_code = 'Stock-Reco-customer-Item-100'
|
||||||
|
create_item(item_code, is_customer_provided_item = 1,
|
||||||
|
customer = '_Test Customer', is_purchase_item = 0)
|
||||||
|
|
||||||
|
sr = create_stock_reconciliation(item_code = item_code, qty = 10, rate = 420)
|
||||||
|
|
||||||
|
self.assertEqual(sr.get("items")[0].allow_zero_valuation_rate, 1)
|
||||||
|
self.assertEqual(sr.get("items")[0].valuation_rate, 0)
|
||||||
|
self.assertEqual(sr.get("items")[0].amount, 0)
|
||||||
|
|
||||||
def insert_existing_sle(warehouse):
|
def insert_existing_sle(warehouse):
|
||||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
"qty",
|
"qty",
|
||||||
"valuation_rate",
|
"valuation_rate",
|
||||||
"amount",
|
"amount",
|
||||||
|
"allow_zero_valuation_rate",
|
||||||
"serial_no_and_batch_section",
|
"serial_no_and_batch_section",
|
||||||
"serial_no",
|
"serial_no",
|
||||||
"column_break_11",
|
"column_break_11",
|
||||||
@ -166,10 +167,19 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Batch No",
|
"label": "Batch No",
|
||||||
"options": "Batch"
|
"options": "Batch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fieldname": "allow_zero_valuation_rate",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Allow Zero Valuation Rate",
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2019-06-14 17:10:53.188305",
|
"links": [],
|
||||||
|
"modified": "2021-03-23 11:09:44.407157",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Stock Reconciliation Item",
|
"name": "Stock Reconciliation Item",
|
||||||
@ -179,4 +189,4 @@
|
|||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"track_changes": 1
|
"track_changes": 1
|
||||||
}
|
}
|
||||||
|
|||||||
@ -110,7 +110,7 @@ def get_item_details(args, doc=None, for_validate=False, overwrite_warehouse=Tru
|
|||||||
get_gross_profit(out)
|
get_gross_profit(out)
|
||||||
if args.doctype == 'Material Request':
|
if args.doctype == 'Material Request':
|
||||||
out.rate = args.rate or out.price_list_rate
|
out.rate = args.rate or out.price_list_rate
|
||||||
out.amount = flt(args.qty * out.rate)
|
out.amount = flt(args.qty) * flt(out.rate)
|
||||||
|
|
||||||
return out
|
return out
|
||||||
|
|
||||||
@ -314,7 +314,9 @@ def get_basic_details(args, item, overwrite_warehouse=True):
|
|||||||
"last_purchase_rate": item.last_purchase_rate if args.get("doctype") in ["Purchase Order"] else 0,
|
"last_purchase_rate": item.last_purchase_rate if args.get("doctype") in ["Purchase Order"] else 0,
|
||||||
"transaction_date": args.get("transaction_date"),
|
"transaction_date": args.get("transaction_date"),
|
||||||
"against_blanket_order": args.get("against_blanket_order"),
|
"against_blanket_order": args.get("against_blanket_order"),
|
||||||
"bom_no": item.get("default_bom")
|
"bom_no": item.get("default_bom"),
|
||||||
|
"weight_per_unit": args.get("weight_per_unit") or item.get("weight_per_unit"),
|
||||||
|
"weight_uom": args.get("weight_uom") or item.get("weight_uom")
|
||||||
})
|
})
|
||||||
|
|
||||||
if item.get("enable_deferred_revenue") or item.get("enable_deferred_expense"):
|
if item.get("enable_deferred_revenue") or item.get("enable_deferred_expense"):
|
||||||
@ -369,6 +371,9 @@ def get_basic_details(args, item, overwrite_warehouse=True):
|
|||||||
if meta.get_field("barcode"):
|
if meta.get_field("barcode"):
|
||||||
update_barcode_value(out)
|
update_barcode_value(out)
|
||||||
|
|
||||||
|
if out.get("weight_per_unit"):
|
||||||
|
out['total_weight'] = out.weight_per_unit * out.stock_qty
|
||||||
|
|
||||||
return out
|
return out
|
||||||
|
|
||||||
def get_item_warehouse(item, args, overwrite_warehouse, defaults={}):
|
def get_item_warehouse(item, args, overwrite_warehouse, defaults={}):
|
||||||
|
|||||||
@ -198,7 +198,7 @@ def get_item_warehouse_map(filters, sle):
|
|||||||
else:
|
else:
|
||||||
qty_diff = flt(d.actual_qty)
|
qty_diff = flt(d.actual_qty)
|
||||||
|
|
||||||
value_diff = flt(d.stock_value) - flt(qty_dict.bal_val)
|
value_diff = flt(d.stock_value_difference)
|
||||||
|
|
||||||
if d.posting_date < from_date:
|
if d.posting_date < from_date:
|
||||||
qty_dict.opening_qty += qty_diff
|
qty_dict.opening_qty += qty_diff
|
||||||
|
|||||||
@ -260,8 +260,7 @@ class IssueSummary(object):
|
|||||||
self.issue_summary_data[value]['avg_user_resolution_time'] = entry.get('avg_user_resolution_time') or 0.0
|
self.issue_summary_data[value]['avg_user_resolution_time'] = entry.get('avg_user_resolution_time') or 0.0
|
||||||
|
|
||||||
def get_chart_data(self):
|
def get_chart_data(self):
|
||||||
if not self.data:
|
self.chart = []
|
||||||
return None
|
|
||||||
|
|
||||||
labels = []
|
labels = []
|
||||||
open_issues = []
|
open_issues = []
|
||||||
@ -310,8 +309,7 @@ class IssueSummary(object):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def get_report_summary(self):
|
def get_report_summary(self):
|
||||||
if not self.data:
|
self.report_summary = []
|
||||||
return None
|
|
||||||
|
|
||||||
open_issues = 0
|
open_issues = 0
|
||||||
replied = 0
|
replied = 0
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user