Merge branch 'develop' into common-party-acc
This commit is contained in:
commit
1db812ab9f
@ -9,19 +9,8 @@ import frappe
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
class TestFinanceBook(unittest.TestCase):
|
class TestFinanceBook(unittest.TestCase):
|
||||||
def create_finance_book(self):
|
|
||||||
if not frappe.db.exists("Finance Book", "_Test Finance Book"):
|
|
||||||
finance_book = frappe.get_doc({
|
|
||||||
"doctype": "Finance Book",
|
|
||||||
"finance_book_name": "_Test Finance Book"
|
|
||||||
}).insert()
|
|
||||||
else:
|
|
||||||
finance_book = frappe.get_doc("Finance Book", "_Test Finance Book")
|
|
||||||
|
|
||||||
return finance_book
|
|
||||||
|
|
||||||
def test_finance_book(self):
|
def test_finance_book(self):
|
||||||
finance_book = self.create_finance_book()
|
finance_book = create_finance_book()
|
||||||
|
|
||||||
# create jv entry
|
# create jv entry
|
||||||
jv = make_journal_entry("_Test Bank - _TC",
|
jv = make_journal_entry("_Test Bank - _TC",
|
||||||
@ -41,3 +30,14 @@ class TestFinanceBook(unittest.TestCase):
|
|||||||
|
|
||||||
for gl_entry in gl_entries:
|
for gl_entry in gl_entries:
|
||||||
self.assertEqual(gl_entry.finance_book, finance_book.name)
|
self.assertEqual(gl_entry.finance_book, finance_book.name)
|
||||||
|
|
||||||
|
def create_finance_book():
|
||||||
|
if not frappe.db.exists("Finance Book", "_Test Finance Book"):
|
||||||
|
finance_book = frappe.get_doc({
|
||||||
|
"doctype": "Finance Book",
|
||||||
|
"finance_book_name": "_Test Finance Book"
|
||||||
|
}).insert()
|
||||||
|
else:
|
||||||
|
finance_book = frappe.get_doc("Finance Book", "_Test Finance Book")
|
||||||
|
|
||||||
|
return finance_book
|
@ -533,8 +533,8 @@ frappe.ui.form.on('Payment Entry', {
|
|||||||
source_exchange_rate: function(frm) {
|
source_exchange_rate: function(frm) {
|
||||||
if (frm.doc.paid_amount) {
|
if (frm.doc.paid_amount) {
|
||||||
frm.set_value("base_paid_amount", flt(frm.doc.paid_amount) * flt(frm.doc.source_exchange_rate));
|
frm.set_value("base_paid_amount", flt(frm.doc.paid_amount) * flt(frm.doc.source_exchange_rate));
|
||||||
if(!frm.set_paid_amount_based_on_received_amount &&
|
// target exchange rate should always be same as source if both account currencies is same
|
||||||
(frm.doc.paid_from_account_currency == frm.doc.paid_to_account_currency)) {
|
if(frm.doc.paid_from_account_currency == frm.doc.paid_to_account_currency) {
|
||||||
frm.set_value("target_exchange_rate", frm.doc.source_exchange_rate);
|
frm.set_value("target_exchange_rate", frm.doc.source_exchange_rate);
|
||||||
frm.set_value("base_received_amount", frm.doc.base_paid_amount);
|
frm.set_value("base_received_amount", frm.doc.base_paid_amount);
|
||||||
}
|
}
|
||||||
|
@ -55,14 +55,17 @@ class PaymentEntry(AccountsController):
|
|||||||
self.validate_mandatory()
|
self.validate_mandatory()
|
||||||
self.validate_reference_documents()
|
self.validate_reference_documents()
|
||||||
self.set_tax_withholding()
|
self.set_tax_withholding()
|
||||||
self.apply_taxes()
|
|
||||||
self.set_amounts()
|
self.set_amounts()
|
||||||
|
self.validate_amounts()
|
||||||
|
self.apply_taxes()
|
||||||
|
self.set_amounts_after_tax()
|
||||||
self.clear_unallocated_reference_document_rows()
|
self.clear_unallocated_reference_document_rows()
|
||||||
self.validate_payment_against_negative_invoice()
|
self.validate_payment_against_negative_invoice()
|
||||||
self.validate_transaction_reference()
|
self.validate_transaction_reference()
|
||||||
self.set_title()
|
self.set_title()
|
||||||
self.set_remarks()
|
self.set_remarks()
|
||||||
self.validate_duplicate_entry()
|
self.validate_duplicate_entry()
|
||||||
|
self.validate_payment_type_with_outstanding()
|
||||||
self.validate_allocated_amount()
|
self.validate_allocated_amount()
|
||||||
self.validate_paid_invoices()
|
self.validate_paid_invoices()
|
||||||
self.ensure_supplier_is_not_blocked()
|
self.ensure_supplier_is_not_blocked()
|
||||||
@ -118,6 +121,11 @@ class PaymentEntry(AccountsController):
|
|||||||
if not self.get(field):
|
if not self.get(field):
|
||||||
self.set(field, bank_data.account)
|
self.set(field, bank_data.account)
|
||||||
|
|
||||||
|
def validate_payment_type_with_outstanding(self):
|
||||||
|
total_outstanding = sum(d.allocated_amount for d in self.get('references'))
|
||||||
|
if total_outstanding < 0 and self.party_type == 'Customer' and self.payment_type == 'Receive':
|
||||||
|
frappe.throw(_("Cannot receive from customer against negative outstanding"), title=_("Incorrect Payment Type"))
|
||||||
|
|
||||||
def validate_allocated_amount(self):
|
def validate_allocated_amount(self):
|
||||||
for d in self.get("references"):
|
for d in self.get("references"):
|
||||||
if (flt(d.allocated_amount))> 0:
|
if (flt(d.allocated_amount))> 0:
|
||||||
@ -236,7 +244,9 @@ class PaymentEntry(AccountsController):
|
|||||||
self.company_currency, self.posting_date)
|
self.company_currency, self.posting_date)
|
||||||
|
|
||||||
def set_target_exchange_rate(self, ref_doc=None):
|
def set_target_exchange_rate(self, ref_doc=None):
|
||||||
if self.paid_to and not self.target_exchange_rate:
|
if self.paid_from_account_currency == self.paid_to_account_currency:
|
||||||
|
self.target_exchange_rate = self.source_exchange_rate
|
||||||
|
elif self.paid_to and not self.target_exchange_rate:
|
||||||
if ref_doc:
|
if ref_doc:
|
||||||
if self.paid_to_account_currency == ref_doc.currency:
|
if self.paid_to_account_currency == ref_doc.currency:
|
||||||
self.target_exchange_rate = ref_doc.get("exchange_rate")
|
self.target_exchange_rate = ref_doc.get("exchange_rate")
|
||||||
@ -468,13 +478,22 @@ class PaymentEntry(AccountsController):
|
|||||||
def set_amounts(self):
|
def set_amounts(self):
|
||||||
self.set_received_amount()
|
self.set_received_amount()
|
||||||
self.set_amounts_in_company_currency()
|
self.set_amounts_in_company_currency()
|
||||||
self.set_amounts_after_tax()
|
|
||||||
self.set_total_allocated_amount()
|
self.set_total_allocated_amount()
|
||||||
self.set_unallocated_amount()
|
self.set_unallocated_amount()
|
||||||
self.set_difference_amount()
|
self.set_difference_amount()
|
||||||
|
|
||||||
|
def validate_amounts(self):
|
||||||
|
self.validate_received_amount()
|
||||||
|
|
||||||
|
def validate_received_amount(self):
|
||||||
|
if self.paid_from_account_currency == self.paid_to_account_currency:
|
||||||
|
if self.paid_amount != self.received_amount:
|
||||||
|
frappe.throw(_("Received Amount cannot be greater than Paid Amount"))
|
||||||
|
|
||||||
def set_received_amount(self):
|
def set_received_amount(self):
|
||||||
self.base_received_amount = self.base_paid_amount
|
self.base_received_amount = self.base_paid_amount
|
||||||
|
if self.paid_from_account_currency == self.paid_to_account_currency:
|
||||||
|
self.received_amount = self.paid_amount
|
||||||
|
|
||||||
def set_amounts_after_tax(self):
|
def set_amounts_after_tax(self):
|
||||||
applicable_tax = 0
|
applicable_tax = 0
|
||||||
|
@ -107,7 +107,7 @@ class TestPaymentEntry(unittest.TestCase):
|
|||||||
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank USD - _TC")
|
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank USD - _TC")
|
||||||
pe.reference_no = "1"
|
pe.reference_no = "1"
|
||||||
pe.reference_date = "2016-01-01"
|
pe.reference_date = "2016-01-01"
|
||||||
pe.target_exchange_rate = 50
|
pe.source_exchange_rate = 50
|
||||||
pe.insert()
|
pe.insert()
|
||||||
pe.submit()
|
pe.submit()
|
||||||
|
|
||||||
@ -154,7 +154,7 @@ class TestPaymentEntry(unittest.TestCase):
|
|||||||
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank USD - _TC")
|
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank USD - _TC")
|
||||||
pe.reference_no = "1"
|
pe.reference_no = "1"
|
||||||
pe.reference_date = "2016-01-01"
|
pe.reference_date = "2016-01-01"
|
||||||
pe.target_exchange_rate = 50
|
pe.source_exchange_rate = 50
|
||||||
pe.insert()
|
pe.insert()
|
||||||
pe.submit()
|
pe.submit()
|
||||||
|
|
||||||
@ -491,7 +491,7 @@ class TestPaymentEntry(unittest.TestCase):
|
|||||||
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank USD - _TC")
|
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank USD - _TC")
|
||||||
pe.reference_no = "1"
|
pe.reference_no = "1"
|
||||||
pe.reference_date = "2016-01-01"
|
pe.reference_date = "2016-01-01"
|
||||||
pe.target_exchange_rate = 55
|
pe.source_exchange_rate = 55
|
||||||
|
|
||||||
pe.append("deductions", {
|
pe.append("deductions", {
|
||||||
"account": "_Test Exchange Gain/Loss - _TC",
|
"account": "_Test Exchange Gain/Loss - _TC",
|
||||||
|
@ -50,9 +50,13 @@ class PeriodClosingVoucher(AccountsController):
|
|||||||
.format(pce[0][0], self.posting_date))
|
.format(pce[0][0], self.posting_date))
|
||||||
|
|
||||||
def make_gl_entries(self):
|
def make_gl_entries(self):
|
||||||
|
gl_entries = self.get_gl_entries()
|
||||||
|
if gl_entries:
|
||||||
|
from erpnext.accounts.general_ledger import make_gl_entries
|
||||||
|
make_gl_entries(gl_entries)
|
||||||
|
|
||||||
|
def get_gl_entries(self):
|
||||||
gl_entries = []
|
gl_entries = []
|
||||||
net_pl_balance = 0
|
|
||||||
|
|
||||||
pl_accounts = self.get_pl_balances()
|
pl_accounts = self.get_pl_balances()
|
||||||
|
|
||||||
for acc in pl_accounts:
|
for acc in pl_accounts:
|
||||||
@ -60,6 +64,7 @@ class PeriodClosingVoucher(AccountsController):
|
|||||||
gl_entries.append(self.get_gl_dict({
|
gl_entries.append(self.get_gl_dict({
|
||||||
"account": acc.account,
|
"account": acc.account,
|
||||||
"cost_center": acc.cost_center,
|
"cost_center": acc.cost_center,
|
||||||
|
"finance_book": acc.finance_book,
|
||||||
"account_currency": acc.account_currency,
|
"account_currency": acc.account_currency,
|
||||||
"debit_in_account_currency": abs(flt(acc.bal_in_account_currency)) if flt(acc.bal_in_account_currency) < 0 else 0,
|
"debit_in_account_currency": abs(flt(acc.bal_in_account_currency)) if flt(acc.bal_in_account_currency) < 0 else 0,
|
||||||
"debit": abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) < 0 else 0,
|
"debit": abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) < 0 else 0,
|
||||||
@ -67,35 +72,13 @@ class PeriodClosingVoucher(AccountsController):
|
|||||||
"credit": abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) > 0 else 0
|
"credit": abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) > 0 else 0
|
||||||
}, item=acc))
|
}, item=acc))
|
||||||
|
|
||||||
net_pl_balance += flt(acc.bal_in_company_currency)
|
if gl_entries:
|
||||||
|
gle_for_net_pl_bal = self.get_pnl_gl_entry(pl_accounts)
|
||||||
|
gl_entries += gle_for_net_pl_bal
|
||||||
|
|
||||||
if net_pl_balance:
|
return gl_entries
|
||||||
if self.cost_center_wise_pnl:
|
|
||||||
costcenter_wise_gl_entries = self.get_costcenter_wise_pnl_gl_entries(pl_accounts)
|
def get_pnl_gl_entry(self, pl_accounts):
|
||||||
gl_entries += costcenter_wise_gl_entries
|
|
||||||
else:
|
|
||||||
gl_entry = self.get_pnl_gl_entry(net_pl_balance)
|
|
||||||
gl_entries.append(gl_entry)
|
|
||||||
|
|
||||||
from erpnext.accounts.general_ledger import make_gl_entries
|
|
||||||
make_gl_entries(gl_entries)
|
|
||||||
|
|
||||||
def get_pnl_gl_entry(self, net_pl_balance):
|
|
||||||
cost_center = frappe.db.get_value("Company", self.company, "cost_center")
|
|
||||||
gl_entry = self.get_gl_dict({
|
|
||||||
"account": self.closing_account_head,
|
|
||||||
"debit_in_account_currency": abs(net_pl_balance) if net_pl_balance > 0 else 0,
|
|
||||||
"debit": abs(net_pl_balance) if net_pl_balance > 0 else 0,
|
|
||||||
"credit_in_account_currency": abs(net_pl_balance) if net_pl_balance < 0 else 0,
|
|
||||||
"credit": abs(net_pl_balance) if net_pl_balance < 0 else 0,
|
|
||||||
"cost_center": cost_center
|
|
||||||
})
|
|
||||||
|
|
||||||
self.update_default_dimensions(gl_entry)
|
|
||||||
|
|
||||||
return gl_entry
|
|
||||||
|
|
||||||
def get_costcenter_wise_pnl_gl_entries(self, pl_accounts):
|
|
||||||
company_cost_center = frappe.db.get_value("Company", self.company, "cost_center")
|
company_cost_center = frappe.db.get_value("Company", self.company, "cost_center")
|
||||||
gl_entries = []
|
gl_entries = []
|
||||||
|
|
||||||
@ -104,6 +87,7 @@ class PeriodClosingVoucher(AccountsController):
|
|||||||
gl_entry = self.get_gl_dict({
|
gl_entry = self.get_gl_dict({
|
||||||
"account": self.closing_account_head,
|
"account": self.closing_account_head,
|
||||||
"cost_center": acc.cost_center or company_cost_center,
|
"cost_center": acc.cost_center or company_cost_center,
|
||||||
|
"finance_book": acc.finance_book,
|
||||||
"account_currency": acc.account_currency,
|
"account_currency": acc.account_currency,
|
||||||
"debit_in_account_currency": abs(flt(acc.bal_in_account_currency)) if flt(acc.bal_in_account_currency) > 0 else 0,
|
"debit_in_account_currency": abs(flt(acc.bal_in_account_currency)) if flt(acc.bal_in_account_currency) > 0 else 0,
|
||||||
"debit": abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) > 0 else 0,
|
"debit": abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) > 0 else 0,
|
||||||
@ -130,7 +114,7 @@ class PeriodClosingVoucher(AccountsController):
|
|||||||
def get_pl_balances(self):
|
def get_pl_balances(self):
|
||||||
"""Get balance for dimension-wise pl accounts"""
|
"""Get balance for dimension-wise pl accounts"""
|
||||||
|
|
||||||
dimension_fields = ['t1.cost_center']
|
dimension_fields = ['t1.cost_center', 't1.finance_book']
|
||||||
|
|
||||||
self.accounting_dimensions = get_accounting_dimensions()
|
self.accounting_dimensions = get_accounting_dimensions()
|
||||||
for dimension in self.accounting_dimensions:
|
for dimension in self.accounting_dimensions:
|
||||||
|
@ -8,6 +8,7 @@ import frappe
|
|||||||
from frappe.utils import flt, today
|
from frappe.utils import flt, today
|
||||||
from erpnext.accounts.utils import get_fiscal_year, now
|
from erpnext.accounts.utils import get_fiscal_year, now
|
||||||
from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
|
from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
|
||||||
|
from erpnext.accounts.doctype.finance_book.test_finance_book import create_finance_book
|
||||||
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
||||||
|
|
||||||
class TestPeriodClosingVoucher(unittest.TestCase):
|
class TestPeriodClosingVoucher(unittest.TestCase):
|
||||||
@ -118,6 +119,58 @@ class TestPeriodClosingVoucher(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertTrue(pcv_gle, expected_gle)
|
self.assertTrue(pcv_gle, expected_gle)
|
||||||
|
|
||||||
|
def test_period_closing_with_finance_book_entries(self):
|
||||||
|
frappe.db.sql("delete from `tabGL Entry` where company='Test PCV Company'")
|
||||||
|
|
||||||
|
company = create_company()
|
||||||
|
surplus_account = create_account()
|
||||||
|
cost_center = create_cost_center("Test Cost Center 1")
|
||||||
|
|
||||||
|
create_sales_invoice(
|
||||||
|
company=company,
|
||||||
|
income_account="Sales - TPC",
|
||||||
|
expense_account="Cost of Goods Sold - TPC",
|
||||||
|
cost_center=cost_center,
|
||||||
|
rate=400,
|
||||||
|
debit_to="Debtors - TPC"
|
||||||
|
)
|
||||||
|
jv = make_journal_entry(
|
||||||
|
account1="Cash - TPC",
|
||||||
|
account2="Sales - TPC",
|
||||||
|
amount=400,
|
||||||
|
cost_center=cost_center,
|
||||||
|
posting_date=now()
|
||||||
|
)
|
||||||
|
jv.company = company
|
||||||
|
jv.finance_book = create_finance_book().name
|
||||||
|
jv.save()
|
||||||
|
jv.submit()
|
||||||
|
|
||||||
|
pcv = frappe.get_doc({
|
||||||
|
"transaction_date": today(),
|
||||||
|
"posting_date": today(),
|
||||||
|
"fiscal_year": get_fiscal_year(today())[0],
|
||||||
|
"company": company,
|
||||||
|
"closing_account_head": surplus_account,
|
||||||
|
"remarks": "Test",
|
||||||
|
"doctype": "Period Closing Voucher"
|
||||||
|
})
|
||||||
|
pcv.insert()
|
||||||
|
pcv.submit()
|
||||||
|
|
||||||
|
expected_gle = (
|
||||||
|
(surplus_account, 0.0, 400.0, ''),
|
||||||
|
(surplus_account, 0.0, 400.0, jv.finance_book),
|
||||||
|
('Sales - TPC', 400.0, 0.0, ''),
|
||||||
|
('Sales - TPC', 400.0, 0.0, jv.finance_book)
|
||||||
|
)
|
||||||
|
|
||||||
|
pcv_gle = frappe.db.sql("""
|
||||||
|
select account, debit, credit, finance_book from `tabGL Entry` where voucher_no=%s
|
||||||
|
""", (pcv.name))
|
||||||
|
|
||||||
|
self.assertTrue(pcv_gle, expected_gle)
|
||||||
|
|
||||||
def make_period_closing_voucher(self):
|
def make_period_closing_voucher(self):
|
||||||
pcv = frappe.get_doc({
|
pcv = frappe.get_doc({
|
||||||
"doctype": "Period Closing Voucher",
|
"doctype": "Period Closing Voucher",
|
||||||
|
@ -85,9 +85,15 @@ class TestPOSClosingEntry(unittest.TestCase):
|
|||||||
|
|
||||||
pcv_doc.load_from_db()
|
pcv_doc.load_from_db()
|
||||||
pcv_doc.cancel()
|
pcv_doc.cancel()
|
||||||
si_doc.load_from_db()
|
|
||||||
|
cancelled_invoice = frappe.db.get_value(
|
||||||
|
'POS Invoice Merge Log', {'pos_closing_entry': pcv_doc.name},
|
||||||
|
'consolidated_invoice'
|
||||||
|
)
|
||||||
|
docstatus = frappe.db.get_value("Sales Invoice", cancelled_invoice, 'docstatus')
|
||||||
|
self.assertEqual(docstatus, 2)
|
||||||
|
|
||||||
pos_inv1.load_from_db()
|
pos_inv1.load_from_db()
|
||||||
self.assertEqual(si_doc.docstatus, 2)
|
|
||||||
self.assertEqual(pos_inv1.status, 'Paid')
|
self.assertEqual(pos_inv1.status, 'Paid')
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ erpnext.selling.POSInvoiceController = class POSInvoiceController extends erpnex
|
|||||||
|
|
||||||
onload(doc) {
|
onload(doc) {
|
||||||
super.onload();
|
super.onload();
|
||||||
this.frm.ignore_doctypes_on_cancel_all = ['POS Invoice Merge Log'];
|
this.frm.ignore_doctypes_on_cancel_all = ['POS Invoice Merge Log', 'POS Closing Entry'];
|
||||||
if(doc.__islocal && doc.is_pos && frappe.get_route_str() !== 'point-of-sale') {
|
if(doc.__islocal && doc.is_pos && frappe.get_route_str() !== 'point-of-sale') {
|
||||||
this.frm.script_manager.trigger("is_pos");
|
this.frm.script_manager.trigger("is_pos");
|
||||||
this.frm.refresh_fields();
|
this.frm.refresh_fields();
|
||||||
@ -111,16 +111,12 @@ erpnext.selling.POSInvoiceController = class POSInvoiceController extends erpnex
|
|||||||
}
|
}
|
||||||
|
|
||||||
write_off_outstanding_amount_automatically() {
|
write_off_outstanding_amount_automatically() {
|
||||||
if(cint(this.frm.doc.write_off_outstanding_amount_automatically)) {
|
if (cint(this.frm.doc.write_off_outstanding_amount_automatically)) {
|
||||||
frappe.model.round_floats_in(this.frm.doc, ["grand_total", "paid_amount"]);
|
frappe.model.round_floats_in(this.frm.doc, ["grand_total", "paid_amount"]);
|
||||||
// this will make outstanding amount 0
|
// this will make outstanding amount 0
|
||||||
this.frm.set_value("write_off_amount",
|
this.frm.set_value("write_off_amount",
|
||||||
flt(this.frm.doc.grand_total - this.frm.doc.paid_amount - this.frm.doc.total_advance, precision("write_off_amount"))
|
flt(this.frm.doc.grand_total - this.frm.doc.paid_amount - this.frm.doc.total_advance, precision("write_off_amount"))
|
||||||
);
|
);
|
||||||
this.frm.toggle_enable("write_off_amount", false);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
this.frm.toggle_enable("write_off_amount", true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.calculate_outstanding_amount(false);
|
this.calculate_outstanding_amount(false);
|
||||||
|
@ -99,6 +99,7 @@
|
|||||||
"loyalty_redemption_account",
|
"loyalty_redemption_account",
|
||||||
"loyalty_redemption_cost_center",
|
"loyalty_redemption_cost_center",
|
||||||
"section_break_49",
|
"section_break_49",
|
||||||
|
"coupon_code",
|
||||||
"apply_discount_on",
|
"apply_discount_on",
|
||||||
"base_discount_amount",
|
"base_discount_amount",
|
||||||
"column_break_51",
|
"column_break_51",
|
||||||
@ -1183,7 +1184,8 @@
|
|||||||
"label": "Write Off Amount",
|
"label": "Write Off Amount",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "currency",
|
"options": "currency",
|
||||||
"print_hide": 1
|
"print_hide": 1,
|
||||||
|
"read_only_depends_on": "eval: doc.write_off_outstanding_amount_automatically"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "base_write_off_amount",
|
"fieldname": "base_write_off_amount",
|
||||||
@ -1549,12 +1551,20 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Sales Invoice",
|
"options": "Sales Invoice",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "coupon_code",
|
||||||
|
"fieldname": "coupon_code",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Coupon Code",
|
||||||
|
"options": "Coupon Code",
|
||||||
|
"print_hide": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-file-text",
|
"icon": "fa fa-file-text",
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-08-17 20:13:44.255437",
|
"modified": "2021-08-18 16:13:52.080543",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "POS Invoice",
|
"name": "POS Invoice",
|
||||||
|
@ -44,6 +44,9 @@ class POSInvoice(SalesInvoice):
|
|||||||
self.validate_pos()
|
self.validate_pos()
|
||||||
self.validate_payment_amount()
|
self.validate_payment_amount()
|
||||||
self.validate_loyalty_transaction()
|
self.validate_loyalty_transaction()
|
||||||
|
if self.coupon_code:
|
||||||
|
from erpnext.accounts.doctype.pricing_rule.utils import validate_coupon_code
|
||||||
|
validate_coupon_code(self.coupon_code)
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
# create the loyalty point ledger entry if the customer is enrolled in any loyalty program
|
# create the loyalty point ledger entry if the customer is enrolled in any loyalty program
|
||||||
@ -58,6 +61,10 @@ class POSInvoice(SalesInvoice):
|
|||||||
self.check_phone_payments()
|
self.check_phone_payments()
|
||||||
self.set_status(update=True)
|
self.set_status(update=True)
|
||||||
|
|
||||||
|
if self.coupon_code:
|
||||||
|
from erpnext.accounts.doctype.pricing_rule.utils import update_coupon_code_count
|
||||||
|
update_coupon_code_count(self.coupon_code,'used')
|
||||||
|
|
||||||
def before_cancel(self):
|
def before_cancel(self):
|
||||||
if self.consolidated_invoice and frappe.db.get_value('Sales Invoice', self.consolidated_invoice, 'docstatus') == 1:
|
if self.consolidated_invoice and frappe.db.get_value('Sales Invoice', self.consolidated_invoice, 'docstatus') == 1:
|
||||||
pos_closing_entry = frappe.get_all(
|
pos_closing_entry = frappe.get_all(
|
||||||
@ -84,6 +91,10 @@ class POSInvoice(SalesInvoice):
|
|||||||
against_psi_doc.delete_loyalty_point_entry()
|
against_psi_doc.delete_loyalty_point_entry()
|
||||||
against_psi_doc.make_loyalty_point_entry()
|
against_psi_doc.make_loyalty_point_entry()
|
||||||
|
|
||||||
|
if self.coupon_code:
|
||||||
|
from erpnext.accounts.doctype.pricing_rule.utils import update_coupon_code_count
|
||||||
|
update_coupon_code_count(self.coupon_code,'cancelled')
|
||||||
|
|
||||||
def check_phone_payments(self):
|
def check_phone_payments(self):
|
||||||
for pay in self.payments:
|
for pay in self.payments:
|
||||||
if pay.type == "Phone" and pay.amount >= 0:
|
if pay.type == "Phone" and pay.amount >= 0:
|
||||||
@ -127,7 +138,7 @@ class POSInvoice(SalesInvoice):
|
|||||||
.format(item.idx, bold_delivered_serial_nos), title=_("Item Unavailable"))
|
.format(item.idx, bold_delivered_serial_nos), title=_("Item Unavailable"))
|
||||||
|
|
||||||
def validate_stock_availablility(self):
|
def validate_stock_availablility(self):
|
||||||
if self.is_return:
|
if self.is_return or self.docstatus != 1:
|
||||||
return
|
return
|
||||||
|
|
||||||
allow_negative_stock = frappe.db.get_single_value('Stock Settings', 'allow_negative_stock')
|
allow_negative_stock = frappe.db.get_single_value('Stock Settings', 'allow_negative_stock')
|
||||||
|
@ -198,12 +198,19 @@ def apply_pricing_rule(args, doc=None):
|
|||||||
set_serial_nos_based_on_fifo = frappe.db.get_single_value("Stock Settings",
|
set_serial_nos_based_on_fifo = frappe.db.get_single_value("Stock Settings",
|
||||||
"automatically_set_serial_nos_based_on_fifo")
|
"automatically_set_serial_nos_based_on_fifo")
|
||||||
|
|
||||||
|
item_code_list = tuple(item.get('item_code') for item in item_list)
|
||||||
|
query_items = frappe.get_all('Item', fields=['item_code','has_serial_no'], filters=[['item_code','in',item_code_list]],as_list=1)
|
||||||
|
serialized_items = dict()
|
||||||
|
for item_code, val in query_items:
|
||||||
|
serialized_items.setdefault(item_code, val)
|
||||||
|
|
||||||
for item in item_list:
|
for item in item_list:
|
||||||
args_copy = copy.deepcopy(args)
|
args_copy = copy.deepcopy(args)
|
||||||
args_copy.update(item)
|
args_copy.update(item)
|
||||||
data = get_pricing_rule_for_item(args_copy, item.get('price_list_rate'), doc=doc)
|
data = get_pricing_rule_for_item(args_copy, item.get('price_list_rate'), doc=doc)
|
||||||
out.append(data)
|
out.append(data)
|
||||||
if not item.get("serial_no") and set_serial_nos_based_on_fifo and not args.get('is_return'):
|
|
||||||
|
if serialized_items.get(item.get('item_code')) and not item.get("serial_no") and set_serial_nos_based_on_fifo and not args.get('is_return'):
|
||||||
out[0].update(get_serial_no_for_item(args_copy))
|
out[0].update(get_serial_no_for_item(args_copy))
|
||||||
|
|
||||||
return out
|
return out
|
||||||
|
@ -324,16 +324,12 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends e
|
|||||||
}
|
}
|
||||||
|
|
||||||
write_off_outstanding_amount_automatically() {
|
write_off_outstanding_amount_automatically() {
|
||||||
if(cint(this.frm.doc.write_off_outstanding_amount_automatically)) {
|
if (cint(this.frm.doc.write_off_outstanding_amount_automatically)) {
|
||||||
frappe.model.round_floats_in(this.frm.doc, ["grand_total", "paid_amount"]);
|
frappe.model.round_floats_in(this.frm.doc, ["grand_total", "paid_amount"]);
|
||||||
// this will make outstanding amount 0
|
// this will make outstanding amount 0
|
||||||
this.frm.set_value("write_off_amount",
|
this.frm.set_value("write_off_amount",
|
||||||
flt(this.frm.doc.grand_total - this.frm.doc.paid_amount - this.frm.doc.total_advance, precision("write_off_amount"))
|
flt(this.frm.doc.grand_total - this.frm.doc.paid_amount - this.frm.doc.total_advance, precision("write_off_amount"))
|
||||||
);
|
);
|
||||||
this.frm.toggle_enable("write_off_amount", false);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
this.frm.toggle_enable("write_off_amount", true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.calculate_outstanding_amount(false);
|
this.calculate_outstanding_amount(false);
|
||||||
@ -787,8 +783,6 @@ frappe.ui.form.on('Sales Invoice', {
|
|||||||
if (frappe.boot.sysdefaults.country == 'India') unhide_field(['c_form_applicable', 'c_form_no']);
|
if (frappe.boot.sysdefaults.country == 'India') unhide_field(['c_form_applicable', 'c_form_no']);
|
||||||
else hide_field(['c_form_applicable', 'c_form_no']);
|
else hide_field(['c_form_applicable', 'c_form_no']);
|
||||||
|
|
||||||
frm.toggle_enable("write_off_amount", !!!cint(doc.write_off_outstanding_amount_automatically));
|
|
||||||
|
|
||||||
frm.refresh_fields();
|
frm.refresh_fields();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1444,7 +1444,8 @@
|
|||||||
"label": "Write Off Amount",
|
"label": "Write Off Amount",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "currency",
|
"options": "currency",
|
||||||
"print_hide": 1
|
"print_hide": 1,
|
||||||
|
"read_only_depends_on": "eval:doc.write_off_outstanding_amount_automatically"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "base_write_off_amount",
|
"fieldname": "base_write_off_amount",
|
||||||
@ -2014,7 +2015,7 @@
|
|||||||
"link_fieldname": "consolidated_invoice"
|
"link_fieldname": "consolidated_invoice"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"modified": "2021-08-17 20:16:12.737743",
|
"modified": "2021-08-18 16:07:45.122570",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Sales Invoice",
|
"name": "Sales Invoice",
|
||||||
|
@ -26,6 +26,7 @@ from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
|
|||||||
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
|
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
|
||||||
from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice
|
from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice
|
||||||
from erpnext.stock.utils import get_incoming_rate
|
from erpnext.stock.utils import get_incoming_rate
|
||||||
|
from erpnext.accounts.utils import PaymentEntryUnlinkError
|
||||||
|
|
||||||
class TestSalesInvoice(unittest.TestCase):
|
class TestSalesInvoice(unittest.TestCase):
|
||||||
def make(self):
|
def make(self):
|
||||||
@ -136,7 +137,7 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
pe.paid_to_account_currency = si.currency
|
pe.paid_to_account_currency = si.currency
|
||||||
pe.source_exchange_rate = 1
|
pe.source_exchange_rate = 1
|
||||||
pe.target_exchange_rate = 1
|
pe.target_exchange_rate = 1
|
||||||
pe.paid_amount = si.grand_total
|
pe.paid_amount = si.outstanding_amount
|
||||||
pe.insert()
|
pe.insert()
|
||||||
pe.submit()
|
pe.submit()
|
||||||
|
|
||||||
@ -145,6 +146,42 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
self.assertRaises(frappe.LinkExistsError, si.cancel)
|
self.assertRaises(frappe.LinkExistsError, si.cancel)
|
||||||
unlink_payment_on_cancel_of_invoice()
|
unlink_payment_on_cancel_of_invoice()
|
||||||
|
|
||||||
|
def test_payment_entry_unlink_against_standalone_credit_note(self):
|
||||||
|
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
|
||||||
|
si1 = create_sales_invoice(rate=1000)
|
||||||
|
si2 = create_sales_invoice(rate=300)
|
||||||
|
si3 = create_sales_invoice(qty=-1, rate=300, is_return=1)
|
||||||
|
|
||||||
|
|
||||||
|
pe = get_payment_entry("Sales Invoice", si1.name, bank_account="_Test Bank - _TC")
|
||||||
|
pe.append('references', {
|
||||||
|
'reference_doctype': 'Sales Invoice',
|
||||||
|
'reference_name': si2.name,
|
||||||
|
'total_amount': si2.grand_total,
|
||||||
|
'outstanding_amount': si2.outstanding_amount,
|
||||||
|
'allocated_amount': si2.outstanding_amount
|
||||||
|
})
|
||||||
|
|
||||||
|
pe.append('references', {
|
||||||
|
'reference_doctype': 'Sales Invoice',
|
||||||
|
'reference_name': si3.name,
|
||||||
|
'total_amount': si3.grand_total,
|
||||||
|
'outstanding_amount': si3.outstanding_amount,
|
||||||
|
'allocated_amount': si3.outstanding_amount
|
||||||
|
})
|
||||||
|
|
||||||
|
pe.reference_no = 'Test001'
|
||||||
|
pe.reference_date = nowdate()
|
||||||
|
pe.save()
|
||||||
|
pe.submit()
|
||||||
|
|
||||||
|
si2.load_from_db()
|
||||||
|
si2.cancel()
|
||||||
|
|
||||||
|
si1.load_from_db()
|
||||||
|
self.assertRaises(PaymentEntryUnlinkError, si1.cancel)
|
||||||
|
|
||||||
|
|
||||||
def test_sales_invoice_calculation_export_currency(self):
|
def test_sales_invoice_calculation_export_currency(self):
|
||||||
si = frappe.copy_doc(test_records[2])
|
si = frappe.copy_doc(test_records[2])
|
||||||
si.currency = "USD"
|
si.currency = "USD"
|
||||||
@ -2014,7 +2051,7 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
|
|
||||||
data = get_ewb_data("Sales Invoice", [si.name])
|
data = get_ewb_data("Sales Invoice", [si.name])
|
||||||
|
|
||||||
self.assertEqual(data['version'], '1.0.1118')
|
self.assertEqual(data['version'], '1.0.0421')
|
||||||
self.assertEqual(data['billLists'][0]['fromGstin'], '27AAECE4835E1ZR')
|
self.assertEqual(data['billLists'][0]['fromGstin'], '27AAECE4835E1ZR')
|
||||||
self.assertEqual(data['billLists'][0]['fromTrdName'], '_Test Company')
|
self.assertEqual(data['billLists'][0]['fromTrdName'], '_Test Company')
|
||||||
self.assertEqual(data['billLists'][0]['toTrdName'], '_Test Customer')
|
self.assertEqual(data['billLists'][0]['toTrdName'], '_Test Customer')
|
||||||
|
@ -101,7 +101,7 @@ def merge_similar_entries(gl_map, precision=None):
|
|||||||
|
|
||||||
def check_if_in_list(gle, gl_map, dimensions=None):
|
def check_if_in_list(gle, gl_map, dimensions=None):
|
||||||
account_head_fieldnames = ['voucher_detail_no', 'party', 'against_voucher',
|
account_head_fieldnames = ['voucher_detail_no', 'party', 'against_voucher',
|
||||||
'cost_center', 'against_voucher_type', 'party_type', 'project']
|
'cost_center', 'against_voucher_type', 'party_type', 'project', 'finance_book']
|
||||||
|
|
||||||
if dimensions:
|
if dimensions:
|
||||||
account_head_fieldnames = account_head_fieldnames + dimensions
|
account_head_fieldnames = account_head_fieldnames + dimensions
|
||||||
|
@ -535,6 +535,8 @@ class ReceivablePayableReport(object):
|
|||||||
if getdate(entry_date) > getdate(self.filters.report_date):
|
if getdate(entry_date) > getdate(self.filters.report_date):
|
||||||
row.range1 = row.range2 = row.range3 = row.range4 = row.range5 = 0.0
|
row.range1 = row.range2 = row.range3 = row.range4 = row.range5 = 0.0
|
||||||
|
|
||||||
|
row.total_due = row.range1 + row.range2 + row.range3 + row.range4 + row.range5
|
||||||
|
|
||||||
def get_ageing_data(self, entry_date, row):
|
def get_ageing_data(self, entry_date, row):
|
||||||
# [0-30, 30-60, 60-90, 90-120, 120-above]
|
# [0-30, 30-60, 60-90, 90-120, 120-above]
|
||||||
row.range1 = row.range2 = row.range3 = row.range4 = row.range5 = 0.0
|
row.range1 = row.range2 = row.range3 = row.range4 = row.range5 = 0.0
|
||||||
|
@ -82,6 +82,7 @@ class AccountsReceivableSummary(ReceivablePayableReport):
|
|||||||
"range3": 0.0,
|
"range3": 0.0,
|
||||||
"range4": 0.0,
|
"range4": 0.0,
|
||||||
"range5": 0.0,
|
"range5": 0.0,
|
||||||
|
"total_due": 0.0,
|
||||||
"sales_person": []
|
"sales_person": []
|
||||||
}))
|
}))
|
||||||
|
|
||||||
@ -135,3 +136,6 @@ class AccountsReceivableSummary(ReceivablePayableReport):
|
|||||||
"{range3}-{range4}".format(range3=cint(self.filters["range3"])+ 1, range4=self.filters["range4"]),
|
"{range3}-{range4}".format(range3=cint(self.filters["range3"])+ 1, range4=self.filters["range4"]),
|
||||||
"{range4}-{above}".format(range4=cint(self.filters["range4"])+ 1, above=_("Above"))]):
|
"{range4}-{above}".format(range4=cint(self.filters["range4"])+ 1, above=_("Above"))]):
|
||||||
self.add_column(label=label, fieldname='range' + str(i+1))
|
self.add_column(label=label, fieldname='range' + str(i+1))
|
||||||
|
|
||||||
|
# Add column for total due amount
|
||||||
|
self.add_column(label="Total Amount Due", fieldname='total_due')
|
||||||
|
@ -210,10 +210,10 @@ def get_data(companies, root_type, balance_must_be, fiscal_year, filters=None, i
|
|||||||
company_currency = get_company_currency(filters)
|
company_currency = get_company_currency(filters)
|
||||||
|
|
||||||
if filters.filter_based_on == 'Fiscal Year':
|
if filters.filter_based_on == 'Fiscal Year':
|
||||||
start_date = fiscal_year.year_start_date
|
start_date = fiscal_year.year_start_date if filters.report != 'Balance Sheet' else None
|
||||||
end_date = fiscal_year.year_end_date
|
end_date = fiscal_year.year_end_date
|
||||||
else:
|
else:
|
||||||
start_date = filters.period_start_date
|
start_date = filters.period_start_date if filters.report != 'Balance Sheet' else None
|
||||||
end_date = filters.period_end_date
|
end_date = filters.period_end_date
|
||||||
|
|
||||||
gl_entries_by_account = {}
|
gl_entries_by_account = {}
|
||||||
|
@ -19,6 +19,7 @@ from erpnext.stock import get_warehouse_account_map
|
|||||||
|
|
||||||
class StockValueAndAccountBalanceOutOfSync(frappe.ValidationError): pass
|
class StockValueAndAccountBalanceOutOfSync(frappe.ValidationError): pass
|
||||||
class FiscalYearError(frappe.ValidationError): pass
|
class FiscalYearError(frappe.ValidationError): pass
|
||||||
|
class PaymentEntryUnlinkError(frappe.ValidationError): pass
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_fiscal_year(date=None, fiscal_year=None, label="Date", verbose=1, company=None, as_dict=False):
|
def get_fiscal_year(date=None, fiscal_year=None, label="Date", verbose=1, company=None, as_dict=False):
|
||||||
@ -555,10 +556,16 @@ def remove_ref_doc_link_from_pe(ref_type, ref_no):
|
|||||||
and docstatus < 2""", (now(), frappe.session.user, ref_type, ref_no))
|
and docstatus < 2""", (now(), frappe.session.user, ref_type, ref_no))
|
||||||
|
|
||||||
for pe in linked_pe:
|
for pe in linked_pe:
|
||||||
pe_doc = frappe.get_doc("Payment Entry", pe)
|
try:
|
||||||
pe_doc.set_total_allocated_amount()
|
pe_doc = frappe.get_doc("Payment Entry", pe)
|
||||||
pe_doc.set_unallocated_amount()
|
pe_doc.set_amounts()
|
||||||
pe_doc.clear_unallocated_reference_document_rows()
|
pe_doc.clear_unallocated_reference_document_rows()
|
||||||
|
pe_doc.validate_payment_type_with_outstanding()
|
||||||
|
except Exception as e:
|
||||||
|
msg = _("There were issues unlinking payment entry {0}.").format(pe_doc.name)
|
||||||
|
msg += '<br>'
|
||||||
|
msg += _("Please cancel payment entry manually first")
|
||||||
|
frappe.throw(msg, exc=PaymentEntryUnlinkError, title=_("Payment Unlink Error"))
|
||||||
|
|
||||||
frappe.db.sql("""update `tabPayment Entry` set total_allocated_amount=%s,
|
frappe.db.sql("""update `tabPayment Entry` set total_allocated_amount=%s,
|
||||||
base_total_allocated_amount=%s, unallocated_amount=%s, modified=%s, modified_by=%s
|
base_total_allocated_amount=%s, unallocated_amount=%s, modified=%s, modified_by=%s
|
||||||
|
@ -1896,6 +1896,11 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
|
|||||||
|
|
||||||
for d in data:
|
for d in data:
|
||||||
new_child_flag = False
|
new_child_flag = False
|
||||||
|
|
||||||
|
if not d.get("item_code"):
|
||||||
|
# ignore empty rows
|
||||||
|
continue
|
||||||
|
|
||||||
if not d.get("docname"):
|
if not d.get("docname"):
|
||||||
new_child_flag = True
|
new_child_flag = True
|
||||||
check_doc_permissions(parent, 'create')
|
check_doc_permissions(parent, 'create')
|
||||||
|
@ -329,7 +329,6 @@ def make_return_doc(doctype, source_name, target_doc=None):
|
|||||||
target_doc.po_detail = source_doc.po_detail
|
target_doc.po_detail = source_doc.po_detail
|
||||||
target_doc.pr_detail = source_doc.pr_detail
|
target_doc.pr_detail = source_doc.pr_detail
|
||||||
target_doc.purchase_invoice_item = source_doc.name
|
target_doc.purchase_invoice_item = source_doc.name
|
||||||
target_doc.price_list_rate = 0
|
|
||||||
|
|
||||||
elif doctype == "Delivery Note":
|
elif doctype == "Delivery Note":
|
||||||
returned_qty_map = get_returned_qty_map_for_row(source_doc.name, doctype)
|
returned_qty_map = get_returned_qty_map_for_row(source_doc.name, doctype)
|
||||||
@ -360,7 +359,6 @@ def make_return_doc(doctype, source_name, target_doc=None):
|
|||||||
else:
|
else:
|
||||||
target_doc.pos_invoice_item = source_doc.name
|
target_doc.pos_invoice_item = source_doc.name
|
||||||
|
|
||||||
target_doc.price_list_rate = 0
|
|
||||||
if default_warehouse_for_sales_return:
|
if default_warehouse_for_sales_return:
|
||||||
target_doc.warehouse = default_warehouse_for_sales_return
|
target_doc.warehouse = default_warehouse_for_sales_return
|
||||||
|
|
||||||
|
@ -595,7 +595,8 @@ class calculate_taxes_and_totals(object):
|
|||||||
self.doc.precision("outstanding_amount"))
|
self.doc.precision("outstanding_amount"))
|
||||||
|
|
||||||
if self.doc.doctype == 'Sales Invoice' and self.doc.get('is_pos') and self.doc.get('is_return'):
|
if self.doc.doctype == 'Sales Invoice' and self.doc.get('is_pos') and self.doc.get('is_return'):
|
||||||
self.update_paid_amount_for_return(total_amount_to_pay)
|
self.set_total_amount_to_default_mop(total_amount_to_pay)
|
||||||
|
self.calculate_paid_amount()
|
||||||
|
|
||||||
def calculate_paid_amount(self):
|
def calculate_paid_amount(self):
|
||||||
|
|
||||||
@ -675,7 +676,7 @@ class calculate_taxes_and_totals(object):
|
|||||||
def set_item_wise_tax_breakup(self):
|
def set_item_wise_tax_breakup(self):
|
||||||
self.doc.other_charges_calculation = get_itemised_tax_breakup_html(self.doc)
|
self.doc.other_charges_calculation = get_itemised_tax_breakup_html(self.doc)
|
||||||
|
|
||||||
def update_paid_amount_for_return(self, total_amount_to_pay):
|
def set_total_amount_to_default_mop(self, total_amount_to_pay):
|
||||||
default_mode_of_payment = frappe.db.get_value('POS Payment Method',
|
default_mode_of_payment = frappe.db.get_value('POS Payment Method',
|
||||||
{'parent': self.doc.pos_profile, 'default': 1}, ['mode_of_payment'], as_dict=1)
|
{'parent': self.doc.pos_profile, 'default': 1}, ['mode_of_payment'], as_dict=1)
|
||||||
|
|
||||||
@ -685,9 +686,7 @@ class calculate_taxes_and_totals(object):
|
|||||||
'mode_of_payment': default_mode_of_payment.mode_of_payment,
|
'mode_of_payment': default_mode_of_payment.mode_of_payment,
|
||||||
'amount': total_amount_to_pay,
|
'amount': total_amount_to_pay,
|
||||||
'default': 1
|
'default': 1
|
||||||
})
|
})
|
||||||
|
|
||||||
self.calculate_paid_amount()
|
|
||||||
|
|
||||||
def get_itemised_tax_breakup_html(doc):
|
def get_itemised_tax_breakup_html(doc):
|
||||||
if not doc.taxes:
|
if not doc.taxes:
|
||||||
|
@ -4,18 +4,11 @@
|
|||||||
frappe.ui.form.on('Salary Component', {
|
frappe.ui.form.on('Salary Component', {
|
||||||
setup: function(frm) {
|
setup: function(frm) {
|
||||||
frm.set_query("account", "accounts", function(doc, cdt, cdn) {
|
frm.set_query("account", "accounts", function(doc, cdt, cdn) {
|
||||||
let d = frappe.get_doc(cdt, cdn);
|
var d = locals[cdt][cdn];
|
||||||
|
|
||||||
let root_type = "Liability";
|
|
||||||
if (frm.doc.type == "Deduction") {
|
|
||||||
root_type = "Expense";
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
filters: {
|
filters: {
|
||||||
"is_group": 0,
|
"is_group": 0,
|
||||||
"company": d.company,
|
"company": d.company
|
||||||
"root_type": root_type
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -754,8 +754,6 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.frm.refresh_fields();
|
this.frm.refresh_fields();
|
||||||
|
|
||||||
this.calculate_paid_amount();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
set_default_payment(total_amount_to_pay, update_paid_amount) {
|
set_default_payment(total_amount_to_pay, update_paid_amount) {
|
||||||
|
@ -2242,12 +2242,19 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
|
|||||||
|
|
||||||
coupon_code() {
|
coupon_code() {
|
||||||
var me = this;
|
var me = this;
|
||||||
frappe.run_serially([
|
if (this.frm.doc.coupon_code) {
|
||||||
() => this.frm.doc.ignore_pricing_rule=1,
|
frappe.run_serially([
|
||||||
() => me.ignore_pricing_rule(),
|
() => this.frm.doc.ignore_pricing_rule=1,
|
||||||
() => this.frm.doc.ignore_pricing_rule=0,
|
() => me.ignore_pricing_rule(),
|
||||||
() => me.apply_pricing_rule()
|
() => this.frm.doc.ignore_pricing_rule=0,
|
||||||
]);
|
() => me.apply_pricing_rule()
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
frappe.run_serially([
|
||||||
|
() => this.frm.doc.ignore_pricing_rule=1,
|
||||||
|
() => me.ignore_pricing_rule()
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -563,7 +563,7 @@ erpnext.utils.update_child_items = function(opts) {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
primary_action: function() {
|
primary_action: function() {
|
||||||
const trans_items = this.get_values()["trans_items"];
|
const trans_items = this.get_values()["trans_items"].filter((item) => !!item.item_code);
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: 'erpnext.controllers.accounts_controller.update_child_qty_rate',
|
method: 'erpnext.controllers.accounts_controller.update_child_qty_rate',
|
||||||
freeze: true,
|
freeze: true,
|
||||||
|
@ -860,6 +860,8 @@
|
|||||||
|
|
||||||
.invoice-fields {
|
.invoice-fields {
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
|
height: 100%;
|
||||||
|
padding-right: var(--padding-sm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,6 +531,7 @@ def make_custom_fields(update=True):
|
|||||||
fieldtype='Link', options='Salary Component', insert_after='hra_section'),
|
fieldtype='Link', options='Salary Component', insert_after='hra_section'),
|
||||||
dict(fieldname='hra_component', label='HRA Component',
|
dict(fieldname='hra_component', label='HRA Component',
|
||||||
fieldtype='Link', options='Salary Component', insert_after='basic_component'),
|
fieldtype='Link', options='Salary Component', insert_after='basic_component'),
|
||||||
|
dict(fieldname='hra_column_break', fieldtype='Column Break', insert_after='hra_component'),
|
||||||
dict(fieldname='arrear_component', label='Arrear Component',
|
dict(fieldname='arrear_component', label='Arrear Component',
|
||||||
fieldtype='Link', options='Salary Component', insert_after='hra_component'),
|
fieldtype='Link', options='Salary Component', insert_after='hra_component'),
|
||||||
dict(fieldname='non_profit_section', label='Non Profit Settings',
|
dict(fieldname='non_profit_section', label='Non Profit Settings',
|
||||||
@ -539,6 +540,7 @@ def make_custom_fields(update=True):
|
|||||||
fieldtype='Data', insert_after='non_profit_section'),
|
fieldtype='Data', insert_after='non_profit_section'),
|
||||||
dict(fieldname='with_effect_from', label='80G With Effect From',
|
dict(fieldname='with_effect_from', label='80G With Effect From',
|
||||||
fieldtype='Date', insert_after='company_80g_number'),
|
fieldtype='Date', insert_after='company_80g_number'),
|
||||||
|
dict(fieldname='non_profit_column_break', fieldtype='Column Break', insert_after='with_effect_from'),
|
||||||
dict(fieldname='pan_details', label='PAN Number',
|
dict(fieldname='pan_details', label='PAN Number',
|
||||||
fieldtype='Data', insert_after='with_effect_from')
|
fieldtype='Data', insert_after='with_effect_from')
|
||||||
],
|
],
|
||||||
|
@ -475,7 +475,7 @@ def get_ewb_data(dt, dn):
|
|||||||
ewaybills.append(data)
|
ewaybills.append(data)
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
'version': '1.0.1118',
|
'version': '1.0.0421',
|
||||||
'billLists': ewaybills
|
'billLists': ewaybills
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,9 +6,8 @@ import frappe
|
|||||||
from frappe.utils import flt, cstr
|
from frappe.utils import flt, cstr
|
||||||
from erpnext.controllers.taxes_and_totals import get_itemised_tax
|
from erpnext.controllers.taxes_and_totals import get_itemised_tax
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.core.doctype.file.file import remove_file
|
from frappe.utils.file_manager import remove_file
|
||||||
from six import string_types
|
from six import string_types
|
||||||
from frappe.desk.form.load import get_attachments
|
|
||||||
from erpnext.regional.italy import state_codes
|
from erpnext.regional.italy import state_codes
|
||||||
|
|
||||||
|
|
||||||
|
@ -394,6 +394,10 @@ erpnext.selling.SellingController = class SellingController extends erpnext.Tran
|
|||||||
}
|
}
|
||||||
|
|
||||||
_set_batch_number(doc) {
|
_set_batch_number(doc) {
|
||||||
|
if (doc.batch_no) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
let args = {'item_code': doc.item_code, 'warehouse': doc.warehouse, 'qty': flt(doc.qty) * flt(doc.conversion_factor)};
|
let args = {'item_code': doc.item_code, 'warehouse': doc.warehouse, 'qty': flt(doc.qty) * flt(doc.conversion_factor)};
|
||||||
if (doc.has_serial_no && doc.serial_no) {
|
if (doc.has_serial_no && doc.serial_no) {
|
||||||
args['serial_no'] = doc.serial_no
|
args['serial_no'] = doc.serial_no
|
||||||
|
@ -46,6 +46,43 @@ frappe.ui.form.on("Company", {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
change_abbreviation(frm) {
|
||||||
|
var dialog = new frappe.ui.Dialog({
|
||||||
|
title: "Replace Abbr",
|
||||||
|
fields: [
|
||||||
|
{"fieldtype": "Data", "label": "New Abbreviation", "fieldname": "new_abbr",
|
||||||
|
"reqd": 1 },
|
||||||
|
{"fieldtype": "Button", "label": "Update", "fieldname": "update"},
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog.fields_dict.update.$input.click(function() {
|
||||||
|
var args = dialog.get_values();
|
||||||
|
if (!args) return;
|
||||||
|
frappe.show_alert(__("Update in progress. It might take a while."));
|
||||||
|
return frappe.call({
|
||||||
|
method: "erpnext.setup.doctype.company.company.enqueue_replace_abbr",
|
||||||
|
args: {
|
||||||
|
"company": frm.doc.name,
|
||||||
|
"old": frm.doc.abbr,
|
||||||
|
"new": args.new_abbr
|
||||||
|
},
|
||||||
|
callback: function(r) {
|
||||||
|
if (r.exc) {
|
||||||
|
frappe.msgprint(__("There were errors."));
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
frm.set_value("abbr", args.new_abbr);
|
||||||
|
}
|
||||||
|
dialog.hide();
|
||||||
|
frm.refresh();
|
||||||
|
},
|
||||||
|
btn: this
|
||||||
|
});
|
||||||
|
});
|
||||||
|
dialog.show();
|
||||||
|
},
|
||||||
|
|
||||||
company_name: function(frm) {
|
company_name: function(frm) {
|
||||||
if(frm.doc.__islocal) {
|
if(frm.doc.__islocal) {
|
||||||
// add missing " " arg in split method
|
// add missing " " arg in split method
|
||||||
@ -127,6 +164,10 @@ frappe.ui.form.on("Company", {
|
|||||||
}, __('Manage'));
|
}, __('Manage'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frm.add_custom_button(__('Change Abbreviation'), () => {
|
||||||
|
frm.trigger('change_abbreviation');
|
||||||
|
}, __('Manage'));
|
||||||
}
|
}
|
||||||
|
|
||||||
erpnext.company.set_chart_of_accounts_options(frm.doc);
|
erpnext.company.set_chart_of_accounts_options(frm.doc);
|
||||||
@ -204,43 +245,6 @@ erpnext.company.set_chart_of_accounts_options = function(doc) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_frm.cscript.change_abbr = function() {
|
|
||||||
var dialog = new frappe.ui.Dialog({
|
|
||||||
title: "Replace Abbr",
|
|
||||||
fields: [
|
|
||||||
{"fieldtype": "Data", "label": "New Abbreviation", "fieldname": "new_abbr",
|
|
||||||
"reqd": 1 },
|
|
||||||
{"fieldtype": "Button", "label": "Update", "fieldname": "update"},
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
dialog.fields_dict.update.$input.click(function() {
|
|
||||||
var args = dialog.get_values();
|
|
||||||
if(!args) return;
|
|
||||||
frappe.show_alert(__("Update in progress. It might take a while."));
|
|
||||||
return frappe.call({
|
|
||||||
method: "erpnext.setup.doctype.company.company.enqueue_replace_abbr",
|
|
||||||
args: {
|
|
||||||
"company": cur_frm.doc.name,
|
|
||||||
"old": cur_frm.doc.abbr,
|
|
||||||
"new": args.new_abbr
|
|
||||||
},
|
|
||||||
callback: function(r) {
|
|
||||||
if(r.exc) {
|
|
||||||
frappe.msgprint(__("There were errors."));
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
cur_frm.set_value("abbr", args.new_abbr);
|
|
||||||
}
|
|
||||||
dialog.hide();
|
|
||||||
cur_frm.refresh();
|
|
||||||
},
|
|
||||||
btn: this
|
|
||||||
})
|
|
||||||
});
|
|
||||||
dialog.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
erpnext.company.setup_queries = function(frm) {
|
erpnext.company.setup_queries = function(frm) {
|
||||||
$.each([
|
$.each([
|
||||||
["default_bank_account", {"account_type": "Bank"}],
|
["default_bank_account", {"account_type": "Bank"}],
|
||||||
|
@ -12,33 +12,48 @@
|
|||||||
"details",
|
"details",
|
||||||
"company_name",
|
"company_name",
|
||||||
"abbr",
|
"abbr",
|
||||||
"change_abbr",
|
"default_currency",
|
||||||
|
"country",
|
||||||
"is_group",
|
"is_group",
|
||||||
"cb0",
|
"cb0",
|
||||||
"domain",
|
|
||||||
"parent_company",
|
|
||||||
"charts_section",
|
|
||||||
"default_currency",
|
|
||||||
"default_letter_head",
|
"default_letter_head",
|
||||||
"default_holiday_list",
|
|
||||||
"default_finance_book",
|
|
||||||
"default_selling_terms",
|
|
||||||
"default_buying_terms",
|
|
||||||
"default_warehouse_for_sales_return",
|
|
||||||
"default_in_transit_warehouse",
|
|
||||||
"column_break_10",
|
|
||||||
"country",
|
|
||||||
"create_chart_of_accounts_based_on",
|
|
||||||
"chart_of_accounts",
|
|
||||||
"existing_company",
|
|
||||||
"tax_id",
|
"tax_id",
|
||||||
|
"domain",
|
||||||
"date_of_establishment",
|
"date_of_establishment",
|
||||||
|
"parent_company",
|
||||||
|
"company_info",
|
||||||
|
"company_logo",
|
||||||
|
"date_of_incorporation",
|
||||||
|
"phone_no",
|
||||||
|
"email",
|
||||||
|
"company_description",
|
||||||
|
"column_break1",
|
||||||
|
"date_of_commencement",
|
||||||
|
"fax",
|
||||||
|
"website",
|
||||||
|
"address_html",
|
||||||
|
"section_break_28",
|
||||||
|
"create_chart_of_accounts_based_on",
|
||||||
|
"existing_company",
|
||||||
|
"column_break_26",
|
||||||
|
"chart_of_accounts",
|
||||||
|
"charts_section",
|
||||||
"sales_settings",
|
"sales_settings",
|
||||||
"monthly_sales_target",
|
"default_buying_terms",
|
||||||
"sales_monthly_history",
|
"sales_monthly_history",
|
||||||
"column_break_goals",
|
"monthly_sales_target",
|
||||||
"transactions_annual_history",
|
|
||||||
"total_monthly_sales",
|
"total_monthly_sales",
|
||||||
|
"column_break_goals",
|
||||||
|
"default_selling_terms",
|
||||||
|
"default_warehouse_for_sales_return",
|
||||||
|
"credit_limit",
|
||||||
|
"transactions_annual_history",
|
||||||
|
"hr_settings_section",
|
||||||
|
"default_holiday_list",
|
||||||
|
"default_expense_claim_payable_account",
|
||||||
|
"column_break_10",
|
||||||
|
"default_employee_advance_account",
|
||||||
|
"default_payroll_payable_account",
|
||||||
"default_settings",
|
"default_settings",
|
||||||
"default_bank_account",
|
"default_bank_account",
|
||||||
"default_cash_account",
|
"default_cash_account",
|
||||||
@ -52,24 +67,20 @@
|
|||||||
"column_break0",
|
"column_break0",
|
||||||
"allow_account_creation_against_child_company",
|
"allow_account_creation_against_child_company",
|
||||||
"default_payable_account",
|
"default_payable_account",
|
||||||
"default_employee_advance_account",
|
|
||||||
"default_expense_account",
|
"default_expense_account",
|
||||||
"default_income_account",
|
"default_income_account",
|
||||||
"default_deferred_revenue_account",
|
"default_deferred_revenue_account",
|
||||||
"default_deferred_expense_account",
|
"default_deferred_expense_account",
|
||||||
"default_payroll_payable_account",
|
|
||||||
"default_expense_claim_payable_account",
|
|
||||||
"default_discount_account",
|
"default_discount_account",
|
||||||
"section_break_22",
|
|
||||||
"cost_center",
|
|
||||||
"column_break_26",
|
|
||||||
"credit_limit",
|
|
||||||
"payment_terms",
|
"payment_terms",
|
||||||
|
"cost_center",
|
||||||
|
"default_finance_book",
|
||||||
"auto_accounting_for_stock_settings",
|
"auto_accounting_for_stock_settings",
|
||||||
"enable_perpetual_inventory",
|
"enable_perpetual_inventory",
|
||||||
"enable_perpetual_inventory_for_non_stock_items",
|
"enable_perpetual_inventory_for_non_stock_items",
|
||||||
"default_inventory_account",
|
"default_inventory_account",
|
||||||
"stock_adjustment_account",
|
"stock_adjustment_account",
|
||||||
|
"default_in_transit_warehouse",
|
||||||
"column_break_32",
|
"column_break_32",
|
||||||
"stock_received_but_not_billed",
|
"stock_received_but_not_billed",
|
||||||
"service_received_but_not_billed",
|
"service_received_but_not_billed",
|
||||||
@ -79,25 +90,14 @@
|
|||||||
"depreciation_expense_account",
|
"depreciation_expense_account",
|
||||||
"series_for_depreciation_entry",
|
"series_for_depreciation_entry",
|
||||||
"expenses_included_in_asset_valuation",
|
"expenses_included_in_asset_valuation",
|
||||||
|
"repair_and_maintenance_account",
|
||||||
"column_break_40",
|
"column_break_40",
|
||||||
"disposal_account",
|
"disposal_account",
|
||||||
"depreciation_cost_center",
|
"depreciation_cost_center",
|
||||||
"capital_work_in_progress_account",
|
"capital_work_in_progress_account",
|
||||||
"repair_and_maintenance_account",
|
|
||||||
"asset_received_but_not_billed",
|
"asset_received_but_not_billed",
|
||||||
"budget_detail",
|
"budget_detail",
|
||||||
"exception_budget_approver_role",
|
"exception_budget_approver_role",
|
||||||
"company_info",
|
|
||||||
"company_logo",
|
|
||||||
"date_of_incorporation",
|
|
||||||
"address_html",
|
|
||||||
"date_of_commencement",
|
|
||||||
"phone_no",
|
|
||||||
"fax",
|
|
||||||
"email",
|
|
||||||
"website",
|
|
||||||
"column_break1",
|
|
||||||
"company_description",
|
|
||||||
"registration_info",
|
"registration_info",
|
||||||
"registration_details",
|
"registration_details",
|
||||||
"lft",
|
"lft",
|
||||||
@ -127,12 +127,6 @@
|
|||||||
"oldfieldtype": "Data",
|
"oldfieldtype": "Data",
|
||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"depends_on": "eval:!doc.__islocal && in_list(frappe.user_roles, \"System Manager\")",
|
|
||||||
"fieldname": "change_abbr",
|
|
||||||
"fieldtype": "Button",
|
|
||||||
"label": "Change Abbreviation"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"bold": 1,
|
"bold": 1,
|
||||||
"default": "0",
|
"default": "0",
|
||||||
@ -176,10 +170,9 @@
|
|||||||
"label": "Company Description"
|
"label": "Company Description"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"collapsible": 1,
|
|
||||||
"fieldname": "sales_settings",
|
"fieldname": "sales_settings",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Sales Settings"
|
"label": "Buying & Selling Settings"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "sales_monthly_history",
|
"fieldname": "sales_monthly_history",
|
||||||
@ -442,10 +435,6 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Account"
|
"options": "Account"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "section_break_22",
|
|
||||||
"fieldtype": "Section Break"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"depends_on": "eval:!doc.__islocal",
|
"depends_on": "eval:!doc.__islocal",
|
||||||
"fieldname": "cost_center",
|
"fieldname": "cost_center",
|
||||||
@ -455,10 +444,6 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Cost Center"
|
"options": "Cost Center"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "column_break_26",
|
|
||||||
"fieldtype": "Column Break"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"depends_on": "eval:!doc.__islocal",
|
"depends_on": "eval:!doc.__islocal",
|
||||||
"fieldname": "credit_limit",
|
"fieldname": "credit_limit",
|
||||||
@ -589,10 +574,10 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"collapsible": 1,
|
"collapsible": 1,
|
||||||
"description": "For reference only.",
|
"depends_on": "eval: doc.docstatus == 0 && doc.__islocal != 1",
|
||||||
"fieldname": "company_info",
|
"fieldname": "company_info",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Company Info"
|
"label": "Address & Contact"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "date_of_incorporation",
|
"fieldname": "date_of_incorporation",
|
||||||
@ -741,6 +726,20 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Repair and Maintenance Account",
|
"label": "Repair and Maintenance Account",
|
||||||
"options": "Account"
|
"options": "Account"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_28",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Chart of Accounts"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "hr_settings_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "HR & Payroll Settings"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_26",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-building",
|
"icon": "fa fa-building",
|
||||||
@ -748,7 +747,7 @@
|
|||||||
"image_field": "company_logo",
|
"image_field": "company_logo",
|
||||||
"is_tree": 1,
|
"is_tree": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-05-12 16:51:08.187233",
|
"modified": "2021-07-12 11:27:06.353860",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Setup",
|
"module": "Setup",
|
||||||
"name": "Company",
|
"name": "Company",
|
||||||
|
@ -84,8 +84,6 @@
|
|||||||
"oldfieldtype": "Section Break"
|
"oldfieldtype": "Section Break"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 1,
|
|
||||||
"default": "{purpose}",
|
|
||||||
"fieldname": "title",
|
"fieldname": "title",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
@ -630,7 +628,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-08-17 20:16:12.737743",
|
"modified": "2021-08-20 19:19:31.514846",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Stock Entry",
|
"name": "Stock Entry",
|
||||||
|
@ -58,6 +58,7 @@ class StockEntry(StockController):
|
|||||||
|
|
||||||
self.validate_posting_time()
|
self.validate_posting_time()
|
||||||
self.validate_purpose()
|
self.validate_purpose()
|
||||||
|
self.set_title()
|
||||||
self.validate_item()
|
self.validate_item()
|
||||||
self.validate_customer_provided_item()
|
self.validate_customer_provided_item()
|
||||||
self.validate_qty()
|
self.validate_qty()
|
||||||
@ -1608,6 +1609,14 @@ class StockEntry(StockController):
|
|||||||
|
|
||||||
return sorted(list(set(get_serial_nos(self.pro_doc.serial_no)) - set(used_serial_nos)))
|
return sorted(list(set(get_serial_nos(self.pro_doc.serial_no)) - set(used_serial_nos)))
|
||||||
|
|
||||||
|
def set_title(self):
|
||||||
|
if frappe.flags.in_import and self.title:
|
||||||
|
# Allow updating title during data import/update
|
||||||
|
return
|
||||||
|
|
||||||
|
self.title = self.purpose
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def move_sample_to_retention_warehouse(company, items):
|
def move_sample_to_retention_warehouse(company, items):
|
||||||
if isinstance(items, string_types):
|
if isinstance(items, string_types):
|
||||||
|
@ -278,6 +278,10 @@ def get_basic_details(args, item, overwrite_warehouse=True):
|
|||||||
else:
|
else:
|
||||||
args.uom = item.stock_uom
|
args.uom = item.stock_uom
|
||||||
|
|
||||||
|
if (args.get("batch_no") and
|
||||||
|
item.name != frappe.get_cached_value('Batch', args.get("batch_no"), 'item')):
|
||||||
|
args['batch_no'] = ''
|
||||||
|
|
||||||
out = frappe._dict({
|
out = frappe._dict({
|
||||||
"item_code": item.name,
|
"item_code": item.name,
|
||||||
"item_name": item.item_name,
|
"item_name": item.item_name,
|
||||||
|
@ -36,12 +36,26 @@ frappe.query_reports["Stock Analytics"] = {
|
|||||||
options:"Brand",
|
options:"Brand",
|
||||||
default: "",
|
default: "",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
fieldname: "company",
|
||||||
|
label: __("Company"),
|
||||||
|
fieldtype: "Link",
|
||||||
|
options: "Company",
|
||||||
|
default: frappe.defaults.get_user_default("Company"),
|
||||||
|
reqd: 1,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
fieldname: "warehouse",
|
fieldname: "warehouse",
|
||||||
label: __("Warehouse"),
|
label: __("Warehouse"),
|
||||||
fieldtype: "Link",
|
fieldtype: "Link",
|
||||||
options:"Warehouse",
|
options: "Warehouse",
|
||||||
default: "",
|
default: "",
|
||||||
|
get_query: function() {
|
||||||
|
const company = frappe.query_report.get_filter_value('company');
|
||||||
|
return {
|
||||||
|
filters: { 'company': company }
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: "from_date",
|
fieldname: "from_date",
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
import datetime
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _, scrub
|
from frappe import _, scrub
|
||||||
from frappe.utils import getdate, flt
|
from frappe.utils import getdate, get_quarter_start, get_first_day_of_week
|
||||||
|
from frappe.utils import get_first_day as get_first_day_of_month
|
||||||
|
|
||||||
from erpnext.stock.report.stock_balance.stock_balance import (get_items, get_stock_ledger_entries, get_item_details)
|
from erpnext.stock.report.stock_balance.stock_balance import (get_items, get_stock_ledger_entries, get_item_details)
|
||||||
from erpnext.accounts.utils import get_fiscal_year
|
from erpnext.accounts.utils import get_fiscal_year
|
||||||
from erpnext.stock.utils import is_reposting_item_valuation_in_progress
|
from erpnext.stock.utils import is_reposting_item_valuation_in_progress
|
||||||
from six import iteritems
|
|
||||||
|
|
||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
is_reposting_item_valuation_in_progress()
|
is_reposting_item_valuation_in_progress()
|
||||||
@ -71,7 +72,8 @@ def get_columns(filters):
|
|||||||
|
|
||||||
def get_period_date_ranges(filters):
|
def get_period_date_ranges(filters):
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
from_date, to_date = getdate(filters.from_date), getdate(filters.to_date)
|
from_date = round_down_to_nearest_frequency(filters.from_date, filters.range)
|
||||||
|
to_date = getdate(filters.to_date)
|
||||||
|
|
||||||
increment = {
|
increment = {
|
||||||
"Monthly": 1,
|
"Monthly": 1,
|
||||||
@ -97,6 +99,31 @@ def get_period_date_ranges(filters):
|
|||||||
|
|
||||||
return periodic_daterange
|
return periodic_daterange
|
||||||
|
|
||||||
|
|
||||||
|
def round_down_to_nearest_frequency(date: str, frequency: str) -> datetime.datetime:
|
||||||
|
"""Rounds down the date to nearest frequency unit.
|
||||||
|
example:
|
||||||
|
|
||||||
|
>>> round_down_to_nearest_frequency("2021-02-21", "Monthly")
|
||||||
|
datetime.datetime(2021, 2, 1)
|
||||||
|
|
||||||
|
>>> round_down_to_nearest_frequency("2021-08-21", "Yearly")
|
||||||
|
datetime.datetime(2021, 1, 1)
|
||||||
|
"""
|
||||||
|
|
||||||
|
def _get_first_day_of_fiscal_year(date):
|
||||||
|
fiscal_year = get_fiscal_year(date)
|
||||||
|
return fiscal_year and fiscal_year[1] or date
|
||||||
|
|
||||||
|
round_down_function = {
|
||||||
|
"Monthly": get_first_day_of_month,
|
||||||
|
"Quarterly": get_quarter_start,
|
||||||
|
"Weekly": get_first_day_of_week,
|
||||||
|
"Yearly": _get_first_day_of_fiscal_year,
|
||||||
|
}.get(frequency, getdate)
|
||||||
|
return round_down_function(date)
|
||||||
|
|
||||||
|
|
||||||
def get_period(posting_date, filters):
|
def get_period(posting_date, filters):
|
||||||
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
|
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
|
||||||
|
|
||||||
@ -177,7 +204,7 @@ def get_data(filters):
|
|||||||
periodic_data = get_periodic_data(sle, filters)
|
periodic_data = get_periodic_data(sle, filters)
|
||||||
ranges = get_period_date_ranges(filters)
|
ranges = get_period_date_ranges(filters)
|
||||||
|
|
||||||
for dummy, item_data in iteritems(item_details):
|
for dummy, item_data in item_details.items():
|
||||||
row = {
|
row = {
|
||||||
"name": item_data.name,
|
"name": item_data.name,
|
||||||
"item_name": item_data.item_name,
|
"item_name": item_data.item_name,
|
||||||
|
35
erpnext/stock/report/stock_analytics/test_stock_analytics.py
Normal file
35
erpnext/stock/report/stock_analytics/test_stock_analytics.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import datetime
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from frappe import _dict
|
||||||
|
from erpnext.accounts.utils import get_fiscal_year
|
||||||
|
|
||||||
|
from erpnext.stock.report.stock_analytics.stock_analytics import get_period_date_ranges
|
||||||
|
|
||||||
|
|
||||||
|
class TestStockAnalyticsReport(unittest.TestCase):
|
||||||
|
def test_get_period_date_ranges(self):
|
||||||
|
|
||||||
|
filters = _dict(range="Monthly", from_date="2020-12-28", to_date="2021-02-06")
|
||||||
|
|
||||||
|
ranges = get_period_date_ranges(filters)
|
||||||
|
|
||||||
|
expected_ranges = [
|
||||||
|
[datetime.date(2020, 12, 1), datetime.date(2020, 12, 31)],
|
||||||
|
[datetime.date(2021, 1, 1), datetime.date(2021, 1, 31)],
|
||||||
|
[datetime.date(2021, 2, 1), datetime.date(2021, 2, 6)],
|
||||||
|
]
|
||||||
|
|
||||||
|
self.assertEqual(ranges, expected_ranges)
|
||||||
|
|
||||||
|
def test_get_period_date_ranges_yearly(self):
|
||||||
|
|
||||||
|
filters = _dict(range="Yearly", from_date="2021-01-28", to_date="2021-02-06")
|
||||||
|
|
||||||
|
ranges = get_period_date_ranges(filters)
|
||||||
|
first_date = get_fiscal_year("2021-01-28")[1]
|
||||||
|
expected_ranges = [
|
||||||
|
[first_date, datetime.date(2021, 2, 6)],
|
||||||
|
]
|
||||||
|
|
||||||
|
self.assertEqual(ranges, expected_ranges)
|
@ -23,6 +23,7 @@ def execute(filters=None):
|
|||||||
conversion_factors = []
|
conversion_factors = []
|
||||||
if opening_row:
|
if opening_row:
|
||||||
data.append(opening_row)
|
data.append(opening_row)
|
||||||
|
conversion_factors.append(0)
|
||||||
|
|
||||||
actual_qty = stock_value = 0
|
actual_qty = stock_value = 0
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user