Merge branch 'develop' into fix_disposal_was_made_on_original_schedule_date_develop
This commit is contained in:
commit
5d8a2d3d3b
@ -32,8 +32,8 @@ repos:
|
||||
- id: black
|
||||
additional_dependencies: ['click==8.0.4']
|
||||
|
||||
- repo: https://github.com/timothycrosley/isort
|
||||
rev: 5.9.1
|
||||
- repo: https://github.com/PyCQA/isort
|
||||
rev: 5.12.0
|
||||
hooks:
|
||||
- id: isort
|
||||
exclude: ".*setup.py$"
|
||||
|
@ -28,9 +28,14 @@ class InvalidDateError(frappe.ValidationError):
|
||||
|
||||
|
||||
class CostCenterAllocation(Document):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(CostCenterAllocation, self).__init__(*args, **kwargs)
|
||||
self._skip_from_date_validation = False
|
||||
|
||||
def validate(self):
|
||||
self.validate_total_allocation_percentage()
|
||||
self.validate_from_date_based_on_existing_gle()
|
||||
if not self._skip_from_date_validation:
|
||||
self.validate_from_date_based_on_existing_gle()
|
||||
self.validate_backdated_allocation()
|
||||
self.validate_main_cost_center()
|
||||
self.validate_child_cost_centers()
|
||||
|
@ -8,7 +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'];
|
||||
frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry'];
|
||||
},
|
||||
|
||||
refresh: function(frm) {
|
||||
|
@ -69,6 +69,10 @@ class PaymentReconciliation(Document):
|
||||
|
||||
def get_jv_entries(self):
|
||||
condition = self.get_conditions()
|
||||
|
||||
if self.get("cost_center"):
|
||||
condition += f" and t2.cost_center = '{self.cost_center}' "
|
||||
|
||||
dr_or_cr = (
|
||||
"credit_in_account_currency"
|
||||
if erpnext.get_party_account_type(self.party_type) == "Receivable"
|
||||
|
@ -747,6 +747,73 @@ class TestPaymentReconciliation(FrappeTestCase):
|
||||
self.assertEqual(len(pr.get("invoices")), 0)
|
||||
self.assertEqual(len(pr.get("payments")), 0)
|
||||
|
||||
def test_cost_center_filter_on_vouchers(self):
|
||||
"""
|
||||
Test Cost Center filter is applied on Invoices, Payment Entries and Journals
|
||||
"""
|
||||
transaction_date = nowdate()
|
||||
rate = 100
|
||||
|
||||
# 'Main - PR' Cost Center
|
||||
si1 = self.create_sales_invoice(
|
||||
qty=1, rate=rate, posting_date=transaction_date, do_not_submit=True
|
||||
)
|
||||
si1.cost_center = self.main_cc.name
|
||||
si1.submit()
|
||||
|
||||
pe1 = self.create_payment_entry(posting_date=transaction_date, amount=rate)
|
||||
pe1.cost_center = self.main_cc.name
|
||||
pe1 = pe1.save().submit()
|
||||
|
||||
je1 = self.create_journal_entry(self.bank, self.debit_to, 100, transaction_date)
|
||||
je1.accounts[0].cost_center = self.main_cc.name
|
||||
je1.accounts[1].cost_center = self.main_cc.name
|
||||
je1.accounts[1].party_type = "Customer"
|
||||
je1.accounts[1].party = self.customer
|
||||
je1 = je1.save().submit()
|
||||
|
||||
# 'Sub - PR' Cost Center
|
||||
si2 = self.create_sales_invoice(
|
||||
qty=1, rate=rate, posting_date=transaction_date, do_not_submit=True
|
||||
)
|
||||
si2.cost_center = self.sub_cc.name
|
||||
si2.submit()
|
||||
|
||||
pe2 = self.create_payment_entry(posting_date=transaction_date, amount=rate)
|
||||
pe2.cost_center = self.sub_cc.name
|
||||
pe2 = pe2.save().submit()
|
||||
|
||||
je2 = self.create_journal_entry(self.bank, self.debit_to, 100, transaction_date)
|
||||
je2.accounts[0].cost_center = self.sub_cc.name
|
||||
je2.accounts[1].cost_center = self.sub_cc.name
|
||||
je2.accounts[1].party_type = "Customer"
|
||||
je2.accounts[1].party = self.customer
|
||||
je2 = je2.save().submit()
|
||||
|
||||
pr = self.create_payment_reconciliation()
|
||||
pr.cost_center = self.main_cc.name
|
||||
|
||||
pr.get_unreconciled_entries()
|
||||
|
||||
# check PR tool output
|
||||
self.assertEqual(len(pr.get("invoices")), 1)
|
||||
self.assertEqual(pr.get("invoices")[0].get("invoice_number"), si1.name)
|
||||
self.assertEqual(len(pr.get("payments")), 2)
|
||||
payment_vouchers = [x.get("reference_name") for x in pr.get("payments")]
|
||||
self.assertCountEqual(payment_vouchers, [pe1.name, je1.name])
|
||||
|
||||
# Change cost center
|
||||
pr.cost_center = self.sub_cc.name
|
||||
|
||||
pr.get_unreconciled_entries()
|
||||
|
||||
# check PR tool output
|
||||
self.assertEqual(len(pr.get("invoices")), 1)
|
||||
self.assertEqual(pr.get("invoices")[0].get("invoice_number"), si2.name)
|
||||
self.assertEqual(len(pr.get("payments")), 2)
|
||||
payment_vouchers = [x.get("reference_name") for x in pr.get("payments")]
|
||||
self.assertCountEqual(payment_vouchers, [je2.name, pe2.name])
|
||||
|
||||
|
||||
def make_customer(customer_name, currency=None):
|
||||
if not frappe.db.exists("Customer", customer_name):
|
||||
|
@ -51,7 +51,7 @@ class PaymentRequest(Document):
|
||||
|
||||
if existing_payment_request_amount:
|
||||
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
|
||||
if hasattr(ref_doc, "order_type") and getattr(ref_doc, "order_type") != "Shopping Cart":
|
||||
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:
|
||||
|
@ -1426,6 +1426,7 @@
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "apply_tds",
|
||||
"fieldname": "tax_withholding_net_total",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 1,
|
||||
@ -1435,12 +1436,13 @@
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "apply_tds",
|
||||
"fieldname": "base_tax_withholding_net_total",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 1,
|
||||
"label": "Base Tax Withholding Net Total",
|
||||
"no_copy": 1,
|
||||
"options": "currency",
|
||||
"options": "Company:company:default_currency",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
@ -1554,7 +1556,7 @@
|
||||
"idx": 204,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2022-12-12 18:37:38.142688",
|
||||
"modified": "2023-01-28 19:18:56.586321",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Invoice",
|
||||
|
@ -211,7 +211,13 @@ def set_address_details(
|
||||
else:
|
||||
party_details.update(get_company_address(company))
|
||||
|
||||
if doctype and doctype in ["Delivery Note", "Sales Invoice", "Sales Order", "Quotation"]:
|
||||
if doctype and doctype in [
|
||||
"Delivery Note",
|
||||
"Sales Invoice",
|
||||
"Sales Order",
|
||||
"Quotation",
|
||||
"POS Invoice",
|
||||
]:
|
||||
if party_details.company_address:
|
||||
party_details.update(
|
||||
get_fetch_values(doctype, "company_address", party_details.company_address)
|
||||
|
@ -526,7 +526,7 @@ def get_columns(filters):
|
||||
"options": "GL Entry",
|
||||
"hidden": 1,
|
||||
},
|
||||
{"label": _("Posting Date"), "fieldname": "posting_date", "fieldtype": "Date", "width": 90},
|
||||
{"label": _("Posting Date"), "fieldname": "posting_date", "fieldtype": "Date", "width": 100},
|
||||
{
|
||||
"label": _("Account"),
|
||||
"fieldname": "account",
|
||||
@ -538,13 +538,13 @@ def get_columns(filters):
|
||||
"label": _("Debit ({0})").format(currency),
|
||||
"fieldname": "debit",
|
||||
"fieldtype": "Float",
|
||||
"width": 100,
|
||||
"width": 130,
|
||||
},
|
||||
{
|
||||
"label": _("Credit ({0})").format(currency),
|
||||
"fieldname": "credit",
|
||||
"fieldtype": "Float",
|
||||
"width": 100,
|
||||
"width": 130,
|
||||
},
|
||||
{
|
||||
"label": _("Balance ({0})").format(currency),
|
||||
|
@ -655,10 +655,35 @@ class GrossProfitGenerator(object):
|
||||
return self.calculate_buying_amount_from_sle(
|
||||
row, my_sle, parenttype, parent, item_row, item_code
|
||||
)
|
||||
elif row.sales_order and row.so_detail:
|
||||
incoming_amount = self.get_buying_amount_from_so_dn(row.sales_order, row.so_detail, item_code)
|
||||
if incoming_amount:
|
||||
return incoming_amount
|
||||
else:
|
||||
return flt(row.qty) * self.get_average_buying_rate(row, item_code)
|
||||
|
||||
return 0.0
|
||||
return flt(row.qty) * self.get_average_buying_rate(row, item_code)
|
||||
|
||||
def get_buying_amount_from_so_dn(self, sales_order, so_detail, item_code):
|
||||
from frappe.query_builder.functions import Sum
|
||||
|
||||
delivery_note = frappe.qb.DocType("Delivery Note")
|
||||
delivery_note_item = frappe.qb.DocType("Delivery Note Item")
|
||||
|
||||
query = (
|
||||
frappe.qb.from_(delivery_note)
|
||||
.inner_join(delivery_note_item)
|
||||
.on(delivery_note.name == delivery_note_item.parent)
|
||||
.select(Sum(delivery_note_item.incoming_rate * delivery_note_item.stock_qty))
|
||||
.where(delivery_note.docstatus == 1)
|
||||
.where(delivery_note_item.item_code == item_code)
|
||||
.where(delivery_note_item.against_sales_order == sales_order)
|
||||
.where(delivery_note_item.so_detail == so_detail)
|
||||
.groupby(delivery_note_item.item_code)
|
||||
)
|
||||
|
||||
incoming_amount = query.run()
|
||||
return flt(incoming_amount[0][0]) if incoming_amount else 0
|
||||
|
||||
def get_average_buying_rate(self, row, item_code):
|
||||
args = row
|
||||
@ -760,7 +785,8 @@ class GrossProfitGenerator(object):
|
||||
`tabSales Invoice`.territory, `tabSales Invoice Item`.item_code,
|
||||
`tabSales Invoice Item`.item_name, `tabSales Invoice Item`.description,
|
||||
`tabSales Invoice Item`.warehouse, `tabSales Invoice Item`.item_group,
|
||||
`tabSales Invoice Item`.brand, `tabSales Invoice Item`.dn_detail,
|
||||
`tabSales Invoice Item`.brand, `tabSales Invoice Item`.so_detail,
|
||||
`tabSales Invoice Item`.sales_order, `tabSales Invoice Item`.dn_detail,
|
||||
`tabSales Invoice Item`.delivery_note, `tabSales Invoice Item`.stock_qty as qty,
|
||||
`tabSales Invoice Item`.base_net_rate, `tabSales Invoice Item`.base_net_amount,
|
||||
`tabSales Invoice Item`.name as "item_row", `tabSales Invoice`.is_return,
|
||||
|
@ -302,3 +302,82 @@ class TestGrossProfit(FrappeTestCase):
|
||||
|
||||
columns, data = execute(filters=filters)
|
||||
self.assertGreater(len(data), 0)
|
||||
|
||||
def test_order_connected_dn_and_inv(self):
|
||||
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
|
||||
|
||||
"""
|
||||
Test gp calculation when invoice and delivery note aren't directly connected.
|
||||
SO -- INV
|
||||
|
|
||||
DN
|
||||
"""
|
||||
se = make_stock_entry(
|
||||
company=self.company,
|
||||
item_code=self.item,
|
||||
target=self.warehouse,
|
||||
qty=3,
|
||||
basic_rate=100,
|
||||
do_not_submit=True,
|
||||
)
|
||||
item = se.items[0]
|
||||
se.append(
|
||||
"items",
|
||||
{
|
||||
"item_code": item.item_code,
|
||||
"s_warehouse": item.s_warehouse,
|
||||
"t_warehouse": item.t_warehouse,
|
||||
"qty": 10,
|
||||
"basic_rate": 200,
|
||||
"conversion_factor": item.conversion_factor or 1.0,
|
||||
"transfer_qty": flt(item.qty) * (flt(item.conversion_factor) or 1.0),
|
||||
"serial_no": item.serial_no,
|
||||
"batch_no": item.batch_no,
|
||||
"cost_center": item.cost_center,
|
||||
"expense_account": item.expense_account,
|
||||
},
|
||||
)
|
||||
se = se.save().submit()
|
||||
|
||||
so = make_sales_order(
|
||||
customer=self.customer,
|
||||
company=self.company,
|
||||
warehouse=self.warehouse,
|
||||
item=self.item,
|
||||
qty=4,
|
||||
do_not_save=False,
|
||||
do_not_submit=False,
|
||||
)
|
||||
|
||||
from erpnext.selling.doctype.sales_order.sales_order import (
|
||||
make_delivery_note,
|
||||
make_sales_invoice,
|
||||
)
|
||||
|
||||
make_delivery_note(so.name).submit()
|
||||
sinv = make_sales_invoice(so.name).submit()
|
||||
|
||||
filters = frappe._dict(
|
||||
company=self.company, from_date=nowdate(), to_date=nowdate(), group_by="Invoice"
|
||||
)
|
||||
|
||||
columns, data = execute(filters=filters)
|
||||
expected_entry = {
|
||||
"parent_invoice": sinv.name,
|
||||
"currency": "INR",
|
||||
"sales_invoice": self.item,
|
||||
"customer": self.customer,
|
||||
"posting_date": frappe.utils.datetime.date.fromisoformat(nowdate()),
|
||||
"item_code": self.item,
|
||||
"item_name": self.item,
|
||||
"warehouse": "Stores - _GP",
|
||||
"qty": 4.0,
|
||||
"avg._selling_rate": 100.0,
|
||||
"valuation_rate": 125.0,
|
||||
"selling_amount": 400.0,
|
||||
"buying_amount": 500.0,
|
||||
"gross_profit": -100.0,
|
||||
"gross_profit_%": -25.0,
|
||||
}
|
||||
gp_entry = [x for x in data if x.parent_invoice == sinv.name]
|
||||
self.assertDictContainsSubset(expected_entry, gp_entry[0])
|
||||
|
@ -15,17 +15,6 @@ class TestBulkTransactionLog(unittest.TestCase):
|
||||
create_customer()
|
||||
create_item()
|
||||
|
||||
def test_for_single_record(self):
|
||||
so_name = create_so()
|
||||
transaction_processing([{"name": so_name}], "Sales Order", "Sales Invoice")
|
||||
data = frappe.db.get_list(
|
||||
"Sales Invoice",
|
||||
filters={"posting_date": date.today(), "customer": "Bulk Customer"},
|
||||
fields=["*"],
|
||||
)
|
||||
if not data:
|
||||
self.fail("No Sales Invoice Created !")
|
||||
|
||||
def test_entry_in_log(self):
|
||||
so_name = create_so()
|
||||
transaction_processing([{"name": so_name}], "Sales Order", "Sales Invoice")
|
||||
|
@ -1221,6 +1221,7 @@
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "apply_tds",
|
||||
"fieldname": "tax_withholding_net_total",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 1,
|
||||
@ -1230,12 +1231,13 @@
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "apply_tds",
|
||||
"fieldname": "base_tax_withholding_net_total",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 1,
|
||||
"label": "Base Tax Withholding Net Total",
|
||||
"no_copy": 1,
|
||||
"options": "currency",
|
||||
"options": "Company:company:default_currency",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
@ -1269,7 +1271,7 @@
|
||||
"idx": 105,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2022-12-25 18:08:59.074182",
|
||||
"modified": "2023-01-28 18:59:16.322824",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Purchase Order",
|
||||
|
@ -15,60 +15,4 @@ from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
|
||||
|
||||
|
||||
class TestProcurementTracker(FrappeTestCase):
|
||||
def test_result_for_procurement_tracker(self):
|
||||
filters = {"company": "_Test Procurement Company", "cost_center": "Main - _TPC"}
|
||||
expected_data = self.generate_expected_data()
|
||||
report = execute(filters)
|
||||
|
||||
length = len(report[1])
|
||||
self.assertEqual(expected_data, report[1][length - 1])
|
||||
|
||||
def generate_expected_data(self):
|
||||
if not frappe.db.exists("Company", "_Test Procurement Company"):
|
||||
frappe.get_doc(
|
||||
dict(
|
||||
doctype="Company",
|
||||
company_name="_Test Procurement Company",
|
||||
abbr="_TPC",
|
||||
default_currency="INR",
|
||||
country="Pakistan",
|
||||
)
|
||||
).insert()
|
||||
warehouse = create_warehouse("_Test Procurement Warehouse", company="_Test Procurement Company")
|
||||
mr = make_material_request(
|
||||
company="_Test Procurement Company", warehouse=warehouse, cost_center="Main - _TPC"
|
||||
)
|
||||
po = make_purchase_order(mr.name)
|
||||
po.supplier = "_Test Supplier"
|
||||
po.get("items")[0].cost_center = "Main - _TPC"
|
||||
po.submit()
|
||||
pr = make_purchase_receipt(po.name)
|
||||
pr.get("items")[0].cost_center = "Main - _TPC"
|
||||
pr.submit()
|
||||
date_obj = datetime.date(datetime.now())
|
||||
|
||||
po.load_from_db()
|
||||
|
||||
expected_data = {
|
||||
"material_request_date": date_obj,
|
||||
"cost_center": "Main - _TPC",
|
||||
"project": None,
|
||||
"requesting_site": "_Test Procurement Warehouse - _TPC",
|
||||
"requestor": "Administrator",
|
||||
"material_request_no": mr.name,
|
||||
"item_code": "_Test Item",
|
||||
"quantity": 10.0,
|
||||
"unit_of_measurement": "_Test UOM",
|
||||
"status": "To Bill",
|
||||
"purchase_order_date": date_obj,
|
||||
"purchase_order": po.name,
|
||||
"supplier": "_Test Supplier",
|
||||
"estimated_cost": 0.0,
|
||||
"actual_cost": 0.0,
|
||||
"purchase_order_amt": po.net_total,
|
||||
"purchase_order_amt_in_company_currency": po.base_net_total,
|
||||
"expected_delivery_date": date_obj,
|
||||
"actual_delivery_date": date_obj,
|
||||
}
|
||||
|
||||
return expected_data
|
||||
pass
|
||||
|
@ -282,6 +282,7 @@ def _make_customer(source_name, target_doc=None, ignore_permissions=False):
|
||||
"contact_no": "phone_1",
|
||||
"fax": "fax_1",
|
||||
},
|
||||
"field_no_map": ["disabled"],
|
||||
}
|
||||
},
|
||||
target_doc,
|
||||
@ -390,7 +391,7 @@ def get_lead_details(lead, posting_date=None, company=None):
|
||||
{
|
||||
"territory": lead.territory,
|
||||
"customer_name": lead.company_name or lead.lead_name,
|
||||
"contact_display": " ".join(filter(None, [lead.salutation, lead.lead_name])),
|
||||
"contact_display": " ".join(filter(None, [lead.lead_name])),
|
||||
"contact_email": lead.email_id,
|
||||
"contact_mobile": lead.mobile_no,
|
||||
"contact_phone": lead.phone,
|
||||
|
@ -18,9 +18,11 @@ def create_new_cost_center_allocation_records(cc_allocations):
|
||||
cca = frappe.new_doc("Cost Center Allocation")
|
||||
cca.main_cost_center = main_cc
|
||||
cca.valid_from = today()
|
||||
cca._skip_from_date_validation = True
|
||||
|
||||
for child_cc, percentage in allocations.items():
|
||||
cca.append("allocation_percentages", ({"cost_center": child_cc, "percentage": percentage}))
|
||||
|
||||
cca.save()
|
||||
cca.submit()
|
||||
|
||||
|
@ -10,62 +10,6 @@ from frappe.website.serve import get_response
|
||||
|
||||
|
||||
class TestHomepageSection(unittest.TestCase):
|
||||
def test_homepage_section_card(self):
|
||||
try:
|
||||
frappe.get_doc(
|
||||
{
|
||||
"doctype": "Homepage Section",
|
||||
"name": "Card Section",
|
||||
"section_based_on": "Cards",
|
||||
"section_cards": [
|
||||
{
|
||||
"title": "Card 1",
|
||||
"subtitle": "Subtitle 1",
|
||||
"content": "This is test card 1",
|
||||
"route": "/card-1",
|
||||
},
|
||||
{
|
||||
"title": "Card 2",
|
||||
"subtitle": "Subtitle 2",
|
||||
"content": "This is test card 2",
|
||||
"image": "test.jpg",
|
||||
},
|
||||
],
|
||||
"no_of_columns": 3,
|
||||
}
|
||||
).insert(ignore_if_duplicate=True)
|
||||
except frappe.DuplicateEntryError:
|
||||
pass
|
||||
|
||||
set_request(method="GET", path="home")
|
||||
response = get_response()
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
html = frappe.safe_decode(response.get_data())
|
||||
|
||||
soup = BeautifulSoup(html, "html.parser")
|
||||
sections = soup.find("main").find_all("section")
|
||||
self.assertEqual(len(sections), 3)
|
||||
|
||||
homepage_section = sections[2]
|
||||
self.assertEqual(homepage_section.h3.text, "Card Section")
|
||||
|
||||
cards = homepage_section.find_all(class_="card")
|
||||
|
||||
self.assertEqual(len(cards), 2)
|
||||
self.assertEqual(cards[0].h5.text, "Card 1")
|
||||
self.assertEqual(cards[0].a["href"], "/card-1")
|
||||
self.assertEqual(cards[1].p.text, "Subtitle 2")
|
||||
|
||||
img = cards[1].find(class_="card-img-top")
|
||||
|
||||
self.assertEqual(img["src"], "test.jpg")
|
||||
self.assertEqual(img["loading"], "lazy")
|
||||
|
||||
# cleanup
|
||||
frappe.db.rollback()
|
||||
|
||||
def test_homepage_section_custom_html(self):
|
||||
frappe.get_doc(
|
||||
{
|
||||
|
@ -1691,6 +1691,10 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
|
||||
var me = this;
|
||||
var valid = true;
|
||||
|
||||
if (frappe.flags.ignore_company_party_validation) {
|
||||
return valid;
|
||||
}
|
||||
|
||||
$.each(["company", "customer"], function(i, fieldname) {
|
||||
if(frappe.meta.has_field(me.frm.doc.doctype, fieldname) && !["Purchase Order","Purchase Invoice"].includes(me.frm.doc.doctype)) {
|
||||
if (!me.frm.doc[fieldname]) {
|
||||
|
@ -13,19 +13,11 @@ frappe.setup.on("before_load", function () {
|
||||
|
||||
erpnext.setup.slides_settings = [
|
||||
{
|
||||
// Brand
|
||||
name: 'brand',
|
||||
icon: "fa fa-bookmark",
|
||||
title: __("The Brand"),
|
||||
// help: __('Upload your letter head and logo. (you can edit them later).'),
|
||||
// Organization
|
||||
name: 'organization',
|
||||
title: __("Setup your organization"),
|
||||
icon: "fa fa-building",
|
||||
fields: [
|
||||
{
|
||||
fieldtype: "Attach Image", fieldname: "attach_logo",
|
||||
label: __("Attach Logo"),
|
||||
description: __("100px by 100px"),
|
||||
is_private: 0,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
fieldname: 'company_name',
|
||||
label: __('Company Name'),
|
||||
@ -35,54 +27,9 @@ erpnext.setup.slides_settings = [
|
||||
{
|
||||
fieldname: 'company_abbr',
|
||||
label: __('Company Abbreviation'),
|
||||
fieldtype: 'Data'
|
||||
}
|
||||
],
|
||||
onload: function(slide) {
|
||||
this.bind_events(slide);
|
||||
},
|
||||
bind_events: function (slide) {
|
||||
slide.get_input("company_name").on("change", function () {
|
||||
var parts = slide.get_input("company_name").val().split(" ");
|
||||
var abbr = $.map(parts, function (p) { return p ? p.substr(0, 1) : null }).join("");
|
||||
slide.get_field("company_abbr").set_value(abbr.slice(0, 10).toUpperCase());
|
||||
}).val(frappe.boot.sysdefaults.company_name || "").trigger("change");
|
||||
|
||||
slide.get_input("company_abbr").on("change", function () {
|
||||
if (slide.get_input("company_abbr").val().length > 10) {
|
||||
frappe.msgprint(__("Company Abbreviation cannot have more than 5 characters"));
|
||||
slide.get_field("company_abbr").set_value("");
|
||||
}
|
||||
});
|
||||
},
|
||||
validate: function() {
|
||||
if ((this.values.company_name || "").toLowerCase() == "company") {
|
||||
frappe.msgprint(__("Company Name cannot be Company"));
|
||||
return false;
|
||||
}
|
||||
if (!this.values.company_abbr) {
|
||||
return false;
|
||||
}
|
||||
if (this.values.company_abbr.length > 10) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
},
|
||||
{
|
||||
// Organisation
|
||||
name: 'organisation',
|
||||
title: __("Your Organization"),
|
||||
icon: "fa fa-building",
|
||||
fields: [
|
||||
{
|
||||
fieldname: 'company_tagline',
|
||||
label: __('What does it do?'),
|
||||
fieldtype: 'Data',
|
||||
placeholder: __('e.g. "Build tools for builders"'),
|
||||
reqd: 1
|
||||
hidden: 1
|
||||
},
|
||||
{ fieldname: 'bank_account', label: __('Bank Name'), fieldtype: 'Data', reqd: 1 },
|
||||
{
|
||||
fieldname: 'chart_of_accounts', label: __('Chart of Accounts'),
|
||||
options: "", fieldtype: 'Select'
|
||||
@ -94,40 +41,24 @@ erpnext.setup.slides_settings = [
|
||||
],
|
||||
|
||||
onload: function (slide) {
|
||||
this.load_chart_of_accounts(slide);
|
||||
this.bind_events(slide);
|
||||
this.load_chart_of_accounts(slide);
|
||||
this.set_fy_dates(slide);
|
||||
},
|
||||
|
||||
validate: function () {
|
||||
let me = this;
|
||||
let exist;
|
||||
|
||||
if (!this.validate_fy_dates()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate bank name
|
||||
if(me.values.bank_account) {
|
||||
frappe.call({
|
||||
async: false,
|
||||
method: "erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts.validate_bank_account",
|
||||
args: {
|
||||
"coa": me.values.chart_of_accounts,
|
||||
"bank_account": me.values.bank_account
|
||||
},
|
||||
callback: function (r) {
|
||||
if(r.message){
|
||||
exist = r.message;
|
||||
me.get_field("bank_account").set_value("");
|
||||
let message = __('Account {0} already exists. Please enter a different name for your bank account.',
|
||||
[me.values.bank_account]
|
||||
);
|
||||
frappe.msgprint(message);
|
||||
}
|
||||
}
|
||||
});
|
||||
return !exist; // Return False if exist = true
|
||||
if ((this.values.company_name || "").toLowerCase() == "company") {
|
||||
frappe.msgprint(__("Company Name cannot be Company"));
|
||||
return false;
|
||||
}
|
||||
if (!this.values.company_abbr) {
|
||||
return false;
|
||||
}
|
||||
if (this.values.company_abbr.length > 10) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -151,15 +82,15 @@ erpnext.setup.slides_settings = [
|
||||
var country = frappe.wizard.values.country;
|
||||
|
||||
if (country) {
|
||||
var fy = erpnext.setup.fiscal_years[country];
|
||||
var current_year = moment(new Date()).year();
|
||||
var next_year = current_year + 1;
|
||||
let fy = erpnext.setup.fiscal_years[country];
|
||||
let current_year = moment(new Date()).year();
|
||||
let next_year = current_year + 1;
|
||||
if (!fy) {
|
||||
fy = ["01-01", "12-31"];
|
||||
next_year = current_year;
|
||||
}
|
||||
|
||||
var year_start_date = current_year + "-" + fy[0];
|
||||
let year_start_date = current_year + "-" + fy[0];
|
||||
if (year_start_date > frappe.datetime.get_today()) {
|
||||
next_year = current_year;
|
||||
current_year -= 1;
|
||||
@ -171,7 +102,7 @@ erpnext.setup.slides_settings = [
|
||||
|
||||
|
||||
load_chart_of_accounts: function (slide) {
|
||||
var country = frappe.wizard.values.country;
|
||||
let country = frappe.wizard.values.country;
|
||||
|
||||
if (country) {
|
||||
frappe.call({
|
||||
@ -202,12 +133,25 @@ erpnext.setup.slides_settings = [
|
||||
|
||||
me.charts_modal(slide, chart_template);
|
||||
});
|
||||
|
||||
slide.get_input("company_name").on("change", function () {
|
||||
let parts = slide.get_input("company_name").val().split(" ");
|
||||
let abbr = $.map(parts, function (p) { return p ? p.substr(0, 1) : null }).join("");
|
||||
slide.get_field("company_abbr").set_value(abbr.slice(0, 10).toUpperCase());
|
||||
}).val(frappe.boot.sysdefaults.company_name || "").trigger("change");
|
||||
|
||||
slide.get_input("company_abbr").on("change", function () {
|
||||
if (slide.get_input("company_abbr").val().length > 10) {
|
||||
frappe.msgprint(__("Company Abbreviation cannot have more than 5 characters"));
|
||||
slide.get_field("company_abbr").set_value("");
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
charts_modal: function(slide, chart_template) {
|
||||
let parent = __('All Accounts');
|
||||
|
||||
var dialog = new frappe.ui.Dialog({
|
||||
let dialog = new frappe.ui.Dialog({
|
||||
title: chart_template,
|
||||
fields: [
|
||||
{'fieldname': 'expand_all', 'label': __('Expand All'), 'fieldtype': 'Button',
|
||||
|
@ -491,7 +491,20 @@ erpnext.utils.update_child_items = function(opts) {
|
||||
const child_meta = frappe.get_meta(`${frm.doc.doctype} Item`);
|
||||
const get_precision = (fieldname) => child_meta.fields.find(f => f.fieldname == fieldname).precision;
|
||||
|
||||
this.data = [];
|
||||
this.data = frm.doc[opts.child_docname].map((d) => {
|
||||
return {
|
||||
"docname": d.name,
|
||||
"name": d.name,
|
||||
"item_code": d.item_code,
|
||||
"delivery_date": d.delivery_date,
|
||||
"schedule_date": d.schedule_date,
|
||||
"conversion_factor": d.conversion_factor,
|
||||
"qty": d.qty,
|
||||
"rate": d.rate,
|
||||
"uom": d.uom
|
||||
}
|
||||
});
|
||||
|
||||
const fields = [{
|
||||
fieldtype:'Data',
|
||||
fieldname:"docname",
|
||||
@ -588,7 +601,7 @@ erpnext.utils.update_child_items = function(opts) {
|
||||
})
|
||||
}
|
||||
|
||||
const dialog = new frappe.ui.Dialog({
|
||||
new frappe.ui.Dialog({
|
||||
title: __("Update Items"),
|
||||
fields: [
|
||||
{
|
||||
@ -624,24 +637,7 @@ erpnext.utils.update_child_items = function(opts) {
|
||||
refresh_field("items");
|
||||
},
|
||||
primary_action_label: __('Update')
|
||||
});
|
||||
|
||||
frm.doc[opts.child_docname].forEach(d => {
|
||||
dialog.fields_dict.trans_items.df.data.push({
|
||||
"docname": d.name,
|
||||
"name": d.name,
|
||||
"item_code": d.item_code,
|
||||
"delivery_date": d.delivery_date,
|
||||
"schedule_date": d.schedule_date,
|
||||
"conversion_factor": d.conversion_factor,
|
||||
"qty": d.qty,
|
||||
"rate": d.rate,
|
||||
"uom": d.uom
|
||||
});
|
||||
this.data = dialog.fields_dict.trans_items.df.data;
|
||||
dialog.fields_dict.trans_items.grid.refresh();
|
||||
})
|
||||
dialog.show();
|
||||
}).show();
|
||||
}
|
||||
|
||||
erpnext.utils.map_current_doc = function(opts) {
|
||||
|
@ -17,45 +17,79 @@ from erpnext.stock.utils import scan_barcode
|
||||
def search_by_term(search_term, warehouse, price_list):
|
||||
result = search_for_serial_or_batch_or_barcode_number(search_term) or {}
|
||||
|
||||
item_code = result.get("item_code") or search_term
|
||||
serial_no = result.get("serial_no") or ""
|
||||
batch_no = result.get("batch_no") or ""
|
||||
barcode = result.get("barcode") or ""
|
||||
item_code = result.get("item_code", search_term)
|
||||
serial_no = result.get("serial_no", "")
|
||||
batch_no = result.get("batch_no", "")
|
||||
barcode = result.get("barcode", "")
|
||||
|
||||
if result:
|
||||
item_info = frappe.db.get_value(
|
||||
"Item",
|
||||
item_code,
|
||||
[
|
||||
"name as item_code",
|
||||
"item_name",
|
||||
"description",
|
||||
"stock_uom",
|
||||
"image as item_image",
|
||||
"is_stock_item",
|
||||
],
|
||||
as_dict=1,
|
||||
)
|
||||
if not result:
|
||||
return
|
||||
|
||||
item_stock_qty, is_stock_item = get_stock_availability(item_code, warehouse)
|
||||
price_list_rate, currency = frappe.db.get_value(
|
||||
"Item Price",
|
||||
{"price_list": price_list, "item_code": item_code},
|
||||
["price_list_rate", "currency"],
|
||||
) or [None, None]
|
||||
item_doc = frappe.get_doc("Item", item_code)
|
||||
|
||||
item_info.update(
|
||||
if not item_doc:
|
||||
return
|
||||
|
||||
item = {
|
||||
"barcode": barcode,
|
||||
"batch_no": batch_no,
|
||||
"description": item_doc.description,
|
||||
"is_stock_item": item_doc.is_stock_item,
|
||||
"item_code": item_doc.name,
|
||||
"item_image": item_doc.image,
|
||||
"item_name": item_doc.item_name,
|
||||
"serial_no": serial_no,
|
||||
"stock_uom": item_doc.stock_uom,
|
||||
"uom": item_doc.stock_uom,
|
||||
}
|
||||
|
||||
if barcode:
|
||||
barcode_info = next(filter(lambda x: x.barcode == barcode, item_doc.get("barcodes", [])), None)
|
||||
if barcode_info and barcode_info.uom:
|
||||
uom = next(filter(lambda x: x.uom == barcode_info.uom, item_doc.uoms), {})
|
||||
item.update(
|
||||
{
|
||||
"uom": barcode_info.uom,
|
||||
"conversion_factor": uom.get("conversion_factor", 1),
|
||||
}
|
||||
)
|
||||
|
||||
item_stock_qty, is_stock_item = get_stock_availability(item_code, warehouse)
|
||||
item_stock_qty = item_stock_qty // item.get("conversion_factor")
|
||||
item.update({"actual_qty": item_stock_qty})
|
||||
|
||||
price = frappe.get_list(
|
||||
doctype="Item Price",
|
||||
filters={
|
||||
"price_list": price_list,
|
||||
"item_code": item_code,
|
||||
},
|
||||
fields=["uom", "stock_uom", "currency", "price_list_rate"],
|
||||
)
|
||||
|
||||
def __sort(p):
|
||||
p_uom = p.get("uom")
|
||||
|
||||
if p_uom == item.get("uom"):
|
||||
return 0
|
||||
elif p_uom == item.get("stock_uom"):
|
||||
return 1
|
||||
else:
|
||||
return 2
|
||||
|
||||
# sort by fallback preference. always pick exact uom match if available
|
||||
price = sorted(price, key=__sort)
|
||||
|
||||
if len(price) > 0:
|
||||
p = price.pop(0)
|
||||
item.update(
|
||||
{
|
||||
"serial_no": serial_no,
|
||||
"batch_no": batch_no,
|
||||
"barcode": barcode,
|
||||
"price_list_rate": price_list_rate,
|
||||
"currency": currency,
|
||||
"actual_qty": item_stock_qty,
|
||||
"currency": p.get("currency"),
|
||||
"price_list_rate": p.get("price_list_rate"),
|
||||
}
|
||||
)
|
||||
|
||||
return {"items": [item_info]}
|
||||
return {"items": [item]}
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
@ -121,33 +155,43 @@ def get_items(start, page_length, price_list, item_group, pos_profile, search_te
|
||||
as_dict=1,
|
||||
)
|
||||
|
||||
if items_data:
|
||||
items = [d.item_code for d in items_data]
|
||||
item_prices_data = frappe.get_all(
|
||||
# return (empty) list if there are no results
|
||||
if not items_data:
|
||||
return result
|
||||
|
||||
for item in items_data:
|
||||
uoms = frappe.get_doc("Item", item.item_code).get("uoms", [])
|
||||
|
||||
item.actual_qty, _ = get_stock_availability(item.item_code, warehouse)
|
||||
item.uom = item.stock_uom
|
||||
|
||||
item_price = frappe.get_all(
|
||||
"Item Price",
|
||||
fields=["item_code", "price_list_rate", "currency"],
|
||||
filters={"price_list": price_list, "item_code": ["in", items]},
|
||||
fields=["price_list_rate", "currency", "uom"],
|
||||
filters={
|
||||
"price_list": price_list,
|
||||
"item_code": item.item_code,
|
||||
"selling": True,
|
||||
},
|
||||
)
|
||||
|
||||
item_prices = {}
|
||||
for d in item_prices_data:
|
||||
item_prices[d.item_code] = d
|
||||
if not item_price:
|
||||
result.append(item)
|
||||
|
||||
for item in items_data:
|
||||
item_code = item.item_code
|
||||
item_price = item_prices.get(item_code) or {}
|
||||
item_stock_qty, is_stock_item = get_stock_availability(item_code, warehouse)
|
||||
for price in item_price:
|
||||
uom = next(filter(lambda x: x.uom == price.uom, uoms), {})
|
||||
|
||||
row = {}
|
||||
row.update(item)
|
||||
row.update(
|
||||
if price.uom != item.stock_uom and uom and uom.conversion_factor:
|
||||
item.actual_qty = item.actual_qty // uom.conversion_factor
|
||||
|
||||
result.append(
|
||||
{
|
||||
"price_list_rate": item_price.get("price_list_rate"),
|
||||
"currency": item_price.get("currency"),
|
||||
"actual_qty": item_stock_qty,
|
||||
**item,
|
||||
"price_list_rate": price.get("price_list_rate"),
|
||||
"currency": price.get("currency"),
|
||||
"uom": price.uom or item.uom,
|
||||
}
|
||||
)
|
||||
result.append(row)
|
||||
|
||||
return {"items": result}
|
||||
|
||||
|
@ -542,12 +542,12 @@ erpnext.PointOfSale.Controller = class {
|
||||
if (!this.frm.doc.customer)
|
||||
return this.raise_customer_selection_alert();
|
||||
|
||||
const { item_code, batch_no, serial_no, rate } = item;
|
||||
const { item_code, batch_no, serial_no, rate, uom } = item;
|
||||
|
||||
if (!item_code)
|
||||
return;
|
||||
|
||||
const new_item = { item_code, batch_no, rate, [field]: value };
|
||||
const new_item = { item_code, batch_no, rate, uom, [field]: value };
|
||||
|
||||
if (serial_no) {
|
||||
await this.check_serial_no_availablilty(item_code, this.frm.doc.set_warehouse, serial_no);
|
||||
@ -649,6 +649,7 @@ erpnext.PointOfSale.Controller = class {
|
||||
const is_stock_item = resp[1];
|
||||
|
||||
frappe.dom.unfreeze();
|
||||
const bold_uom = item_row.stock_uom.bold();
|
||||
const bold_item_code = item_row.item_code.bold();
|
||||
const bold_warehouse = warehouse.bold();
|
||||
const bold_available_qty = available_qty.toString().bold()
|
||||
@ -664,7 +665,7 @@ erpnext.PointOfSale.Controller = class {
|
||||
}
|
||||
} else if (is_stock_item && available_qty < qty_needed) {
|
||||
frappe.throw({
|
||||
message: __('Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.', [bold_item_code, bold_warehouse, bold_available_qty]),
|
||||
message: __('Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2} {3}.', [bold_item_code, bold_warehouse, bold_available_qty, bold_uom]),
|
||||
indicator: 'orange'
|
||||
});
|
||||
frappe.utils.play_sound("error");
|
||||
|
@ -609,7 +609,7 @@ erpnext.PointOfSale.ItemCart = class {
|
||||
if (item_data.rate && item_data.amount && item_data.rate !== item_data.amount) {
|
||||
return `
|
||||
<div class="item-qty-rate">
|
||||
<div class="item-qty"><span>${item_data.qty || 0}</span></div>
|
||||
<div class="item-qty"><span>${item_data.qty || 0} ${item_data.uom}</span></div>
|
||||
<div class="item-rate-amount">
|
||||
<div class="item-rate">${format_currency(item_data.amount, currency)}</div>
|
||||
<div class="item-amount">${format_currency(item_data.rate, currency)}</div>
|
||||
@ -618,7 +618,7 @@ erpnext.PointOfSale.ItemCart = class {
|
||||
} else {
|
||||
return `
|
||||
<div class="item-qty-rate">
|
||||
<div class="item-qty"><span>${item_data.qty || 0}</span></div>
|
||||
<div class="item-qty"><span>${item_data.qty || 0} ${item_data.uom}</span></div>
|
||||
<div class="item-rate-amount">
|
||||
<div class="item-rate">${format_currency(item_data.rate, currency)}</div>
|
||||
</div>
|
||||
|
@ -78,7 +78,7 @@ erpnext.PointOfSale.ItemSelector = class {
|
||||
get_item_html(item) {
|
||||
const me = this;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const { item_image, serial_no, batch_no, barcode, actual_qty, stock_uom, price_list_rate } = item;
|
||||
const { item_image, serial_no, batch_no, barcode, actual_qty, uom, price_list_rate } = item;
|
||||
const precision = flt(price_list_rate, 2) % 1 != 0 ? 2 : 0;
|
||||
let indicator_color;
|
||||
let qty_to_display = actual_qty;
|
||||
@ -118,7 +118,7 @@ erpnext.PointOfSale.ItemSelector = class {
|
||||
return (
|
||||
`<div class="item-wrapper"
|
||||
data-item-code="${escape(item.item_code)}" data-serial-no="${escape(serial_no)}"
|
||||
data-batch-no="${escape(batch_no)}" data-uom="${escape(stock_uom)}"
|
||||
data-batch-no="${escape(batch_no)}" data-uom="${escape(uom)}"
|
||||
data-rate="${escape(price_list_rate || 0)}"
|
||||
title="${item.item_name}">
|
||||
|
||||
@ -128,7 +128,7 @@ erpnext.PointOfSale.ItemSelector = class {
|
||||
<div class="item-name">
|
||||
${frappe.ellipsis(item.item_name, 18)}
|
||||
</div>
|
||||
<div class="item-rate">${format_currency(price_list_rate, item.currency, precision) || 0}</div>
|
||||
<div class="item-rate">${format_currency(price_list_rate, item.currency, precision) || 0} / ${uom}</div>
|
||||
</div>
|
||||
</div>`
|
||||
);
|
||||
|
@ -94,7 +94,7 @@ erpnext.PointOfSale.PastOrderSummary = class {
|
||||
get_item_html(doc, item_data) {
|
||||
return `<div class="item-row-wrapper">
|
||||
<div class="item-name">${item_data.item_name}</div>
|
||||
<div class="item-qty">${item_data.qty || 0}</div>
|
||||
<div class="item-qty">${item_data.qty || 0} ${item_data.uom}</div>
|
||||
<div class="item-rate-disc">${get_rate_discount_html()}</div>
|
||||
</div>`;
|
||||
|
||||
|
@ -4,7 +4,6 @@
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import cstr, getdate
|
||||
from .default_website import website_maker
|
||||
|
||||
|
||||
def create_fiscal_year_and_company(args):
|
||||
@ -48,83 +47,6 @@ def enable_shopping_cart(args): # nosemgrep
|
||||
).insert()
|
||||
|
||||
|
||||
def create_email_digest():
|
||||
from frappe.utils.user import get_system_managers
|
||||
|
||||
system_managers = get_system_managers(only_name=True)
|
||||
|
||||
if not system_managers:
|
||||
return
|
||||
|
||||
recipients = []
|
||||
for d in system_managers:
|
||||
recipients.append({"recipient": d})
|
||||
|
||||
companies = frappe.db.sql_list("select name FROM `tabCompany`")
|
||||
for company in companies:
|
||||
if not frappe.db.exists("Email Digest", "Default Weekly Digest - " + company):
|
||||
edigest = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Email Digest",
|
||||
"name": "Default Weekly Digest - " + company,
|
||||
"company": company,
|
||||
"frequency": "Weekly",
|
||||
"recipients": recipients,
|
||||
}
|
||||
)
|
||||
|
||||
for df in edigest.meta.get("fields", {"fieldtype": "Check"}):
|
||||
if df.fieldname != "scheduler_errors":
|
||||
edigest.set(df.fieldname, 1)
|
||||
|
||||
edigest.insert()
|
||||
|
||||
# scheduler errors digest
|
||||
if companies:
|
||||
edigest = frappe.new_doc("Email Digest")
|
||||
edigest.update(
|
||||
{
|
||||
"name": "Scheduler Errors",
|
||||
"company": companies[0],
|
||||
"frequency": "Daily",
|
||||
"recipients": recipients,
|
||||
"scheduler_errors": 1,
|
||||
"enabled": 1,
|
||||
}
|
||||
)
|
||||
edigest.insert()
|
||||
|
||||
|
||||
def create_logo(args):
|
||||
if args.get("attach_logo"):
|
||||
attach_logo = args.get("attach_logo").split(",")
|
||||
if len(attach_logo) == 3:
|
||||
filename, filetype, content = attach_logo
|
||||
_file = frappe.get_doc(
|
||||
{
|
||||
"doctype": "File",
|
||||
"file_name": filename,
|
||||
"attached_to_doctype": "Website Settings",
|
||||
"attached_to_name": "Website Settings",
|
||||
"decode": True,
|
||||
}
|
||||
)
|
||||
_file.save()
|
||||
fileurl = _file.file_url
|
||||
frappe.db.set_value(
|
||||
"Website Settings",
|
||||
"Website Settings",
|
||||
"brand_html",
|
||||
"<img src='{0}' style='max-width: 40px; max-height: 25px;'> {1}".format(
|
||||
fileurl, args.get("company_name")
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def create_website(args):
|
||||
website_maker(args)
|
||||
|
||||
|
||||
def get_fy_details(fy_start_date, fy_end_date):
|
||||
start_year = getdate(fy_start_date).year
|
||||
if start_year == getdate(fy_end_date).year:
|
||||
|
@ -1,89 +0,0 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import nowdate
|
||||
|
||||
|
||||
class website_maker(object):
|
||||
def __init__(self, args):
|
||||
self.args = args
|
||||
self.company = args.company_name
|
||||
self.tagline = args.company_tagline
|
||||
self.user = args.get("email")
|
||||
self.make_web_page()
|
||||
self.make_website_settings()
|
||||
self.make_blog()
|
||||
|
||||
def make_web_page(self):
|
||||
# home page
|
||||
homepage = frappe.get_doc("Homepage", "Homepage")
|
||||
homepage.company = self.company
|
||||
homepage.tag_line = self.tagline
|
||||
homepage.setup_items()
|
||||
homepage.save()
|
||||
|
||||
def make_website_settings(self):
|
||||
# update in home page in settings
|
||||
website_settings = frappe.get_doc("Website Settings", "Website Settings")
|
||||
website_settings.home_page = "home"
|
||||
website_settings.brand_html = self.company
|
||||
website_settings.copyright = self.company
|
||||
website_settings.top_bar_items = []
|
||||
website_settings.append(
|
||||
"top_bar_items", {"doctype": "Top Bar Item", "label": "Contact", "url": "/contact"}
|
||||
)
|
||||
website_settings.append(
|
||||
"top_bar_items", {"doctype": "Top Bar Item", "label": "Blog", "url": "/blog"}
|
||||
)
|
||||
website_settings.append(
|
||||
"top_bar_items", {"doctype": "Top Bar Item", "label": _("Products"), "url": "/all-products"}
|
||||
)
|
||||
website_settings.save()
|
||||
|
||||
def make_blog(self):
|
||||
blog_category = frappe.get_doc(
|
||||
{"doctype": "Blog Category", "category_name": "general", "published": 1, "title": _("General")}
|
||||
).insert()
|
||||
|
||||
if not self.user:
|
||||
# Admin setup
|
||||
return
|
||||
|
||||
blogger = frappe.new_doc("Blogger")
|
||||
user = frappe.get_doc("User", self.user)
|
||||
blogger.user = self.user
|
||||
blogger.full_name = user.first_name + (" " + user.last_name if user.last_name else "")
|
||||
blogger.short_name = user.first_name.lower()
|
||||
blogger.avatar = user.user_image
|
||||
blogger.insert()
|
||||
|
||||
frappe.get_doc(
|
||||
{
|
||||
"doctype": "Blog Post",
|
||||
"title": "Welcome",
|
||||
"published": 1,
|
||||
"published_on": nowdate(),
|
||||
"blogger": blogger.name,
|
||||
"blog_category": blog_category.name,
|
||||
"blog_intro": "My First Blog",
|
||||
"content": frappe.get_template("setup/setup_wizard/data/sample_blog_post.html").render(),
|
||||
}
|
||||
).insert()
|
||||
|
||||
|
||||
def test():
|
||||
frappe.delete_doc("Web Page", "test-company")
|
||||
frappe.delete_doc("Blog Post", "welcome")
|
||||
frappe.delete_doc("Blogger", "administrator")
|
||||
frappe.delete_doc("Blog Category", "general")
|
||||
website_maker(
|
||||
{
|
||||
"company": "Test Company",
|
||||
"company_tagline": "Better Tools for Everyone",
|
||||
"name": "Administrator",
|
||||
}
|
||||
)
|
||||
frappe.db.commit()
|
@ -5,7 +5,6 @@
|
||||
import frappe
|
||||
from frappe import _
|
||||
|
||||
from .operations import company_setup
|
||||
from .operations import install_fixtures as fixtures
|
||||
|
||||
|
||||
@ -35,7 +34,6 @@ def get_setup_stages(args=None):
|
||||
"fail_msg": "Failed to set defaults",
|
||||
"tasks": [
|
||||
{"fn": setup_defaults, "args": args, "fail_msg": _("Failed to setup defaults")},
|
||||
{"fn": stage_four, "args": args, "fail_msg": _("Failed to create website")},
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -60,12 +58,6 @@ def setup_defaults(args):
|
||||
fixtures.install_defaults(frappe._dict(args))
|
||||
|
||||
|
||||
def stage_four(args):
|
||||
company_setup.create_website(args)
|
||||
company_setup.create_email_digest()
|
||||
company_setup.create_logo(args)
|
||||
|
||||
|
||||
def fin(args):
|
||||
frappe.local.message_log = []
|
||||
login_as_first_user(args)
|
||||
@ -81,5 +73,4 @@ def setup_complete(args=None):
|
||||
stage_fixtures(args)
|
||||
setup_company(args)
|
||||
setup_defaults(args)
|
||||
stage_four(args)
|
||||
fin(args)
|
||||
|
@ -894,6 +894,12 @@ function open_form(frm, doctype, child_doctype, parentfield) {
|
||||
new_child_doc.uom = frm.doc.stock_uom;
|
||||
new_child_doc.description = frm.doc.description;
|
||||
|
||||
frappe.ui.form.make_quick_entry(doctype, null, null, new_doc);
|
||||
frappe.run_serially([
|
||||
() => frappe.ui.form.make_quick_entry(doctype, null, null, new_doc),
|
||||
() => {
|
||||
frappe.flags.ignore_company_party_validation = true;
|
||||
frappe.model.trigger("item_code", frm.doc.name, new_child_doc);
|
||||
}
|
||||
])
|
||||
});
|
||||
}
|
||||
|
@ -3311,7 +3311,6 @@ Quality Feedback Template,質量反饋模板,
|
||||
Rules for applying different promotional schemes.,適用不同促銷計劃的規則。,
|
||||
Shift,轉移,
|
||||
Show {0},顯示{0},
|
||||
"Special Characters except '-', '#', '.', '/', '{{' and '}}' not allowed in naming series {0}",命名系列中不允許使用除 "-", "#", "।", "/", "{{" 和 "}}"之外的特殊字符 {0},
|
||||
Target Details,目標細節,
|
||||
API,API,
|
||||
Annual,年刊,
|
||||
|
Can't render this file because it has a wrong number of fields in line 3314.
|
Loading…
Reference in New Issue
Block a user