mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-06 13:49:13 +00:00
Merge branch 'develop' of github.com:aerele/erpnext into update_actual_qty
This commit is contained in:
@@ -5,8 +5,8 @@
|
||||
import json
|
||||
|
||||
import frappe
|
||||
from frappe.test_runner import make_test_records
|
||||
from frappe.tests.utils import FrappeTestCase
|
||||
from frappe.tests import IntegrationTestCase, UnitTestCase
|
||||
from frappe.tests.utils import make_test_records
|
||||
from frappe.utils import flt
|
||||
|
||||
from erpnext.accounts.party import get_due_date
|
||||
@@ -23,7 +23,16 @@ test_dependencies = ["Payment Term", "Payment Terms Template"]
|
||||
test_records = frappe.get_test_records("Customer")
|
||||
|
||||
|
||||
class TestCustomer(FrappeTestCase):
|
||||
class UnitTestCustomer(UnitTestCase):
|
||||
"""
|
||||
Unit tests for Customer.
|
||||
Use this class for testing individual functions and methods.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class TestCustomer(IntegrationTestCase):
|
||||
def setUp(self):
|
||||
if not frappe.get_value("Item", "_Test Item"):
|
||||
make_test_records("Item")
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
|
||||
import unittest
|
||||
|
||||
from frappe.tests import IntegrationTestCase
|
||||
|
||||
# test_records = frappe.get_test_records('Installation Note')
|
||||
|
||||
|
||||
class TestInstallationNote(unittest.TestCase):
|
||||
class TestInstallationNote(IntegrationTestCase):
|
||||
pass
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# See license.txt
|
||||
|
||||
import frappe
|
||||
from frappe.tests.utils import FrappeTestCase
|
||||
from frappe.tests import IntegrationTestCase, UnitTestCase
|
||||
|
||||
from erpnext.controllers.queries import item_query
|
||||
|
||||
@@ -18,7 +18,16 @@ def create_party_specific_item(**args):
|
||||
psi.insert()
|
||||
|
||||
|
||||
class TestPartySpecificItem(FrappeTestCase):
|
||||
class UnitTestPartySpecificItem(UnitTestCase):
|
||||
"""
|
||||
Unit tests for PartySpecificItem.
|
||||
Use this class for testing individual functions and methods.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class TestPartySpecificItem(IntegrationTestCase):
|
||||
def setUp(self):
|
||||
self.customer = frappe.get_last_doc("Customer")
|
||||
self.supplier = frappe.get_last_doc("Supplier")
|
||||
|
||||
@@ -71,7 +71,7 @@ frappe.ui.form.on("Quotation", {
|
||||
frm.trigger("set_label");
|
||||
frm.trigger("toggle_reqd_lead_customer");
|
||||
frm.trigger("set_dynamic_field_label");
|
||||
frm.set_value("party_name", "");
|
||||
// frm.set_value("party_name", ""); // removed to set party_name from url for crm integration
|
||||
frm.set_value("customer_name", "");
|
||||
},
|
||||
|
||||
|
||||
@@ -124,8 +124,10 @@
|
||||
"customer_group",
|
||||
"territory",
|
||||
"column_break_108",
|
||||
"campaign",
|
||||
"source",
|
||||
"utm_source",
|
||||
"utm_campaign",
|
||||
"utm_medium",
|
||||
"utm_content",
|
||||
"column_break4",
|
||||
"opportunity",
|
||||
"supplier_quotation",
|
||||
@@ -853,24 +855,6 @@
|
||||
"fieldtype": "Button",
|
||||
"label": "Update Auto Repeat Reference"
|
||||
},
|
||||
{
|
||||
"fieldname": "campaign",
|
||||
"fieldtype": "Link",
|
||||
"label": "Campaign",
|
||||
"oldfieldname": "campaign",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Campaign",
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "source",
|
||||
"fieldtype": "Link",
|
||||
"label": "Source",
|
||||
"oldfieldname": "source",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "Lead Source",
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
"depends_on": "eval:doc.status=='Lost'",
|
||||
@@ -1068,13 +1052,44 @@
|
||||
"fieldname": "named_place",
|
||||
"fieldtype": "Data",
|
||||
"label": "Named Place"
|
||||
},
|
||||
{
|
||||
"fieldname": "utm_campaign",
|
||||
"fieldtype": "Link",
|
||||
"label": "Campaign",
|
||||
"oldfieldname": "campaign",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "UTM Campaign",
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "utm_source",
|
||||
"fieldtype": "Link",
|
||||
"label": "Source",
|
||||
"oldfieldname": "source",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "UTM Source",
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "utm_medium",
|
||||
"print_hide": 1,
|
||||
"fieldtype": "Link",
|
||||
"label": "Medium",
|
||||
"options": "UTM Medium"
|
||||
},
|
||||
{
|
||||
"fieldname": "utm_content",
|
||||
"print_hide": 1,
|
||||
"fieldtype": "Data",
|
||||
"label": "Content"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-shopping-cart",
|
||||
"idx": 82,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2024-04-20 01:15:19.171383",
|
||||
"modified": "2024-06-28 10:32:47.638342",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Quotation",
|
||||
@@ -1172,4 +1187,4 @@
|
||||
"states": [],
|
||||
"timeline_field": "party_name",
|
||||
"title_field": "title"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,6 @@ class Quotation(SellingController):
|
||||
base_rounding_adjustment: DF.Currency
|
||||
base_total: DF.Currency
|
||||
base_total_taxes_and_charges: DF.Currency
|
||||
campaign: DF.Link | None
|
||||
company: DF.Link
|
||||
company_address: DF.Link | None
|
||||
company_address_display: DF.TextEditor | None
|
||||
@@ -96,7 +95,6 @@ class Quotation(SellingController):
|
||||
shipping_address: DF.TextEditor | None
|
||||
shipping_address_name: DF.Link | None
|
||||
shipping_rule: DF.Link | None
|
||||
source: DF.Link | None
|
||||
status: DF.Literal[
|
||||
"Draft", "Open", "Replied", "Partially Ordered", "Ordered", "Lost", "Cancelled", "Expired"
|
||||
]
|
||||
@@ -113,6 +111,10 @@ class Quotation(SellingController):
|
||||
total_qty: DF.Float
|
||||
total_taxes_and_charges: DF.Currency
|
||||
transaction_date: DF.Date
|
||||
utm_campaign: DF.Link | None
|
||||
utm_content: DF.Data | None
|
||||
utm_medium: DF.Link | None
|
||||
utm_source: DF.Link | None
|
||||
valid_till: DF.Date | None
|
||||
# end: auto-generated types
|
||||
|
||||
@@ -220,6 +222,10 @@ class Quotation(SellingController):
|
||||
"Lead", self.party_name, ["lead_name", "company_name"]
|
||||
)
|
||||
self.customer_name = company_name or lead_name
|
||||
elif self.party_name and self.quotation_to == "Prospect":
|
||||
self.customer_name = self.party_name
|
||||
elif self.party_name and self.quotation_to == "CRM Deal":
|
||||
self.customer_name = frappe.db.get_value("CRM Deal", self.party_name, "organization")
|
||||
|
||||
def update_opportunity(self, status):
|
||||
for opportunity in set(d.prevdoc_docname for d in self.get("items")):
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
import frappe
|
||||
from frappe.tests.utils import FrappeTestCase
|
||||
from frappe.tests import IntegrationTestCase, UnitTestCase
|
||||
from frappe.utils import add_days, add_months, flt, getdate, nowdate
|
||||
|
||||
from erpnext.controllers.accounts_controller import InvalidQtyError
|
||||
@@ -10,7 +10,16 @@ from erpnext.controllers.accounts_controller import InvalidQtyError
|
||||
test_dependencies = ["Product Bundle"]
|
||||
|
||||
|
||||
class TestQuotation(FrappeTestCase):
|
||||
class UnitTestQuotation(UnitTestCase):
|
||||
"""
|
||||
Unit tests for Quotation.
|
||||
Use this class for testing individual functions and methods.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class TestQuotation(IntegrationTestCase):
|
||||
def test_quotation_qty(self):
|
||||
qo = make_quotation(qty=0, do_not_save=True)
|
||||
with self.assertRaises(InvalidQtyError):
|
||||
@@ -573,12 +582,50 @@ class TestQuotation(FrappeTestCase):
|
||||
"description": "VAT",
|
||||
"doctype": "Sales Taxes and Charges",
|
||||
"rate": 10,
|
||||
"included_in_print_rate": 1,
|
||||
},
|
||||
)
|
||||
quotation.submit()
|
||||
|
||||
self.assertEqual(quotation.net_total, 290)
|
||||
self.assertEqual(quotation.grand_total, 319)
|
||||
self.assertEqual(round(quotation.items[1].net_rate, 2), 136.36)
|
||||
self.assertEqual(round(quotation.items[1].amount, 2), 150)
|
||||
|
||||
self.assertEqual(round(quotation.items[2].net_rate, 2), 163.64)
|
||||
self.assertEqual(round(quotation.items[2].amount, 2), 180)
|
||||
|
||||
self.assertEqual(round(quotation.net_total, 2), 263.64)
|
||||
self.assertEqual(round(quotation.total_taxes_and_charges, 2), 26.36)
|
||||
self.assertEqual(quotation.grand_total, 290)
|
||||
|
||||
def test_amount_calculation_for_alternative_items(self):
|
||||
"""Make sure that the amount is calculated correctly for alternative items when the qty is changed."""
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
|
||||
item_list = []
|
||||
stock_items = {
|
||||
"_Test Simple Item 1": 100,
|
||||
"_Test Alt 1": 120,
|
||||
}
|
||||
|
||||
for item, rate in stock_items.items():
|
||||
make_item(item, {"is_stock_item": 0})
|
||||
item_list.append(
|
||||
{
|
||||
"item_code": item,
|
||||
"qty": 1,
|
||||
"rate": rate,
|
||||
"is_alternative": "Alt" in item,
|
||||
}
|
||||
)
|
||||
|
||||
quotation = make_quotation(item_list=item_list, do_not_submit=1)
|
||||
|
||||
self.assertEqual(quotation.items[1].amount, 120)
|
||||
|
||||
quotation.items[1].qty = 2
|
||||
quotation.save()
|
||||
|
||||
self.assertEqual(quotation.items[1].amount, 240)
|
||||
|
||||
def test_alternative_items_sales_order_mapping_with_stock_items(self):
|
||||
from erpnext.selling.doctype.quotation.quotation import make_sales_order
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
"column_break_18",
|
||||
"discount_percentage",
|
||||
"discount_amount",
|
||||
"distributed_discount_amount",
|
||||
"base_rate_with_margin",
|
||||
"section_break1",
|
||||
"rate",
|
||||
@@ -235,7 +236,7 @@
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount",
|
||||
"collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount || doc.distributed_discount_amount",
|
||||
"fieldname": "discount_and_margin",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Discount and Margin"
|
||||
@@ -662,12 +663,18 @@
|
||||
"label": "Has Alternative Item",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "distributed_discount_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Distributed Discount Amount",
|
||||
"options": "currency"
|
||||
}
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2024-03-27 13:10:31.183320",
|
||||
"modified": "2024-06-02 06:21:09.508680",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Quotation Item",
|
||||
|
||||
@@ -32,6 +32,7 @@ class QuotationItem(Document):
|
||||
description: DF.TextEditor | None
|
||||
discount_amount: DF.Currency
|
||||
discount_percentage: DF.Percent
|
||||
distributed_discount_amount: DF.Currency
|
||||
gross_profit: DF.Currency
|
||||
has_alternative_item: DF.Check
|
||||
image: DF.Attach | None
|
||||
|
||||
@@ -1249,7 +1249,7 @@ erpnext.selling.SalesOrderController = class SalesOrderController extends erpnex
|
||||
],
|
||||
},
|
||||
],
|
||||
primary_action_label: "Create Purchase Order",
|
||||
primary_action_label: __("Create Purchase Order"),
|
||||
primary_action(args) {
|
||||
if (!args) return;
|
||||
|
||||
|
||||
@@ -159,10 +159,13 @@
|
||||
"additional_info_section",
|
||||
"is_internal_customer",
|
||||
"represents_company",
|
||||
"column_break_yvzv",
|
||||
"utm_source",
|
||||
"utm_campaign",
|
||||
"utm_medium",
|
||||
"utm_content",
|
||||
"column_break_152",
|
||||
"source",
|
||||
"inter_company_order_reference",
|
||||
"campaign",
|
||||
"party_account_currency",
|
||||
"connections_tab"
|
||||
],
|
||||
@@ -1165,28 +1168,6 @@
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "source",
|
||||
"fieldtype": "Link",
|
||||
"hide_days": 1,
|
||||
"hide_seconds": 1,
|
||||
"label": "Source",
|
||||
"oldfieldname": "source",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "Lead Source",
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "campaign",
|
||||
"fieldtype": "Link",
|
||||
"hide_days": 1,
|
||||
"hide_seconds": 1,
|
||||
"label": "Campaign",
|
||||
"oldfieldname": "campaign",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Campaign",
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"fieldname": "printing_details",
|
||||
@@ -1656,13 +1637,52 @@
|
||||
"no_copy": 1,
|
||||
"options": "Not Requested\nRequested\nPartially Paid\nFully Paid",
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_yvzv",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "utm_medium",
|
||||
"print_hide": 1,
|
||||
"fieldtype": "Link",
|
||||
"label": "Medium",
|
||||
"options": "UTM Medium"
|
||||
},
|
||||
{
|
||||
"fieldname": "utm_content",
|
||||
"print_hide": 1,
|
||||
"fieldtype": "Data",
|
||||
"label": "Content"
|
||||
},
|
||||
{
|
||||
"fieldname": "utm_source",
|
||||
"fieldtype": "Link",
|
||||
"hide_days": 1,
|
||||
"hide_seconds": 1,
|
||||
"label": "Source",
|
||||
"oldfieldname": "source",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "UTM Source",
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "utm_campaign",
|
||||
"fieldtype": "Link",
|
||||
"hide_days": 1,
|
||||
"hide_seconds": 1,
|
||||
"label": "Campaign",
|
||||
"oldfieldname": "campaign",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "UTM Campaign",
|
||||
"print_hide": 1
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-file-text",
|
||||
"idx": 105,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2024-05-27 18:51:54.905804",
|
||||
"modified": "2024-06-28 10:36:23.824623",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Sales Order",
|
||||
@@ -1740,4 +1760,4 @@
|
||||
"title_field": "customer_name",
|
||||
"track_changes": 1,
|
||||
"track_seen": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,6 @@ class SalesOrder(SellingController):
|
||||
base_total: DF.Currency
|
||||
base_total_taxes_and_charges: DF.Currency
|
||||
billing_status: DF.Literal["Not Billed", "Fully Billed", "Partly Billed", "Closed"]
|
||||
campaign: DF.Link | None
|
||||
commission_rate: DF.Float
|
||||
company: DF.Link
|
||||
company_address: DF.Link | None
|
||||
@@ -152,7 +151,6 @@ class SalesOrder(SellingController):
|
||||
shipping_address_name: DF.Link | None
|
||||
shipping_rule: DF.Link | None
|
||||
skip_delivery_note: DF.Check
|
||||
source: DF.Link | None
|
||||
status: DF.Literal[
|
||||
"",
|
||||
"Draft",
|
||||
@@ -180,12 +178,18 @@ class SalesOrder(SellingController):
|
||||
total_qty: DF.Float
|
||||
total_taxes_and_charges: DF.Currency
|
||||
transaction_date: DF.Date
|
||||
utm_campaign: DF.Link | None
|
||||
utm_content: DF.Data | None
|
||||
utm_medium: DF.Link | None
|
||||
utm_source: DF.Link | None
|
||||
# end: auto-generated types
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def onload(self) -> None:
|
||||
super().onload()
|
||||
|
||||
if frappe.db.get_single_value("Stock Settings", "enable_stock_reservation"):
|
||||
if self.has_unreserved_stock():
|
||||
self.set_onload("has_unreserved_stock", True)
|
||||
@@ -1045,6 +1049,7 @@ def make_delivery_note(source_name, target_doc=None, kwargs=None):
|
||||
)
|
||||
|
||||
dn_item.qty = flt(sre.reserved_qty) * flt(dn_item.get("conversion_factor", 1))
|
||||
dn_item.warehouse = sre.warehouse
|
||||
|
||||
if sre.reservation_based_on == "Serial and Batch" and (sre.has_serial_no or sre.has_batch_no):
|
||||
dn_item.serial_and_batch_bundle = get_ssb_bundle_for_voucher(sre)
|
||||
@@ -1093,6 +1098,7 @@ def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False):
|
||||
# set the redeem loyalty points if provided via shopping cart
|
||||
if source.loyalty_points and source.order_type == "Shopping Cart":
|
||||
target.redeem_loyalty_points = 1
|
||||
target.loyalty_points = source.loyalty_points
|
||||
|
||||
target.debit_to = get_party_account("Customer", source.customer, source.company)
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ from unittest.mock import patch
|
||||
import frappe
|
||||
import frappe.permissions
|
||||
from frappe.core.doctype.user_permission.test_user_permission import create_user
|
||||
from frappe.tests.utils import FrappeTestCase, change_settings
|
||||
from frappe.tests import IntegrationTestCase
|
||||
from frappe.utils import add_days, flt, getdate, nowdate, today
|
||||
|
||||
from erpnext.accounts.test.accounts_mixin import AccountsTestMixin
|
||||
@@ -33,7 +33,7 @@ from erpnext.stock.doctype.item.test_item import make_item
|
||||
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
|
||||
|
||||
|
||||
class TestSalesOrder(AccountsTestMixin, FrappeTestCase):
|
||||
class TestSalesOrder(AccountsTestMixin, IntegrationTestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
@@ -53,6 +53,7 @@ class TestSalesOrder(AccountsTestMixin, FrappeTestCase):
|
||||
self.create_customer("_Test Customer Credit")
|
||||
|
||||
def tearDown(self):
|
||||
frappe.db.rollback()
|
||||
frappe.set_user("Administrator")
|
||||
|
||||
def test_sales_order_with_negative_rate(self):
|
||||
@@ -1315,7 +1316,9 @@ class TestSalesOrder(AccountsTestMixin, FrappeTestCase):
|
||||
|
||||
self.assertRaises(frappe.LinkExistsError, so_doc.cancel)
|
||||
|
||||
@change_settings("Accounts Settings", {"unlink_advance_payment_on_cancelation_of_order": 1})
|
||||
@IntegrationTestCase.change_settings(
|
||||
"Accounts Settings", {"unlink_advance_payment_on_cancelation_of_order": 1}
|
||||
)
|
||||
def test_advance_paid_upon_payment_cancellation(self):
|
||||
from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
|
||||
|
||||
@@ -1905,7 +1908,7 @@ class TestSalesOrder(AccountsTestMixin, FrappeTestCase):
|
||||
self.assertEqual(len(dn.packed_items), 1)
|
||||
self.assertEqual(dn.items[0].item_code, "_Test Product Bundle Item Partial 2")
|
||||
|
||||
@change_settings("Selling Settings", {"editable_bundle_item_rates": 1})
|
||||
@IntegrationTestCase.change_settings("Selling Settings", {"editable_bundle_item_rates": 1})
|
||||
def test_expired_rate_for_packed_item(self):
|
||||
bundle = "_Test Product Bundle 1"
|
||||
packed_item = "_Packed Item 1"
|
||||
@@ -2197,6 +2200,75 @@ class TestSalesOrder(AccountsTestMixin, FrappeTestCase):
|
||||
|
||||
self.assertRaises(frappe.ValidationError, so1.update_status, "Draft")
|
||||
|
||||
@IntegrationTestCase.change_settings("Stock Settings", {"enable_stock_reservation": True})
|
||||
def test_warehouse_mapping_based_on_stock_reservation(self):
|
||||
self.create_company(company_name="Glass Ceiling", abbr="GC")
|
||||
self.create_item("Lamy Safari 2", True, self.warehouse_stores, self.company, 2000)
|
||||
self.create_customer()
|
||||
self.clear_old_entries()
|
||||
|
||||
so = frappe.new_doc("Sales Order")
|
||||
so.company = self.company
|
||||
so.customer = self.customer
|
||||
so.transaction_date = today()
|
||||
so.append(
|
||||
"items",
|
||||
{
|
||||
"item_code": self.item,
|
||||
"qty": 10,
|
||||
"rate": 2000,
|
||||
"warehouse": self.warehouse_stores,
|
||||
"delivery_date": today(),
|
||||
},
|
||||
)
|
||||
so.submit()
|
||||
|
||||
# Create stock
|
||||
se = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Stock Entry",
|
||||
"company": self.company,
|
||||
"stock_entry_type": "Material Receipt",
|
||||
"posting_date": today(),
|
||||
"items": [
|
||||
{"item_code": self.item, "t_warehouse": self.warehouse_stores, "qty": 5},
|
||||
{"item_code": self.item, "t_warehouse": self.warehouse_finished_goods, "qty": 5},
|
||||
],
|
||||
}
|
||||
)
|
||||
se.submit()
|
||||
|
||||
# Reserve stock on 2 different warehouses
|
||||
itm = so.items[0]
|
||||
so.create_stock_reservation_entries(
|
||||
[
|
||||
{
|
||||
"sales_order_item": itm.name,
|
||||
"item_code": itm.item_code,
|
||||
"warehouse": self.warehouse_stores,
|
||||
"qty_to_reserve": 2,
|
||||
}
|
||||
]
|
||||
)
|
||||
so.create_stock_reservation_entries(
|
||||
[
|
||||
{
|
||||
"sales_order_item": itm.name,
|
||||
"item_code": itm.item_code,
|
||||
"warehouse": self.warehouse_finished_goods,
|
||||
"qty_to_reserve": 3,
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
# Delivery note should auto-select warehouse based on reservation
|
||||
dn = make_delivery_note(so.name, kwargs={"for_reserved_stock": True})
|
||||
self.assertEqual(2, len(dn.items))
|
||||
self.assertEqual(dn.items[0].qty, 2)
|
||||
self.assertEqual(dn.items[0].warehouse, self.warehouse_stores)
|
||||
self.assertEqual(dn.items[1].qty, 3)
|
||||
self.assertEqual(dn.items[1].warehouse, self.warehouse_finished_goods)
|
||||
|
||||
|
||||
def automatically_fetch_payment_terms(enable=1):
|
||||
accounts_settings = frappe.get_doc("Accounts Settings")
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
"column_break_19",
|
||||
"discount_percentage",
|
||||
"discount_amount",
|
||||
"distributed_discount_amount",
|
||||
"base_rate_with_margin",
|
||||
"section_break_simple1",
|
||||
"rate",
|
||||
@@ -280,7 +281,7 @@
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount",
|
||||
"collapsible_depends_on": "eval: doc.margin_type || doc.discount_amount || doc.distributed_discount_amount",
|
||||
"fieldname": "discount_and_margin",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Discount and Margin"
|
||||
@@ -905,12 +906,18 @@
|
||||
"label": "Is Stock Item",
|
||||
"print_hide": 1,
|
||||
"report_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "distributed_discount_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Distributed Discount Amount",
|
||||
"options": "currency"
|
||||
}
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2024-03-27 13:10:37.177978",
|
||||
"modified": "2024-06-02 06:13:40.597947",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Sales Order Item",
|
||||
|
||||
@@ -38,6 +38,7 @@ class SalesOrderItem(Document):
|
||||
description: DF.TextEditor | None
|
||||
discount_amount: DF.Currency
|
||||
discount_percentage: DF.Percent
|
||||
distributed_discount_amount: DF.Currency
|
||||
ensure_delivery_based_on_produced_serial_no: DF.Check
|
||||
grant_commission: DF.Check
|
||||
gross_profit: DF.Currency
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
|
||||
import unittest
|
||||
|
||||
from frappe.tests import IntegrationTestCase
|
||||
|
||||
class TestSalesPartnerType(unittest.TestCase):
|
||||
|
||||
class TestSalesPartnerType(IntegrationTestCase):
|
||||
pass
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
|
||||
import unittest
|
||||
|
||||
import frappe
|
||||
from frappe.tests import IntegrationTestCase
|
||||
|
||||
|
||||
class TestSellingSettings(unittest.TestCase):
|
||||
class TestSellingSettings(IntegrationTestCase):
|
||||
def test_defaults_populated(self):
|
||||
# Setup default values are not populated on migrate, this test checks
|
||||
# if setup was completed correctly
|
||||
|
||||
Reference in New Issue
Block a user