Merge branch 'develop' into remove-nonprofit
This commit is contained in:
commit
768e6b2e0e
@ -8,6 +8,7 @@ frappe.provide("erpnext.journal_entry");
|
||||
frappe.ui.form.on("Journal Entry", {
|
||||
setup: function(frm) {
|
||||
frm.add_fetch("bank_account", "account", "account");
|
||||
frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice'];
|
||||
},
|
||||
|
||||
refresh: function(frm) {
|
||||
|
@ -537,8 +537,11 @@ class PurchaseInvoice(BuyingController):
|
||||
|
||||
voucher_wise_stock_value = {}
|
||||
if self.update_stock:
|
||||
for d in frappe.get_all('Stock Ledger Entry',
|
||||
fields = ["voucher_detail_no", "stock_value_difference", "warehouse"], filters={'voucher_no': self.name}):
|
||||
stock_ledger_entries = frappe.get_all("Stock Ledger Entry",
|
||||
fields = ["voucher_detail_no", "stock_value_difference", "warehouse"],
|
||||
filters={"voucher_no": self.name, "voucher_type": self.doctype, "is_cancelled": 0}
|
||||
)
|
||||
for d in stock_ledger_entries:
|
||||
voucher_wise_stock_value.setdefault((d.voucher_detail_no, d.warehouse), d.stock_value_difference)
|
||||
|
||||
valuation_tax_accounts = [d.account_head for d in self.get("taxes")
|
||||
|
@ -120,11 +120,11 @@ def check_opening_balance(asset, liability, equity):
|
||||
opening_balance = 0
|
||||
float_precision = cint(frappe.db.get_default("float_precision")) or 2
|
||||
if asset:
|
||||
opening_balance = flt(asset[0].get("opening_balance", 0), float_precision)
|
||||
opening_balance = flt(asset[-1].get("opening_balance", 0), float_precision)
|
||||
if liability:
|
||||
opening_balance -= flt(liability[0].get("opening_balance", 0), float_precision)
|
||||
opening_balance -= flt(liability[-1].get("opening_balance", 0), float_precision)
|
||||
if equity:
|
||||
opening_balance -= flt(equity[0].get("opening_balance", 0), float_precision)
|
||||
opening_balance -= flt(equity[-1].get("opening_balance", 0), float_precision)
|
||||
|
||||
opening_balance = flt(opening_balance, float_precision)
|
||||
if opening_balance:
|
||||
|
@ -282,7 +282,8 @@ def add_total_row(out, root_type, balance_must_be, period_list, company_currency
|
||||
total_row = {
|
||||
"account_name": _("Total {0} ({1})").format(_(root_type), _(balance_must_be)),
|
||||
"account": _("Total {0} ({1})").format(_(root_type), _(balance_must_be)),
|
||||
"currency": company_currency
|
||||
"currency": company_currency,
|
||||
"opening_balance": 0.0
|
||||
}
|
||||
|
||||
for row in out:
|
||||
@ -294,6 +295,7 @@ def add_total_row(out, root_type, balance_must_be, period_list, company_currency
|
||||
|
||||
total_row.setdefault("total", 0.0)
|
||||
total_row["total"] += flt(row["total"])
|
||||
total_row["opening_balance"] += row["opening_balance"]
|
||||
row["total"] = ""
|
||||
|
||||
if "total" in total_row:
|
||||
|
@ -400,6 +400,16 @@ class StatusUpdater(Document):
|
||||
ref_doc = frappe.get_doc(ref_dt, ref_dn)
|
||||
|
||||
ref_doc.db_set("per_billed", per_billed)
|
||||
|
||||
# set billling status
|
||||
if hasattr(ref_doc, 'billing_status'):
|
||||
if ref_doc.per_billed < 0.001:
|
||||
ref_doc.db_set("billing_status", "Not Billed")
|
||||
elif ref_doc.per_billed > 99.999999:
|
||||
ref_doc.db_set("billing_status", "Fully Billed")
|
||||
else:
|
||||
ref_doc.db_set("billing_status", "Partly Billed")
|
||||
|
||||
ref_doc.set_status(update=True)
|
||||
|
||||
def get_allowance_for(item_code, item_allowance=None, global_qty_allowance=None, global_amount_allowance=None, qty_or_amount="qty"):
|
||||
|
@ -172,10 +172,15 @@ class ProductionPlanReport(object):
|
||||
|
||||
self.purchase_details = {}
|
||||
|
||||
for d in frappe.get_all("Purchase Order Item",
|
||||
purchased_items = frappe.get_all("Purchase Order Item",
|
||||
fields=["item_code", "min(schedule_date) as arrival_date", "qty as arrival_qty", "warehouse"],
|
||||
filters = {"item_code": ("in", self.item_codes), "warehouse": ("in", self.warehouses)},
|
||||
group_by = "item_code, warehouse"):
|
||||
filters={
|
||||
"item_code": ("in", self.item_codes),
|
||||
"warehouse": ("in", self.warehouses),
|
||||
"docstatus": 1,
|
||||
},
|
||||
group_by = "item_code, warehouse")
|
||||
for d in purchased_items:
|
||||
key = (d.item_code, d.warehouse)
|
||||
if key not in self.purchase_details:
|
||||
self.purchase_details.setdefault(key, d)
|
||||
|
@ -58,6 +58,7 @@
|
||||
"width": "50%"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
"default": "Yes",
|
||||
"fieldname": "is_active",
|
||||
"fieldtype": "Select",
|
||||
@ -232,10 +233,11 @@
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2021-03-31 15:41:12.342380",
|
||||
"modified": "2022-02-03 23:50:10.205676",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Payroll",
|
||||
"name": "Salary Structure",
|
||||
"naming_rule": "Set by user",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
@ -271,5 +273,6 @@
|
||||
],
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC"
|
||||
"sort_order": "DESC",
|
||||
"states": []
|
||||
}
|
@ -295,6 +295,10 @@ class GSTR3BReport(Document):
|
||||
inter_state_supply_details = {}
|
||||
|
||||
for inv, items_based_on_rate in self.items_based_on_tax_rate.items():
|
||||
gst_category = self.invoice_detail_map.get(inv, {}).get('gst_category')
|
||||
place_of_supply = self.invoice_detail_map.get(inv, {}).get('place_of_supply') or '00-Other Territory'
|
||||
export_type = self.invoice_detail_map.get(inv, {}).get('export_type')
|
||||
|
||||
for rate, items in items_based_on_rate.items():
|
||||
for item_code, taxable_value in self.invoice_items.get(inv).items():
|
||||
if item_code in items:
|
||||
@ -302,9 +306,8 @@ class GSTR3BReport(Document):
|
||||
self.report_dict['sup_details']['osup_nil_exmp']['txval'] += taxable_value
|
||||
elif item_code in self.is_non_gst:
|
||||
self.report_dict['sup_details']['osup_nongst']['txval'] += taxable_value
|
||||
elif rate == 0:
|
||||
elif rate == 0 or (gst_category == 'Overseas' and export_type == 'Without Payment of Tax'):
|
||||
self.report_dict['sup_details']['osup_zero']['txval'] += taxable_value
|
||||
#self.report_dict['sup_details']['osup_zero'][key] += tax_amount
|
||||
else:
|
||||
if inv in self.cgst_sgst_invoices:
|
||||
tax_rate = rate/2
|
||||
@ -315,9 +318,6 @@ class GSTR3BReport(Document):
|
||||
self.report_dict['sup_details']['osup_det']['iamt'] += (taxable_value * rate /100)
|
||||
self.report_dict['sup_details']['osup_det']['txval'] += taxable_value
|
||||
|
||||
gst_category = self.invoice_detail_map.get(inv, {}).get('gst_category')
|
||||
place_of_supply = self.invoice_detail_map.get(inv, {}).get('place_of_supply') or '00-Other Territory'
|
||||
|
||||
if gst_category in ['Unregistered', 'Registered Composition', 'UIN Holders'] and \
|
||||
self.gst_details.get("gst_state") != place_of_supply.split("-")[1]:
|
||||
inter_state_supply_details.setdefault((gst_category, place_of_supply), {
|
||||
|
@ -1375,6 +1375,30 @@ class TestSalesOrder(ERPNextTestCase):
|
||||
|
||||
automatically_fetch_payment_terms(enable=0)
|
||||
|
||||
def test_zero_amount_sales_order_billing_status(self):
|
||||
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
||||
|
||||
so = make_sales_order(uom="Nos", do_not_save=1)
|
||||
so.items[0].rate = 0
|
||||
so.save()
|
||||
so.submit()
|
||||
|
||||
self.assertEqual(so.net_total, 0)
|
||||
self.assertEqual(so.billing_status, 'Not Billed')
|
||||
|
||||
si = create_sales_invoice(qty=10, do_not_save=1)
|
||||
si.price_list = '_Test Price List'
|
||||
si.items[0].rate = 0
|
||||
si.items[0].price_list_rate = 0
|
||||
si.items[0].sales_order = so.name
|
||||
si.items[0].so_detail = so.items[0].name
|
||||
si.save()
|
||||
si.submit()
|
||||
|
||||
self.assertEqual(si.net_total, 0)
|
||||
so.load_from_db()
|
||||
self.assertEqual(so.billing_status, 'Fully Billed')
|
||||
|
||||
def automatically_fetch_payment_terms(enable=1):
|
||||
accounts_settings = frappe.get_doc("Accounts Settings")
|
||||
accounts_settings.automatically_fetch_payment_terms = enable
|
||||
|
@ -4,10 +4,11 @@
|
||||
|
||||
|
||||
import frappe
|
||||
from frappe.utils import flt
|
||||
from frappe.utils import add_to_date, flt, now
|
||||
|
||||
from erpnext.accounts.doctype.account.test_account import create_account, get_inventory_account
|
||||
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
|
||||
from erpnext.accounts.utils import update_gl_entries_after
|
||||
from erpnext.assets.doctype.asset.test_asset import create_asset_category, create_fixed_asset_item
|
||||
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import (
|
||||
get_gl_entries,
|
||||
@ -28,7 +29,8 @@ class TestLandedCostVoucher(ERPNextTestCase):
|
||||
"voucher_type": pr.doctype,
|
||||
"voucher_no": pr.name,
|
||||
"item_code": "_Test Item",
|
||||
"warehouse": "Stores - TCP1"
|
||||
"warehouse": "Stores - TCP1",
|
||||
"is_cancelled": 0,
|
||||
},
|
||||
fieldname=["qty_after_transaction", "stock_value"], as_dict=1)
|
||||
|
||||
@ -41,14 +43,39 @@ class TestLandedCostVoucher(ERPNextTestCase):
|
||||
"voucher_type": pr.doctype,
|
||||
"voucher_no": pr.name,
|
||||
"item_code": "_Test Item",
|
||||
"warehouse": "Stores - TCP1"
|
||||
"warehouse": "Stores - TCP1",
|
||||
"is_cancelled": 0,
|
||||
},
|
||||
fieldname=["qty_after_transaction", "stock_value"], as_dict=1)
|
||||
|
||||
self.assertEqual(last_sle.qty_after_transaction, last_sle_after_landed_cost.qty_after_transaction)
|
||||
|
||||
self.assertEqual(last_sle_after_landed_cost.stock_value - last_sle.stock_value, 25.0)
|
||||
|
||||
# assert after submit
|
||||
self.assertPurchaseReceiptLCVGLEntries(pr)
|
||||
|
||||
# Mess up cancelled SLE modified timestamp to check
|
||||
# if they aren't effective in any business logic.
|
||||
frappe.db.set_value("Stock Ledger Entry",
|
||||
{
|
||||
"is_cancelled": 1,
|
||||
"voucher_type": pr.doctype,
|
||||
"voucher_no": pr.name
|
||||
},
|
||||
"is_cancelled", 1,
|
||||
modified=add_to_date(now(), hours=1, as_datetime=True, as_string=True)
|
||||
)
|
||||
|
||||
items, warehouses = pr.get_items_and_warehouses()
|
||||
update_gl_entries_after(pr.posting_date, pr.posting_time,
|
||||
warehouses, items, company=pr.company)
|
||||
|
||||
# reassert after reposting
|
||||
self.assertPurchaseReceiptLCVGLEntries(pr)
|
||||
|
||||
|
||||
def assertPurchaseReceiptLCVGLEntries(self, pr):
|
||||
|
||||
gl_entries = get_gl_entries("Purchase Receipt", pr.name)
|
||||
|
||||
self.assertTrue(gl_entries)
|
||||
@ -74,8 +101,8 @@ class TestLandedCostVoucher(ERPNextTestCase):
|
||||
|
||||
for gle in gl_entries:
|
||||
if not gle.get('is_cancelled'):
|
||||
self.assertEqual(expected_values[gle.account][0], gle.debit)
|
||||
self.assertEqual(expected_values[gle.account][1], gle.credit)
|
||||
self.assertEqual(expected_values[gle.account][0], gle.debit, msg=f"incorrect debit for {gle.account}")
|
||||
self.assertEqual(expected_values[gle.account][1], gle.credit, msg=f"incorrect credit for {gle.account}")
|
||||
|
||||
|
||||
def test_landed_cost_voucher_against_purchase_invoice(self):
|
||||
|
@ -27,8 +27,7 @@ def make_packing_list(doc):
|
||||
|
||||
stale_packed_items_table = get_indexed_packed_items_table(doc)
|
||||
|
||||
if not doc.is_new():
|
||||
reset = reset_packing_list_if_deleted_items_exist(doc)
|
||||
reset = reset_packing_list(doc)
|
||||
|
||||
for item_row in doc.get("items"):
|
||||
if frappe.db.exists("Product Bundle", {"new_item_code": item_row.item_code}):
|
||||
@ -64,20 +63,24 @@ def get_indexed_packed_items_table(doc):
|
||||
|
||||
return indexed_table
|
||||
|
||||
def reset_packing_list_if_deleted_items_exist(doc):
|
||||
doc_before_save = doc.get_doc_before_save()
|
||||
def reset_packing_list(doc):
|
||||
"Conditionally reset the table and return if it was reset or not."
|
||||
reset_table = False
|
||||
doc_before_save = doc.get_doc_before_save()
|
||||
|
||||
if doc_before_save:
|
||||
# reset table if:
|
||||
# 1. items were deleted
|
||||
# 2. if bundle item replaced by another item (same no. of items but different items)
|
||||
# we maintain list to maintain repeated item rows as well
|
||||
# we maintain list to track recurring item rows as well
|
||||
items_before_save = [item.item_code for item in doc_before_save.get("items")]
|
||||
items_after_save = [item.item_code for item in doc.get("items")]
|
||||
reset_table = items_before_save != items_after_save
|
||||
else:
|
||||
reset_table = True # reset if via Update Items (cannot determine action)
|
||||
# reset: if via Update Items OR
|
||||
# if new mapped doc with packed items set (SO -> DN)
|
||||
# (cannot determine action)
|
||||
reset_table = True
|
||||
|
||||
if reset_table:
|
||||
doc.set("packed_items", [])
|
||||
|
@ -2,6 +2,7 @@
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle
|
||||
from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note
|
||||
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
from erpnext.tests.utils import ERPNextTestCase, change_settings
|
||||
@ -22,7 +23,7 @@ class TestPackedItem(ERPNextTestCase):
|
||||
qty=2
|
||||
)
|
||||
|
||||
def test_sales_order_adding_bundle_item(self):
|
||||
def test_adding_bundle_item(self):
|
||||
"Test impact on packed items if bundle item row is added."
|
||||
so = make_sales_order(item_code = "_Test Product Bundle X", qty=1,
|
||||
do_not_submit=True)
|
||||
@ -32,7 +33,7 @@ class TestPackedItem(ERPNextTestCase):
|
||||
self.assertEqual(so.packed_items[0].item_code, "_Test Bundle Item 1")
|
||||
self.assertEqual(so.packed_items[0].qty, 2)
|
||||
|
||||
def test_sales_order_updating_bundle_item(self):
|
||||
def test_updating_bundle_item(self):
|
||||
"Test impact on packed items if bundle item row is updated."
|
||||
so = make_sales_order(item_code = "_Test Product Bundle X", qty=1,
|
||||
do_not_submit=True)
|
||||
@ -49,7 +50,7 @@ class TestPackedItem(ERPNextTestCase):
|
||||
|
||||
self.assertEqual(len(so.packed_items), 0)
|
||||
|
||||
def test_sales_order_recurring_bundle_item(self):
|
||||
def test_recurring_bundle_item(self):
|
||||
"Test impact on packed items if same bundle item is added and removed."
|
||||
so_items = []
|
||||
for qty in [2, 4, 6, 8]:
|
||||
@ -91,7 +92,7 @@ class TestPackedItem(ERPNextTestCase):
|
||||
self.assertEqual(so.packed_items[3].qty, 12)
|
||||
|
||||
@change_settings("Selling Settings", {"editable_bundle_item_rates": 1})
|
||||
def test_sales_order_bundle_item_cumulative_price(self):
|
||||
def test_bundle_item_cumulative_price(self):
|
||||
"Test if Bundle Item rate is cumulative from packed items."
|
||||
so = make_sales_order(item_code = "_Test Product Bundle X", qty=2,
|
||||
do_not_submit=True)
|
||||
@ -102,3 +103,25 @@ class TestPackedItem(ERPNextTestCase):
|
||||
|
||||
self.assertEqual(so.items[0].rate, 350)
|
||||
self.assertEqual(so.items[0].amount, 700)
|
||||
|
||||
def test_newly_mapped_doc_packed_items(self):
|
||||
"Test impact on packed items in newly mapped DN from SO."
|
||||
so_items = []
|
||||
for qty in [2, 4]:
|
||||
so_items.append({
|
||||
"item_code": "_Test Product Bundle X",
|
||||
"qty": qty,
|
||||
"rate": 400,
|
||||
"warehouse": "_Test Warehouse - _TC"
|
||||
})
|
||||
|
||||
# create SO with recurring bundle item
|
||||
so = make_sales_order(item_list=so_items)
|
||||
|
||||
dn = make_delivery_note(so.name)
|
||||
dn.items[1].qty = 3 # change second row qty for inserting doc
|
||||
dn.save()
|
||||
|
||||
self.assertEqual(len(dn.packed_items), 4)
|
||||
self.assertEqual(dn.packed_items[2].qty, 6)
|
||||
self.assertEqual(dn.packed_items[3].qty, 6)
|
@ -286,7 +286,7 @@ class PurchaseReceipt(BuyingController):
|
||||
if warehouse_account.get(d.warehouse):
|
||||
stock_value_diff = frappe.db.get_value("Stock Ledger Entry",
|
||||
{"voucher_type": "Purchase Receipt", "voucher_no": self.name,
|
||||
"voucher_detail_no": d.name, "warehouse": d.warehouse}, "stock_value_difference")
|
||||
"voucher_detail_no": d.name, "warehouse": d.warehouse, "is_cancelled": 0}, "stock_value_difference")
|
||||
|
||||
if not stock_value_diff:
|
||||
continue
|
||||
|
Loading…
Reference in New Issue
Block a user