Merge branch 'develop' into fix_picked_qty_in_DN
This commit is contained in:
commit
bc50193702
@ -12,6 +12,10 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_pu
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
|
||||
class TestPOSInvoice(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
frappe.db.sql("delete from `tabTax Rule`")
|
||||
|
||||
def tearDown(self):
|
||||
if frappe.session.user != "Administrator":
|
||||
frappe.set_user("Administrator")
|
||||
|
@ -14,10 +14,15 @@ test_records = frappe.get_test_records('Tax Rule')
|
||||
from six import iteritems
|
||||
|
||||
class TestTaxRule(unittest.TestCase):
|
||||
def setUp(self):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
frappe.db.set_value("Shopping Cart Settings", None, "enabled", 0)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
frappe.db.sql("delete from `tabTax Rule`")
|
||||
|
||||
def tearDown(self):
|
||||
def setUp(self):
|
||||
frappe.db.sql("delete from `tabTax Rule`")
|
||||
|
||||
def test_conflict(self):
|
||||
|
@ -368,7 +368,6 @@ def make_purchase_receipt(source_name, target_doc=None):
|
||||
"Purchase Order": {
|
||||
"doctype": "Purchase Receipt",
|
||||
"field_map": {
|
||||
"per_billed": "per_billed",
|
||||
"supplier_warehouse":"supplier_warehouse"
|
||||
},
|
||||
"validation": {
|
||||
|
@ -113,10 +113,10 @@ class calculate_taxes_and_totals(object):
|
||||
item.rate_with_margin, item.base_rate_with_margin = self.calculate_margin(item)
|
||||
if flt(item.rate_with_margin) > 0:
|
||||
item.rate = flt(item.rate_with_margin * (1.0 - (item.discount_percentage / 100.0)), item.precision("rate"))
|
||||
if not item.discount_amount:
|
||||
item.discount_amount = item.rate_with_margin - item.rate
|
||||
elif not item.discount_percentage:
|
||||
if item.discount_amount and not item.discount_percentage:
|
||||
item.rate -= item.discount_amount
|
||||
else:
|
||||
item.discount_amount = item.rate_with_margin - item.rate
|
||||
elif flt(item.price_list_rate) > 0:
|
||||
item.discount_amount = item.price_list_rate - item.rate
|
||||
elif flt(item.price_list_rate) > 0 and not item.discount_amount:
|
||||
@ -808,4 +808,4 @@ class init_landed_taxes_and_totals(object):
|
||||
def set_amounts_in_company_currency(self):
|
||||
for d in self.doc.get(self.tax_field):
|
||||
d.amount = flt(d.amount, d.precision("amount"))
|
||||
d.base_amount = flt(d.amount * flt(d.exchange_rate), d.precision("base_amount"))
|
||||
d.base_amount = flt(d.amount * flt(d.exchange_rate), d.precision("base_amount"))
|
||||
|
@ -81,15 +81,8 @@ class TestInpatientMedicationOrder(unittest.TestCase):
|
||||
self.ip_record.reload()
|
||||
discharge_patient(self.ip_record)
|
||||
|
||||
for entry in frappe.get_all('Inpatient Medication Entry'):
|
||||
doc = frappe.get_doc('Inpatient Medication Entry', entry.name)
|
||||
doc.cancel()
|
||||
doc.delete()
|
||||
|
||||
for entry in frappe.get_all('Inpatient Medication Order'):
|
||||
doc = frappe.get_doc('Inpatient Medication Order', entry.name)
|
||||
doc.cancel()
|
||||
doc.delete()
|
||||
for doctype in ["Inpatient Medication Entry", "Inpatient Medication Order"]:
|
||||
frappe.db.sql("delete from `tab{doctype}`".format(doctype=doctype))
|
||||
|
||||
def create_dosage_form():
|
||||
if not frappe.db.exists('Dosage Form', 'Tablet'):
|
||||
|
@ -56,6 +56,7 @@ class TestLeaveApplication(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
set_leave_approver()
|
||||
frappe.db.sql("delete from tabAttendance where employee='_T-Employee-00001'")
|
||||
|
||||
def tearDown(self):
|
||||
frappe.set_user("Administrator")
|
||||
@ -230,8 +231,9 @@ class TestLeaveApplication(unittest.TestCase):
|
||||
def test_optional_leave(self):
|
||||
leave_period = get_leave_period()
|
||||
today = nowdate()
|
||||
from datetime import date
|
||||
holiday_list = 'Test Holiday List for Optional Holiday'
|
||||
optional_leave_date = add_days(today, 7)
|
||||
|
||||
if not frappe.db.exists('Holiday List', holiday_list):
|
||||
frappe.get_doc(dict(
|
||||
doctype = 'Holiday List',
|
||||
@ -239,7 +241,7 @@ class TestLeaveApplication(unittest.TestCase):
|
||||
from_date = add_months(today, -6),
|
||||
to_date = add_months(today, 6),
|
||||
holidays = [
|
||||
dict(holiday_date = today, description = 'Test')
|
||||
dict(holiday_date = optional_leave_date, description = 'Test')
|
||||
]
|
||||
)).insert()
|
||||
employee = get_employee()
|
||||
@ -255,7 +257,7 @@ class TestLeaveApplication(unittest.TestCase):
|
||||
|
||||
allocate_leaves(employee, leave_period, leave_type, 10)
|
||||
|
||||
date = add_days(today, - 1)
|
||||
date = add_days(today, 6)
|
||||
|
||||
leave_application = frappe.get_doc(dict(
|
||||
doctype = 'Leave Application',
|
||||
@ -270,14 +272,14 @@ class TestLeaveApplication(unittest.TestCase):
|
||||
# can only apply on optional holidays
|
||||
self.assertRaises(NotAnOptionalHoliday, leave_application.insert)
|
||||
|
||||
leave_application.from_date = today
|
||||
leave_application.to_date = today
|
||||
leave_application.from_date = optional_leave_date
|
||||
leave_application.to_date = optional_leave_date
|
||||
leave_application.status = "Approved"
|
||||
leave_application.insert()
|
||||
leave_application.submit()
|
||||
|
||||
# check leave balance is reduced
|
||||
self.assertEqual(get_leave_balance_on(employee.name, leave_type, today), 9)
|
||||
self.assertEqual(get_leave_balance_on(employee.name, leave_type, optional_leave_date), 9)
|
||||
|
||||
def test_leaves_allowed(self):
|
||||
employee = get_employee()
|
||||
@ -341,7 +343,7 @@ class TestLeaveApplication(unittest.TestCase):
|
||||
to_date = add_days(date, 4),
|
||||
company = "_Test Company",
|
||||
docstatus = 1,
|
||||
status = "Approved"
|
||||
status = "Approved"
|
||||
))
|
||||
|
||||
self.assertRaises(frappe.ValidationError, leave_application.insert)
|
||||
@ -363,7 +365,7 @@ class TestLeaveApplication(unittest.TestCase):
|
||||
to_date = add_days(date, 4),
|
||||
company = "_Test Company",
|
||||
docstatus = 1,
|
||||
status = "Approved"
|
||||
status = "Approved"
|
||||
))
|
||||
|
||||
self.assertTrue(leave_application.insert())
|
||||
@ -393,7 +395,7 @@ class TestLeaveApplication(unittest.TestCase):
|
||||
to_date = add_days(date, 4),
|
||||
company = "_Test Company",
|
||||
docstatus = 1,
|
||||
status = "Approved"
|
||||
status = "Approved"
|
||||
))
|
||||
|
||||
self.assertRaises(frappe.ValidationError, leave_application.insert)
|
||||
@ -508,7 +510,7 @@ class TestLeaveApplication(unittest.TestCase):
|
||||
description = "_Test Reason",
|
||||
company = "_Test Company",
|
||||
docstatus = 1,
|
||||
status = "Approved"
|
||||
status = "Approved"
|
||||
))
|
||||
leave_application.submit()
|
||||
leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=dict(transaction_name=leave_application.name))
|
||||
@ -540,7 +542,7 @@ class TestLeaveApplication(unittest.TestCase):
|
||||
description = "_Test Reason",
|
||||
company = "_Test Company",
|
||||
docstatus = 1,
|
||||
status = "Approved"
|
||||
status = "Approved"
|
||||
))
|
||||
leave_application.submit()
|
||||
|
||||
|
@ -52,7 +52,9 @@ def create_leave_ledger_entry(ref_doc, args, submit=True):
|
||||
ledger.update(args)
|
||||
|
||||
if submit:
|
||||
frappe.get_doc(ledger).submit()
|
||||
doc = frappe.get_doc(ledger)
|
||||
doc.flags.ignore_permissions = 1
|
||||
doc.submit()
|
||||
else:
|
||||
delete_ledger_entry(ledger)
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "LM-LSS-.#####",
|
||||
"creation": "2019-09-06 11:33:34.709540",
|
||||
"doctype": "DocType",
|
||||
@ -14,6 +15,7 @@
|
||||
"shortfall_amount",
|
||||
"column_break_8",
|
||||
"security_value",
|
||||
"shortfall_percentage",
|
||||
"section_break_8",
|
||||
"process_loan_security_shortfall"
|
||||
],
|
||||
@ -85,10 +87,18 @@
|
||||
{
|
||||
"fieldname": "column_break_8",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "shortfall_percentage",
|
||||
"fieldtype": "Percent",
|
||||
"label": "Shortfall Percentage",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"in_create": 1,
|
||||
"modified": "2019-10-24 06:24:26.128997",
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2021-04-01 08:13:43.263772",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Loan Management",
|
||||
"name": "Loan Security Shortfall",
|
||||
|
@ -22,7 +22,9 @@ def update_shortfall_status(loan, security_value):
|
||||
if security_value >= loan_security_shortfall.shortfall_amount:
|
||||
frappe.db.set_value("Loan Security Shortfall", loan_security_shortfall.name, {
|
||||
"status": "Completed",
|
||||
"shortfall_amount": loan_security_shortfall.shortfall_amount})
|
||||
"shortfall_amount": loan_security_shortfall.shortfall_amount,
|
||||
"shortfall_percentage": 0
|
||||
})
|
||||
else:
|
||||
frappe.db.set_value("Loan Security Shortfall", loan_security_shortfall.name,
|
||||
"shortfall_amount", loan_security_shortfall.shortfall_amount - security_value)
|
||||
@ -65,7 +67,8 @@ def check_for_ltv_shortfall(process_loan_security_shortfall):
|
||||
outstanding_amount = flt(loan.total_payment) - flt(loan.total_interest_payable) \
|
||||
- flt(loan.total_principal_paid)
|
||||
else:
|
||||
outstanding_amount = loan.disbursed_amount
|
||||
outstanding_amount = flt(loan.disbursed_amount) - flt(loan.total_interest_payable) \
|
||||
- flt(loan.total_principal_paid)
|
||||
|
||||
pledged_securities = get_pledged_security_qty(loan.name)
|
||||
ltv_ratio = ''
|
||||
@ -81,14 +84,15 @@ def check_for_ltv_shortfall(process_loan_security_shortfall):
|
||||
if current_ratio > ltv_ratio:
|
||||
shortfall_amount = outstanding_amount - ((security_value * ltv_ratio) / 100)
|
||||
create_loan_security_shortfall(loan.name, outstanding_amount, security_value, shortfall_amount,
|
||||
process_loan_security_shortfall)
|
||||
current_ratio, process_loan_security_shortfall)
|
||||
elif loan_shortfall_map.get(loan.name):
|
||||
shortfall_amount = outstanding_amount - ((security_value * ltv_ratio) / 100)
|
||||
if shortfall_amount <= 0:
|
||||
shortfall = loan_shortfall_map.get(loan.name)
|
||||
update_pending_shortfall(shortfall)
|
||||
|
||||
def create_loan_security_shortfall(loan, loan_amount, security_value, shortfall_amount, process_loan_security_shortfall):
|
||||
def create_loan_security_shortfall(loan, loan_amount, security_value, shortfall_amount, shortfall_ratio,
|
||||
process_loan_security_shortfall):
|
||||
existing_shortfall = frappe.db.get_value("Loan Security Shortfall", {"loan": loan, "status": "Pending"}, "name")
|
||||
|
||||
if existing_shortfall:
|
||||
@ -101,6 +105,7 @@ def create_loan_security_shortfall(loan, loan_amount, security_value, shortfall_
|
||||
ltv_shortfall.loan_amount = loan_amount
|
||||
ltv_shortfall.security_value = security_value
|
||||
ltv_shortfall.shortfall_amount = shortfall_amount
|
||||
ltv_shortfall.shortfall_percentage = shortfall_ratio
|
||||
ltv_shortfall.process_loan_security_shortfall = process_loan_security_shortfall
|
||||
ltv_shortfall.save()
|
||||
|
||||
@ -114,6 +119,7 @@ def update_pending_shortfall(shortfall):
|
||||
frappe.db.set_value("Loan Security Shortfall", shortfall,
|
||||
{
|
||||
"status": "Completed",
|
||||
"shortfall_amount": 0
|
||||
"shortfall_amount": 0,
|
||||
"shortfall_percentage": 0
|
||||
})
|
||||
|
||||
|
@ -63,9 +63,11 @@ def get_active_loan_details(filters):
|
||||
currency = erpnext.get_company_currency(filters.get('company'))
|
||||
|
||||
for loan in loan_details:
|
||||
total_payment = loan.total_payment if loan.status == 'Disbursed' else loan.disbursed_amount
|
||||
|
||||
loan.update({
|
||||
"sanctioned_amount": flt(sanctioned_amount_map.get(loan.applicant_name)),
|
||||
"principal_outstanding": flt(loan.total_payment) - flt(loan.total_principal_paid) \
|
||||
"principal_outstanding": flt(total_payment) - flt(loan.total_principal_paid) \
|
||||
- flt(loan.total_interest_payable) - flt(loan.written_off_amount),
|
||||
"total_repayment": flt(payments.get(loan.loan)),
|
||||
"accrued_interest": flt(accrual_map.get(loan.loan, {}).get("accrued_interest")),
|
||||
|
@ -134,7 +134,13 @@ class TestBOM(unittest.TestCase):
|
||||
bom.items[0].conversion_factor = 6
|
||||
bom.insert()
|
||||
|
||||
reset_item_valuation_rate(item_code='_Test Item', qty=200, rate=200)
|
||||
reset_item_valuation_rate(
|
||||
item_code='_Test Item',
|
||||
warehouse_list=frappe.get_all("Warehouse",
|
||||
{"is_group":0, "company": bom.company}, pluck="name"),
|
||||
qty=200,
|
||||
rate=200
|
||||
)
|
||||
|
||||
bom.update_cost()
|
||||
|
||||
|
@ -13,8 +13,15 @@ from erpnext.manufacturing.doctype.workstation.test_workstation import make_work
|
||||
from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record
|
||||
|
||||
class TestRouting(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.item_code = "Test Routing Item - A"
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
frappe.db.sql('delete from tabBOM where item=%s', cls.item_code)
|
||||
|
||||
def test_sequence_id(self):
|
||||
item_code = "Test Routing Item - A"
|
||||
operations = [{"operation": "Test Operation A", "workstation": "Test Workstation A", "time_in_mins": 30},
|
||||
{"operation": "Test Operation B", "workstation": "Test Workstation A", "time_in_mins": 20}]
|
||||
|
||||
@ -22,8 +29,8 @@ class TestRouting(unittest.TestCase):
|
||||
|
||||
setup_operations(operations)
|
||||
routing_doc = create_routing(routing_name="Testing Route", operations=operations)
|
||||
bom_doc = setup_bom(item_code=item_code, routing=routing_doc.name)
|
||||
wo_doc = make_wo_order_test_record(production_item = item_code, bom_no=bom_doc.name)
|
||||
bom_doc = setup_bom(item_code=self.item_code, routing=routing_doc.name)
|
||||
wo_doc = make_wo_order_test_record(production_item = self.item_code, bom_no=bom_doc.name)
|
||||
|
||||
for row in routing_doc.operations:
|
||||
self.assertEqual(row.sequence_id, row.idx)
|
||||
|
@ -371,14 +371,14 @@ class TestWorkOrder(unittest.TestCase):
|
||||
|
||||
def test_job_card(self):
|
||||
stock_entries = []
|
||||
data = frappe.get_cached_value('BOM',
|
||||
{'docstatus': 1, 'with_operations': 1, 'company': '_Test Company'}, ['name', 'item'])
|
||||
bom = frappe.get_doc('BOM', {
|
||||
'docstatus': 1,
|
||||
'with_operations': 1,
|
||||
'company': '_Test Company'
|
||||
})
|
||||
|
||||
bom, bom_item = data
|
||||
|
||||
bom_doc = frappe.get_doc('BOM', bom)
|
||||
work_order = make_wo_order_test_record(item=bom_item, qty=1,
|
||||
bom_no=bom, source_warehouse="_Test Warehouse - _TC")
|
||||
work_order = make_wo_order_test_record(item=bom.item, qty=1,
|
||||
bom_no=bom.name, source_warehouse="_Test Warehouse - _TC")
|
||||
|
||||
for row in work_order.required_items:
|
||||
stock_entry_doc = test_stock_entry.make_stock_entry(item_code=row.item_code,
|
||||
@ -390,14 +390,14 @@ class TestWorkOrder(unittest.TestCase):
|
||||
stock_entries.append(ste)
|
||||
|
||||
job_cards = frappe.get_all('Job Card', filters = {'work_order': work_order.name})
|
||||
self.assertEqual(len(job_cards), len(bom_doc.operations))
|
||||
self.assertEqual(len(job_cards), len(bom.operations))
|
||||
|
||||
for i, job_card in enumerate(job_cards):
|
||||
doc = frappe.get_doc("Job Card", job_card)
|
||||
doc.append("time_logs", {
|
||||
"from_time": now(),
|
||||
"hours": i,
|
||||
"to_time": add_to_date(now(), i),
|
||||
"from_time": add_to_date(None, i),
|
||||
"hours": 1,
|
||||
"to_time": add_to_date(None, i + 1),
|
||||
"completed_qty": doc.for_quantity
|
||||
})
|
||||
doc.submit()
|
||||
|
@ -763,3 +763,4 @@ erpnext.patches.v13_0.setup_gratuity_rule_for_india_and_uae
|
||||
erpnext.patches.v13_0.setup_uae_vat_fields
|
||||
execute:frappe.db.set_value('System Settings', None, 'app_name', 'ERPNext')
|
||||
erpnext.patches.v13_0.rename_discharge_date_in_ip_record
|
||||
erpnext.patches.v12_0.purchase_receipt_status
|
||||
|
30
erpnext/patches/v12_0/purchase_receipt_status.py
Normal file
30
erpnext/patches/v12_0/purchase_receipt_status.py
Normal file
@ -0,0 +1,30 @@
|
||||
""" This patch fixes old purchase receipts (PR) where even after submitting
|
||||
the PR, the `status` remains "Draft". `per_billed` field was copied over from previous
|
||||
doc (PO), hence it is recalculated for setting new correct status of PR.
|
||||
"""
|
||||
|
||||
import frappe
|
||||
|
||||
logger = frappe.logger("patch", allow_site=True, file_count=50)
|
||||
|
||||
def execute():
|
||||
affected_purchase_receipts = frappe.db.sql(
|
||||
"""select name from `tabPurchase Receipt`
|
||||
where status = 'Draft' and per_billed = 100 and docstatus = 1"""
|
||||
)
|
||||
|
||||
if not affected_purchase_receipts:
|
||||
return
|
||||
|
||||
logger.info("purchase_receipt_status: begin patch, PR count: {}"
|
||||
.format(len(affected_purchase_receipts)))
|
||||
|
||||
|
||||
for pr in affected_purchase_receipts:
|
||||
pr_name = pr[0]
|
||||
logger.info("purchase_receipt_status: patching PR - {}".format(pr_name))
|
||||
|
||||
pr_doc = frappe.get_doc("Purchase Receipt", pr_name)
|
||||
|
||||
pr_doc.update_billing_status(update_modified=False)
|
||||
pr_doc.set_status(update=True, update_modified=False)
|
@ -6,6 +6,8 @@ def execute():
|
||||
if "Healthcare" not in frappe.get_active_domains():
|
||||
return
|
||||
|
||||
frappe.reload_doc("healthcare", "doctype", "Therapy Session")
|
||||
frappe.reload_doc("healthcare", "doctype", "Inpatient Medication Order")
|
||||
frappe.reload_doc("healthcare", "doctype", "Patient History Settings")
|
||||
frappe.reload_doc("healthcare", "doctype", "Patient History Standard Document Type")
|
||||
frappe.reload_doc("healthcare", "doctype", "Patient History Custom Document Type")
|
||||
|
@ -618,13 +618,16 @@ class SalarySlip(TransactionBase):
|
||||
|
||||
component_row = self.append(component_type)
|
||||
for attr in (
|
||||
'depends_on_payment_days', 'salary_component', 'abbr'
|
||||
'depends_on_payment_days', 'salary_component',
|
||||
'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))
|
||||
|
||||
abbr = component_data.get('abbr') or component_data.get('salary_component_abbr')
|
||||
component_row.set('abbr', abbr)
|
||||
|
||||
if additional_salary:
|
||||
component_row.default_amount = 0
|
||||
component_row.additional_amount = amount
|
||||
|
@ -100,7 +100,7 @@ class SalaryStructure(Document):
|
||||
from_date=from_date, base=base, variable=variable, income_tax_slab=income_tax_slab)
|
||||
else:
|
||||
assign_salary_structure_for_employees(employees, self,
|
||||
payroll_payable_account=payroll_payable_account,
|
||||
payroll_payable_account=payroll_payable_account,
|
||||
from_date=from_date, base=base, variable=variable, income_tax_slab=income_tax_slab)
|
||||
else:
|
||||
frappe.msgprint(_("No Employee Found"))
|
||||
|
@ -87,10 +87,10 @@ def get_doc_details(invoice):
|
||||
invoice_date=invoice_date
|
||||
))
|
||||
|
||||
def get_party_details(address_name):
|
||||
def get_party_details(address_name, company_address=None, billing_address=None, shipping_address=None):
|
||||
d = frappe.get_all('Address', filters={'name': address_name}, fields=['*'])[0]
|
||||
|
||||
if (not d.gstin
|
||||
if ((not d.gstin and not shipping_address)
|
||||
or not d.city
|
||||
or not d.pincode
|
||||
or not d.address_title
|
||||
@ -108,8 +108,7 @@ def get_party_details(address_name):
|
||||
# according to einvoice standard
|
||||
pincode = 999999
|
||||
|
||||
return frappe._dict(dict(
|
||||
gstin=d.gstin,
|
||||
party_address_details = frappe._dict(dict(
|
||||
legal_name=sanitize_for_json(d.address_title),
|
||||
location=sanitize_for_json(d.city),
|
||||
pincode=d.pincode,
|
||||
@ -117,6 +116,9 @@ def get_party_details(address_name):
|
||||
address_line1=sanitize_for_json(d.address_line1),
|
||||
address_line2=sanitize_for_json(d.address_line2)
|
||||
))
|
||||
if d.gstin:
|
||||
party_address_details.gstin = d.gstin
|
||||
return party_address_details
|
||||
|
||||
def get_gstin_details(gstin):
|
||||
if not hasattr(frappe.local, 'gstin_cache'):
|
||||
@ -328,12 +330,12 @@ def make_einvoice(invoice):
|
||||
item_list = get_item_list(invoice)
|
||||
doc_details = get_doc_details(invoice)
|
||||
invoice_value_details = get_invoice_value_details(invoice)
|
||||
seller_details = get_party_details(invoice.company_address)
|
||||
seller_details = get_party_details(invoice.company_address, company_address=1)
|
||||
|
||||
if invoice.gst_category == 'Overseas':
|
||||
buyer_details = get_overseas_address_details(invoice.customer_address)
|
||||
else:
|
||||
buyer_details = get_party_details(invoice.customer_address)
|
||||
buyer_details = get_party_details(invoice.customer_address, billing_address=1)
|
||||
place_of_supply = get_place_of_supply(invoice, invoice.doctype)
|
||||
if place_of_supply:
|
||||
place_of_supply = place_of_supply.split('-')[0]
|
||||
@ -346,7 +348,7 @@ def make_einvoice(invoice):
|
||||
if invoice.gst_category == 'Overseas':
|
||||
shipping_details = get_overseas_address_details(invoice.shipping_address_name)
|
||||
else:
|
||||
shipping_details = get_party_details(invoice.shipping_address_name)
|
||||
shipping_details = get_party_details(invoice.shipping_address_name, shipping_address=1)
|
||||
|
||||
if invoice.is_pos and invoice.base_paid_amount:
|
||||
payment_details = get_payment_details(invoice)
|
||||
@ -394,7 +396,9 @@ def safe_json_load(json_string):
|
||||
snippet = json_string[start:end]
|
||||
frappe.throw(_("Error in input data. Please check for any special characters near following input: <br> {}").format(snippet))
|
||||
|
||||
def validate_einvoice(validations, einvoice, errors=[]):
|
||||
def validate_einvoice(validations, einvoice, errors=None):
|
||||
if errors is None:
|
||||
errors = []
|
||||
for fieldname, field_validation in validations.items():
|
||||
value = einvoice.get(fieldname, None)
|
||||
if not value or value == "None":
|
||||
|
@ -16,6 +16,11 @@ class TestShoppingCart(unittest.TestCase):
|
||||
Note:
|
||||
Shopping Cart == Quotation
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
frappe.db.sql("delete from `tabTax Rule`")
|
||||
|
||||
def setUp(self):
|
||||
frappe.set_user("Administrator")
|
||||
create_test_contact_and_address()
|
||||
@ -51,8 +56,8 @@ class TestShoppingCart(unittest.TestCase):
|
||||
def test_add_to_cart(self):
|
||||
self.login_as_customer()
|
||||
|
||||
# remove from cart
|
||||
self.remove_all_items_from_cart()
|
||||
# clear existing quotations
|
||||
self.clear_existing_quotations()
|
||||
|
||||
# add first item
|
||||
update_cart("_Test Item", 1)
|
||||
@ -100,6 +105,7 @@ class TestShoppingCart(unittest.TestCase):
|
||||
self.assertEqual(len(quotation.get("items")), 1)
|
||||
|
||||
def test_tax_rule(self):
|
||||
self.create_tax_rule()
|
||||
self.login_as_customer()
|
||||
quotation = self.create_quotation()
|
||||
|
||||
@ -115,6 +121,13 @@ class TestShoppingCart(unittest.TestCase):
|
||||
|
||||
self.remove_test_quotation(quotation)
|
||||
|
||||
def create_tax_rule(self):
|
||||
tax_rule = frappe.get_test_records("Tax Rule")[0]
|
||||
try:
|
||||
frappe.get_doc(tax_rule).insert()
|
||||
except frappe.DuplicateEntryError:
|
||||
pass
|
||||
|
||||
def create_quotation(self):
|
||||
quotation = frappe.new_doc("Quotation")
|
||||
|
||||
@ -195,10 +208,15 @@ class TestShoppingCart(unittest.TestCase):
|
||||
"_Test Contact For _Test Customer")
|
||||
frappe.set_user("test_contact_customer@example.com")
|
||||
|
||||
def remove_all_items_from_cart(self):
|
||||
quotation = _get_cart_quotation()
|
||||
quotation.flags.ignore_permissions=True
|
||||
quotation.delete()
|
||||
def clear_existing_quotations(self):
|
||||
quotations = frappe.get_all("Quotation", filters={
|
||||
"party_name": get_party().name,
|
||||
"order_type": "Shopping Cart",
|
||||
"docstatus": 0
|
||||
}, order_by="modified desc", pluck="name")
|
||||
|
||||
for quotation in quotations:
|
||||
frappe.delete_doc("Quotation", quotation, ignore_permissions=True, force=True)
|
||||
|
||||
def create_user_if_not_exists(self, email, first_name = None):
|
||||
if frappe.db.exists("User", email):
|
||||
|
@ -23,7 +23,7 @@ class TestPickList(unittest.TestCase):
|
||||
'purpose': 'Opening Stock',
|
||||
'expense_account': 'Temporary Opening - _TC',
|
||||
'items': [{
|
||||
'item_code': '_Test Item Home Desktop 100',
|
||||
'item_code': '_Test Item',
|
||||
'warehouse': '_Test Warehouse - _TC',
|
||||
'valuation_rate': 100,
|
||||
'qty': 5
|
||||
@ -38,7 +38,7 @@ class TestPickList(unittest.TestCase):
|
||||
'customer': '_Test Customer',
|
||||
'items_based_on': 'Sales Order',
|
||||
'locations': [{
|
||||
'item_code': '_Test Item Home Desktop 100',
|
||||
'item_code': '_Test Item',
|
||||
'qty': 5,
|
||||
'stock_qty': 5,
|
||||
'conversion_factor': 1,
|
||||
@ -48,7 +48,7 @@ class TestPickList(unittest.TestCase):
|
||||
})
|
||||
pick_list.set_item_locations()
|
||||
|
||||
self.assertEqual(pick_list.locations[0].item_code, '_Test Item Home Desktop 100')
|
||||
self.assertEqual(pick_list.locations[0].item_code, '_Test Item')
|
||||
self.assertEqual(pick_list.locations[0].warehouse, '_Test Warehouse - _TC')
|
||||
self.assertEqual(pick_list.locations[0].qty, 5)
|
||||
|
||||
@ -238,7 +238,7 @@ class TestPickList(unittest.TestCase):
|
||||
'purpose': 'Opening Stock',
|
||||
'expense_account': 'Temporary Opening - _TC',
|
||||
'items': [{
|
||||
'item_code': '_Test Item Home Desktop 100',
|
||||
'item_code': '_Test Item',
|
||||
'warehouse': '_Test Warehouse - _TC',
|
||||
'valuation_rate': 100,
|
||||
'qty': 10
|
||||
@ -252,7 +252,7 @@ class TestPickList(unittest.TestCase):
|
||||
'customer': '_Test Customer',
|
||||
'company': '_Test Company',
|
||||
'items': [{
|
||||
'item_code': '_Test Item Home Desktop 100',
|
||||
'item_code': '_Test Item',
|
||||
'qty': 10,
|
||||
'delivery_date': frappe.utils.today()
|
||||
}],
|
||||
@ -265,14 +265,14 @@ class TestPickList(unittest.TestCase):
|
||||
'customer': '_Test Customer',
|
||||
'items_based_on': 'Sales Order',
|
||||
'locations': [{
|
||||
'item_code': '_Test Item Home Desktop 100',
|
||||
'item_code': '_Test Item',
|
||||
'qty': 5,
|
||||
'stock_qty': 5,
|
||||
'conversion_factor': 1,
|
||||
'sales_order': '_T-Sales Order-1',
|
||||
'sales_order_item': '_T-Sales Order-1_item',
|
||||
}, {
|
||||
'item_code': '_Test Item Home Desktop 100',
|
||||
'item_code': '_Test Item',
|
||||
'qty': 5,
|
||||
'stock_qty': 5,
|
||||
'conversion_factor': 1,
|
||||
@ -282,12 +282,12 @@ class TestPickList(unittest.TestCase):
|
||||
})
|
||||
pick_list.set_item_locations()
|
||||
|
||||
self.assertEqual(pick_list.locations[0].item_code, '_Test Item Home Desktop 100')
|
||||
self.assertEqual(pick_list.locations[0].item_code, '_Test Item')
|
||||
self.assertEqual(pick_list.locations[0].warehouse, '_Test Warehouse - _TC')
|
||||
self.assertEqual(pick_list.locations[0].qty, 5)
|
||||
self.assertEqual(pick_list.locations[0].sales_order_item, '_T-Sales Order-1_item')
|
||||
|
||||
self.assertEqual(pick_list.locations[1].item_code, '_Test Item Home Desktop 100')
|
||||
self.assertEqual(pick_list.locations[1].item_code, '_Test Item')
|
||||
self.assertEqual(pick_list.locations[1].warehouse, '_Test Warehouse - _TC')
|
||||
self.assertEqual(pick_list.locations[1].qty, 5)
|
||||
self.assertEqual(pick_list.locations[1].sales_order_item, sales_order.items[0].name)
|
||||
@ -358,4 +358,4 @@ class TestPickList(unittest.TestCase):
|
||||
# pass
|
||||
|
||||
# def test_pick_list_from_material_request(self):
|
||||
# pass
|
||||
# pass
|
||||
|
@ -176,7 +176,7 @@ class PurchaseReceipt(BuyingController):
|
||||
if flt(self.per_billed) < 100:
|
||||
self.update_billing_status()
|
||||
else:
|
||||
self.status = "Completed"
|
||||
self.db_set("status", "Completed")
|
||||
|
||||
|
||||
# Updating stock ledger should always be called after updating prevdoc status,
|
||||
|
@ -191,7 +191,7 @@ class TestPurchaseReceipt(unittest.TestCase):
|
||||
|
||||
rm_supp_cost = sum([d.amount for d in pr.get("supplied_items")])
|
||||
self.assertEqual(pr.get("items")[0].rm_supp_cost, flt(rm_supp_cost, 2))
|
||||
|
||||
|
||||
pr.cancel()
|
||||
|
||||
def test_subcontracting_gle_fg_item_rate_zero(self):
|
||||
@ -912,6 +912,57 @@ class TestPurchaseReceipt(unittest.TestCase):
|
||||
ste1.cancel()
|
||||
po.cancel()
|
||||
|
||||
|
||||
def test_po_to_pi_and_po_to_pr_worflow_full(self):
|
||||
"""Test following behaviour:
|
||||
- Create PO
|
||||
- Create PI from PO and submit
|
||||
- Create PR from PO and submit
|
||||
"""
|
||||
from erpnext.buying.doctype.purchase_order import test_purchase_order
|
||||
from erpnext.buying.doctype.purchase_order import purchase_order
|
||||
|
||||
po = test_purchase_order.create_purchase_order()
|
||||
|
||||
pi = purchase_order.make_purchase_invoice(po.name)
|
||||
pi.submit()
|
||||
|
||||
pr = purchase_order.make_purchase_receipt(po.name)
|
||||
pr.submit()
|
||||
|
||||
pr.load_from_db()
|
||||
|
||||
self.assertEqual(pr.status, "Completed")
|
||||
self.assertEqual(pr.per_billed, 100)
|
||||
|
||||
def test_po_to_pi_and_po_to_pr_worflow_partial(self):
|
||||
"""Test following behaviour:
|
||||
- Create PO
|
||||
- Create partial PI from PO and submit
|
||||
- Create PR from PO and submit
|
||||
"""
|
||||
from erpnext.buying.doctype.purchase_order import test_purchase_order
|
||||
from erpnext.buying.doctype.purchase_order import purchase_order
|
||||
|
||||
po = test_purchase_order.create_purchase_order()
|
||||
|
||||
pi = purchase_order.make_purchase_invoice(po.name)
|
||||
pi.items[0].qty /= 2 # roughly 50%, ^ this function only creates PI with 1 item.
|
||||
pi.submit()
|
||||
|
||||
pr = purchase_order.make_purchase_receipt(po.name)
|
||||
pr.save()
|
||||
# per_billed is only updated after submission.
|
||||
self.assertEqual(flt(pr.per_billed), 0)
|
||||
|
||||
pr.submit()
|
||||
|
||||
pi.load_from_db()
|
||||
pr.load_from_db()
|
||||
|
||||
self.assertEqual(pr.status, "To Bill")
|
||||
self.assertAlmostEqual(pr.per_billed, 50.0, places=2)
|
||||
|
||||
def get_sl_entries(voucher_type, voucher_no):
|
||||
return frappe.db.sql(""" select actual_qty, warehouse, stock_value_difference
|
||||
from `tabStock Ledger Entry` where voucher_type=%s and voucher_no=%s
|
||||
|
@ -100,6 +100,13 @@ frappe.ui.form.on('Stock Entry', {
|
||||
|
||||
frm.add_fetch("bom_no", "inspection_required", "inspection_required");
|
||||
erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
|
||||
|
||||
frappe.db.get_single_value('Stock Settings', 'disable_serial_no_and_batch_selector')
|
||||
.then((value) => {
|
||||
if (value) {
|
||||
frappe.flags.hide_serial_batch_dialog = true;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setup_quality_inspection: function(frm) {
|
||||
@ -721,7 +728,7 @@ frappe.ui.form.on('Stock Entry Detail', {
|
||||
no_batch_serial_number_value = !d.batch_no;
|
||||
}
|
||||
|
||||
if (no_batch_serial_number_value) {
|
||||
if (no_batch_serial_number_value && !frappe.flags.hide_serial_batch_dialog) {
|
||||
erpnext.stock.select_batch_and_serial_no(frm, d);
|
||||
}
|
||||
}
|
||||
|
@ -313,8 +313,8 @@ class TestStockLedgerEntry(unittest.TestCase):
|
||||
|
||||
# Set User with Stock User role but not Stock Manager
|
||||
try:
|
||||
frappe.set_user("test@example.com")
|
||||
user = frappe.get_doc("User", "test@example.com")
|
||||
frappe.set_user(user.name)
|
||||
user.add_roles("Stock User")
|
||||
user.remove_roles("Stock Manager")
|
||||
|
||||
@ -325,7 +325,9 @@ class TestStockLedgerEntry(unittest.TestCase):
|
||||
# Block back-dated entry
|
||||
self.assertRaises(BackDatedStockTransaction, back_dated_se_1.submit)
|
||||
|
||||
frappe.set_user("Administrator")
|
||||
user.add_roles("Stock Manager")
|
||||
frappe.set_user(user.name)
|
||||
|
||||
# Back dated entry allowed to Stock Manager
|
||||
back_dated_se_2 = make_stock_entry(target="_Test Warehouse - _TC", qty=10, basic_rate=100,
|
||||
@ -337,6 +339,7 @@ class TestStockLedgerEntry(unittest.TestCase):
|
||||
finally:
|
||||
frappe.db.set_value("Stock Settings", None, "role_allowed_to_create_edit_back_dated_transactions", None)
|
||||
frappe.set_user("Administrator")
|
||||
user.remove_roles("Stock Manager")
|
||||
|
||||
|
||||
def create_repack_entry(**args):
|
||||
@ -400,4 +403,4 @@ def create_items():
|
||||
|
||||
make_item(d, properties=properties)
|
||||
|
||||
return items
|
||||
return items
|
||||
|
Loading…
x
Reference in New Issue
Block a user