Merge branch 'develop' into fix-so-on-hold

This commit is contained in:
Sagar Sharma 2023-02-14 11:06:10 +05:30 committed by GitHub
commit 5faa62c49a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 2265 additions and 2375 deletions

View File

@ -40,7 +40,7 @@ class Dunning(AccountsController):
def on_cancel(self):
if self.dunning_amount:
self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry")
self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry", "Payment Ledger Entry")
make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
def make_gl_entries(self):

View File

@ -234,7 +234,7 @@ class PaymentReconciliation(Document):
def allocate_entries(self, args):
self.validate_entries()
invoice_exchange_map = self.get_invoice_exchange_map(args.get("invoices"))
invoice_exchange_map = self.get_invoice_exchange_map(args.get("invoices"), args.get("payments"))
default_exchange_gain_loss_account = frappe.get_cached_value(
"Company", self.company, "exchange_gain_loss_account"
)
@ -253,6 +253,9 @@ class PaymentReconciliation(Document):
pay["amount"] = 0
inv["exchange_rate"] = invoice_exchange_map.get(inv.get("invoice_number"))
if pay.get("reference_type") in ["Sales Invoice", "Purchase Invoice"]:
pay["exchange_rate"] = invoice_exchange_map.get(pay.get("reference_name"))
res.difference_amount = self.get_difference_amount(pay, inv, res["allocated_amount"])
res.difference_account = default_exchange_gain_loss_account
res.exchange_rate = inv.get("exchange_rate")
@ -407,13 +410,21 @@ class PaymentReconciliation(Document):
if not self.get("payments"):
frappe.throw(_("No records found in the Payments table"))
def get_invoice_exchange_map(self, invoices):
def get_invoice_exchange_map(self, invoices, payments):
sales_invoices = [
d.get("invoice_number") for d in invoices if d.get("invoice_type") == "Sales Invoice"
]
sales_invoices.extend(
[d.get("reference_name") for d in payments if d.get("reference_type") == "Sales Invoice"]
)
purchase_invoices = [
d.get("invoice_number") for d in invoices if d.get("invoice_type") == "Purchase Invoice"
]
purchase_invoices.extend(
[d.get("reference_name") for d in payments if d.get("reference_type") == "Purchase Invoice"]
)
invoice_exchange_map = frappe._dict()
if sales_invoices:

View File

@ -473,6 +473,11 @@ class TestPaymentReconciliation(FrappeTestCase):
invoices = [x.as_dict() for x in pr.get("invoices")]
payments = [x.as_dict() for x in pr.get("payments")]
pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
# Cr Note and Invoice are of the same currency. There shouldn't any difference amount.
for row in pr.allocation:
self.assertEqual(flt(row.get("difference_amount")), 0.0)
pr.reconcile()
pr.get_unreconciled_entries()
@ -506,6 +511,11 @@ class TestPaymentReconciliation(FrappeTestCase):
payments = [x.as_dict() for x in pr.get("payments")]
pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments}))
pr.allocation[0].allocated_amount = allocated_amount
# Cr Note and Invoice are of the same currency. There shouldn't any difference amount.
for row in pr.allocation:
self.assertEqual(flt(row.get("difference_amount")), 0.0)
pr.reconcile()
# assert outstanding

View File

@ -45,21 +45,20 @@ class PaymentRequest(Document):
frappe.throw(_("To create a Payment Request reference document is required"))
def validate_payment_request_amount(self):
existing_payment_request_amount = get_existing_payment_request_amount(
self.reference_doctype, self.reference_name
existing_payment_request_amount = flt(
get_existing_payment_request_amount(self.reference_doctype, self.reference_name)
)
if existing_payment_request_amount:
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
if not hasattr(ref_doc, "order_type") or getattr(ref_doc, "order_type") != "Shopping Cart":
ref_amount = get_amount(ref_doc, self.payment_account)
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
if not hasattr(ref_doc, "order_type") or getattr(ref_doc, "order_type") != "Shopping Cart":
ref_amount = get_amount(ref_doc, self.payment_account)
if existing_payment_request_amount + flt(self.grand_total) > ref_amount:
frappe.throw(
_("Total Payment Request amount cannot be greater than {0} amount").format(
self.reference_doctype
)
if existing_payment_request_amount + flt(self.grand_total) > ref_amount:
frappe.throw(
_("Total Payment Request amount cannot be greater than {0} amount").format(
self.reference_doctype
)
)
def validate_currency(self):
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)

View File

@ -1512,9 +1512,12 @@ def update_voucher_outstanding(voucher_type, voucher_no, account, party_type, pa
ref_doc = frappe.get_doc(voucher_type, voucher_no)
# Didn't use db_set for optimisation purpose
ref_doc.outstanding_amount = outstanding["outstanding_in_account_currency"]
ref_doc.outstanding_amount = outstanding["outstanding_in_account_currency"] or 0.0
frappe.db.set_value(
voucher_type, voucher_no, "outstanding_amount", outstanding["outstanding_in_account_currency"]
voucher_type,
voucher_no,
"outstanding_amount",
outstanding["outstanding_in_account_currency"] or 0.0,
)
ref_doc.set_status(update=True)

View File

@ -252,6 +252,7 @@ def get_already_returned_items(doc):
child.parent = par.name and par.docstatus = 1
and par.is_return = 1 and par.return_against = %s
group by item_code
for update
""".format(
column, doc.doctype, doc.doctype
),

View File

@ -26,10 +26,11 @@
}
],
"links": [],
"modified": "2021-02-08 12:51:48.971517",
"modified": "2023-02-10 00:51:44.973957",
"modified_by": "Administrator",
"module": "CRM",
"name": "Lead Source",
"naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [
{
@ -58,5 +59,7 @@
],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC"
"sort_order": "DESC",
"states": [],
"translated_doctype": 1
}

View File

@ -18,10 +18,11 @@
}
],
"links": [],
"modified": "2020-05-20 12:22:01.866472",
"modified": "2023-02-10 01:40:23.713390",
"modified_by": "Administrator",
"module": "CRM",
"name": "Sales Stage",
"naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [
{
@ -40,5 +41,7 @@
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
"states": [],
"track_changes": 1,
"translated_doctype": 1
}

View File

@ -289,7 +289,7 @@
{
"fieldname": "scrap_items",
"fieldtype": "Table",
"label": "Items",
"label": "Scrap Items",
"options": "BOM Scrap Item"
},
{
@ -605,7 +605,7 @@
"image_field": "image",
"is_submittable": 1,
"links": [],
"modified": "2023-01-10 07:47:08.652616",
"modified": "2023-02-13 17:31:37.504565",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM",

View File

@ -1,16 +1,17 @@
import frappe
from frappe import _
def execute():
from erpnext.setup.setup_wizard.operations.install_fixtures import default_sales_partner_type
from erpnext.setup.setup_wizard.operations.install_fixtures import read_lines
frappe.reload_doc("selling", "doctype", "sales_partner_type")
frappe.local.lang = frappe.db.get_default("lang") or "en"
default_sales_partner_type = read_lines("sales_partner_type.txt")
for s in default_sales_partner_type:
insert_sales_partner_type(_(s))
insert_sales_partner_type(s)
# get partner type in existing forms (customized)
# and create a document if not created

View File

@ -1,123 +1,68 @@
{
"allow_copy": 0,
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:industry",
"beta": 0,
"creation": "2012-03-27 14:36:09",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "Setup",
"editable_grid": 0,
"actions": [],
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:industry",
"creation": "2012-03-27 14:36:09",
"doctype": "DocType",
"document_type": "Setup",
"engine": "InnoDB",
"field_order": [
"industry"
],
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "industry",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Industry",
"length": 0,
"no_copy": 0,
"oldfieldname": "industry",
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
"fieldname": "industry",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Industry",
"oldfieldname": "industry",
"oldfieldtype": "Data",
"reqd": 1,
"unique": 1
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-flag",
"idx": 1,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2020-09-18 17:26:09.703215",
"modified_by": "Administrator",
"module": "Selling",
"name": "Industry Type",
"owner": "Administrator",
],
"icon": "fa fa-flag",
"idx": 1,
"links": [],
"modified": "2023-02-10 03:14:40.735763",
"modified_by": "Administrator",
"module": "Selling",
"name": "Industry Type",
"naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 0,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"create": 1,
"email": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales Manager",
"share": 1,
"write": 1
},
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales User",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
},
"email": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales User"
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 0,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales Master Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"create": 1,
"email": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales Master Manager",
"share": 1,
"write": 1
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"track_seen": 0
],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"translated_doctype": 1
}

View File

@ -85,11 +85,15 @@ erpnext.selling.QuotationController = class QuotationController extends erpnext.
}
if (doc.docstatus == 1 && !["Lost", "Ordered"].includes(doc.status)) {
this.frm.add_custom_button(
__("Sales Order"),
this.frm.cscript["Make Sales Order"],
__("Create")
);
if (frappe.boot.sysdefaults.allow_sales_order_creation_for_expired_quotation
|| (!doc.valid_till)
|| frappe.datetime.get_diff(doc.valid_till, frappe.datetime.get_today()) >= 0) {
this.frm.add_custom_button(
__("Sales Order"),
this.frm.cscript["Make Sales Order"],
__("Create")
);
}
if(doc.status!=="Ordered") {
this.frm.add_custom_button(__('Set as Lost'), () => {

View File

@ -195,6 +195,17 @@ def get_list_context(context=None):
@frappe.whitelist()
def make_sales_order(source_name: str, target_doc=None):
if not frappe.db.get_singles_value(
"Selling Settings", "allow_sales_order_creation_for_expired_quotation"
):
quotation = frappe.db.get_value(
"Quotation", source_name, ["transaction_date", "valid_till"], as_dict=1
)
if quotation.valid_till and (
quotation.valid_till < quotation.transaction_date or quotation.valid_till < getdate(nowdate())
):
frappe.throw(_("Validity period of this quotation has ended."))
return _make_sales_order(source_name, target_doc)

View File

@ -144,11 +144,21 @@ class TestQuotation(FrappeTestCase):
def test_so_from_expired_quotation(self):
from erpnext.selling.doctype.quotation.quotation import make_sales_order
frappe.db.set_single_value(
"Selling Settings", "allow_sales_order_creation_for_expired_quotation", 0
)
quotation = frappe.copy_doc(test_records[0])
quotation.valid_till = add_days(nowdate(), -1)
quotation.insert()
quotation.submit()
self.assertRaises(frappe.ValidationError, make_sales_order, quotation.name)
frappe.db.set_single_value(
"Selling Settings", "allow_sales_order_creation_for_expired_quotation", 1
)
make_sales_order(quotation.name)
def test_shopping_cart_without_website_item(self):

View File

@ -1,94 +1,47 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "field:sales_partner_type",
"beta": 0,
"creation": "2018-06-11 13:15:57.404716",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"actions": [],
"autoname": "field:sales_partner_type",
"creation": "2018-06-11 13:15:57.404716",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"sales_partner_type"
],
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "sales_partner_type",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Sales Partner Type",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"fieldname": "sales_partner_type",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Sales Partner Type",
"reqd": 1,
"unique": 1
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-06-11 13:45:13.554307",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Partner Type",
"name_case": "",
"owner": "Administrator",
],
"links": [],
"modified": "2023-02-10 01:00:20.110800",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Partner Type",
"naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0
],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"translated_doctype": 1
}

View File

@ -27,6 +27,7 @@
"column_break_5",
"allow_multiple_items",
"allow_against_multiple_purchase_orders",
"allow_sales_order_creation_for_expired_quotation",
"hide_tax_id",
"enable_discount_accounting"
],
@ -172,6 +173,12 @@
"fieldname": "enable_discount_accounting",
"fieldtype": "Check",
"label": "Enable Discount Accounting for Selling"
},
{
"default": "0",
"fieldname": "allow_sales_order_creation_for_expired_quotation",
"fieldtype": "Check",
"label": "Allow Sales Order Creation For Expired Quotation"
}
],
"icon": "fa fa-cog",
@ -179,7 +186,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2022-05-31 19:39:48.398738",
"modified": "2023-02-04 12:37:53.380857",
"modified_by": "Administrator",
"module": "Selling",
"name": "Selling Settings",

View File

@ -103,6 +103,11 @@ function get_filters() {
return options
}
},
{
"fieldname":"only_immediate_upcoming_term",
"label": __("Show only the Immediate Upcoming Term"),
"fieldtype": "Check",
},
]
return filters;
}

View File

@ -4,6 +4,7 @@
import frappe
from frappe import _, qb, query_builder
from frappe.query_builder import Criterion, functions
from frappe.utils.dateutils import getdate
def get_columns():
@ -208,6 +209,7 @@ def get_so_with_invoices(filters):
)
.where(
(so.docstatus == 1)
& (so.status.isin(["To Deliver and Bill", "To Bill"]))
& (so.payment_terms_template != "NULL")
& (so.company == conditions.company)
& (so.transaction_date[conditions.start_date : conditions.end_date])
@ -291,6 +293,18 @@ def filter_on_calculated_status(filters, sales_orders):
return sales_orders
def filter_for_immediate_upcoming_term(filters, sales_orders):
if filters.only_immediate_upcoming_term and sales_orders:
immediate_term_found = set()
filtered_data = []
for order in sales_orders:
if order.name not in immediate_term_found and order.due_date > getdate():
filtered_data.append(order)
immediate_term_found.add(order.name)
return filtered_data
return sales_orders
def execute(filters=None):
columns = get_columns()
sales_orders, so_invoices = get_so_with_invoices(filters)
@ -298,6 +312,8 @@ def execute(filters=None):
sales_orders = filter_on_calculated_status(filters, sales_orders)
sales_orders = filter_for_immediate_upcoming_term(filters, sales_orders)
prepare_chart(sales_orders)
data = sales_orders

View File

@ -31,7 +31,7 @@
"icon": "fa fa-bookmark",
"idx": 1,
"links": [],
"modified": "2022-06-28 17:10:26.853753",
"modified": "2023-02-10 01:53:41.319386",
"modified_by": "Administrator",
"module": "Setup",
"name": "Designation",
@ -58,5 +58,6 @@
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "ASC",
"states": []
"states": [],
"translated_doctype": 1
}

View File

@ -0,0 +1,31 @@
Accountant
Administrative Assistant
Administrative Officer
Analyst
Associate
Business Analyst
Business Development Manager
Consultant
Chief Executive Officer
Chief Financial Officer
Chief Operating Officer
Chief Technology Officer
Customer Service Representative
Designer
Engineer
Executive Assistant
Finance Manager
HR Manager
Head of Marketing and Sales
Manager
Managing Director
Marketing Manager
Marketing Specialist
President
Product Manager
Project Manager
Researcher
Sales Representative
Secretary
Software Developer
Vice President

View File

@ -1,57 +0,0 @@
from frappe import _
def get_industry_types():
return [
_("Accounting"),
_("Advertising"),
_("Aerospace"),
_("Agriculture"),
_("Airline"),
_("Apparel & Accessories"),
_("Automotive"),
_("Banking"),
_("Biotechnology"),
_("Broadcasting"),
_("Brokerage"),
_("Chemical"),
_("Computer"),
_("Consulting"),
_("Consumer Products"),
_("Cosmetics"),
_("Defense"),
_("Department Stores"),
_("Education"),
_("Electronics"),
_("Energy"),
_("Entertainment & Leisure"),
_("Executive Search"),
_("Financial Services"),
_("Food, Beverage & Tobacco"),
_("Grocery"),
_("Health Care"),
_("Internet Publishing"),
_("Investment Banking"),
_("Legal"),
_("Manufacturing"),
_("Motion Picture & Video"),
_("Music"),
_("Newspaper Publishers"),
_("Online Auctions"),
_("Pension Funds"),
_("Pharmaceuticals"),
_("Private Equity"),
_("Publishing"),
_("Real Estate"),
_("Retail & Wholesale"),
_("Securities & Commodity Exchanges"),
_("Service"),
_("Soap & Detergent"),
_("Software"),
_("Sports"),
_("Technology"),
_("Telecommunications"),
_("Television"),
_("Transportation"),
_("Venture Capital"),
]

View File

@ -0,0 +1,51 @@
Accounting
Advertising
Aerospace
Agriculture
Airline
Apparel & Accessories
Automotive
Banking
Biotechnology
Broadcasting
Brokerage
Chemical
Computer
Consulting
Consumer Products
Cosmetics
Defense
Department Stores
Education
Electronics
Energy
Entertainment & Leisure
Executive Search
Financial Services
Food, Beverage & Tobacco
Grocery
Health Care
Internet Publishing
Investment Banking
Legal
Manufacturing
Motion Picture & Video
Music
Newspaper Publishers
Online Auctions
Pension Funds
Pharmaceuticals
Private Equity
Publishing
Real Estate
Retail & Wholesale
Securities & Commodity Exchanges
Service
Soap & Detergent
Software
Sports
Technology
Telecommunications
Television
Transportation
Venture Capital

View File

@ -0,0 +1,10 @@
Existing Customer
Reference
Advertisement
Cold Calling
Exhibition
Supplier Reference
Mass Mailing
Customer's Vendor
Campaign
Walk In

View File

@ -0,0 +1,7 @@
Channel Partner
Distributor
Dealer
Agent
Retailer
Implementation Partner
Reseller

View File

@ -0,0 +1,8 @@
Prospecting
Qualification
Needs Analysis
Value Proposition
Identifying Decision Makers
Perception Analysis
Proposal/Price Quote
Negotiation/Review

View File

@ -4,6 +4,7 @@
import json
import os
from pathlib import Path
import frappe
from frappe import _
@ -16,28 +17,10 @@ from frappe.utils import cstr, getdate
from erpnext.accounts.doctype.account.account import RootNotEditable
from erpnext.regional.address_template.setup import set_up_address_templates
default_lead_sources = [
"Existing Customer",
"Reference",
"Advertisement",
"Cold Calling",
"Exhibition",
"Supplier Reference",
"Mass Mailing",
"Customer's Vendor",
"Campaign",
"Walk In",
]
default_sales_partner_type = [
"Channel Partner",
"Distributor",
"Dealer",
"Agent",
"Retailer",
"Implementation Partner",
"Reseller",
]
def read_lines(filename: str) -> list[str]:
"""Return a list of lines from a file in the data directory."""
return (Path(__file__).parent.parent / "data" / filename).read_text().splitlines()
def install(country=None):
@ -85,7 +68,11 @@ def install(country=None):
# Stock Entry Type
{"doctype": "Stock Entry Type", "name": "Material Issue", "purpose": "Material Issue"},
{"doctype": "Stock Entry Type", "name": "Material Receipt", "purpose": "Material Receipt"},
{"doctype": "Stock Entry Type", "name": "Material Transfer", "purpose": "Material Transfer"},
{
"doctype": "Stock Entry Type",
"name": "Material Transfer",
"purpose": "Material Transfer",
},
{"doctype": "Stock Entry Type", "name": "Manufacture", "purpose": "Manufacture"},
{"doctype": "Stock Entry Type", "name": "Repack", "purpose": "Repack"},
{
@ -103,22 +90,6 @@ def install(country=None):
"name": "Material Consumption for Manufacture",
"purpose": "Material Consumption for Manufacture",
},
# Designation
{"doctype": "Designation", "designation_name": _("CEO")},
{"doctype": "Designation", "designation_name": _("Manager")},
{"doctype": "Designation", "designation_name": _("Analyst")},
{"doctype": "Designation", "designation_name": _("Engineer")},
{"doctype": "Designation", "designation_name": _("Accountant")},
{"doctype": "Designation", "designation_name": _("Secretary")},
{"doctype": "Designation", "designation_name": _("Associate")},
{"doctype": "Designation", "designation_name": _("Administrative Officer")},
{"doctype": "Designation", "designation_name": _("Business Development Manager")},
{"doctype": "Designation", "designation_name": _("HR Manager")},
{"doctype": "Designation", "designation_name": _("Project Manager")},
{"doctype": "Designation", "designation_name": _("Head of Marketing and Sales")},
{"doctype": "Designation", "designation_name": _("Software Developer")},
{"doctype": "Designation", "designation_name": _("Designer")},
{"doctype": "Designation", "designation_name": _("Researcher")},
# territory: with two default territories, one for home country and one named Rest of the World
{
"doctype": "Territory",
@ -291,28 +262,18 @@ def install(country=None):
{"doctype": "Market Segment", "market_segment": _("Lower Income")},
{"doctype": "Market Segment", "market_segment": _("Middle Income")},
{"doctype": "Market Segment", "market_segment": _("Upper Income")},
# Sales Stages
{"doctype": "Sales Stage", "stage_name": _("Prospecting")},
{"doctype": "Sales Stage", "stage_name": _("Qualification")},
{"doctype": "Sales Stage", "stage_name": _("Needs Analysis")},
{"doctype": "Sales Stage", "stage_name": _("Value Proposition")},
{"doctype": "Sales Stage", "stage_name": _("Identifying Decision Makers")},
{"doctype": "Sales Stage", "stage_name": _("Perception Analysis")},
{"doctype": "Sales Stage", "stage_name": _("Proposal/Price Quote")},
{"doctype": "Sales Stage", "stage_name": _("Negotiation/Review")},
# Warehouse Type
{"doctype": "Warehouse Type", "name": "Transit"},
]
from erpnext.setup.setup_wizard.data.industry_type import get_industry_types
records += [{"doctype": "Industry Type", "industry": d} for d in get_industry_types()]
# records += [{"doctype":"Operation", "operation": d} for d in get_operations()]
records += [{"doctype": "Lead Source", "source_name": _(d)} for d in default_lead_sources]
records += [
{"doctype": "Sales Partner Type", "sales_partner_type": _(d)} for d in default_sales_partner_type
]
for doctype, title_field, filename in (
("Designation", "designation_name", "designation.txt"),
("Sales Stage", "stage_name", "sales_stage.txt"),
("Industry Type", "industry", "industry_type.txt"),
("Lead Source", "source_name", "lead_source.txt"),
("Sales Partner Type", "sales_partner_type", "sales_partner_type.txt"),
):
records += [{"doctype": doctype, title_field: title} for title in read_lines(filename)]
base_path = frappe.get_app_path("erpnext", "stock", "doctype")
response = frappe.read_file(
@ -397,7 +358,8 @@ def add_uom_data():
frappe.get_doc({"doctype": "UOM Category", "category_name": _(d.get("category"))}).db_insert()
if not frappe.db.exists(
"UOM Conversion Factor", {"from_uom": _(d.get("from_uom")), "to_uom": _(d.get("to_uom"))}
"UOM Conversion Factor",
{"from_uom": _(d.get("from_uom")), "to_uom": _(d.get("to_uom"))},
):
frappe.get_doc(
{
@ -535,7 +497,8 @@ def create_bank_account(args):
company_name = args.get("company_name")
bank_account_group = frappe.db.get_value(
"Account", {"account_type": "Bank", "is_group": 1, "root_type": "Asset", "company": company_name}
"Account",
{"account_type": "Bank", "is_group": 1, "root_type": "Asset", "company": company_name},
)
if bank_account_group:
bank_account = frappe.get_doc(

View File

@ -25,6 +25,12 @@ def boot_session(bootinfo):
frappe.db.get_single_value("CRM Settings", "default_valid_till")
)
bootinfo.sysdefaults.allow_sales_order_creation_for_expired_quotation = cint(
frappe.db.get_single_value(
"Selling Settings", "allow_sales_order_creation_for_expired_quotation"
)
)
# if no company, show a dialog box to create a new company
bootinfo.customer_count = frappe.db.sql("""SELECT count(*) FROM `tabCustomer`""")[0][0]

View File

@ -38,5 +38,19 @@
"price_list_rate": 1000,
"valid_from": "2017-04-10",
"valid_upto": "2017-04-17"
},
{
"doctype": "Item Price",
"item_code": "_Test Item",
"price_list": "_Test Buying Price List",
"price_list_rate": 100,
"supplier": "_Test Supplier"
},
{
"doctype": "Item Price",
"item_code": "_Test Item",
"price_list": "_Test Selling Price List",
"price_list_rate": 200,
"customer": "_Test Customer"
}
]

View File

@ -31,5 +31,21 @@
"enabled": 1,
"price_list_name": "_Test Price List Rest of the World",
"selling": 1
},
{
"buying": 0,
"currency": "USD",
"doctype": "Price List",
"enabled": 1,
"price_list_name": "_Test Selling Price List",
"selling": 1
},
{
"buying": 1,
"currency": "USD",
"doctype": "Price List",
"enabled": 1,
"price_list_name": "_Test Buying Price List",
"selling": 0
}
]

View File

@ -88,8 +88,15 @@ def get_item_details(args, doc=None, for_validate=False, overwrite_warehouse=Tru
update_party_blanket_order(args, out)
# Never try to find a customer price if customer is set in these Doctype
current_customer = args.customer
if args.get("doctype") in ["Purchase Order", "Purchase Receipt", "Purchase Invoice"]:
args.customer = None
out.update(get_price_list_rate(args, item))
args.customer = current_customer
if args.customer and cint(args.is_pos):
out.update(get_pos_profile_item_details(args.company, args, update_data=True))

View File

@ -0,0 +1,40 @@
import json
import frappe
from frappe.test_runner import make_test_records
from frappe.tests.utils import FrappeTestCase
from erpnext.stock.get_item_details import get_item_details
test_ignore = ["BOM"]
test_dependencies = ["Customer", "Supplier", "Item", "Price List", "Item Price"]
class TestGetItemDetail(FrappeTestCase):
def setUp(self):
make_test_records("Price List")
super().setUp()
def test_get_item_detail_purchase_order(self):
args = frappe._dict(
{
"item_code": "_Test Item",
"company": "_Test Company",
"customer": "_Test Customer",
"conversion_rate": 1.0,
"price_list_currency": "USD",
"plc_conversion_rate": 1.0,
"doctype": "Purchase Order",
"name": None,
"supplier": "_Test Supplier",
"transaction_date": None,
"conversion_rate": 1.0,
"price_list": "_Test Buying Price List",
"is_subcontracted": 0,
"ignore_pricing_rule": 1,
"qty": 1,
}
)
details = get_item_details(args)
self.assertEqual(details.get("price_list_rate"), 100)

File diff suppressed because it is too large Load Diff